1 subroutine da_vv_to_v_spectral(ni, nj, max_wavenumber, inc, lenr, lensav, lenwrk, &
2 alp_size, r_cvsize, alp, wsave, int_wgts, rcv, field)
4 !-------------------------------------------------------------------------
5 ! Purpose: Performs gridpoint to spectral transformation on a sphere.
6 ! Note: Routine works for both regular and Gaussian latitude (latitude
7 ! integration weights contain necessary info).
8 !-------------------------------------------------------------------------
12 integer, intent(in) :: ni ! Number of longitudes.
13 integer, intent(in) :: nj ! Number of latitudes.
14 integer, intent(in) :: r_cvsize ! Size of real control cv-array.
15 integer, intent(in) :: max_wavenumber ! Smallest scale required (ni/2 - 1).
16 integer, intent(in) :: inc ! Jump between elements of vector in array.
17 integer, intent(in) :: lenr ! FFT array dimension (at least inc*(n-1)+1).
18 real, intent(in) :: field(1:ni,1:nj) ! Gridpoint field.
19 real, intent(out) :: rcv(1:r_cvsize) ! Spectral modes.
20 integer, intent(in) :: lensav ! wsave dimension (n+int(log(real(ni)))+4).
21 integer, intent(in) :: lenwrk ! Dimension of work array.
22 integer, intent(in) :: alp_size ! Size of ALP vector.
23 real, intent(in) :: alp(1:alp_size) ! Associated Legendre Polynomials.
24 real, intent(in) :: wsave(1:lensav) ! Primes for FFT.
25 real, intent(in) :: int_wgts(1:nj) ! Legendre integration weights.
27 integer :: i, j, m, mm ! Loop counters.
28 integer :: sizec ! Size of complex cv-array
29 integer :: index_r, index_c ! Array index for complex v_fou
30 integer :: index_start, index_end ! Position markers in cv.
31 real :: r_fou(1:lenr) ! FFT array.
32 logical :: odd_longitudes
33 complex :: v_fou(1:nj,0:max_wavenumber)! Intermediate Fourier state.
34 complex :: r_leg(1:nj) ! Intermediate Fourier state.
35 complex, allocatable:: ccv(:) ! Spectral modes.
38 real :: work(1:lenwrk) ! FFT work array.
41 ! if (trace_use) call da_trace_entry("da_vv_to_v_spectral")
43 sizec = int(0.5 * r_cvsize)
44 allocate (ccv(1:sizec))
46 if ((ni+1) / 2 == ni/2 + 1) then ! Odd number of longitudes:
47 odd_longitudes = .true.
48 else ! Even number of longitudes:
49 odd_longitudes = .false.
52 !-------------------------------------------------------------------------
53 ! [1] Perform Adjoint of inverse Fourier decomposition in E-W direction:
54 !-------------------------------------------------------------------------
56 if ((ni+1) / 2 == ni/2 + 1) then ! Odd number of longitudes:
57 odd_longitudes = .true.
58 else ! Even number of longitudes:
59 odd_longitudes = .false.
62 ! [1] Perform Fourier decomposition in E-W direction:
65 r_fou(1:ni) = field(1:ni,j)
67 call rfft1f(ni, inc, r_fou, lenr, wsave, lensav, work, lenwrk, ierr)
69 call da_error(__FILE__,__LINE__,(/"Needs to be compiled with FFTPACK"/))
72 if (odd_longitudes) then
73 v_fou(j,0) = CMPLX(r_fou(1), 0.0) ! m = 0 is real.
75 ! m = 0 is real, but pack R(NI/2) in imag m = 0:
76 v_fou(j,0) = CMPLX(r_fou(1), r_fou(ni))
79 do m = 1, max_wavenumber
82 v_fou(j,m) = CMPLX(r_fou(index_r), r_fou(index_c)) ! 2.0 * Fourier mode.
86 ! [2] Perform Legendre decomposition in N-S direction:
88 do m = 0, max_wavenumber
89 index_start = m * (max_wavenumber + 1 - m) + m * (m + 1) / 2 + 1
90 index_end = index_start + max_wavenumber - m
91 r_leg(1:nj) = v_fou(1:nj,m)
92 call da_legtra (nj, max_wavenumber, alp_size, m, int_wgts, alp, r_leg, &
93 ccv(index_start:index_end))
98 rcv(mm ) = real (ccv(i))
99 rcv(mm+1) = aimag(ccv(i))
103 ! if (trace_use) call da_trace_exit("da_vv_to_v_spectral")
105 end subroutine da_vv_to_v_spectral