function validate(v, mdl, l, w)
    p, p2 = precalc_terms(v, mdl, l, w)

    plt∇L = Plots.scatter(
        numerical_∇L(v, mdl, l, w),
        ∇L(v, mdl, l, w),
        size=(250,200), legend=:none, title="∇L")

    pltD²f_xx = Plots.scatter(
        cat(vec(map(vec, numerical_D²f_xx(mdl, l, w)))..., dims=1),
        cat(vec(map(vec, p.D²f_xx))..., dims=1),
        size=(250,200), legend=:none, title="D²f_xx")

    ####################################################################
    plt∇∇L_xx = Plots.scatter(
        vec(numerical_∇∇L_xx(mdl, l, w)),
        vec(∇∇L_xx(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_xx")

    plt∇∇L_xr = Plots.scatter(
        vec(numerical_∇∇L_xr(mdl, l, w)),
        vec(∇∇L_xr(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_xr")

    plt∇∇L_xη = Plots.scatter(
        vec(numerical_∇∇L_xη(mdl, l, w)),
        vec(∇∇L_xη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_xη")

    plt∇∇L_xa = Plots.scatter(
        vec(numerical_∇∇L_xa(mdl, l, w)),
        vec(∇∇L_xa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_xa")

    plt∇∇L_rr = Plots.scatter(
        vec(numerical_∇∇L_rr(mdl, l, w)),
        vec(∇∇L_rr(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rr")

    plt∇∇L_rη = Plots.scatter(
        vec(numerical_∇∇L_rη(mdl, l, w)),
        vec(∇∇L_rη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rη")

    plt∇∇L_ra = Plots.scatter(
        vec(numerical_∇∇L_ra(mdl, l, w)),
        vec(∇∇L_ra(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ra")

    plt∇∇L_ηη = Plots.scatter(
        vec(numerical_∇∇L_ηη(mdl, l, w)),
        vec(∇∇L_ηη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ηη")

    plt∇∇L_ηa = Plots.scatter(
        vec(numerical_∇∇L_ηa(mdl, l, w)),
        vec(∇∇L_ηa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ηa")

    plt∇∇L_aa = Plots.scatter(
        vec(numerical_∇∇L_aa(mdl, l, w)),
        vec(∇∇L_aa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_aa")

    ####################################################################
    plt∇∇∇L_xxx = Plots.scatter(
        vec(numerical_∇∇L_xxx(mdl, l, w)),
        vec(∇∇∇L_xxx(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_xx")

    # plt∇∇∇L_xxr = Plots.scatter(
    #     vec(numerical_∇∇∇L_xxr(mdl, l, w)),
    #     vec(∇∇∇L_xxr(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_xr")
    #
    # plt∇∇∇L_xη = Plots.scatter(
    #     vec(numerical_∇∇∇L_xxη(mdl, l, w)),
    #     vec(∇∇∇L_xxη(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_xη")
    #
    # plt∇∇∇L_xxa = Plots.scatter(
    #     vec(numerical_∇∇∇L_xxa(mdl, l, w)),
    #     vec(∇∇∇L_xxa(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_xa")

    plt∇∇∇L_xrr = Plots.scatter(
        vec(numerical_∇∇∇L_xrr(mdl, l, w)),
        vec(∇∇∇L_xrr(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rr")

    plt∇∇∇L_xrη = Plots.scatter(
        vec(numerical_∇∇∇L_xrη(mdl, l, w)),
        vec(∇∇∇L_xrη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rη")

    # plt∇∇∇L_xra = Plots.scatter(
    #     vec(numerical_∇∇∇L_xra(mdl, l, w)),
    #     vec(∇∇∇L_xra(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_ra")

    plt∇∇∇L_xηη = Plots.scatter(
        vec(numerical_∇∇∇L_xηη(mdl, l, w)),
        vec(∇∇∇L_xηη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rη")

    # plt∇∇∇L_xηa = Plots.scatter(
    #     vec(numerical_∇∇∇L_xηa(mdl, l, w)),
    #     vec(∇∇∇L_xηa(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_ra")

    plt∇∇∇L_xaa = Plots.scatter(
        vec(numerical_∇∇∇L_xaa(mdl, l, w)),
        vec(∇∇∇L_xηa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ra")

    plt∇∇∇L_rrr = Plots.scatter(
        vec(numerical_∇∇∇L_rrr(mdl, l, w)),
        vec(∇∇∇L_rrr(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rr")

    plt∇∇∇L_rrη = Plots.scatter(
        vec(numerical_∇∇∇L_rrη(mdl, l, w)),
        vec(∇∇∇L_rrη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_rη")

    plt∇∇∇L_rra = Plots.scatter(
        vec(numerical_∇∇∇L_rra(mdl, l, w)),
        vec(∇∇∇L_rra(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ra")

    # plt∇∇∇L_rηη = Plots.scatter(
    #     vec(numerical_∇∇∇L_rηη(mdl, l, w)),
    #     vec(∇∇∇L_rηη(v, mdl, l, w)),
    #     size=(250,200), legend=:none, title="∇∇L_ηη")

    plt∇∇∇L_rηa = Plots.scatter(
        vec(numerical_∇∇∇L_rηa(mdl, l, w)),
        vec(∇∇∇L_rηa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ηa")

    plt∇∇∇L_ηηη = Plots.scatter(
        vec(numerical_∇∇∇L_ηηη(mdl, l, w)),
        vec(∇∇∇L_ηηη(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_ηη")

    plt∇∇∇L_ηηa = Plots.scatter(
        vec(numerical_∇∇∇L_ηηa(mdl, l, w)),
        vec(∇∇∇L_ηηa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_aa")

    plt∇∇∇L_ηaa = Plots.scatter(
        vec(numerical_∇∇∇L_ηaa(mdl, l, w)),
        vec(∇∇∇L_ηaa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_aa")

    plt∇∇∇L_aaa = Plots.scatter(
        vec(numerical_∇∇∇L_aaa(mdl, l, w)),
        vec(∇∇∇L_aaa(v, mdl, l, w)),
        size=(250,200), legend=:none, title="∇∇L_aa")

    res = []
    push!(res, plt∇L)

    push!(res, pltD²f_xx)
    push!(res, plt∇∇L_xx)
    push!(res, plt∇∇L_xr)
    push!(res, plt∇∇L_xη)
    push!(res, plt∇∇L_xa)
    push!(res, plt∇∇L_rr)
    push!(res, plt∇∇L_rη)
    push!(res, plt∇∇L_ra)
    push!(res, plt∇∇L_ηη)
    push!(res, plt∇∇L_ηa)
    push!(res, plt∇∇L_aa)

    push!(res, plt∇∇∇L_xxx)
    # push!(res, plt∇∇∇L_xxr)
    # push!(res, plt∇∇∇L_xη)
    # push!(res, plt∇∇∇L_xxa)
    push!(res, plt∇∇∇L_xrr)
    push!(res, plt∇∇∇L_xrη)
    # push!(res, plt∇∇∇L_xra)
    push!(res, plt∇∇∇L_xηη)
    # push!(res, plt∇∇∇L_xηa)
    push!(res, plt∇∇∇L_xaa)
    push!(res, plt∇∇∇L_rrr)
    push!(res, plt∇∇∇L_rrη)
    push!(res, plt∇∇∇L_rra)
    # push!(res, plt∇∇∇L_rηη)
    push!(res, plt∇∇∇L_rηa)
    push!(res, plt∇∇∇L_ηηη)
    push!(res, plt∇∇∇L_ηηa)
    push!(res, plt∇∇∇L_ηaa)
    push!(res, plt∇∇∇L_aaa)

    return res
end

function precalc_terms(v::DenseVector, mdl::CLVGM, l::Int, w::Int)
    C          = mdl.dt.C
    Y          = mdl.dt.Y
    T          = mdl.pr.T
    λ0         = mdl.pr.λ0
    r_fix      = mdl.pr.r_fix
    η_fix      = mdl.pr.η_fix
    η_unify    = mdl.pr.η_unify
    r_hp       = mdl.pr.r_hp
    η_hp       = mdl.pr.η_hp
    a_hp       = mdl.pr.a_hp

    kc         = mdl.kc
    Σm_γ²I_s   = kc.Σm_γ²I
    Σm_γ²I⁻¹_s = kc.Σm_γ²I⁻¹
    Kxx_s      = kc.Kxx
    crossKxx_s = kc.crossKxx
    Dm_x_s     = kc.Dm_x
    σ = mdl.st.σ[l,w]
    τ_ys = mdl.dt.τ_ys
    K̂yy_σ²I_s = [mdl.kc.K̂yy[c] .+ diagm(fill(σ[c]^2, length(τ_ys[c]))) for c in 1:C]

    X, r_ℝ, η_ℝ, a_ℝ = decompose_variables(v, mdl, l, w)
    Λy = λ0' .* exp.(Y)
    Λx = λ0' .* exp.(X)
    r = scaled_sigmoid.(r_ℝ, r_hp[1][1], r_hp[1][2])
    η = scaled_sigmoid.(η_ℝ, η_hp[1][1], η_hp[1][2])
    a = scaled_sigmoid.(a_ℝ, a_hp[1][1], a_hp[1][2])
    A = competitive_coef_matrix(a, C)
    fℝ = Lotka_Volterra(Λx, r, η, A) ./ Λx
    m = reduce(hcat, [gp_grad_mean(Kxx_s[c], crossKxx_s[c], X[:,c]) for c in 1:C]) # T × C

    # calculate shared terms in advance to avoid redundant recalculation
    p = (
        Σm_γ²I_s   = Σm_γ²I_s,
        Σm_γ²I⁻¹_s = Σm_γ²I⁻¹_s,
        Kxx_s      = Kxx_s,
        crossKxx_s = crossKxx_s,
        Dm_x_s     = Dm_x_s,
        K̂yy_σ²I_s  = K̂yy_σ²I_s,

        DLg_f   = DLg_f(fℝ, m, kc.Σm_γ²I⁻¹),           # T*C
        Df_x    = Df_x(Λx, r, η, A, T, C),             # C [T × C]
        Df_r    = Df_r(Λx, r_ℝ, η, A, T, C, r_hp),     # C [T × C]
        Df_η    = Df_η(Λx, r, η, η_ℝ, A, T, C, η_hp),  # C [T × C]
        Df_a    = Df_a(Λx, r, η, a_ℝ, T, C, a_hp),     # C^2-C [T × C]
        Dm_x    = Dm_x(T, C, kc.Dm_x),                 # C [T × C]
        Df_λ    = Df_λ(r, η, A, T, C),                 # T*C [T × C]
        Df_r⁺   = Df_r⁺(Λx, η, A, T, C),
        Df_η⁺   = Df_η⁺(Λx, r, η, A, T, C),
        Df_a⁺   = Df_a⁺(Λx, r, η, T, C),
        Dλ_x    = Dλ_x(Λx),                            # T × C
        Dr⁺_r   = Dr⁺_r(r_ℝ, r_hp),                    # C
        Dη⁺_η   = Dη⁺_η(η_ℝ, η_hp),                    # C
        Da⁺_a   = Da⁺_a(a_ℝ, a_hp),                    # C^2-C

        D²λ_xx  = diagm(vec(Dλ_x(Λx))),          # T*C × T*C
        D²f_λr⁺ = D²f_λr⁺(η, A, T, C),           # T*C × C [T × C]
        D²f_λη⁺ = D²f_λη⁺(r, η, A, T, C),        # T*C × C [T × C]
        D²f_λa⁺ = D²f_λa⁺(r, η, T, C),           # T*C × C^2-C [T × C]
        D²f_r⁺η⁺ = D²f_r⁺η⁺(Λx, η, A, T, C),
        D²f_r⁺a⁺ = D²f_r⁺a⁺(Λx, η, T, C),
        D²f_η⁺η⁺ = D²f_η⁺η⁺(Λx, r, η, A, T, C),
        D²f_η⁺a⁺ = D²f_η⁺a⁺(Λx, r, η, T, C),
        D²r⁺_rr = diagm(D²scaledsigmoid_xx(r_ℝ, r_hp[1][1], r_hp[1][2])),  # C × C
        D²η⁺_ηη = diagm(D²scaledsigmoid_xx(η_ℝ, η_hp[1][1], η_hp[1][2])),  # C × C
        D²a⁺_aa = diagm(D²scaledsigmoid_xx(a_ℝ, a_hp[1][1], a_hp[1][2])),  # C^2^C × C^2-C

        D²f_xx  = D²f_xx(Λx, r, η, A, T, C),                     # T*C × T*C [T × C]
        D²f_xr  = D²f_xr(Λx, r_ℝ, η, A, T, C, r_hp),             # T*C × C [T × C]
        D²f_xη  = D²f_xη(Λx, r, η, η_ℝ, A, T, C, η_hp),          # T*C × C [T × C]
        D²f_xa  = D²f_xa(Λx, r, η, a_ℝ, T, C, a_hp),             # T*C × C^2-C [T × C]
        D²f_rr  = D²f_rr(Λx, r_ℝ, η, A, T, C, r_hp),             # C × C [T × C]
        D²f_rη  = D²f_rη(Λx, r_ℝ, η, η_ℝ, A, T, C, r_hp, η_hp),  # C × C [T × C]
        D²f_ra  = D²f_ra(Λx, r_ℝ, η, a_ℝ, T, C, r_hp, a_hp),     # C × C^2-C [T × C]
        D²f_ηη  = D²f_ηη(Λx, r, η, η_ℝ, A, T, C, η_hp),          # C × C [T × C]
        D²f_ηa  = D²f_ηa(Λx, r, η, η_ℝ, a_ℝ, T, C, η_hp, a_hp),  # C × C^2-C [T × C]
        D²f_aa  = D²f_aa(Λx, r, η, a_ℝ, T, C, a_hp),             # C^2-C × C^2-C [T × C]

        D²Lg_ff = D²Lg_ff(kc),  # T*C × T*C
        D²Lg_mf = D²Lg_mf(kc),  # T*C × T*C
        D²Lg_mm = D²Lg_mm(kc),
        D²Lg_fm = D²Lg_fm(kc),

        D³f_λr⁺η⁺ = D³f_λr⁺η⁺(η, A, T, C),     # T*C × C × C [T × C]
        D³f_λr⁺a⁺ = D³f_λr⁺a⁺(η, T, C),        # T*C × C × C^2-C [T × C]
        D³f_λη⁺η⁺ = D³f_λη⁺η⁺(r, η, A, T, C),  # T*C × C × C [T × C]
        D³f_λη⁺a⁺ = D³f_λη⁺a⁺(r, η, T, C),     # T*C × C × C^2-C [T × C]
        D³λ_xxx_vec  = vec(Λx),                # T*C
        D³r⁺_rrr_vec = D³scaledsigmoid_xxx.(r_ℝ, r_hp[1][1], r_hp[1][2]),
        D³η⁺_ηηη_vec = D³scaledsigmoid_xxx.(η_ℝ, η_hp[1][1], η_hp[1][2]),
        D³a⁺_aaa_vec = D³scaledsigmoid_xxx.(a_ℝ, a_hp[1][1], a_hp[1][2]),
        D³f_r⁺η⁺η⁺ = D³f_r⁺η⁺η⁺(Λx, η, A, T, C),
        D³f_r⁺η⁺a⁺ = D³f_r⁺η⁺a⁺(Λx, η, T, C),
        D³f_η⁺η⁺η⁺ = D³f_η⁺η⁺η⁺(Λx, r, η, A, T, C),
        D³f_η⁺η⁺a⁺ = D³f_η⁺η⁺a⁺(Λx, r, η, T, C),
    )

    p2 = (
        D³f_xxx = D³f_xxx(T, C, p.D³λ_xxx_vec, p.Df_λ),                               # T*C × T*C × T*C [T × C] NOTE: 符号
        D³f_xxr = D³f_xxr(T, C, p.D²λ_xx, p.Dr⁺_r, p.D²f_λr⁺),                         # T*C × T*C × C [T × C] NOTE: 符号
        D³f_xxη = D³f_xxη(T, C, p.D²λ_xx, p.Dη⁺_η, p.D²f_λη⁺),                         # T*C × T*C × C [T × C] NOTE: 符号
        D³f_xxa = D³f_xxa(T, C, p.D²λ_xx, p.Da⁺_a, p.D²f_λa⁺),                         # T*C × T*C × C^2-C [T × C] NOTE: 符号
        D³f_xrr = D³f_xrr(T, C, p.Dλ_x, p.D²r⁺_rr, p.D²f_λr⁺),                         # T*C × C × C [T × C] NOTE: 符号
        D³f_xrη = D³f_xrη(T, C, p.Dλ_x, p.Dr⁺_r, p.Dη⁺_η, p.D³f_λr⁺η⁺),                 # T*C × C × C [T × C] NOTE: 符号
        D³f_xra = D³f_xra(T, C, p.Dλ_x, p.Dr⁺_r, p.Da⁺_a, p.D³f_λr⁺a⁺),                 # T*C × C × C^2-C [T × C] NOTE: 符号
        D³f_xηη = D³f_xηη(T, C, p.D³f_λη⁺η⁺, p.Dλ_x, p.Dη⁺_η, p.D²η⁺_ηη, p.D²f_λη⁺),     # T*C × C × C [T × C] NOTE: 符号
        D³f_xηa = D³f_xηa(T, C, p.Dλ_x, p.Dη⁺_η, p.Da⁺_a, p.D³f_λη⁺a⁺),                 # T*C × C × C^2-C [T × C] NOTE: 符号
        D³f_xaa = D³f_xaa(T, C, p.Dλ_x, p.D²a⁺_aa, p.D²f_λa⁺),                         # T*C × C^2-C × C^2-C [T × C] NOTE: 符号
        D³f_rrr = D³f_rrr(T, C, p.Df_r⁺, p.D³r⁺_rrr_vec),                                   # C × C × C [T × C] NOTE: 符号
        D³f_rrη = D³f_rrη(T, C, p.D²f_r⁺η⁺, p.D²r⁺_rr, p.Dη⁺_η),                       # C × C × C [T × C] NOTE: 符号
        D³f_rra = D³f_rra(T, C, p.D²f_r⁺a⁺, p.D²r⁺_rr, p.Da⁺_a),                       # C × C × C^2-C [T × C] NOTE: 符号
        D³f_rηη = D³f_rηη(T, C, p.D³f_r⁺η⁺η⁺, p.Dr⁺_r, p.Dη⁺_η, p.D²f_r⁺η⁺, p.D²η⁺_ηη),  # C × C × C [T × C] NOTE: 符号
        D³f_rηa = D³f_rηa(T, C, p.D³f_r⁺η⁺a⁺, p.Dr⁺_r, p.Dη⁺_η, p.Da⁺_a),                  # C × C × C^2-C [T × C] NOTE: 符号
        D³f_raa = D³f_raa(T, C, p.D²f_r⁺a⁺, p.D²a⁺_aa, p.Dr⁺_r),                       # C × C × C [T × C] NOTE: 符号
        D³f_ηηη = D³f_ηηη(T, C, p.Dη⁺_η, p.Df_η⁺, p.D²η⁺_ηη, p.D²f_η⁺η⁺, p.D³f_η⁺η⁺η⁺, p.D³η⁺_ηηη_vec),  # C × C × C [T × C] NOTE: 符号
        D³f_ηηa = D³f_ηηa(T, C, p.D³f_η⁺η⁺a⁺, p.Da⁺_a, p.Dη⁺_η, p.D²f_η⁺a⁺, p.D²η⁺_ηη),    # C × C × C^2-C [T × C] NOTE: 符号
        D³f_ηaa = D³f_ηaa(T, C, p.D²f_η⁺a⁺, p.Dη⁺_η, p.D²a⁺_aa),                       # C × C^2-C × C^2-C [T × C] NOTE: 符号
        D³f_aaa = D³f_aaa(T, C, p.Df_a⁺, p.D³a⁺_aaa_vec),                             # C^2-C × C^2-C × C^2-C [T × C] NOTE: 符号
    )
    return p, p2
end

####################################################################################################
function numerical_∇L(v::Vf, mdl::CLVGM, l::Int, w::Int)
    nmr = Float64[]
    for i in 1:45
        X, r_ℝ, η_ℝ, a_ℝ = decompose_variables(v, mdl, 1, 1)
        l1 = L_posterior(mdl, l, w, X=X, r_ℝ=r_ℝ, η_ℝ=η_ℝ, a_ℝ=a_ℝ)
        v[i] += 1e-8
        X, r_ℝ, η_ℝ, a_ℝ = decompose_variables(v, mdl, 1, 1)
        l2 = L_posterior(mdl, l, w, X=X, r_ℝ=r_ℝ, η_ℝ=η_ℝ, a_ℝ=a_ℝ)
        v[i] -= 1e-8
        δ = (l2 - l1) / 1e-8
        push!(nmr, δ)
    end
    return nmr
end

function numerical_D²f_xx(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    nmrs = Array{Mf}(undef, n_x, n_x)
    for i in 1:n_x, j in 1:n_x
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.Df_x[i]
        v[j] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.Df_x[i]
        v[j] -= δ
        nmrs[i,j] = (g2 .- g1) ./ δ
    end
    return nmrs
end

####################################################################################################
function ∇∇L_xx(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_xx(mdl, l, p.K̂yy_σ²I_s, p.D²Lg_ff, p.D²Lg_mf, p.D²Lg_mm, p.D²Lg_fm, p.DLg_f, p.Dm_x, p.Df_x, p.D²f_xx)
end

function ∇∇L_xr(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_xr(mdl, l, p.D²Lg_ff, p.D²Lg_mf, p.DLg_f, p.Dm_x, p.Df_x, p.Df_r, p.D²f_xr)
end

function ∇∇L_xη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_xη(mdl, l, p.D²Lg_ff, p.D²Lg_mf, p.DLg_f, p.Dm_x, p.Df_x, p.Df_η, p.D²f_xη)
end

function ∇∇L_xa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_xa(mdl, l, p.D²Lg_ff, p.D²Lg_mf, p.DLg_f, p.Dm_x, p.Df_x, p.Df_a, p.D²f_xa)
end

function ∇∇L_rr(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_rr(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_r, p.D²f_rr)
end

function ∇∇L_rη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_rη(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_r, p.Df_η, p.D²f_rη)
end

function ∇∇L_ra(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_ra(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_r, p.Df_a, p.D²f_ra)
end

function ∇∇L_ηη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_ηη(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_η, p.D²f_ηη)
end

function ∇∇L_ηa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_ηa(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_η, p.Df_a, p.D²f_ηa)
end

function ∇∇L_aa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, _ = precalc_terms(v, mdl, l, w)
    ∇∇L_aa(mdl, l, p.D²Lg_ff, p.DLg_f, p.Df_a, p.D²f_aa)
end

function ∇∇∇L_xxx(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xxx(mdl, l,  p2.D³f_xxx, p.D²f_xx, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.DLg_f)
end

function ∇∇∇L_xxr(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xxr(mdl, l, p2.D³f_xxr, p.D²f_xr, p.D²f_xx, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Df_r, p.Dm_x, p.DLg_f)
end

function ∇∇∇L_xxη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xxη(mdl, l, p2.D³f_xxη, p.D²f_xη, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.DLg_f)
end

function ∇∇∇L_xxa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xxa(mdl, l, p2.D³f_xxa, p.D²f_xa, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.DLg_f)
end

function ∇∇∇L_xrr(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xrr(mdl, l,  p2.D³f_xrr, p.D²f_xr, p.D²f_rr, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_r, p.DLg_f)
end

function ∇∇∇L_xrη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xrη(mdl, l,  p2.D³f_xrη, p.D²f_xη, p.D²f_xr, p.D²f_rη, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_r, p.Df_η, p.DLg_f)
end

function ∇∇∇L_xra(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xra(mdl, l, p2.D³f_xra, p.D²f_xa, p.D²f_xr, p.D²f_ra, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_r, p.Df_a, p.DLg_f)
end

function ∇∇∇L_xηη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xηη(mdl, l, p2.D³f_xηη, p.D²f_xη, p.D²f_ηη, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_η, p.DLg_f)
end

function ∇∇∇L_xηa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xηa(mdl, l, p2.D³f_xηa, p.D²f_xa, p.D²f_xη, p.D²f_ηa, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_η, p.Df_a, p.DLg_f)
end

function ∇∇∇L_xaa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_xaa(mdl, l, p2.D³f_xaa, p.D²f_xa, p.D²f_aa, p.D²Lg_ff, p.D²Lg_mf, p.Df_x, p.Dm_x, p.Df_a, p.DLg_f)
end

function ∇∇∇L_rrr(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_rrr(mdl, l, p2.D³f_rrr, p.D²f_rr, p.D²Lg_ff, p.Df_r, p.DLg_f)
end

function ∇∇∇L_rrη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_rrη(mdl, l, p2.D³f_rrη, p.D²f_rr, p.D²f_rη, p.D²Lg_ff, p.Df_r, p.Df_η, p.DLg_f)
end

function ∇∇∇L_rra(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_rra(mdl, l, p2.D³f_rra, p.D²f_rr, p.D²f_ra, p.D²Lg_ff, p.Df_r, p.Df_a, p.DLg_f)
end

function ∇∇∇L_rηη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_rηη(mdl, l, p2.D³f_rηη, p.D²f_rη, p.D²f_ηη, p.D²Lg_ff, p.Df_r, p.Df_η, p.DLg_f)
end

function ∇∇∇L_rηa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_rηa(mdl, l, p2.D³f_rηa, p.D²f_rη, p.D²f_ra, p.D²f_ηa, p.D²Lg_ff, p.Df_r, p.Df_η, p.Df_a, p.DLg_f)
end

function ∇∇∇L_raa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_raa(mdl, l, p2.D³f_raa, p.D²f_ra, p.D²f_aa, p.D²Lg_ff, p.Df_r, p.Df_a, p.DLg_f)
end

function ∇∇∇L_ηηη(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_ηηη(mdl, l, p2.D³f_ηηη, p.D²f_ηη, p.D²Lg_ff, p.Df_η, p.DLg_f)
end

function ∇∇∇L_ηηa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_ηηa(mdl, l, p2.D³f_ηηa, p.D²f_ηη, p.D²f_ηa, p.D²Lg_ff, p.Df_η, p.Df_a, p.DLg_f)
end

function ∇∇∇L_ηaa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_ηaa(mdl, l, p2.D³f_ηaa, p.D²f_ηa, p.D²f_aa, p.D²Lg_ff, p.Df_η, p.Df_a, p.DLg_f)
end

function ∇∇∇L_aaa(v::Vf, mdl::CLVGM, l::Int, w::Int)
    p, p2 = precalc_terms(v, mdl, l, w)
    ∇∇∇L_aaa(mdl, l, p2.D³f_aaa, p.D²f_aa, p.D²Lg_ff, p.Df_a, p.DLg_f)
end

function numerical_∇∇L_xx(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    for i in 1:n_x
        h1 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_xr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_xη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_xa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[1:n_x]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_rr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_rη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_ra(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+1:n_x+n_r]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_ηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇L(v, mdl, l, w)[n_x+n_r+1:n_x+n_r+n_η]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+n_r+1:n_x+n_r+n_η]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_ηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇L(v, mdl, l, w)[n_x+n_r+1:n_x+n_r+n_η]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+n_r+1:n_x+n_r+n_η]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇L_aa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇L(v, mdl, l, w)[n_x+n_r+n_η+1:end]
        v[i] += δ
        h2 = ∇L(v, mdl, l, w)[n_x+n_r+n_η+1:end]
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=2)
    return nmr
end

function numerical_∇∇∇L_xxx(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    for i in 1:n_x
        h1 = ∇∇L_xx(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xx(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xxr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇∇L_xx(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xx(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xxη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇∇L_xx(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xx(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xxa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_xx(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xx(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xrr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇∇L_xr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xrη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇∇L_xr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xra(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_xr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇∇L_xη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_xη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_xaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_xa(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_xa(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_rrr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇∇L_rr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_rr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_rrη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇∇L_rr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_rr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_rra(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_rr(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_rr(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_rηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    for i in n_x+1:n_x+n_r
        h1 = ∇∇L_rη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_rη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_rηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_rη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_rη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_raa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_ra(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_ra(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_ηηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    for i in n_x+n_r+1:n_x+n_r+n_η
        h1 = ∇∇L_ηη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_ηη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_ηηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_ηη(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_ηη(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_ηaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_ηa(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_ηa(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

function numerical_∇∇∇L_aaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    for i in n_x+n_r+n_η+1:n_x+n_r+n_η+n_a
        h1 = ∇∇L_aa(v, mdl, l, w)
        v[i] += δ
        h2 = ∇∇L_aa(v, mdl, l, w)
        v[i] -= δ
        ∇ = (h2 .- h1) ./ δ
        push!(nmr_slices, ∇)
    end
    nmr = cat(nmr_slices..., dims=3)
    return nmr
end

####################################################################################################
D³f_xxx(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xxx; end
D³f_xxr(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xxr; end
D³f_xxη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xxη; end
D³f_xxa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xxa; end
D³f_xrr(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xrr; end
D³f_xrη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xrη; end
D³f_xra(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xra; end
D³f_xηη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xηη; end
D³f_xηa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xηa; end
D³f_xaa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_xaa; end

D³f_rrr(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_rrr; end
D³f_rrη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_rrη; end
D³f_rra(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_rra; end
D³f_rηη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_rηη; end
D³f_rηa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_rηa; end
D³f_raa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_raa; end
D³f_ηηη(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_ηηη; end
D³f_ηηa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_ηηa; end
D³f_ηaa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_ηaa; end
D³f_aaa(v::Vf, mdl::CLVGM, l::Int, w::Int) = begin p, p2 = precalc_terms(v, mdl, l, w); p2.D³f_aaa; end

function numerical_D³f_xxx(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    nmr = Array{Mf}(undef, n_x, n_x, n_x)
    for i in 1:n_x
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xx
        v[i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xx
        v[i] -= δ
        nmr[:,:, i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xxr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_x, n_r)
    for i in 1:n_r
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xx
        v[n_x + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xx
        v[n_x + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xxη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_x, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xx
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xx
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xxa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_x, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xx
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xx
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xrr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_r, n_r)
    for i in 1:n_r
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xr
        v[n_x + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xr
        v[n_x + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xrη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_r, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xr
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xr
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xra(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_r, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xr
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xr
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_η, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xη
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xη
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_η, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xη
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xη
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_xaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_x, n_a, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_xa
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_xa
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_rrr(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_r, n_r)
    for i in 1:n_r
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_rr
        v[n_x + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_rr
        v[n_x + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_rrη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_r, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_rr
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_rr
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_rra(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_r, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_rr
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_rr
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_rηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_η, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_rη
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_rη
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_rηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_η, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_rη
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_rη
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_raa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_r, n_a, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_ra
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_ra
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_ηηη(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_η, n_η, n_η)
    for i in 1:n_η
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_ηη
        v[n_x + n_r + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_ηη
        v[n_x + n_r + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_ηηa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_η, n_η, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_ηη
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_ηη
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_ηaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_η, n_a, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_ηa
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_ηa
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end

function numerical_D³f_aaa(mdl::CLVGM, l::Int, w::Int; δ=1e-5)
    @assert mdl.pr.r_fix == false
    @assert mdl.pr.η_fix == false
    nmr_slices = []
    v = create_samplevector(mdl, l, w)
    C = mdl.dt.C
    T = mdl.pr.T
    n_x = C*T
    n_r = C
    n_η = mdl.pr.η_unify ? 1 : C
    n_a = Int(C^2-C)
    nmr = Array{Mf}(undef, n_a, n_a, n_a)
    for i in 1:n_a
        p, p2 = precalc_terms(v, mdl, l, w)
        g1 = p.D²f_aa
        v[n_x + n_r + n_η + i] += δ
        p, p2 = precalc_terms(v, mdl, l, w)
        g2 = p.D²f_aa
        v[n_x + n_r + n_η + i] -= δ
        nmr[:,:,i] = (g2 .- g1) ./ δ
    end
    return nmr
end
