ASSOC_LEGENDRE_AND_DERIV_DP Subroutine

private subroutine ASSOC_LEGENDRE_AND_DERIV_DP(L, K, X, PLK, DPLK)

Private helper: and together, from a single upward recurrence pass. Avoids the redundant separate ASSOC_LEGENDRE calls that DDX_ASSOC_LEGENDRE would otherwise need, and the repeated SSH + DDX_ASSOC_LEGENDRE evaluation that GRAD_SSH and L_SSH both build on.

Warning

Inherits ASSOC_LEGENDRE's stability limit (safe for at any ) -- see STABILITY_FINDINGS.md at the repo root, Part 2.

Arguments

Type IntentOptional Attributes Name
integer(kind=i4), intent(in) :: L

Degree, .

integer(kind=i4), intent(in) :: K

Order, .

real(kind=dp), intent(in) :: X

Argument, .

real(kind=dp), intent(out) :: PLK

Output ; 0 for or .

real(kind=dp), intent(out) :: DPLK

Output ; 0 at the poles ().


Calls

proc~~assoc_legendre_and_deriv_dp~~CallsGraph proc~assoc_legendre_and_deriv_dp ASSOC_LEGENDRE_AND_DERIV_DP interface~log_fact LOG_FACT proc~assoc_legendre_and_deriv_dp->interface~log_fact proc~log_fact_dp LOG_FACT_DP interface~log_fact->proc~log_fact_dp

Called by

proc~~assoc_legendre_and_deriv_dp~~CalledByGraph proc~assoc_legendre_and_deriv_dp ASSOC_LEGENDRE_AND_DERIV_DP interface~assoc_legendre_and_deriv ASSOC_LEGENDRE_AND_DERIV interface~assoc_legendre_and_deriv->proc~assoc_legendre_and_deriv_dp proc~ddx_assoc_legendre_dp DDX_ASSOC_LEGENDRE_DP proc~ddx_assoc_legendre_dp->interface~assoc_legendre_and_deriv proc~grad_ssh_dp GRAD_SSH_DP proc~grad_ssh_dp->interface~assoc_legendre_and_deriv proc~l_ssh_dp L_SSH_DP proc~l_ssh_dp->interface~assoc_legendre_and_deriv proc~pvsh_pol_dp PVSH_POL_DP proc~pvsh_pol_dp->interface~assoc_legendre_and_deriv proc~pvsh_tor_dp PVSH_TOR_DP proc~pvsh_tor_dp->interface~assoc_legendre_and_deriv proc~vsh_pol_dn_dp VSH_POL_DN_DP proc~vsh_pol_dn_dp->interface~assoc_legendre_and_deriv proc~vsh_pol_up_dp VSH_POL_UP_DP proc~vsh_pol_up_dp->interface~assoc_legendre_and_deriv interface~ddx_assoc_legendre DDX_ASSOC_LEGENDRE interface~ddx_assoc_legendre->proc~ddx_assoc_legendre_dp interface~grad_ssh GRAD_SSH interface~grad_ssh->proc~grad_ssh_dp interface~l_ssh L_SSH interface~l_ssh->proc~l_ssh_dp interface~pvsh_pol PVSH_POL interface~pvsh_pol->proc~pvsh_pol_dp interface~pvsh_tor PVSH_TOR interface~pvsh_tor->proc~pvsh_tor_dp interface~vsh_pol_dn VSH_POL_DN interface~vsh_pol_dn->proc~vsh_pol_dn_dp interface~vsh_pol_up VSH_POL_UP interface~vsh_pol_up->proc~vsh_pol_up_dp proc~batch_dalm_cons BATCH_DALM_CONS proc~batch_dalm_cons->interface~ddx_assoc_legendre proc~batch_grad_ssh_cons BATCH_GRAD_SSH_CONS proc~batch_grad_ssh_cons->interface~grad_ssh proc~batch_l_ssh_cons BATCH_L_SSH_CONS proc~batch_l_ssh_cons->interface~l_ssh proc~batch_pvsh_pol_cons BATCH_PVSH_POL_CONS proc~batch_pvsh_pol_cons->interface~pvsh_pol proc~batch_pvsh_tor_cons BATCH_PVSH_TOR_CONS proc~batch_pvsh_tor_cons->interface~pvsh_tor proc~batch_vsh_pol_dn_cons BATCH_VSH_POL_DN_CONS proc~batch_vsh_pol_dn_cons->interface~vsh_pol_dn proc~batch_vsh_pol_up_cons BATCH_VSH_POL_UP_CONS proc~batch_vsh_pol_up_cons->interface~vsh_pol_up proc~bench_vsh_pol_dn BENCH_VSH_POL_DN proc~bench_vsh_pol_dn->interface~vsh_pol_dn proc~bench_vsh_pol_up BENCH_VSH_POL_UP proc~bench_vsh_pol_up->interface~vsh_pol_up proc~field_known FIELD_KNOWN proc~field_known->interface~pvsh_pol proc~field_known->interface~pvsh_tor proc~field_known_tor FIELD_KNOWN_TOR proc~field_known_tor->interface~pvsh_tor proc~field_quad_bump FIELD_QUAD_BUMP proc~field_quad_bump->interface~pvsh_tor proc~run_gwj_sweep RUN_GWJ_SWEEP proc~run_gwj_sweep->interface~pvsh_pol proc~run_gwj_sweep->interface~pvsh_tor proc~test1_vsh TEST1_VSH proc~test1_vsh->interface~vsh_pol_dn proc~test1_vsh->interface~vsh_pol_up interface~vsh_tor VSH_TOR proc~test1_vsh->interface~vsh_tor proc~test2_vsh TEST2_VSH proc~test2_vsh->interface~pvsh_pol proc~test2_vsh->interface~pvsh_tor proc~vsh_tor_dp VSH_TOR_DP proc~vsh_tor_dp->interface~pvsh_tor program~convergence_main CONVERGENCE_MAIN program~convergence_main->interface~vsh_pol_dn program~convergence_main->interface~vsh_pol_up program~convergence_main->proc~batch_vsh_pol_dn_cons program~convergence_main->proc~batch_vsh_pol_up_cons program~convergence_main->interface~vsh_tor proc~batch_vsh_tor_cons BATCH_VSH_TOR_CONS program~convergence_main->proc~batch_vsh_tor_cons program~dipole_flux_expulsion DIPOLE_FLUX_EXPULSION program~dipole_flux_expulsion->interface~pvsh_pol program~dipole_synthesis DIPOLE_SYNTHESIS program~dipole_synthesis->interface~pvsh_pol program~dipole_uniform_sphere DIPOLE_UNIFORM_SPHERE program~dipole_uniform_sphere->interface~pvsh_pol interface~vsh_tor->proc~vsh_tor_dp proc~run_part_b~2 RUN_PART_B proc~run_part_b~2->proc~field_quad_bump program~bench_main BENCH_MAIN program~bench_main->proc~bench_vsh_pol_dn program~bench_main->proc~bench_vsh_pol_up proc~bench_vsh_tor BENCH_VSH_TOR program~bench_main->proc~bench_vsh_tor program~gwi_gwj_sweep GWI_GWJ_SWEEP program~gwi_gwj_sweep->proc~run_gwj_sweep program~main MAIN program~main->proc~batch_dalm_cons program~main->proc~batch_grad_ssh_cons program~main->proc~batch_l_ssh_cons program~main->proc~batch_pvsh_pol_cons program~main->proc~batch_pvsh_tor_cons program~main->proc~batch_vsh_pol_dn_cons program~main->proc~batch_vsh_pol_up_cons program~main->proc~test1_vsh program~main->proc~test2_vsh program~main->proc~batch_vsh_tor_cons proc~batch_vsh_tor_cons->interface~vsh_tor proc~bench_vsh_tor->interface~vsh_tor program~vsh_decomposition_tor VSH_DECOMPOSITION_TOR program~vsh_decomposition_tor->proc~run_part_b~2

