Skip to content

aurelio-amerio/FunctionTabulations.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FunctionTabulations

CI Coverage

This package is a wrapper around Interpolations.jl to compute interpolation tables (FunctionTabulations) for functions of up to three variables with support for Unitful.

This package stems from the common need in physics research projects to tabulate slow functions. With this package, it becomes possible to easily compute the values of a function and tabulate its values for up to three variables.

Installation

using Pkg; Pkg.add("FunctionTabulations")

Usage: 1D FunctionTabulations

Simple usage

To compute and load the tabulation of a function with one variable, it is necessary to use create_tabulation_1D:

using FunctionTabulations

func_1D(x) = sin(x)

sin_tabulation = create_tabulation_1D(func_1D, xmin = 0.0, xmax = 3.0, npoints = 100) # produces a file called `func_1D_data.jld2`

isapprox(sin(3.0), sin_tabulation(3.0), rtol=1e-3)

It is always necessary to specify the function to be tabulated, the interval and the number of points of the tabulation grid. The routine will compute npoints values of the function in the range xmin:xmax, save the table in a .jld2 file, and return the interpolating function of the tabulated data. If a proper .jld2 file already exists for that function, and it was computed in the same x range with the same number of points npoints, it will automatically be loaded on subsequent calls of compute_tabulation_1D.

Logarithmic scale

Sometimes, it is more advantageous to tabulate a function using a logarithmic scale. For example, a function y=f(x) might display a more linear trend when the x or f(x) axis is expressed in logarithmic (log10) scale. In this case, it is possible to ask the routine to tabulate or interpolate that axis in logarithmic scale. For example, given the function f(x)=10^x, it is more advantageous to consider the f(x) axis in logarithmic scale for the interpolation:

func_1D(x) = 10^x

func_1D_tabulation = create_tabulation_1D(func_1D, xmin = 0.0, xmax = 3.0, npoints = 100, f_scale=:log10)

isapprox(func_1D(3.0), func_1D_tabulation(3.0), rtol=1e-3)

On the other hand, a function which needs to be interpolated in a wide range of x and does not vary harshly with x may benefit from the option x_scale=:log10.

Unitful support

FunctionTabulations.jl supports Unitful.jl. It is possible to tabulate functions which have variables of the Quantity type, and/or return quantities. This means that units of measurement are fully supported.

using Unitful

func_1d(x) = x^2

itp_1d_1 = create_tabulation_1D(
    func_1d,
    custom_name = "1d_1",
    xmin = 0.0u"m",
    xmax = 3.0u"m",
    npoints = 100,
    x_scale = :linear,
    f_scale = :linear
)

isapprox(itp_1d_1(2.0u"m"), func_1d(2.0u"m"), rtol = 1e-3)
    

In the case of a tabulation with units of measurement, the unit of the result of the tabulated function is the one returned by f(xmin). Nontheless, it supports automatic unit conversion for the input variables:

func_1d(x) = x^2

itp_1d_1 = create_tabulation_1D(
    func_1d,
    custom_name = "1d_1",
    xmin = 0.0u"m",
    xmax = 3.0u"m",
    npoints = 100,
    x_scale = :linear,
    f_scale = :linear
)

isapprox(itp_1d_1(2.0u"m"), itp_1d_1(200.0u"cm"), rtol = 1e-3)
    

Save location

It is possible to specify the folder where to save/load the interpolation using the option jld_base_path. Furthermore it is possible to specify the name of the file in which the interpolation will be stored using the option custom_name. Please note that the suffix _data.jld2 will always be appended to the filename when the tabulation is stored.

func_1d(x) = sin(x)

itp_1d_2 = create_tabulation_1D(
    func_1d,
    jld_base_path = "interpolations",
    custom_name = "1d_2",
    xmin = 0.0,
    xmax = 3.0,
    npoints = 100,
) 
# will generate a file called "1d_2_data.jld2" in the folder "interpolations". 
# If the folder doesn't exist, the routine will create it.

Interpolation options

