LCOV - code coverage report
Current view: top level - utils - zonal_mean_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 11 681 1.6 %
Date: 2024-12-17 22:39:59 Functions: 2 28 7.1 %

          Line data    Source code
       1             : module zonal_mean_mod
       2             : !======================================================================
       3             : !
       4             : ! Purpose: Compute and make use of Zonal Mean values on physgrid
       5             : !
       6             : !    This module implements 3 data structures for the spectral analysis
       7             : !    and synthesis of zonal mean values based on m=0 spherical harmonics.
       8             : !
       9             : !    ZonalMean_t:    For the analysis/synthesis of zonal mean values
      10             : !                    on a 2D grid of points distributed over the
      11             : !                    surface of a sphere.
      12             : !    ZonalProfile_t: For the analysis/synthesis of zonal mean values
      13             : !                    on a meridional grid that spans the latitudes
      14             : !                    from SP to NP
      15             : !    ZonalAverage_t: To calculate zonal mean values via a simple
      16             : !                    area weighted bin-averaging of 2D grid points
      17             : !                    assigned to each latitude band.
      18             : !
      19             : !   NOTE: The weighting of the Zonal Profiles values is scaled such
      20             : !         that ZonalMean_t amplitudes can be used to evaluate values
      21             : !         on the ZonalProfile_t grid and vice-versa.
      22             : !
      23             : !         The ZonalMean_t computes global integrals to compute basis
      24             : !         amplitudes. For distributed environments the cost of these
      25             : !         can be reduced using the The ZonalAverage_t data structures.
      26             : !
      27             : ! USAGE:
      28             : !
      29             : !    (1) Compute Zonal mean amplitudes and synthesize values on 2D/3D physgrid
      30             : !
      31             : !         Usage: type(ZonalMean_t):: ZM
      32             : !         =========================================
      33             : !           call ZM%init(nbas)
      34             : !           ------------------
      35             : !               - Initialize the data structure with 'nbas' basis functions
      36             : !                 for the given physgrid latitudes and areas.
      37             : !
      38             : !               Arguments:
      39             : !                 integer ,intent(in):: nbas     -Number of m=0 spherical harmonics
      40             : !
      41             : !           call ZM%calc_amps(Gdata,Bamp)
      42             : !           -----------------------------
      43             : !               - For the initialized ZonalMean_t; Given Gdata() values on the physgrid,
      44             : !                 compute the zonal mean basis amplitudes Bamp().
      45             : !
      46             : !               Interface: 2D data on the physgrid
      47             : !                 real(r8),intent(in ):: Gdata(pcols,begchunk:endchunk)
      48             : !                 real(r8),intent(out):: Bamp (nbas)
      49             : !
      50             : !               Interface: 3D data on the physgrid
      51             : !                 real(r8),intent(in ):: Gdata(pcols,pver,begchunk:endchunk)
      52             : !                 real(r8),intent(out):: Bamp (nbas,pver)
      53             : !
      54             : !           call ZM%eval_grid(Bamp,Gdata)
      55             : !           -----------------------------
      56             : !               - For the initialized ZonalMean_t; Given Bamp() zonal mean basis
      57             : !                 amplitudes, compute the Gdata() values on the physgrid.
      58             : !
      59             : !               Interface: 2D data on the physgrid
      60             : !                 real(r8),intent(in ):: Bamp (nbas)
      61             : !                 real(r8),intent(out):: Gdata(pcols,begchunk:endchunk)
      62             : !
      63             : !               Interface: 3D data on the physgrid
      64             : !                 real(r8),intent(in ):: Bamp (nbas,pver)
      65             : !                 real(r8),intent(out):: Gdata(pcols,pver,begchunk:endchunk)
      66             : !
      67             : !
      68             : !    (2) Compute Zonal mean amplitudes and synthesize values on Zonal profile grid
      69             : !
      70             : !         Usage: type(ZonalProfile_t):: ZP
      71             : !         =========================================
      72             : !           call ZP%init(lats,area,nlat,nbas,GEN_GAUSSLATS=.true.)
      73             : !           ------------------------------------------------------
      74             : !               - Initialize the data structure for the given number of
      75             : !                 latitudes. Either use the given Latitudes and weights,
      76             : !                 or OPTIONALLY create profile gridpoints and associated
      77             : !                 area weights from SP to NP. Then initialize 'nbas' basis
      78             : !                 functions for the profile gridpoints.
      79             : !                 If the user supplies the lats/area values, the area values must
      80             : !                 be correctly scaled such that the global area adds up to 4PI.
      81             : !                 Otherwise, the ampitudes between ZonalProfile_t and ZonalMean_t
      82             : !                 are not interchangable.
      83             : !
      84             : !               Arguments:
      85             : !                 real(r8),intent(inout):: lats(:) - Latitudes of meridional grid.
      86             : !                 real(r8),intent(inout):: area(:) - Area of each meridional gridpoint.
      87             : !                 integer ,intent(in)   :: nlat    - Number of meridional gridpoints.
      88             : !                 integer ,intent(in)   :: nbas    - Number of m=0 spherical harmonics
      89             : !                 logical ,intent(in),optional:: GEN_GAUSLATS - Flag to generate
      90             : !                                                               lats/areas values.
      91             : !
      92             : !           call ZP%calc_amps(Zdata,Bamp)
      93             : !           -----------------------------
      94             : !               - Given Zdata() on the Zonal profile grid, compute the
      95             : !                 zonal basis amplitudes Bamp().
      96             : !
      97             : !               Interface: 1D data on (nlat) grid
      98             : !                 real(r8),intent(in ):: Zdata(nlat) - Meridional Profile data
      99             : !                 real(r8),intent(out):: Bamp (nbas) - Zonal Basis Amplitudes
     100             : !
     101             : !               Interface: 2D data on (nlat,pver) grid
     102             : !                 real(r8),intent(in ):: Zdata(nlat,pver) - Meridional Profile data
     103             : !                 real(r8),intent(out):: Bamp (nbas,pver) - Zonal Basis Amplitudes
     104             : !
     105             : !           call ZP%eval_grid(Bamp,Zdata)
     106             : !           -----------------------------
     107             : !               - Given Bamp() zonal basis amplitudes, evaluate the Zdata()
     108             : !                 values on the Zonal profile grid.
     109             : !
     110             : !               Interface: 1D data on (nlat) grid
     111             : !                 real(r8),intent(in ):: Bamp (nbas) - Zonal Basis Amplitudes
     112             : !                 real(r8),intent(out):: Zdata(nlat) - Meridional Profile data
     113             : !
     114             : !               Interface: 2D data on (nlat,pver) grid
     115             : !                 real(r8),intent(in ):: Bamp (nbas,pver) - Zonal Basis Amplitudes
     116             : !                 real(r8),intent(out):: Zdata(nlat,pver) - Meridional Profile data
     117             : !
     118             : !    (3) Compute Zonal mean averages (FASTER/LESS-ACCURATE) on Zonal profile grid
     119             : !        (For the created zonal profile, just bin average area weighted
     120             : !         2D/3D physgrid grid values)
     121             : !
     122             : !         Usage: type(ZonalAverage_t):: ZA
     123             : !         =========================================
     124             : !           call ZA%init(lats,area,nlat,GEN_GAUSSLATS=.true.)
     125             : !           --------------------------------------------------
     126             : !               - Given the latitude/area for the nlat meridional gridpoints, initialize
     127             : !                 the ZonalAverage data structure for computing bin-averaging of physgrid
     128             : !                 values. It is assumed that the domain of these gridpoints of the
     129             : !                 profile span latitudes from SP to NP.
     130             : !                 The optional GEN_GAUSSLATS flag allows for the generation of Gaussian
     131             : !                 latitude gridpoints. The generated grid over-writes the given values
     132             : !                 lats and area passed by the user.
     133             : !
     134             : !               Arguments:
     135             : !                 real(r8),intent(inout):: lats(nlat) - Latitudes of meridional grid.
     136             : !                 real(r8),intent(inout):: area(nlat) - Area of meridional gridpoints.
     137             : !                 integer    ,intent(in):: nlat       - Number of meridional gridpoints
     138             : !                 logical,intent(in),optional:: GEN_GAUSLATS - Flag to generate
     139             : !                                                              lats/areas values.
     140             : !
     141             : !           call ZA%binAvg(Gdata,Zdata)
     142             : !           ---------------------------
     143             : !               - For the initialized ZonalAverage_t; Given Gdata() on the physgrid,
     144             : !                 compute bin averages and return Zdata() on the Zonal profile grid.
     145             : !
     146             : !               Interface: 2D data on the physgrid
     147             : !                 real(r8),intent(out):: Gdata(pcols,begchunk:endchunk)
     148             : !                 real(r8),intent(out):: Zdata(nlat)
     149             : !
     150             : !               Interface: 3D data on the physgrid
     151             : !                 real(r8),intent(out):: Gdata(pcols,pver,begchunk:endchunk)
     152             : !                 real(r8),intent(out):: Zdata(nlat,pver)
     153             : !
     154             : !======================================================================
     155             : 
     156             :   use shr_kind_mod,    only: r8=>SHR_KIND_R8
     157             :   use phys_grid,       only: get_ncols_p, get_rlat_p, get_wght_all_p, get_nlcols_p
     158             :   use ppgrid,          only: begchunk, endchunk, pcols
     159             :   use shr_reprosum_mod,only: shr_reprosum_calc
     160             :   use cam_abortutils,  only: endrun, handle_allocate_error
     161             :   use spmd_utils,      only: mpicom
     162             :   use physconst,       only: pi
     163             :   use phys_grid,       only: ngcols_p => num_global_phys_cols
     164             :   use cam_logfile,     only: iulog
     165             : 
     166             :   implicit none
     167             :   private
     168             : 
     169             :   public :: ZonalMean_t
     170             :   public :: ZonalProfile_t
     171             :   public :: ZonalAverage_t
     172             : 
     173             :   ! Type definitions
     174             :   !-------------------
     175             :   type ZonalMean_t
     176             :      private
     177             :      integer             :: nbas
     178             :      real(r8),allocatable:: area (:,:)
     179             :      real(r8),allocatable:: basis(:,:,:)
     180             :      real(r8),allocatable:: map  (:,:)
     181             :     contains
     182             :      procedure,pass:: init      => init_ZonalMean
     183             :      generic,public:: calc_amps => calc_ZonalMean_2Damps, &
     184             :                                    calc_ZonalMean_3Damps
     185             :      generic,public:: eval_grid => eval_ZonalMean_2Dgrid, &
     186             :                                    eval_ZonalMean_3Dgrid
     187             :      procedure,private,pass:: calc_ZonalMean_2Damps
     188             :      procedure,private,pass:: calc_ZonalMean_3Damps
     189             :      procedure,private,pass:: eval_ZonalMean_2Dgrid
     190             :      procedure,private,pass:: eval_ZonalMean_3Dgrid
     191             :      procedure, pass :: final => final_ZonalMean
     192             :  end type ZonalMean_t
     193             : 
     194             :   type ZonalProfile_t
     195             :      private
     196             :      integer             :: nlat
     197             :      integer             :: nbas
     198             :      real(r8),allocatable:: area (:)
     199             :      real(r8),allocatable:: basis(:,:)
     200             :      real(r8),allocatable:: map  (:,:)
     201             :     contains
     202             :      procedure,pass:: init      => init_ZonalProfile
     203             :      generic,public:: calc_amps => calc_ZonalProfile_1Damps, &
     204             :                                    calc_ZonalProfile_2Damps
     205             :      generic,public:: eval_grid => eval_ZonalProfile_1Dgrid, &
     206             :                                    eval_ZonalProfile_2Dgrid
     207             :      procedure,private,pass:: calc_ZonalProfile_1Damps
     208             :      procedure,private,pass:: calc_ZonalProfile_2Damps
     209             :      procedure,private,pass:: eval_ZonalProfile_1Dgrid
     210             :      procedure,private,pass:: eval_ZonalProfile_2Dgrid
     211             :      procedure, pass :: final => final_ZonalProfile
     212             :   end type ZonalProfile_t
     213             : 
     214             :   type ZonalAverage_t
     215             :      private
     216             :      integer             :: nlat
     217             :      real(r8),allocatable:: area   (:)
     218             :      real(r8),allocatable:: a_norm (:)
     219             :      real(r8),allocatable:: area_g (:,:)
     220             :      integer ,allocatable:: idx_map(:,:)
     221             :     contains
     222             :      procedure,pass:: init   => init_ZonalAverage
     223             :      generic,public:: binAvg => calc_ZonalAverage_2DbinAvg, &
     224             :                                 calc_ZonalAverage_3DbinAvg
     225             :      procedure,private,pass:: calc_ZonalAverage_2DbinAvg
     226             :      procedure,private,pass:: calc_ZonalAverage_3DbinAvg
     227             :      procedure, pass :: final => final_ZonalAverage
     228             :   end type ZonalAverage_t
     229             : 
     230             :   real(r8), parameter :: halfPI = 0.5_r8*pi
     231             :   real(r8), parameter :: twoPI  = 2.0_r8*pi
     232             :   real(r8), parameter :: fourPI = 4.0_r8*pi
     233             :   real(r8), parameter :: qrtrPI = 0.25_r8*pi
     234             :   real(r8), parameter :: invSqrt4pi = 1._r8/sqrt(fourPI)
     235             : 
     236             : contains
     237             :     !=======================================================================
     238           0 :     subroutine init_ZonalMean(this,I_nbas)
     239             :       !
     240             :       ! init_ZonalMean: Initialize the ZonalMean data structures for the
     241             :       !                 physics grid. It is assumed that the domain
     242             :       !                 of these gridpoints spans the surface of the sphere.
     243             :       !                 The representation of basis functions is
     244             :       !                 normalized w.r.t integration over the sphere.
     245             :       !=====================================================================
     246             :       !
     247             :       ! Passed Variables
     248             :       !------------------
     249             :       class(ZonalMean_t) :: this
     250             :       integer ,intent(in):: I_nbas
     251             :       !
     252             :       ! Local Values
     253             :       !--------------
     254           0 :       real(r8),allocatable:: Clats(:,:)
     255           0 :       real(r8),allocatable:: Bcoef(:)
     256           0 :       real(r8),allocatable:: Csum (:,:)
     257           0 :       real(r8),allocatable:: Cvec (:)
     258           0 :       real(r8),allocatable:: Bsum (:,:)
     259           0 :       real(r8),allocatable:: Bnorm(:)
     260           0 :       real(r8),allocatable:: Bcov (:,:)
     261             :       real(r8):: area(pcols),rlat
     262             : 
     263             :       integer :: nn,n2,nb,lchnk,ncols,cc
     264             :       integer :: cnum,Cvec_len
     265             : 
     266             :       integer :: nlcols, count, astat
     267             :       character(len=*), parameter :: subname = 'init_ZonalMean'
     268             : 
     269           0 :       if (I_nbas<1) then
     270           0 :          call endrun('ZonalMean%init: ERROR I_nbas must be greater than 0')
     271             :       end if
     272             : 
     273             :       ! Allocate space
     274             :       !-----------------
     275           0 :       if(allocated(this%area )) deallocate(this%area)
     276           0 :       if(allocated(this%basis)) deallocate(this%basis)
     277           0 :       if(allocated(this%map  )) deallocate(this%map)
     278             : 
     279           0 :       this%nbas = I_nbas
     280           0 :       allocate(this%area (pcols,begchunk:endchunk), stat=astat)
     281           0 :       call handle_allocate_error(astat, subname, 'this%area')
     282           0 :       allocate(this%basis(pcols,begchunk:endchunk,I_nbas), stat=astat)
     283           0 :       call handle_allocate_error(astat, subname, 'this%basis')
     284           0 :       allocate(this%map  (I_nbas,I_nbas), stat=astat)
     285           0 :       call handle_allocate_error(astat, subname, 'this%map')
     286           0 :       this%area (:,:)   = 0._r8
     287           0 :       this%basis(:,:,:) = 0._r8
     288           0 :       this%map  (:,:)   = 0._r8
     289             : 
     290           0 :       Cvec_len = 0
     291           0 :       do nn= 1,this%nbas
     292           0 :          do n2=nn,this%nbas
     293           0 :             Cvec_len = Cvec_len + 1
     294             :          end do
     295             :       end do
     296             : 
     297           0 :       nlcols = get_nlcols_p()
     298             : 
     299           0 :       allocate(Clats(pcols,begchunk:endchunk), stat=astat)
     300           0 :       call handle_allocate_error(astat, subname, 'Clats')
     301           0 :       allocate(Bcoef(I_nbas/2+1), stat=astat)
     302           0 :       call handle_allocate_error(astat, subname, 'Bcoef')
     303           0 :       allocate(Csum (nlcols, Cvec_len), stat=astat)
     304           0 :       call handle_allocate_error(astat, subname, 'Csum')
     305           0 :       allocate(Cvec (Cvec_len), stat=astat)
     306           0 :       call handle_allocate_error(astat, subname, 'Cvec')
     307           0 :       allocate(Bsum (nlcols, I_nbas), stat=astat)
     308           0 :       call handle_allocate_error(astat, subname, 'Bsum')
     309           0 :       allocate(Bnorm(I_nbas), stat=astat)
     310           0 :       call handle_allocate_error(astat, subname, 'Bnorm')
     311           0 :       allocate(Bcov (I_nbas,I_nbas), stat=astat)
     312           0 :       call handle_allocate_error(astat, subname, 'Bcov')
     313             : 
     314           0 :       Bsum(:,:) = 0._r8
     315           0 :       Csum(:,:) = 0._r8
     316             : 
     317             :       ! Save a copy of the area weights for each ncol gridpoint
     318             :       ! and convert Latitudes to SP->NP colatitudes in radians
     319             :       !-------------------------------------------------------
     320           0 :       do lchnk=begchunk,endchunk
     321           0 :          ncols = get_ncols_p(lchnk)
     322           0 :          call get_wght_all_p(lchnk, ncols, area)
     323           0 :          do cc = 1,ncols
     324           0 :             rlat=get_rlat_p(lchnk,cc)
     325           0 :             this%area(cc,lchnk) = area(cc)
     326           0 :             Clats    (cc,lchnk) = rlat + halfPI
     327             :          end do
     328             :       end do
     329             : 
     330             :       ! Add first basis for the mean values.
     331             :       !------------------------------------------
     332           0 :       this%basis(:,begchunk:endchunk,1) = invSqrt4pi
     333             : 
     334             :       ! Loop over the remaining basis functions
     335             :       !---------------------------------------
     336           0 :       do nn=2,this%nbas
     337           0 :          nb = nn-1
     338             : 
     339             :          ! Generate coefs for the basis
     340             :          !------------------------------
     341           0 :          call sh_gen_basis_coefs(nb,0,Bcoef)
     342             : 
     343             :          ! Create basis for the coefs at each ncol gridpoint
     344             :          !---------------------------------------------------
     345           0 :          do lchnk=begchunk,endchunk
     346           0 :             ncols = get_ncols_p(lchnk)
     347           0 :             do cc = 1,ncols
     348           0 :                call sh_create_basis(nb,0,Clats(cc,lchnk),Bcoef,this%basis(cc,lchnk,nn))
     349             :             end do
     350             :          end do
     351             :       end do ! nn=2,this%nbas
     352             : 
     353             :       ! Numerically normalize the basis funnctions
     354             :       !--------------------------------------------------------------
     355           0 :       do nn=1,this%nbas
     356           0 :          count = 0
     357           0 :          do lchnk=begchunk,endchunk
     358           0 :             ncols = get_ncols_p(lchnk)
     359           0 :             do cc = 1,ncols
     360           0 :                count=count+1
     361           0 :                Bsum(count,nn) = this%basis(cc,lchnk,nn)*this%basis(cc,lchnk,nn)*this%area(cc,lchnk)
     362             :             end do
     363             :          end do
     364             :       end do ! nn=1,this%nbas
     365             : 
     366           0 :       call shr_reprosum_calc(Bsum, Bnorm, count, nlcols, this%nbas, gbl_count=ngcols_p, commid=mpicom)
     367             : 
     368           0 :       do nn=1,this%nbas
     369           0 :          do lchnk=begchunk,endchunk
     370           0 :             ncols = get_ncols_p(lchnk)
     371           0 :             this%basis(:ncols,lchnk,nn) = this%basis(:ncols,lchnk,nn)/sqrt(Bnorm(nn))
     372             :          end do
     373             :       end do ! nn=1,this%nbas
     374             : 
     375             :       ! Compute covariance matrix for basis functions
     376             :       ! (Yes, they are theoretically orthonormal, but lets make sure)
     377             :       !---------------------------------------------------------------
     378           0 :       cnum = 0
     379           0 :       do nn= 1,this%nbas
     380           0 :          do n2=nn,this%nbas
     381           0 :             cnum = cnum + 1
     382           0 :             count = 0
     383           0 :             do lchnk=begchunk,endchunk
     384           0 :                ncols = get_ncols_p(lchnk)
     385           0 :                do cc = 1,ncols
     386           0 :                   count=count+1
     387           0 :                   Csum(count,cnum) = this%basis(cc,lchnk,nn)*this%basis(cc,lchnk,n2)*this%area(cc,lchnk)
     388             :                end do
     389             :             end do
     390             : 
     391             :          end do
     392             :       end do
     393             : 
     394           0 :       call shr_reprosum_calc(Csum, Cvec, count, nlcols, Cvec_len, gbl_count=ngcols_p, commid=mpicom)
     395             : 
     396           0 :       cnum = 0
     397           0 :       do nn= 1,this%nbas
     398           0 :          do n2=nn,this%nbas
     399           0 :             cnum = cnum + 1
     400           0 :             Bcov(nn,n2) = Cvec(cnum)
     401           0 :             Bcov(n2,nn) = Cvec(cnum)
     402             :          end do
     403             :       end do
     404             : 
     405             :       ! Invert to get the basis amplitude map
     406             :       !--------------------------------------
     407           0 :       call Invert_Matrix(Bcov,this%nbas,this%map)
     408             : 
     409             :       ! End Routine
     410             :       !------------
     411           0 :       deallocate(Clats)
     412           0 :       deallocate(Bcoef)
     413           0 :       deallocate(Csum )
     414           0 :       deallocate(Cvec )
     415           0 :       deallocate(Bsum )
     416           0 :       deallocate(Bnorm)
     417           0 :       deallocate(Bcov )
     418             : 
     419           0 :     end subroutine init_ZonalMean
     420             :     !=======================================================================
     421             : 
     422             : 
     423             :     !=======================================================================
     424           0 :     subroutine calc_ZonalMean_2Damps(this,I_Gdata,O_Bamp)
     425             :       !
     426             :       ! calc_ZonalMean_2Damps: Given 2D data values for the ncol gridpoints,
     427             :       !                        compute the zonal mean basis amplitudes.
     428             :       !=====================================================================
     429             :       !
     430             :       ! Passed Variables
     431             :       !------------------
     432             :       class(ZonalMean_t) :: this
     433             :       real(r8),intent(in ) :: I_Gdata(pcols,begchunk:endchunk)
     434             :       real(r8),intent(out) :: O_Bamp(:)
     435             :       !
     436             :       ! Local Values
     437             :       !--------------
     438           0 :       real(r8),allocatable :: Csum(:,:)
     439           0 :       real(r8),allocatable :: Gcov(:)
     440             :       integer :: nn,n2,ncols,lchnk,cc
     441             :       integer :: nlcols, count, astat
     442             : 
     443             :       character(len=*), parameter :: subname = 'calc_ZonalMean_2Damps'
     444             : 
     445           0 :       nlcols = get_nlcols_p()
     446             : 
     447           0 :       allocate(Gcov(this%nbas), stat=astat)
     448           0 :       call handle_allocate_error(astat, subname, 'Gcov')
     449           0 :       allocate(Csum(nlcols, this%nbas), stat=astat)
     450           0 :       call handle_allocate_error(astat, subname, 'Csum')
     451           0 :       Csum(:,:) = 0._r8
     452             : 
     453             :       ! Compute Covariance with input data and basis functions
     454             :       !--------------------------------------------------------
     455           0 :       do nn= 1,this%nbas
     456           0 :         count = 0
     457           0 :         do lchnk=begchunk,endchunk
     458           0 :           ncols = get_ncols_p(lchnk)
     459           0 :           do cc = 1,ncols
     460           0 :             count=count+1
     461           0 :             Csum(count,nn) = I_Gdata(cc,lchnk)*this%basis(cc,lchnk,nn)*this%area(cc,lchnk)
     462             :           end do
     463             :         end do
     464             :       end do
     465             : 
     466           0 :       call shr_reprosum_calc(Csum, Gcov, count, nlcols, this%nbas, gbl_count=ngcols_p, commid=mpicom)
     467             : 
     468             :       ! Multiply by map to get the amplitudes
     469             :       !-------------------------------------------
     470           0 :       do nn=1,this%nbas
     471           0 :         O_Bamp(nn) = 0._r8
     472           0 :         do n2=1,this%nbas
     473           0 :           O_Bamp(nn) = O_Bamp(nn) + this%map(n2,nn)*Gcov(n2)
     474             :         end do
     475             :       end do
     476             : 
     477             :       ! End Routine
     478             :       !------------
     479           0 :       deallocate(Csum)
     480           0 :       deallocate(Gcov)
     481             : 
     482           0 :     end subroutine calc_ZonalMean_2Damps
     483             :     !=======================================================================
     484             : 
     485             : 
     486             :     !=======================================================================
     487           0 :     subroutine calc_ZonalMean_3Damps(this,I_Gdata,O_Bamp)
     488             :       !
     489             :       ! calc_ZonalMean_3Damps: Given 3D data values for the ncol,nlev gridpoints,
     490             :       !                        compute the zonal mean basis amplitudes.
     491             :       !=====================================================================
     492             :       !
     493             :       ! Passed Variables
     494             :       !------------------
     495             :       class(ZonalMean_t) :: this
     496             :       real(r8),intent(in ):: I_Gdata(:,:,begchunk:)
     497             :       real(r8),intent(out):: O_Bamp (:,:)
     498             :       !
     499             :       ! Local Values
     500             :       !--------------
     501           0 :       real(r8),allocatable:: Csum (:,:)
     502           0 :       real(r8),allocatable:: Gcov (:)
     503             :       integer:: nn,n2,ncols,lchnk,cc
     504             :       integer:: Nsum,ns,ll
     505             :       integer :: nlcols, count, astat
     506             : 
     507             :       integer :: nlev
     508             :       character(len=*), parameter :: subname = 'calc_ZonalMean_3Damps'
     509             : 
     510           0 :       nlev = size(I_Gdata,dim=2)
     511             : 
     512           0 :       nlcols = get_nlcols_p()
     513           0 :       allocate(Gcov(this%nbas), stat=astat)
     514           0 :       call handle_allocate_error(astat, subname, 'Gcov')
     515           0 :       allocate(Csum(nlcols, this%nbas), stat=astat)
     516           0 :       call handle_allocate_error(astat, subname, 'Csum')
     517             : 
     518           0 :       Csum(:,:) = 0._r8
     519           0 :       O_Bamp(:,:) = 0._r8
     520             : 
     521             :       ! Compute Covariance with input data and basis functions
     522             :       !--------------------------------------------------------
     523           0 :       do ll= 1,nlev
     524             : 
     525           0 :          Csum(:,:) = 0._r8
     526           0 :          Gcov(:) = 0._r8
     527             : 
     528           0 :          do nn= 1,this%nbas
     529           0 :             count = 0
     530           0 :             do lchnk=begchunk,endchunk
     531           0 :                ncols = get_ncols_p(lchnk)
     532           0 :                do cc = 1,ncols
     533           0 :                   count=count+1
     534           0 :                   Csum(count,nn) = I_Gdata(cc,ll,lchnk)*this%basis(cc,lchnk,nn)*this%area(cc,lchnk)
     535             :                end do
     536             :             end do
     537             :          end do
     538             : 
     539           0 :          call shr_reprosum_calc(Csum, Gcov, count, nlcols, this%nbas, gbl_count=ngcols_p, commid=mpicom)
     540             : 
     541             :          ! Multiply by map to get the amplitudes
     542             :          !-------------------------------------------
     543           0 :          do nn=1,this%nbas
     544           0 :             O_Bamp(nn,ll) = 0._r8
     545           0 :             do n2=1,this%nbas
     546           0 :                O_Bamp(nn,ll) = O_Bamp(nn,ll) + this%map(n2,nn)*Gcov(n2)
     547             :             end do
     548             :          end do
     549             : 
     550             :       end do
     551             : 
     552             :       ! End Routine
     553             :       !------------
     554           0 :       deallocate(Csum)
     555           0 :       deallocate(Gcov)
     556             : 
     557           0 :     end subroutine calc_ZonalMean_3Damps
     558             :     !=======================================================================
     559             : 
     560             : 
     561             :     !=======================================================================
     562           0 :     subroutine eval_ZonalMean_2Dgrid(this,I_Bamp,O_Gdata)
     563             :       !
     564             :       ! eval_ZonalMean_2Dgrid: Given the zonal mean basis amplitudes,
     565             :       !                        compute 2D data values for the ncol gridpoints.
     566             :       !=====================================================================
     567             :       !
     568             :       ! Passed Variables
     569             :       !------------------
     570             :       class(ZonalMean_t) :: this
     571             :       real(r8),intent(in ):: I_Bamp (:)
     572             :       real(r8),intent(out):: O_Gdata(pcols,begchunk:endchunk)
     573             :       !
     574             :       ! Local Values
     575             :       !--------------
     576             :       integer:: nn,ncols,lchnk,cc
     577             : 
     578           0 :       O_Gdata(:,:) = 0._r8
     579             : 
     580             :       ! Construct grid values from basis amplitudes.
     581             :       !--------------------------------------------------
     582             : 
     583           0 :       do nn=1,this%nbas
     584           0 :          do lchnk=begchunk,endchunk
     585           0 :             ncols = get_ncols_p(lchnk)
     586           0 :             do cc = 1,ncols
     587           0 :                O_Gdata(cc,lchnk) = O_Gdata(cc,lchnk) + (I_Bamp(nn)*this%basis(cc,lchnk,nn))
     588             :             end do
     589             :          end do
     590             :       end do
     591             : 
     592           0 :     end subroutine eval_ZonalMean_2Dgrid
     593             :     !=======================================================================
     594             : 
     595             : 
     596             :     !=======================================================================
     597           0 :     subroutine eval_ZonalMean_3Dgrid(this,I_Bamp,O_Gdata)
     598             :       !
     599             :       ! eval_ZonalMean_3Dgrid: Given the zonal mean basis amplitudes,
     600             :       !                      compute 3D data values for the ncol,nlev gridpoints.
     601             :       !=====================================================================
     602             :       !
     603             :       ! Passed Variables
     604             :       !------------------
     605             :       class(ZonalMean_t) :: this
     606             :       real(r8),intent(in ):: I_Bamp (:,:)
     607             :       real(r8),intent(out):: O_Gdata(:,:,begchunk:)
     608             :       !
     609             :       ! Local Values
     610             :       !--------------
     611             :       integer:: nn,ncols,lchnk,cc
     612             :       integer:: ll
     613             : 
     614             :       integer :: nlev
     615           0 :       nlev = size(O_Gdata,dim=2)
     616             : 
     617           0 :       O_Gdata(:,:,:) = 0._r8
     618             : 
     619             :       ! Construct grid values from basis amplitudes.
     620             :       !--------------------------------------------------
     621             : 
     622           0 :       do ll = 1,nlev
     623           0 :          do nn=1,this%nbas
     624           0 :             do lchnk=begchunk,endchunk
     625           0 :                ncols = get_ncols_p(lchnk)
     626           0 :                do cc = 1,ncols
     627           0 :                   O_Gdata(cc,ll,lchnk) = O_Gdata(cc,ll,lchnk) + (I_Bamp(nn,ll)*this%basis(cc,lchnk,nn))
     628             :                end do
     629             :             end do
     630             :          end do
     631             :       end do
     632             : 
     633           0 :     end subroutine eval_ZonalMean_3Dgrid
     634             :     !=======================================================================
     635             : 
     636             :     !=======================================================================
     637        1536 :     subroutine final_ZonalMean(this)
     638             :       class(ZonalMean_t) :: this
     639             : 
     640        1536 :       if(allocated(this%area )) deallocate(this%area)
     641        1536 :       if(allocated(this%basis)) deallocate(this%basis)
     642        1536 :       if(allocated(this%map  )) deallocate(this%map)
     643             : 
     644        1536 :     end subroutine final_ZonalMean
     645             :     !=======================================================================
     646             : 
     647             :     !=======================================================================
     648           0 :     subroutine init_ZonalProfile(this,IO_lats,IO_area,I_nlat,I_nbas,GEN_GAUSSLATS)
     649             :       !
     650             :       ! init_ZonalProfile: Initialize the ZonalProfile data structure for the
     651             :       !                    given nlat gridpoints. It is assumed that the domain
     652             :       !                    of these gridpoints of the profile span latitudes
     653             :       !                    from SP to NP.
     654             :       !                    The representation of basis functions functions is
     655             :       !                    normalized w.r.t integration over the sphere so that
     656             :       !                    when configured for tha same number of basis functions,
     657             :       !                    the calculated amplitudes are interchangable with
     658             :       !                    those for the ZonalMean_t class.
     659             :       !
     660             :       !                    The optional GEN_GAUSSLATS flag allows for the
     661             :       !                    generation of Gaussian latitudes. The generated grid
     662             :       !                    over-writes the values of IO_lats/IO_area passed by
     663             :       !                    the user.
     664             :       !=====================================================================
     665             :       !
     666             :       ! Passed Variables
     667             :       !------------------
     668             :       class(ZonalProfile_t) :: this
     669             :       real(r8)     ,intent(inout):: IO_lats(:)
     670             :       real(r8)     ,intent(inout):: IO_area(:)
     671             :       integer         ,intent(in):: I_nlat
     672             :       integer         ,intent(in):: I_nbas
     673             :       logical,optional,intent(in):: GEN_GAUSSLATS
     674             :       !
     675             :       ! Local Values
     676             :       !--------------
     677           0 :       real(r8),allocatable:: Clats(:)
     678           0 :       real(r8),allocatable:: Bcoef(:)
     679           0 :       real(r8),allocatable:: Bcov (:,:)
     680             :       real(r8):: Bnorm
     681             :       integer :: ii,nn,n2,nb,ierr, astat
     682             :       logical :: generate_lats
     683             : 
     684             :       character(len=*), parameter :: subname = 'init_ZonalProfile'
     685             : 
     686           0 :       generate_lats = .false.
     687             : 
     688           0 :       if (present(GEN_GAUSSLATS)) then
     689           0 :          generate_lats = GEN_GAUSSLATS
     690             :       end if
     691             : 
     692             :       ! Allocate space
     693             :       !-----------------
     694           0 :       if(allocated(this%area )) deallocate(this%area)
     695           0 :       if(allocated(this%basis)) deallocate(this%basis)
     696           0 :       if(allocated(this%map  )) deallocate(this%map)
     697             : 
     698           0 :       this%nlat = I_nlat
     699           0 :       this%nbas = I_nbas
     700           0 :       allocate(this%area (I_nlat), stat=astat)
     701           0 :       call handle_allocate_error(astat, subname, 'this%area')
     702           0 :       allocate(this%basis(I_nlat,I_nbas), stat=astat)
     703           0 :       call handle_allocate_error(astat, subname, 'this%basis')
     704           0 :       allocate(this%map  (I_nbas,I_nbas), stat=astat)
     705           0 :       call handle_allocate_error(astat, subname, 'this%map')
     706             : 
     707           0 :       allocate(Clats(I_nlat), stat=astat)
     708           0 :       call handle_allocate_error(astat, subname, 'Clats')
     709           0 :       allocate(Bcoef(I_nbas/2+1), stat=astat)
     710           0 :       call handle_allocate_error(astat, subname, 'Bcoef')
     711           0 :       allocate(Bcov (I_nbas,I_nbas), stat=astat)
     712           0 :       call handle_allocate_error(astat, subname, 'Bcov')
     713             : 
     714             :       ! Optionally create the Latitude Gridpoints
     715             :       ! and their associated area weights. Otherwise
     716             :       ! they need to be supplied by the user.
     717             :       !-----------------------------------------------
     718           0 :       if(generate_lats) then
     719             : 
     720             :         ! Create a Gaussian grid from SP to NP
     721             :         !--------------------------------------
     722           0 :         call sh_create_gaus_grid(I_nlat,Clats,IO_area,ierr)
     723           0 :         if (ierr/=0) then
     724           0 :            call endrun('init_ZonalProfile: Error creating Gaussian grid')
     725             :         end if
     726             : 
     727             :         ! Convert generated colatitudes SP->NP to Lats and convert
     728             :         ! to degrees and scale the area for global 2D integrals
     729             :         !-----------------------------------------------------------
     730           0 :         do nn=1,I_nlat
     731           0 :           IO_lats(nn) = (45._r8*Clats(nn)/qrtrPI) - 90._r8
     732           0 :           IO_area(nn) = IO_area(nn)*twoPI
     733             :         end do
     734             :       else
     735             :         ! Convert Latitudes to SP->NP colatitudes in radians
     736             :         !----------------------------------------------------
     737           0 :         do nn=1,I_nlat
     738           0 :           Clats(nn) = (IO_lats(nn) + 90._r8)*qrtrPI/45._r8
     739             :         end do
     740             :       endif
     741             : 
     742             :       ! Copy the area weights for each nlat
     743             :       ! gridpoint to the data structure
     744             :       !---------------------------------------
     745           0 :       this%area(1:I_nlat) = IO_area(1:I_nlat)
     746             : 
     747             :       ! Add first basis for the mean values.
     748             :       !------------------------------------------
     749           0 :       this%basis(:,1) = invSqrt4pi
     750             :       Bnorm = 0._r8
     751           0 :       do ii=1,I_nlat
     752           0 :         Bnorm = Bnorm + (this%basis(ii,1)*this%basis(ii,1)*this%area(ii))
     753             :       end do
     754           0 :       this%basis(:,1) = this%basis(:,1)/sqrt(Bnorm)
     755             : 
     756             :       ! Loop over the remaining basis functions
     757             :       !---------------------------------------
     758           0 :       do nn=2,I_nbas
     759           0 :         nb = nn-1
     760             : 
     761             :         ! Generate coefs for the basis
     762             :         !------------------------------
     763           0 :         call sh_gen_basis_coefs(nb,0,Bcoef)
     764             : 
     765             :         ! Create an un-normalized basis for the
     766             :         ! coefs at each nlat gridpoint
     767             :         !---------------------------------------
     768           0 :         do ii=1,I_nlat
     769           0 :           call sh_create_basis(nb,0,Clats(ii),Bcoef,this%basis(ii,nn))
     770             :         end do
     771             : 
     772             :         ! Numerically normalize the basis funnction
     773             :         !--------------------------------------------------------------
     774             :         Bnorm = 0._r8
     775           0 :         do ii=1,I_nlat
     776           0 :           Bnorm = Bnorm + (this%basis(ii,nn)*this%basis(ii,nn)*this%area(ii))
     777             :         end do
     778           0 :         this%basis(:,nn) = this%basis(:,nn)/sqrt(Bnorm)
     779             : 
     780             :       end do ! nn=1,I_nbas
     781             : 
     782             :       ! Compute covariance matrix for basis functions
     783             :       ! (Yes, they are theoretically orthonormal, but lets make sure)
     784             :       !--------------------------------------------------------------
     785           0 :       do nn=1,I_nbas
     786           0 :         do n2=1,I_nbas
     787           0 :           Bcov(nn,n2) = 0._r8
     788           0 :           do ii=1,I_nlat
     789           0 :             Bcov(nn,n2) = Bcov(nn,n2) + (this%basis(ii,nn)*this%basis(ii,n2)*this%area(ii))
     790             :           end do
     791             :         end do
     792             :       end do
     793             : 
     794             :       ! Invert to get the basis amplitude map
     795             :       !--------------------------------------
     796           0 :       call Invert_Matrix(Bcov,I_nbas,this%map)
     797             : 
     798             :       ! End Routine
     799             :       !------------
     800           0 :       deallocate(Clats)
     801           0 :       deallocate(Bcoef)
     802           0 :       deallocate(Bcov )
     803             : 
     804           0 :     end subroutine init_ZonalProfile
     805             :     !=======================================================================
     806             : 
     807             : 
     808             :     !=======================================================================
     809           0 :     subroutine calc_ZonalProfile_1Damps(this,I_Zdata,O_Bamp)
     810             :       !
     811             :       ! calc_ZonalProfile_1Damps: Given 1D data values for the nlat zonal
     812             :       !                           profiles gridpoints, compute the zonal
     813             :       !                           profile basis amplitudes.
     814             :       !=====================================================================
     815             :       !
     816             :       ! Passed Variables
     817             :       !------------------
     818             :       class(ZonalProfile_t):: this
     819             :       real(r8),intent(in ):: I_Zdata(:)
     820             :       real(r8),intent(out):: O_Bamp (:)
     821             :       !
     822             :       ! Local Values
     823             :       !--------------
     824           0 :       real(r8),allocatable:: Gcov(:)
     825             :       integer:: ii,nn,n2, astat
     826             :       character(len=*), parameter :: subname = 'calc_ZonalProfile_1Damps'
     827             : 
     828             :       ! Compute Covariance with input data and basis functions
     829             :       !--------------------------------------------------------
     830           0 :       allocate(Gcov(this%nbas), stat=astat)
     831           0 :       call handle_allocate_error(astat, subname, 'Gcov')
     832           0 :       do nn=1,this%nbas
     833           0 :         Gcov(nn) = 0._r8
     834           0 :         do ii=1,this%nlat
     835           0 :           Gcov(nn) = Gcov(nn) + (I_Zdata(ii)*this%basis(ii,nn)*this%area(ii))
     836             :         end do
     837             :       end do
     838             : 
     839             :       ! Multiply by map to get the amplitudes
     840             :       !-------------------------------------------
     841           0 :       do nn=1,this%nbas
     842           0 :         O_Bamp(nn) = 0._r8
     843           0 :         do n2=1,this%nbas
     844           0 :           O_Bamp(nn) = O_Bamp(nn) + this%map(n2,nn)*Gcov(n2)
     845             :         end do
     846             :       end do
     847             : 
     848           0 :       deallocate(Gcov)
     849             : 
     850           0 :     end subroutine calc_ZonalProfile_1Damps
     851             :     !=======================================================================
     852             : 
     853             : 
     854             :     !=======================================================================
     855           0 :     subroutine calc_ZonalProfile_2Damps(this,I_Zdata,O_Bamp)
     856             :       !
     857             :       ! calc_ZonalProfile_2Damps: Given 2D data values for the nlat,nlev zonal
     858             :       !                           profiles gridpoints, compute the zonal
     859             :       !                           profile basis amplitudes.
     860             :       !=====================================================================
     861             :       !
     862             :       ! Passed Variables
     863             :       !------------------
     864             :       class(ZonalProfile_t):: this
     865             :       real(r8),intent(in ):: I_Zdata(:,:)
     866             :       real(r8),intent(out):: O_Bamp (:,:)
     867             :       !
     868             :       ! Local Values
     869             :       !--------------
     870           0 :       real(r8),allocatable:: Gcov(:,:)
     871             :       integer:: ii,nn,n2,ilev
     872             : 
     873             :       integer :: nlev, astat
     874             :       character(len=*), parameter :: subname = 'calc_ZonalProfile_2Damps'
     875             : 
     876           0 :       nlev = size(I_Zdata,dim=2)
     877             : 
     878             :       ! Compute Covariance with input data and basis functions
     879             :       !--------------------------------------------------------
     880           0 :       allocate(Gcov(this%nbas,nlev), stat=astat)
     881           0 :       call handle_allocate_error(astat, subname, 'Gcov')
     882           0 :       do ilev=1,nlev
     883           0 :          do nn=1,this%nbas
     884           0 :             Gcov(nn,ilev) = 0._r8
     885           0 :             do ii=1,this%nlat
     886           0 :                Gcov(nn,ilev) = Gcov(nn,ilev) + (I_Zdata(ii,ilev)*this%basis(ii,nn)*this%area(ii))
     887             :             end do
     888             :          end do
     889             :       end do
     890             : 
     891             :       ! Multiply by map to get the amplitudes
     892             :       !-------------------------------------------
     893           0 :       do ilev=1,nlev
     894           0 :          do nn=1,this%nbas
     895           0 :             O_Bamp(nn,ilev) = 0._r8
     896           0 :             do n2=1,this%nbas
     897           0 :                O_Bamp(nn,ilev) = O_Bamp(nn,ilev) + this%map(n2,nn)*Gcov(n2,ilev)
     898             :             end do
     899             :          end do
     900             :       end do
     901           0 :       deallocate(Gcov)
     902             : 
     903           0 :     end subroutine calc_ZonalProfile_2Damps
     904             :     !=======================================================================
     905             : 
     906             : 
     907             :     !=======================================================================
     908           0 :     subroutine eval_ZonalProfile_1Dgrid(this,I_Bamp,O_Zdata)
     909             :       !
     910             :       ! eval_ZonalProfile_1Dgrid: Given the zonal profile basis amplitudes,
     911             :       !                           compute 1D data values for the nlat gridpoints.
     912             :       !=====================================================================
     913             :       !
     914             :       ! Passed Variables
     915             :       !------------------
     916             :       class(ZonalProfile_t):: this
     917             :       real(r8),intent(in ):: I_Bamp (:)
     918             :       real(r8),intent(out):: O_Zdata(:)
     919             :       !
     920             :       ! Local Values
     921             :       !--------------
     922             :       integer:: ii,nn
     923             : 
     924             :       ! Construct grid values from basis amplitudes.
     925             :       !--------------------------------------------------
     926           0 :       O_Zdata(1:this%nlat) = 0._r8
     927           0 :       do nn=1,this%nbas
     928           0 :         do ii=1,this%nlat
     929           0 :           O_Zdata(ii) = O_Zdata(ii) + (I_Bamp(nn)*this%basis(ii,nn))
     930             :         end do
     931             :       end do
     932             : 
     933           0 :     end subroutine eval_ZonalProfile_1Dgrid
     934             :     !=======================================================================
     935             : 
     936             : 
     937             :     !=======================================================================
     938           0 :     subroutine eval_ZonalProfile_2Dgrid(this,I_Bamp,O_Zdata)
     939             :       !
     940             :       ! eval_ZonalProfile_2Dgrid: Given the zonal profile basis amplitudes,
     941             :       !                           compute 2D data values for the nlat,nlev gridpoints.
     942             :       !=====================================================================
     943             :       !
     944             :       ! Passed Variables
     945             :       !------------------
     946             :       class(ZonalProfile_t):: this
     947             :       real(r8),intent(in ):: I_Bamp (:,:)
     948             :       real(r8),intent(out):: O_Zdata(:,:)
     949             :       !
     950             :       ! Local Values
     951             :       !--------------
     952             :       integer:: ii,nn,ilev
     953             : 
     954             :       integer :: nlev
     955             : 
     956           0 :       nlev = size(I_Bamp,dim=2)
     957             : 
     958             :       ! Construct grid values from basis amplitudes.
     959             :       !--------------------------------------------------
     960           0 :       O_Zdata(1:this%nlat,1:nlev) = 0._r8
     961           0 :       do nn=1,this%nbas
     962           0 :         do ilev=1,nlev
     963           0 :           do ii=1,this%nlat
     964           0 :             O_Zdata(ii,ilev) = O_Zdata(ii,ilev) + (I_Bamp(nn,ilev)*this%basis(ii,nn))
     965             :           end do
     966             :         end do
     967             :       end do
     968             : 
     969           0 :     end subroutine eval_ZonalProfile_2Dgrid
     970             :     !=======================================================================
     971             : 
     972             :     !=======================================================================
     973           0 :     subroutine final_ZonalProfile(this)
     974             :       class(ZonalProfile_t) :: this
     975             : 
     976           0 :       if(allocated(this%area )) deallocate(this%area)
     977           0 :       if(allocated(this%basis)) deallocate(this%basis)
     978           0 :       if(allocated(this%map  )) deallocate(this%map)
     979             : 
     980           0 :     end subroutine final_ZonalProfile
     981             :     !=======================================================================
     982             : 
     983             :     !=======================================================================
     984           0 :     subroutine init_ZonalAverage(this,IO_lats,IO_area,I_nlat,GEN_GAUSSLATS)
     985             :       !
     986             :       ! init_ZonalAverage: Initialize the ZonalAverage data structure for the
     987             :       !                    given nlat gridpoints. It is assumed that the domain
     988             :       !                    of these gridpoints of the profile span latitudes
     989             :       !                    from SP to NP.
     990             :       !
     991             :       !                    The optional GEN_GAUSSLATS flag allows for the
     992             :       !                    generation of Gaussian latitudes. The generated grid
     993             :       !                    over-writes the values of IO_lats/IO_area passed by
     994             :       !                    the user.
     995             :       !=====================================================================
     996             :       !
     997             :       ! Passed Variables
     998             :       !------------------
     999             :       class(ZonalAverage_t) :: this
    1000             :       real(r8)     ,intent(inout):: IO_lats(:)
    1001             :       real(r8)     ,intent(inout):: IO_area(:)
    1002             :       integer         ,intent(in):: I_nlat
    1003             :       logical,optional,intent(in):: GEN_GAUSSLATS
    1004             :       !
    1005             :       ! Local Values
    1006             :       !--------------
    1007           0 :       real(r8),allocatable:: Clats (:)
    1008           0 :       real(r8),allocatable:: Glats (:,:)
    1009           0 :       real(r8),allocatable:: BinLat(:)
    1010           0 :       real(r8),allocatable:: Asum  (:,:)
    1011           0 :       real(r8),allocatable:: Anorm (:)
    1012             :       real(r8):: area(pcols),rlat
    1013             :       integer :: nn,jj,ierr, astat
    1014             :       integer :: ncols,lchnk,cc,jlat
    1015             :       integer :: nlcols, count
    1016             :       logical :: generate_lats
    1017             :       character(len=*), parameter :: subname = 'init_ZonalAverage'
    1018             : 
    1019           0 :       generate_lats = .false.
    1020             : 
    1021           0 :       if (present(GEN_GAUSSLATS)) then
    1022           0 :          generate_lats = GEN_GAUSSLATS
    1023             :       end if
    1024             : 
    1025           0 :       nlcols = get_nlcols_p()
    1026             : 
    1027             :       ! Allocate space
    1028             :       !-----------------
    1029           0 :       if(allocated(this%area   )) deallocate(this%area)
    1030           0 :       if(allocated(this%a_norm )) deallocate(this%a_norm)
    1031           0 :       if(allocated(this%area_g )) deallocate(this%area_g)
    1032           0 :       if(allocated(this%idx_map)) deallocate(this%idx_map)
    1033             : 
    1034           0 :       this%nlat = I_nlat
    1035           0 :       allocate(this%area   (I_nlat), stat=astat)
    1036           0 :       call handle_allocate_error(astat, subname, 'this%area')
    1037           0 :       allocate(this%a_norm (I_nlat), stat=astat)
    1038           0 :       call handle_allocate_error(astat, subname, 'this%a_norm')
    1039           0 :       allocate(this%area_g (pcols,begchunk:endchunk), stat=astat)
    1040           0 :       call handle_allocate_error(astat, subname, 'this%area_g')
    1041           0 :       allocate(this%idx_map(pcols,begchunk:endchunk), stat=astat)
    1042           0 :       call handle_allocate_error(astat, subname, 'this%idx_map')
    1043             : 
    1044           0 :       allocate(Clats (I_nlat), stat=astat)
    1045           0 :       call handle_allocate_error(astat, subname, 'Clats')
    1046           0 :       allocate(BinLat(I_nlat+1), stat=astat)
    1047           0 :       call handle_allocate_error(astat, subname, 'BinLat')
    1048           0 :       allocate(Glats (pcols,begchunk:endchunk), stat=astat)
    1049           0 :       call handle_allocate_error(astat, subname, 'Glats')
    1050           0 :       allocate(Asum  (nlcols,I_nlat), stat=astat)
    1051           0 :       call handle_allocate_error(astat, subname, 'Asum')
    1052           0 :       allocate(Anorm (I_nlat), stat=astat)
    1053           0 :       call handle_allocate_error(astat, subname, 'Anorm')
    1054             : 
    1055             :       ! Optionally create the Latitude Gridpoints
    1056             :       ! and their associated area weights. Otherwise
    1057             :       ! they need to be supplied by the user.
    1058             :       !-----------------------------------------------
    1059           0 :       if(generate_lats) then
    1060             : 
    1061             :         ! Create a Gaussin grid from SP to NP
    1062             :         !--------------------------------------
    1063           0 :         call sh_create_gaus_grid(this%nlat,Clats,IO_area,ierr)
    1064           0 :         if (ierr/=0) then
    1065           0 :            call endrun('init_ZonalAverage: Error creating Gaussian grid')
    1066             :         end if
    1067             : 
    1068             :         ! Convert generated colatitudes SP->NP to Lats and convert
    1069             :         ! to degrees and scale the area for global 2D integrals
    1070             :         !-----------------------------------------------------------
    1071           0 :         do nn=1,this%nlat
    1072           0 :           IO_lats(nn) = (45._r8*Clats(nn)/qrtrPI) - 90._r8
    1073           0 :           IO_area(nn) = IO_area(nn)*twoPI
    1074             :         end do
    1075             :       else
    1076             :         ! Convert Latitudes to SP->NP colatitudes in radians
    1077             :         !----------------------------------------------------
    1078           0 :         do nn=1,this%nlat
    1079           0 :           Clats(nn) = (IO_lats(nn) + 90._r8)*qrtrPI/45._r8
    1080             :         end do
    1081             :       endif
    1082             : 
    1083             :       ! Copy the Lat grid area weights to the data structure
    1084             :       !-----------------------------------------------------
    1085           0 :       this%area(1:this%nlat) = IO_area(1:this%nlat)
    1086             : 
    1087             :       ! Save a copy of the area weights for each 2D gridpoint
    1088             :       ! and convert Latitudes to SP->NP colatitudes in radians
    1089             :       !-------------------------------------------------------
    1090           0 :       do lchnk=begchunk,endchunk
    1091           0 :         ncols = get_ncols_p(lchnk)
    1092           0 :         call get_wght_all_p(lchnk, ncols, area)
    1093           0 :         do cc = 1,ncols
    1094           0 :           rlat=get_rlat_p(lchnk,cc)
    1095           0 :           this%area_g(cc,lchnk) = area(cc)
    1096           0 :           Glats      (cc,lchnk) = rlat + halfPI
    1097             :         end do
    1098             :       end do
    1099             : 
    1100             :       ! Set boundaries for Latitude bins
    1101             :       !-----------------------------------
    1102           0 :       BinLat(1)           = 0._r8
    1103           0 :       BinLat(this%nlat+1) = pi
    1104           0 :       do nn=2,this%nlat
    1105           0 :         BinLat(nn) = (Clats(nn-1)+Clats(nn))/2._r8
    1106             :       end do
    1107             : 
    1108             :       ! Loop over 2D gridpoints and determine its lat bin index
    1109             :       !---------------------------------------------------------
    1110           0 :       do lchnk=begchunk,endchunk
    1111           0 :         ncols = get_ncols_p(lchnk)
    1112           0 :         do cc = 1,ncols
    1113           0 :           jlat = -1
    1114           0 :           if((Glats(cc,lchnk)<=BinLat(2)).and. &
    1115             :              (Glats(cc,lchnk)>=BinLat(1))      ) then
    1116           0 :             jlat = 1
    1117           0 :           elseif((Glats(cc,lchnk)>=BinLat(this%nlat)  ).and. &
    1118           0 :                  (Glats(cc,lchnk)<=BinLat(this%nlat+1))      ) then
    1119           0 :             jlat = this%nlat
    1120             :           else
    1121           0 :             do jj=2,(this%nlat-1)
    1122           0 :               if((Glats(cc,lchnk)>BinLat(jj  )).and. &
    1123           0 :                  (Glats(cc,lchnk)<=BinLat(jj+1))      ) then
    1124           0 :                 jlat = jj
    1125           0 :                 exit
    1126             :               endif
    1127             :             end do
    1128             :           endif
    1129           0 :           if (jlat<1) then
    1130           0 :             call endrun('ZonalAverage init ERROR: jlat not in range')
    1131             :           endif
    1132           0 :           this%idx_map(cc,lchnk) = jlat
    1133             :         end do
    1134             :       end do
    1135             : 
    1136             :       ! Initialize 2D Area sums for each bin
    1137             :       !--------------------------------------
    1138           0 :       Asum(:,:) = 0._r8
    1139           0 :       Anorm(:) = 0._r8
    1140           0 :       count = 0
    1141           0 :       do lchnk=begchunk,endchunk
    1142           0 :         ncols = get_ncols_p(lchnk)
    1143           0 :         do cc = 1,ncols
    1144           0 :           jlat = this%idx_map(cc,lchnk)
    1145           0 :           count=count+1
    1146           0 :           Asum(count,jlat) = this%area_g(cc,lchnk)
    1147             :         end do
    1148             :       end do
    1149             : 
    1150           0 :       call shr_reprosum_calc(Asum, Anorm, count, nlcols, I_nlat, gbl_count=ngcols_p, commid=mpicom)
    1151             : 
    1152           0 :       this%a_norm = Anorm
    1153             : 
    1154           0 :       if (.not.all(Anorm(:)>0._r8)) then
    1155           0 :          write(iulog,*) 'init_ZonalAverage -- ERROR in Anorm values: '
    1156           0 :          do jlat = 1,I_nlat
    1157           0 :             if (.not.Anorm(jlat)>0._r8) then
    1158           0 :                write(iulog,*) ' Anorm(',jlat,'): ', Anorm(jlat)
    1159             :             endif
    1160             :          end do
    1161           0 :          call endrun('init_ZonalAverage -- ERROR in Anorm values')
    1162             :       end if
    1163             : 
    1164             :       ! End Routine
    1165             :       !------------
    1166           0 :       deallocate(Clats)
    1167           0 :       deallocate(BinLat)
    1168           0 :       deallocate(Glats)
    1169           0 :       deallocate(Asum)
    1170           0 :       deallocate(Anorm)
    1171             : 
    1172           0 :     end subroutine init_ZonalAverage
    1173             :     !=======================================================================
    1174             : 
    1175             : 
    1176             :     !=======================================================================
    1177           0 :     subroutine calc_ZonalAverage_2DbinAvg(this,I_Gdata,O_Zdata)
    1178             :       !
    1179             :       ! calc_ZonalAverage_2DbinAvg: Given 2D data values for ncol gridpoints,
    1180             :       !                             compute the nlat area weighted binAvg profile
    1181             :       !=====================================================================
    1182             :       !
    1183             :       ! Passed Variables
    1184             :       !------------------
    1185             :       class(ZonalAverage_t):: this
    1186             :       real(r8),intent(in ):: I_Gdata(pcols,begchunk:endchunk)
    1187             :       real(r8),intent(out):: O_Zdata(:)
    1188             :       !
    1189             :       ! Local Values
    1190             :       !--------------
    1191           0 :       real(r8),allocatable:: Asum (:,:)
    1192             :       integer:: nn,ncols,lchnk,cc,jlat
    1193             :       integer :: nlcols, count, astat
    1194             :       character(len=*), parameter :: subname = 'calc_ZonalAverage_2DbinAvg'
    1195             : 
    1196           0 :       nlcols = get_nlcols_p()
    1197             : 
    1198             : 
    1199             :       ! Initialize Zonal profile
    1200             :       !---------------------------
    1201           0 :       allocate(Asum(nlcols,this%nlat), stat=astat)
    1202           0 :       call handle_allocate_error(astat, subname, 'Asum')
    1203           0 :       Asum(:,:) = 0._r8
    1204             : 
    1205           0 :       O_Zdata(1:this%nlat) = 0._r8
    1206             : 
    1207             :       ! Compute area-weighted sums
    1208             :       !-----------------------------
    1209           0 :       count = 0
    1210           0 :       do lchnk=begchunk,endchunk
    1211           0 :         ncols = get_ncols_p(lchnk)
    1212           0 :         do cc = 1,ncols
    1213           0 :           jlat = this%idx_map(cc,lchnk)
    1214           0 :           count=count+1
    1215           0 :           Asum(count,jlat) = I_Gdata(cc,lchnk)*this%area_g(cc,lchnk)
    1216             :         end do
    1217             :       end do
    1218             : 
    1219           0 :       call shr_reprosum_calc(Asum,O_Zdata,count, nlcols, this%nlat,gbl_count=ngcols_p, commid=mpicom)
    1220             : 
    1221             :       ! Divide by area norm to get the averages
    1222             :       !-----------------------------------------
    1223           0 :       do nn=1,this%nlat
    1224           0 :         O_Zdata(nn) = O_Zdata(nn)/this%a_norm(nn)
    1225             :       end do
    1226             : 
    1227           0 :       deallocate(Asum)
    1228             : 
    1229           0 :     end subroutine calc_ZonalAverage_2DbinAvg
    1230             :     !=======================================================================
    1231             : 
    1232             : 
    1233             :     !=======================================================================
    1234           0 :     subroutine calc_ZonalAverage_3DbinAvg(this,I_Gdata,O_Zdata)
    1235             :       !
    1236             :       ! calc_ZonalAverage_3DbinAvg: Given 3D data values for ncol,nlev gridpoints,
    1237             :       !                             compute the nlat,nlev area weighted binAvg profile
    1238             :       !=====================================================================
    1239             :       !
    1240             :       ! Passed Variables
    1241             :       !------------------
    1242             :       class(ZonalAverage_t):: this
    1243             :       real(r8),intent(in ):: I_Gdata(:,:,begchunk:)
    1244             :       real(r8),intent(out):: O_Zdata(:,:)
    1245             :       !
    1246             :       ! Local Values
    1247             :       !--------------
    1248           0 :       real(r8),allocatable:: Gsum(:)
    1249           0 :       real(r8),allocatable:: Asum(:,:)
    1250             :       integer:: nn,ncols,lchnk,cc,jlat
    1251             :       integer:: Nsum,ilev,ns
    1252             : 
    1253             :       integer :: nlev
    1254             :       integer :: nlcols, count, astat
    1255             :       character(len=*), parameter :: subname = 'calc_ZonalAverage_3DbinAvg'
    1256             : 
    1257           0 :       nlev = size(I_Gdata,dim=2)
    1258           0 :       nlcols = get_nlcols_p()
    1259             : 
    1260             :       ! Initialize Zonal profile
    1261             :       !---------------------------
    1262           0 :       Nsum = this%nlat*nlev
    1263           0 :       allocate(Gsum(Nsum), stat=astat)
    1264           0 :       call handle_allocate_error(astat, subname, 'Gsum')
    1265           0 :       allocate(Asum(nlcols,Nsum), stat=astat)
    1266           0 :       call handle_allocate_error(astat, subname, 'Asum')
    1267           0 :       Asum(:,:) = 0._r8
    1268             : 
    1269           0 :       O_Zdata(1:this%nlat,1:nlev) = 0._r8
    1270             : 
    1271             :       ! Compute area-weighted sums
    1272             :       !-----------------------------
    1273           0 :       do ilev = 1,nlev
    1274           0 :          count = 0
    1275           0 :          do lchnk=begchunk,endchunk
    1276           0 :             ncols = get_ncols_p(lchnk)
    1277           0 :             do cc = 1,ncols
    1278           0 :                jlat = this%idx_map(cc,lchnk)
    1279           0 :                ns = jlat + (ilev-1)*this%nlat
    1280           0 :                count=count+1
    1281           0 :                Asum(count,ns) = I_Gdata(cc,ilev,lchnk)*this%area_g(cc,lchnk)
    1282             :             end do
    1283             :          end do
    1284             :       end do
    1285             : 
    1286           0 :       call shr_reprosum_calc(Asum,Gsum, count, nlcols, Nsum, gbl_count=ngcols_p, commid=mpicom)
    1287             : 
    1288             :       ! Divide by area norm to get the averages
    1289             :       !-----------------------------------------
    1290           0 :       do ilev = 1,nlev
    1291           0 :          do nn = 1,this%nlat
    1292           0 :             ns = nn + (ilev-1)*this%nlat
    1293           0 :             O_Zdata(nn,ilev) = Gsum(ns)/this%a_norm(nn)
    1294             :          end do
    1295             :       end do
    1296             : 
    1297           0 :       deallocate(Gsum)
    1298           0 :       deallocate(Asum)
    1299             : 
    1300           0 :     end subroutine calc_ZonalAverage_3DbinAvg
    1301             :     !=======================================================================
    1302             : 
    1303             :     !=======================================================================
    1304        1536 :     subroutine final_ZonalAverage(this)
    1305             :       class(ZonalAverage_t) :: this
    1306             : 
    1307        1536 :       if(allocated(this%area   )) deallocate(this%area)
    1308        1536 :       if(allocated(this%a_norm )) deallocate(this%a_norm)
    1309        1536 :       if(allocated(this%area_g )) deallocate(this%area_g)
    1310        1536 :       if(allocated(this%idx_map)) deallocate(this%idx_map)
    1311             : 
    1312        1536 :     end subroutine final_ZonalAverage
    1313             :     !=======================================================================
    1314             : 
    1315             : 
    1316             :     !=======================================================================
    1317           0 :     subroutine Invert_Matrix(I_Mat,Nbas,O_InvMat)
    1318             :       !
    1319             :       ! Invert_Matrix: Given the NbasxNbas matrix, calculate and return
    1320             :       !                the inverse of the matrix.
    1321             :       !
    1322             :       ! Implemented with the LAPACK DGESV routine.
    1323             :       !
    1324             :       !====================================================================
    1325             :       !
    1326             :       ! Passed Variables
    1327             :       !------------------
    1328             :       real(r8), intent(inout) :: I_Mat(:,:)  ! input matrix contains P*L*U
    1329             :                                              ! decomposition on output
    1330             :       integer,  intent(in)    :: Nbas
    1331             :       real(r8), intent(out)   :: O_InvMat(:,:)
    1332             :       !
    1333             :       ! Local Values
    1334             :       !-------------
    1335           0 :       integer, allocatable :: Indx(:)  ! pivot indices
    1336             :       integer :: astat, ii
    1337             :       character(len=*), parameter :: subname = 'Invert_Matrix'
    1338             :       character(len=80) :: msg
    1339             : 
    1340             :       external DGESV
    1341             : 
    1342             :       ! Allocate work space
    1343             :       !---------------------
    1344           0 :       allocate(Indx(Nbas), stat=astat)
    1345           0 :       call handle_allocate_error(astat, subname, 'Indx')
    1346             : 
    1347             :       ! Initialize the inverse array with the identity matrix
    1348             :       !-------------------------------------------------------
    1349           0 :       O_InvMat(:,:) = 0._r8
    1350           0 :       do ii=1,Nbas
    1351           0 :         O_InvMat(ii,ii) = 1._r8
    1352             :       end do
    1353             : 
    1354           0 :       call DGESV(Nbas, Nbas, I_Mat, Nbas, Indx, O_InvMat, Nbas, astat)
    1355             : 
    1356           0 :       if (astat < 0) then
    1357           0 :          write(msg, '(a, i1, a)') 'argument # ', abs(astat), ' has an illegal value'
    1358           0 :          call endrun(subname//': DGESV error return: '//msg)
    1359           0 :       else if (astat > 0) then
    1360           0 :          call endrun(subname//': DGESV error return: matrix is singular')
    1361             :       end if
    1362             : 
    1363           0 :       deallocate(Indx)
    1364             : 
    1365           0 :     end subroutine Invert_Matrix
    1366             :     !=======================================================================
    1367             : 
    1368             :     !=======================================================================
    1369             :     ! legacy spherepack routines
    1370             :     !=======================================================================
    1371           0 :     subroutine sh_gen_basis_coefs(nn,mm,cp)
    1372             :       !
    1373             :       ! spherepack alfk
    1374             :       !
    1375             :       ! dimension of           real cp(nn/2 + 1)
    1376             :       ! arguments
    1377             :       !
    1378             :       ! purpose                computes fourier coefficients in the trigonometric series
    1379             :       !                        representation of the normalized associated
    1380             :       !                        legendre function pbar(nn,mm,theta) for use by
    1381             :       !                        sh_gen_basis_coefs in calculating pbar(nn,mm,theta).
    1382             :       !
    1383             :       !                        first define the normalized associated
    1384             :       !                        legendre functions
    1385             :       !
    1386             :       !                        pbar(mm,nn,theta) = sqrt((2*nn+1)*factorial(nn-mm)
    1387             :       !                        /(2*factorial(nn+mm)))*sin(theta)**mm/(2**nn*
    1388             :       !                        factorial(nn)) times the (nn+mm)th derivative of
    1389             :       !                        (x**2-1)**nn with respect to x=cos(theta)
    1390             :       !
    1391             :       !                        where theta is colatitude.
    1392             :       !
    1393             :       !                        then subroutine sh_gen_basis_coefs computes the coefficients
    1394             :       !                        cp(k) in the following trigonometric
    1395             :       !                        expansion of pbar(m,n,theta).
    1396             :       !
    1397             :       !                        1) for n even and m even, pbar(mm,nn,theta) =
    1398             :       !                           .5*cp(1) plus the sum from k=1 to k=nn/2
    1399             :       !                           of cp(k+1)*cos(2*k*th)
    1400             :       !
    1401             :       !                        2) for nn even and mm odd, pbar(mm,nn,theta) =
    1402             :       !                           the sum from k=1 to k=nn/2 of
    1403             :       !                           cp(k)*sin(2*k*th)
    1404             :       !
    1405             :       !                        3) for n odd and m even, pbar(mm,nn,theta) =
    1406             :       !                           the sum from k=1 to k=(nn+1)/2 of
    1407             :       !                           cp(k)*cos((2*k-1)*th)
    1408             :       !
    1409             :       !                        4) for nn odd and mm odd,  pbar(mm,nn,theta) =
    1410             :       !                           the sum from k=1 to k=(nn+1)/2 of
    1411             :       !                           cp(k)*sin((2*k-1)*th)
    1412             :       !
    1413             :       ! arguments
    1414             :       !
    1415             :       ! on input               nn
    1416             :       !                          nonnegative integer specifying the degree of
    1417             :       !                          pbar(nn,mm,theta)
    1418             :       !
    1419             :       !                        mm
    1420             :       !                          is the order of pbar(nn,mm,theta). mm can be
    1421             :       !                          any integer however cp is computed such that
    1422             :       !                          pbar(nn,mm,theta) = 0 if abs(m) is greater
    1423             :       !                          than nn and pbar(nn,mm,theta) = (-1)**mm*
    1424             :       !                          pbar(nn,-mm,theta) for negative mm.
    1425             :       !
    1426             :       ! on output              cp
    1427             :       !                          array of length (nn/2)+1
    1428             :       !                          which contains the fourier coefficients in
    1429             :       !                          the trigonometric series representation of
    1430             :       !                          pbar(nn,mm,theta)
    1431             :       !
    1432             :       ! special conditions     none
    1433             :       !
    1434             :       ! algorithm              the highest order coefficient is determined in
    1435             :       !                        closed form and the remainig coefficients are
    1436             :       !                        determined as the solution of a backward
    1437             :       !                        recurrence relation.
    1438             :       !
    1439             :       !=====================================================================
    1440             :       !
    1441             :       ! Passed Variables
    1442             :       !------------------
    1443             :       integer ,intent(in ):: nn
    1444             :       integer ,intent(in ):: mm
    1445             :       real(r8),intent(out):: cp(nn/2+1)
    1446             :       !
    1447             :       ! Local Values
    1448             :       !----------------
    1449             :       real(r8):: fnum,fnmh
    1450             :       real(r8):: pm1
    1451             :       real(r8):: t1,t2
    1452             :       real(r8):: fden
    1453             :       real(r8):: cp2
    1454             :       real(r8):: fnnp1
    1455             :       real(r8):: fnmsq
    1456             :       real(r8):: fk
    1457             :       real(r8):: a1,b1,C1
    1458             :       integer :: ma,nmms2,nex
    1459             :       integer :: ii,jj
    1460             : 
    1461             :       real(r8),parameter:: SC10=1024._r8
    1462             :       real(r8),parameter:: SC20=SC10*SC10
    1463             :       real(r8),parameter:: SC40=SC20*SC20
    1464             : 
    1465           0 :       cp(1) = 0._r8
    1466           0 :       ma = abs(mm)
    1467           0 :       if(ma>nn) return
    1468             : 
    1469           0 :       if((nn-1)<0) then
    1470           0 :         cp(1) = sqrt(2._r8)
    1471           0 :         return
    1472           0 :       elseif((nn-1)==0) then
    1473           0 :         if(ma/=0) then
    1474           0 :           cp(1) = sqrt(.75_r8)
    1475           0 :           if(mm==-1) cp(1) = -cp(1)
    1476             :         else
    1477           0 :           cp(1) = sqrt(1.5_r8)
    1478             :         endif
    1479           0 :         return
    1480             :       else
    1481           0 :         if(mod(nn+ma,2)/=0) then
    1482           0 :           nmms2 = (nn-ma-1)/2
    1483           0 :           fnum  = nn + ma + 2
    1484           0 :           fnmh  = nn - ma + 2
    1485           0 :           pm1   = -1._r8
    1486             :         else
    1487           0 :           nmms2 = (nn-ma)/2
    1488           0 :           fnum  = nn + ma + 1
    1489           0 :           fnmh  = nn - ma + 1
    1490           0 :           pm1   = 1._r8
    1491             :         endif
    1492             :       endif
    1493             : 
    1494           0 :       t1   = 1._r8/SC20
    1495           0 :       nex  = 20
    1496           0 :       fden = 2._r8
    1497           0 :       if(nmms2>=1) then
    1498           0 :         do ii = 1,nmms2
    1499           0 :           t1 = fnum*t1/fden
    1500           0 :           if (t1>SC20) then
    1501           0 :             t1  = t1/SC40
    1502           0 :             nex = nex + 40
    1503             :           endif
    1504           0 :           fnum = fnum + 2._r8
    1505           0 :           fden = fden + 2._r8
    1506             :         end do
    1507             :       endif
    1508             : 
    1509           0 :       if(mod(ma/2,2)/=0) then
    1510           0 :         t1 = -t1/2._r8**(nn-1-nex)
    1511             :       else
    1512           0 :         t1 =  t1/2._r8**(nn-1-nex)
    1513             :       endif
    1514           0 :       t2 = 1._r8
    1515           0 :       if(ma/=0) then
    1516           0 :         do ii = 1,ma
    1517           0 :           t2   = fnmh*t2/ (fnmh+pm1)
    1518           0 :           fnmh = fnmh + 2._r8
    1519             :         end do
    1520             :       endif
    1521             : 
    1522           0 :       cp2   = t1*sqrt((nn+.5_r8)*t2)
    1523           0 :       fnnp1 = nn*(nn+1)
    1524           0 :       fnmsq = fnnp1 - 2._r8*ma*ma
    1525             : 
    1526           0 :       if((mod(nn,2)==0).and.(mod(ma,2)==0)) then
    1527           0 :         jj = 1+(nn+1)/2
    1528             :       else
    1529           0 :         jj = (nn+1)/2
    1530             :       endif
    1531             : 
    1532           0 :       cp(jj) = cp2
    1533           0 :       if(mm<0) then
    1534           0 :         if(mod(ma,2)/=0) cp(jj) = -cp(jj)
    1535             :       endif
    1536           0 :       if(jj<=1) return
    1537             : 
    1538           0 :       fk = nn
    1539           0 :       a1 = (fk-2._r8)*(fk-1._r8) - fnnp1
    1540           0 :       b1 = 2._r8* (fk*fk-fnmsq)
    1541           0 :       cp(jj-1) = b1*cp(jj)/a1
    1542             : 
    1543           0 :       jj = jj - 1
    1544           0 :       do while(jj>1)
    1545           0 :         fk = fk - 2._r8
    1546           0 :         a1 = (fk-2._r8)*(fk-1._r8) - fnnp1
    1547           0 :         b1 = -2._r8*(fk*fk-fnmsq)
    1548           0 :         c1 = (fk+1._r8)*(fk+2._r8) - fnnp1
    1549           0 :         cp(jj-1) = -(b1*cp(jj)+c1*cp(jj+1))/a1
    1550           0 :         jj = jj - 1
    1551             :      end do
    1552             : 
    1553             :     end subroutine sh_gen_basis_coefs
    1554             :     !=======================================================================
    1555             : 
    1556             :     !=======================================================================
    1557           0 :     subroutine sh_create_basis(nn,mm,theta,cp,pb)
    1558             :       !
    1559             :       ! spherepack lfpt
    1560             :       !
    1561             :       ! dimension of
    1562             :       ! arguments
    1563             :       !                        cp((nn/2)+1)
    1564             :       !
    1565             :       ! purpose                routine sh_create_basis uses coefficients computed by
    1566             :       !                        routine sh_gen_basis_coefs to compute the
    1567             :       !                        normalized associated legendre function pbar(nn,mm,theta)
    1568             :       !                        at colatitude theta.
    1569             :       !
    1570             :       ! arguments
    1571             :       !
    1572             :       ! on input               nn
    1573             :       !                          nonnegative integer specifying the degree of
    1574             :       !                          pbar(nn,mm,theta)
    1575             :       !                        mm
    1576             :       !                          is the order of pbar(nn,mm,theta). mm can be
    1577             :       !                          any integer however pbar(nn,mm,theta) = 0
    1578             :       !                          if abs(mm) is greater than nn and
    1579             :       !                          pbar(nn,mm,theta) = (-1)**mm*pbar(nn,-mm,theta)
    1580             :       !                          for negative mm.
    1581             :       !
    1582             :       !                        theta
    1583             :       !                          colatitude in radians
    1584             :       !
    1585             :       !                        cp
    1586             :       !                          array of length (nn/2)+1
    1587             :       !                          containing coefficients computed by routine
    1588             :       !                          sh_gen_basis_coefs
    1589             :       !
    1590             :       ! on output              pb
    1591             :       !                          variable containing pbar(n,m,theta)
    1592             :       !
    1593             :       ! special conditions     calls to routine sh_create_basis must be preceded by an
    1594             :       !                        appropriate call to routine sh_gen_basis_coefs.
    1595             :       !
    1596             :       ! algorithm              the trigonometric series formula used by
    1597             :       !                        routine sh_create_basis to calculate pbar(nn,mm,theta) at
    1598             :       !                        colatitude theta depends on mm and nn as follows:
    1599             :       !
    1600             :       !                           1) for nn even and mm even, the formula is
    1601             :       !                              .5*cp(1) plus the sum from k=1 to k=n/2
    1602             :       !                              of cp(k)*cos(2*k*theta)
    1603             :       !                           2) for nn even and mm odd. the formula is
    1604             :       !                              the sum from k=1 to k=nn/2 of
    1605             :       !                              cp(k)*sin(2*k*theta)
    1606             :       !                           3) for nn odd and mm even, the formula is
    1607             :       !                              the sum from k=1 to k=(nn+1)/2 of
    1608             :       !                              cp(k)*cos((2*k-1)*theta)
    1609             :       !                           4) for nn odd and mm odd, the formula is
    1610             :       !                              the sum from k=1 to k=(nn+1)/2 of
    1611             :       !                              cp(k)*sin((2*k-1)*theta)
    1612             :       !
    1613             :       !=====================================================================
    1614             :       integer, intent(in) :: nn,mm
    1615             :       real(r8), intent(in) :: theta
    1616             :       real(r8), intent(in) :: cp(:)
    1617             :       real(r8), intent(out) :: pb
    1618             : 
    1619             :       real(r8) :: cdt
    1620             :       real(r8) :: sdt
    1621             :       real(r8) :: ct
    1622             :       real(r8) :: st
    1623             :       real(r8) :: summ
    1624             :       real(r8) :: cth
    1625             : 
    1626             :       integer:: ma,nmod,mmod,kdo
    1627             :       integer:: kp1,kk
    1628             : 
    1629           0 :       pb = 0._r8
    1630           0 :       ma = abs(mm)
    1631           0 :       if(ma>nn) return
    1632             : 
    1633           0 :       if(nn<=0) then
    1634           0 :         if(ma<=0) then
    1635           0 :           pb = sqrt(.5_r8)
    1636           0 :           return
    1637             :         endif
    1638             :       endif
    1639             : 
    1640           0 :       nmod = mod(nn,2)
    1641           0 :       mmod = mod(ma,2)
    1642             : 
    1643           0 :       if(nmod<=0) then
    1644           0 :         if(mmod<=0) then
    1645           0 :           kdo = nn/2 + 1
    1646           0 :           cdt = cos(theta+theta)
    1647           0 :           sdt = sin(theta+theta)
    1648           0 :           ct  = 1._r8
    1649           0 :           st  = 0._r8
    1650           0 :           summ = .5_r8*cp(1)
    1651           0 :           do kp1 = 2,kdo
    1652           0 :             cth = cdt*ct - sdt*st
    1653           0 :             st  = sdt*ct + cdt*st
    1654           0 :             ct  = cth
    1655           0 :             summ = summ + cp(kp1)*ct
    1656             :           end do
    1657           0 :           pb = summ
    1658           0 :           return
    1659             :         endif
    1660           0 :         kdo = nn/2
    1661           0 :         cdt = cos(theta+theta)
    1662           0 :         sdt = sin(theta+theta)
    1663           0 :         ct  = 1._r8
    1664           0 :         st  = 0._r8
    1665           0 :         summ = 0._r8
    1666           0 :         do kk = 1,kdo
    1667           0 :           cth = cdt*ct - sdt*st
    1668           0 :           st  = sdt*ct + cdt*st
    1669           0 :           ct  = cth
    1670           0 :           summ = summ + cp(kk)*st
    1671             :         end do
    1672           0 :         pb = summ
    1673           0 :         return
    1674             :       endif
    1675             : 
    1676           0 :       kdo = (nn+1)/2
    1677           0 :       if(mmod<=0) then
    1678           0 :         cdt =  cos(theta+theta)
    1679           0 :         sdt =  sin(theta+theta)
    1680           0 :         ct  =  cos(theta)
    1681           0 :         st  = -sin(theta)
    1682           0 :         summ = 0._r8
    1683           0 :         do kk = 1,kdo
    1684           0 :           cth = cdt*ct - sdt*st
    1685           0 :           st  = sdt*ct + cdt*st
    1686           0 :           ct  = cth
    1687           0 :           summ = summ + cp(kk)*ct
    1688             :         end do
    1689           0 :         pb = summ
    1690           0 :         return
    1691             :       endif
    1692             : 
    1693           0 :       cdt =  cos(theta+theta)
    1694           0 :       sdt =  sin(theta+theta)
    1695           0 :       ct  =  cos(theta)
    1696           0 :       st  = -sin(theta)
    1697           0 :       summ = 0._r8
    1698           0 :       do kk = 1,kdo
    1699           0 :         cth = cdt*ct - sdt*st
    1700           0 :         st  = sdt*ct + cdt*st
    1701           0 :         ct  = cth
    1702           0 :         summ = summ + cp(kk)*st
    1703             :       end do
    1704           0 :       pb = summ
    1705             : 
    1706             :     end subroutine sh_create_basis
    1707             :     !=======================================================================
    1708             : 
    1709             :     !=======================================================================
    1710           0 :     subroutine sh_create_gaus_grid(nlat,theta,wts,ierr)
    1711             :       !
    1712             :       ! spherepack gaqd
    1713             :       !  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    1714             :       !  .                                                             .
    1715             :       !  .                  copyright (c) 2001 by ucar                 .
    1716             :       !  .                                                             .
    1717             :       !  .       university corporation for atmospheric research       .
    1718             :       !  .                                                             .
    1719             :       !  .                      all rights reserved                    .
    1720             :       !  .                                                             .
    1721             :       !  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    1722             :       !
    1723             :       !                             February 2002
    1724             :       !
    1725             :       !     gauss points and weights are computed using the fourier-newton
    1726             :       !     described in "on computing the points and weights for
    1727             :       !     gauss-legendre quadrature", paul n. swarztrauber, siam journal
    1728             :       !     on scientific computing (DOI 10.1137/S1064827500379690).
    1729             :       !     This routine is faster and more accurate than older program
    1730             :       !     with the same name.
    1731             :       !
    1732             :       !     computes the nlat gaussian colatitudes and weights
    1733             :       !     in double precision. the colatitudes are in radians and lie in the
    1734             :       !     in the interval (0,pi).
    1735             :       !
    1736             :       !     input parameters
    1737             :       !
    1738             :       !     nlat    the number of gaussian colatitudes in the interval (0,pi)
    1739             :       !             (between the two poles).  nlat must be greater than zero.
    1740             :       !
    1741             :       !     output parameters
    1742             :       !
    1743             :       !     theta   a double precision array with length nlat
    1744             :       !             containing the gaussian colatitudes in
    1745             :       !             increasing radians on the interval (0,pi).
    1746             :       !
    1747             :       !     wts     a double precision array with lenght nlat
    1748             :       !             containing the gaussian weights.
    1749             :       !
    1750             :       !     ierror = 0 no errors
    1751             :       !            = 1 if nlat<=0
    1752             :       !
    1753             :       !===================================================================
    1754             :       !
    1755             :       ! Passed variables
    1756             :       !-----------------
    1757             :       integer ,intent(in ) :: nlat
    1758             :       real(r8),intent(out) :: theta(nlat)
    1759             :       real(r8),intent(out) :: wts(nlat)
    1760             :       integer ,intent(out) :: ierr
    1761             :       !
    1762             :       ! Local Values
    1763             :       !-------------
    1764             :       real(r8):: sgnd
    1765             :       real(r8):: xx,dtheta,dthalf
    1766             :       real(r8):: cmax,zprev,zlast,zero,zhold,pb,dpb,dcor,summ,cz
    1767             :       integer :: mnlat,ns2,nhalf,nix,it,ii
    1768             : 
    1769             :       real(r8), parameter :: eps = epsilon(1._r8)
    1770             : 
    1771             :       ! check work space length
    1772             :       !------------------------
    1773           0 :       if(nlat<=0) then
    1774           0 :         ierr = 1
    1775           0 :         return
    1776             :       endif
    1777           0 :       ierr = 0
    1778             : 
    1779             :       ! compute weights and points analytically when nlat=1,2
    1780             :       !-------------------------------------------------------
    1781           0 :       if(nlat==1) then
    1782           0 :         theta(1) = acos(0._r8)
    1783           0 :         wts  (1) = 2._r8
    1784           0 :         return
    1785           0 :       elseif(nlat==2) then
    1786           0 :         xx       = sqrt(1._r8/3._r8)
    1787           0 :         theta(1) = acos( xx)
    1788           0 :         theta(2) = acos(-xx)
    1789           0 :         wts  (1) = 1._r8
    1790           0 :         wts  (2) = 1._r8
    1791           0 :         return
    1792             :       endif
    1793             : 
    1794             :       ! Proceed for nlat > 2
    1795             :       !----------------------
    1796           0 :       mnlat = mod(nlat,2)
    1797           0 :       ns2   = nlat/2
    1798           0 :       nhalf = (nlat+1)/2
    1799             : 
    1800           0 :       call sh_fourier_coefs_dp(nlat,cz,theta(ns2+1),wts(ns2+1))
    1801             : 
    1802           0 :       dtheta = halfPI/nhalf
    1803           0 :       dthalf = dtheta/2._r8
    1804           0 :       cmax   = .2_r8*dtheta
    1805             : 
    1806             :       ! estimate first point next to theta = pi/2
    1807             :       !-------------------------------------------
    1808           0 :       if(mnlat/=0) then
    1809           0 :         zero  = halfPI - dtheta
    1810           0 :         zprev = halfPI
    1811           0 :         nix   = nhalf - 1
    1812             :       else
    1813           0 :         zero = halfPI - dthalf
    1814           0 :         nix  = nhalf
    1815             :       endif
    1816             : 
    1817           0 :       do while(nix/=0)
    1818             :          dcor = huge(1._r8)
    1819             :          it = 0
    1820           0 :          do while (abs(dcor) > eps*abs(zero))
    1821             :             it = it + 1
    1822             :             ! newton iterations
    1823             :             !-----------------------
    1824           0 :             call sh_legp_dlegp_theta(nlat,zero,cz,theta(ns2+1),wts(ns2+1),pb,dpb)
    1825           0 :             dcor = pb/dpb
    1826           0 :             if(dcor.ne.0._r8) then
    1827           0 :                sgnd = dcor/abs(dcor)
    1828             :             else
    1829             :                sgnd = 1._r8
    1830             :             endif
    1831           0 :             dcor = sgnd*min(abs(dcor),cmax)
    1832           0 :             zero = zero - dcor
    1833             :          end do
    1834             : 
    1835           0 :          theta(nix) = zero
    1836           0 :          zhold      = zero
    1837             : 
    1838             :          !   wts(nix) = (nlat+nlat+1)/(dpb*dpb)
    1839             :          ! yakimiw's formula permits using old pb and dpb
    1840             :          !--------------------------------------------------
    1841           0 :          wts(nix) = (nlat+nlat+1)/ (dpb+pb*dcos(zlast)/dsin(zlast))**2
    1842           0 :          nix      = nix - 1
    1843           0 :          if(nix==nhalf-1) zero = 3._r8*zero - pi
    1844           0 :          if(nix<nhalf-1) zero = zero + zero - zprev
    1845           0 :          zprev = zhold
    1846             :       end do
    1847             : 
    1848             :       ! extend points and weights via symmetries
    1849             :       !-------------------------------------------
    1850           0 :       if(mnlat/=0) then
    1851           0 :         theta(nhalf) = halfPI
    1852           0 :         call sh_legp_dlegp_theta(nlat,halfPI,cz,theta(ns2+1),wts(ns2+1),pb,dpb)
    1853           0 :         wts(nhalf) = (nlat+nlat+1)/ (dpb*dpb)
    1854             :       endif
    1855             : 
    1856           0 :       do ii = 1,ns2
    1857           0 :         wts  (nlat-ii+1) = wts(ii)
    1858           0 :         theta(nlat-ii+1) = pi - theta(ii)
    1859             :       end do
    1860             : 
    1861             :       summ = 0._r8
    1862           0 :       do ii = 1,nlat
    1863           0 :         summ = summ + wts(ii)
    1864             :       end do
    1865           0 :       do ii = 1,nlat
    1866           0 :         wts(ii) = 2._r8*wts(ii)/summ
    1867             :       end do
    1868             : 
    1869             :     end subroutine sh_create_gaus_grid
    1870             :     !=======================================================================
    1871             : 
    1872             :     !=======================================================================
    1873           0 :     subroutine sh_fourier_coefs_dp(nn,cz,cp,dcp)
    1874             :       !
    1875             :       ! spherepack cpdp
    1876             :       !
    1877             :       !     computes the fourier coefficients of the legendre
    1878             :       !     polynomial p_n^0 and its derivative.
    1879             :       !     nn is the degree and nn/2 or (nn+1)/2
    1880             :       !     coefficients are returned in cp depending on whether
    1881             :       !     nn is even or odd. The same number of coefficients
    1882             :       !     are returned in dcp. For nn even the constant
    1883             :       !     coefficient is returned in cz.
    1884             :       !=====================================================================
    1885             :       !
    1886             :       ! Passed variables
    1887             :       !-----------------
    1888             :       integer, intent(in) :: nn
    1889             :       real(r8), intent(out) :: cz
    1890             :       real(r8), intent(out) :: cp(nn/2+1)
    1891             :       real(r8), intent(out) :: dcp(nn/2+1)
    1892             :       !
    1893             :       ! Local Values
    1894             :       !--------------
    1895             :       real(r8):: t1,t2,t3,t4
    1896             :       integer :: ncp,jj
    1897             : 
    1898           0 :       ncp = (nn+1)/2
    1899           0 :       t1  = -1._r8
    1900           0 :       t2  = nn + 1._r8
    1901           0 :       t3  = 0._r8
    1902           0 :       t4  = nn + nn + 1._r8
    1903           0 :       if(mod(nn,2)==0) then
    1904           0 :         cp(ncp) = 1._r8
    1905           0 :         do jj = ncp,2,-1
    1906           0 :           t1 = t1 + 2._r8
    1907           0 :           t2 = t2 - 1._r8
    1908           0 :           t3 = t3 + 1._r8
    1909           0 :           t4 = t4 - 2._r8
    1910           0 :           cp(jj-1) = (t1*t2)/ (t3*t4)*cp(jj)
    1911             :         end do
    1912           0 :         t1 = t1 + 2._r8
    1913           0 :         t2 = t2 - 1._r8
    1914           0 :         t3 = t3 + 1._r8
    1915           0 :         t4 = t4 - 2._r8
    1916           0 :         cz = (t1*t2)/ (t3*t4)*cp(1)
    1917           0 :         do jj = 1,ncp
    1918           0 :           dcp(jj) = (jj+jj)*cp(jj)
    1919             :         end do
    1920             :       else
    1921           0 :         cp(ncp) = 1._r8
    1922           0 :         do jj = ncp - 1,1,-1
    1923           0 :           t1 = t1 + 2._r8
    1924           0 :           t2 = t2 - 1._r8
    1925           0 :           t3 = t3 + 1._r8
    1926           0 :           t4 = t4 - 2._r8
    1927           0 :           cp(jj) = (t1*t2)/ (t3*t4)*cp(jj+1)
    1928             :         end do
    1929           0 :         do jj = 1,ncp
    1930           0 :           dcp(jj) = (jj+jj-1)*cp(jj)
    1931             :         end do
    1932             :       endif
    1933             : 
    1934           0 :     end subroutine sh_fourier_coefs_dp
    1935             :     !=======================================================================
    1936             : 
    1937             :     !=======================================================================
    1938           0 :     subroutine sh_legp_dlegp_theta(nn,theta,cz,cp,dcp,pb,dpb)
    1939             :       !
    1940             :       ! spherepack tpdp
    1941             :       !
    1942             :       !     computes pn(theta) and its derivative dpb(theta) with
    1943             :       !     respect to theta
    1944             :       !=====================================================================
    1945             :       !
    1946             :       ! Passed variables
    1947             :       !------------------
    1948             :       integer, intent(in) :: nn
    1949             :       real(r8), intent(in) :: theta
    1950             :       real(r8), intent(in) :: cz
    1951             :       real(r8), intent(in) :: cp (nn/2+1)
    1952             :       real(r8), intent(in) :: dcp(nn/2+1)
    1953             :       real(r8), intent(out) :: pb
    1954             :       real(r8), intent(out) :: dpb
    1955             :       !
    1956             :       ! Local Values
    1957             :       !--------------
    1958             :       real(r8):: cdt,sdt,cth,sth,chh
    1959             :       integer :: kdo,kk
    1960             : 
    1961           0 :       cdt = dcos(theta+theta)
    1962           0 :       sdt = dsin(theta+theta)
    1963           0 :       if(mod(nn,2)==0) then
    1964             :         ! n even
    1965             :         !----------
    1966           0 :         kdo = nn/2
    1967           0 :         pb  = .5_r8*cz
    1968           0 :         dpb = 0._r8
    1969           0 :         if(nn>0) then
    1970             :           cth = cdt
    1971             :           sth = sdt
    1972           0 :           do kk = 1,kdo
    1973           0 :             pb  = pb  +  cp(kk)*cth
    1974           0 :             dpb = dpb - dcp(kk)*sth
    1975           0 :             chh = cdt*cth - sdt*sth
    1976           0 :             sth = sdt*cth + cdt*sth
    1977           0 :             cth = chh
    1978             :           end do
    1979             :         endif
    1980             :       else
    1981             :         ! n odd
    1982             :         !-----------
    1983           0 :         kdo = (nn+1)/2
    1984           0 :         pb  = 0._r8
    1985           0 :         dpb = 0._r8
    1986           0 :         cth = dcos(theta)
    1987           0 :         sth = dsin(theta)
    1988           0 :         do kk = 1,kdo
    1989           0 :           pb  = pb  +  cp(kk)*cth
    1990           0 :           dpb = dpb - dcp(kk)*sth
    1991           0 :           chh = cdt*cth - sdt*sth
    1992           0 :           sth = sdt*cth + cdt*sth
    1993           0 :           cth = chh
    1994             :         end do
    1995             :       endif
    1996             : 
    1997           0 :     end subroutine sh_legp_dlegp_theta
    1998             :     !=======================================================================
    1999             : 
    2000           0 : end module zonal_mean_mod

Generated by: LCOV version 1.14