changeset 1019:3031ce7a4999 feature/stencil_set_type

Rename readoperator.jl to stencil_set.jl
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Tue, 22 Mar 2022 10:02:47 +0100
parents 5ec49dd2c7c4
children 99d1f5651d0b
files src/SbpOperators/SbpOperators.jl src/SbpOperators/readoperator.jl src/SbpOperators/stencil_set.jl test/SbpOperators/readoperator_test.jl test/SbpOperators/stencil_set_test.jl
diffstat 5 files changed, 337 insertions(+), 337 deletions(-) [+]
line wrap: on
line diff
--- a/src/SbpOperators/SbpOperators.jl	Tue Mar 22 09:57:28 2022 +0100
+++ b/src/SbpOperators/SbpOperators.jl	Tue Mar 22 10:02:47 2022 +0100
@@ -30,7 +30,7 @@
 end
 
 include("stencil.jl")
-include("readoperator.jl")
+include("stencil_set.jl")
 include("volumeops/volume_operator.jl")
 include("volumeops/constant_interior_scaling_operator.jl")
 include("volumeops/derivatives/first_derivative.jl")
--- a/src/SbpOperators/readoperator.jl	Tue Mar 22 09:57:28 2022 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-using TOML
-
-
-"""
-    StencilSet
-
-A `StencilSet` contains a set of associated stencils. The stencils
-are are stored in a table, and can be accesed by indexing into the `StencilSet`.
-"""
-struct StencilSet
-    table
-end
-Base.getindex(set::StencilSet,I...) = set.table[I...]
-
-
-"""
-read_stencil_set(filename; filters)
-
-Creates a `StencilSet` from a TOML file based on some key-value
-filters. If more than one set matches the filters an error is raised. The
-table of the `StencilSet` is a parsed TOML intended for functions like
-`parse_scalar` and `parse_stencil`.
-
-The `StencilSet` table is not parsed beyond the inital TOML parse. To get usable
-stencils use the `parse_stencil` functions on the fields of the stencil set.
-
-The reason for this is that since stencil sets are intended to be very
-general, and currently do not include any way to specify how to parse a given
-section, the exact parsing is left to the user.
-
-For more information see [Operator file format](@ref) in the documentation.
-
-See also [`StencilSet`](@ref), [`sbp_operators_path`](@ref), [`get_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref).
-"""
-read_stencil_set(filename; filters...) = StencilSet(get_stencil_set(TOML.parsefile(filename); filters...))
-
-
-"""
-    get_stencil_set(parsed_toml; filters...)
-
-Picks out a stencil set from an already parsed TOML based on some key-value
-filters.
-
-See also [`read_stencil_set`](@ref).
-"""
-function get_stencil_set(parsed_toml; filters...)
-    matches = findall(parsed_toml["stencil_set"]) do set
-        for (key, val) ∈ filters
-            if set[string(key)] != val
-                return false
-            end
-        end
-
-        return true
-    end
-
-    if length(matches) != 1
-        throw(ArgumentError("filters must pick out a single stencil set"))
-    end
-
-    i = matches[1]
-    return parsed_toml["stencil_set"][i]
-end
-
-"""
-    parse_stencil(parsed_toml)
-
-Accepts parsed TOML and reads it as a stencil.
-
-See also [`read_stencil_set`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref).
-"""
-function parse_stencil(parsed_toml)
-    check_stencil_toml(parsed_toml)
-
-    if parsed_toml isa Array
-        weights = parse_rational.(parsed_toml)
-        return CenteredStencil(weights...)
-    end
-
-    weights = parse_rational.(parsed_toml["s"])
-    return Stencil(weights..., center = parsed_toml["c"])
-end
-
-"""
-    parse_stencil(T, parsed_toml)
-
-Parses the input as a stencil with element type `T`.
-"""
-parse_stencil(T, parsed_toml) = Stencil{T}(parse_stencil(parsed_toml))
-
-function check_stencil_toml(parsed_toml)
-    if !(parsed_toml isa Dict || parsed_toml isa Vector{String})
-        throw(ArgumentError("the TOML for a stencil must be a vector of strings or a table."))
-    end
-
-    if parsed_toml isa Vector{String}
-        return
-    end
-
-    if !(haskey(parsed_toml, "s") && haskey(parsed_toml, "c"))
-        throw(ArgumentError("the table form of a stencil must have fields `s` and `c`."))
-    end
-
-    if !(parsed_toml["s"] isa Vector{String})
-        throw(ArgumentError("a stencil must be specified as a vector of strings."))
-    end
-
-    if !(parsed_toml["c"] isa Int)
-        throw(ArgumentError("the center of a stencil must be specified as an integer."))
-    end
-end
-
-"""
-    parse_scalar(parsed_toml)
-
-Parse a scalar, represented as a string or a number in the TOML, and return it as a `Rational`
-
-See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref) [`parse_tuple`](@ref).
-"""
-function parse_scalar(parsed_toml)
-    try
-        return parse_rational(parsed_toml)
-    catch e
-        throw(ArgumentError("must be a number or a string representing a number."))
-    end
-end
-
-"""
-    parse_tuple(parsed_toml)
-
-Parse an array as a tuple of scalars.
-
-See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref).
-"""
-function parse_tuple(parsed_toml)
-    if !(parsed_toml isa Array)
-        throw(ArgumentError("argument must be an array"))
-    end
-    return Tuple(parse_scalar.(parsed_toml))
-end
-
-
-"""
-    parse_rational(parsed_toml)
-
-Parse a string or a number as a rational.
-"""
-function parse_rational(parsed_toml)
-    if parsed_toml isa String
-        expr = Meta.parse(replace(parsed_toml, "/"=>"//"))
-        return eval(:(Rational($expr)))
-    else
-        return Rational(parsed_toml)
-    end
-end
-
-"""
-    sbp_operators_path()
-
-Calculate the path for the operators folder with included stencil sets.
-
-See also [`StencilSet`](@ref), [`read_stencil_set`](@ref).
-"""
-sbp_operators_path() = (@__DIR__) * "/operators/"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/SbpOperators/stencil_set.jl	Tue Mar 22 10:02:47 2022 +0100
@@ -0,0 +1,164 @@
+using TOML
+
+
+"""
+    StencilSet
+
+A `StencilSet` contains a set of associated stencils. The stencils
+are are stored in a table, and can be accesed by indexing into the `StencilSet`.
+"""
+struct StencilSet
+    table
+end
+Base.getindex(set::StencilSet,I...) = set.table[I...]
+
+
+"""
+read_stencil_set(filename; filters)
+
+Creates a `StencilSet` from a TOML file based on some key-value
+filters. If more than one set matches the filters an error is raised. The
+table of the `StencilSet` is a parsed TOML intended for functions like
+`parse_scalar` and `parse_stencil`.
+
+The `StencilSet` table is not parsed beyond the inital TOML parse. To get usable
+stencils use the `parse_stencil` functions on the fields of the stencil set.
+
+The reason for this is that since stencil sets are intended to be very
+general, and currently do not include any way to specify how to parse a given
+section, the exact parsing is left to the user.
+
+For more information see [Operator file format](@ref) in the documentation.
+
+See also [`StencilSet`](@ref), [`sbp_operators_path`](@ref), [`get_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref).
+"""
+read_stencil_set(filename; filters...) = StencilSet(get_stencil_set(TOML.parsefile(filename); filters...))
+
+
+"""
+    get_stencil_set(parsed_toml; filters...)
+
+Picks out a stencil set from an already parsed TOML based on some key-value
+filters.
+
+See also [`read_stencil_set`](@ref).
+"""
+function get_stencil_set(parsed_toml; filters...)
+    matches = findall(parsed_toml["stencil_set"]) do set
+        for (key, val) ∈ filters
+            if set[string(key)] != val
+                return false
+            end
+        end
+
+        return true
+    end
+
+    if length(matches) != 1
+        throw(ArgumentError("filters must pick out a single stencil set"))
+    end
+
+    i = matches[1]
+    return parsed_toml["stencil_set"][i]
+end
+
+"""
+    parse_stencil(parsed_toml)
+
+Accepts parsed TOML and reads it as a stencil.
+
+See also [`read_stencil_set`](@ref), [`parse_scalar`](@ref), [`parse_tuple`](@ref).
+"""
+function parse_stencil(parsed_toml)
+    check_stencil_toml(parsed_toml)
+
+    if parsed_toml isa Array
+        weights = parse_rational.(parsed_toml)
+        return CenteredStencil(weights...)
+    end
+
+    weights = parse_rational.(parsed_toml["s"])
+    return Stencil(weights..., center = parsed_toml["c"])
+end
+
+"""
+    parse_stencil(T, parsed_toml)
+
+Parses the input as a stencil with element type `T`.
+"""
+parse_stencil(T, parsed_toml) = Stencil{T}(parse_stencil(parsed_toml))
+
+function check_stencil_toml(parsed_toml)
+    if !(parsed_toml isa Dict || parsed_toml isa Vector{String})
+        throw(ArgumentError("the TOML for a stencil must be a vector of strings or a table."))
+    end
+
+    if parsed_toml isa Vector{String}
+        return
+    end
+
+    if !(haskey(parsed_toml, "s") && haskey(parsed_toml, "c"))
+        throw(ArgumentError("the table form of a stencil must have fields `s` and `c`."))
+    end
+
+    if !(parsed_toml["s"] isa Vector{String})
+        throw(ArgumentError("a stencil must be specified as a vector of strings."))
+    end
+
+    if !(parsed_toml["c"] isa Int)
+        throw(ArgumentError("the center of a stencil must be specified as an integer."))
+    end
+end
+
+"""
+    parse_scalar(parsed_toml)
+
+Parse a scalar, represented as a string or a number in the TOML, and return it as a `Rational`
+
+See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref) [`parse_tuple`](@ref).
+"""
+function parse_scalar(parsed_toml)
+    try
+        return parse_rational(parsed_toml)
+    catch e
+        throw(ArgumentError("must be a number or a string representing a number."))
+    end
+end
+
+"""
+    parse_tuple(parsed_toml)
+
+Parse an array as a tuple of scalars.
+
+See also [`read_stencil_set`](@ref), [`parse_stencil`](@ref), [`parse_scalar`](@ref).
+"""
+function parse_tuple(parsed_toml)
+    if !(parsed_toml isa Array)
+        throw(ArgumentError("argument must be an array"))
+    end
+    return Tuple(parse_scalar.(parsed_toml))
+end
+
+
+"""
+    parse_rational(parsed_toml)
+
+Parse a string or a number as a rational.
+"""
+function parse_rational(parsed_toml)
+    if parsed_toml isa String
+        expr = Meta.parse(replace(parsed_toml, "/"=>"//"))
+        return eval(:(Rational($expr)))
+    else
+        return Rational(parsed_toml)
+    end
+end
+
+"""
+    sbp_operators_path()
+
+Calculate the path for the operators folder with included stencil sets.
+
+See also [`StencilSet`](@ref), [`read_stencil_set`](@ref).
+"""
+sbp_operators_path() = (@__DIR__) * "/operators/"
--- a/test/SbpOperators/readoperator_test.jl	Tue Mar 22 09:57:28 2022 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-using Test
-
-using TOML
-using Sbplib.SbpOperators
-
-import Sbplib.SbpOperators.Stencil
-
-@testset "readoperator" begin
-    toml_str = """
-        [meta]
-        authors = "Ken Mattson"
-        description = "Standard operators for equidistant grids"
-        type = "equidistant"
-        cite = "A paper a long time ago in a galaxy far far away."
-
-        [[stencil_set]]
-
-        order = 2
-        test = 2
-
-        H.inner = ["1"]
-        H.closure = ["1/2"]
-
-        D1.inner_stencil = ["-1/2", "0", "1/2"]
-        D1.closure_stencils = [
-            {s = ["-1", "1"], c = 1},
-        ]
-
-        D2.inner_stencil = ["1", "-2", "1"]
-        D2.closure_stencils = [
-            {s = ["1", "-2", "1"], c = 1},
-        ]
-
-        e.closure = ["1"]
-        d1.closure = {s = ["-3/2", "2", "-1/2"], c = 1}
-
-        [[stencil_set]]
-
-        order = 4
-        test = 1
-        H.inner = ["1"]
-        H.closure = ["17/48", "59/48", "43/48", "49/48"]
-
-        D2.inner_stencil = ["-1/12","4/3","-5/2","4/3","-1/12"]
-        D2.closure_stencils = [
-            {s = [     "2",    "-5",      "4",       "-1",     "0",     "0"], c = 1},
-            {s = [     "1",    "-2",      "1",        "0",     "0",     "0"], c = 2},
-            {s = [ "-4/43", "59/43", "-110/43",   "59/43", "-4/43",     "0"], c = 3},
-            {s = [ "-1/49",     "0",   "59/49", "-118/49", "64/49", "-4/49"], c = 4},
-        ]
-
-        e.closure = ["1"]
-        d1.closure = {s = ["-11/6", "3", "-3/2", "1/3"], c = 1}
-
-        [[stencil_set]]
-        order = 4
-        test = 2
-
-        H.closure = ["-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"]
-    """
-
-    parsed_toml = TOML.parse(toml_str)
-
-    @testset "get_stencil_set" begin
-        @test get_stencil_set(parsed_toml; order = 2) isa Dict
-        @test get_stencil_set(parsed_toml; order = 2) == parsed_toml["stencil_set"][1]
-        @test get_stencil_set(parsed_toml; test = 1) == parsed_toml["stencil_set"][2]
-        @test get_stencil_set(parsed_toml; order = 4, test = 2) == parsed_toml["stencil_set"][3]
-
-        @test_throws ArgumentError get_stencil_set(parsed_toml; test = 2)
-        @test_throws ArgumentError get_stencil_set(parsed_toml; order = 4)
-    end
-
-    @testset "parse_stencil" begin
-        toml = """
-            s1 = ["-1/12","4/3","-5/2","4/3","-1/12"]
-            s2 = {s = ["2", "-5", "4", "-1", "0", "0"], c = 1}
-            s3 = {s = ["1", "-2", "1", "0", "0", "0"], c = 2}
-            s4 = "not a stencil"
-            s5 = [-1, 4, 3]
-            s6 = {k = ["1", "-2", "1", "0", "0", "0"], c = 2}
-            s7 = {s = [-1, 4, 3], c = 2}
-            s8 = {s = ["1", "-2", "1", "0", "0", "0"], c = [2,2]}
-        """
-
-        @test parse_stencil(TOML.parse(toml)["s1"]) == CenteredStencil(-1//12, 4//3, -5//2, 4//3, -1//12)
-        @test parse_stencil(TOML.parse(toml)["s2"]) == Stencil(2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1)
-        @test parse_stencil(TOML.parse(toml)["s3"]) == Stencil(1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2)
-
-        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s4"])
-        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s5"])
-        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s6"])
-        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s7"])
-        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s8"])
-
-        stencil_set = get_stencil_set(parsed_toml; order = 4, test = 1)
-
-        @test parse_stencil.(stencil_set["D2"]["closure_stencils"]) == [
-            Stencil(  2//1,  -5//1,     4//1,    -1//1,   0//1,   0//1; center=1),
-            Stencil(  1//1,  -2//1,     1//1,     0//1,   0//1,   0//1; center=2),
-            Stencil(-4//43, 59//43, -110//43,   59//43, -4//43,   0//1; center=3),
-            Stencil(-1//49,   0//1,   59//49, -118//49, 64//49, -4//49; center=4),
-        ]
-
-
-        @test parse_stencil(Float64, TOML.parse(toml)["s1"]) == CenteredStencil(-1/12, 4/3, -5/2, 4/3, -1/12)
-        @test parse_stencil(Float64, TOML.parse(toml)["s2"]) == Stencil(2/1, -5/1, 4/1, -1/1, 0/1, 0/1; center=1)
-        @test parse_stencil(Float64, TOML.parse(toml)["s3"]) == Stencil(1/1, -2/1, 1/1, 0/1, 0/1, 0/1; center=2)
-    end
-
-    @testset "parse_scalar" begin
-        toml = TOML.parse("""
-            a1 = 1
-            a2 = 1.5
-            a3 = 1.0
-            a4 = 10
-            a5 = "1/2"
-            a6 = "1.5"
-
-            e1 = [1,2,3]
-            e2 = "a string value"
-        """)
-
-        @test parse_scalar(toml["a1"]) == 1//1
-        @test parse_scalar(toml["a2"]) == 3//2
-        @test parse_scalar(toml["a3"]) == 1//1
-        @test parse_scalar(toml["a4"]) == 10//1
-        @test parse_scalar(toml["a5"]) == 1//2
-        @test parse_scalar(toml["a6"]) == 3//2
-
-        @test_throws ArgumentError parse_scalar(toml["e1"])
-        @test_throws ArgumentError parse_scalar(toml["e2"])
-    end
-
-    @testset "parse_tuple" begin
-        toml = TOML.parse("""
-            t1 = [1,3,4]
-            t2 = ["1/2","3/4","2/1"]
-
-            e1 = "not a tuple"
-            e2.a="1"
-            e3 = 1
-            e4 = ["1/2","3/4","not a number"]
-        """)
-
-        @test parse_tuple(toml["t1"]) == (1//1,3//1,4//1)
-        @test parse_tuple(toml["t2"]) == (1//2,3//4,2//1)
-
-        @test_throws ArgumentError parse_tuple(toml["e1"])
-        @test_throws ArgumentError parse_tuple(toml["e2"])
-        @test_throws ArgumentError parse_tuple(toml["e3"])
-        @test_throws ArgumentError parse_tuple(toml["e4"])
-    end
-end
-
-@testset "parse_rational" begin
-    @test SbpOperators.parse_rational("1") isa Rational
-    @test SbpOperators.parse_rational("1") == 1//1
-    @test SbpOperators.parse_rational("1/2") isa Rational
-    @test SbpOperators.parse_rational("1/2") == 1//2
-    @test SbpOperators.parse_rational("37/13") isa Rational
-    @test SbpOperators.parse_rational("37/13") == 37//13
-
-    @test SbpOperators.parse_rational(0.5) isa Rational
-    @test SbpOperators.parse_rational(0.5) == 1//2
-
-    @test SbpOperators.parse_rational("0.5") isa Rational
-    @test SbpOperators.parse_rational("0.5") == 1//2
-
-    @test SbpOperators.parse_rational(2) isa Rational
-    @test SbpOperators.parse_rational(2) == 2//1
-end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/SbpOperators/stencil_set_test.jl	Tue Mar 22 10:02:47 2022 +0100
@@ -0,0 +1,172 @@
+using Test
+
+using TOML
+using Sbplib.SbpOperators
+
+import Sbplib.SbpOperators.Stencil
+
+@testset "readoperator" begin
+    toml_str = """
+        [meta]
+        authors = "Ken Mattson"
+        description = "Standard operators for equidistant grids"
+        type = "equidistant"
+        cite = "A paper a long time ago in a galaxy far far away."
+
+        [[stencil_set]]
+
+        order = 2
+        test = 2
+
+        H.inner = ["1"]
+        H.closure = ["1/2"]
+
+        D1.inner_stencil = ["-1/2", "0", "1/2"]
+        D1.closure_stencils = [
+            {s = ["-1", "1"], c = 1},
+        ]
+
+        D2.inner_stencil = ["1", "-2", "1"]
+        D2.closure_stencils = [
+            {s = ["1", "-2", "1"], c = 1},
+        ]
+
+        e.closure = ["1"]
+        d1.closure = {s = ["-3/2", "2", "-1/2"], c = 1}
+
+        [[stencil_set]]
+
+        order = 4
+        test = 1
+        H.inner = ["1"]
+        H.closure = ["17/48", "59/48", "43/48", "49/48"]
+
+        D2.inner_stencil = ["-1/12","4/3","-5/2","4/3","-1/12"]
+        D2.closure_stencils = [
+            {s = [     "2",    "-5",      "4",       "-1",     "0",     "0"], c = 1},
+            {s = [     "1",    "-2",      "1",        "0",     "0",     "0"], c = 2},
+            {s = [ "-4/43", "59/43", "-110/43",   "59/43", "-4/43",     "0"], c = 3},
+            {s = [ "-1/49",     "0",   "59/49", "-118/49", "64/49", "-4/49"], c = 4},
+        ]
+
+        e.closure = ["1"]
+        d1.closure = {s = ["-11/6", "3", "-3/2", "1/3"], c = 1}
+
+        [[stencil_set]]
+        order = 4
+        test = 2
+
+        H.closure = ["-1/49", "0", "59/49", "-118/49", "64/49", "-4/49"]
+    """
+
+    parsed_toml = TOML.parse(toml_str)
+
+    @testset "get_stencil_set" begin
+        @test get_stencil_set(parsed_toml; order = 2) isa Dict
+        @test get_stencil_set(parsed_toml; order = 2) == parsed_toml["stencil_set"][1]
+        @test get_stencil_set(parsed_toml; test = 1) == parsed_toml["stencil_set"][2]
+        @test get_stencil_set(parsed_toml; order = 4, test = 2) == parsed_toml["stencil_set"][3]
+
+        @test_throws ArgumentError get_stencil_set(parsed_toml; test = 2)
+        @test_throws ArgumentError get_stencil_set(parsed_toml; order = 4)
+    end
+
+    @testset "parse_stencil" begin
+        toml = """
+            s1 = ["-1/12","4/3","-5/2","4/3","-1/12"]
+            s2 = {s = ["2", "-5", "4", "-1", "0", "0"], c = 1}
+            s3 = {s = ["1", "-2", "1", "0", "0", "0"], c = 2}
+            s4 = "not a stencil"
+            s5 = [-1, 4, 3]
+            s6 = {k = ["1", "-2", "1", "0", "0", "0"], c = 2}
+            s7 = {s = [-1, 4, 3], c = 2}
+            s8 = {s = ["1", "-2", "1", "0", "0", "0"], c = [2,2]}
+        """
+
+        @test parse_stencil(TOML.parse(toml)["s1"]) == CenteredStencil(-1//12, 4//3, -5//2, 4//3, -1//12)
+        @test parse_stencil(TOML.parse(toml)["s2"]) == Stencil(2//1, -5//1, 4//1, -1//1, 0//1, 0//1; center=1)
+        @test parse_stencil(TOML.parse(toml)["s3"]) == Stencil(1//1, -2//1, 1//1, 0//1, 0//1, 0//1; center=2)
+
+        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s4"])
+        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s5"])
+        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s6"])
+        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s7"])
+        @test_throws ArgumentError parse_stencil(TOML.parse(toml)["s8"])
+
+        stencil_set = get_stencil_set(parsed_toml; order = 4, test = 1)
+
+        @test parse_stencil.(stencil_set["D2"]["closure_stencils"]) == [
+            Stencil(  2//1,  -5//1,     4//1,    -1//1,   0//1,   0//1; center=1),
+            Stencil(  1//1,  -2//1,     1//1,     0//1,   0//1,   0//1; center=2),
+            Stencil(-4//43, 59//43, -110//43,   59//43, -4//43,   0//1; center=3),
+            Stencil(-1//49,   0//1,   59//49, -118//49, 64//49, -4//49; center=4),
+        ]
+
+
+        @test parse_stencil(Float64, TOML.parse(toml)["s1"]) == CenteredStencil(-1/12, 4/3, -5/2, 4/3, -1/12)
+        @test parse_stencil(Float64, TOML.parse(toml)["s2"]) == Stencil(2/1, -5/1, 4/1, -1/1, 0/1, 0/1; center=1)
+        @test parse_stencil(Float64, TOML.parse(toml)["s3"]) == Stencil(1/1, -2/1, 1/1, 0/1, 0/1, 0/1; center=2)
+    end
+
+    @testset "parse_scalar" begin
+        toml = TOML.parse("""
+            a1 = 1
+            a2 = 1.5
+            a3 = 1.0
+            a4 = 10
+            a5 = "1/2"
+            a6 = "1.5"
+
+            e1 = [1,2,3]
+            e2 = "a string value"
+        """)
+
+        @test parse_scalar(toml["a1"]) == 1//1
+        @test parse_scalar(toml["a2"]) == 3//2
+        @test parse_scalar(toml["a3"]) == 1//1
+        @test parse_scalar(toml["a4"]) == 10//1
+        @test parse_scalar(toml["a5"]) == 1//2
+        @test parse_scalar(toml["a6"]) == 3//2
+
+        @test_throws ArgumentError parse_scalar(toml["e1"])
+        @test_throws ArgumentError parse_scalar(toml["e2"])
+    end
+
+    @testset "parse_tuple" begin
+        toml = TOML.parse("""
+            t1 = [1,3,4]
+            t2 = ["1/2","3/4","2/1"]
+
+            e1 = "not a tuple"
+            e2.a="1"
+            e3 = 1
+            e4 = ["1/2","3/4","not a number"]
+        """)
+
+        @test parse_tuple(toml["t1"]) == (1//1,3//1,4//1)
+        @test parse_tuple(toml["t2"]) == (1//2,3//4,2//1)
+
+        @test_throws ArgumentError parse_tuple(toml["e1"])
+        @test_throws ArgumentError parse_tuple(toml["e2"])
+        @test_throws ArgumentError parse_tuple(toml["e3"])
+        @test_throws ArgumentError parse_tuple(toml["e4"])
+    end
+end
+
+@testset "parse_rational" begin
+    @test SbpOperators.parse_rational("1") isa Rational
+    @test SbpOperators.parse_rational("1") == 1//1
+    @test SbpOperators.parse_rational("1/2") isa Rational
+    @test SbpOperators.parse_rational("1/2") == 1//2
+    @test SbpOperators.parse_rational("37/13") isa Rational
+    @test SbpOperators.parse_rational("37/13") == 37//13
+
+    @test SbpOperators.parse_rational(0.5) isa Rational
+    @test SbpOperators.parse_rational(0.5) == 1//2
+
+    @test SbpOperators.parse_rational("0.5") isa Rational
+    @test SbpOperators.parse_rational("0.5") == 1//2
+
+    @test SbpOperators.parse_rational(2) isa Rational
+    @test SbpOperators.parse_rational(2) == 2//1
+end