It is possible to customize the behaviour of the interpolation of the tabulated grid using interpolation_type and extrapolation_bc. The default interpolation method is a linear interpolation (:linear), but it is also possible to use a cubic spline (:cubic). Furthermore, it is possible to specify the behaviour outside of the tabulation domain (xmin, xmax) using extrapolation_bc. The default behaviour is to throw an exception, but it is also possible for to extrapolate linearly:

using Interpolations: Line

func_1d(x) = sin(x)

itp_1d_1 = create_tabulation_1D(
    func_1d,
    xmin = 0.0,
    xmax = 3.0,
    npoints = 100,
    x_scale = :linear,
    f_scale = :linear,
    interpolation_type = :linear,
    extrapolation_bc = Line,
)

For more information about the extrapolation conditions, see the Interpolations.jl documentation and pass the extrapolation function as the extrapolation_bc argument.

Extra args and kwargs

In case it is necessary to pass further fixed positional arguments or keyword arguments to the tabulated function, create_tabulation_1D will pass the extra args and kwargs to the function to be tabulated:

func_1d(x, a; b) = x^2 + a*b

itp_1d_1 = create_tabulation_1D(
    func_1d,
    2, # the `a` positional argument 
    xmin = 0.0,
    xmax = 3.0,
    npoints = 100,
    b=1, # the `b` positional argument
)

isapprox(itp_1d_1(2.0), func_1d(2.0, 2; b=1), rtol = 1e-3)

Storing metadata

It is possible to store some metadata in the tabulation archive, by specifying the metadata keyword argument. metadata has to be provided in the form of a Dict{String, Any}. By default, when loading a tabulation, if some metadata is provided it will be compared against the stored metadata through the equality metadata == stored_metadata. In case more articulated metadata validation is required, it is possible to pass a validate_metadata_fn function, which will be responsible of metadata validation.

func_1d(x) = sin(x)

function metadata_validation_fn(metadata, loaded_metadata)
    return metadata["a"] == loaded_metadata["a"]
end

itp_1d_1 = create_tabulation_1D(
    func_1d,
    xmin = 0.0,
    xmax = 3.0,
    npoints = 100,
    x_scale = :linear,
    f_scale = :linear,
    metadata = Dict{String, Any}("a"=>1),
    metadata_validation_fn = metadata_validation_fn
) # create the tabulation

itp_1d_1_loaded = create_tabulation_1D(
    func_1d,
    xmin = 0.0,
    xmax = 3.0,
    npoints = 100,
    x_scale = :linear,
    f_scale = :linear,
    metadata = Dict{String, Any}("a"=>1),
    metadata_validation_fn = metadata_validation_fn
) # reload the tabulation

While the library used for storing the tabulations (JLD2) should be able to serialise any dictionary passed as metadata, it is up to the user to properly create and validate the metadata.

Usage: 2D FunctionTabulations & 3D FunctionTabulations

2D FunctionTabulations and 3D FunctionTabulations have a similar syntax, with extra parameters for the y and z variables:

func_2d(x, y) = sin(x) * sin(y)

itp_2d_1 = create_tabulation_2D(
    func_2d,
    xmin = 0.0,
    xmax = 1.0,
    ymin = 0.0,
    ymax = 2.0,
    npoints_x = 100,
    npoints_y = 200,
    x_scale = :linear,
    y_scale = :linear,
    f_scale = :linear
)
isapprox(itp_2d_1(1.0, 1.3), func_2d(1.0, 1.3), rtol = 1e-3)
func_3d(x, y, z) = x * y + z

itp_3d_1 = create_tabulation_3D(
    func_3d,
    xmin = 0.0,
    xmax = 1.0,
    ymin = 0.0,
    ymax = 2.0,
    zmin = 0.0,
    zmax = 3.0,
    npoints_x = 100,
    npoints_y = 200,
    npoints_z = 200,
    x_scale = :linear,
    y_scale = :linear,
    z_scale = :linear,
    f_scale = :linear
)

isapprox(itp_3d_1(1.0, 1.3, 2.5), func_3d(1.0, 1.3, 2.5), rtol = 1e-3)