CONVERGENCE_MAIN Program

Uses

  • program~~convergence_main~~UsesGraph program~convergence_main CONVERGENCE_MAIN module~globals GLOBALS program~convergence_main->module~globals module~kinds KINDS program~convergence_main->module~kinds module~tests TESTS program~convergence_main->module~tests module~vsh VSH program~convergence_main->module~vsh module~globals->module~kinds module~tests->module~globals module~tests->module~kinds module~tests->module~vsh module~vsh->module~globals module~vsh->module~kinds

Driver for the convergence-vs-degree accuracy sweep (opt-in VSH_BUILD_CONVERGENCE CMake target, not part of ctest): calls the same TESTS batch-consistency routines the core ctest gate uses (BATCH_ALM_CONS, BATCH_SSH_CONS, BATCH_VSH_TOR_CONS, BATCH_VSH_POL_UP_CONS, BATCH_VSH_POL_DN_CONS), but at instead of the small, fixed values main.f90 uses to gate correctness. Each routine already loops internally over every degree in one call, so this produces dense per-degree error data up to 300 without needing an outer sweep here.

Deliberately does not check the STATUS each routine returns: batch-vs-single error legitimately grows with (that's the point of the resulting figure), so failing a 1e-12-style tolerance at high is expected, not a regression. Writes to ./convergence/*.dat -- a directory kept separate from ./validation/*.dat specifically so this sweep can never interact with VSH_REGRESSION_TEST's comparison against validation/reference/. Consumed by py/plot_convergence.py for the manuscript's convergence figure.


Calls

program~~convergence_main~~CallsGraph program~convergence_main CONVERGENCE_MAIN dimag dimag program~convergence_main->dimag interface~assoc_legendre ASSOC_LEGENDRE program~convergence_main->interface~assoc_legendre interface~assoc_legendre_all ASSOC_LEGENDRE_ALL program~convergence_main->interface~assoc_legendre_all interface~assoc_legendre_norm_all ASSOC_LEGENDRE_NORM_ALL program~convergence_main->interface~assoc_legendre_norm_all interface~ssh SSH program~convergence_main->interface~ssh interface~ssh_all SSH_ALL program~convergence_main->interface~ssh_all interface~vsh_pol_dn VSH_POL_DN program~convergence_main->interface~vsh_pol_dn interface~vsh_pol_dn_all VSH_POL_DN_ALL program~convergence_main->interface~vsh_pol_dn_all interface~vsh_pol_up VSH_POL_UP program~convergence_main->interface~vsh_pol_up interface~vsh_pol_up_all VSH_POL_UP_ALL program~convergence_main->interface~vsh_pol_up_all interface~vsh_tor VSH_TOR program~convergence_main->interface~vsh_tor interface~vsh_tor_all VSH_TOR_ALL program~convergence_main->interface~vsh_tor_all proc~batch_alm_cons BATCH_ALM_CONS program~convergence_main->proc~batch_alm_cons proc~batch_ssh_cons BATCH_SSH_CONS program~convergence_main->proc~batch_ssh_cons proc~batch_vsh_pol_dn_cons BATCH_VSH_POL_DN_CONS program~convergence_main->proc~batch_vsh_pol_dn_cons proc~batch_vsh_pol_up_cons BATCH_VSH_POL_UP_CONS program~convergence_main->proc~batch_vsh_pol_up_cons proc~batch_vsh_tor_cons BATCH_VSH_TOR_CONS program~convergence_main->proc~batch_vsh_tor_cons proc~plm_index PLM_INDEX program~convergence_main->proc~plm_index proc~ylm_index YLM_INDEX program~convergence_main->proc~ylm_index proc~assoc_legendre_dp ASSOC_LEGENDRE_DP interface~assoc_legendre->proc~assoc_legendre_dp proc~assoc_legendre_all_dp ASSOC_LEGENDRE_ALL_DP interface~assoc_legendre_all->proc~assoc_legendre_all_dp proc~assoc_legendre_norm_all_dp ASSOC_LEGENDRE_NORM_ALL_DP interface~assoc_legendre_norm_all->proc~assoc_legendre_norm_all_dp proc~ssh_dp SSH_DP interface~ssh->proc~ssh_dp proc~ssh_all_dp SSH_ALL_DP interface~ssh_all->proc~ssh_all_dp proc~vsh_pol_dn_dp VSH_POL_DN_DP interface~vsh_pol_dn->proc~vsh_pol_dn_dp proc~vsh_pol_dn_all_dp VSH_POL_DN_ALL_DP interface~vsh_pol_dn_all->proc~vsh_pol_dn_all_dp proc~vsh_pol_up_dp VSH_POL_UP_DP interface~vsh_pol_up->proc~vsh_pol_up_dp proc~vsh_pol_up_all_dp VSH_POL_UP_ALL_DP interface~vsh_pol_up_all->proc~vsh_pol_up_all_dp proc~vsh_tor_dp VSH_TOR_DP interface~vsh_tor->proc~vsh_tor_dp proc~vsh_tor_all_dp VSH_TOR_ALL_DP interface~vsh_tor_all->proc~vsh_tor_all_dp proc~batch_alm_cons->interface~assoc_legendre proc~batch_alm_cons->interface~assoc_legendre_all proc~batch_alm_cons->proc~plm_index proc~batch_ssh_cons->dimag proc~batch_ssh_cons->interface~ssh proc~batch_ssh_cons->interface~ssh_all proc~batch_ssh_cons->proc~ylm_index proc~batch_vsh_pol_dn_cons->interface~vsh_pol_dn proc~batch_vsh_pol_dn_cons->interface~vsh_pol_dn_all proc~batch_vsh_pol_dn_cons->proc~ylm_index proc~batch_vsh_pol_up_cons->interface~vsh_pol_up proc~batch_vsh_pol_up_cons->interface~vsh_pol_up_all proc~batch_vsh_pol_up_cons->proc~ylm_index proc~batch_vsh_tor_cons->interface~vsh_tor proc~batch_vsh_tor_cons->interface~vsh_tor_all proc~batch_vsh_tor_cons->proc~ylm_index proc~assoc_legendre_all_dp->proc~plm_index interface~log_fact LOG_FACT proc~assoc_legendre_dp->interface~log_fact proc~assoc_legendre_norm_all_dp->proc~plm_index proc~ssh_all_dp->interface~assoc_legendre_norm_all proc~ssh_all_dp->proc~plm_index proc~ssh_all_dp->proc~ylm_index dcos dcos proc~ssh_all_dp->dcos proc~ssh_dp->interface~assoc_legendre proc~ssh_dp->dcos proc~ssh_dp->interface~log_fact proc~vsh_pol_dn_all_dp->proc~ylm_index interface~vsh_core VSH_CORE proc~vsh_pol_dn_all_dp->interface~vsh_core proc~vsh_pol_dn_dp->dcos dsin dsin proc~vsh_pol_dn_dp->dsin interface~assoc_legendre_and_deriv ASSOC_LEGENDRE_AND_DERIV proc~vsh_pol_dn_dp->interface~assoc_legendre_and_deriv proc~vsh_pol_dn_dp->interface~log_fact proc~vsh_pol_up_all_dp->proc~ylm_index proc~vsh_pol_up_all_dp->interface~vsh_core proc~vsh_pol_up_dp->dcos proc~vsh_pol_up_dp->dsin proc~vsh_pol_up_dp->interface~assoc_legendre_and_deriv proc~vsh_pol_up_dp->interface~log_fact interface~pvsh_tor_all PVSH_TOR_ALL proc~vsh_tor_all_dp->interface~pvsh_tor_all interface~pvsh_tor PVSH_TOR proc~vsh_tor_dp->interface~pvsh_tor proc~assoc_legendre_and_deriv_dp ASSOC_LEGENDRE_AND_DERIV_DP interface~assoc_legendre_and_deriv->proc~assoc_legendre_and_deriv_dp proc~log_fact_dp LOG_FACT_DP interface~log_fact->proc~log_fact_dp proc~pvsh_tor_dp PVSH_TOR_DP interface~pvsh_tor->proc~pvsh_tor_dp proc~pvsh_tor_all_dp PVSH_TOR_ALL_DP interface~pvsh_tor_all->proc~pvsh_tor_all_dp proc~vsh_core_dp VSH_CORE_DP interface~vsh_core->proc~vsh_core_dp proc~assoc_legendre_and_deriv_dp->interface~log_fact proc~pvsh_tor_all_dp->proc~ylm_index proc~pvsh_tor_all_dp->interface~vsh_core proc~pvsh_tor_dp->dcos proc~pvsh_tor_dp->dsin proc~pvsh_tor_dp->interface~assoc_legendre_and_deriv proc~pvsh_tor_dp->interface~log_fact proc~vsh_core_dp->interface~assoc_legendre_norm_all proc~vsh_core_dp->proc~plm_index proc~vsh_core_dp->proc~ylm_index proc~vsh_core_dp->dcos proc~vsh_core_dp->dsin interface~ddx_assoc_legendre_norm_all DDX_ASSOC_LEGENDRE_NORM_ALL proc~vsh_core_dp->interface~ddx_assoc_legendre_norm_all proc~ddx_assoc_legendre_norm_all_dp DDX_ASSOC_LEGENDRE_NORM_ALL_DP interface~ddx_assoc_legendre_norm_all->proc~ddx_assoc_legendre_norm_all_dp proc~ddx_assoc_legendre_norm_all_dp->proc~plm_index

Variables

Type Attributes Name Initial
complex(kind=dp), ALLOCATABLE :: DNBATCH(:,:)
integer(kind=i4) :: IL
integer(kind=i4) :: IM
integer(kind=i4) :: ITH
integer(kind=i4) :: IX
integer(kind=i4) :: L
integer(kind=i4), parameter :: LMAX = 300
integer(kind=i4) :: M
integer(kind=i4) :: MSAMP(3)
integer(kind=i4) :: NMSAMP
integer(kind=i4), parameter :: NREFL = 16
integer(kind=i4), parameter :: NTH = 15
integer(kind=i4), parameter :: NTH_REF = 5
integer(kind=i4), parameter :: NX_ALM = 20
integer(kind=i4), parameter :: NX_REF = 3
real(kind=dp), ALLOCATABLE :: PBATCH(:)
real(kind=dp), parameter :: PHI_REF = pi/4
real(kind=dp), ALLOCATABLE :: PNORMBATCH(:)
real(kind=dp) :: PSING
integer(kind=i4), parameter, DIMENSION(NREFL) :: REFL_LIST = (/1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000/)
integer(kind=i4) :: STATUS
real(kind=dp) :: TH
real(kind=dp), parameter, DIMENSION(NTH_REF) :: TH_REF_LIST = (/pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6/)
complex(kind=dp), ALLOCATABLE :: TORBATCH(:,:)
complex(kind=dp), ALLOCATABLE :: UPBATCH(:,:)
complex(kind=dp) :: VSING(3)
real(kind=dp) :: XX
real(kind=dp), parameter, DIMENSION(NX_REF) :: X_REF_LIST = (/-0.6_dp, 0.0_dp, 0.6_dp/)
complex(kind=dp), ALLOCATABLE :: YBATCH(:)
complex(kind=dp) :: YSING

Source Code

PROGRAM CONVERGENCE_MAIN
USE KINDS,  ONLY: i4, dp
USE TESTS,  ONLY: &
  BATCH_ALM_CONS, BATCH_SSH_CONS, &
  BATCH_VSH_TOR_CONS, BATCH_VSH_POL_UP_CONS, BATCH_VSH_POL_DN_CONS
USE GLOBALS, ONLY: pi
USE VSH,    ONLY: &
  PLM_INDEX, YLM_INDEX, &
  ASSOC_LEGENDRE, ASSOC_LEGENDRE_ALL, ASSOC_LEGENDRE_NORM_ALL, &
  SSH, SSH_ALL, &
  VSH_TOR, VSH_TOR_ALL, VSH_POL_UP, VSH_POL_UP_ALL, &
  VSH_POL_DN, VSH_POL_DN_ALL
IMPLICIT NONE

INTEGER(KIND=i4), PARAMETER :: LMAX = 300
INTEGER(KIND=i4), PARAMETER :: NX_ALM = 20   !- x-grid density (matches main.f90)
INTEGER(KIND=i4), PARAMETER :: NTH    = 15   !- theta-grid density (matches main.f90)
INTEGER(KIND=i4) :: STATUS

!- Sparse sample grid for the independent-reference accuracy check (see
!- py/mpmath_reference.py): matches bench_main.f90's LMAX_LIST so this
!- figure and benchmark_scaling share the same x-axis sample points. Writes
!- RAW single-mode and batch values here (not diffs -- unlike the dense
!- sweep above) since py/plot_convergence.py diffs each independently
!- against an arbitrary-precision mpmath reference rather than against
!- each other.
INTEGER(KIND=i4), PARAMETER :: NREFL = 16
INTEGER(KIND=i4), DIMENSION(NREFL), PARAMETER :: &
  REFL_LIST = (/1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 1500, 2000, &
                2500, 3000, 3500, 4000/)
INTEGER(KIND=i4), PARAMETER :: NX_REF = 3
REAL(KIND=dp), DIMENSION(NX_REF), PARAMETER :: &
  X_REF_LIST = (/-0.6_dp, 0.0_dp, 0.6_dp/)
INTEGER(KIND=i4), PARAMETER :: NTH_REF = 5
REAL(KIND=dp), DIMENSION(NTH_REF), PARAMETER :: &
  TH_REF_LIST = (/pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6/)
REAL(KIND=dp), PARAMETER :: PHI_REF = pi/4
INTEGER(KIND=i4) :: L, M, IL, IX, ITH, IM, NMSAMP, MSAMP(3)
REAL(KIND=dp) :: XX, TH, PSING
COMPLEX(KIND=dp) :: YSING, VSING(3)
REAL(KIND=dp), ALLOCATABLE :: PBATCH(:), PNORMBATCH(:)
COMPLEX(KIND=dp), ALLOCATABLE :: YBATCH(:), TORBATCH(:,:), UPBATCH(:,:), DNBATCH(:,:)

WRITE(*,'(A,I0,A)') "Sweeping batch-consistency error up to Lmax=", LMAX, "..."

OPEN(UNIT=11, FILE="./convergence/batch_alm_cons.dat")
CALL BATCH_ALM_CONS(LMAX, NX_ALM, 11, STATUS)
CLOSE(11)
WRITE(*,'(A)') "  Legendre done"

OPEN(UNIT=12, FILE="./convergence/batch_ssh_cons.dat")
CALL BATCH_SSH_CONS(LMAX, NTH, 12, STATUS)
CLOSE(12)
WRITE(*,'(A)') "  SSH done"

OPEN(UNIT=13, FILE="./convergence/batch_vsh_tor_cons.dat")
CALL BATCH_VSH_TOR_CONS(LMAX, NTH, 13, STATUS)
CLOSE(13)
WRITE(*,'(A)') "  VSH toroidal done"

OPEN(UNIT=14, FILE="./convergence/batch_vsh_pol_up_cons.dat")
CALL BATCH_VSH_POL_UP_CONS(LMAX, NTH, 14, STATUS)
CLOSE(14)
WRITE(*,'(A)') "  VSH poloidal (up) done"

OPEN(UNIT=15, FILE="./convergence/batch_vsh_pol_dn_cons.dat")
CALL BATCH_VSH_POL_DN_CONS(LMAX, NTH, 15, STATUS)
CLOSE(15)
WRITE(*,'(A)') "  VSH poloidal (dn) done"

WRITE(*,'(A)') "RESULT: convergence sweep complete - see ./convergence/*.dat"

WRITE(*,'(A)') "Sampling single-mode/batch values for independent-reference check..."

OPEN(UNIT=21, FILE="./convergence/reference_alm.dat")
WRITE(21,'(A)') &
    '# L  M  X  P_single  P_batch  P_batch_norm'// &
    '  -- P_single/P_batch are unnormalized (ASSOC_LEGENDRE/_ALL);'// &
    ' P_batch_norm is ASSOC_LEGENDRE_NORM_ALL (no single-mode normalized'// &
    ' counterpart exists) -- see py/mpmath_reference.py legendre_norm_ref'
OPEN(UNIT=22, FILE="./convergence/reference_ssh.dat")
WRITE(22,'(A)') '# L  M  THETA  PHI  single_re  single_im  batch_re  batch_im'
OPEN(UNIT=23, FILE="./convergence/reference_vsh_tor.dat")
WRITE(23,'(A)') '# L  M  THETA  PHI'// &
    '  single_r_re single_r_im single_th_re single_th_im single_ph_re single_ph_im'// &
    '  batch_r_re batch_r_im batch_th_re batch_th_im batch_ph_re batch_ph_im'
OPEN(UNIT=24, FILE="./convergence/reference_vsh_pol_up.dat")
WRITE(24,'(A)') '# L  M  THETA  PHI'// &
    '  single_r_re single_r_im single_th_re single_th_im single_ph_re single_ph_im'// &
    '  batch_r_re batch_r_im batch_th_re batch_th_im batch_ph_re batch_ph_im'
OPEN(UNIT=25, FILE="./convergence/reference_vsh_pol_dn.dat")
WRITE(25,'(A)') '# L  M  THETA  PHI'// &
    '  single_r_re single_r_im single_th_re single_th_im single_ph_re single_ph_im'// &
    '  batch_r_re batch_r_im batch_th_re batch_th_im batch_ph_re batch_ph_im'

DO IL = 1, NREFL
  L = REFL_LIST(IL)

  !- dedup M samples {0, L/2, L}
  MSAMP(1) = 0
  MSAMP(2) = L/2
  MSAMP(3) = L
  NMSAMP = 1
  DO IM = 2, 3
    IF (MSAMP(IM) /= MSAMP(NMSAMP)) THEN
      NMSAMP = NMSAMP + 1
      MSAMP(NMSAMP) = MSAMP(IM)
    END IF
  END DO

  !- Legendre
  DO IX = 1, NX_REF
    XX = X_REF_LIST(IX)
    ALLOCATE(PBATCH((L+1)*(L+2)/2))
    ALLOCATE(PNORMBATCH((L+1)*(L+2)/2))
    CALL ASSOC_LEGENDRE_ALL(PBATCH, L, XX)
    CALL ASSOC_LEGENDRE_NORM_ALL(PNORMBATCH, L, XX)
    DO IM = 1, NMSAMP
      M = MSAMP(IM)
      PSING = ASSOC_LEGENDRE(L, M, XX)
      WRITE(21, *) L, M, XX, PSING, PBATCH(PLM_INDEX(L, M)), &
          PNORMBATCH(PLM_INDEX(L, M))
    END DO
    DEALLOCATE(PBATCH)
    DEALLOCATE(PNORMBATCH)
  END DO

  !- SSH, VSH toroidal, VSH poloidal (up/dn) share one THETA loop -- their
  !- batch calls are all keyed off the same (L, THETA, PHI_REF)
  DO ITH = 1, NTH_REF
    TH = TH_REF_LIST(ITH)
    ALLOCATE(YBATCH((L+1)**2))
    ALLOCATE(TORBATCH(3, (L+1)**2))
    ALLOCATE(UPBATCH(3, (L+1)**2))
    ALLOCATE(DNBATCH(3, (L+1)**2))
    CALL SSH_ALL(YBATCH, L, TH, PHI_REF)
    CALL VSH_TOR_ALL(TORBATCH, L, TH, PHI_REF)
    CALL VSH_POL_UP_ALL(UPBATCH, L, TH, PHI_REF)
    CALL VSH_POL_DN_ALL(DNBATCH, L, TH, PHI_REF)

    DO IM = 1, NMSAMP
      M = MSAMP(IM)

      YSING = SSH(L, M, TH, PHI_REF)
      WRITE(22, *) L, M, TH, PHI_REF, &
          DREAL(YSING), DIMAG(YSING), &
          DREAL(YBATCH(YLM_INDEX(L,M))), DIMAG(YBATCH(YLM_INDEX(L,M)))

      VSING = VSH_TOR(L, M, TH, PHI_REF)
      WRITE(23, *) L, M, TH, PHI_REF, &
          DREAL(VSING(1)), DIMAG(VSING(1)), &
          DREAL(VSING(2)), DIMAG(VSING(2)), &
          DREAL(VSING(3)), DIMAG(VSING(3)), &
          DREAL(TORBATCH(1,YLM_INDEX(L,M))), DIMAG(TORBATCH(1,YLM_INDEX(L,M))), &
          DREAL(TORBATCH(2,YLM_INDEX(L,M))), DIMAG(TORBATCH(2,YLM_INDEX(L,M))), &
          DREAL(TORBATCH(3,YLM_INDEX(L,M))), DIMAG(TORBATCH(3,YLM_INDEX(L,M)))

      VSING = VSH_POL_UP(L, M, TH, PHI_REF)
      WRITE(24, *) L, M, TH, PHI_REF, &
          DREAL(VSING(1)), DIMAG(VSING(1)), &
          DREAL(VSING(2)), DIMAG(VSING(2)), &
          DREAL(VSING(3)), DIMAG(VSING(3)), &
          DREAL(UPBATCH(1,YLM_INDEX(L,M))), DIMAG(UPBATCH(1,YLM_INDEX(L,M))), &
          DREAL(UPBATCH(2,YLM_INDEX(L,M))), DIMAG(UPBATCH(2,YLM_INDEX(L,M))), &
          DREAL(UPBATCH(3,YLM_INDEX(L,M))), DIMAG(UPBATCH(3,YLM_INDEX(L,M)))

      VSING = VSH_POL_DN(L, M, TH, PHI_REF)
      WRITE(25, *) L, M, TH, PHI_REF, &
          DREAL(VSING(1)), DIMAG(VSING(1)), &
          DREAL(VSING(2)), DIMAG(VSING(2)), &
          DREAL(VSING(3)), DIMAG(VSING(3)), &
          DREAL(DNBATCH(1,YLM_INDEX(L,M))), DIMAG(DNBATCH(1,YLM_INDEX(L,M))), &
          DREAL(DNBATCH(2,YLM_INDEX(L,M))), DIMAG(DNBATCH(2,YLM_INDEX(L,M))), &
          DREAL(DNBATCH(3,YLM_INDEX(L,M))), DIMAG(DNBATCH(3,YLM_INDEX(L,M)))
    END DO
    DEALLOCATE(YBATCH, TORBATCH, UPBATCH, DNBATCH)
  END DO

  WRITE(*,'(A,I0,A)') "  L=", L, " done"
END DO

CLOSE(21)
CLOSE(22)
CLOSE(23)
CLOSE(24)
CLOSE(25)

WRITE(*,'(A)') &
    "RESULT: independent-reference sample data complete - see ./convergence/reference_*.dat"

END PROGRAM CONVERGENCE_MAIN