Source Code

  SUBROUTINE ASSOC_LEGENDRE_AND_DERIV_DP(L, K, X, PLK, DPLK)
  IMPLICIT NONE
  INTEGER(KIND=i4), INTENT(IN)  :: L
  INTEGER(KIND=i4), INTENT(IN)  :: K
  REAL(KIND=dp),    INTENT(IN)  :: X
  REAL(KIND=dp),    INTENT(OUT) :: PLK
  REAL(KIND=dp),    INTENT(OUT) :: DPLK
  INTEGER(KIND=i4) :: ABSK, I
  REAL(KIND=dp)    :: Pmm, Pmm1, Plm, Plm1, somx2, DOM, SIGN_K
  ABSK = ABS(K)
  IF (ABSK .GT. L .OR. ABS(X) .GT. 1.0_dp) THEN
    PLK  = 0.0_dp
    DPLK = 0.0_dp
    RETURN
  END IF
  DOM  = 1.0_dp - X**2
  Pmm  = 1.0_dp
  Plm1 = 0.0_dp
  IF (ABSK .GT. 0) THEN
    somx2 = SQRT((1.0_dp - X) * (1.0_dp + X))
    DO I = 1, ABSK
      Pmm = -Pmm * (2*I - 1) * somx2
    END DO
  END IF
  IF (L .EQ. ABSK) THEN
    Plm = Pmm
  ELSE
    Pmm1 = X * (2 * ABSK + 1) * Pmm
    IF (L .EQ. ABSK + 1) THEN
      Plm  = Pmm1
      Plm1 = Pmm
    ELSE
      DO I = ABSK + 2, L
        Plm  = (X*(2*I-1)*Pmm1-(I+ABSK-1)*Pmm) / (I-ABSK)
        Pmm  = Pmm1
        Pmm1 = Plm
      END DO
      Plm1 = Pmm
    END IF
  END IF
  IF (K .LT. 0) THEN
    SIGN_K = (-1.0_dp)**ABSK
    Plm  = SIGN_K*EXP(LOG_FACT(L-ABSK)-LOG_FACT(L+ABSK))*Plm
    IF (L .GT. ABSK) &
      Plm1 = SIGN_K* &
             EXP(LOG_FACT(L-1-ABSK)-LOG_FACT(L-1+ABSK))*Plm1
  END IF
  PLK = Plm
  IF (L .EQ. 0 .OR. ABS(X) .GE. 1.0_dp) THEN
    DPLK = 0.0_dp
  ELSE
    DPLK = ((L + K) * Plm1 - L * X * Plm) / DOM
  END IF
  END SUBROUTINE ASSOC_LEGENDRE_AND_DERIV_DP