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.
| Type | Intent | Optional | 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 (). |
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