Processing math: 100%

Non-uniform grids

By employing non-uniform grids, more effort can be concentrated to those parts where the function is expected to vary more, hopefully leading to a better approximation. StaggeredFiniteDifferences supports both uniform and non-uniform node distributions; in the former case, the node locations are stored as an AbstractRange, in the latter, as any other kind of AbstractVector.

Integrals

Since the quadrature weights in the non-uniform case are location-dependent, they are baked into to the expansion coefficients (as in the FE-DVR case), such that

dxf(x)ifi,

where fi is the ith expansion coefficient of f(x). In the uniform case, the expansion coefficients instead equal the function value at the nodes, which means

dxf(x)Δxifi.

To be sure that you always get the right integration weight, use the metric to perform integrals, e.g.

dxf(x)

is computed using

integral = sum(S*f)

where the metric matrix can be found using

S = B'B

Similarly, integrals of the kind

dxf(x)g(x)

are easily computed as

integral = dot(f, S, g)

Example

We start by constructing two StaggeredFiniteDifferences grids, one uniform and one log–linear, of approximately the same extent (at least including r=30):

julia> N = 50
50

julia> rmax = 30.0
30.0

julia> B1 = StaggeredFiniteDifferences(rmax, N)
Staggered finite differences basis {Float64} on 0.0..30.606060606060606 with 50 points spaced by ρ = 0.6060606060606061

julia> ρmin = 0.001 # Min step-size
0.001

julia> ρmax = 1.0 # Max step-size
1.0

julia> α = 0.1 # Step-size change rate
0.1

julia> B2 = StaggeredFiniteDifferences(ρmin, ρmax, α, rmax)
Staggered finite differences basis {Float64} on 0.0..31.475628188861677 with 103 points

As mentioned above, the metrics are different in the uniform and non-uniform cases:

julia> S1 = B1'B1
UniformScaling{Float64}
0.6060606060606061*I

julia> S2 = B2'B2
UniformScaling{Bool}
true*I

Since the step-size is changing for non-uniform grids, step is ill-defined, but returns unity to simplify the implementation of the differential operators (the coefficients are divided by step(B)^k, where k is the order of the differential; since that is already accounted for in the case of non-uniform grids by scaling the coefficients, 1^k does not change the result):

julia> step(B1)
0.6060606060606061

julia> step(B2)
1.0

The node locations and weights are shown in the figure below: Non-uniform grid

The basis functions become asymmetric in the non-uniform case:

julia> # Compute basis functions on a dense grid
       ξ = 10.0 .^ range(-3, stop=log10(25), length=1000);

julia> χ1 = B1[ξ, :];

julia> χ2 = B2[ξ, :];

Non-uniform basis functions

We then expand the function

f(x)=sin(2πx/30)exp(4x/30)

on both grids and compare the error:

julia> f = x -> sin(2π*x/rmax)*exp(-4x/rmax)
#47 (generic function with 1 method)

julia> xx1 = axes(B1,1)
Inclusion(0.0..30.606060606060606)

julia> c1 = B1 \ f.(xx1);


julia> xx2 = axes(B2,1)
Inclusion(0.0..31.475628188861677)

julia> c2 = B2 \ f.(xx2);

julia> f1 = χ1*c1;

julia> f2 = χ2*c2;

julia> fe = f.(ξ);

Non-uniform basis functions