diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml new file mode 100644 index 0000000..2529fde --- /dev/null +++ b/.github/workflows/Documentation.yml @@ -0,0 +1,27 @@ +name: Documentation + +on: + push: + branches: + - main # update to match your development branch (master, main, dev, trunk, ...) + tags: '*' + pull_request: + +jobs: + build: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - uses: julia-actions/cache@v2 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: '1.12' + - uses: julia-actions/julia-buildpkg@v1 + - name: Install dependencies + run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - name: Build and deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token + run: julia --color=yes --project=docs/ docs/make.jl diff --git a/.gitignore b/.gitignore index ba39cc5..42a25a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ Manifest.toml +docs/build \ No newline at end of file diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..665298e --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,3 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +TabularFunctions = "7add9882-6fce-4afb-882d-af036a41bc9c" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..09e7e08 --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,40 @@ +using Documenter +using TabularFunctions + +DocMeta.setdocmeta!(TabularFunctions, :DocTestSetup, :(using TabularFunctions); recursive=true) +# meshes_ext = Base.get_extension(Exodus, :ExodusMeshesExt) +# unitful_ext = Base.get_extension(Exodus, :ExodusUnitfulExt) +makedocs(; + # modules=[Exodus, meshes_ext, unitful_ext], + modules=[TabularFunctions], + authors="Craig M. Hamel and contributors", + repo="https://github.com/cthonios/TabularFunctions.jl/blob/{commit}{path}#{line}", + sitename="TabularFunctions.jl", + format=Documenter.HTML(; + prettyurls=get(ENV, "CI", "false") == "true", + canonical="https://cthonios.github.io/TabularFunctions.jl/stable", + edit_link="main", + assets=String[], + size_threshold=nothing + ), + pages=[ + # "Exodus" => "index.md", + # "Installation" => "installation.md", + # "Opening Files" => "opening_files.md", + # "Reading Data" => "reading_data.md", + # "Writing Data" => "writing_data.md", + # "Use With MPI" => "use_with_mpi.md", + # "Exodus Methods" => "methods.md", + # "Exodus Types" => "types.md", + # "ExodusMeshesExt" => "meshes_ext.md", + # "ExodusUnitfulExt" => "unitful_ext.md", + # "Glossary" => "glossary.md" + # "README" => "../README.md" + "TabularFunctions" => "index.md" + ], +) + +deploydocs(; + repo="github.com/cthonios/TabularFunctions.jl", + devbranch="main" +) diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..6e335df --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,145 @@ +# TabularFunctions.jl + +## Description +This is a small package to help define julia functions via +either tabular data, e.g. (x, y) pairs, or tables of functions +to aid in simply writing piecewise analytic functions. + +## Installation +Currently ```TabularFunctions.jl``` has not been registered. To install, one +can do the following in the package manager +```julia +pkg> add https://github.com/Cthonios/TabularFunctions.jl/ +``` + +## Future installation instructions +From the package manager simply type +```julia +pkg> add TabularFunctions +``` + +Or from the REPL +```julia +julia> using Pkg +julia> Pkg.add("TabularFunctions") +``` + +# Examples + +## PiecewiseAnalyticFunction +Suppose we like to define a piecewise analytic function such that +$$ +f(x) = +\begin{cases} +x, & \text{if } x < 1 \\ +x^2, & \text{if } x \ge 1 +\end{cases} +$$ + +then we can use the maco ```@piecewise_analytic``` to define the above function as follows + +```jldoctest analytic +using TabularFunctions +func = @piecewise_analytic begin + 0.0, x -> x + 1.0, x -> x^2 +end; +nothing +# output + +``` + +and this can be used like a regular julia function as follows +```jldoctest analytic +x = 0.5 +y = func(x) + +# output +0.5 +``` + +```jldoctest analytic +x = 1.5 +y = func(x) + +# output +2.25 +``` + +Note that closures are not necessary in the macro definition. The following is also valid syntax for the ```@piecewise_analytic``` macro +```jldoctest; output=false +using TabularFunctions +func = @piecewise_analytic begin + 0.0, sin + 1.0, cos +end +nothing + +# output + +``` + +## PiecewiseLinearFunction +If instead you need to define a function simply from sparse tabular data, you can use the ```@piecewise_linear``` macro. This creates a simple function that will exactly reproduce values at the supplied points and linearly interpolate when provided with values between those points. If the provided input lies outside the bounds, the lower or upper bound is returned respectively. An example of a triangle wave is shown below + +```jldoctest linear +using TabularFunctions +func = @piecewise_linear begin + 0.0, 0.0 + 0.5, 1.0 + 1.0, 0.0 +end +nothing + +# output + +``` + +```jldoctest linear +x = -1.0 +y = func(x) +# output +0.0 +``` +```jldoctest linear +x = 0.0 +y = func(x) +# output +0.0 +``` +```jldoctest linear +x = 0.25 +y = func(x) +# output +0.5 +``` +```jldoctest linear +x = 0.5 +y = func(x) +# output +1.0 +``` +```jldoctest linear +x = 0.75 +y = func(x) +# output +0.5 +``` +```jldoctest linear +x = 1.0 +y = func(x) +# output +0.0 +``` +```jldoctest linear +x = 2.0 +y = func(x) +# output +0.0 +``` + +# Reference +```@autodocs +Modules = [TabularFunctions] +Order = [:module, :type, :function, :macro] +``` diff --git a/src/TabularFunctions.jl b/src/TabularFunctions.jl index 8e52cb4..ff4f0a2 100644 --- a/src/TabularFunctions.jl +++ b/src/TabularFunctions.jl @@ -10,6 +10,10 @@ using DocStringExtensions using KernelAbstractions # Error helpers +""" +$(TYPEDEF) +$(TYPEDFIELDS) +""" struct XsNotMonotonicallyIncreasing <: Exception end @@ -22,24 +26,35 @@ function _monotonic_error() end # Abstract types +""" +$(TYPEDEF) +""" abstract type AbstractTabularFunction{ V <: AbstractVector{<:Number} } end - +""" +$(TYPEDSIGNATURES) +""" function KernelAbstractions.get_backend(f::AbstractTabularFunction) return get_backend(f.x_vals) end +""" +$(TYPEDEF) +$(TYPEDFIELDS) +""" struct PiecewiseAnalyticFunction{ V <: AbstractVector{<:Number}, - # Funcs <: NamedTuple Funcs } <: AbstractTabularFunction{V} x_vals::V funcs::Funcs end +""" +$(TYPEDSIGNATURES) +""" function PiecewiseAnalyticFunction( xs::V, funcs::Funcs ) where { @@ -60,6 +75,9 @@ function PiecewiseAnalyticFunction( return PiecewiseAnalyticFunction(xs, funcs) end +""" +$(TYPEDSIGNATURES) +""" function Adapt.adapt_structure(to, func::PiecewiseAnalyticFunction) return PiecewiseAnalyticFunction( adapt(to, func.x_vals), @@ -78,6 +96,9 @@ function _func(func::PiecewiseAnalyticFunction, x, ::CPU) end end +""" +$(TYPEDSIGNATURES) +""" function (func::PiecewiseAnalyticFunction{V1, Funcs})(x::T) where { T <: Number, V1 <: AbstractVector{T}, @@ -87,6 +108,10 @@ function (func::PiecewiseAnalyticFunction{V1, Funcs})(x::T) where { end # Piecewise Linear +""" +$(TYPEDEF) +$(TYPEDFIELDS) +""" struct PiecewiseLinearFunction{ V1 <: AbstractVector{<:Number}, V2 <: AbstractVector{<:Number} @@ -113,6 +138,9 @@ struct PiecewiseLinearFunction{ end end +""" +$(TYPEDSIGNATURES) +""" function Adapt.adapt_structure(to, f::PiecewiseLinearFunction) return PiecewiseLinearFunction( adapt(to, f.x_vals), @@ -154,6 +182,9 @@ function _func(func, x, ::Backend) # kernel!(func, x, ndrange = length(func.x_vals) + 1) end +""" +$(TYPEDSIGNATURES) +""" function (func::PiecewiseLinearFunction{V1, V2})(x::T) where { T <: Number, V1 <: AbstractVector{T}, @@ -172,6 +203,23 @@ function _is_number_expr(ex) return ex isa Number end +""" +$(TYPEDSIGNATURES) +Example: +Define a function that switches between a linear and quadratic function +```jldoctest +func = @piecewise_analytic begin + 0.0, x -> x + 1.0, x -> x^2 +end + +func(0.) + +# output +0.0 + +``` +""" macro piecewise_analytic(expr) # Extract expressions inside the block lines = expr isa Expr && expr.head == :block ? expr.args : [expr] @@ -204,6 +252,18 @@ macro piecewise_analytic(expr) # end end +""" +$(TYPEDSIGNATURES) +Example: +Define a triangular wave of a single period +```julia +func = @piecewise_linear begin + 0.0, 0.0 + 0.5, 1.0 + 1.0, 0.0 +end +``` +""" macro piecewise_linear(expr) # Get the expressions inside the block pairs = expr isa Expr && expr.head == :block ? expr.args : [expr]