ssht_core_mod.f90

Go to the documentation of this file.
00001 ! SSHT package to perform spin spherical harmonic transforms
00002 ! Copyright (C) 2011  Jason McEwen
00003 ! See LICENSE.txt for license details
00004 
00005 
00006 !------------------------------------------------------------------------------
00007 ! ssht_core_mod  -- SSHT library core class
00008 ! 
00016 
00017 module ssht_core_mod
00018 
00019   use ssht_types_mod
00020   use ssht_error_mod
00021   use ssht_dl_mod
00022   use ssht_sampling_mod
00023 
00024   implicit none
00025 
00026   private
00027 
00028 
00029   !---------------------------------------
00030   ! Subroutine and function scope
00031   !---------------------------------------
00032 
00033   public :: &
00034        ssht_core_dh_inverse, &
00035        ssht_core_dh_forward, &
00036        ssht_core_gl_inverse, &
00037        ssht_core_gl_forward, &
00038        ssht_core_mweo_inverse, &
00039        ssht_core_mweo_forward, &
00040        ssht_core_mw_inverse, &
00041        ssht_core_mw_forward, &
00042        ssht_core_dh_inverse_real, &
00043        ssht_core_dh_forward_real, &
00044        ssht_core_gl_inverse_real, &
00045        ssht_core_gl_forward_real, &
00046        ssht_core_mweo_inverse_real, &
00047        ssht_core_mweo_forward_real, &
00048        ssht_core_mw_inverse_real, &
00049        ssht_core_mw_forward_real
00050 
00051 
00052   !----------------------------------------------------------------------------
00053   ! DH interfaces
00054   !----------------------------------------------------------------------------
00055 
00056   ! Define implementations available publicly.
00057 
00059   interface ssht_core_dh_inverse
00060      module procedure ssht_core_dh_inverse_sov_sym
00061   end interface
00062 
00064   interface ssht_core_dh_forward
00065      module procedure ssht_core_dh_forward_sov_sym
00066   end interface
00067 
00069   interface ssht_core_dh_inverse_real
00070      module procedure ssht_core_dh_inverse_sov_sym_real
00071   end interface
00072 
00074   interface ssht_core_dh_forward_real
00075      module procedure ssht_core_dh_forward_sov_sym_real
00076   end interface
00077 
00078   ! DH sampling does not have South pole sample so no alternative interface.
00079 
00080   !----------------------------------------------------------------------------
00081   ! GL interfaces
00082   !----------------------------------------------------------------------------
00083 
00084   ! Define implementations available publicly.
00085 
00087   interface ssht_core_gl_inverse
00088      module procedure ssht_core_gl_inverse_sov_sym
00089   end interface
00090 
00092   interface ssht_core_gl_forward
00093      module procedure ssht_core_gl_forward_sov_sym
00094   end interface
00095 
00097   interface ssht_core_gl_inverse_real
00098      module procedure ssht_core_gl_inverse_sov_sym_real
00099   end interface
00100 
00102   interface ssht_core_gl_forward_real
00103      module procedure ssht_core_gl_forward_sov_sym_real
00104   end interface
00105 
00106   ! GL sampling does not have South pole sample so no alternative interface.
00107 
00108 
00109   !----------------------------------------------------------------------------
00110   ! MWEO interfaces
00111   !----------------------------------------------------------------------------
00112 
00113   ! Define implementations available publicly.
00114 
00116   interface ssht_core_mweo_inverse
00117      module procedure ssht_core_mweo_inverse_sp
00118   end interface
00119 
00121   interface ssht_core_mweo_forward
00122      module procedure ssht_core_mweo_forward_sp
00123   end interface
00124 
00126   interface ssht_core_mweo_inverse_real
00127      module procedure ssht_core_mweo_inverse_real_sp
00128   end interface
00129 
00131   interface ssht_core_mweo_forward_real
00132      module procedure ssht_core_mweo_forward_real_sp
00133   end interface
00134 
00135   ! Define implementations to use in south pole wrapper routines.
00136 
00138   interface ssht_core_mweo_inverse_rsp
00139      module procedure ssht_core_mweo_inverse_sov_sym
00140   end interface
00141 
00143   interface ssht_core_mweo_forward_rsp
00144      module procedure ssht_core_mweo_forward_sov_conv_sym
00145   end interface
00146 
00148   interface ssht_core_mweo_inverse_real_rsp
00149      module procedure ssht_core_mweo_inverse_sov_sym_real
00150   end interface
00151 
00153   interface ssht_core_mweo_forward_real_rsp
00154      module procedure ssht_core_mweo_forward_sov_conv_sym_real
00155   end interface
00156 
00157 
00158   !----------------------------------------------------------------------------
00159   ! MW interfaces
00160   !----------------------------------------------------------------------------
00161 
00162   ! Define implementations available publicly.
00163 
00165   interface ssht_core_mw_inverse
00166      module procedure ssht_core_mw_inverse_sp
00167   end interface
00168 
00170   interface ssht_core_mw_forward
00171      module procedure ssht_core_mw_forward_sp
00172   end interface
00173 
00175   interface ssht_core_mw_inverse_real
00176      module procedure ssht_core_mw_inverse_real_sp
00177   end interface
00178 
00180   interface ssht_core_mw_forward_real
00181      module procedure ssht_core_mw_forward_real_sp
00182   end interface
00183 
00184   ! Define implementations to use in south pole wrapper routines.
00185 
00187   interface ssht_core_mw_inverse_rsp
00188      module procedure ssht_core_mw_inverse_sov_sym
00189   end interface
00190 
00192   interface ssht_core_mw_forward_rsp
00193      module procedure ssht_core_mw_forward_sov_conv_sym
00194   end interface
00195 
00197   interface ssht_core_mw_inverse_real_rsp
00198      module procedure ssht_core_mw_inverse_sov_sym_real
00199   end interface
00200 
00202   interface ssht_core_mw_forward_real_rsp
00203      module procedure ssht_core_mw_forward_sov_conv_sym_real
00204   end interface
00205 
00206 
00207   !---------------------------------------
00208   ! Global variables
00209   !---------------------------------------
00210 
00211   integer, parameter :: FFTW_ESTIMATE=64, FFTW_MEASURE=0
00212   integer, parameter :: FFTW_FORWARD=-1, FFTW_BACKWARD=1
00213 
00214 
00215   !---------------------------------------
00216   ! Data types
00217   !---------------------------------------
00218 
00219   ! None.
00220 
00221 
00222   !----------------------------------------------------------------------------
00223 
00224 contains
00225 
00226 
00227   !============================================================================
00228   ! South pole interface routines
00229   !============================================================================
00230 
00231 
00232   !----------------------------------------------------------------------------
00233   ! MWEO
00234   !----------------------------------------------------------------------------
00235 
00236  
00237   !----------------------------------------------------------------------------
00238   ! ssht_core_mweo_inverse_sp
00239   !
00258   
00259   subroutine ssht_core_mweo_inverse_sp(f, f_sp, phi_sp, flm, L, spin, verbosity) 
00260 
00261     integer, intent(in) :: L
00262     integer, intent(in) :: spin
00263     integer, intent(in), optional :: verbosity
00264     complex(dpc), intent(in) :: flm(0:L**2-1)
00265     real(dp), intent(out) :: phi_sp
00266     complex(dpc), intent(out) :: f_sp
00267     complex(dpc), intent(out) :: f(0:L-2, 0:2*L-2)
00268     
00269     complex(dpc) :: f_ext(0:L-1, 0:2*L-2)
00270 
00271     call ssht_core_mweo_inverse_rsp(f_ext, flm, L, spin, verbosity)
00272 
00273     f(0:L-2, 0:2*L-2) = f_ext(0:L-2, 0:2*L-2)
00274     f_sp = f_ext(L-1, 0)
00275     phi_sp = ssht_sampling_mweo_p2phi(0, L)
00276 
00277   end subroutine ssht_core_mweo_inverse_sp
00278 
00279 
00280   !----------------------------------------------------------------------------
00281   ! ssht_core_mweo_forward_sp
00282   !
00301 
00302   subroutine ssht_core_mweo_forward_sp(flm, f, f_sp, phi_sp, L, spin, verbosity)
00303 
00304     integer, intent(in) :: L
00305     integer, intent(in) :: spin
00306     integer, intent(in), optional :: verbosity
00307     complex(dpc), intent(in) :: f(0:L-2 ,0:2*L-2)
00308     real(dp), intent(in) :: phi_sp
00309     complex(dpc), intent(in) :: f_sp
00310     complex(dpc), intent(out) :: flm(0:L**2-1)
00311 
00312     complex(dpc) :: f_ext(0:L-1, 0:2*L-2)
00313     integer :: p
00314     real(dp) :: phi
00315   
00316     f_ext(0:L-2 ,0:2*L-2) = f(0:L-2 ,0:2*L-2)
00317     do p = 0, 2*L-2
00318        phi = ssht_sampling_mweo_p2phi(p, L)
00319        f_ext(L-1, p) = f_sp * exp(I*spin*(phi-phi_sp))
00320     end do
00321 
00322     call ssht_core_mweo_forward_rsp(flm, f_ext, L, spin, verbosity)
00323 
00324   end subroutine ssht_core_mweo_forward_sp
00325 
00326 
00327   !----------------------------------------------------------------------------
00328   ! ssht_core_mweo_inverse_real_sp
00329   !
00346 
00347   subroutine ssht_core_mweo_inverse_real_sp(f, f_sp, flm, L, verbosity)
00348     
00349     integer, intent(in) :: L
00350     integer, intent(in), optional :: verbosity
00351     complex(dpc), intent(in) :: flm(0:L**2-1)
00352     real(dp), intent(out) :: f_sp
00353     real(dp), intent(out) :: f(0:L-2, 0:2*L-2)
00354 
00355     real(dp) :: f_ext(0:L-1, 0:2*L-2)
00356 
00357     call ssht_core_mweo_inverse_real_rsp(f_ext, flm, L, verbosity)
00358 
00359     f(0:L-2, 0:2*L-2) = f_ext(0:L-2, 0:2*L-2)
00360     f_sp = f_ext(L-1, 0)
00361 
00362   end subroutine ssht_core_mweo_inverse_real_sp
00363 
00364 
00365   !----------------------------------------------------------------------------
00366   ! ssht_core_mweo_forward_real_sp
00367   !
00384 
00385   subroutine ssht_core_mweo_forward_real_sp(flm, f, f_sp, L, verbosity)
00386 
00387     integer, intent(in) :: L
00388     integer, intent(in), optional :: verbosity
00389     real(dp), intent(in) :: f(0:L-2, 0:2*L-2)
00390     real(dp), intent(in) :: f_sp
00391     complex(dpc), intent(out) :: flm(0:L**2-1)
00392 
00393     real(dp) :: f_ext(0:L-1, 0:2*L-2)
00394 
00395     f_ext(0:L-2, 0:2*L-2) = f(0:L-2, 0:2*L-2)
00396     f_ext(L-1, 0:2*L-2) = f_sp
00397 
00398     call ssht_core_mweo_forward_real_rsp(flm, f_ext, L, verbosity)
00399 
00400   end subroutine ssht_core_mweo_forward_real_sp
00401 
00402 
00403   !----------------------------------------------------------------------------
00404   ! MW
00405   !----------------------------------------------------------------------------
00406 
00407 
00408   !----------------------------------------------------------------------------
00409   ! ssht_core_mw_inverse_sp
00410   !
00429 
00430   subroutine ssht_core_mw_inverse_sp(f, f_sp, phi_sp, flm, L, spin, verbosity) 
00431 
00432     integer, intent(in) :: L
00433     integer, intent(in) :: spin
00434     integer, intent(in), optional :: verbosity
00435     complex(dpc), intent(in) :: flm(0:L**2-1)
00436     real(dp), intent(out) :: phi_sp
00437     complex(dpc), intent(out) :: f_sp
00438     complex(dpc), intent(out) :: f(0:L-2, 0:2*L-2)
00439     
00440     complex(dpc) :: f_ext(0:L-1, 0:2*L-2)
00441 
00442     call ssht_core_mw_inverse_rsp(f_ext, flm, L, spin, verbosity)
00443 
00444     f(0:L-2, 0:2*L-2) = f_ext(0:L-2, 0:2*L-2)
00445     f_sp = f_ext(L-1, 0)
00446     phi_sp = ssht_sampling_mw_p2phi(0, L)
00447 
00448   end subroutine ssht_core_mw_inverse_sp
00449 
00450 
00451   !----------------------------------------------------------------------------
00452   ! ssht_core_mw_forward_sp
00453   !
00472 
00473   subroutine ssht_core_mw_forward_sp(flm, f, f_sp, phi_sp, L, spin, verbosity)
00474 
00475     integer, intent(in) :: L
00476     integer, intent(in) :: spin
00477     integer, intent(in), optional :: verbosity
00478     complex(dpc), intent(in) :: f(0:L-2 ,0:2*L-2)
00479     real(dp), intent(in) :: phi_sp
00480     complex(dpc), intent(in) :: f_sp
00481     complex(dpc), intent(out) :: flm(0:L**2-1)
00482 
00483     complex(dpc) :: f_ext(0:L-1, 0:2*L-2)
00484     integer :: p
00485     real(dp) :: phi
00486   
00487     f_ext(0:L-2 ,0:2*L-2) = f(0:L-2 ,0:2*L-2)
00488     do p = 0, 2*L-2
00489        phi = ssht_sampling_mw_p2phi(p, L)
00490        f_ext(L-1, p) = f_sp * exp(I*spin*(phi-phi_sp))
00491     end do
00492 
00493     call ssht_core_mw_forward_rsp(flm, f_ext, L, spin, verbosity)
00494 
00495   end subroutine ssht_core_mw_forward_sp
00496 
00497 
00498   !----------------------------------------------------------------------------
00499   ! ssht_core_mw_inverse_real_sp
00500   !
00517 
00518   subroutine ssht_core_mw_inverse_real_sp(f, f_sp, flm, L, verbosity)
00519     
00520     integer, intent(in) :: L
00521     integer, intent(in), optional :: verbosity
00522     complex(dpc), intent(in) :: flm(0:L**2-1)
00523     real(dp), intent(out) :: f_sp
00524     real(dp), intent(out) :: f(0:L-2, 0:2*L-2)
00525 
00526     real(dp) :: f_ext(0:L-1, 0:2*L-2)
00527 
00528     call ssht_core_mw_inverse_real_rsp(f_ext, flm, L, verbosity)
00529 
00530     f(0:L-2, 0:2*L-2) = f_ext(0:L-2, 0:2*L-2)
00531     f_sp = f_ext(L-1, 0)
00532 
00533   end subroutine ssht_core_mw_inverse_real_sp
00534 
00535 
00536   !----------------------------------------------------------------------------
00537   ! ssht_core_mw_forward_real_sp
00538   !
00555 
00556   subroutine ssht_core_mw_forward_real_sp(flm, f, f_sp, L, verbosity)
00557 
00558     integer, intent(in) :: L
00559     integer, intent(in), optional :: verbosity
00560     real(dp), intent(in) :: f(0:L-2, 0:2*L-2)
00561     real(dp), intent(in) :: f_sp
00562     complex(dpc), intent(out) :: flm(0:L**2-1)
00563 
00564     real(dp) :: f_ext(0:L-1, 0:2*L-2)
00565 
00566     f_ext(0:L-2, 0:2*L-2) = f(0:L-2, 0:2*L-2)
00567     f_ext(L-1, 0:2*L-2) = f_sp
00568 
00569     call ssht_core_mw_forward_real_rsp(flm, f_ext, L, verbosity)
00570 
00571   end subroutine ssht_core_mw_forward_real_sp
00572 
00573 
00574   !============================================================================
00575   ! Inverse transforms
00576   !============================================================================
00577 
00578 
00579   !----------------------------------------------------------------------------
00580   ! DH
00581   !----------------------------------------------------------------------------
00582 
00583 
00584   !----------------------------------------------------------------------------
00585   ! ssht_core_dh_inverse_direct
00586   !
00605 
00606   subroutine ssht_core_dh_inverse_direct(f, flm, L, spin, verbosity)
00607     
00608     integer, intent(in) :: L
00609     integer, intent(in) :: spin
00610     integer, intent(in), optional :: verbosity
00611     complex(dpc), intent(in) :: flm(0:L**2-1)
00612     complex(dpc), intent(out) :: f(0:2*L-1, 0:2*L-2)
00613 
00614     integer :: el, m, t, p, ind
00615     real(dp) :: theta, phi
00616     real(dp) :: elfactor
00617     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)          
00618     character(len=STRING_LEN) :: format_spec
00619 
00620     ! Print messages depending on verbosity level.
00621     if (present(verbosity)) then
00622        if (verbosity > 0) then
00623           write(*,'(a,a)') SSHT_PROMPT, &
00624                'Computing inverse transform using Driscoll and Healy sampling with'
00625           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
00626           write(*,trim(format_spec)) SSHT_PROMPT, &
00627                'parameters (L,spin,reality) = (', &
00628                L, ',', spin, ',FALSE)...'
00629        end if
00630        if (verbosity > 1) then
00631           write(*,'(a,a)') SSHT_PROMPT, &
00632                'Using routine ssht_core_dh_inverse_direct...'
00633        end if
00634     end if
00635 
00636     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
00637     do el = abs(spin), L-1
00638        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
00639        do t = 0, 2*L-1
00640           theta = ssht_sampling_dh_t2theta(t, L)             
00641           call ssht_dl_beta_operator(dl(-el:el,-el:el), theta, el)
00642           do m = -el, el
00643              call ssht_sampling_elm2ind(ind, el, m)
00644              do p = 0, 2*L-2
00645                 phi = ssht_sampling_dh_p2phi(p, L)
00646                 f(t,p) = f(t,p) + &
00647                      (-1)**spin * elfactor &
00648                      * exp(I*m*phi) &
00649                      * dl(m,-spin) * flm(ind)
00650              end do
00651           end do
00652           
00653        end do
00654     end do
00655 
00656     ! Print finished if verbosity set.
00657     if (present(verbosity)) then
00658        if (verbosity > 0) then
00659           write(*,'(a,a)') SSHT_PROMPT, &
00660                'Inverse transform computed!'
00661        end if
00662     end if
00663 
00664   end subroutine ssht_core_dh_inverse_direct
00665 
00666 
00667   !----------------------------------------------------------------------------
00668   ! ssht_core_dh_inverse_direct_factored
00669   !
00688 
00689   subroutine ssht_core_dh_inverse_direct_factored(f, flm, L, spin, verbosity)
00690     
00691     integer, intent(in) :: L
00692     integer, intent(in) :: spin
00693     integer, intent(in), optional :: verbosity
00694     complex(dpc), intent(in) :: flm(0:L**2-1)
00695     complex(dpc), intent(out) :: f(0:2*L-1, 0:2*L-2)
00696 
00697     integer :: el, m, mm, t, p, ind
00698     real(dp) :: theta, phi
00699     real(dp) :: elfactor
00700     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
00701     character(len=STRING_LEN) :: format_spec
00702 
00703     ! Print messages depending on verbosity level.
00704     if (present(verbosity)) then
00705        if (verbosity > 0) then
00706           write(*,'(a,a)') SSHT_PROMPT, &
00707                'Computing inverse transform using Driscoll and Healy sampling with'
00708           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
00709           write(*,trim(format_spec)) SSHT_PROMPT, &
00710                'parameters (L,spin,reality) = (', &
00711                L, ',', spin, ',FALSE)...'
00712        end if
00713        if (verbosity > 1) then
00714           write(*,'(a,a)') SSHT_PROMPT, &
00715                'Using routine ssht_core_dh_inverse_direct_factored...'
00716        end if
00717     end if     
00718 
00719     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
00720     do el = abs(spin), L-1
00721        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
00722        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
00723        do m = -el, el
00724           call ssht_sampling_elm2ind(ind, el, m)
00725           do mm = -el, el
00726              do t = 0, 2*L-1
00727                 theta = ssht_sampling_dh_t2theta(t, L)             
00728                 do p = 0, 2*L-2
00729                    phi = ssht_sampling_dh_p2phi(p, L)
00730                    f(t,p) = f(t,p) + &
00731                         (-1)**spin * elfactor &
00732                         * exp(-I*PION2*(m+spin)) &
00733                         * exp(I*m*phi + I*mm*theta) &
00734                         * dl(mm,m) * dl(mm,-spin) &
00735                         * flm(ind)
00736                 end do
00737              end do
00738           end do
00739        end do
00740     end do
00741 
00742     ! Print finished if verbosity set.
00743     if (present(verbosity)) then
00744        if (verbosity > 0) then
00745           write(*,'(a,a)') SSHT_PROMPT, &
00746                'Inverse transform computed!'
00747        end if
00748     end if
00749 
00750   end subroutine ssht_core_dh_inverse_direct_factored
00751 
00752 
00753   !----------------------------------------------------------------------------
00754   ! ssht_core_dh_inverse_sov_direct
00755   !
00774 
00775   subroutine ssht_core_dh_inverse_sov_direct(f, flm, L, spin, verbosity)
00776     
00777     integer, intent(in) :: L
00778     integer, intent(in) :: spin
00779     integer, intent(in), optional :: verbosity
00780     complex(dpc), intent(in) :: flm(0:L**2-1)
00781     complex(dpc), intent(out) :: f(0:2*L-1, 0:2*L-2)
00782 
00783     integer :: el, m, mm, t, p, ind
00784     real(dp) :: theta, phi
00785     real(dp) :: elfactor
00786     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
00787     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
00788     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
00789 
00790     character(len=STRING_LEN) :: format_spec
00791 
00792     ! Print messages depending on verbosity level.
00793     if (present(verbosity)) then
00794        if (verbosity > 0) then
00795           write(*,'(a,a)') SSHT_PROMPT, &
00796                'Computing inverse transform using Driscoll and Healy sampling with'
00797           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
00798           write(*,trim(format_spec)) SSHT_PROMPT, &
00799                'parameters (L,spin,reality) = (', &
00800                L, ',', spin, ',FALSE)...'
00801        end if
00802        if (verbosity > 1) then
00803           write(*,'(a,a)') SSHT_PROMPT, &
00804                'Using routine ssht_core_dh_inverse_sov_direct...'
00805        end if
00806     end if
00807 
00808     ! Compute Fmm.
00809     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
00810     do el = abs(spin), L-1
00811        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
00812        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
00813        do m = -el, el
00814           call ssht_sampling_elm2ind(ind, el, m)
00815           do mm = -el, el
00816              Fmm(m,mm) = Fmm(m,mm) + &
00817                   (-1)**spin * elfactor &
00818                   * exp(-I*PION2*(m+spin)) &
00819                   * dl(mm,m) * dl(mm,-spin) &
00820                   * flm(ind)
00821           end do
00822        end do
00823     end do
00824 
00825     ! Compute fmt.
00826     fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
00827     do t = 0, 2*L-1     
00828        theta = ssht_sampling_dh_t2theta(t, L)       
00829        do m = -(L-1), L-1          
00830           do mm = -(L-1), L-1
00831              fmt(m,t) = fmt(m,t) + &
00832                   Fmm(m,mm) * exp(I*mm*theta)
00833           end do
00834        end do
00835     end do
00836 
00837     ! Compute f.
00838     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
00839     do t = 0, 2*L-1       
00840        do p = 0, 2*L-2
00841           phi = ssht_sampling_dh_p2phi(p, L)
00842           do m = -(L-1), L-1          
00843              f(t,p) = f(t,p) + &
00844                   fmt(m,t) * exp(I*m*phi)
00845           end do
00846        end do
00847     end do
00848 
00849     ! Print finished if verbosity set.
00850     if (present(verbosity)) then
00851        if (verbosity > 0) then
00852           write(*,'(a,a)') SSHT_PROMPT, &
00853                'Inverse transform computed!'
00854        end if
00855     end if
00856 
00857   end subroutine ssht_core_dh_inverse_sov_direct
00858 
00859 
00860   !----------------------------------------------------------------------------
00861   ! ssht_core_dh_inverse_sov
00862   !
00878 
00879   subroutine ssht_core_dh_inverse_sov(f, flm, L, spin, verbosity)
00880     
00881     integer, intent(in) :: L
00882     integer, intent(in) :: spin
00883     integer, intent(in), optional :: verbosity
00884     complex(dpc), intent(in) :: flm(0:L**2-1)
00885     complex(dpc), intent(out) :: f(0:2*L-1, 0:2*L-2)
00886 
00887     integer :: el, m, mm, t, p, ind
00888     real(dp) :: theta, phi
00889     real(dp) :: elfactor
00890     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
00891     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
00892     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
00893     integer*8 :: fftw_plan
00894     character(len=STRING_LEN) :: format_spec
00895 
00896     ! Print messages depending on verbosity level.
00897     if (present(verbosity)) then
00898        if (verbosity > 0) then
00899           write(*,'(a,a)') SSHT_PROMPT, &
00900                'Computing inverse transform using Driscoll and Healy sampling with'
00901           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
00902           write(*,trim(format_spec)) SSHT_PROMPT, &
00903                'parameters (L,spin,reality) = (', &
00904                L, ',', spin, ',FALSE)...'
00905        end if
00906        if (verbosity > 1) then
00907           write(*,'(a,a)') SSHT_PROMPT, &
00908                'Using routine ssht_core_dh_inverse_sov...'
00909        end if
00910     end if
00911 
00912 
00913     ! Compute Fmm.
00914     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
00915     do el = abs(spin), L-1
00916        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
00917        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
00918        do m = -el, el
00919           call ssht_sampling_elm2ind(ind, el, m)
00920           do mm = -el, el
00921              Fmm(m,mm) = Fmm(m,mm) + &
00922                   (-1)**spin * elfactor &
00923                   * exp(-I*PION2*(m+spin)) &
00924                   * dl(mm,m) * dl(mm,-spin) &
00925                   * flm(ind)
00926           end do
00927        end do
00928     end do
00929 
00930     ! Compute fmt.
00931     fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
00932     do t = 0, 2*L-1     
00933        theta = ssht_sampling_dh_t2theta(t, L)       
00934        do m = -(L-1), L-1          
00935           do mm = -(L-1), L-1
00936              fmt(m,t) = fmt(m,t) + &
00937                   Fmm(m,mm) * exp(I*mm*theta)
00938           end do
00939        end do
00940     end do
00941 
00942     ! Compute f using FFT.
00943     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
00944     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, f(0,0:2*L-2), &
00945          f(0,0:2*L-2), FFTW_BACKWARD, FFTW_MEASURE)
00946     do t = 0, 2*L-1       
00947 
00948        ! Spatial shift in frequency.
00949        f(t,0:L-1) = fmt(0:L-1,t)
00950        f(t,L:2*L-2) = fmt(-(L-1):-1,t)
00951 
00952        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), f(t,0:2*L-2))
00953 
00954     end do
00955     call dfftw_destroy_plan(fftw_plan)
00956 
00957     ! Print finished if verbosity set.
00958     if (present(verbosity)) then
00959        if (verbosity > 0) then
00960           write(*,'(a,a)') SSHT_PROMPT, &
00961                'Inverse transform computed!'
00962        end if
00963     end if
00964 
00965   end subroutine ssht_core_dh_inverse_sov
00966 
00967 
00968   !----------------------------------------------------------------------------
00969   ! ssht_core_dh_inverse_sov_sym
00970   !
00987 
00988   subroutine ssht_core_dh_inverse_sov_sym(f, flm, L, spin, verbosity)
00989     
00990     integer, intent(in) :: L
00991     integer, intent(in) :: spin
00992     integer, intent(in), optional :: verbosity
00993     complex(dpc), intent(in) :: flm(0:L**2-1)
00994     complex(dpc), intent(out) :: f(0:2*L-1, 0:2*L-2)
00995 
00996     integer :: el, m, mm, t, p, ind
00997     real(dp) :: theta, phi
00998     real(dp) :: elfactor
00999     real(dp) :: dl(0:L-1, -(L-1):L-1)
01000     complex(dpc) :: Fmm(-(L-1):L-1, 0:L-1)
01001     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
01002     integer*8 :: fftw_plan
01003     character(len=STRING_LEN) :: format_spec
01004 
01005     integer :: eltmp
01006     real(dp) :: signs(0:L), ssign
01007     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
01008 
01009     ! Perform precomputations.
01010     do el = 0, 2*(L-1) + 1
01011        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
01012     end do
01013     do m = 0, L-1, 2
01014        signs(m)   =  1.0_dp
01015        signs(m+1) = -1.0_dp
01016     enddo
01017     ssign = signs(abs(spin))
01018 
01019     ! Print messages depending on verbosity level.
01020     if (present(verbosity)) then
01021        if (verbosity > 0) then
01022           write(*,'(a,a)') SSHT_PROMPT, &
01023                'Computing inverse transform using Driscoll and Healy sampling with'
01024           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
01025           write(*,trim(format_spec)) SSHT_PROMPT, &
01026                'parameters (L,spin,reality) = (', &
01027                L, ',', spin, ',FALSE)...'
01028        end if
01029        if (verbosity > 1) then
01030           write(*,'(a,a)') SSHT_PROMPT, &
01031                'Using routine ssht_core_dh_inverse_sov_sym...'
01032        end if
01033     end if
01034 
01035     ! Compute Fmm.
01036     Fmm(-(L-1):L-1, 0:L-1) = cmplx(0d0, 0d0)
01037     do el = abs(spin), L-1
01038        if (el /= 0 .and. el == abs(spin)) then
01039           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
01040           do eltmp = 0, abs(spin)
01041              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
01042                   sqrt_tbl(0:2*eltmp+1))
01043           end do       
01044           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01045                el, signs)
01046        else
01047           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
01048                sqrt_tbl(0:2*el+1))
01049           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01050                el, signs)
01051        end if
01052 
01053        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01054        do m = -el, el
01055           call ssht_sampling_elm2ind(ind, el, m)
01056           do mm = 0, el
01057              Fmm(m,mm) = Fmm(m,mm) + &
01058                   ssign * elfactor &
01059                   * exp(-I*PION2*(m+spin)) &
01060                   * dl(mm,m) * dl(mm,-spin) &
01061                   * flm(ind)
01062           end do
01063        end do
01064     end do
01065 
01066     ! Use symmetry to compute Fmm for negative mm.
01067 !!$    do m = -(L-1), L-1       
01068 !!$       do mm = -(L-1), -1
01069 !!$          Fmm(m,mm) = (-1)**(m+spin) * Fmm(m,-mm)
01070 !!$       end do
01071 !!$    end do
01072 
01073     ! Compute fmt.
01074 !!$    fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
01075 !!$    do t = 0, 2*L-1     
01076 !!$       theta = ssht_sampling_dh_t2theta(t, L)       
01077 !!$       do m = -(L-1), L-1          
01078 !!$          do mm = -(L-1), L-1
01079 !!$             fmt(m,t) = fmt(m,t) + &
01080 !!$                  Fmm(m,mm) * exp(I*mm*theta)
01081 !!$          end do
01082 !!$       end do
01083 !!$    end do
01084 
01085 
01086     fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
01087     do t = 0, 2*L-1     
01088        theta = ssht_sampling_dh_t2theta(t, L)       
01089        do m = -(L-1), L-1          
01090           fmt(m,t) = fmt(m,t) + Fmm(m,0)
01091        end do
01092        do mm = 1, L-1
01093           do m = -(L-1), L-1          
01094              fmt(m,t) = fmt(m,t) + &
01095 !!$                  Fmm(m,mm) * exp(I*mm*theta) &
01096 !!$                  + Fmm(m,-mm) * exp(-I*mm*theta)
01097                   Fmm(m,mm) * &
01098                   (exp(I*mm*theta) + signs(abs(m)) * ssign * exp(-I*mm*theta))
01099           end do
01100        end do
01101     end do
01102 
01103 
01104     ! Compute f using FFT.
01105     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
01106     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, f(0,0:2*L-2), &
01107          f(0,0:2*L-2), FFTW_BACKWARD, FFTW_MEASURE)
01108     do t = 0, 2*L-1       
01109 
01110        ! Spatial shift in frequency.
01111        f(t,0:L-1) = fmt(0:L-1,t)
01112        f(t,L:2*L-2) = fmt(-(L-1):-1,t)
01113 
01114        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), f(t,0:2*L-2))
01115 
01116     end do
01117     call dfftw_destroy_plan(fftw_plan)
01118 
01119     ! Print finished if verbosity set.
01120     if (present(verbosity)) then
01121        if (verbosity > 0) then
01122           write(*,'(a,a)') SSHT_PROMPT, &
01123                'Inverse transform computed!'
01124        end if
01125     end if
01126 
01127   end subroutine ssht_core_dh_inverse_sov_sym
01128 
01129 
01130   !----------------------------------------------------------------------------
01131   ! ssht_core_dh_inverse_sov_sym_real
01132   !
01150 
01151   subroutine ssht_core_dh_inverse_sov_sym_real(f, flm, L, verbosity)
01152     
01153     integer, intent(in) :: L
01154     integer, intent(in), optional :: verbosity
01155     complex(dpc), intent(in) :: flm(0:L**2-1)
01156     real(dp), intent(out) :: f(0:2*L-1, 0:2*L-2)
01157 
01158     integer :: el, m, mm, t, p, ind
01159     real(dp) :: theta, phi
01160     real(dp) :: elfactor
01161     real(dp) :: dl(0:L-1, 0:L-1)
01162     complex(dpc) :: Fmm(0:L-1, 0:L-1)
01163     complex(dpc) :: fmt(0:L-1, 0:2*L-1)
01164     integer*8 :: fftw_plan
01165 
01166     character(len=STRING_LEN) :: format_spec
01167 
01168     integer :: spin
01169     integer :: eltmp
01170     real(dp) :: signs(0:L), ssign
01171     real(dp) :: dl_mm_spin
01172     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
01173 
01174     ! Perform precomputations.
01175     do el = 0, 2*(L-1) + 1
01176        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
01177     end do
01178     do m = 0, L-1, 2
01179        signs(m)   =  1.0_dp
01180        signs(m+1) = -1.0_dp
01181     enddo
01182 
01183     ! Set spin to zero.
01184     spin = 0
01185     ssign = signs(abs(spin))    
01186 
01187     ! Print messages depending on verbosity level.
01188     if (present(verbosity)) then
01189        if (verbosity > 0) then
01190           write(*,'(a,a)') SSHT_PROMPT, &
01191                'Computing inverse transform using Driscoll and Healy sampling with'
01192           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
01193           write(*,trim(format_spec)) SSHT_PROMPT, &
01194                'parameters (L,spin,reality) = (', &
01195                L, ',', spin, ',TRUE)...'
01196        end if
01197        if (verbosity > 1) then
01198           write(*,'(a,a)') SSHT_PROMPT, &
01199                'Using routine ssht_core_dh_inverse_sov_sym_real...'
01200        end if
01201     end if
01202 
01203     ! Compute Fmm.
01204     Fmm(0:L-1, 0:L-1) = cmplx(0d0, 0d0)
01205     do el = abs(spin), L-1
01206        if (el /= 0 .and. el == abs(spin)) then
01207           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
01208           do eltmp = 0, abs(spin)
01209              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
01210                   sqrt_tbl(0:2*eltmp+1))
01211           end do
01212           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
01213                el, signs(0:el))
01214        else
01215           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
01216                sqrt_tbl(0:2*el+1))
01217           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
01218                el, signs(0:el))
01219        end if
01220 
01221 !       call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
01222        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01223        do m = 0, el
01224           call ssht_sampling_elm2ind(ind, el, m)
01225           do mm = 0, el
01226              if (spin <= 0) then
01227                 dl_mm_spin = dl(mm,-spin)
01228              else
01229                 dl_mm_spin =  signs(el) * signs(mm) * dl(mm,spin)
01230              end if
01231              Fmm(m,mm) = Fmm(m,mm) + &
01232                   ssign * elfactor &
01233                   * exp(-I*PION2*(m+spin)) &
01234                   * dl(mm,m) * dl_mm_spin &
01235                   * flm(ind)
01236           end do
01237        end do
01238     end do
01239 
01240     ! Compute fmt.
01241     fmt(0:L-1, 0:2*L-1) = cmplx(0d0, 0d0)
01242     do t = 0, 2*L-1     
01243        theta = ssht_sampling_dh_t2theta(t, L)       
01244 ! Switching order of mm and m loops changes computation time by a factor of ~10!
01245        do m = 0, L-1          
01246           fmt(m,t) = fmt(m,t) + Fmm(m,0)
01247        end do
01248        do mm = 1, L-1
01249           do m = 0, L-1          
01250              fmt(m,t) = fmt(m,t) + &
01251                   Fmm(m,mm) * (exp(I*mm*theta)  + signs(m) * ssign * exp(-I*mm*theta))
01252           end do
01253        end do
01254     end do
01255 
01256     ! Compute f using FFT.
01257     f(0:2*L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
01258     call dfftw_plan_dft_c2r_1d(fftw_plan, 2*L-1, Fmm(0:L-1,0), &
01259          f(0,0:2*L-2), FFTW_MEASURE)
01260     do t = 0, 2*L-1       
01261        call dfftw_execute_dft_c2r(fftw_plan, fmt(0:L-1,t), f(t,0:2*L-2))
01262     end do
01263     call dfftw_destroy_plan(fftw_plan)
01264 
01265     ! Print finished if verbosity set.
01266     if (present(verbosity)) then
01267        if (verbosity > 0) then
01268           write(*,'(a,a)') SSHT_PROMPT, &
01269                'Inverse transform computed!'
01270        end if
01271     end if
01272 
01273   end subroutine ssht_core_dh_inverse_sov_sym_real
01274 
01275 
01276   !----------------------------------------------------------------------------
01277   ! GL
01278   !----------------------------------------------------------------------------
01279 
01280 
01281   !----------------------------------------------------------------------------
01282   ! ssht_core_gl_inverse_sov_sym
01283   !
01300 
01301   subroutine ssht_core_gl_inverse_sov_sym(f, flm, L, spin, verbosity)
01302     
01303     integer, intent(in) :: L
01304     integer, intent(in) :: spin
01305     integer, intent(in), optional :: verbosity
01306     complex(dpc), intent(in) :: flm(0:L**2-1)
01307     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
01308 
01309     integer :: el, m, mm, t, p, ind
01310     real(dp) :: theta, phi
01311     real(dp) :: elfactor
01312     real(dp) :: dl(0:L-1, -(L-1):L-1)
01313     complex(dpc) :: Fmm(-(L-1):L-1, 0:L-1)
01314     complex(dpc) :: fmt(-(L-1):L-1, 0:L-1)
01315     integer*8 :: fftw_plan
01316     character(len=STRING_LEN) :: format_spec
01317 
01318     real(dp) :: thetas(0:L-1)
01319     real(dp) :: weights(0:L-1)
01320 
01321     integer :: eltmp
01322     real(dp) :: signs(0:L), ssign
01323     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
01324 
01325     ! Perform precomputations.
01326     do el = 0, 2*(L-1) + 1
01327        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
01328     end do
01329     do m = 0, L-1, 2
01330        signs(m)   =  1.0_dp
01331        signs(m+1) = -1.0_dp
01332     enddo
01333     ssign = signs(abs(spin))
01334 
01335     ! Print messages depending on verbosity level.
01336     if (present(verbosity)) then
01337        if (verbosity > 0) then
01338           write(*,'(a,a)') SSHT_PROMPT, &
01339                'Computing inverse transform using Gauss-Legendre sampling with'
01340           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
01341           write(*,trim(format_spec)) SSHT_PROMPT, &
01342                'parameters (L,spin,reality) = (', &
01343                L, ',', spin, ',FALSE)...'
01344        end if
01345        if (verbosity > 1) then
01346           write(*,'(a,a)') SSHT_PROMPT, &
01347                'Using routine ssht_core_gl_inverse_sov_sym...'
01348        end if
01349     end if
01350 
01351     ! Compute weights and theta positions.
01352     call ssht_sampling_gl_thetas_weights(thetas, weights, L)
01353 
01354     ! Compute Fmm.
01355     Fmm(-(L-1):L-1, 0:L-1) = cmplx(0d0, 0d0)
01356     do el = abs(spin), L-1
01357        if (el /= 0 .and. el == abs(spin)) then
01358           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
01359           do eltmp = 0, abs(spin)
01360              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
01361                   sqrt_tbl(0:2*eltmp+1))
01362           end do       
01363           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01364                el, signs)
01365        else
01366           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
01367                sqrt_tbl(0:2*el+1))
01368           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01369                el, signs)
01370        end if
01371  
01372        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01373        do m = -el, el
01374           call ssht_sampling_elm2ind(ind, el, m)
01375           do mm = 0, el
01376              Fmm(m,mm) = Fmm(m,mm) + &
01377                   ssign * elfactor &
01378                   * exp(-I*PION2*(m+spin)) &
01379                   * dl(mm,m) * dl(mm,-spin) &
01380                   * flm(ind)
01381           end do
01382        end do
01383     end do
01384 
01385     ! Use symmetry to compute Fmm for negative mm.
01386 !!$    do m = -(L-1), L-1       
01387 !!$       do mm = -(L-1), -1
01388 !!$          Fmm(m,mm) = (-1)**(m+spin) * Fmm(m,-mm)
01389 !!$       end do
01390 !!$    end do
01391 
01392     ! Compute fmt.
01393 !!$    fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
01394 !!$    do t = 0, 2*L-1     
01395 !!$       theta = ssht_sampling_dh_t2theta(t, L)       
01396 !!$       do m = -(L-1), L-1          
01397 !!$          do mm = -(L-1), L-1
01398 !!$             fmt(m,t) = fmt(m,t) + &
01399 !!$                  Fmm(m,mm) * exp(I*mm*theta)
01400 !!$          end do
01401 !!$       end do
01402 !!$    end do
01403 
01404 
01405     fmt(-(L-1):L-1, 0:L-1) = cmplx(0d0, 0d0)
01406     do t = 0, L-1     
01407        theta = thetas(t)
01408        do m = -(L-1), L-1          
01409           fmt(m,t) = fmt(m,t) + Fmm(m,0)
01410        end do
01411        do mm = 1, L-1
01412           do m = -(L-1), L-1    
01413              fmt(m,t) = fmt(m,t) + &
01414 !!$                  Fmm(m,mm) * exp(I*mm*theta) &
01415 !!$                  + Fmm(m,-mm) * exp(-I*mm*theta)
01416                   Fmm(m,mm) * &
01417                   (exp(I*mm*theta) + signs(abs(m)) * ssign * exp(-I*mm*theta))
01418           end do
01419        end do
01420     end do
01421 
01422     ! Compute f using FFT.
01423     f(0:L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
01424     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, f(0,0:2*L-2), &
01425          f(0,0:2*L-2), FFTW_BACKWARD, FFTW_MEASURE)
01426     do t = 0, L-1       
01427 
01428        ! Spatial shift in frequency.
01429        f(t,0:L-1) = fmt(0:L-1,t)
01430        f(t,L:2*L-2) = fmt(-(L-1):-1,t)
01431 
01432        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), f(t,0:2*L-2))
01433 
01434     end do
01435     call dfftw_destroy_plan(fftw_plan)
01436 
01437     ! Print finished if verbosity set.
01438     if (present(verbosity)) then
01439        if (verbosity > 0) then
01440           write(*,'(a,a)') SSHT_PROMPT, &
01441                'Inverse transform computed!'
01442        end if
01443     end if
01444 
01445   end subroutine ssht_core_gl_inverse_sov_sym
01446 
01447 
01448   !----------------------------------------------------------------------------
01449   ! ssht_core_gl_inverse_sov_sym_real
01450   !
01468 
01469   subroutine ssht_core_gl_inverse_sov_sym_real(f, flm, L, verbosity)
01470     
01471     integer, intent(in) :: L
01472     integer, intent(in), optional :: verbosity
01473     complex(dpc), intent(in) :: flm(0:L**2-1)
01474     real(dp), intent(out) :: f(0:L-1, 0:2*L-2)
01475 
01476     integer :: el, m, mm, t, p, ind
01477     real(dp) :: theta, phi
01478     real(dp) :: elfactor
01479     real(dp) :: dl(0:L-1, 0:L-1)
01480     complex(dpc) :: Fmm(0:L-1, 0:L-1)
01481     complex(dpc) :: fmt(0:L-1, 0:L-1)
01482     integer*8 :: fftw_plan
01483 
01484     character(len=STRING_LEN) :: format_spec
01485 
01486     real(dp) :: thetas(0:L-1)
01487     real(dp) :: weights(0:L-1)
01488 
01489     integer :: spin
01490     integer :: eltmp
01491     real(dp) :: signs(0:L), ssign
01492     real(dp) :: dl_mm_spin
01493     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
01494 
01495     ! Perform precomputations.
01496     do el = 0, 2*(L-1) + 1
01497        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
01498     end do
01499     do m = 0, L-1, 2
01500        signs(m)   =  1.0_dp
01501        signs(m+1) = -1.0_dp
01502     enddo
01503 
01504     ! Set spin to zero.
01505     spin = 0
01506     ssign = signs(abs(spin))
01507     
01508     ! Print messages depending on verbosity level.
01509     if (present(verbosity)) then
01510        if (verbosity > 0) then
01511           write(*,'(a,a)') SSHT_PROMPT, &
01512                'Computing inverse transform using Gauss-Legendre sampling with'
01513           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
01514           write(*,trim(format_spec)) SSHT_PROMPT, &
01515                'parameters (L,spin,reality) = (', &
01516                L, ',', spin, ',TRUE)...'
01517        end if
01518        if (verbosity > 1) then
01519           write(*,'(a,a)') SSHT_PROMPT, &
01520                'Using routine ssht_core_gl_inverse_sov_sym_real...'
01521        end if
01522     end if
01523 
01524     ! Compute weights and theta positions.
01525     call ssht_sampling_gl_thetas_weights(thetas, weights, L)
01526 
01527     ! Compute Fmm.
01528     Fmm(0:L-1, 0:L-1) = cmplx(0d0, 0d0)
01529     do el = abs(spin), L-1
01530       if (el /= 0 .and. el == abs(spin)) then
01531           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
01532           do eltmp = 0, abs(spin)
01533              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
01534                   sqrt_tbl(0:2*eltmp+1))
01535           end do       
01536           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
01537                el, signs(0:el))
01538        else
01539           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
01540                sqrt_tbl(0:2*el+1))
01541           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
01542                el, signs(0:el))
01543        end if
01544 
01545        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01546        do m = 0, el
01547           call ssht_sampling_elm2ind(ind, el, m)
01548           do mm = 0, el
01549              if (spin <= 0) then
01550                 dl_mm_spin = dl(mm,-spin)
01551              else
01552                 dl_mm_spin =  signs(el) * signs(mm) * dl(mm,spin)
01553              end if
01554 
01555              Fmm(m,mm) = Fmm(m,mm) + &
01556                   ssign * elfactor &
01557                   * exp(-I*PION2*(m+spin)) &
01558                   * dl(mm,m) * dl_mm_spin &
01559                   * flm(ind)
01560           end do
01561        end do
01562     end do
01563 
01564     ! Compute fmt.
01565     fmt(0:L-1, 0:L-1) = cmplx(0d0, 0d0)
01566     do t = 0, L-1     
01567        theta = thetas(t)
01568        do m = 0, L-1          
01569           fmt(m,t) = fmt(m,t) + Fmm(m,0)
01570        end do
01571        do mm = 1, L-1
01572           do m = 0, L-1          
01573              fmt(m,t) = fmt(m,t) + &
01574                   Fmm(m,mm) * (exp(I*mm*theta)  + signs(m) * ssign * exp(-I*mm*theta))
01575           end do
01576        end do
01577     end do
01578 
01579     ! Compute f using FFT.
01580     f(0:L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
01581     call dfftw_plan_dft_c2r_1d(fftw_plan, 2*L-1, Fmm(0:L-1,0), &
01582          f(0,0:2*L-2), FFTW_MEASURE)
01583     do t = 0, L-1       
01584        call dfftw_execute_dft_c2r(fftw_plan, fmt(0:L-1,t), f(t,0:2*L-2))
01585     end do
01586     call dfftw_destroy_plan(fftw_plan)
01587 
01588     ! Print finished if verbosity set.
01589     if (present(verbosity)) then
01590        if (verbosity > 0) then
01591           write(*,'(a,a)') SSHT_PROMPT, &
01592                'Inverse transform computed!'
01593        end if
01594     end if
01595 
01596   end subroutine ssht_core_gl_inverse_sov_sym_real
01597 
01598 
01599   !----------------------------------------------------------------------------
01600   ! MWEO
01601   !----------------------------------------------------------------------------
01602 
01603 
01604   !----------------------------------------------------------------------------
01605   ! ssht_core_mweo_inverse_direct
01606   !
01625 
01626   subroutine ssht_core_mweo_inverse_direct(f, flm, L, spin, verbosity)
01627     
01628     integer, intent(in) :: L
01629     integer, intent(in) :: spin
01630     integer, intent(in), optional :: verbosity
01631     complex(dpc), intent(in) :: flm(0:L**2-1)
01632     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
01633 
01634     integer :: el, m, t, p, ind
01635     real(dp) :: theta, phi
01636     real(dp) :: elfactor
01637     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
01638     character(len=STRING_LEN) :: format_spec
01639 
01640     ! Print messages depending on verbosity level.
01641     if (present(verbosity)) then
01642        if (verbosity > 0) then
01643           write(*,'(a,a,a)') SSHT_PROMPT, &
01644                'Computing inverse transform using McEwen and Wiaux', &
01645                ' even-odd sampling with'
01646           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
01647                digit(spin),',a)'
01648           write(*,trim(format_spec)) SSHT_PROMPT, &
01649                'parameters (L,spin,reality) = (', &
01650                L, ',', spin, ',FALSE)...'
01651        end if
01652        if (verbosity > 1) then
01653           write(*,'(a,a)') SSHT_PROMPT, &
01654                'Using routine ssht_core_mweo_inverse_direct...'
01655        end if
01656     end if
01657 
01658     f(0:L-1 ,0:2*L-2) = cmplx(0d0, 0d0)
01659     do el = abs(spin), L-1
01660        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01661        do t = 0, L-1
01662           theta = ssht_sampling_mweo_t2theta(t, L)             
01663           call ssht_dl_beta_operator(dl(-el:el,-el:el), theta, el)
01664           do m = -el, el
01665              call ssht_sampling_elm2ind(ind, el, m)
01666              do p = 0, 2*L-2
01667                 phi = ssht_sampling_mweo_p2phi(p, L)
01668                 f(t,p) = f(t,p) + &
01669                      (-1)**spin * elfactor &
01670                      * exp(I*m*phi) &
01671                      * dl(m,-spin) * flm(ind)
01672              end do
01673           end do
01674           
01675        end do
01676     end do
01677 
01678     ! Print finished if verbosity set.
01679     if (present(verbosity)) then
01680        if (verbosity > 0) then
01681           write(*,'(a,a)') SSHT_PROMPT, &
01682                'Inverse transform computed!'
01683        end if
01684     end if
01685 
01686   end subroutine ssht_core_mweo_inverse_direct
01687 
01688 
01689   !----------------------------------------------------------------------------
01690   ! ssht_core_mweo_inverse_sov_direct
01691   !
01710 
01711   subroutine ssht_core_mweo_inverse_sov_direct(f, flm, L, spin, verbosity)
01712     
01713     integer, intent(in) :: L
01714     integer, intent(in) :: spin
01715     integer, intent(in), optional :: verbosity
01716     complex(dpc), intent(in) :: flm(0:L**2-1)
01717     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
01718 
01719     integer :: el, m, mm, t, p, ind
01720     real(dp) :: theta, phi
01721     real(dp) :: elfactor
01722     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
01723     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
01724     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
01725     character(len=STRING_LEN) :: format_spec
01726 
01727     ! Print messages depending on verbosity level.
01728     if (present(verbosity)) then
01729        if (verbosity > 0) then
01730           write(*,'(a,a,a)') SSHT_PROMPT, &
01731                'Computing inverse transform using McEwen and Wiaux', &
01732                ' even-odd sampling with'
01733           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
01734                digit(spin),',a)'
01735           write(*,trim(format_spec)) SSHT_PROMPT, &
01736                'parameters (L,spin,reality) = (', &
01737                L, ',', spin, ',FALSE)...'
01738        end if
01739        if (verbosity > 1) then
01740           write(*,'(a,a)') SSHT_PROMPT, &
01741                'Using routine ssht_core_mweo_inverse_sov_direct...'
01742        end if
01743     end if
01744 
01745     ! Compute Fmm.
01746     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
01747     do el = abs(spin), L-1
01748        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
01749        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01750        do m = -el, el
01751           call ssht_sampling_elm2ind(ind, el, m)
01752           do mm = -el, el
01753              Fmm(m,mm) = Fmm(m,mm) + &
01754                   (-1)**spin * elfactor &
01755                   * exp(-I*PION2*(m+spin)) &
01756                   * dl(mm,m) * dl(mm,-spin) &
01757                   * flm(ind)
01758           end do
01759        end do
01760     end do
01761 
01762     ! Compute fext using 2D DFT.
01763     fext(0:2*L-2, 0:2*L-2) = cmplx(0d0, 0d0)
01764     do t = 0, 2*L-2     
01765        theta = ssht_sampling_mweo_t2theta(t, L)    
01766        do p = 0, 2*L-2
01767           phi = ssht_sampling_mweo_p2phi(p, L)
01768           do m = -(L-1), L-1          
01769              do mm = -(L-1), L-1
01770                 fext(t,p) = fext(t,p) + &
01771                      Fmm(m,mm) * exp(I*m*phi + I*mm*theta)
01772              end do
01773           end do
01774        end do
01775     end do
01776 
01777     ! Extract f from version of f extended to the torus (fext).
01778     f(0:L-1, 0:2*L-2) = fext(0:L-1, 0:2*L-2)
01779 
01780     ! Print finished if verbosity set.
01781     if (present(verbosity)) then
01782        if (verbosity > 0) then
01783           write(*,'(a,a)') SSHT_PROMPT, &
01784                'Inverse transform computed!'
01785        end if
01786     end if
01787 
01788   end subroutine ssht_core_mweo_inverse_sov_direct
01789 
01790 
01791   !----------------------------------------------------------------------------
01792   ! ssht_core_mweo_inverse_sov
01793   !
01809 
01810   subroutine ssht_core_mweo_inverse_sov(f, flm, L, spin, verbosity)
01811     
01812     integer, intent(in) :: L
01813     integer, intent(in) :: spin
01814     integer, intent(in), optional :: verbosity
01815     complex(dpc), intent(in) :: flm(0:L**2-1)
01816     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
01817 
01818     integer :: el, m, mm, t, p, ind
01819     real(dp) :: theta, phi
01820     real(dp) :: elfactor
01821     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
01822     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
01823     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
01824     integer*8 :: fftw_plan
01825     character(len=STRING_LEN) :: format_spec
01826 
01827     ! Print messages depending on verbosity level.
01828     if (present(verbosity)) then
01829        if (verbosity > 0) then
01830           write(*,'(a,a,a)') SSHT_PROMPT, &
01831                'Computing inverse transform using McEwen and Wiaux', &
01832                ' even-odd sampling with'
01833           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
01834                digit(spin),',a)'
01835           write(*,trim(format_spec)) SSHT_PROMPT, &
01836                'parameters (L,spin,reality) = (', &
01837                L, ',', spin, ',FALSE)...'
01838        end if
01839        if (verbosity > 1) then
01840           write(*,'(a,a)') SSHT_PROMPT, &
01841                'Using routine ssht_core_mweo_inverse_sov...'
01842        end if
01843     end if
01844 
01845     ! Compute Fmm.
01846     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
01847     do el = abs(spin), L-1
01848        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
01849        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
01850        do m = -el, el
01851           call ssht_sampling_elm2ind(ind, el, m)
01852           do mm = -el, el
01853              Fmm(m,mm) = Fmm(m,mm) + &
01854                   (-1)**spin * elfactor &
01855                   * exp(-I*PION2*(m+spin)) &
01856                   * dl(mm,m) * dl(mm,-spin) &
01857                   * flm(ind)
01858           end do
01859        end do
01860     end do
01861 
01862     ! Apply phase modulation to account for sampling offset.
01863 !!$    do m = 0, 2*L-2
01864 !!$       do mm = 0, 2*L-2
01865 !!$          Fmm(m-L+1,mm-L+1) = Fmm(m-L+1,mm-L+1) * exp(I*(m+mm)*PI/(2d0*L-1d0))
01866 !!$       end do
01867 !!$    end do
01868     do m = -(L-1), L-1
01869        do mm = -(L-1), L-1
01870           Fmm(m,mm) = Fmm(m,mm) * exp(I*(m+mm)*PI/(2d0*L-1d0))
01871        end do
01872     end do  
01873     
01874     ! Apply spatial shift.
01875     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
01876     fext(L:2*L-2, 0:L-1) = Fmm(-(L-1):-1,0:L-1)
01877     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
01878     fext(L:2*L-2, L:2*L-2) = Fmm(-(L-1):-1,-(L-1):-1)
01879 ! If apply phase shift below then just copy Fmm.
01880 !!$    fext(0:2*L-2, 0:2*L-2) = Fmm(-(L-1):L-1,-(L-1):L-1)
01881 
01882     ! Perform 2D FFT.
01883     call dfftw_plan_dft_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:2*L-2,0:2*L-2), &
01884          fext(0:2*L-2,0:2*L-2), FFTW_BACKWARD, FFTW_ESTIMATE)
01885     call dfftw_execute_dft(fftw_plan, fext(0:2*L-2,0:2*L-2), fext(0:2*L-2,0:2*L-2))
01886     call dfftw_destroy_plan(fftw_plan)
01887 
01888     ! Extract f from version of f extended to the torus (fext).
01889     ! Also note that additional phase modulation is again applied to 
01890     ! account for sampling offset.
01891     f(0:L-1, 0:2*L-2) = transpose(fext(0:2*L-2, 0:L-1)) !&
01892 !         * exp(-I*(L-1)*2d0*PI/(2d0*L-1d0))
01893 
01894 ! If don't apply spatial shift above then apply phase modulation here.
01895 !!$    do t = 0, L-1     
01896 !!$       theta = ssht_sampling_mweo_t2theta(t, L)    
01897 !!$       do p = 0, 2*L-2
01898 !!$          phi = ssht_sampling_mweo_p2phi(p, L)
01899 !!$          f(t,p) = f(t,p) * exp(-I*(L-1)*(theta+phi))
01900 !!$       end do
01901 !!$    end do
01902 
01903     ! Print finished if verbosity set.
01904     if (present(verbosity)) then
01905        if (verbosity > 0) then
01906           write(*,'(a,a)') SSHT_PROMPT, &
01907                'Inverse transform computed!'
01908        end if
01909     end if
01910 
01911   end subroutine ssht_core_mweo_inverse_sov
01912 
01913 
01914   !----------------------------------------------------------------------------
01915   ! ssht_core_mweo_inverse_sov_sym
01916   !
01933 
01934   subroutine ssht_core_mweo_inverse_sov_sym(f, flm, L, spin, verbosity)
01935     
01936     integer, intent(in) :: L
01937     integer, intent(in) :: spin
01938     integer, intent(in), optional :: verbosity
01939     complex(dpc), intent(in) :: flm(0:L**2-1)
01940     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
01941 
01942     integer :: el, m, mm, t, p, ind
01943     real(dp) :: theta, phi
01944     real(dp) :: elfactor
01945     real(dp) :: dl(0:L-1, -(L-1):L-1)
01946     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
01947     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
01948     integer*8 :: fftw_plan
01949     character(len=STRING_LEN) :: format_spec
01950 
01951     integer :: eltmp
01952     real(dp) :: signs(0:L), ssign
01953     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
01954 
01955     ! Perform precomputations.
01956     do el = 0, 2*(L-1) + 1
01957        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
01958     end do
01959     do m = 0, L-1, 2
01960        signs(m)   =  1.0_dp
01961        signs(m+1) = -1.0_dp
01962     enddo
01963     ssign = signs(abs(spin))
01964 
01965     ! Print messages depending on verbosity level.
01966     if (present(verbosity)) then
01967        if (verbosity > 0) then
01968           write(*,'(a,a,a)') SSHT_PROMPT, &
01969                'Computing inverse transform using McEwen and Wiaux', &
01970                ' even-odd sampling with'
01971           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
01972                digit(spin),',a)'
01973           write(*,trim(format_spec)) SSHT_PROMPT, &
01974                'parameters (L,spin,reality) = (', &
01975                L, ',', spin, ',FALSE)...'
01976        end if
01977        if (verbosity > 1) then
01978           write(*,'(a,a)') SSHT_PROMPT, &
01979                'Using routine ssht_core_mweo_inverse_sov_sym...'
01980        end if
01981     end if
01982 
01983     ! Compute Fmm.
01984     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
01985     do el = abs(spin), L-1
01986        if (el /= 0 .and. el == abs(spin)) then
01987           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
01988           do eltmp = 0, abs(spin)
01989              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
01990                   sqrt_tbl(0:2*eltmp+1))
01991           end do       
01992           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01993                el, signs)
01994        else
01995           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
01996                sqrt_tbl(0:2*el+1))
01997           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
01998                el, signs)
01999        end if
02000 
02001        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02002        do m = -el, el
02003           call ssht_sampling_elm2ind(ind, el, m)
02004           do mm = 0, el
02005              Fmm(m,mm) = Fmm(m,mm) + &
02006                   ssign * elfactor &
02007                   * exp(-I*PION2*(m+spin)) &
02008                   * dl(mm,m) * dl(mm,-spin) &
02009                   * flm(ind)
02010           end do
02011        end do
02012     end do
02013 
02014     ! Use symmetry to compute Fmm for negative mm.
02015     do mm = -(L-1), -1
02016        do m = -(L-1), L-1      
02017           Fmm(m,mm) = signs(abs(m)) * ssign * Fmm(m,-mm)
02018        end do
02019     end do
02020 
02021     ! Apply phase modulation to account for sampling offset.
02022 !!$    do m = 0, 2*L-2
02023 !!$       do mm = 0, 2*L-2
02024 !!$          Fmm(m-L+1,mm-L+1) = Fmm(m-L+1,mm-L+1) * exp(I*(m+mm)*PI/(2d0*L-1d0))
02025 !!$       end do
02026 !!$    end do
02027     do mm = -(L-1), L-1
02028        do m = -(L-1), L-1
02029           Fmm(m,mm) = Fmm(m,mm) * exp(I*(m+mm)*PI/(2d0*L-1d0))
02030        end do
02031     end do    
02032 
02033     ! Apply spatial shift.
02034     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
02035     fext(L:2*L-2, 0:L-1) = Fmm(-(L-1):-1,0:L-1)
02036     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
02037     fext(L:2*L-2, L:2*L-2) = Fmm(-(L-1):-1,-(L-1):-1)
02038 ! If apply phase shift below then just copy Fmm.
02039 !!$    fext(0:2*L-2, 0:2*L-2) = Fmm(-(L-1):L-1,-(L-1):L-1)
02040 
02041     ! Perform 2D FFT.
02042     call dfftw_plan_dft_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:2*L-2,0:2*L-2), &
02043          fext(0:2*L-2,0:2*L-2), FFTW_BACKWARD, FFTW_ESTIMATE)
02044     call dfftw_execute_dft(fftw_plan, fext(0:2*L-2,0:2*L-2), fext(0:2*L-2,0:2*L-2))
02045     call dfftw_destroy_plan(fftw_plan)
02046 
02047     ! Extract f from version of f extended to the torus (fext).
02048     ! Also note that additional phase modulation is again applied to 
02049     ! account for sampling offset.
02050     f(0:L-1, 0:2*L-2) = transpose(fext(0:2*L-2, 0:L-1))! &
02051 !         * exp(-I*(L-1)*2d0*PI/(2d0*L-1d0))
02052 
02053 ! If don't apply spatial shift above then apply phase modulation here.
02054 !!$    do t = 0, L-1     
02055 !!$       theta = ssht_sampling_mweo_t2theta(t, L)    
02056 !!$       do p = 0, 2*L-2
02057 !!$          phi = ssht_sampling_mweo_p2phi(p, L)
02058 !!$          f(t,p) = f(t,p) * exp(-I*(L-1)*(theta+phi))
02059 !!$       end do
02060 !!$    end do
02061 
02062     ! Print finished if verbosity set.
02063     if (present(verbosity)) then
02064        if (verbosity > 0) then
02065           write(*,'(a,a)') SSHT_PROMPT, &
02066                'Inverse transform computed!'
02067        end if
02068     end if
02069 
02070   end subroutine ssht_core_mweo_inverse_sov_sym
02071 
02072 
02073   !----------------------------------------------------------------------------
02074   ! ssht_core_mweo_inverse_sov_sym_real
02075   !
02093 
02094   subroutine ssht_core_mweo_inverse_sov_sym_real(f, flm, L, verbosity)
02095     
02096     integer, intent(in) :: L
02097     integer, intent(in), optional :: verbosity
02098     complex(dpc), intent(in) :: flm(0:L**2-1)
02099     real(dp), intent(out) :: f(0:L-1, 0:2*L-2)
02100 
02101     integer :: el, m, mm, t, p, ind
02102     real(dp) :: theta, phi
02103     real(dp) :: elfactor
02104     real(dp) :: dl(0:L-1, 0:L-1)
02105     complex(dpc) :: Fmm(0:L-1, -(L-1):L-1)
02106     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
02107     real(dp) :: fext_real(0:2*L-2,0:2*L-2)
02108     integer*8 :: fftw_plan
02109     character(len=STRING_LEN) :: format_spec
02110 
02111     integer :: spin
02112     integer :: eltmp
02113     real(dp) :: signs(0:L), ssign
02114     real(dp) :: dl_mm_spin
02115     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
02116 
02117     ! Perform precomputations.
02118     do el = 0, 2*(L-1) + 1
02119        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
02120     end do
02121     do m = 0, L-1, 2
02122        signs(m)   =  1.0_dp
02123        signs(m+1) = -1.0_dp
02124     enddo
02125 
02126     ! Set spin to zero.
02127     spin = 0
02128     ssign = signs(abs(spin))
02129 
02130     ! Print messages depending on verbosity level.
02131     if (present(verbosity)) then
02132        if (verbosity > 0) then
02133           write(*,'(a,a,a)') SSHT_PROMPT, &
02134                'Computing inverse transform using McEwen and Wiaux', &
02135                ' even-odd sampling with'
02136           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
02137                digit(spin),',a)'
02138           write(*,trim(format_spec)) SSHT_PROMPT, &
02139                'parameters (L,spin,reality) = (', &
02140                L, ',', spin, ',TRUE)...'
02141        end if
02142        if (verbosity > 1) then
02143           write(*,'(a,a)') SSHT_PROMPT, &
02144                'Using routine ssht_core_mweo_inverse_sov_sym_real...'
02145        end if
02146     end if
02147 
02148     ! Compute Fmm.
02149     Fmm(0:L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02150     do el = abs(spin), L-1
02151        if (el /= 0 .and. el == abs(spin)) then
02152           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
02153           do eltmp = 0, abs(spin)
02154              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
02155                   sqrt_tbl(0:2*eltmp+1))
02156           end do       
02157           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
02158                el, signs(0:el))
02159        else
02160           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
02161                sqrt_tbl(0:2*el+1))
02162           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
02163                el, signs(0:el))
02164        end if
02165        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02166        do m = 0, el
02167           call ssht_sampling_elm2ind(ind, el, m)
02168           do mm = 0, el
02169              if (spin <= 0) then
02170                 dl_mm_spin = dl(mm,-spin)
02171              else
02172                 dl_mm_spin =  signs(el) * signs(mm) * dl(mm,spin)
02173              end if
02174 
02175              Fmm(m,mm) = Fmm(m,mm) + &
02176                   ssign * elfactor &
02177                   * exp(-I*PION2*(m+spin)) &
02178                   * dl(mm,m) * dl_mm_spin &
02179                   * flm(ind)
02180           end do
02181        end do
02182     end do
02183 
02184     ! Use symmetry to compute Fmm for negative mm.
02185     do m = 0, L-1       
02186        do mm = -(L-1), -1
02187           Fmm(m,mm) = signs(m) * ssign * Fmm(m,-mm)
02188        end do
02189     end do
02190 
02191     ! Apply phase modulation to account for sampling offset.
02192     do mm = -(L-1), L-1
02193        do m = 0, L-1
02194           Fmm(m,mm) = Fmm(m,mm) * exp(I*(m+mm)*PI/(2d0*L-1d0))
02195        end do
02196     end do
02197     
02198     ! Apply spatial shift.
02199     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
02200     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
02201 
02202     ! Perform 2D FFT.
02203     call dfftw_plan_dft_c2r_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:L-1,0:2*L-2), &
02204          fext_real(0:2*L-2,0:2*L-2), FFTW_ESTIMATE)
02205     call dfftw_execute_dft_c2r(fftw_plan, fext(0:L-1,0:2*L-2), fext_real(0:2*L-2,0:2*L-2))
02206     call dfftw_destroy_plan(fftw_plan)
02207 
02208     ! Extract f from version of f extended to the torus (fext).
02209     ! Also note that additional phase modulation is again applied to 
02210     ! account for sampling offset.
02211     f(0:L-1, 0:2*L-2) = transpose(fext_real(0:2*L-2, 0:L-1))
02212 
02213     ! Print finished if verbosity set.
02214     if (present(verbosity)) then
02215        if (verbosity > 0) then
02216           write(*,'(a,a)') SSHT_PROMPT, &
02217                'Inverse transform computed!'
02218        end if
02219     end if
02220 
02221   end subroutine ssht_core_mweo_inverse_sov_sym_real
02222 
02223 
02224   !----------------------------------------------------------------------------
02225   ! MW
02226   !----------------------------------------------------------------------------
02227 
02228 
02229   !----------------------------------------------------------------------------
02230   ! ssht_core_mw_inverse_sov_direct
02231   !
02250 
02251   subroutine ssht_core_mw_inverse_sov_direct(f, flm, L, spin, verbosity)
02252     
02253     integer, intent(in) :: L
02254     integer, intent(in) :: spin
02255     integer, intent(in), optional :: verbosity
02256     complex(dpc), intent(in) :: flm(0:L**2-1)
02257     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
02258 
02259     integer :: el, m, mm, t, p, ind
02260     real(dp) :: theta, phi
02261     real(dp) :: elfactor
02262     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
02263     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02264     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
02265     character(len=STRING_LEN) :: format_spec
02266 
02267     ! Print messages depending on verbosity level.
02268     if (present(verbosity)) then
02269        if (verbosity > 0) then
02270           write(*,'(a,a,a)') SSHT_PROMPT, &
02271                'Computing inverse transform using McEwen and Wiaux', &
02272                ' sampling with'
02273           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
02274                digit(spin),',a)'
02275           write(*,trim(format_spec)) SSHT_PROMPT, &
02276                'parameters (L,spin,reality) = (', &
02277                L, ',', spin, ',FALSE)...'
02278        end if
02279        if (verbosity > 1) then
02280           write(*,'(a,a)') SSHT_PROMPT, &
02281                'Using routine ssht_core_mweo_inverse_direct...'
02282        end if
02283     end if
02284 
02285     ! Compute Fmm.
02286     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02287     do el = abs(spin), L-1
02288        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
02289        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02290        do m = -el, el
02291           call ssht_sampling_elm2ind(ind, el, m)
02292           do mm = -el, el
02293              Fmm(m,mm) = Fmm(m,mm) + &
02294                   (-1)**spin * elfactor &
02295                   * exp(-I*PION2*(m+spin)) &
02296                   * dl(mm,m) * dl(mm,-spin) &
02297                   * flm(ind)
02298           end do
02299        end do
02300     end do
02301 
02302     ! Compute fext using 2D DFT.
02303     fext(0:2*L-2, 0:2*L-2) = cmplx(0d0, 0d0)
02304     do t = 0, 2*L-2     
02305        theta = ssht_sampling_mw_t2theta(t, L)    
02306        do p = 0, 2*L-2
02307           phi = ssht_sampling_mw_p2phi(p, L)
02308           do m = -(L-1), L-1          
02309              do mm = -(L-1), L-1
02310                 fext(t,p) = fext(t,p) + &
02311                      Fmm(m,mm) * exp(I*m*phi + I*mm*theta)
02312              end do
02313           end do
02314        end do
02315     end do
02316 
02317     ! Extract f from version of f extended to the torus (fext).
02318     f(0:L-1, 0:2*L-2) = fext(0:L-1, 0:2*L-2)
02319 
02320     ! Print finished if verbosity set.
02321     if (present(verbosity)) then
02322        if (verbosity > 0) then
02323           write(*,'(a,a)') SSHT_PROMPT, &
02324                'Inverse transform computed!'
02325        end if
02326     end if
02327 
02328   end subroutine ssht_core_mw_inverse_sov_direct
02329 
02330 
02331   !----------------------------------------------------------------------------
02332   ! ssht_core_mw_inverse_sov
02333   !
02349 
02350   subroutine ssht_core_mw_inverse_sov(f, flm, L, spin, verbosity)
02351     
02352     integer, intent(in) :: L
02353     integer, intent(in) :: spin
02354     integer, intent(in), optional :: verbosity
02355     complex(dpc), intent(in) :: flm(0:L**2-1)
02356     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
02357 
02358     integer :: el, m, mm, t, p, ind
02359     real(dp) :: theta, phi
02360     real(dp) :: elfactor
02361     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
02362     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02363     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
02364     integer*8 :: fftw_plan
02365     character(len=STRING_LEN) :: format_spec
02366 
02367     ! Print messages depending on verbosity level.
02368     if (present(verbosity)) then
02369        if (verbosity > 0) then
02370           write(*,'(a,a,a)') SSHT_PROMPT, &
02371                'Computing inverse transform using McEwen and Wiaux', &
02372                ' sampling with'
02373           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
02374                digit(spin),',a)'
02375           write(*,trim(format_spec)) SSHT_PROMPT, &
02376                'parameters (L,spin,reality) = (', &
02377                L, ',', spin, ',FALSE)...'
02378        end if
02379        if (verbosity > 1) then
02380           write(*,'(a,a)') SSHT_PROMPT, &
02381                'Using routine ssht_core_mw_inverse_sov...'
02382        end if
02383     end if
02384 
02385     ! Compute Fmm.
02386     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02387     do el = abs(spin), L-1
02388        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
02389        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02390        do m = -el, el
02391           call ssht_sampling_elm2ind(ind, el, m)
02392           do mm = -el, el
02393              Fmm(m,mm) = Fmm(m,mm) + &
02394                   (-1)**spin * elfactor &
02395                   * exp(-I*PION2*(m+spin)) &
02396                   * dl(mm,m) * dl(mm,-spin) &
02397                   * flm(ind)
02398           end do
02399        end do
02400     end do
02401 
02402     ! Apply phase modulation to account for sampling offset.
02403     do mm = -(L-1), L-1
02404        Fmm(-(L-1):L-1,mm) = Fmm(-(L-1):L-1,mm) * exp(I*mm*PI/(2d0*L-1d0))
02405     end do
02406 
02407     ! Apply spatial shift.
02408     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
02409     fext(L:2*L-2, 0:L-1) = Fmm(-(L-1):-1,0:L-1)
02410     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
02411     fext(L:2*L-2, L:2*L-2) = Fmm(-(L-1):-1,-(L-1):-1)
02412 
02413     ! Perform 2D FFT.
02414     call dfftw_plan_dft_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:2*L-2,0:2*L-2), &
02415          fext(0:2*L-2,0:2*L-2), FFTW_BACKWARD, FFTW_ESTIMATE)
02416     call dfftw_execute_dft(fftw_plan, fext(0:2*L-2,0:2*L-2), fext(0:2*L-2,0:2*L-2))
02417     call dfftw_destroy_plan(fftw_plan)
02418 
02419     ! Extract f from version of f extended to the torus (fext).
02420     f(0:L-1, 0:2*L-2) = transpose(fext(0:2*L-2, 0:L-1))
02421 
02422     ! Print finished if verbosity set.
02423     if (present(verbosity)) then
02424        if (verbosity > 0) then
02425           write(*,'(a,a)') SSHT_PROMPT, &
02426                'Inverse transform computed!'
02427        end if
02428     end if
02429 
02430   end subroutine ssht_core_mw_inverse_sov
02431 
02432 
02433   !----------------------------------------------------------------------------
02434   ! ssht_core_mw_inverse_sov_sym
02435   !
02452 
02453   subroutine ssht_core_mw_inverse_sov_sym(f, flm, L, spin, verbosity)
02454     
02455     integer, intent(in) :: L
02456     integer, intent(in) :: spin
02457     integer, intent(in), optional :: verbosity
02458     complex(dpc), intent(in) :: flm(0:L**2-1)
02459     complex(dpc), intent(out) :: f(0:L-1, 0:2*L-2)
02460 
02461     integer :: el, m, mm, t, p, ind
02462     real(dp) :: theta, phi
02463     real(dp) :: elfactor
02464     real(dp) :: dl(0:L-1, -(L-1):L-1)
02465     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02466     complex(dpc) :: fext(0:2*L-2, 0:2*L-2)
02467     integer*8 :: fftw_plan
02468     character(len=STRING_LEN) :: format_spec
02469 
02470     integer :: eltmp
02471     real(dp) :: signs(0:L), ssign
02472     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
02473 
02474     ! Perform precomputations.
02475     do el = 0, 2*(L-1) + 1
02476        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
02477     end do
02478     do m = 0, L-1, 2
02479        signs(m)   =  1.0_dp
02480        signs(m+1) = -1.0_dp
02481     enddo
02482     ssign = signs(abs(spin))
02483 
02484     ! Print messages depending on verbosity level.
02485     if (present(verbosity)) then
02486        if (verbosity > 0) then
02487           write(*,'(a,a,a)') SSHT_PROMPT, &
02488                'Computing inverse transform using McEwen and Wiaux', &
02489                ' sampling with'
02490           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
02491                digit(spin),',a)'
02492           write(*,trim(format_spec)) SSHT_PROMPT, &
02493                'parameters (L,spin,reality) = (', &
02494                L, ',', spin, ',FALSE)...'
02495        end if
02496        if (verbosity > 1) then
02497           write(*,'(a,a)') SSHT_PROMPT, &
02498                'Using routine ssht_core_mw_inverse_sov_sym...'
02499        end if
02500     end if
02501 
02502     ! Compute Fmm.
02503     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02504     do el = abs(spin), L-1
02505 
02506        if (el /= 0 .and. el == abs(spin)) then
02507           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
02508           do eltmp = 0, abs(spin)
02509              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
02510                   sqrt_tbl(0:2*eltmp+1))
02511           end do       
02512           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
02513                el, signs)
02514        else
02515           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
02516                sqrt_tbl(0:2*el+1))
02517           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
02518                el, signs)
02519        end if
02520 
02521        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02522        do m = -el, el
02523           call ssht_sampling_elm2ind(ind, el, m)
02524           do mm = 0, el
02525              Fmm(m,mm) = Fmm(m,mm) + &
02526                   ssign * elfactor &
02527                   * exp(-I*PION2*(m+spin)) &
02528                   * dl(mm,m) * dl(mm,-spin) &
02529                   * flm(ind)
02530           end do
02531        end do
02532     end do
02533 
02534     ! Use symmetry to compute Fmm for negative mm.
02535     do mm = -(L-1), -1
02536        do m = -(L-1), L-1       
02537           Fmm(m,mm) = signs(abs(m)) * ssign * Fmm(m,-mm)
02538        end do
02539     end do
02540 
02541     ! Apply phase modulation to account for sampling offset.
02542     do mm = -(L-1), L-1
02543        Fmm(-(L-1):L-1,mm) = Fmm(-(L-1):L-1,mm) * exp(I*mm*PI/(2d0*L-1d0))
02544     end do
02545 
02546     ! Apply spatial shift.
02547     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
02548     fext(L:2*L-2, 0:L-1) = Fmm(-(L-1):-1,0:L-1)
02549     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
02550     fext(L:2*L-2, L:2*L-2) = Fmm(-(L-1):-1,-(L-1):-1)
02551 
02552     ! Perform 2D FFT.
02553     call dfftw_plan_dft_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:2*L-2,0:2*L-2), &
02554          fext(0:2*L-2,0:2*L-2), FFTW_BACKWARD, FFTW_ESTIMATE)
02555     call dfftw_execute_dft(fftw_plan, fext(0:2*L-2,0:2*L-2), fext(0:2*L-2,0:2*L-2))
02556     call dfftw_destroy_plan(fftw_plan)
02557 
02558     ! Extract f from version of f extended to the torus (fext).
02559     f(0:L-1, 0:2*L-2) = transpose(fext(0:2*L-2, 0:L-1))
02560 
02561     ! Print finished if verbosity set.
02562     if (present(verbosity)) then
02563        if (verbosity > 0) then
02564           write(*,'(a,a)') SSHT_PROMPT, &
02565                'Inverse transform computed!'
02566        end if
02567     end if
02568 
02569   end subroutine ssht_core_mw_inverse_sov_sym
02570 
02571 
02572   !----------------------------------------------------------------------------
02573   ! ssht_core_mw_inverse_sov_sym_real
02574   !
02592 
02593   subroutine ssht_core_mw_inverse_sov_sym_real(f, flm, L, verbosity)
02594     
02595     integer, intent(in) :: L
02596     integer, intent(in), optional :: verbosity
02597     complex(dpc), intent(in) :: flm(0:L**2-1)
02598     real(dp), intent(out) :: f(0:L-1, 0:2*L-2)
02599 
02600     integer :: el, m, mm, t, p, ind
02601     real(dp) :: theta, phi
02602     real(dp) :: elfactor
02603     real(dp) :: dl(0:L-1, 0:L-1)
02604     complex(dpc) :: Fmm(0:L-1, -(L-1):L-1)
02605     complex(dpc) :: fext(0:L-1, 0:2*L-2)
02606     real(dp) :: fext_real(0:2*L-2,0:2*L-2)
02607     integer*8 :: fftw_plan
02608     character(len=STRING_LEN) :: format_spec
02609 
02610     integer :: spin
02611     integer :: eltmp
02612     real(dp) :: signs(0:L), ssign
02613     real(dp) :: dl_mm_spin
02614     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
02615 
02616     ! Perform precomputations.
02617     do el = 0, 2*(L-1) + 1
02618        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
02619     end do
02620     do m = 0, L-1, 2
02621        signs(m)   =  1.0_dp
02622        signs(m+1) = -1.0_dp
02623     enddo
02624 
02625     ! Set spin to zero.
02626     spin = 0
02627     ssign = signs(abs(spin))
02628 
02629     ! Print messages depending on verbosity level.
02630     if (present(verbosity)) then
02631        if (verbosity > 0) then
02632           write(*,'(a,a,a)') SSHT_PROMPT, &
02633                'Computing inverse transform using McEwen and Wiaux', &
02634                ' sampling with'
02635           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
02636                digit(spin),',a)'
02637           write(*,trim(format_spec)) SSHT_PROMPT, &
02638                'parameters (L,spin,reality) = (', &
02639                L, ',', spin, ',TRUE)...'
02640        end if
02641        if (verbosity > 1) then
02642           write(*,'(a,a)') SSHT_PROMPT, &
02643                'Using routine ssht_core_mw_inverse_sov_sym...'
02644        end if
02645     end if
02646 
02647     ! Compute Fmm.
02648     Fmm(0:L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02649     do el = abs(spin), L-1
02650        if (el /= 0 .and. el == abs(spin)) then
02651           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
02652           do eltmp = 0, abs(spin)
02653              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
02654                   sqrt_tbl(0:2*eltmp+1))
02655           end do       
02656           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
02657                el, signs(0:el))
02658        else
02659           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
02660                sqrt_tbl(0:2*el+1))
02661           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
02662                el, signs(0:el))
02663        end if
02664 
02665        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02666        do m = 0, el
02667           call ssht_sampling_elm2ind(ind, el, m)
02668           do mm = 0, el
02669              if (spin <= 0) then
02670                 dl_mm_spin = dl(mm,-spin)
02671              else
02672                 dl_mm_spin =  signs(el) * signs(mm) * dl(mm,spin)
02673              end if
02674 
02675              Fmm(m,mm) = Fmm(m,mm) + &
02676                   ssign * elfactor &
02677                   * exp(-I*PION2*(m+spin)) &
02678 !!$                  * dl(mm,m) * dl(mm,-spin) &
02679                   * dl(mm,m) * dl_mm_spin &
02680                   * flm(ind)
02681           end do
02682        end do
02683     end do
02684 
02685     ! Use symmetry to compute Fmm for negative mm.
02686     do mm = -(L-1), -1
02687        do m = 0, L-1       
02688           Fmm(m,mm) = signs(m) * ssign * Fmm(m,-mm)
02689        end do
02690     end do
02691 
02692     ! Apply phase modulation to account for sampling offset.
02693     do mm = -(L-1), L-1
02694        Fmm(0:L-1,mm) = Fmm(0:L-1,mm) * exp(I*mm*PI/(2d0*L-1d0))
02695     end do
02696 
02697     ! Apply spatial shift.
02698     fext(0:L-1, 0:L-1) = Fmm(0:L-1,0:L-1)
02699     fext(0:L-1, L:2*L-2) = Fmm(0:L-1,-(L-1):-1)
02700 
02701     ! Perform 2D FFT.
02702     call dfftw_plan_dft_c2r_2d(fftw_plan, 2*L-1, 2*L-1, fext(0:L-1,0:2*L-2), &
02703          fext_real(0:2*L-2,0:2*L-2), FFTW_ESTIMATE)
02704     call dfftw_execute_dft_c2r(fftw_plan, fext(0:L-1,0:2*L-2), fext_real(0:2*L-2,0:2*L-2))
02705     call dfftw_destroy_plan(fftw_plan)
02706 
02707     ! Extract f from version of f extended to the torus (fext).
02708     f(0:L-1, 0:2*L-2) = transpose(fext_real(0:2*L-2, 0:L-1))
02709 
02710     ! Print finished if verbosity set.
02711     if (present(verbosity)) then
02712        if (verbosity > 0) then
02713           write(*,'(a,a)') SSHT_PROMPT, &
02714                'Inverse transform computed!'
02715        end if
02716     end if
02717 
02718   end subroutine ssht_core_mw_inverse_sov_sym_real
02719 
02720 
02721   !============================================================================
02722   ! Forward transforms
02723   !============================================================================
02724 
02725 
02726   !----------------------------------------------------------------------------
02727   ! DH
02728   !----------------------------------------------------------------------------
02729 
02730 
02731   !----------------------------------------------------------------------------
02732   ! ssht_core_dh_forward_sov_direct
02733   !
02752 
02753   subroutine ssht_core_dh_forward_sov_direct(flm, f, L, spin, verbosity)
02754 
02755     integer, intent(in) :: L
02756     integer, intent(in) :: spin
02757     integer, intent(in), optional :: verbosity
02758     complex(dpc), intent(in) :: f(0:2*L-1 ,0:2*L-2)
02759     complex(dpc), intent(out) :: flm(0:L**2-1)
02760 
02761     integer :: p, m, t, mm, el, ind
02762     real(dp) :: theta, phi
02763     real(dp) :: elfactor
02764     real(dp) :: w
02765     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
02766     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02767     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
02768     character(len=STRING_LEN) :: format_spec
02769 
02770     ! Print messages depending on verbosity level.
02771     if (present(verbosity)) then
02772        if (verbosity > 0) then
02773           write(*,'(a,a)') SSHT_PROMPT, &
02774                'Computing forward transform using Driscoll and Healy sampling with'
02775           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
02776           write(*,trim(format_spec)) SSHT_PROMPT, &
02777                'parameters (L,spin,reality) = (', &
02778                L, ',', spin, ',FALSE)...'
02779        end if
02780        if (verbosity > 1) then
02781           write(*,'(a,a)') SSHT_PROMPT, &
02782                'Using routine ssht_core_dh_forward_sov_direct...'
02783        end if
02784     end if
02785 
02786     ! Compute fmt.
02787     fmt(-(L-1):L-1, 0:2*L-1) = cmplx(0d0, 0d0)
02788     do p = 0, 2*L-2
02789        phi = ssht_sampling_dh_p2phi(p, L)
02790        do m = -(L-1), L-1
02791           do t = 0, 2*L-1             
02792              fmt(m,t) = fmt(m,t) + &
02793                   f(t,p) * exp(-I*m*phi)
02794           end do
02795        end do
02796     end do
02797     fmt(-(L-1):L-1, 0:2*L-1) = fmt(-(L-1):L-1, 0:2*L-1) &
02798          * 2d0*PI / (2d0*L-1d0)
02799     
02800     ! Compute Fmm.
02801     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02802     do t = 0, 2*L-1
02803        theta = ssht_sampling_dh_t2theta(t, L)
02804        w = ssht_sampling_weight_dh(theta, L)
02805        do m = -(L-1), L-1
02806           do mm = -(L-1), L-1
02807              Fmm(m,mm) = Fmm(m,mm) + &
02808                   fmt(m,t) * exp(-I*mm*theta) * w
02809           end do
02810        end do
02811     end do
02812 
02813     ! Compute flm.
02814     flm(0::L**2-1) = cmplx(0d0, 0d0)
02815     do el = abs(spin), L-1
02816        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
02817        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02818        do m = -el, el
02819           call ssht_sampling_elm2ind(ind, el, m)
02820           do mm = -el, el
02821              flm(ind) = flm(ind) + &
02822                   (-1)**spin * elfactor &
02823                   * exp(I*PION2*(m+spin)) &
02824                   * dl(mm,m) * dl(mm,-spin) &
02825                   * Fmm(m,mm)
02826           end do
02827        end do
02828     end do
02829 
02830     ! Print finished if verbosity set.
02831     if (present(verbosity)) then
02832        if (verbosity > 0) then
02833           write(*,'(a,a)') SSHT_PROMPT, &
02834                'Forward transform computed!'
02835        end if
02836     end if
02837 
02838   end subroutine ssht_core_dh_forward_sov_direct
02839 
02840 
02841   !----------------------------------------------------------------------------
02842   ! ssht_core_dh_forward_sov
02843   !
02859 
02860   subroutine ssht_core_dh_forward_sov(flm, f, L, spin, verbosity)
02861 
02862     integer, intent(in) :: L
02863     integer, intent(in) :: spin
02864     integer, intent(in), optional :: verbosity
02865     complex(dpc), intent(in) :: f(0:2*L-1 ,0:2*L-2)
02866     complex(dpc), intent(out) :: flm(0:L**2-1)
02867 
02868     integer :: p, m, t, mm, el, ind
02869     real(dp) :: theta, phi
02870     real(dp) :: elfactor
02871     real(dp) :: w
02872     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
02873     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02874     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
02875     integer*8 :: fftw_plan
02876     complex(dpc) :: tmp(0:2*L-2)
02877     character(len=STRING_LEN) :: format_spec
02878 
02879     ! Print messages depending on verbosity level.
02880     if (present(verbosity)) then
02881        if (verbosity > 0) then
02882           write(*,'(a,a)') SSHT_PROMPT, &
02883                'Computing forward transform using Driscoll and Healy sampling with'
02884           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
02885           write(*,trim(format_spec)) SSHT_PROMPT, &
02886                'parameters (L,spin,reality) = (', &
02887                L, ',', spin, ',FALSE)...'
02888        end if
02889        if (verbosity > 1) then
02890           write(*,'(a,a)') SSHT_PROMPT, &
02891                'Using routine ssht_core_dh_forward_sov...'
02892        end if
02893     end if
02894 
02895     ! Compute fmt using FFT.     
02896     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, fmt(-(L-1):L-1,0), &
02897          fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
02898     do t = 0, 2*L-1             
02899 
02900        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
02901 
02902        ! Spatial shift in frequency.
02903        fmt(0:L-1, t) = tmp(0:L-1)
02904        fmt(-(L-1):-1, t) = tmp(L:2*L-2)
02905     end do
02906     call dfftw_destroy_plan(fftw_plan)
02907     fmt(-(L-1):L-1, 0:2*L-1) = fmt(-(L-1):L-1, 0:2*L-1) &
02908          * 2d0*PI / (2d0*L-1d0)
02909 
02910     ! Compute Fmm.
02911     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
02912     do t = 0, 2*L-1
02913        theta = ssht_sampling_dh_t2theta(t, L)
02914        w = ssht_sampling_weight_dh(theta, L)
02915        do m = -(L-1), L-1
02916           do mm = -(L-1), L-1
02917              Fmm(m,mm) = Fmm(m,mm) + &
02918                   fmt(m,t) * exp(-I*mm*theta) * w
02919           end do
02920        end do
02921     end do
02922 
02923     ! Compute flm.
02924     flm(0::L**2-1) = cmplx(0d0, 0d0)
02925     do el = abs(spin), L-1
02926        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
02927        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
02928        do m = -el, el
02929           call ssht_sampling_elm2ind(ind, el, m)
02930           do mm = -el, el
02931              flm(ind) = flm(ind) + &
02932                   (-1)**spin * elfactor &
02933                   * exp(I*PION2*(m+spin)) &
02934                   * dl(mm,m) * dl(mm,-spin) &
02935                   * Fmm(m,mm)
02936           end do
02937        end do
02938     end do
02939 
02940     ! Print finished if verbosity set.
02941     if (present(verbosity)) then
02942        if (verbosity > 0) then
02943           write(*,'(a,a)') SSHT_PROMPT, &
02944                'Forward transform computed!'
02945        end if
02946     end if
02947 
02948   end subroutine ssht_core_dh_forward_sov
02949 
02950 
02951   !----------------------------------------------------------------------------
02952   ! ssht_core_dh_forward_sov_sym
02953   !
02970 
02971   subroutine ssht_core_dh_forward_sov_sym(flm, f, L, spin, verbosity)
02972 
02973     integer, intent(in) :: L
02974     integer, intent(in) :: spin
02975     integer, intent(in), optional :: verbosity
02976     complex(dpc), intent(in) :: f(0:2*L-1 ,0:2*L-2)
02977     complex(dpc), intent(out) :: flm(0:L**2-1)
02978 
02979     integer :: p, m, t, mm, el, ind
02980     real(dp) :: theta, phi
02981     real(dp) :: elfactor
02982     real(dp) :: w
02983     complex(dpc) :: fmt(-(L-1):L-1, 0:2*L-1)
02984     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
02985     real(dp) :: dl(0:L-1, -(L-1):L-1)
02986     integer*8 :: fftw_plan
02987     complex(dpc) :: tmp(0:2*L-2)
02988     character(len=STRING_LEN) :: format_spec
02989 
02990     real(dp) :: signs(0:L), ssign
02991     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
02992     integer :: eltmp
02993 
02994     ! Perform precomputations.
02995     do el = 0, 2*(L-1) + 1
02996        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
02997     end do
02998     do m = 0, L-1, 2
02999        signs(m)   =  1.0_dp
03000        signs(m+1) = -1.0_dp
03001     enddo
03002 
03003     ! Set spin sign.
03004     ssign = signs(abs(spin))
03005 
03006     ! Print messages depending on verbosity level.
03007     if (present(verbosity)) then
03008        if (verbosity > 0) then
03009           write(*,'(a,a)') SSHT_PROMPT, &
03010                'Computing forward transform using Driscoll and Healy sampling with'
03011           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
03012           write(*,trim(format_spec)) SSHT_PROMPT, &
03013                'parameters (L,spin,reality) = (', &
03014                L, ',', spin, ',FALSE)...'
03015        end if
03016        if (verbosity > 1) then
03017           write(*,'(a,a)') SSHT_PROMPT, &
03018                'Using routine ssht_core_dh_forward_sov_sym...'
03019        end if
03020     end if
03021 
03022     ! Compute fmt using FFT.     
03023     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, fmt(-(L-1):L-1,0), &
03024          fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
03025     do t = 0, 2*L-1             
03026 
03027        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
03028 
03029        ! Spatial shift in frequency.
03030        fmt(0:L-1, t) = tmp(0:L-1)
03031        fmt(-(L-1):-1, t) = tmp(L:2*L-2)
03032     end do
03033     call dfftw_destroy_plan(fftw_plan)
03034     fmt(-(L-1):L-1, 0:2*L-1) = fmt(-(L-1):L-1, 0:2*L-1) &
03035          * 2d0*PI / (2d0*L-1d0)
03036 
03037     ! Compute Fmm.
03038     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03039     do t = 0, 2*L-1
03040        theta = ssht_sampling_dh_t2theta(t, L)
03041        w = ssht_sampling_weight_dh(theta, L)
03042        do mm = -(L-1), L-1
03043           do m = -(L-1), L-1
03044              Fmm(m,mm) = Fmm(m,mm) + &
03045                   fmt(m,t) * exp(-I*mm*theta) * w
03046           end do
03047        end do
03048     end do
03049 
03050     ! Compute flm.
03051     flm(0::L**2-1) = cmplx(0d0, 0d0)
03052     do el = abs(spin), L-1
03053        if (el /= 0 .and. el == abs(spin)) then
03054           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
03055           do eltmp = 0, abs(spin)
03056              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
03057                   sqrt_tbl(0:2*eltmp+1))
03058           end do
03059           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
03060                el, signs(0:el))
03061        else
03062           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
03063                sqrt_tbl(0:2*el+1))
03064           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
03065                el, signs(0:el))
03066        end if
03067 
03068        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03069        do m = -el, el
03070           call ssht_sampling_elm2ind(ind, el, m)
03071 
03072           flm(ind) = flm(ind) + &
03073                ssign * elfactor &
03074                * exp(I*PION2*(m+spin)) &
03075                * dl(0,m) * dl(0,-spin) &
03076                * Fmm(m,0)
03077 
03078           do mm = 1, el
03079              flm(ind) = flm(ind) + &
03080                   ssign * elfactor &
03081                   * exp(I*PION2*(m+spin)) &
03082                   * dl(mm,m) * dl(mm,-spin) &
03083                   * (Fmm(m,mm) + signs(abs(m)) * ssign * Fmm(m,-mm))
03084 
03085           end do
03086        end do
03087     end do
03088 
03089     ! Print finished if verbosity set.
03090     if (present(verbosity)) then
03091        if (verbosity > 0) then
03092           write(*,'(a,a)') SSHT_PROMPT, &
03093                'Forward transform computed!'
03094        end if
03095     end if
03096 
03097   end subroutine ssht_core_dh_forward_sov_sym
03098 
03099 
03100   !----------------------------------------------------------------------------
03101   ! ssht_core_dh_forward_sov_sym_real
03102   !
03120 
03121   subroutine ssht_core_dh_forward_sov_sym_real(flm, f, L, verbosity)
03122 
03123     integer, intent(in) :: L
03124     integer, intent(in), optional :: verbosity
03125     real(dp), intent(in) :: f(0:2*L-1 ,0:2*L-2)
03126     complex(dpc), intent(out) :: flm(0:L**2-1)
03127 
03128     integer :: p, m, t, mm, el, ind
03129     real(dp) :: theta, phi
03130     real(dp) :: elfactor
03131     real(dp) :: w
03132     complex(dpc) :: fmt(0:L-1, 0:2*L-1)
03133     complex(dpc) :: Fmm(0:L-1, -(L-1):L-1)
03134     real(dp) :: dl(0:L-1, 0:L-1)
03135     integer*8 :: fftw_plan
03136 
03137     integer :: spin
03138     real(dp) :: tmp(0:2*L-2)
03139     integer :: ind_nm
03140     character(len=STRING_LEN) :: format_spec
03141     integer :: eltmp
03142 
03143     real(dp) :: signs(0:L), ssign
03144     real(dp) :: dl_mm_spin, dl_0_spin
03145     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
03146 
03147     ! Perform precomputations.
03148     do el = 0, 2*(L-1) + 1
03149        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
03150     end do
03151     do m = 0, L-1, 2
03152        signs(m)   =  1.0_dp
03153        signs(m+1) = -1.0_dp
03154     enddo
03155 
03156     ! Set spin to zero.
03157     spin = 0
03158     ssign = signs(abs(spin))
03159 
03160     ! Print messages depending on verbosity level.
03161     if (present(verbosity)) then
03162        if (verbosity > 0) then
03163           write(*,'(a,a)') SSHT_PROMPT, &
03164                'Computing forward transform using Driscoll and Healy sampling with'
03165           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
03166           write(*,trim(format_spec)) SSHT_PROMPT, &
03167                'parameters (L,spin,reality) = (', &
03168                L, ',', spin, ',TRUE)...'
03169        end if
03170        if (verbosity > 1) then
03171           write(*,'(a,a)') SSHT_PROMPT, &
03172                'Using routine ssht_core_dh_forward_sov_sym_real...'
03173        end if
03174     end if
03175 
03176     ! Compute fmt using FFT.     
03177     call dfftw_plan_dft_r2c_1d(fftw_plan, 2*L-1, tmp(0:2*L-2), &
03178          fmt(0:L-1,0), FFTW_MEASURE)
03179     do t = 0, 2*L-1             
03180        call dfftw_execute_dft_r2c(fftw_plan, f(t,0:2*L-2), fmt(0:L-1,t))
03181     end do
03182     call dfftw_destroy_plan(fftw_plan)
03183     fmt(0:L-1, 0:2*L-1) = fmt(0:L-1, 0:2*L-1) &
03184          * 2d0*PI / (2d0*L-1d0)
03185 
03186     ! Compute Fmm.
03187     Fmm(0:L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03188     do t = 0, 2*L-1
03189        theta = ssht_sampling_dh_t2theta(t, L)
03190        w = ssht_sampling_weight_dh(theta, L)
03191 ! Switching order of mm and m loops changes computation time by a factor of ~10!
03192        do mm = -(L-1), L-1
03193           do m = 0, L-1
03194              Fmm(m,mm) = Fmm(m,mm) + &
03195                   fmt(m,t) * exp(-I*mm*theta) * w
03196           end do
03197        end do
03198     end do
03199 
03200     ! Compute flm.
03201     flm(0::L**2-1) = cmplx(0d0, 0d0)
03202     do el = abs(spin), L-1
03203        if (el /= 0 .and. el == abs(spin)) then
03204           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
03205           do eltmp = 0, abs(spin)
03206              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
03207                   sqrt_tbl(0:2*eltmp+1))
03208           end do
03209           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
03210                el, signs(0:el))
03211        else
03212           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
03213                sqrt_tbl(0:2*el+1))
03214           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
03215                el, signs(0:el))
03216        end if
03217       
03218        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03219        do m = 0, el
03220           call ssht_sampling_elm2ind(ind, el, m)
03221 
03222           if (spin <= 0) then
03223              dl_0_spin = dl(0,-spin)
03224           else
03225              dl_0_spin = signs(el) * dl(0,spin)
03226           end if
03227 
03228           flm(ind) = flm(ind) + &
03229                ssign * elfactor &
03230                * exp(I*PION2*(m+spin)) &
03231                * dl(0,m) * dl_0_spin &
03232                * Fmm(m,0)
03233 
03234           do mm = 1, el
03235 
03236              if (spin <= 0) then
03237                 dl_mm_spin = dl(mm,-spin)
03238              else
03239                 dl_mm_spin = signs(el) * signs(mm) * dl(mm,spin)
03240              end if
03241 
03242              flm(ind) = flm(ind) + &
03243                   (-1)**spin * elfactor &
03244                   * exp(I*PION2*(m+spin)) &
03245                   * dl(mm,m) * dl_mm_spin &
03246                   * (Fmm(m,mm) + signs(m) * ssign * Fmm(m,-mm))
03247 
03248           end do
03249        end do
03250     end do
03251 
03252     ! Set flm values for negative m using conjugate symmetry.
03253     do el = abs(spin), L-1
03254        do m = 1, el
03255           call ssht_sampling_elm2ind(ind, el, m)
03256           call ssht_sampling_elm2ind(ind_nm, el, -m)
03257           flm(ind_nm) = signs(m) * conjg(flm(ind))
03258        end do
03259     end do
03260 
03261     ! Print finished if verbosity set.
03262     if (present(verbosity)) then
03263        if (verbosity > 0) then
03264           write(*,'(a,a)') SSHT_PROMPT, &
03265                'Forward transform computed!'
03266        end if
03267     end if
03268 
03269   end subroutine ssht_core_dh_forward_sov_sym_real
03270 
03271 
03272   !----------------------------------------------------------------------------
03273   ! GL
03274   !----------------------------------------------------------------------------
03275 
03276 
03277   !----------------------------------------------------------------------------
03278   ! ssht_core_gl_forward_sov_sym
03279   !
03296 
03297   subroutine ssht_core_gl_forward_sov_sym(flm, f, L, spin, verbosity)
03298 
03299     integer, intent(in) :: L
03300     integer, intent(in) :: spin
03301     integer, intent(in), optional :: verbosity
03302     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
03303     complex(dpc), intent(out) :: flm(0:L**2-1)
03304 
03305     integer :: p, m, t, mm, el, ind
03306     real(dp) :: theta, phi
03307     real(dp) :: elfactor
03308     real(dp) :: w
03309     complex(dpc) :: fmt(-(L-1):L-1, 0:L-1)
03310     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
03311     real(dp) :: dl(0:L-1, -(L-1):L-1)
03312     integer*8 :: fftw_plan
03313     complex(dpc) :: tmp(0:2*L-2)
03314     character(len=STRING_LEN) :: format_spec
03315 
03316     real(dp) :: thetas(0:L-1)
03317     real(dp) :: weights(0:L-1)
03318 
03319     real(dp) :: signs(0:L), ssign
03320     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
03321     integer :: eltmp
03322 
03323     ! Perform precomputations.
03324     do el = 0, 2*(L-1) + 1
03325        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
03326     end do
03327     do m = 0, L-1, 2
03328        signs(m)   =  1.0_dp
03329        signs(m+1) = -1.0_dp
03330     enddo
03331 
03332     ! Set spin sign.
03333     ssign = signs(abs(spin))
03334 
03335     ! Print messages depending on verbosity level.
03336     if (present(verbosity)) then
03337        if (verbosity > 0) then
03338           write(*,'(a,a)') SSHT_PROMPT, &
03339                'Computing forward transform using Gauss-Legendre sampling with'
03340           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
03341           write(*,trim(format_spec)) SSHT_PROMPT, &
03342                'parameters (L,spin,reality) = (', &
03343                L, ',', spin, ',FALSE)...'
03344        end if
03345        if (verbosity > 1) then
03346           write(*,'(a,a)') SSHT_PROMPT, &
03347                'Using routine ssht_core_gl_forward_sov_sym...'
03348        end if
03349     end if
03350 
03351     ! Compute weights and theta positions.
03352     call ssht_sampling_gl_thetas_weights(thetas, weights, L)
03353 
03354     ! Compute fmt using FFT.     
03355     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, fmt(-(L-1):L-1,0), &
03356          fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
03357     do t = 0, L-1             
03358 
03359        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
03360 
03361        ! Spatial shift in frequency.
03362        fmt(0:L-1, t) = tmp(0:L-1)
03363        fmt(-(L-1):-1, t) = tmp(L:2*L-2)
03364     end do
03365     call dfftw_destroy_plan(fftw_plan)
03366     fmt(-(L-1):L-1, 0:L-1) = fmt(-(L-1):L-1, 0:L-1) &
03367          * 2d0*PI / (2d0*L-1d0)
03368 
03369     ! Compute Fmm.
03370     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03371     do t = 0, L-1
03372        theta = thetas(t)
03373        w = weights(t)
03374        do mm = -(L-1), L-1
03375           do m = -(L-1), L-1
03376              Fmm(m,mm) = Fmm(m,mm) + &
03377                   fmt(m,t) * exp(-I*mm*theta) * w
03378           end do
03379        end do
03380     end do
03381 
03382     ! Compute flm.
03383     flm(0::L**2-1) = cmplx(0d0, 0d0)
03384     do el = abs(spin), L-1
03385        if (el /= 0 .and. el == abs(spin)) then
03386           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
03387           do eltmp = 0, abs(spin)
03388              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
03389                   sqrt_tbl(0:2*eltmp+1))
03390           end do
03391           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
03392                el, signs(0:el))
03393        else
03394           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
03395                sqrt_tbl(0:2*el+1))
03396           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
03397                el, signs(0:el))
03398        end if
03399 
03400        !call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
03401        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03402        do m = -el, el
03403           call ssht_sampling_elm2ind(ind, el, m)
03404 
03405           flm(ind) = flm(ind) + &
03406                ssign * elfactor &
03407                * exp(I*PION2*(m+spin)) &
03408                * dl(0,m) * dl(0,-spin) &
03409                * Fmm(m,0)
03410 
03411           do mm = 1, el
03412              flm(ind) = flm(ind) + &
03413                   ssign * elfactor &
03414                   * exp(I*PION2*(m+spin)) &
03415                   * dl(mm,m) * dl(mm,-spin) &
03416                   * (Fmm(m,mm) + signs(abs(m)) * ssign * Fmm(m,-mm))
03417 
03418           end do
03419        end do
03420     end do
03421 
03422     ! Print finished if verbosity set.
03423     if (present(verbosity)) then
03424        if (verbosity > 0) then
03425           write(*,'(a,a)') SSHT_PROMPT, &
03426                'Forward transform computed!'
03427        end if
03428     end if
03429 
03430   end subroutine ssht_core_gl_forward_sov_sym
03431 
03432 
03433   !----------------------------------------------------------------------------
03434   ! ssht_core_gl_forward_sov_sym_real
03435   !
03453 
03454   subroutine ssht_core_gl_forward_sov_sym_real(flm, f, L, verbosity)
03455 
03456     integer, intent(in) :: L
03457     integer, intent(in), optional :: verbosity
03458     real(dp), intent(in) :: f(0:L-1 ,0:2*L-2)
03459     complex(dpc), intent(out) :: flm(0:L**2-1)
03460 
03461     integer :: p, m, t, mm, el, ind
03462     real(dp) :: theta, phi
03463     real(dp) :: elfactor
03464     real(dp) :: w
03465     complex(dpc) :: fmt(0:L-1, 0:L-1)
03466     complex(dpc) :: Fmm(0:L-1, -(L-1):L-1)
03467     real(dp) :: dl(0:L-1, 0:L-1)
03468     integer*8 :: fftw_plan
03469 
03470     integer :: spin
03471     real(dp) :: tmp(0:2*L-2)
03472     integer :: ind_nm
03473     character(len=STRING_LEN) :: format_spec
03474 
03475     real(dp) :: thetas(0:L-1)
03476     real(dp) :: weights(0:L-1)
03477 
03478     real(dp) :: signs(0:L), ssign
03479     real(dp) :: dl_mm_spin, dl_0_spin
03480     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
03481     integer :: eltmp
03482 
03483     ! Perform precomputations.
03484     do el = 0, 2*(L-1) + 1
03485        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
03486     end do
03487     do m = 0, L-1, 2
03488        signs(m)   =  1.0_dp
03489        signs(m+1) = -1.0_dp
03490     enddo
03491 
03492     ! Set spin to zero.
03493     spin = 0
03494     ssign = signs(abs(spin))
03495 
03496     ! Print messages depending on verbosity level.
03497     if (present(verbosity)) then
03498        if (verbosity > 0) then
03499           write(*,'(a,a)') SSHT_PROMPT, &
03500                'Computing forward transform using Gauss-Legendre sampling with'
03501           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', digit(spin),',a)'
03502           write(*,trim(format_spec)) SSHT_PROMPT, &
03503                'parameters (L,spin,reality) = (', &
03504                L, ',', spin, ',TRUE)...'
03505        end if
03506        if (verbosity > 1) then
03507           write(*,'(a,a)') SSHT_PROMPT, &
03508                'Using routine ssht_core_gl_forward_sov_sym_real...'
03509        end if
03510     end if
03511 
03512     ! Compute weights and theta positions.
03513     call ssht_sampling_gl_thetas_weights(thetas, weights, L)
03514 
03515     ! Compute fmt using FFT.     
03516     call dfftw_plan_dft_r2c_1d(fftw_plan, 2*L-1, tmp(0:2*L-2), &
03517          fmt(0:L-1,0), FFTW_MEASURE)
03518     do t = 0, L-1             
03519        call dfftw_execute_dft_r2c(fftw_plan, f(t,0:2*L-2), fmt(0:L-1,t))
03520     end do
03521     call dfftw_destroy_plan(fftw_plan)
03522     fmt(0:L-1, 0:L-1) = fmt(0:L-1, 0:L-1) &
03523          * 2d0*PI / (2d0*L-1d0)
03524 
03525     ! Compute Fmm.
03526     Fmm(0:L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03527     do t = 0, L-1
03528        theta = thetas(t)
03529        w = weights(t)
03530        do mm = -(L-1), L-1
03531           do m = 0, L-1
03532              Fmm(m,mm) = Fmm(m,mm) + &
03533                   fmt(m,t) * exp(-I*mm*theta) * w
03534           end do
03535        end do
03536     end do
03537 
03538     ! Compute flm.
03539     flm(0::L**2-1) = cmplx(0d0, 0d0)
03540     do el = abs(spin), L-1
03541        if (el /= 0 .and. el == abs(spin)) then
03542           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
03543           do eltmp = 0, abs(spin)
03544              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
03545                   sqrt_tbl(0:2*eltmp+1))
03546           end do
03547           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
03548                el, signs(0:el))
03549        else
03550           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
03551                sqrt_tbl(0:2*el+1))
03552           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
03553                el, signs(0:el))
03554        end if
03555 
03556        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03557        do m = 0, el
03558           call ssht_sampling_elm2ind(ind, el, m)
03559 
03560           if (spin <= 0) then
03561              dl_0_spin = dl(0,-spin)
03562           else
03563              dl_0_spin = signs(el) * dl(0,spin)
03564           end if         
03565 
03566           flm(ind) = flm(ind) + &
03567                ssign * elfactor &
03568                * exp(I*PION2*(m+spin)) &
03569                * dl(0,m) * dl_0_spin &
03570                * Fmm(m,0)
03571 
03572           do mm = 1, el
03573 
03574              if (spin <= 0) then
03575                 dl_mm_spin = dl(mm,-spin)
03576              else
03577                 dl_mm_spin = signs(el) * signs(mm) * dl(mm,spin)
03578              end if
03579 
03580              flm(ind) = flm(ind) + &
03581                   ssign * elfactor &
03582                   * exp(I*PION2*(m+spin)) &
03583                   * dl(mm,m) * dl_mm_spin &
03584                   * (Fmm(m,mm) + signs(m) * ssign * Fmm(m,-mm))
03585 
03586           end do
03587        end do
03588     end do
03589 
03590     ! Set flm values for negative m using conjugate symmetry.
03591     do el = abs(spin), L-1
03592        do m = 1, el
03593           call ssht_sampling_elm2ind(ind, el, m)
03594           call ssht_sampling_elm2ind(ind_nm, el, -m)
03595           flm(ind_nm) = signs(m) * conjg(flm(ind))
03596        end do
03597     end do
03598 
03599     ! Print finished if verbosity set.
03600     if (present(verbosity)) then
03601        if (verbosity > 0) then
03602           write(*,'(a,a)') SSHT_PROMPT, &
03603                'Forward transform computed!'
03604        end if
03605     end if
03606 
03607   end subroutine ssht_core_gl_forward_sov_sym_real
03608 
03609 
03610   !----------------------------------------------------------------------------
03611   ! MWEO
03612   !----------------------------------------------------------------------------
03613 
03614 
03615   !----------------------------------------------------------------------------
03616   ! ssht_core_mweo_forward_sov_direct
03617   !
03636 
03637   subroutine ssht_core_mweo_forward_sov_direct(flm, f, L, spin, verbosity)
03638 
03639     integer, intent(in) :: L
03640     integer, intent(in) :: spin
03641     integer, intent(in), optional :: verbosity
03642     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
03643     complex(dpc), intent(out) :: flm(0:L**2-1)
03644 
03645     integer :: p, m, t, mm, el, ind, k
03646     real(dp) :: theta, phi
03647     real(dp) :: elfactor
03648 
03649     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
03650     complex(dpc) :: fe(0:2*L-2 ,0:2*L-2)
03651     complex(dpc) :: fo(0:2*L-2 ,0:2*L-2)
03652     complex(dpc) :: Fmme(-(L-1):L-1, -(L-1):L-1)
03653     complex(dpc) :: Fmmo(-(L-1):L-1, -(L-1):L-1)
03654     complex(dpc) :: Gmme(-(L-1):L-1, -(L-1):L-1)
03655     complex(dpc) :: Gmmo(-(L-1):L-1, -(L-1):L-1)
03656     complex(dpc) :: Gmm_term
03657     character(len=STRING_LEN) :: format_spec
03658 
03659     ! Print messages depending on verbosity level.
03660     if (present(verbosity)) then
03661        if (verbosity > 0) then
03662           write(*,'(a,a,a)') SSHT_PROMPT, &
03663                'Computing forward transform using McEwen and Wiaux', &
03664                ' even-odd sampling with'
03665           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
03666                digit(spin),',a)'
03667           write(*,trim(format_spec)) SSHT_PROMPT, &
03668                'parameters (L,spin,reality) = (', &
03669                L, ',', spin, ',FALSE)...'
03670        end if
03671        if (verbosity > 1) then
03672           write(*,'(a,a)') SSHT_PROMPT, &
03673                'Using routine ssht_core_mweo_forward_sov_direct...'
03674        end if
03675     end if
03676 
03677     ! Extend f to the torus with even and odd extensions 
03678     ! about theta=PI.
03679     fe(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03680     fe(L:2*L-2, 0:2*L-2) = f(L-2:0:-1, 0:2*L-2)
03681     fo(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03682     fo(L:2*L-2, 0:2*L-2) = -f(L-2:0:-1, 0:2*L-2)
03683 
03684     ! Compute Fmm for even and odd extensions.
03685     Fmme(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03686     Fmmo(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03687     do p = 0, 2*L-2
03688        phi = ssht_sampling_mweo_p2phi(p, L)
03689        do t = 0, 2*L-2
03690           theta = ssht_sampling_mweo_t2theta(t, L)    
03691           do m = -(L-1), L-1
03692              do mm = -(L-1), L-1
03693                 Fmme(m,mm) = Fmme(m,mm) + &
03694                      fe(t,p) * exp(-I*(m*phi + mm*theta))
03695                 Fmmo(m,mm) = Fmmo(m,mm) + &
03696                      fo(t,p) * exp(-I*(m*phi + mm*theta))
03697              end do
03698           end do
03699 
03700        end do
03701     end do
03702     Fmme(-(L-1):L-1, -(L-1):L-1) = Fmme(-(L-1):L-1, -(L-1):L-1) &
03703          / (2d0*L-1d0)**2
03704     Fmmo(-(L-1):L-1, -(L-1):L-1) = Fmmo(-(L-1):L-1, -(L-1):L-1) &
03705          / (2d0*L-1d0)**2
03706 
03707     ! Compute Gmm for even and odd extensions by direct calculation 
03708     ! of convolution.
03709     Gmme(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03710     Gmmo(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03711     do m = -(L-1), L-1
03712        do mm = -(L-1), L-1
03713           do k = -(L-1), L-1 
03714              Gmme(m,mm) = Gmme(m,mm) + &
03715                   Fmme(m,k) * ssht_sampling_weight_mw(k - mm) * 2d0 * PI
03716              Gmmo(m,mm) = Gmmo(m,mm) + &
03717                   Fmmo(m,k) *ssht_sampling_weight_mw(k - mm) * 2d0 * PI
03718           end do
03719        end do
03720     end do
03721 
03722     ! Compute flm.
03723     flm(0::L**2-1) = cmplx(0d0, 0d0)
03724     do el = abs(spin), L-1
03725        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
03726        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03727        do m = -el, el
03728           call ssht_sampling_elm2ind(ind, el, m)
03729           do mm = -el, el
03730              if (mod(m+spin,2) == 0) then
03731                 ! m+spin even
03732                 Gmm_term = Gmme(m,mm)
03733              else
03734                 ! m+spin odd
03735                 Gmm_term = Gmmo(m,mm)
03736              end if
03737 
03738              flm(ind) = flm(ind) + &
03739                   (-1)**spin * elfactor &
03740                   * exp(I*PION2*(m+spin)) &
03741                   * dl(mm,m) * dl(mm,-spin) &
03742                   * Gmm_term
03743 
03744           end do
03745        end do
03746     end do
03747 
03748     ! Print finished if verbosity set.
03749     if (present(verbosity)) then
03750        if (verbosity > 0) then
03751           write(*,'(a,a)') SSHT_PROMPT, &
03752                'Forward transform computed!'
03753        end if
03754     end if
03755 
03756   end subroutine ssht_core_mweo_forward_sov_direct
03757 
03758 
03759   !----------------------------------------------------------------------------
03760   ! ssht_core_mweo_forward_sov
03761   !
03777 
03778   subroutine ssht_core_mweo_forward_sov(flm, f, L, spin, verbosity)
03779 
03780     integer, intent(in) :: L
03781     integer, intent(in) :: spin
03782     integer, intent(in), optional :: verbosity
03783     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
03784     complex(dpc), intent(out) :: flm(0:L**2-1)
03785 
03786     integer :: p, m, t, mm, el, ind, k
03787     real(dp) :: theta, phi
03788     real(dp) :: elfactor
03789 
03790     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
03791     complex(dpc) :: fe(0:2*L-2 ,0:2*L-2)
03792     complex(dpc) :: fo(0:2*L-2 ,0:2*L-2)
03793     complex(dpc) :: Fmme(-(L-1):L-1, -(L-1):L-1)
03794     complex(dpc) :: Fmmo(-(L-1):L-1, -(L-1):L-1)
03795     complex(dpc) :: Gmme(-(L-1):L-1, -(L-1):L-1)
03796     complex(dpc) :: Gmmo(-(L-1):L-1, -(L-1):L-1)
03797     complex(dpc) :: Gmm_term
03798     integer*8 :: fftw_plan
03799     character(len=STRING_LEN) :: format_spec
03800 
03801     ! Print messages depending on verbosity level.
03802     if (present(verbosity)) then
03803        if (verbosity > 0) then
03804           write(*,'(a,a,a)') SSHT_PROMPT, &
03805                'Computing forward transform using McEwen and Wiaux', &
03806                ' even-odd sampling with'
03807           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
03808                digit(spin),',a)'
03809           write(*,trim(format_spec)) SSHT_PROMPT, &
03810                'parameters (L,spin,reality) = (', &
03811                L, ',', spin, ',FALSE)...'
03812        end if
03813        if (verbosity > 1) then
03814           write(*,'(a,a)') SSHT_PROMPT, &
03815                'Using routine ssht_core_mweo_forward_sov...'
03816        end if
03817     end if
03818 
03819     ! Extend f to the torus with even and odd extensions 
03820     ! about theta=PI.
03821     fe(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03822     fe(L:2*L-2, 0:2*L-2) = f(L-2:0:-1, 0:2*L-2)
03823     fo(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03824     fo(L:2*L-2, 0:2*L-2) = -f(L-2:0:-1, 0:2*L-2)
03825 
03826 ! If don't apply spatial shift below then apply phase modulation here.
03827 !!$    do p = 0, 2*L-2
03828 !!$       phi = ssht_sampling_mweo_p2phi(p, L)
03829 !!$       do t = 0, 2*L-2
03830 !!$          theta = ssht_sampling_mweo_t2theta(t, L)   
03831 !!$          fe(t,p) = fe(t,p) * exp(I*(phi+theta)*(L-1))
03832 !!$          fo(t,p) = fo(t,p) * exp(I*(phi+theta)*(L-1))
03833 !!$       end do
03834 !!$    end do
03835 
03836     ! Compute Fmm for even and odd extensions by 2D FFT.
03837     call dfftw_plan_dft_2d(fftw_plan, 2*L-1, 2*L-1, fe(0:2*L-2,0:2*L-2), &
03838          fe(0:2*L-2,0:2*L-2), FFTW_FORWARD, FFTW_ESTIMATE)
03839     call dfftw_execute_dft(fftw_plan, fe(0:2*L-2,0:2*L-2), fe(0:2*L-2,0:2*L-2))
03840     call dfftw_execute_dft(fftw_plan, fo(0:2*L-2,0:2*L-2), fo(0:2*L-2,0:2*L-2))
03841     call dfftw_destroy_plan(fftw_plan)
03842 
03843 ! If apply phase shift above just copy Fmm.
03844 !!$    Fmme(-(L-1):L-1, -(L-1):L-1) = transpose(fe(0:2*L-2,0:2*L-2))
03845 !!$    Fmmo(-(L-1):L-1, -(L-1):L-1) = transpose(fo(0:2*L-2,0:2*L-2))
03846 
03847     ! Apply spatial shift in frequency.
03848     fe(0:2*L-2,0:2*L-2) = transpose(fe(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
03849     fo(0:2*L-2,0:2*L-2) = transpose(fo(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
03850     Fmme(0:L-1,0:L-1) = fe(0:L-1, 0:L-1)
03851     Fmme(-(L-1):-1,0:L-1) = fe(L:2*L-2, 0:L-1)
03852     Fmme(0:L-1,-(L-1):-1) = fe(0:L-1, L:2*L-2)
03853     Fmme(-(L-1):-1,-(L-1):-1) = fe(L:2*L-2, L:2*L-2)
03854     Fmmo(0:L-1,0:L-1) = fo(0:L-1, 0:L-1)
03855     Fmmo(-(L-1):-1,0:L-1) = fo(L:2*L-2, 0:L-1)
03856     Fmmo(0:L-1,-(L-1):-1) = fo(0:L-1, L:2*L-2)
03857     Fmmo(-(L-1):-1,-(L-1):-1) = fo(L:2*L-2, L:2*L-2)
03858 
03859     ! Apply phase modulation to account for sampling offset.
03860     do m = 0, 2*L-2
03861        do mm = 0, 2*L-2
03862           Fmme(m-(L-1),mm-(L-1)) = Fmme(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
03863           Fmmo(m-(L-1),mm-(L-1)) = Fmmo(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
03864        end do
03865     end do
03866 
03867     Fmme(-(L-1):L-1, -(L-1):L-1) = Fmme(-(L-1):L-1, -(L-1):L-1) &
03868          / (2d0*L-1d0)**2
03869     Fmmo(-(L-1):L-1, -(L-1):L-1) = Fmmo(-(L-1):L-1, -(L-1):L-1) &
03870          / (2d0*L-1d0)**2
03871 
03872     ! Compute Gmm for even and odd extensions by direct calculation 
03873     ! of convolution.
03874     Gmme(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03875     Gmmo(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
03876     do m = -(L-1), L-1
03877        do mm = -(L-1), L-1
03878           do k = -(L-1), L-1 
03879              Gmme(m,mm) = Gmme(m,mm) + &
03880                   Fmme(m,k) * ssht_sampling_weight_mw(k - mm) * 2d0 * PI
03881              Gmmo(m,mm) = Gmmo(m,mm) + &
03882                   Fmmo(m,k) * ssht_sampling_weight_mw(k - mm) * 2d0 * PI
03883           end do
03884        end do
03885     end do
03886 
03887     ! Compute flm.
03888     flm(0::L**2-1) = cmplx(0d0, 0d0)
03889     do el = abs(spin), L-1
03890        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
03891        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
03892        do m = -el, el
03893           call ssht_sampling_elm2ind(ind, el, m)
03894           do mm = -el, el
03895              if (mod(m+spin,2) == 0) then
03896                 ! m+spin even
03897                 Gmm_term = Gmme(m,mm)
03898              else
03899                 ! m+spin odd
03900                 Gmm_term = Gmmo(m,mm)
03901              end if
03902 
03903              flm(ind) = flm(ind) + &
03904                   (-1)**spin * elfactor &
03905                   * exp(I*PION2*(m+spin)) &
03906                   * dl(mm,m) * dl(mm,-spin) &
03907                   * Gmm_term
03908 
03909           end do
03910        end do
03911     end do
03912 
03913     ! Print finished if verbosity set.
03914     if (present(verbosity)) then
03915        if (verbosity > 0) then
03916           write(*,'(a,a)') SSHT_PROMPT, &
03917                'Forward transform computed!'
03918        end if
03919     end if
03920 
03921   end subroutine ssht_core_mweo_forward_sov
03922 
03923 
03924   !----------------------------------------------------------------------------
03925   ! ssht_core_mweo_forward_sov_conv
03926   !
03943 
03944   subroutine ssht_core_mweo_forward_sov_conv(flm, f, L, spin, verbosity)
03945 
03946     integer, intent(in) :: L
03947     integer, intent(in) :: spin
03948     integer, intent(in), optional :: verbosity
03949     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
03950     complex(dpc), intent(out) :: flm(0:L**2-1)
03951 
03952     integer :: p, m, t, mm, el, ind, k
03953     real(dp) :: theta, phi
03954     real(dp) :: elfactor
03955 
03956     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
03957     complex(dpc) :: fe(0:2*L-2 ,0:2*L-2)
03958     complex(dpc) :: fo(0:2*L-2 ,0:2*L-2)
03959     complex(dpc) :: Fmme(-(L-1):L-1, -(L-1):L-1)
03960     complex(dpc) :: Fmmo(-(L-1):L-1, -(L-1):L-1)
03961     complex(dpc) :: Gmme(-(L-1):L-1, -(L-1):L-1)
03962     complex(dpc) :: Gmmo(-(L-1):L-1, -(L-1):L-1)
03963     complex(dpc) :: Gmm_term
03964     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
03965     
03966     integer :: r
03967     complex(dpc) :: Fmme_pad(-2*(L-1):2*(L-1))
03968     complex(dpc) :: Fmmo_pad(-2*(L-1):2*(L-1))
03969     complex(dpc) :: w(-2*(L-1):2*(L-1))
03970     complex(dpc) :: wr(-2*(L-1):2*(L-1))
03971     character(len=STRING_LEN) :: format_spec
03972 
03973     ! Print messages depending on verbosity level.
03974     if (present(verbosity)) then
03975        if (verbosity > 0) then
03976           write(*,'(a,a,a)') SSHT_PROMPT, &
03977                'Computing forward transform using McEwen and Wiaux', &
03978                ' even-odd sampling with'
03979           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
03980                digit(spin),',a)'
03981           write(*,trim(format_spec)) SSHT_PROMPT, &
03982                'parameters (L,spin,reality) = (', &
03983                L, ',', spin, ',FALSE)...'
03984        end if
03985        if (verbosity > 1) then
03986           write(*,'(a,a)') SSHT_PROMPT, &
03987                'Using routine ssht_core_mweo_forward_sov_conv...'
03988        end if
03989     end if
03990 
03991     ! Extend f to the torus with even and odd extensions 
03992     ! about theta=PI.
03993     fe(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03994     fe(L:2*L-2, 0:2*L-2) = f(L-2:0:-1, 0:2*L-2)
03995     fo(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
03996     fo(L:2*L-2, 0:2*L-2) = -f(L-2:0:-1, 0:2*L-2)
03997 
03998 ! If don't apply spatial shift below then apply phase modulation here.
03999 !!$    do p = 0, 2*L-2
04000 !!$       phi = ssht_sampling_mweo_p2phi(p, L)
04001 !!$       do t = 0, 2*L-2
04002 !!$          theta = ssht_sampling_mweo_t2theta(t, L)   
04003 !!$          fe(t,p) = fe(t,p) * exp(I*(phi+theta)*(L-1))
04004 !!$          fo(t,p) = fo(t,p) * exp(I*(phi+theta)*(L-1))
04005 !!$       end do
04006 !!$    end do
04007 
04008     ! Compute Fmm for even and odd extensions by 2D FFT.
04009     call dfftw_plan_dft_2d(fftw_plan_fwd, 2*L-1, 2*L-1, fe(0:2*L-2,0:2*L-2), &
04010          fe(0:2*L-2,0:2*L-2), FFTW_FORWARD, FFTW_ESTIMATE)
04011     call dfftw_execute_dft(fftw_plan_fwd, fe(0:2*L-2,0:2*L-2), fe(0:2*L-2,0:2*L-2))
04012     call dfftw_execute_dft(fftw_plan_fwd, fo(0:2*L-2,0:2*L-2), fo(0:2*L-2,0:2*L-2))
04013     call dfftw_destroy_plan(fftw_plan_fwd)
04014 
04015 ! If apply phase shift above just copy Fmm.
04016 !!$    Fmme(-(L-1):L-1, -(L-1):L-1) = transpose(fe(0:2*L-2,0:2*L-2))
04017 !!$    Fmmo(-(L-1):L-1, -(L-1):L-1) = transpose(fo(0:2*L-2,0:2*L-2))
04018 
04019     ! Apply spatial shift in frequency.
04020     fe(0:2*L-2,0:2*L-2) = transpose(fe(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
04021     fo(0:2*L-2,0:2*L-2) = transpose(fo(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
04022     Fmme(0:L-1,0:L-1) = fe(0:L-1, 0:L-1)
04023     Fmme(-(L-1):-1,0:L-1) = fe(L:2*L-2, 0:L-1)
04024     Fmme(0:L-1,-(L-1):-1) = fe(0:L-1, L:2*L-2)
04025     Fmme(-(L-1):-1,-(L-1):-1) = fe(L:2*L-2, L:2*L-2)
04026     Fmmo(0:L-1,0:L-1) = fo(0:L-1, 0:L-1)
04027     Fmmo(-(L-1):-1,0:L-1) = fo(L:2*L-2, 0:L-1)
04028     Fmmo(0:L-1,-(L-1):-1) = fo(0:L-1, L:2*L-2)
04029     Fmmo(-(L-1):-1,-(L-1):-1) = fo(L:2*L-2, L:2*L-2)
04030 
04031     ! Apply phase modulation to account for sampling offset.
04032     do m = 0, 2*L-2
04033        do mm = 0, 2*L-2
04034           Fmme(m-(L-1),mm-(L-1)) = Fmme(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04035           Fmmo(m-(L-1),mm-(L-1)) = Fmmo(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04036        end do
04037     end do
04038 
04039     Fmme(-(L-1):L-1, -(L-1):L-1) = Fmme(-(L-1):L-1, -(L-1):L-1) &
04040          / (2d0*L-1d0)**2
04041     Fmmo(-(L-1):L-1, -(L-1):L-1) = Fmmo(-(L-1):L-1, -(L-1):L-1) &
04042          / (2d0*L-1d0)**2
04043 
04044     ! Compute weights.
04045     do mm = -2*(L-1), 2*(L-1)
04046        w(mm) = ssht_sampling_weight_mw(mm)
04047     end do
04048 
04049     ! Compute IFFT of w to give wr.
04050     wr(1:2*(L-1)) = w(-2*(L-1):-1)
04051     wr(-2*(L-1):0) = w(0:2*(L-1))
04052     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
04053     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
04054          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
04055     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
04056     wr(0:2*(L-1)) = w(-2*(L-1):0)
04057     wr(-2*(L-1):-1) = w(1:2*(L-1))
04058 
04059     ! Plan forward FFT.
04060     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
04061          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
04062 
04063     ! Compute Gmm for even and odd extensions by convolution implemented 
04064     ! as product in real space.
04065     do m = -(L-1), L-1
04066 
04067        ! Zero-pad Fmme.
04068        Fmme_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04069        Fmme_pad(-(L-1):L-1) = Fmme(m,-(L-1):L-1)
04070        Fmme_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04071 
04072        ! Compute IFFT of Fmme (Fmmo used for temporary storage).
04073        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04074        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04075        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04076        call dfftw_execute_dft(fftw_plan_bwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04077             Fmme_pad(-2*(L-1):2*(L-1)))
04078        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04079        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04080        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04081 
04082        ! Compute product of Fmme and weight in real space.
04083        do r = -2*(L-1), 2*(L-1)
04084           Fmme_pad(r) = Fmme_pad(r) * wr(-r)
04085        end do
04086 
04087        ! Compute Gmme by FFT.
04088        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04089        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04090        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04091        call dfftw_execute_dft(fftw_plan_fwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04092             Fmme_pad(-2*(L-1):2*(L-1)))
04093        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04094        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04095        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04096 
04097        ! Extract section of Gmme of interest.
04098        Gmme(m,-(L-1):(L-1)) = Fmme_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04099 
04100        ! Repeat for odd signal...
04101 
04102        ! Zero-pad Fmmo.
04103        Fmmo_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04104        Fmmo_pad(-(L-1):L-1) = Fmmo(m,-(L-1):L-1)
04105        Fmmo_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04106 
04107        ! Compute IFFT of Fmmo (Fmme used for temporary storage).
04108        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04109        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04110        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04111        call dfftw_execute_dft(fftw_plan_bwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04112             Fmmo_pad(-2*(L-1):2*(L-1)))
04113        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04114        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04115        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04116 
04117        ! Compute product of Fmmo and weight in real space.
04118        do r = -2*(L-1), 2*(L-1)
04119           Fmmo_pad(r) = Fmmo_pad(r) * wr(-r)
04120        end do
04121 
04122        ! Compute Gmmo by FFT.
04123        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04124        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04125        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04126        call dfftw_execute_dft(fftw_plan_fwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04127             Fmmo_pad(-2*(L-1):2*(L-1)))
04128        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04129        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04130        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04131 
04132        ! Extract section of Gmmo of interest.
04133        Gmmo(m,-(L-1):(L-1)) = Fmmo_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04134 
04135     end do
04136     call dfftw_destroy_plan(fftw_plan_bwd)
04137     call dfftw_destroy_plan(fftw_plan_fwd)    
04138 
04139     ! Compute flm.
04140     flm(0::L**2-1) = cmplx(0d0, 0d0)
04141     do el = abs(spin), L-1
04142        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
04143        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
04144        do m = -el, el
04145           call ssht_sampling_elm2ind(ind, el, m)
04146           do mm = -el, el
04147              if (mod(m+spin,2) == 0) then
04148                 ! m+spin even
04149                 Gmm_term = Gmme(m,mm)
04150              else
04151                 ! m+spin odd
04152                 Gmm_term = Gmmo(m,mm)
04153              end if
04154 
04155              flm(ind) = flm(ind) + &
04156                   (-1)**spin * elfactor &
04157                   * exp(I*PION2*(m+spin)) &
04158                   * dl(mm,m) * dl(mm,-spin) &
04159                   * Gmm_term
04160 
04161           end do
04162        end do
04163     end do
04164 
04165     ! Print finished if verbosity set.
04166     if (present(verbosity)) then
04167        if (verbosity > 0) then
04168           write(*,'(a,a)') SSHT_PROMPT, &
04169                'Forward transform computed!'
04170        end if
04171     end if
04172 
04173   end subroutine ssht_core_mweo_forward_sov_conv
04174 
04175 
04176   !----------------------------------------------------------------------------
04177   ! ssht_core_mweo_forward_sov_conv_sym
04178   !
04196 
04197   subroutine ssht_core_mweo_forward_sov_conv_sym(flm, f, L, spin, verbosity)
04198 
04199     integer, intent(in) :: L
04200     integer, intent(in) :: spin
04201     integer, intent(in), optional :: verbosity
04202     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
04203     complex(dpc), intent(out) :: flm(0:L**2-1)
04204 
04205     integer :: p, m, t, mm, el, ind, k
04206     real(dp) :: theta, phi
04207     real(dp) :: elfactor
04208 
04209     real(dp) :: dl(0:L-1, -(L-1):L-1)
04210     complex(dpc) :: fe(0:2*L-2 ,0:2*L-2)
04211     complex(dpc) :: fo(0:2*L-2 ,0:2*L-2)
04212     complex(dpc) :: Fmme(-(L-1):L-1, -(L-1):L-1)
04213     complex(dpc) :: Fmmo(-(L-1):L-1, -(L-1):L-1)
04214     complex(dpc) :: Gmme(-(L-1):L-1, -(L-1):L-1)
04215     complex(dpc) :: Gmmo(-(L-1):L-1, -(L-1):L-1)
04216     complex(dpc) :: Gmm_term
04217     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
04218     
04219     integer :: r
04220     complex(dpc) :: Fmme_pad(-2*(L-1):2*(L-1))
04221     complex(dpc) :: Fmmo_pad(-2*(L-1):2*(L-1))
04222     complex(dpc) :: w(-2*(L-1):2*(L-1))
04223     complex(dpc) :: wr(-2*(L-1):2*(L-1))
04224     character(len=STRING_LEN) :: format_spec
04225 
04226     real(dp) :: signs(0:L), ssign
04227     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
04228     integer :: eltmp
04229 
04230     ! Perform precomputations.
04231     do el = 0, 2*(L-1) + 1
04232        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
04233     end do
04234     do m = 0, L-1, 2
04235        signs(m)   =  1.0_dp
04236        signs(m+1) = -1.0_dp
04237     enddo
04238 
04239     ! Set spin sign.
04240     ssign = signs(abs(spin))
04241 
04242     ! Print messages depending on verbosity level.
04243     if (present(verbosity)) then
04244        if (verbosity > 0) then
04245           write(*,'(a,a,a)') SSHT_PROMPT, &
04246                'Computing forward transform using McEwen and Wiaux', &
04247                ' even-odd sampling with'
04248           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
04249                digit(spin),',a)'
04250           write(*,trim(format_spec)) SSHT_PROMPT, &
04251                'parameters (L,spin,reality) = (', &
04252                L, ',', spin, ',FALSE)...'
04253        end if
04254        if (verbosity > 1) then
04255           write(*,'(a,a)') SSHT_PROMPT, &
04256                'Using routine ssht_core_mweo_forward_sov_conv_sym...'
04257        end if
04258     end if
04259 
04260     ! Extend f to the torus with even and odd extensions 
04261     ! about theta=PI.
04262     fe(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
04263     fe(L:2*L-2, 0:2*L-2) = f(L-2:0:-1, 0:2*L-2)
04264     fo(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
04265     fo(L:2*L-2, 0:2*L-2) = -f(L-2:0:-1, 0:2*L-2)
04266 
04267 ! If don't apply spatial shift below then apply phase modulation here.
04268 !!$    do p = 0, 2*L-2
04269 !!$       phi = ssht_sampling_mweo_p2phi(p, L)
04270 !!$       do t = 0, 2*L-2
04271 !!$          theta = ssht_sampling_mweo_t2theta(t, L)   
04272 !!$          fe(t,p) = fe(t,p) * exp(I*(phi+theta)*(L-1))
04273 !!$          fo(t,p) = fo(t,p) * exp(I*(phi+theta)*(L-1))
04274 !!$       end do
04275 !!$    end do
04276 
04277     ! Compute Fmm for even and odd extensions by 2D FFT.
04278     call dfftw_plan_dft_2d(fftw_plan_fwd, 2*L-1, 2*L-1, fe(0:2*L-2,0:2*L-2), &
04279          fe(0:2*L-2,0:2*L-2), FFTW_FORWARD, FFTW_ESTIMATE)
04280     call dfftw_execute_dft(fftw_plan_fwd, fe(0:2*L-2,0:2*L-2), fe(0:2*L-2,0:2*L-2))
04281     call dfftw_execute_dft(fftw_plan_fwd, fo(0:2*L-2,0:2*L-2), fo(0:2*L-2,0:2*L-2))
04282     call dfftw_destroy_plan(fftw_plan_fwd)
04283 
04284 ! If apply phase shift above just copy Fmm.
04285 !!$    Fmme(-(L-1):L-1, -(L-1):L-1) = transpose(fe(0:2*L-2,0:2*L-2))
04286 !!$    Fmmo(-(L-1):L-1, -(L-1):L-1) = transpose(fo(0:2*L-2,0:2*L-2))
04287 
04288     ! Apply spatial shift in frequency.
04289     fe(0:2*L-2,0:2*L-2) = transpose(fe(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
04290     fo(0:2*L-2,0:2*L-2) = transpose(fo(0:2*L-2,0:2*L-2)) * exp(I*(L-1)*2d0*PI/(2d0*L-1d0))
04291     Fmme(0:L-1,0:L-1) = fe(0:L-1, 0:L-1)
04292     Fmme(-(L-1):-1,0:L-1) = fe(L:2*L-2, 0:L-1)
04293     Fmme(0:L-1,-(L-1):-1) = fe(0:L-1, L:2*L-2)
04294     Fmme(-(L-1):-1,-(L-1):-1) = fe(L:2*L-2, L:2*L-2)
04295     Fmmo(0:L-1,0:L-1) = fo(0:L-1, 0:L-1)
04296     Fmmo(-(L-1):-1,0:L-1) = fo(L:2*L-2, 0:L-1)
04297     Fmmo(0:L-1,-(L-1):-1) = fo(0:L-1, L:2*L-2)
04298     Fmmo(-(L-1):-1,-(L-1):-1) = fo(L:2*L-2, L:2*L-2)
04299 
04300     ! Apply phase modulation to account for sampling offset.
04301     do mm = 0, 2*L-2
04302        do m = 0, 2*L-2
04303           Fmme(m-(L-1),mm-(L-1)) = Fmme(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04304           Fmmo(m-(L-1),mm-(L-1)) = Fmmo(m-(L-1),mm-(L-1)) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04305        end do
04306     end do
04307 
04308     Fmme(-(L-1):L-1, -(L-1):L-1) = Fmme(-(L-1):L-1, -(L-1):L-1) &
04309          / (2d0*L-1d0)**2
04310     Fmmo(-(L-1):L-1, -(L-1):L-1) = Fmmo(-(L-1):L-1, -(L-1):L-1) &
04311          / (2d0*L-1d0)**2
04312 
04313     ! Compute weights.
04314     do mm = -2*(L-1), 2*(L-1)
04315        w(mm) = ssht_sampling_weight_mw(mm)
04316     end do
04317 
04318     ! Compute IFFT of w to give wr.
04319     wr(1:2*(L-1)) = w(-2*(L-1):-1)
04320     wr(-2*(L-1):0) = w(0:2*(L-1))
04321     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
04322     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
04323          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
04324     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
04325     wr(0:2*(L-1)) = w(-2*(L-1):0)
04326     wr(-2*(L-1):-1) = w(1:2*(L-1))
04327 
04328     ! Plan forward FFT.
04329     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
04330          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
04331 
04332     ! Compute Gmm for even and odd extensions by convolution implemented 
04333     ! as product in real space.
04334     do m = -(L-1), L-1
04335 
04336        ! Zero-pad Fmme.
04337        Fmme_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04338        Fmme_pad(-(L-1):L-1) = Fmme(m,-(L-1):L-1)
04339        Fmme_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04340 
04341        ! Compute IFFT of Fmme (Fmmo used for temporary storage).
04342        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04343        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04344        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04345        call dfftw_execute_dft(fftw_plan_bwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04346             Fmme_pad(-2*(L-1):2*(L-1)))
04347        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04348        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04349        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04350 
04351        ! Compute product of Fmme and weight in real space.
04352        do r = -2*(L-1), 2*(L-1)
04353           Fmme_pad(r) = Fmme_pad(r) * wr(-r)
04354        end do
04355 
04356        ! Compute Gmme by FFT.
04357        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04358        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04359        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04360        call dfftw_execute_dft(fftw_plan_fwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04361             Fmme_pad(-2*(L-1):2*(L-1)))
04362        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04363        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04364        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04365 
04366        ! Extract section of Gmme of interest.
04367        Gmme(m,-(L-1):(L-1)) = Fmme_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04368 
04369        ! Repeat for odd signal...
04370 
04371        ! Zero-pad Fmmo.
04372        Fmmo_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04373        Fmmo_pad(-(L-1):L-1) = Fmmo(m,-(L-1):L-1)
04374        Fmmo_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04375 
04376        ! Compute IFFT of Fmmo (Fmme used for temporary storage).
04377        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04378        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04379        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04380        call dfftw_execute_dft(fftw_plan_bwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04381             Fmmo_pad(-2*(L-1):2*(L-1)))
04382        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04383        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04384        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04385 
04386        ! Compute product of Fmmo and weight in real space.
04387        do r = -2*(L-1), 2*(L-1)
04388           Fmmo_pad(r) = Fmmo_pad(r) * wr(-r)
04389        end do
04390 
04391        ! Compute Gmmo by FFT.
04392        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04393        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04394        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04395        call dfftw_execute_dft(fftw_plan_fwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04396             Fmmo_pad(-2*(L-1):2*(L-1)))
04397        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04398        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04399        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04400 
04401        ! Extract section of Gmmo of interest.
04402        Gmmo(m,-(L-1):(L-1)) = Fmmo_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04403 
04404     end do
04405     call dfftw_destroy_plan(fftw_plan_bwd)
04406     call dfftw_destroy_plan(fftw_plan_fwd)    
04407 
04408     ! Compute flm.
04409     flm(0::L**2-1) = cmplx(0d0, 0d0)
04410     do el = abs(spin), L-1
04411        if (el /= 0 .and. el == abs(spin)) then
04412           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
04413           do eltmp = 0, abs(spin)
04414              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
04415                   sqrt_tbl(0:2*eltmp+1))
04416           end do
04417           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
04418                el, signs(0:el))
04419        else
04420           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
04421                sqrt_tbl(0:2*el+1))
04422           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
04423                el, signs(0:el))
04424        end if
04425 
04426        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
04427        do m = -el, el
04428           call ssht_sampling_elm2ind(ind, el, m)
04429 
04430           flm(ind) = flm(ind) + &
04431                ssign * elfactor &
04432                * exp(I*PION2*(m+spin)) &
04433                * dl(0,m) * dl(0,-spin) &
04434                * Gmme(m,0)
04435 
04436           do mm = 1, el
04437              if (mod(m+spin,2) == 0) then
04438                 ! m+spin even
04439                 Gmm_term = Gmme(m,mm) + signs(abs(m)) * ssign * Gmme(m,-mm)
04440              else
04441                 ! m+spin odd
04442                 Gmm_term = Gmmo(m,mm) + signs(abs(m)) * ssign * Gmmo(m,-mm)
04443              end if
04444 
04445              flm(ind) = flm(ind) + &
04446                   ssign * elfactor &
04447                   * exp(I*PION2*(m+spin)) &
04448                   * dl(mm,m) * dl(mm,-spin) &
04449                   * Gmm_term
04450 
04451           end do
04452        end do
04453     end do
04454 
04455     ! Print finished if verbosity set.
04456     if (present(verbosity)) then
04457        if (verbosity > 0) then
04458           write(*,'(a,a)') SSHT_PROMPT, &
04459                'Forward transform computed!'
04460        end if
04461     end if
04462 
04463   end subroutine ssht_core_mweo_forward_sov_conv_sym
04464 
04465 
04466   !----------------------------------------------------------------------------
04467   ! ssht_core_mweo_forward_sov_conv_sym_real
04468   !
04487 
04488   subroutine ssht_core_mweo_forward_sov_conv_sym_real(flm, f, L, verbosity)
04489 
04490     integer, intent(in) :: L
04491     integer, intent(in), optional :: verbosity
04492     real(dp), intent(in) :: f(0:L-1 ,0:2*L-2)
04493     complex(dpc), intent(out) :: flm(0:L**2-1)
04494 
04495     integer :: p, m, t, mm, el, ind, k
04496     real(dp) :: theta, phi
04497     real(dp) :: elfactor
04498 
04499     real(dp) :: dl(0:L-1, 0:L-1)
04500     real(dp) :: fe(0:2*L-2 ,0:2*L-2)
04501     real(dp) :: fo(0:2*L-2 ,0:2*L-2)
04502     complex(dpc) :: Fmme(0:L-1, -(L-1):L-1)
04503     complex(dpc) :: Fmmo(0:L-1, -(L-1):L-1)
04504     complex(dpc) :: Gmme(0:L-1, -(L-1):L-1)
04505     complex(dpc) :: Gmmo(0:L-1, -(L-1):L-1)
04506     complex(dpc) :: Gmm_term
04507     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
04508     
04509     integer :: r
04510     complex(dpc) :: Fmme_pad(-2*(L-1):2*(L-1))
04511     complex(dpc) :: Fmmo_pad(-2*(L-1):2*(L-1))
04512     complex(dpc) :: w(-2*(L-1):2*(L-1))
04513     complex(dpc) :: wr(-2*(L-1):2*(L-1))
04514 
04515     integer :: ind_nm
04516     integer :: spin
04517     complex(dpc) :: tmp(0:L-1,0:2*L-2)
04518     character(len=STRING_LEN) :: format_spec
04519 
04520     real(dp) :: signs(0:L), ssign
04521     real(dp) :: dl_mm_spin, dl_0_spin
04522     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
04523     integer :: eltmp
04524 
04525     ! Perform precomputations.
04526     do el = 0, 2*(L-1) + 1
04527        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
04528     end do
04529     do m = 0, L-1, 2
04530        signs(m)   =  1.0_dp
04531        signs(m+1) = -1.0_dp
04532     enddo
04533 
04534     ! Set spin to zero.
04535     spin = 0
04536     ssign = signs(abs(spin))
04537 
04538     ! Print messages depending on verbosity level.
04539     if (present(verbosity)) then
04540        if (verbosity > 0) then
04541           write(*,'(a,a,a)') SSHT_PROMPT, &
04542                'Computing forward transform using McEwen and Wiaux', &
04543                ' even-odd sampling with'
04544           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
04545                digit(spin),',a)'
04546           write(*,trim(format_spec)) SSHT_PROMPT, &
04547                'parameters (L,spin,reality) = (', &
04548                L, ',', spin, ',TRUE)...'
04549        end if
04550        if (verbosity > 1) then
04551           write(*,'(a,a)') SSHT_PROMPT, &
04552                'Using routine ssht_core_mweo_forward_sov_conv_sym_real...'
04553        end if
04554     end if
04555 
04556     ! Extend f to the torus with even and odd extensions 
04557     ! about theta=PI.
04558     ! Compute Fmm for even and odd extensions by 2D FFT.
04559     ! Apply spatial shift in frequency.
04560     call dfftw_plan_dft_r2c_2d(fftw_plan_fwd, 2*L-1, 2*L-1, fe(0:2*L-2,0:2*L-2), &
04561          tmp(0:L-1,0:2*L-2), FFTW_ESTIMATE)
04562 
04563     fe(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
04564     fe(L:2*L-2, 0:2*L-2) = f(L-2:0:-1, 0:2*L-2)
04565     call dfftw_execute_dft_r2c(fftw_plan_fwd, &
04566          transpose(fe(0:2*L-2,0:2*L-2)), tmp(0:L-1,0:2*L-2))
04567     Fmme(0:L-1,0:L-1) = tmp(0:L-1, 0:L-1)
04568     Fmme(0:L-1,-(L-1):-1) = tmp(0:L-1, L:2*L-2)
04569 
04570     fo(0:L-1, 0:2*L-2) = f(0:L-1, 0:2*L-2)
04571     fo(L:2*L-2, 0:2*L-2) = -f(L-2:0:-1, 0:2*L-2)
04572     call dfftw_execute_dft_r2c(fftw_plan_fwd, &
04573          transpose(fo(0:2*L-2,0:2*L-2)), tmp(0:L-1,0:2*L-2))
04574     Fmmo(0:L-1,0:L-1) = tmp(0:L-1, 0:L-1)
04575     Fmmo(0:L-1,-(L-1):-1) = tmp(0:L-1, L:2*L-2)
04576 
04577     call dfftw_destroy_plan(fftw_plan_fwd)
04578 
04579     Fmme(0:L-1, -(L-1):L-1) = Fmme(0:L-1, -(L-1):L-1) &
04580          / (2d0*L-1d0)**2
04581     Fmmo(0:L-1, -(L-1):L-1) = Fmmo(0:L-1, -(L-1):L-1) &
04582          / (2d0*L-1d0)**2
04583 
04584     ! Apply phase modulation to account for sampling offset.
04585 
04586     do mm = -(L-1), L-1
04587        do m = 0, L-1
04588           Fmme(m,mm) = Fmme(m,mm) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04589           Fmmo(m,mm) = Fmmo(m,mm) * exp(-I*(m+mm)*PI/(2d0*L-1d0))
04590        end do
04591     end do
04592 
04593     ! Compute weights.
04594     do mm = -2*(L-1), 2*(L-1)
04595        w(mm) = ssht_sampling_weight_mw(mm)
04596     end do
04597 
04598     ! Compute IFFT of w to give wr.
04599     wr(1:2*(L-1)) = w(-2*(L-1):-1)
04600     wr(-2*(L-1):0) = w(0:2*(L-1))
04601     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
04602     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
04603          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
04604     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
04605     wr(0:2*(L-1)) = w(-2*(L-1):0)
04606     wr(-2*(L-1):-1) = w(1:2*(L-1))
04607 
04608     ! Plan forward FFT.
04609     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
04610          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
04611 
04612     ! Compute Gmm for even and odd extensions by convolution implemented 
04613     ! as product in real space.
04614     do m = 0, L-1
04615 
04616        ! Zero-pad Fmme.
04617        Fmme_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04618        Fmme_pad(-(L-1):L-1) = Fmme(m,-(L-1):L-1)
04619        Fmme_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04620 
04621        ! Compute IFFT of Fmme (Fmmo used for temporary storage).
04622        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04623        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04624        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04625        call dfftw_execute_dft(fftw_plan_bwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04626             Fmme_pad(-2*(L-1):2*(L-1)))
04627        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04628        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04629        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04630 
04631        ! Compute product of Fmme and weight in real space.
04632        do r = -2*(L-1), 2*(L-1)
04633           Fmme_pad(r) = Fmme_pad(r) * wr(-r)
04634        end do
04635 
04636        ! Compute Gmme by FFT.
04637        Fmmo_pad(1:2*(L-1)) = Fmme_pad(-2*(L-1):-1)
04638        Fmmo_pad(-2*(L-1):0) = Fmme_pad(0:2*(L-1))
04639        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04640        call dfftw_execute_dft(fftw_plan_fwd, Fmme_pad(-2*(L-1):2*(L-1)), &
04641             Fmme_pad(-2*(L-1):2*(L-1)))
04642        Fmmo_pad(0:2*(L-1)) = Fmme_pad(-2*(L-1):0)
04643        Fmmo_pad(-2*(L-1):-1) = Fmme_pad(1:2*(L-1))
04644        Fmme_pad(-2*(L-1):2*(L-1)) = Fmmo_pad(-2*(L-1):2*(L-1))
04645 
04646        ! Extract section of Gmme of interest.
04647        Gmme(m,-(L-1):(L-1)) = Fmme_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04648 
04649        ! Repeat for odd signal...
04650 
04651        ! Zero-pad Fmmo.
04652        Fmmo_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
04653        Fmmo_pad(-(L-1):L-1) = Fmmo(m,-(L-1):L-1)
04654        Fmmo_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
04655 
04656        ! Compute IFFT of Fmmo (Fmme used for temporary storage).
04657        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04658        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04659        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04660        call dfftw_execute_dft(fftw_plan_bwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04661             Fmmo_pad(-2*(L-1):2*(L-1)))
04662        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04663        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04664        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04665 
04666        ! Compute product of Fmmo and weight in real space.
04667        do r = -2*(L-1), 2*(L-1)
04668           Fmmo_pad(r) = Fmmo_pad(r) * wr(-r)
04669        end do
04670 
04671        ! Compute Gmmo by FFT.
04672        Fmme_pad(1:2*(L-1)) = Fmmo_pad(-2*(L-1):-1)
04673        Fmme_pad(-2*(L-1):0) = Fmmo_pad(0:2*(L-1))
04674        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04675        call dfftw_execute_dft(fftw_plan_fwd, Fmmo_pad(-2*(L-1):2*(L-1)), &
04676             Fmmo_pad(-2*(L-1):2*(L-1)))
04677        Fmme_pad(0:2*(L-1)) = Fmmo_pad(-2*(L-1):0)
04678        Fmme_pad(-2*(L-1):-1) = Fmmo_pad(1:2*(L-1))
04679        Fmmo_pad(-2*(L-1):2*(L-1)) = Fmme_pad(-2*(L-1):2*(L-1))
04680 
04681        ! Extract section of Gmmo of interest.
04682        Gmmo(m,-(L-1):(L-1)) = Fmmo_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
04683 
04684     end do
04685     call dfftw_destroy_plan(fftw_plan_bwd)
04686     call dfftw_destroy_plan(fftw_plan_fwd)    
04687 
04688     ! Compute flm.
04689     flm(0::L**2-1) = cmplx(0d0, 0d0)
04690     do el = abs(spin), L-1
04691        if (el /= 0 .and. el == abs(spin)) then
04692           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
04693           do eltmp = 0, abs(spin)
04694              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
04695                   sqrt_tbl(0:2*eltmp+1))
04696           end do
04697           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
04698                el, signs(0:el))
04699        else
04700           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
04701                sqrt_tbl(0:2*el+1))
04702           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
04703                el, signs(0:el))
04704        end if
04705 
04706        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
04707        do m = 0, el
04708           call ssht_sampling_elm2ind(ind, el, m)
04709 
04710           if (spin <= 0) then
04711              dl_0_spin = dl(0,-spin)
04712           else
04713              dl_0_spin = signs(el) * dl(0,spin)
04714           end if
04715 
04716           flm(ind) = flm(ind) + &
04717                ssign * elfactor &
04718                * exp(I*PION2*(m+spin)) &
04719                * dl(0,m) * dl_0_spin &
04720                * Gmme(m,0)
04721 
04722           do mm = 1, el
04723              if (mod(m+spin,2) == 0) then
04724                 ! m+spin even
04725                 Gmm_term = Gmme(m,mm) + signs(m) * ssign * Gmme(m,-mm)
04726              else
04727                 ! m+spin odd
04728                 Gmm_term = Gmmo(m,mm) + signs(m) * ssign * Gmmo(m,-mm)
04729              end if
04730 
04731              if (spin <= 0) then
04732                 dl_mm_spin = dl(mm,-spin)
04733              else
04734                 dl_mm_spin = signs(el) * signs(mm) * dl(mm,spin)
04735              end if
04736 
04737              flm(ind) = flm(ind) + &
04738                   ssign * elfactor &
04739                   * exp(I*PION2*(m+spin)) &
04740                   * dl(mm,m) * dl_mm_spin &
04741                   * Gmm_term
04742 
04743           end do
04744        end do
04745     end do
04746 
04747     ! Set flm values for negative m using conjugate symmetry.
04748     do el = abs(spin), L-1
04749        do m = 1, el
04750           call ssht_sampling_elm2ind(ind, el, m)
04751           call ssht_sampling_elm2ind(ind_nm, el, -m)
04752           flm(ind_nm) = signs(m) * conjg(flm(ind))
04753        end do
04754     end do
04755 
04756     ! Print finished if verbosity set.
04757     if (present(verbosity)) then
04758        if (verbosity > 0) then
04759           write(*,'(a,a)') SSHT_PROMPT, &
04760                'Forward transform computed!'
04761        end if
04762     end if
04763 
04764   end subroutine ssht_core_mweo_forward_sov_conv_sym_real
04765 
04766 
04767   !----------------------------------------------------------------------------
04768   ! MW
04769   !----------------------------------------------------------------------------
04770 
04771 
04772   !----------------------------------------------------------------------------
04773   ! ssht_core_mw_forward_sov_direct
04774   !
04793 
04794   subroutine ssht_core_mw_forward_sov_direct(flm, f, L, spin, verbosity)
04795 
04796     integer, intent(in) :: L
04797     integer, intent(in) :: spin
04798     integer, intent(in), optional :: verbosity
04799     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
04800     complex(dpc), intent(out) :: flm(0:L**2-1)
04801 
04802     integer :: p, m, t, mm, el, ind, k
04803     real(dp) :: theta, phi
04804     real(dp) :: elfactor
04805 
04806     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
04807     complex(dpc) :: Fmt(-(L-1):L-1, 0:2*L-2)
04808     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
04809     complex(dpc) :: Gmm(-(L-1):L-1, -(L-1):L-1) 
04810     character(len=STRING_LEN) :: format_spec
04811 
04812     ! Print messages depending on verbosity level.
04813     if (present(verbosity)) then
04814        if (verbosity > 0) then
04815           write(*,'(a,a,a)') SSHT_PROMPT, &
04816                'Computing forward transform using McEwen and Wiaux', &
04817                ' sampling with'
04818           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
04819                digit(spin),',a)'
04820           write(*,trim(format_spec)) SSHT_PROMPT, &
04821                'parameters (L,spin,reality) = (', &
04822                L, ',', spin, ',FALSE)...'
04823        end if
04824        if (verbosity > 1) then
04825           write(*,'(a,a)') SSHT_PROMPT, &
04826                'Using routine ssht_core_mw_forward_sov_direct...'
04827        end if
04828     end if
04829 
04830     ! Compute Fourier transform over phi, i.e. compute Fmt.
04831     Fmt(-(L-1):L-1,0:2*L-2) = cmplx(0d0, 0d0)    
04832     do p = 0, 2*L-2
04833        phi = ssht_sampling_mw_p2phi(p, L)
04834        do t = 0, L-1
04835           do m = -(L-1), L-1
04836              Fmt(m,t) = Fmt(m,t) + &
04837                   f(t,p) * exp(-I*m*phi)
04838           end do
04839        end do
04840     end do
04841     Fmt(-(L-1):L-1,0:2*L-2) = Fmt(-(L-1):L-1,0:2*L-2) / (2d0*L-1d0)
04842 
04843     ! Extend Fmt periodically.
04844     do m = -(L-1), L-1
04845        Fmt(m, L:2*L-2) = (-1)**(m+spin) * Fmt(m, L-2:0:-1)
04846     end do
04847 
04848     ! Compute Fmm.
04849     Fmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
04850     do t = 0, 2*L-2
04851        theta = ssht_sampling_mw_t2theta(t, L)    
04852        do m = -(L-1), L-1
04853           do mm = -(L-1), L-1
04854              Fmm(m,mm) = Fmm(m,mm) + &
04855                   Fmt(m,t) * exp(-I*mm*theta)
04856           end do
04857        end do
04858     end do
04859     Fmm(-(L-1):L-1, -(L-1):L-1) = Fmm(-(L-1):L-1, -(L-1):L-1) / (2d0*L-1d0)
04860 
04861     ! Compute Gmm by direct convolution.
04862     Gmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
04863     do m = -(L-1), L-1
04864        do mm = -(L-1), L-1
04865           do k = -(L-1), L-1 
04866              Gmm(m,mm) = Gmm(m,mm) + &
04867                   Fmm(m,k) * ssht_sampling_weight_mw(k - mm) * 2d0 * PI
04868           end do
04869        end do
04870     end do
04871 
04872     ! Compute flm.
04873     flm(0::L**2-1) = cmplx(0d0, 0d0)
04874     do el = abs(spin), L-1
04875        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
04876        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
04877        do m = -el, el
04878           call ssht_sampling_elm2ind(ind, el, m)
04879           do mm = -el, el             
04880              flm(ind) = flm(ind) + &
04881                   (-1)**spin * elfactor &
04882                   * exp(I*PION2*(m+spin)) &
04883                   * dl(mm,m) * dl(mm,-spin) &
04884                   * Gmm(m,mm)
04885           end do
04886        end do
04887     end do
04888 
04889     ! Print finished if verbosity set.
04890     if (present(verbosity)) then
04891        if (verbosity > 0) then
04892           write(*,'(a,a)') SSHT_PROMPT, &
04893                'Forward transform computed!'
04894        end if
04895     end if
04896 
04897   end subroutine ssht_core_mw_forward_sov_direct
04898 
04899 
04900   !----------------------------------------------------------------------------
04901   ! ssht_core_mw_forward_sov
04902   !
04918 
04919   subroutine ssht_core_mw_forward_sov(flm, f, L, spin, verbosity)
04920 
04921     integer, intent(in) :: L
04922     integer, intent(in) :: spin
04923     integer, intent(in), optional :: verbosity
04924     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
04925     complex(dpc), intent(out) :: flm(0:L**2-1)
04926 
04927     integer :: p, m, t, mm, el, ind, k
04928     real(dp) :: theta, phi
04929     real(dp) :: elfactor
04930 
04931     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
04932     complex(dpc) :: Fmt(-(L-1):L-1, 0:2*L-2)
04933     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
04934     complex(dpc) :: Gmm(-(L-1):L-1, -(L-1):L-1) 
04935     integer*8 :: fftw_plan
04936     complex(dpc) :: tmp(0:2*L-2)
04937     character(len=STRING_LEN) :: format_spec
04938 
04939     ! Print messages depending on verbosity level.
04940     if (present(verbosity)) then
04941        if (verbosity > 0) then
04942           write(*,'(a,a,a)') SSHT_PROMPT, &
04943                'Computing forward transform using McEwen and Wiaux', &
04944                ' sampling with'
04945           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
04946                digit(spin),',a)'
04947           write(*,trim(format_spec)) SSHT_PROMPT, &
04948                'parameters (L,spin,reality) = (', &
04949                L, ',', spin, ',FALSE)...'
04950        end if
04951        if (verbosity > 1) then
04952           write(*,'(a,a)') SSHT_PROMPT, &
04953                'Using routine ssht_core_mw_forward_sov...'
04954        end if
04955     end if
04956 
04957     ! Compute Fourier transform over phi, i.e. compute Fmt.
04958     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, Fmt(-(L-1):L-1,0), &
04959          Fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
04960     do t = 0, L-1
04961        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
04962        Fmt(0:L-1,t) = tmp(0:L-1)
04963        Fmt(-(L-1):-1,t) = tmp(L:2*L-2)
04964     end do
04965 !    call dfftw_destroy_plan(fftw_plan)
04966     Fmt(-(L-1):L-1, 0:L-1) = Fmt(-(L-1):L-1, 0:L-1) / (2d0*L-1d0)
04967 
04968     ! Extend Fmt periodically.
04969     do m = -(L-1), L-1
04970        Fmt(m, L:2*L-2) = (-1)**(m+spin) * Fmt(m, L-2:0:-1)
04971     end do
04972 
04973     ! Compute Fourier transform over theta, i.e. compute Fmm.
04974     do m = -(L-1), L-1
04975        call dfftw_execute_dft(fftw_plan, Fmt(m,0:2*L-2), tmp(0:2*L-2))
04976        Fmm(m,0:L-1) = tmp(0:L-1)
04977        Fmm(m,-(L-1):-1) = tmp(L:2*L-2)
04978     end do
04979     Fmm(-(L-1):L-1, -(L-1):L-1) = Fmm(-(L-1):L-1, -(L-1):L-1) / (2d0*L-1d0)
04980     call dfftw_destroy_plan(fftw_plan)
04981 
04982     ! Apply phase modulation to account for sampling offset.
04983     do mm = -(L-1), L-1
04984        Fmm(-(L-1):L-1,mm) = Fmm(-(L-1):L-1, mm) * exp(-I*mm*PI/(2d0*L - 1d0))
04985     end do
04986 
04987     ! Compute Gmm by direct convolution.
04988     Gmm(-(L-1):L-1, -(L-1):L-1) = cmplx(0d0, 0d0)
04989     do m = -(L-1), L-1
04990        do mm = -(L-1), L-1
04991           do k = -(L-1), L-1 
04992              Gmm(m,mm) = Gmm(m,mm) + &
04993                   Fmm(m,k) * ssht_sampling_weight_mw(k - mm) * 2d0 * PI
04994           end do
04995        end do
04996     end do
04997 
04998     ! Compute flm.
04999     flm(0::L**2-1) = cmplx(0d0, 0d0)
05000     do el = abs(spin), L-1
05001        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
05002        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
05003        do m = -el, el
05004           call ssht_sampling_elm2ind(ind, el, m)
05005           do mm = -el, el             
05006              flm(ind) = flm(ind) + &
05007                   (-1)**spin * elfactor &
05008                   * exp(I*PION2*(m+spin)) &
05009                   * dl(mm,m) * dl(mm,-spin) &
05010                   * Gmm(m,mm)
05011           end do
05012        end do
05013     end do
05014 
05015     ! Print finished if verbosity set.
05016     if (present(verbosity)) then
05017        if (verbosity > 0) then
05018           write(*,'(a,a)') SSHT_PROMPT, &
05019                'Forward transform computed!'
05020        end if
05021     end if
05022 
05023   end subroutine ssht_core_mw_forward_sov
05024 
05025 
05026   !----------------------------------------------------------------------------
05027   ! ssht_core_mw_forward_sov_conv
05028   !
05045 
05046   subroutine ssht_core_mw_forward_sov_conv(flm, f, L, spin, verbosity)
05047 
05048     integer, intent(in) :: L
05049     integer, intent(in) :: spin
05050     integer, intent(in), optional :: verbosity
05051     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
05052     complex(dpc), intent(out) :: flm(0:L**2-1)
05053 
05054     integer :: p, m, t, mm, el, ind, k
05055     real(dp) :: theta, phi
05056     real(dp) :: elfactor
05057 
05058     real(dp) :: dl(-(L-1):L-1, -(L-1):L-1)
05059     complex(dpc) :: Fmt(-(L-1):L-1, 0:2*L-2)
05060     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
05061     complex(dpc) :: Gmm(-(L-1):L-1, -(L-1):L-1) 
05062     integer*8 :: fftw_plan
05063     complex(dpc) :: tmp(0:2*L-2)
05064 
05065     integer :: r
05066     complex(dpc) :: Fmm_pad(-2*(L-1):2*(L-1))
05067     complex(dpc) :: tmp_pad(-2*(L-1):2*(L-1))
05068     complex(dpc) :: w(-2*(L-1):2*(L-1))
05069     complex(dpc) :: wr(-2*(L-1):2*(L-1))
05070     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
05071     character(len=STRING_LEN) :: format_spec
05072 
05073     ! Print messages depending on verbosity level.
05074     if (present(verbosity)) then
05075        if (verbosity > 0) then
05076           write(*,'(a,a,a)') SSHT_PROMPT, &
05077                'Computing forward transform using McEwen and Wiaux', &
05078                ' sampling with'
05079           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
05080                digit(spin),',a)'
05081           write(*,trim(format_spec)) SSHT_PROMPT, &
05082                'parameters (L,spin,reality) = (', &
05083                L, ',', spin, ',FALSE)...'
05084        end if
05085        if (verbosity > 1) then
05086           write(*,'(a,a)') SSHT_PROMPT, &
05087                'Using routine ssht_core_mw_forward_sov_conv...'
05088        end if
05089     end if
05090 
05091     ! Compute Fourier transform over phi, i.e. compute Fmt.
05092     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, Fmt(-(L-1):L-1,0), &
05093          Fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
05094     do t = 0, L-1
05095        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
05096        Fmt(0:L-1,t) = tmp(0:L-1)
05097        Fmt(-(L-1):-1,t) = tmp(L:2*L-2)
05098     end do
05099     Fmt(-(L-1):L-1, 0:L-1) = Fmt(-(L-1):L-1, 0:L-1) / (2d0*L-1d0)
05100 
05101     ! Extend Fmt periodically.
05102     do m = -(L-1), L-1
05103        Fmt(m, L:2*L-2) = (-1)**(m+spin) * Fmt(m, L-2:0:-1)
05104     end do
05105 
05106     ! Compute Fourier transform over theta, i.e. compute Fmm.
05107     do m = -(L-1), L-1
05108        call dfftw_execute_dft(fftw_plan, Fmt(m,0:2*L-2), tmp(0:2*L-2))
05109        Fmm(m,0:L-1) = tmp(0:L-1)
05110        Fmm(m,-(L-1):-1) = tmp(L:2*L-2)
05111     end do
05112     Fmm(-(L-1):L-1, -(L-1):L-1) = Fmm(-(L-1):L-1, -(L-1):L-1) / (2d0*L-1d0)
05113     call dfftw_destroy_plan(fftw_plan)
05114 
05115     ! Apply phase modulation to account for sampling offset.
05116     do mm = -(L-1), L-1
05117        Fmm(-(L-1):L-1,mm) = Fmm(-(L-1):L-1, mm) * exp(-I*mm*PI/(2d0*L - 1d0))
05118     end do
05119 
05120     ! Compute weights.
05121     do mm = -2*(L-1), 2*(L-1)
05122        w(mm) = ssht_sampling_weight_mw(mm)
05123     end do
05124 
05125     ! Compute IFFT of w to give wr.
05126     wr(1:2*(L-1)) = w(-2*(L-1):-1)
05127     wr(-2*(L-1):0) = w(0:2*(L-1))
05128     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
05129     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
05130          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
05131     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
05132     wr(0:2*(L-1)) = w(-2*(L-1):0)
05133     wr(-2*(L-1):-1) = w(1:2*(L-1))
05134 
05135     ! Plan forward FFT.
05136     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
05137          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
05138 
05139     ! Compute Gmm by convolution implemented as product in real space.
05140     do m = -(L-1), L-1
05141 
05142        ! Zero-pad Fmm.
05143        Fmm_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
05144        Fmm_pad(-(L-1):L-1) = Fmm(m,-(L-1):L-1)
05145        Fmm_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
05146        
05147        ! Compute IFFT of Fmm.
05148        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05149        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05150        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05151        call dfftw_execute_dft(fftw_plan_bwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05152             Fmm_pad(-2*(L-1):2*(L-1)))
05153        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05154        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05155        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05156 
05157        ! Compute product of Fmm and weight in real space.
05158        do r = -2*(L-1), 2*(L-1)
05159           Fmm_pad(r) = Fmm_pad(r) * wr(-r)
05160        end do
05161 
05162        ! Compute Gmm by FFT.
05163        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05164        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05165        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05166        call dfftw_execute_dft(fftw_plan_fwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05167             Fmm_pad(-2*(L-1):2*(L-1)))
05168        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05169        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05170        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05171 
05172        ! Extract section of Gmm of interest.
05173        Gmm(m,-(L-1):(L-1)) = Fmm_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
05174 
05175     end do
05176     call dfftw_destroy_plan(fftw_plan_bwd)
05177     call dfftw_destroy_plan(fftw_plan_fwd)   
05178 
05179     ! Compute flm.
05180     flm(0::L**2-1) = cmplx(0d0, 0d0)
05181     do el = abs(spin), L-1
05182        call ssht_dl_beta_operator(dl(-el:el,-el:el), PION2, el)
05183        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
05184        do m = -el, el
05185           call ssht_sampling_elm2ind(ind, el, m)
05186           do mm = -el, el             
05187              flm(ind) = flm(ind) + &
05188                   (-1)**spin * elfactor &
05189                   * exp(I*PION2*(m+spin)) &
05190                   * dl(mm,m) * dl(mm,-spin) &
05191                   * Gmm(m,mm)
05192           end do
05193        end do
05194     end do
05195 
05196     ! Print finished if verbosity set.
05197     if (present(verbosity)) then
05198        if (verbosity > 0) then
05199           write(*,'(a,a)') SSHT_PROMPT, &
05200                'Forward transform computed!'
05201        end if
05202     end if
05203 
05204   end subroutine ssht_core_mw_forward_sov_conv
05205 
05206 
05207   !----------------------------------------------------------------------------
05208   ! ssht_core_mw_forward_sov_conv_sym
05209   !
05227 
05228   subroutine ssht_core_mw_forward_sov_conv_sym(flm, f, L, spin, verbosity)
05229 
05230     integer, intent(in) :: L
05231     integer, intent(in) :: spin
05232     integer, intent(in), optional :: verbosity
05233     complex(dpc), intent(in) :: f(0:L-1 ,0:2*L-2)
05234     complex(dpc), intent(out) :: flm(0:L**2-1)
05235 
05236     integer :: p, m, t, mm, el, ind, k
05237     real(dp) :: theta, phi
05238     real(dp) :: elfactor
05239 
05240     real(dp) :: dl(0:L-1, -(L-1):L-1)
05241     complex(dpc) :: Fmt(-(L-1):L-1, 0:2*L-2)
05242     complex(dpc) :: Fmm(-(L-1):L-1, -(L-1):L-1)
05243     complex(dpc) :: Gmm(-(L-1):L-1, -(L-1):L-1) 
05244     integer*8 :: fftw_plan
05245     complex(dpc) :: tmp(0:2*L-2)
05246 
05247     integer :: r
05248     complex(dpc) :: Fmm_pad(-2*(L-1):2*(L-1))
05249     complex(dpc) :: tmp_pad(-2*(L-1):2*(L-1))
05250     complex(dpc) :: w(-2*(L-1):2*(L-1))
05251     complex(dpc) :: wr(-2*(L-1):2*(L-1))
05252     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
05253     character(len=STRING_LEN) :: format_spec
05254 
05255     real(dp) :: signs(0:L), ssign
05256     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
05257     integer :: eltmp
05258 
05259     ! Perform precomputations.
05260     do el = 0, 2*(L-1) + 1
05261        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
05262     end do
05263     do m = 0, L-1, 2
05264        signs(m)   =  1.0_dp
05265        signs(m+1) = -1.0_dp
05266     enddo
05267 
05268     ! Set spin sign.
05269     ssign = signs(abs(spin))
05270 
05271     ! Print messages depending on verbosity level.
05272     if (present(verbosity)) then
05273        if (verbosity > 0) then
05274           write(*,'(a,a,a)') SSHT_PROMPT, &
05275                'Computing forward transform using McEwen and Wiaux', &
05276                ' sampling with'
05277           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
05278                digit(spin),',a)'
05279           write(*,trim(format_spec)) SSHT_PROMPT, &
05280                'parameters (L,spin,reality) = (', &
05281                L, ',', spin, ',FALSE)...'
05282        end if
05283        if (verbosity > 1) then
05284           write(*,'(a,a)') SSHT_PROMPT, &
05285                'Using routine ssht_core_mw_forward_sov_conv_sym...'
05286        end if
05287     end if
05288 
05289     ! Compute Fourier transform over phi, i.e. compute Fmt.
05290     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, Fmt(-(L-1):L-1,0), &
05291          Fmt(-(L-1):L-1,0), FFTW_FORWARD, FFTW_MEASURE)
05292     do t = 0, L-1
05293        call dfftw_execute_dft(fftw_plan, f(t,0:2*L-2), tmp(0:2*L-2))
05294        Fmt(0:L-1,t) = tmp(0:L-1)
05295        Fmt(-(L-1):-1,t) = tmp(L:2*L-2)
05296     end do
05297     Fmt(-(L-1):L-1, 0:L-1) = Fmt(-(L-1):L-1, 0:L-1) / (2d0*L-1d0)
05298 
05299     ! Extend Fmt periodically.
05300     do m = -(L-1), L-1
05301        Fmt(m, L:2*L-2) = signs(abs(m)) * ssign * Fmt(m, L-2:0:-1)
05302     end do
05303 
05304     ! Compute Fourier transform over theta, i.e. compute Fmm.
05305     do m = -(L-1), L-1
05306        call dfftw_execute_dft(fftw_plan, Fmt(m,0:2*L-2), tmp(0:2*L-2))
05307        Fmm(m,0:L-1) = tmp(0:L-1)
05308        Fmm(m,-(L-1):-1) = tmp(L:2*L-2)
05309     end do
05310     Fmm(-(L-1):L-1, -(L-1):L-1) = Fmm(-(L-1):L-1, -(L-1):L-1) / (2d0*L-1d0)
05311     call dfftw_destroy_plan(fftw_plan)
05312 
05313     ! Apply phase modulation to account for sampling offset.
05314     do mm = -(L-1), L-1
05315        Fmm(-(L-1):L-1,mm) = Fmm(-(L-1):L-1, mm) * exp(-I*mm*PI/(2d0*L - 1d0))
05316     end do
05317 
05318     ! Compute weights.
05319     do mm = -2*(L-1), 2*(L-1)
05320        w(mm) = ssht_sampling_weight_mw(mm)
05321     end do
05322 
05323     ! Compute IFFT of w to give wr.
05324     wr(1:2*(L-1)) = w(-2*(L-1):-1)
05325     wr(-2*(L-1):0) = w(0:2*(L-1))
05326     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
05327     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
05328          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
05329     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
05330     wr(0:2*(L-1)) = w(-2*(L-1):0)
05331     wr(-2*(L-1):-1) = w(1:2*(L-1))
05332 
05333     ! Plan forward FFT.
05334     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
05335          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
05336 
05337     ! Compute Gmm by convolution implemented as product in real space.
05338     do m = -(L-1), L-1
05339 
05340        ! Zero-pad Fmm.
05341        Fmm_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
05342        Fmm_pad(-(L-1):L-1) = Fmm(m,-(L-1):L-1)
05343        Fmm_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
05344        
05345        ! Compute IFFT of Fmm.
05346        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05347        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05348        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05349        call dfftw_execute_dft(fftw_plan_bwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05350             Fmm_pad(-2*(L-1):2*(L-1)))
05351        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05352        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05353        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05354 
05355        ! Compute product of Fmm and weight in real space.
05356        do r = -2*(L-1), 2*(L-1)
05357           Fmm_pad(r) = Fmm_pad(r) * wr(-r)
05358        end do
05359 
05360        ! Compute Gmm by FFT.
05361        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05362        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05363        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05364        call dfftw_execute_dft(fftw_plan_fwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05365             Fmm_pad(-2*(L-1):2*(L-1)))
05366        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05367        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05368        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05369 
05370        ! Extract section of Gmm of interest.
05371        Gmm(m,-(L-1):(L-1)) = Fmm_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
05372 
05373     end do
05374     call dfftw_destroy_plan(fftw_plan_bwd)
05375     call dfftw_destroy_plan(fftw_plan_fwd)   
05376 
05377     ! Compute flm.
05378     flm(0::L**2-1) = cmplx(0d0, 0d0)
05379     do el = abs(spin), L-1
05380        if (el /= 0 .and. el == abs(spin)) then
05381           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
05382           do eltmp = 0, abs(spin)
05383              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
05384                   sqrt_tbl(0:2*eltmp+1))
05385           end do
05386           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
05387                el, signs(0:el))
05388        else
05389           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
05390                sqrt_tbl(0:2*el+1))
05391           call ssht_dl_halfpi_trapani_fill_eighth2righthalf_table(dl(0:el,-el:el), &
05392                el, signs(0:el))
05393        end if
05394 
05395        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
05396        do m = -el, el
05397           call ssht_sampling_elm2ind(ind, el, m)
05398 
05399           flm(ind) = flm(ind) + &
05400                ssign * elfactor &
05401                * exp(I*PION2*(m+spin)) &
05402                * dl(0,m) * dl(0,-spin) &
05403                * Gmm(m,0)
05404 
05405           do mm = 1, el             
05406              flm(ind) = flm(ind) + &
05407                   ssign * elfactor &
05408                   * exp(I*PION2*(m+spin)) &
05409                   * dl(mm,m) * dl(mm,-spin) &
05410                   * (Gmm(m,mm) + signs(abs(m)) * ssign * Gmm(m,-mm))
05411           end do
05412        end do
05413     end do
05414 
05415     ! Print finished if verbosity set.
05416     if (present(verbosity)) then
05417        if (verbosity > 0) then
05418           write(*,'(a,a)') SSHT_PROMPT, &
05419                'Forward transform computed!'
05420        end if
05421     end if
05422 
05423   end subroutine ssht_core_mw_forward_sov_conv_sym
05424 
05425 
05426   !----------------------------------------------------------------------------
05427   ! ssht_core_mw_forward_sov_conv_sym_real
05428   !
05447 
05448   subroutine ssht_core_mw_forward_sov_conv_sym_real(flm, f, L, verbosity)
05449 
05450     integer, intent(in) :: L
05451     integer, intent(in), optional :: verbosity
05452     real(dp), intent(in) :: f(0:L-1 ,0:2*L-2)
05453     complex(dpc), intent(out) :: flm(0:L**2-1)
05454 
05455     integer :: p, m, t, mm, el, ind, k
05456     real(dp) :: theta, phi
05457     real(dp) :: elfactor
05458 
05459     real(dp) :: dl(0:L-1, 0:L-1)
05460     complex(dpc) :: Fmt(0:L-1, 0:2*L-2)
05461     complex(dpc) :: Fmm(0:L-1, -(L-1):L-1)
05462     complex(dpc) :: Gmm(0:L-1, -(L-1):L-1) 
05463     integer*8 :: fftw_plan
05464     complex(dpc) :: tmp(0:2*L-2)
05465 
05466     integer :: r
05467     complex(dpc) :: Fmm_pad(-2*(L-1):2*(L-1))
05468     complex(dpc) :: tmp_pad(-2*(L-1):2*(L-1))
05469     complex(dpc) :: w(-2*(L-1):2*(L-1))
05470     complex(dpc) :: wr(-2*(L-1):2*(L-1))
05471     integer*8 :: fftw_plan_fwd, fftw_plan_bwd
05472 
05473     real(dp) :: tmpr(0:2*L-2)
05474     integer :: ind_nm
05475     integer :: spin
05476     character(len=STRING_LEN) :: format_spec
05477 
05478     real(dp) :: signs(0:L), ssign
05479     real(dp) :: dl_mm_spin, dl_0_spin
05480     real(dp) :: sqrt_tbl(0:2*(L-1)+1)
05481     integer :: eltmp
05482 
05483     ! Perform precomputations.
05484     do el = 0, 2*(L-1) + 1
05485        sqrt_tbl(el) = dsqrt(real(el,kind=dp))
05486     end do
05487     do m = 0, L-1, 2
05488        signs(m)   =  1.0_dp
05489        signs(m+1) = -1.0_dp
05490     enddo
05491 
05492     ! Set spin to zero.
05493     spin = 0
05494     ssign = signs(abs(spin))
05495 
05496     ! Print messages depending on verbosity level.
05497     if (present(verbosity)) then
05498        if (verbosity > 0) then
05499           write(*,'(a,a,a)') SSHT_PROMPT, &
05500                'Computing forward transform using McEwen and Wiaux', &
05501                ' sampling with'
05502           write(format_spec,'(a,i20,a,i20,a)') '(a,a,i', digit(L),',a,i', &
05503                digit(spin),',a)'
05504           write(*,trim(format_spec)) SSHT_PROMPT, &
05505                'parameters (L,spin,reality) = (', &
05506                L, ',', spin, ',TRUE)...'
05507        end if
05508        if (verbosity > 1) then
05509           write(*,'(a,a)') SSHT_PROMPT, &
05510                'Using routine ssht_core_mw_forward_sov_conv_sym_real...'
05511        end if
05512     end if
05513 
05514     ! Compute Fourier transform over phi, i.e. compute Fmt.
05515     call dfftw_plan_dft_r2c_1d(fftw_plan, 2*L-1, tmpr(0:2*L-2), &
05516          Fmt(0:L-1,0), FFTW_MEASURE)
05517     do t = 0, L-1             
05518        call dfftw_execute_dft_r2c(fftw_plan, f(t,0:2*L-2), tmp(0:L-1))
05519        Fmt(0:L-1,t) = tmp(0:L-1)
05520     end do
05521     call dfftw_destroy_plan(fftw_plan)
05522     Fmt(0:L-1, 0:L-1) = Fmt(0:L-1, 0:L-1) / (2d0*L-1d0)
05523 
05524     ! Extend Fmt periodically.
05525 !!$    do m = 0, L-1
05526 !!$       Fmt(m, L:2*L-2) = (-1)**(m+spin) * Fmt(m, L-2:0:-1)
05527 !!$    end do
05528     do t = L, 2*L-2
05529        Fmt(0:L-1, t) = ssign * signs(0:L-1) * Fmt(0:L-1, 2*L-2-t)
05530     end do
05531 
05532     ! Compute Fourier transform over theta, i.e. compute Fmm.
05533     call dfftw_plan_dft_1d(fftw_plan, 2*L-1, tmp(0:2*L-2), &
05534          tmp(0:2*L-2), FFTW_FORWARD, FFTW_MEASURE)
05535     do m = 0, L-1
05536        call dfftw_execute_dft(fftw_plan, Fmt(m,0:2*L-2), tmp(0:2*L-2))
05537        Fmm(m,0:L-1) = tmp(0:L-1)
05538        Fmm(m,-(L-1):-1) = tmp(L:2*L-2)
05539     end do
05540     Fmm(0:L-1, -(L-1):L-1) = Fmm(0:L-1, -(L-1):L-1) / (2d0*L-1d0)
05541     call dfftw_destroy_plan(fftw_plan)
05542 
05543     ! Apply phase modulation to account for sampling offset.
05544     do mm = -(L-1), L-1
05545        Fmm(0:L-1,mm) = Fmm(0:L-1, mm) * exp(-I*mm*PI/(2d0*L - 1d0))
05546     end do
05547 
05548     ! Compute weights.
05549     do mm = -2*(L-1), 2*(L-1)
05550        w(mm) = ssht_sampling_weight_mw(mm)
05551     end do
05552 
05553     ! Compute IFFT of w to give wr.
05554     wr(1:2*(L-1)) = w(-2*(L-1):-1)
05555     wr(-2*(L-1):0) = w(0:2*(L-1))
05556     w(-2*(L-1):2*(L-1)) = wr(-2*(L-1):2*(L-1))
05557     call dfftw_plan_dft_1d(fftw_plan_bwd, 4*L-3, wr(-2*(L-1):2*(L-1)), &
05558          wr(-2*(L-1):2*(L-1)), FFTW_BACKWARD, FFTW_MEASURE)
05559     call dfftw_execute_dft(fftw_plan_bwd, w(-2*(L-1):2*(L-1)), w(-2*(L-1):2*(L-1)))
05560     wr(0:2*(L-1)) = w(-2*(L-1):0)
05561     wr(-2*(L-1):-1) = w(1:2*(L-1))
05562 
05563     ! Plan forward FFT.
05564     call dfftw_plan_dft_1d(fftw_plan_fwd, 4*L-3, w(-2*(L-1):2*(L-1)), &
05565          w(-2*(L-1):2*(L-1)), FFTW_FORWARD, FFTW_MEASURE)
05566 
05567     ! Compute Gmm by convolution implemented as product in real space.
05568     do m = 0, L-1
05569 
05570        ! Zero-pad Fmm.
05571        Fmm_pad(-2*(L-1):-L) = cmplx(0d0, 0d0)
05572        Fmm_pad(-(L-1):L-1) = Fmm(m,-(L-1):L-1)
05573        Fmm_pad(L:2*(L-1)) = cmplx(0d0, 0d0)
05574        
05575        ! Compute IFFT of Fmm.
05576        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05577        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05578        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05579        call dfftw_execute_dft(fftw_plan_bwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05580             Fmm_pad(-2*(L-1):2*(L-1)))
05581        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05582        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05583        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05584 
05585        ! Compute product of Fmm and weight in real space.
05586 !!$       do r = -2*(L-1), 2*(L-1)
05587 !!$          Fmm_pad(r) = Fmm_pad(r) * wr(-r)
05588 !!$       end do
05589        Fmm_pad(-2*(L-1):2*(L-1)) = Fmm_pad(-2*(L-1):2*(L-1)) * wr(2*(L-1):-2*(L-1):-1)
05590 
05591        ! Compute Gmm by FFT.
05592        tmp_pad(1:2*(L-1)) = Fmm_pad(-2*(L-1):-1)
05593        tmp_pad(-2*(L-1):0) = Fmm_pad(0:2*(L-1))
05594        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05595        call dfftw_execute_dft(fftw_plan_fwd, Fmm_pad(-2*(L-1):2*(L-1)), &
05596             Fmm_pad(-2*(L-1):2*(L-1)))
05597        tmp_pad(0:2*(L-1)) = Fmm_pad(-2*(L-1):0)
05598        tmp_pad(-2*(L-1):-1) = Fmm_pad(1:2*(L-1))
05599        Fmm_pad(-2*(L-1):2*(L-1)) = tmp_pad(-2*(L-1):2*(L-1))
05600 
05601        ! Extract section of Gmm of interest.
05602        Gmm(m,-(L-1):(L-1)) = Fmm_pad(-(L-1):(L-1)) * 2d0 * PI / (4d0*L-3d0)
05603 
05604     end do
05605     call dfftw_destroy_plan(fftw_plan_bwd)
05606     call dfftw_destroy_plan(fftw_plan_fwd)   
05607 
05608     ! Compute flm.
05609     flm(0::L**2-1) = cmplx(0d0, 0d0)
05610     do el = abs(spin), L-1
05611        if (el /= 0 .and. el == abs(spin)) then
05612           ! Recurse Wigner plane from 0 up to first el, i.e. abs(spin).
05613           do eltmp = 0, abs(spin)
05614              call ssht_dl_halfpi_trapani_eighth_table(dl(0:eltmp,0:eltmp), eltmp, &
05615                   sqrt_tbl(0:2*eltmp+1))
05616           end do
05617           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
05618                el, signs(0:el))
05619        else
05620           call ssht_dl_halfpi_trapani_eighth_table(dl(0:el,0:el), el, &
05621                sqrt_tbl(0:2*el+1))
05622           call ssht_dl_halfpi_trapani_fill_eighth2quarter_table(dl(0:el,0:el), &
05623                el, signs(0:el))
05624        end if
05625 
05626        elfactor = sqrt((2d0*el+1d0)/(4d0*PI))
05627        do m = 0, el
05628           call ssht_sampling_elm2ind(ind, el, m)
05629 
05630           if (spin <= 0) then
05631              dl_0_spin = dl(0,-spin)
05632           else
05633              dl_0_spin = signs(el) * dl(0,spin)
05634           end if
05635           
05636           flm(ind) = flm(ind) + &
05637                ssign * elfactor &
05638                * exp(I*PION2*(m+spin)) &
05639 !               * dl(0,m) * dl(0,-spin) &
05640                * dl(0,m) * dl_0_spin &
05641                * Gmm(m,0)
05642 
05643           do mm = 1, el 
05644 
05645              if (spin <= 0) then
05646                 dl_mm_spin = dl(mm,-spin)
05647              else
05648                 dl_mm_spin = signs(el) * signs(mm) * dl(mm,spin)
05649              end if
05650             
05651              flm(ind) = flm(ind) + &
05652                   ssign * elfactor &
05653                   * exp(I*PION2*(m+spin)) &
05654 !!$                  * dl(mm,m) * dl(mm,-spin) &
05655                   * dl(mm,m) * dl_mm_spin &
05656                   * (Gmm(m,mm) + ssign * signs(m) * Gmm(m,-mm))
05657           end do
05658        end do
05659     end do
05660 
05661     ! Set flm values for negative m using conjugate symmetry.
05662     do el = abs(spin), L-1
05663        do m = 1, el
05664           call ssht_sampling_elm2ind(ind, el, m)
05665           call ssht_sampling_elm2ind(ind_nm, el, -m)
05666           flm(ind_nm) = signs(m) * conjg(flm(ind))
05667        end do
05668     end do
05669 
05670     ! Print finished if verbosity set.
05671     if (present(verbosity)) then
05672        if (verbosity > 0) then
05673           write(*,'(a,a)') SSHT_PROMPT, &
05674                'Forward transform computed!'
05675        end if
05676     end if
05677 
05678   end subroutine ssht_core_mw_forward_sov_conv_sym_real
05679 
05680 
05681 
05682   !--------------------------------------------------------------------------
05683   ! Utility routines
05684   !--------------------------------------------------------------------------
05685 
05686 
05687   !----------------------------------------------------------------------------
05688   ! digit
05689   !
05702 
05703   function digit(L) result(d)
05704 
05705     integer, intent(in) :: L
05706     integer :: d
05707 
05708     if(L/10 < 1) then
05709        d = 1
05710     elseif(L/100 < 1) then
05711        d = 2
05712     elseif(L/1000 < 1) then
05713        d = 3
05714     elseif(L/10000 < 1) then
05715        d = 4
05716     elseif(L/100000 < 1) then
05717        d = 5
05718     else
05719        d = 25
05720     end if
05721  
05722   end function digit
05723 
05724 
05725 end module ssht_core_mod
Generated on Mon Oct 31 01:20:05 2011 by  doxygen 1.6.3