diff --git a/Manifest.toml b/Manifest.toml
index 29b2bbfdf36df5445385c51d504ae12052560b6a..576c4eb541f0f5fe72228f26b0b546d72fd75a22 100644
--- a/Manifest.toml
+++ b/Manifest.toml
@@ -2,7 +2,7 @@
 
 julia_version = "1.10.0-rc2"
 manifest_format = "2.0"
-project_hash = "4772e5e6caf338d2c755b5d4461c2d0c5c7482c5"
+project_hash = "7e9cb4087253abe43f5a39d1ae318381c828bb4b"
 
 [[deps.Adapt]]
 deps = ["LinearAlgebra", "Requires"]
@@ -46,6 +46,12 @@ uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
 [[deps.Base64]]
 uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
 
+[[deps.BasicInterpolators]]
+deps = ["LinearAlgebra", "Memoize", "Random"]
+git-tree-sha1 = "3f7be532673fc4a22825e7884e9e0e876236b12a"
+uuid = "26cce99e-4866-4b6d-ab74-862489e035e0"
+version = "0.7.1"
+
 [[deps.BitTwiddlingConvenienceFunctions]]
 deps = ["Static"]
 git-tree-sha1 = "0c5f81f47bbbcf4aea7b2959135713459170798b"
@@ -409,6 +415,12 @@ deps = ["Artifacts", "Libdl"]
 uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
 version = "2.28.2+1"
 
+[[deps.Memoize]]
+deps = ["MacroTools"]
+git-tree-sha1 = "2b1dfcba103de714d31c033b5dacc2e4a12c7caa"
+uuid = "c03570c3-d221-55d1-a50c-7939bbd78826"
+version = "0.4.4"
+
 [[deps.MicrosoftMPI_jll]]
 deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
 git-tree-sha1 = "b01beb91d20b0d1312a9471a36017b5b339d26de"
diff --git a/Project.toml b/Project.toml
index 2db747a55670b6b48e24a528b4641dd5a2a741b2..587cbd461b485914a9db01b213a337fa7cf3d610 100644
--- a/Project.toml
+++ b/Project.toml
@@ -5,6 +5,7 @@ version = "1.2.0"
 
 [deps]
 Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
+BasicInterpolators = "26cce99e-4866-4b6d-ab74-862489e035e0"
 FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
 HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
 Jacobi = "83f21c0b-4282-5fbc-9e3f-f6da3d2e584c"
@@ -27,12 +28,12 @@ ToggleableAsserts = "07ecc579-1b30-493c-b961-3180daf6e3ae"
 WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192"
 
 [compat]
-julia = "1.9"
 PrettyTables = "<2.3.0"
+julia = "1.9"
 
 [extras]
-Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
 InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
+Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
 
 [targets]
-test = ["Test","InteractiveUtils"]
+test = ["Test", "InteractiveUtils"]
diff --git a/examples/grhd_bondi/dg.toml b/examples/grhd_bondi/dg.toml
new file mode 100644
index 0000000000000000000000000000000000000000..c0bc7dad27076cdd7c97a986fed7e13581e7d241
--- /dev/null
+++ b/examples/grhd_bondi/dg.toml
@@ -0,0 +1,28 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 0.02143872868864732
+polytrope_gamma = "$(4/3)"
+
+[GRHD]
+bc = "from_id"
+id = "bondi_accretion"
+id_filename = "$(joinpath(ROOTDIR,\"initialdata\",\"bondi_accretion.h5\"))"
+# formulation = "spherical1d"
+
+[Mesh]
+range = [ 1.8, 10.0 ]
+n = 4
+k = 35
+basis = "lgl"
+periodic = false
+
+[Output]
+every_iteration = 1
+# every_dt  = 0.1
+variables = [ "D", "Sr", "τ", "p", "ρ", "ϵ", "vr", "rhs_D", "rhs_Sr", "rhs_τ", "src_D", "src_Sr", "src_τ" ]
+# aligned_ts      = "$(collect(range(0.01,0.6,step=0.01)))"
+enable1d  = true
+
+[Evolution]
+cfl = 0.4
+tend = 20.0
diff --git a/examples/grhd_bondi/fv.toml b/examples/grhd_bondi/fv.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7577160c717365a34ffc8aae85d38e57e204cd80
--- /dev/null
+++ b/examples/grhd_bondi/fv.toml
@@ -0,0 +1,25 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 0.02143872868864732
+polytrope_gamma = "$(4/3)"
+
+[GRHD]
+bc = "from_id"
+id = "bondi_accretion"
+id_filename = """$(joinpath(ROOTDIR,"initialdata","bondi_accretion.h5"))"""
+
+[Mesh]
+range = [ 1.8, 10.0 ]
+k = 1024
+scheme = "FV"
+periodic = false
+
+[Output]
+every_iteration = 1
+variables       = [ "D", "Sr", "τ", "p", "ρ", "ϵ", "vr", "rhs_D", "rhs_Sr", "rhs_τ", "src_D", "src_Sr", "src_τ" ]
+# aligned_ts      = "$(collect(range(0.01,0.6,step=0.01)))"
+enable1d        = true
+
+[Evolution]
+cfl = 1.0
+tend = 20.0
diff --git a/examples/grhd_tov/dg.toml b/examples/grhd_tov/dg.toml
new file mode 100644
index 0000000000000000000000000000000000000000..13c0f2869bd4850c29c8cf332a33b0499cd82144
--- /dev/null
+++ b/examples/grhd_tov/dg.toml
@@ -0,0 +1,35 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 100.0
+polytrope_gamma = 2.0
+
+[GRHD]
+bc = "from_id"
+id = "tov"
+id_filename = "$(joinpath(ROOTDIR,\"initialdata\",\"TOV_stable.h5\"))"
+atm_factor = 1e-8
+
+[Mesh]
+range = [ 0.5, 20.0 ]
+n = 1
+k = 2048
+basis = "lgl"
+periodic = false
+
+[Output]
+# every_iteration = 1
+every_dt  = 0.2
+variables = [ "D", "Sr", "Ï„",
+              "p", "ρ", "ϵ", "vr",
+              # "rD", "rSr", "rτ",
+              # "rhs_rD", "rhs_rSr", "rhs_rτ",
+              # "src_rD", "src_rSr", "src_rτ",
+              # "flr_rD", "flr_rSr", "flr_rτ",
+              # "A", "∂Ar", "B", "∂Br"
+              ]
+# aligned_ts      = "$(collect(range(0.01,0.6,step=0.01)))"
+enable1d  = true
+
+[Evolution]
+cfl = 0.2
+tend = 40.0
diff --git a/examples/grhd_tov/dg_spherical1d.toml b/examples/grhd_tov/dg_spherical1d.toml
new file mode 100644
index 0000000000000000000000000000000000000000..336c21a26b9e82d11c8ddbbeb482c66010f464d9
--- /dev/null
+++ b/examples/grhd_tov/dg_spherical1d.toml
@@ -0,0 +1,36 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 100.0
+polytrope_gamma = 2.0
+
+[GRHD]
+bc = "from_id"
+id = "tov"
+id_filename = "$(joinpath(ROOTDIR,\"initialdata\",\"TOV_stable.h5\"))"
+atm_factor = 1e-8
+formulation = "spherical1d"
+
+[Mesh]
+range = [ 0.5, 20.0 ]
+# n = 1
+# k = 2048
+n = 4
+k = 124
+basis = "lgl"
+periodic = false
+
+[Output]
+# every_iteration = 1
+# every_dt  = 0.2
+variables = [ "D", "Sr", "Ï„",
+              "p", "ρ", "ϵ", "vr",
+              "src_D", "src_Sr", "src_Ï„",
+              "flr_D", "flr_Sr", "flr_Ï„",
+              # "A", "∂Ar", "B", "∂Br"
+              ]
+aligned_ts      = "$(collect(range(0.2,120.0,step=0.2)))"
+enable1d  = true
+
+[Evolution]
+cfl = 0.2
+tend = 120.0
diff --git a/initialdata/.gitignore b/initialdata/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..29338d3be317b4168da766017947c8868c110fd9
--- /dev/null
+++ b/initialdata/.gitignore
@@ -0,0 +1,2 @@
+SphericalAccretion
+*.txt
diff --git a/initialdata/Makefile b/initialdata/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..cda6cb9bb4739863230ea34526d833a803def9e8
--- /dev/null
+++ b/initialdata/Makefile
@@ -0,0 +1,5 @@
+default:
+	gcc SphericalAccretion.c -o SphericalAccretion -lm
+
+clean:
+	rm SphericalAccretion bondi-acc-ref.txt
diff --git a/initialdata/Manifest.toml b/initialdata/Manifest.toml
new file mode 100644
index 0000000000000000000000000000000000000000..80311f4944c7ef8d6de082712794a3d517a8a90a
--- /dev/null
+++ b/initialdata/Manifest.toml
@@ -0,0 +1,2181 @@
+# This file is machine-generated - editing it directly is not advised
+
+julia_version = "1.10.0-rc2"
+manifest_format = "2.0"
+project_hash = "5dbed5c8ef2f569ca843e8145ef3d50a3796d9b5"
+
+[[deps.ADTypes]]
+git-tree-sha1 = "41c37aa88889c171f1300ceac1313c06e891d245"
+uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
+version = "0.2.6"
+
+[[deps.AbstractFFTs]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "d92ad398961a3ed262d8bf04a1a2b8340f915fef"
+uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
+version = "1.5.0"
+weakdeps = ["ChainRulesCore", "Test"]
+
+    [deps.AbstractFFTs.extensions]
+    AbstractFFTsChainRulesCoreExt = "ChainRulesCore"
+    AbstractFFTsTestExt = "Test"
+
+[[deps.AbstractLattices]]
+git-tree-sha1 = "222ee9e50b98f51b5d78feb93dd928880df35f06"
+uuid = "398f06c4-4d28-53ec-89ca-5b2656b7603d"
+version = "0.3.0"
+
+[[deps.AbstractTrees]]
+git-tree-sha1 = "faa260e4cb5aba097a73fab382dd4b5819d8ec8c"
+uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
+version = "0.4.4"
+
+[[deps.Adapt]]
+deps = ["LinearAlgebra", "Requires"]
+git-tree-sha1 = "cde29ddf7e5726c9fb511f340244ea3481267608"
+uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
+version = "3.7.2"
+weakdeps = ["StaticArrays"]
+
+    [deps.Adapt.extensions]
+    AdaptStaticArraysExt = "StaticArrays"
+
+[[deps.Animations]]
+deps = ["Colors"]
+git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d"
+uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340"
+version = "0.4.1"
+
+[[deps.ArgTools]]
+uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
+version = "1.1.1"
+
+[[deps.ArnoldiMethod]]
+deps = ["LinearAlgebra", "Random", "StaticArrays"]
+git-tree-sha1 = "62e51b39331de8911e4a7ff6f5aaf38a5f4cc0ae"
+uuid = "ec485272-7323-5ecc-a04f-4719b315124d"
+version = "0.2.0"
+
+[[deps.ArrayInterface]]
+deps = ["Adapt", "LinearAlgebra", "Requires", "SparseArrays", "SuiteSparse"]
+git-tree-sha1 = "bbec08a37f8722786d87bedf84eae19c020c4efa"
+uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
+version = "7.7.0"
+
+    [deps.ArrayInterface.extensions]
+    ArrayInterfaceBandedMatricesExt = "BandedMatrices"
+    ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices"
+    ArrayInterfaceCUDAExt = "CUDA"
+    ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore"
+    ArrayInterfaceStaticArraysCoreExt = "StaticArraysCore"
+    ArrayInterfaceTrackerExt = "Tracker"
+
+    [deps.ArrayInterface.weakdeps]
+    BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
+    BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
+    CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
+    GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527"
+    StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
+    Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
+
+[[deps.ArrayLayouts]]
+deps = ["FillArrays", "LinearAlgebra"]
+git-tree-sha1 = "a45ec4acc9d905f94b47243cff666820bb107789"
+uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
+version = "1.5.2"
+weakdeps = ["SparseArrays"]
+
+    [deps.ArrayLayouts.extensions]
+    ArrayLayoutsSparseArraysExt = "SparseArrays"
+
+[[deps.Artifacts]]
+uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
+
+[[deps.Automa]]
+deps = ["PrecompileTools", "TranscodingStreams"]
+git-tree-sha1 = "0da671c730d79b8f9a88a391556ec695ea921040"
+uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b"
+version = "1.0.2"
+
+[[deps.AxisAlgorithms]]
+deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
+git-tree-sha1 = "01b8ccb13d68535d73d2b0c23e39bd23155fb712"
+uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
+version = "1.1.0"
+
+[[deps.AxisArrays]]
+deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"]
+git-tree-sha1 = "16351be62963a67ac4083f748fdb3cca58bfd52f"
+uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9"
+version = "0.4.7"
+
+[[deps.Base64]]
+uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
+
+[[deps.BitTwiddlingConvenienceFunctions]]
+deps = ["Static"]
+git-tree-sha1 = "0c5f81f47bbbcf4aea7b2959135713459170798b"
+uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b"
+version = "0.1.5"
+
+[[deps.Bzip2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
+uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
+version = "1.0.8+0"
+
+[[deps.CEnum]]
+git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc"
+uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
+version = "0.5.0"
+
+[[deps.CPUSummary]]
+deps = ["CpuId", "IfElse", "PrecompileTools", "Static"]
+git-tree-sha1 = "601f7e7b3d36f18790e2caf83a882d88e9b71ff1"
+uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9"
+version = "0.2.4"
+
+[[deps.CRC32c]]
+uuid = "8bf52ea8-c179-5cab-976a-9e18b702a9bc"
+
+[[deps.CRlibm]]
+deps = ["CRlibm_jll"]
+git-tree-sha1 = "32abd86e3c2025db5172aa182b982debed519834"
+uuid = "96374032-68de-5a5b-8d9e-752f78720389"
+version = "1.0.1"
+
+[[deps.CRlibm_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "e329286945d0cfc04456972ea732551869af1cfc"
+uuid = "4e9b3aee-d8a1-5a3d-ad8b-7d824db253f0"
+version = "1.0.1+0"
+
+[[deps.Cairo]]
+deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"]
+git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b"
+uuid = "159f3aea-2a34-519c-b102-8c37f9878175"
+version = "1.0.5"
+
+[[deps.CairoMakie]]
+deps = ["CRC32c", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "PrecompileTools"]
+git-tree-sha1 = "a12dc4d061b03a60dbaf31582b12601331e8ecff"
+uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
+version = "0.11.4"
+
+[[deps.Cairo_jll]]
+deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
+git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2"
+uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
+version = "1.16.1+1"
+
+[[deps.Calculus]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad"
+uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
+version = "0.5.1"
+
+[[deps.ChainRulesCore]]
+deps = ["Compat", "LinearAlgebra"]
+git-tree-sha1 = "2118cb2765f8197b08e5958cdd17c165427425ee"
+uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+version = "1.19.0"
+weakdeps = ["SparseArrays"]
+
+    [deps.ChainRulesCore.extensions]
+    ChainRulesCoreSparseArraysExt = "SparseArrays"
+
+[[deps.CloseOpenIntervals]]
+deps = ["Static", "StaticArrayInterface"]
+git-tree-sha1 = "70232f82ffaab9dc52585e0dd043b5e0c6b714f1"
+uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9"
+version = "0.1.12"
+
+[[deps.ColorBrewer]]
+deps = ["Colors", "JSON", "Test"]
+git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4"
+uuid = "a2cac450-b92f-5266-8821-25eda20663c8"
+version = "0.4.0"
+
+[[deps.ColorSchemes]]
+deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"]
+git-tree-sha1 = "67c1f244b991cad9b0aa4b7540fb758c2488b129"
+uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
+version = "3.24.0"
+
+[[deps.ColorTypes]]
+deps = ["FixedPointNumbers", "Random"]
+git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4"
+uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
+version = "0.11.4"
+
+[[deps.ColorVectorSpace]]
+deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"]
+git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249"
+uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
+version = "0.10.0"
+weakdeps = ["SpecialFunctions"]
+
+    [deps.ColorVectorSpace.extensions]
+    SpecialFunctionsExt = "SpecialFunctions"
+
+[[deps.Colors]]
+deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
+git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a"
+uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
+version = "0.12.10"
+
+[[deps.Combinatorics]]
+git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860"
+uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
+version = "1.0.2"
+
+[[deps.CommonSolve]]
+git-tree-sha1 = "0eee5eb66b1cf62cd6ad1b460238e60e4b09400c"
+uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
+version = "0.2.4"
+
+[[deps.CommonSubexpressions]]
+deps = ["MacroTools", "Test"]
+git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7"
+uuid = "bbf7d656-a473-5ed7-a52c-81e309532950"
+version = "0.3.0"
+
+[[deps.Compat]]
+deps = ["UUIDs"]
+git-tree-sha1 = "886826d76ea9e72b35fcd000e535588f7b60f21d"
+uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
+version = "4.10.1"
+weakdeps = ["Dates", "LinearAlgebra"]
+
+    [deps.Compat.extensions]
+    CompatLinearAlgebraExt = "LinearAlgebra"
+
+[[deps.CompilerSupportLibraries_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
+version = "1.0.5+1"
+
+[[deps.ConcreteStructs]]
+git-tree-sha1 = "f749037478283d372048690eb3b5f92a79432b34"
+uuid = "2569d6c7-a4a2-43d3-a901-331e8e4be471"
+version = "0.2.3"
+
+[[deps.ConstructionBase]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "c53fc348ca4d40d7b371e71fd52251839080cbc9"
+uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
+version = "1.5.4"
+weakdeps = ["IntervalSets", "StaticArrays"]
+
+    [deps.ConstructionBase.extensions]
+    ConstructionBaseIntervalSetsExt = "IntervalSets"
+    ConstructionBaseStaticArraysExt = "StaticArrays"
+
+[[deps.Contour]]
+git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781"
+uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
+version = "0.6.2"
+
+[[deps.CpuId]]
+deps = ["Markdown"]
+git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406"
+uuid = "adafc99b-e345-5852-983c-f28acb93d879"
+version = "0.3.1"
+
+[[deps.DataAPI]]
+git-tree-sha1 = "8da84edb865b0b5b0100c0666a9bc9a0b71c553c"
+uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
+version = "1.15.0"
+
+[[deps.DataStructures]]
+deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
+git-tree-sha1 = "3dbd312d370723b6bb43ba9d02fc36abade4518d"
+uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
+version = "0.18.15"
+
+[[deps.DataValueInterfaces]]
+git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
+uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
+version = "1.0.0"
+
+[[deps.Dates]]
+deps = ["Printf"]
+uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
+
+[[deps.DelaunayTriangulation]]
+deps = ["DataStructures", "EnumX", "ExactPredicates", "Random", "SimpleGraphs"]
+git-tree-sha1 = "26eb8e2331b55735c3d305d949aabd7363f07ba7"
+uuid = "927a84f5-c5f4-47a5-9785-b46e178433df"
+version = "0.8.11"
+
+[[deps.DelimitedFiles]]
+deps = ["Mmap"]
+git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae"
+uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
+version = "1.9.1"
+
+[[deps.DiffEqBase]]
+deps = ["ArrayInterface", "DataStructures", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "ForwardDiff", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PreallocationTools", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "Setfield", "SparseArrays", "Static", "StaticArraysCore", "Statistics", "Tricks", "TruncatedStacktraces"]
+git-tree-sha1 = "044648af911974c3928058c1f8c83f159dece274"
+uuid = "2b5f629d-d688-5b77-993f-72d75c75574e"
+version = "6.145.6"
+
+    [deps.DiffEqBase.extensions]
+    DiffEqBaseChainRulesCoreExt = "ChainRulesCore"
+    DiffEqBaseDistributionsExt = "Distributions"
+    DiffEqBaseEnzymeExt = ["ChainRulesCore", "Enzyme"]
+    DiffEqBaseGeneralizedGeneratedExt = "GeneralizedGenerated"
+    DiffEqBaseMPIExt = "MPI"
+    DiffEqBaseMeasurementsExt = "Measurements"
+    DiffEqBaseMonteCarloMeasurementsExt = "MonteCarloMeasurements"
+    DiffEqBaseReverseDiffExt = "ReverseDiff"
+    DiffEqBaseTrackerExt = "Tracker"
+    DiffEqBaseUnitfulExt = "Unitful"
+
+    [deps.DiffEqBase.weakdeps]
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
+    Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
+    GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb"
+    MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
+    Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
+    MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca"
+    ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
+    Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
+    Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
+
+[[deps.DiffResults]]
+deps = ["StaticArraysCore"]
+git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621"
+uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
+version = "1.1.0"
+
+[[deps.DiffRules]]
+deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"]
+git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272"
+uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
+version = "1.15.1"
+
+[[deps.Distributed]]
+deps = ["Random", "Serialization", "Sockets"]
+uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
+
+[[deps.Distributions]]
+deps = ["FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"]
+git-tree-sha1 = "9242eec9b7e2e14f9952e8ea1c7e31a50501d587"
+uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
+version = "0.25.104"
+
+    [deps.Distributions.extensions]
+    DistributionsChainRulesCoreExt = "ChainRulesCore"
+    DistributionsDensityInterfaceExt = "DensityInterface"
+    DistributionsTestExt = "Test"
+
+    [deps.Distributions.weakdeps]
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d"
+    Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[[deps.DocStringExtensions]]
+deps = ["LibGit2"]
+git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d"
+uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
+version = "0.9.3"
+
+[[deps.Downloads]]
+deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
+uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
+version = "1.6.0"
+
+[[deps.DualNumbers]]
+deps = ["Calculus", "NaNMath", "SpecialFunctions"]
+git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566"
+uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74"
+version = "0.6.8"
+
+[[deps.EarCut_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053"
+uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
+version = "2.2.4+0"
+
+[[deps.EnumX]]
+git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237"
+uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
+version = "1.0.4"
+
+[[deps.EnzymeCore]]
+git-tree-sha1 = "59c44d8fbc651c0395d8a6eda64b05ce316f58b4"
+uuid = "f151be2c-9106-41f4-ab19-57ee4f262869"
+version = "0.6.5"
+weakdeps = ["Adapt"]
+
+    [deps.EnzymeCore.extensions]
+    AdaptExt = "Adapt"
+
+[[deps.ErrorfreeArithmetic]]
+git-tree-sha1 = "d6863c556f1142a061532e79f611aa46be201686"
+uuid = "90fa49ef-747e-5e6f-a989-263ba693cf1a"
+version = "0.5.2"
+
+[[deps.ExactPredicates]]
+deps = ["IntervalArithmetic", "Random", "StaticArraysCore"]
+git-tree-sha1 = "499b1ca78f6180c8f8bdf1cabde2d39120229e5c"
+uuid = "429591f6-91af-11e9-00e2-59fbe8cec110"
+version = "2.2.6"
+
+[[deps.Expat_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "4558ab818dcceaab612d1bb8c19cee87eda2b83c"
+uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
+version = "2.5.0+0"
+
+[[deps.ExponentialUtilities]]
+deps = ["Adapt", "ArrayInterface", "GPUArraysCore", "GenericSchur", "LinearAlgebra", "PrecompileTools", "Printf", "SparseArrays", "libblastrampoline_jll"]
+git-tree-sha1 = "602e4585bcbd5a25bc06f514724593d13ff9e862"
+uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18"
+version = "1.25.0"
+
+[[deps.ExprTools]]
+git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec"
+uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
+version = "0.1.10"
+
+[[deps.Extents]]
+git-tree-sha1 = "2140cd04483da90b2da7f99b2add0750504fc39c"
+uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910"
+version = "0.1.2"
+
+[[deps.FFMPEG_jll]]
+deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
+git-tree-sha1 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e"
+uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
+version = "4.4.4+1"
+
+[[deps.FFTW]]
+deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
+git-tree-sha1 = "ec22cbbcd01cba8f41eecd7d44aac1f23ee985e3"
+uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
+version = "1.7.2"
+
+[[deps.FFTW_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea"
+uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
+version = "3.3.10+0"
+
+[[deps.FastBroadcast]]
+deps = ["ArrayInterface", "LinearAlgebra", "Polyester", "Static", "StaticArrayInterface", "StrideArraysCore"]
+git-tree-sha1 = "a6e756a880fc419c8b41592010aebe6a5ce09136"
+uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
+version = "0.2.8"
+
+[[deps.FastClosures]]
+git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef"
+uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a"
+version = "0.3.2"
+
+[[deps.FastLapackInterface]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "b12f05108e405dadcc2aff0008db7f831374e051"
+uuid = "29a986be-02c6-4525-aec4-84b980013641"
+version = "2.0.0"
+
+[[deps.FastRounding]]
+deps = ["ErrorfreeArithmetic", "LinearAlgebra"]
+git-tree-sha1 = "6344aa18f654196be82e62816935225b3b9abe44"
+uuid = "fa42c844-2597-5d31-933b-ebd51ab2693f"
+version = "0.3.1"
+
+[[deps.FileIO]]
+deps = ["Pkg", "Requires", "UUIDs"]
+git-tree-sha1 = "299dc33549f68299137e51e6d49a13b5b1da9673"
+uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
+version = "1.16.1"
+
+[[deps.FilePaths]]
+deps = ["FilePathsBase", "MacroTools", "Reexport", "Requires"]
+git-tree-sha1 = "919d9412dbf53a2e6fe74af62a73ceed0bce0629"
+uuid = "8fc22ac5-c921-52a6-82fd-178b2807b824"
+version = "0.8.3"
+
+[[deps.FilePathsBase]]
+deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"]
+git-tree-sha1 = "9f00e42f8d99fdde64d40c8ea5d14269a2e2c1aa"
+uuid = "48062228-2e41-5def-b9a4-89aafe57970f"
+version = "0.9.21"
+
+[[deps.FileWatching]]
+uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
+
+[[deps.FillArrays]]
+deps = ["LinearAlgebra", "Random"]
+git-tree-sha1 = "5b93957f6dcd33fc343044af3d48c215be2562f1"
+uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
+version = "1.9.3"
+weakdeps = ["PDMats", "SparseArrays", "Statistics"]
+
+    [deps.FillArrays.extensions]
+    FillArraysPDMatsExt = "PDMats"
+    FillArraysSparseArraysExt = "SparseArrays"
+    FillArraysStatisticsExt = "Statistics"
+
+[[deps.FiniteDiff]]
+deps = ["ArrayInterface", "LinearAlgebra", "Requires", "Setfield", "SparseArrays"]
+git-tree-sha1 = "73d1214fec245096717847c62d389a5d2ac86504"
+uuid = "6a86dc24-6348-571c-b903-95158fe2bd41"
+version = "2.22.0"
+
+    [deps.FiniteDiff.extensions]
+    FiniteDiffBandedMatricesExt = "BandedMatrices"
+    FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices"
+    FiniteDiffStaticArraysExt = "StaticArrays"
+
+    [deps.FiniteDiff.weakdeps]
+    BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
+    BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0"
+    StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
+
+[[deps.FixedPointNumbers]]
+deps = ["Statistics"]
+git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
+uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
+version = "0.8.4"
+
+[[deps.Fontconfig_jll]]
+deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
+git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
+uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
+version = "2.13.93+0"
+
+[[deps.Formatting]]
+deps = ["Printf"]
+git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
+uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
+version = "0.4.2"
+
+[[deps.ForwardDiff]]
+deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"]
+git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad"
+uuid = "f6369f11-7733-5829-9624-2563aa707210"
+version = "0.10.36"
+weakdeps = ["StaticArrays"]
+
+    [deps.ForwardDiff.extensions]
+    ForwardDiffStaticArraysExt = "StaticArrays"
+
+[[deps.FreeType]]
+deps = ["CEnum", "FreeType2_jll"]
+git-tree-sha1 = "907369da0f8e80728ab49c1c7e09327bf0d6d999"
+uuid = "b38be410-82b0-50bf-ab77-7b57e271db43"
+version = "4.1.1"
+
+[[deps.FreeType2_jll]]
+deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"]
+git-tree-sha1 = "d8db6a5a2fe1381c1ea4ef2cab7c69c2de7f9ea0"
+uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
+version = "2.13.1+0"
+
+[[deps.FreeTypeAbstraction]]
+deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"]
+git-tree-sha1 = "055626e1a35f6771fe99060e835b72ca61a52621"
+uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
+version = "0.10.1"
+
+[[deps.FriBidi_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
+uuid = "559328eb-81f9-559d-9380-de523a88c83c"
+version = "1.0.10+0"
+
+[[deps.FunctionWrappers]]
+git-tree-sha1 = "d62485945ce5ae9c0c48f124a84998d755bae00e"
+uuid = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e"
+version = "1.1.3"
+
+[[deps.FunctionWrappersWrappers]]
+deps = ["FunctionWrappers"]
+git-tree-sha1 = "b104d487b34566608f8b4e1c39fb0b10aa279ff8"
+uuid = "77dc65aa-8811-40c2-897b-53d922fa7daf"
+version = "0.1.3"
+
+[[deps.Future]]
+deps = ["Random"]
+uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"
+
+[[deps.GPUArraysCore]]
+deps = ["Adapt"]
+git-tree-sha1 = "2d6ca471a6c7b536127afccfa7564b5b39227fe0"
+uuid = "46192b85-c4d5-4398-a991-12ede77f4527"
+version = "0.1.5"
+
+[[deps.GenericSchur]]
+deps = ["LinearAlgebra", "Printf"]
+git-tree-sha1 = "fb69b2a645fa69ba5f474af09221b9308b160ce6"
+uuid = "c145ed77-6b09-5dd9-b285-bf645a82121e"
+version = "0.5.3"
+
+[[deps.GeoInterface]]
+deps = ["Extents"]
+git-tree-sha1 = "d4f85701f569584f2cff7ba67a137d03f0cfb7d0"
+uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
+version = "1.3.3"
+
+[[deps.GeometryBasics]]
+deps = ["EarCut_jll", "Extents", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
+git-tree-sha1 = "424a5a6ce7c5d97cca7bcc4eac551b97294c54af"
+uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
+version = "0.4.9"
+
+[[deps.Gettext_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
+git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
+uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
+version = "0.21.0+0"
+
+[[deps.Glib_jll]]
+deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"]
+git-tree-sha1 = "e94c92c7bf4819685eb80186d51c43e71d4afa17"
+uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
+version = "2.76.5+0"
+
+[[deps.Graphics]]
+deps = ["Colors", "LinearAlgebra", "NaNMath"]
+git-tree-sha1 = "d61890399bc535850c4bf08e4e0d3a7ad0f21cbd"
+uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
+version = "1.1.2"
+
+[[deps.Graphite2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
+uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
+version = "1.3.14+0"
+
+[[deps.Graphs]]
+deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"]
+git-tree-sha1 = "899050ace26649433ef1af25bc17a815b3db52b7"
+uuid = "86223c79-3864-5bf0-83f7-82e725a168b6"
+version = "1.9.0"
+
+[[deps.GridLayoutBase]]
+deps = ["GeometryBasics", "InteractiveUtils", "Observables"]
+git-tree-sha1 = "af13a277efd8a6e716d79ef635d5342ccb75be61"
+uuid = "3955a311-db13-416c-9275-1d80ed98e5e9"
+version = "0.10.0"
+
+[[deps.Grisu]]
+git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
+uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
+version = "1.0.2"
+
+[[deps.HDF5]]
+deps = ["Compat", "HDF5_jll", "Libdl", "MPIPreferences", "Mmap", "Preferences", "Printf", "Random", "Requires", "UUIDs"]
+git-tree-sha1 = "26407bd1c60129062cec9da63dc7d08251544d53"
+uuid = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
+version = "0.17.1"
+
+    [deps.HDF5.extensions]
+    MPIExt = "MPI"
+
+    [deps.HDF5.weakdeps]
+    MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
+
+[[deps.HDF5_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "LazyArtifacts", "LibCURL_jll", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "OpenSSL_jll", "TOML", "Zlib_jll", "libaec_jll"]
+git-tree-sha1 = "38c8874692d48d5440d5752d6c74b0c6b0b60739"
+uuid = "0234f1f7-429e-5d53-9886-15a909be8d59"
+version = "1.14.2+1"
+
+[[deps.HarfBuzz_jll]]
+deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
+git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3"
+uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
+version = "2.8.1+1"
+
+[[deps.HostCPUFeatures]]
+deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"]
+git-tree-sha1 = "eb8fed28f4994600e29beef49744639d985a04b2"
+uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0"
+version = "0.1.16"
+
+[[deps.Hwloc_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "ca0f6bf568b4bfc807e7537f081c81e35ceca114"
+uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8"
+version = "2.10.0+0"
+
+[[deps.HypergeometricFunctions]]
+deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"]
+git-tree-sha1 = "f218fe3736ddf977e0e772bc9a586b2383da2685"
+uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a"
+version = "0.3.23"
+
+[[deps.IfElse]]
+git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1"
+uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
+version = "0.1.1"
+
+[[deps.ImageAxes]]
+deps = ["AxisArrays", "ImageBase", "ImageCore", "Reexport", "SimpleTraits"]
+git-tree-sha1 = "2e4520d67b0cef90865b3ef727594d2a58e0e1f8"
+uuid = "2803e5a7-5153-5ecf-9a86-9b4c37f5f5ac"
+version = "0.6.11"
+
+[[deps.ImageBase]]
+deps = ["ImageCore", "Reexport"]
+git-tree-sha1 = "eb49b82c172811fd2c86759fa0553a2221feb909"
+uuid = "c817782e-172a-44cc-b673-b171935fbb9e"
+version = "0.1.7"
+
+[[deps.ImageCore]]
+deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "PrecompileTools", "Reexport"]
+git-tree-sha1 = "fc5d1d3443a124fde6e92d0260cd9e064eba69f8"
+uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
+version = "0.10.1"
+
+[[deps.ImageIO]]
+deps = ["FileIO", "IndirectArrays", "JpegTurbo", "LazyModules", "Netpbm", "OpenEXR", "PNGFiles", "QOI", "Sixel", "TiffImages", "UUIDs"]
+git-tree-sha1 = "bca20b2f5d00c4fbc192c3212da8fa79f4688009"
+uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
+version = "0.6.7"
+
+[[deps.ImageMetadata]]
+deps = ["AxisArrays", "ImageAxes", "ImageBase", "ImageCore"]
+git-tree-sha1 = "355e2b974f2e3212a75dfb60519de21361ad3cb7"
+uuid = "bc367c6b-8a6b-528e-b4bd-a4b897500b49"
+version = "0.9.9"
+
+[[deps.Imath_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "3d09a9f60edf77f8a4d99f9e015e8fbf9989605d"
+uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1"
+version = "3.1.7+0"
+
+[[deps.IndirectArrays]]
+git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f"
+uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
+version = "1.0.0"
+
+[[deps.Inflate]]
+git-tree-sha1 = "ea8031dea4aff6bd41f1df8f2fdfb25b33626381"
+uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
+version = "0.1.4"
+
+[[deps.IntegerMathUtils]]
+git-tree-sha1 = "b8ffb903da9f7b8cf695a8bead8e01814aa24b30"
+uuid = "18e54dd8-cb9d-406c-a71d-865a43cbb235"
+version = "0.1.2"
+
+[[deps.IntelOpenMP_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "5fdf2fe6724d8caabf43b557b84ce53f3b7e2f6b"
+uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
+version = "2024.0.2+0"
+
+[[deps.InteractiveUtils]]
+deps = ["Markdown"]
+uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
+
+[[deps.Interpolations]]
+deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
+git-tree-sha1 = "88a101217d7cb38a7b481ccd50d21876e1d1b0e0"
+uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
+version = "0.15.1"
+
+    [deps.Interpolations.extensions]
+    InterpolationsUnitfulExt = "Unitful"
+
+    [deps.Interpolations.weakdeps]
+    Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
+
+[[deps.IntervalArithmetic]]
+deps = ["CRlibm", "EnumX", "FastRounding", "LinearAlgebra", "Markdown", "Random", "RecipesBase", "RoundingEmulator", "SetRounding", "StaticArrays"]
+git-tree-sha1 = "f59e639916283c1d2e106d2b00910b50f4dab76c"
+uuid = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
+version = "0.21.2"
+
+[[deps.IntervalSets]]
+deps = ["Dates", "Random"]
+git-tree-sha1 = "3d8866c029dd6b16e69e0d4a939c4dfcb98fac47"
+uuid = "8197267c-284f-5f27-9208-e0e47529a953"
+version = "0.7.8"
+weakdeps = ["Statistics"]
+
+    [deps.IntervalSets.extensions]
+    IntervalSetsStatisticsExt = "Statistics"
+
+[[deps.IrrationalConstants]]
+git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2"
+uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
+version = "0.2.2"
+
+[[deps.Isoband]]
+deps = ["isoband_jll"]
+git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137"
+uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4"
+version = "0.1.1"
+
+[[deps.IterTools]]
+git-tree-sha1 = "274c38bd733f9d29036d0a73658fff1dc1d3a065"
+uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
+version = "1.9.0"
+
+[[deps.IteratorInterfaceExtensions]]
+git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
+uuid = "82899510-4779-5014-852e-03e436cf321d"
+version = "1.0.0"
+
+[[deps.JLLWrappers]]
+deps = ["Artifacts", "Preferences"]
+git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca"
+uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
+version = "1.5.0"
+
+[[deps.JSON]]
+deps = ["Dates", "Mmap", "Parsers", "Unicode"]
+git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a"
+uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
+version = "0.21.4"
+
+[[deps.JpegTurbo]]
+deps = ["CEnum", "FileIO", "ImageCore", "JpegTurbo_jll", "TOML"]
+git-tree-sha1 = "fa6d0bcff8583bac20f1ffa708c3913ca605c611"
+uuid = "b835a17e-a41a-41e7-81f0-2f016b05efe0"
+version = "0.1.5"
+
+[[deps.JpegTurbo_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "60b1194df0a3298f460063de985eae7b01bc011a"
+uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
+version = "3.0.1+0"
+
+[[deps.KLU]]
+deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse_jll"]
+git-tree-sha1 = "884c2968c2e8e7e6bf5956af88cb46aa745c854b"
+uuid = "ef3ab10e-7fda-4108-b977-705223b18434"
+version = "0.4.1"
+
+[[deps.KernelDensity]]
+deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"]
+git-tree-sha1 = "fee018a29b60733876eb557804b5b109dd3dd8a7"
+uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
+version = "0.6.8"
+
+[[deps.Krylov]]
+deps = ["LinearAlgebra", "Printf", "SparseArrays"]
+git-tree-sha1 = "8a6837ec02fe5fb3def1abc907bb802ef11a0729"
+uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7"
+version = "0.9.5"
+
+[[deps.LAME_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
+uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
+version = "3.100.1+0"
+
+[[deps.LLVMOpenMP_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "d986ce2d884d49126836ea94ed5bfb0f12679713"
+uuid = "1d63c593-3942-5779-bab2-d838dc0a180e"
+version = "15.0.7+0"
+
+[[deps.LZO_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
+uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
+version = "2.10.1+0"
+
+[[deps.LaTeXStrings]]
+git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec"
+uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
+version = "1.3.1"
+
+[[deps.LayoutPointers]]
+deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface"]
+git-tree-sha1 = "62edfee3211981241b57ff1cedf4d74d79519277"
+uuid = "10f19ff3-798f-405d-979b-55457f8fc047"
+version = "0.1.15"
+
+[[deps.Lazy]]
+deps = ["MacroTools"]
+git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f"
+uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"
+version = "0.15.1"
+
+[[deps.LazyArrays]]
+deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "MacroTools", "MatrixFactorizations", "SparseArrays"]
+git-tree-sha1 = "9cfca23ab83b0dfac93cb1a1ef3331ab9fe596a5"
+uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02"
+version = "1.8.3"
+weakdeps = ["StaticArrays"]
+
+    [deps.LazyArrays.extensions]
+    LazyArraysStaticArraysExt = "StaticArrays"
+
+[[deps.LazyArtifacts]]
+deps = ["Artifacts", "Pkg"]
+uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"
+
+[[deps.LazyModules]]
+git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e"
+uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e"
+version = "0.3.1"
+
+[[deps.LibCURL]]
+deps = ["LibCURL_jll", "MozillaCACerts_jll"]
+uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
+version = "0.6.4"
+
+[[deps.LibCURL_jll]]
+deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
+uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
+version = "8.4.0+0"
+
+[[deps.LibGit2]]
+deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
+uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
+
+[[deps.LibGit2_jll]]
+deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"]
+uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5"
+version = "1.6.4+0"
+
+[[deps.LibSSH2_jll]]
+deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
+uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
+version = "1.11.0+1"
+
+[[deps.Libdl]]
+uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+
+[[deps.Libffi_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290"
+uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
+version = "3.2.2+1"
+
+[[deps.Libgcrypt_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
+git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
+uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
+version = "1.8.7+0"
+
+[[deps.Libgpg_error_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
+uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
+version = "1.42.0+0"
+
+[[deps.Libiconv_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175"
+uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
+version = "1.17.0+0"
+
+[[deps.Libmount_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
+uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
+version = "2.35.0+0"
+
+[[deps.Libuuid_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
+uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
+version = "2.36.0+0"
+
+[[deps.LightXML]]
+deps = ["Libdl", "XML2_jll"]
+git-tree-sha1 = "3a994404d3f6709610701c7dabfc03fed87a81f8"
+uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179"
+version = "0.9.1"
+
+[[deps.LineSearches]]
+deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"]
+git-tree-sha1 = "7bbea35cec17305fc70a0e5b4641477dc0789d9d"
+uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
+version = "7.2.0"
+
+[[deps.LinearAlgebra]]
+deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
+uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
+
+[[deps.LinearAlgebraX]]
+deps = ["LinearAlgebra", "Mods", "Permutations", "Primes", "SimplePolynomials"]
+git-tree-sha1 = "89ed93300377e0742ae8a7423f7543c8f5eb73a4"
+uuid = "9b3f67b0-2d00-526e-9884-9e4938f8fb88"
+version = "0.2.5"
+
+[[deps.LinearSolve]]
+deps = ["ArrayInterface", "ConcreteStructs", "DocStringExtensions", "EnumX", "FastLapackInterface", "GPUArraysCore", "InteractiveUtils", "KLU", "Krylov", "Libdl", "LinearAlgebra", "MKL_jll", "PrecompileTools", "Preferences", "RecursiveFactorization", "Reexport", "SciMLBase", "SciMLOperators", "Setfield", "SparseArrays", "Sparspak", "StaticArraysCore", "UnPack"]
+git-tree-sha1 = "6f8e084deabe3189416c4e505b1c53e1b590cae8"
+uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
+version = "2.22.1"
+
+    [deps.LinearSolve.extensions]
+    LinearSolveBandedMatricesExt = "BandedMatrices"
+    LinearSolveBlockDiagonalsExt = "BlockDiagonals"
+    LinearSolveCUDAExt = "CUDA"
+    LinearSolveEnzymeExt = ["Enzyme", "EnzymeCore"]
+    LinearSolveFastAlmostBandedMatricesExt = ["FastAlmostBandedMatrices"]
+    LinearSolveHYPREExt = "HYPRE"
+    LinearSolveIterativeSolversExt = "IterativeSolvers"
+    LinearSolveKernelAbstractionsExt = "KernelAbstractions"
+    LinearSolveKrylovKitExt = "KrylovKit"
+    LinearSolveMetalExt = "Metal"
+    LinearSolvePardisoExt = "Pardiso"
+    LinearSolveRecursiveArrayToolsExt = "RecursiveArrayTools"
+
+    [deps.LinearSolve.weakdeps]
+    BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
+    BlockDiagonals = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0"
+    CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
+    Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
+    EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869"
+    FastAlmostBandedMatrices = "9d29842c-ecb8-4973-b1e9-a27b1157504e"
+    HYPRE = "b5ffcf37-a2bd-41ab-a3da-4bd9bc8ad771"
+    IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153"
+    KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
+    KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
+    Metal = "dde4c033-4e86-420c-a63e-0dd931031962"
+    Pardiso = "46dd5b70-b6fb-5a00-ae2d-e8fea33afaf2"
+    RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
+
+[[deps.LogExpFunctions]]
+deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
+git-tree-sha1 = "7d6dd4e9212aebaeed356de34ccf262a3cd415aa"
+uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
+version = "0.3.26"
+
+    [deps.LogExpFunctions.extensions]
+    LogExpFunctionsChainRulesCoreExt = "ChainRulesCore"
+    LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables"
+    LogExpFunctionsInverseFunctionsExt = "InverseFunctions"
+
+    [deps.LogExpFunctions.weakdeps]
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
+    InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
+
+[[deps.Logging]]
+uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
+
+[[deps.LoopVectorization]]
+deps = ["ArrayInterface", "CPUSummary", "CloseOpenIntervals", "DocStringExtensions", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "PrecompileTools", "SIMDTypes", "SLEEFPirates", "Static", "StaticArrayInterface", "ThreadingUtilities", "UnPack", "VectorizationBase"]
+git-tree-sha1 = "0f5648fbae0d015e3abe5867bca2b362f67a5894"
+uuid = "bdcacae8-1622-11e9-2a5c-532679323890"
+version = "0.12.166"
+weakdeps = ["ChainRulesCore", "ForwardDiff", "SpecialFunctions"]
+
+    [deps.LoopVectorization.extensions]
+    ForwardDiffExt = ["ChainRulesCore", "ForwardDiff"]
+    SpecialFunctionsExt = "SpecialFunctions"
+
+[[deps.MKL_jll]]
+deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl"]
+git-tree-sha1 = "72dc3cf284559eb8f53aa593fe62cb33f83ed0c0"
+uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
+version = "2024.0.0+0"
+
+[[deps.MPICH_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"]
+git-tree-sha1 = "2ee75365ca243c1a39d467e35ffd3d4d32eef11e"
+uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4"
+version = "4.1.2+1"
+
+[[deps.MPIPreferences]]
+deps = ["Libdl", "Preferences"]
+git-tree-sha1 = "8f6af051b9e8ec597fa09d8885ed79fd582f33c9"
+uuid = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267"
+version = "0.1.10"
+
+[[deps.MPItrampoline_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"]
+git-tree-sha1 = "8eeb3c73bbc0ca203d0dc8dad4008350bbe5797b"
+uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748"
+version = "5.3.1+1"
+
+[[deps.MacroTools]]
+deps = ["Markdown", "Random"]
+git-tree-sha1 = "b211c553c199c111d998ecdaf7623d1b89b69f93"
+uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
+version = "0.5.12"
+
+[[deps.Makie]]
+deps = ["Animations", "Base64", "CRC32c", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "DelaunayTriangulation", "Distributions", "DocStringExtensions", "Downloads", "FFMPEG_jll", "FileIO", "FilePaths", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "InteractiveUtils", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MacroTools", "MakieCore", "Markdown", "MathTeXEngine", "Observables", "OffsetArrays", "Packing", "PlotUtils", "PolygonOps", "PrecompileTools", "Printf", "REPL", "Random", "RelocatableFolders", "Scratch", "Setfield", "ShaderAbstractions", "Showoff", "SignedDistanceFields", "SparseArrays", "StableHashTraits", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "TriplotBase", "UnicodeFun"]
+git-tree-sha1 = "1c080946c18c905311f6c79af66f642f309e9d59"
+uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
+version = "0.20.3"
+
+[[deps.MakieCore]]
+deps = ["Observables", "REPL"]
+git-tree-sha1 = "ec5db7bb2dc9b85072658dcb2d3ad09569b09ac9"
+uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
+version = "0.7.2"
+
+[[deps.ManualMemory]]
+git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd"
+uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667"
+version = "0.1.8"
+
+[[deps.MappedArrays]]
+git-tree-sha1 = "2dab0221fe2b0f2cb6754eaa743cc266339f527e"
+uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
+version = "0.4.2"
+
+[[deps.Markdown]]
+deps = ["Base64"]
+uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
+
+[[deps.MathTeXEngine]]
+deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "UnicodeFun"]
+git-tree-sha1 = "96ca8a313eb6437db5ffe946c457a401bbb8ce1d"
+uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
+version = "0.5.7"
+
+[[deps.MatrixFactorizations]]
+deps = ["ArrayLayouts", "LinearAlgebra", "Printf", "Random"]
+git-tree-sha1 = "78f6e33434939b0ac9ba1df81e6d005ee85a7396"
+uuid = "a3b82374-2e81-5b9e-98ce-41277c0e4c87"
+version = "2.1.0"
+
+[[deps.MaybeInplace]]
+deps = ["ArrayInterface", "LinearAlgebra", "MacroTools", "SparseArrays"]
+git-tree-sha1 = "a85c6a98c9e5a2a7046bc1bb89f28a3241e1de4d"
+uuid = "bb5d69b7-63fc-4a16-80bd-7e42200c7bdb"
+version = "0.1.1"
+
+[[deps.MbedTLS_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
+version = "2.28.2+1"
+
+[[deps.MicrosoftMPI_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "b01beb91d20b0d1312a9471a36017b5b339d26de"
+uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf"
+version = "10.1.4+1"
+
+[[deps.Missings]]
+deps = ["DataAPI"]
+git-tree-sha1 = "f66bdc5de519e8f8ae43bdc598782d35a25b1272"
+uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
+version = "1.1.0"
+
+[[deps.Mmap]]
+uuid = "a63ad114-7e13-5084-954f-fe012c677804"
+
+[[deps.Mods]]
+git-tree-sha1 = "9d292c7fb23e9a756094f8617a0f10e3b9582f47"
+uuid = "7475f97c-0381-53b1-977b-4c60186c8d62"
+version = "2.2.0"
+
+[[deps.MosaicViews]]
+deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
+git-tree-sha1 = "7b86a5d4d70a9f5cdf2dacb3cbe6d251d1a61dbe"
+uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
+version = "0.3.4"
+
+[[deps.MozillaCACerts_jll]]
+uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
+version = "2023.1.10"
+
+[[deps.MuladdMacro]]
+git-tree-sha1 = "cac9cc5499c25554cba55cd3c30543cff5ca4fab"
+uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221"
+version = "0.2.4"
+
+[[deps.Multisets]]
+git-tree-sha1 = "8d852646862c96e226367ad10c8af56099b4047e"
+uuid = "3b2b4ff1-bcff-5658-a3ee-dbcf1ce5ac09"
+version = "0.4.4"
+
+[[deps.NLSolversBase]]
+deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"]
+git-tree-sha1 = "a0b464d183da839699f4c79e7606d9d186ec172c"
+uuid = "d41bc354-129a-5804-8e4c-c37616107c6c"
+version = "7.8.3"
+
+[[deps.NaNMath]]
+deps = ["OpenLibm_jll"]
+git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4"
+uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
+version = "1.0.2"
+
+[[deps.Netpbm]]
+deps = ["FileIO", "ImageCore", "ImageMetadata"]
+git-tree-sha1 = "d92b107dbb887293622df7697a2223f9f8176fcd"
+uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
+version = "1.1.1"
+
+[[deps.NetworkOptions]]
+uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
+version = "1.2.0"
+
+[[deps.NonlinearSolve]]
+deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "EnumX", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LazyArrays", "LineSearches", "LinearAlgebra", "LinearSolve", "MaybeInplace", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SimpleNonlinearSolve", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"]
+git-tree-sha1 = "72b036b728461272ae1b1c3f7096cb4c319d8793"
+uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
+version = "3.4.0"
+
+    [deps.NonlinearSolve.extensions]
+    NonlinearSolveBandedMatricesExt = "BandedMatrices"
+    NonlinearSolveFastLevenbergMarquardtExt = "FastLevenbergMarquardt"
+    NonlinearSolveFixedPointAccelerationExt = "FixedPointAcceleration"
+    NonlinearSolveLeastSquaresOptimExt = "LeastSquaresOptim"
+    NonlinearSolveMINPACKExt = "MINPACK"
+    NonlinearSolveNLsolveExt = "NLsolve"
+    NonlinearSolveSIAMFANLEquationsExt = "SIAMFANLEquations"
+    NonlinearSolveSpeedMappingExt = "SpeedMapping"
+    NonlinearSolveSymbolicsExt = "Symbolics"
+    NonlinearSolveZygoteExt = "Zygote"
+
+    [deps.NonlinearSolve.weakdeps]
+    BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
+    FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce"
+    FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176"
+    LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891"
+    MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
+    NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
+    SIAMFANLEquations = "084e46ad-d928-497d-ad5e-07fa361a48c4"
+    SpeedMapping = "f1835b91-879b-4a3f-a438-e4baacf14412"
+    Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
+    Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
+
+[[deps.Observables]]
+git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225"
+uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
+version = "0.5.5"
+
+[[deps.OffsetArrays]]
+git-tree-sha1 = "6a731f2b5c03157418a20c12195eb4b74c8f8621"
+uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
+version = "1.13.0"
+weakdeps = ["Adapt"]
+
+    [deps.OffsetArrays.extensions]
+    OffsetArraysAdaptExt = "Adapt"
+
+[[deps.Ogg_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f"
+uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
+version = "1.3.5+1"
+
+[[deps.OpenBLAS_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
+uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
+version = "0.3.23+2"
+
+[[deps.OpenEXR]]
+deps = ["Colors", "FileIO", "OpenEXR_jll"]
+git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633"
+uuid = "52e1d378-f018-4a11-a4be-720524705ac7"
+version = "0.3.2"
+
+[[deps.OpenEXR_jll]]
+deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Zlib_jll"]
+git-tree-sha1 = "a4ca623df1ae99d09bc9868b008262d0c0ac1e4f"
+uuid = "18a262bb-aa17-5467-a713-aee519bc75cb"
+version = "3.1.4+0"
+
+[[deps.OpenLibm_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
+version = "0.8.1+2"
+
+[[deps.OpenMPI_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "PMIx_jll", "TOML", "Zlib_jll", "libevent_jll", "prrte_jll"]
+git-tree-sha1 = "1d1421618bab0e820bdc7ae1a2b46ce576981273"
+uuid = "fe0851c0-eecd-5654-98d4-656369965a5c"
+version = "5.0.1+0"
+
+[[deps.OpenSSL_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "cc6e1927ac521b659af340e0ca45828a3ffc748f"
+uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
+version = "3.0.12+0"
+
+[[deps.OpenSpecFun_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
+uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
+version = "0.5.5+0"
+
+[[deps.Optim]]
+deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"]
+git-tree-sha1 = "01f85d9269b13fedc61e63cc72ee2213565f7a72"
+uuid = "429524aa-4258-5aef-a3af-852621145aeb"
+version = "1.7.8"
+
+[[deps.Opus_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
+uuid = "91d4177d-7536-5919-b921-800302f37372"
+version = "1.3.2+0"
+
+[[deps.OrderedCollections]]
+git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5"
+uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
+version = "1.6.3"
+
+[[deps.OrdinaryDiffEq]]
+deps = ["ADTypes", "Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FillArrays", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "IfElse", "InteractiveUtils", "LineSearches", "LinearAlgebra", "LinearSolve", "Logging", "MacroTools", "MuladdMacro", "NonlinearSolve", "Polyester", "PreallocationTools", "PrecompileTools", "Preferences", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SimpleNonlinearSolve", "SimpleUnPack", "SparseArrays", "SparseDiffTools", "StaticArrayInterface", "StaticArrays", "TruncatedStacktraces"]
+git-tree-sha1 = "7c6738f21fba2ccd07b7eaa9d23b437a8a97f1a1"
+uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
+version = "6.69.0"
+
+[[deps.PCRE2_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15"
+version = "10.42.0+1"
+
+[[deps.PDMats]]
+deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
+git-tree-sha1 = "949347156c25054de2db3b166c52ac4728cbad65"
+uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
+version = "0.11.31"
+
+[[deps.PMIx_jll]]
+deps = ["Artifacts", "Hwloc_jll", "JLLWrappers", "Libdl", "Zlib_jll", "libevent_jll"]
+git-tree-sha1 = "8b3b19351fa24791f94d7ae85faf845ca1362541"
+uuid = "32165bc3-0280-59bc-8c0b-c33b6203efab"
+version = "4.2.7+0"
+
+[[deps.PNGFiles]]
+deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
+git-tree-sha1 = "67186a2bc9a90f9f85ff3cc8277868961fb57cbd"
+uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
+version = "0.4.3"
+
+[[deps.PackageExtensionCompat]]
+git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518"
+uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930"
+version = "1.0.2"
+weakdeps = ["Requires", "TOML"]
+
+[[deps.Packing]]
+deps = ["GeometryBasics"]
+git-tree-sha1 = "ec3edfe723df33528e085e632414499f26650501"
+uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566"
+version = "0.5.0"
+
+[[deps.PaddedViews]]
+deps = ["OffsetArrays"]
+git-tree-sha1 = "0fac6313486baae819364c52b4f483450a9d793f"
+uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
+version = "0.5.12"
+
+[[deps.Pango_jll]]
+deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "4745216e94f71cb768d58330b059c9b76f32cb66"
+uuid = "36c8627f-9965-5494-a995-c6b170f724f3"
+version = "1.50.14+0"
+
+[[deps.Parameters]]
+deps = ["OrderedCollections", "UnPack"]
+git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
+uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
+version = "0.12.3"
+
+[[deps.Parsers]]
+deps = ["Dates", "PrecompileTools", "UUIDs"]
+git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
+uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
+version = "2.8.1"
+
+[[deps.Permutations]]
+deps = ["Combinatorics", "LinearAlgebra", "Random"]
+git-tree-sha1 = "c7745750b8a829bc6039b7f1f0981bcda526a946"
+uuid = "2ae35dd2-176d-5d53-8349-f30d82d94d4f"
+version = "0.4.19"
+
+[[deps.Pixman_jll]]
+deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"]
+git-tree-sha1 = "64779bc4c9784fee475689a1752ef4d5747c5e87"
+uuid = "30392449-352a-5448-841d-b1acce4e97dc"
+version = "0.42.2+0"
+
+[[deps.Pkg]]
+deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
+uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
+version = "1.10.0"
+
+[[deps.PkgVersion]]
+deps = ["Pkg"]
+git-tree-sha1 = "f9501cc0430a26bc3d156ae1b5b0c1b47af4d6da"
+uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
+version = "0.3.3"
+
+[[deps.PlotUtils]]
+deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"]
+git-tree-sha1 = "862942baf5663da528f66d24996eb6da85218e76"
+uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
+version = "1.4.0"
+
+[[deps.Polyester]]
+deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StaticArrayInterface", "StrideArraysCore", "ThreadingUtilities"]
+git-tree-sha1 = "fca25670784a1ae44546bcb17288218310af2778"
+uuid = "f517fe37-dbe3-4b94-8317-1923a5111588"
+version = "0.7.9"
+
+[[deps.PolyesterWeave]]
+deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"]
+git-tree-sha1 = "240d7170f5ffdb285f9427b92333c3463bf65bf6"
+uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad"
+version = "0.2.1"
+
+[[deps.PolygonOps]]
+git-tree-sha1 = "77b3d3605fc1cd0b42d95eba87dfcd2bf67d5ff6"
+uuid = "647866c9-e3ac-4575-94e7-e3d426903924"
+version = "0.1.2"
+
+[[deps.Polynomials]]
+deps = ["LinearAlgebra", "RecipesBase", "Setfield", "SparseArrays"]
+git-tree-sha1 = "a9c7a523d5ed375be3983db190f6a5874ae9286d"
+uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
+version = "4.0.6"
+
+    [deps.Polynomials.extensions]
+    PolynomialsChainRulesCoreExt = "ChainRulesCore"
+    PolynomialsFFTWExt = "FFTW"
+    PolynomialsMakieCoreExt = "MakieCore"
+    PolynomialsMutableArithmeticsExt = "MutableArithmetics"
+
+    [deps.Polynomials.weakdeps]
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
+    MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
+    MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
+
+[[deps.PositiveFactorizations]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20"
+uuid = "85a6dd25-e78a-55b7-8502-1745935b8125"
+version = "0.2.4"
+
+[[deps.PreallocationTools]]
+deps = ["Adapt", "ArrayInterface", "ForwardDiff"]
+git-tree-sha1 = "64bb68f76f789f5fe5930a80af310f19cdafeaed"
+uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
+version = "0.4.17"
+
+    [deps.PreallocationTools.extensions]
+    PreallocationToolsReverseDiffExt = "ReverseDiff"
+
+    [deps.PreallocationTools.weakdeps]
+    ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
+
+[[deps.PrecompileTools]]
+deps = ["Preferences"]
+git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f"
+uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
+version = "1.2.0"
+
+[[deps.Preferences]]
+deps = ["TOML"]
+git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e"
+uuid = "21216c6a-2e73-6563-6e65-726566657250"
+version = "1.4.1"
+
+[[deps.Primes]]
+deps = ["IntegerMathUtils"]
+git-tree-sha1 = "1d05623b5952aed1307bf8b43bec8b8d1ef94b6e"
+uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae"
+version = "0.5.5"
+
+[[deps.Printf]]
+deps = ["Unicode"]
+uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
+
+[[deps.ProgressMeter]]
+deps = ["Distributed", "Printf"]
+git-tree-sha1 = "00099623ffee15972c16111bcf84c58a0051257c"
+uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
+version = "1.9.0"
+
+[[deps.QOI]]
+deps = ["ColorTypes", "FileIO", "FixedPointNumbers"]
+git-tree-sha1 = "18e8f4d1426e965c7b532ddd260599e1510d26ce"
+uuid = "4b34888f-f399-49d4-9bb3-47ed5cae4e65"
+version = "1.0.0"
+
+[[deps.QuadGK]]
+deps = ["DataStructures", "LinearAlgebra"]
+git-tree-sha1 = "9ebcd48c498668c7fa0e97a9cae873fbee7bfee1"
+uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
+version = "2.9.1"
+
+[[deps.REPL]]
+deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
+uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
+
+[[deps.Random]]
+deps = ["SHA"]
+uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
+
+[[deps.RangeArrays]]
+git-tree-sha1 = "b9039e93773ddcfc828f12aadf7115b4b4d225f5"
+uuid = "b3c3ace0-ae52-54e7-9d0b-2c1406fd6b9d"
+version = "0.3.2"
+
+[[deps.Ratios]]
+deps = ["Requires"]
+git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b"
+uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
+version = "0.4.5"
+weakdeps = ["FixedPointNumbers"]
+
+    [deps.Ratios.extensions]
+    RatiosFixedPointNumbersExt = "FixedPointNumbers"
+
+[[deps.RecipesBase]]
+deps = ["PrecompileTools"]
+git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff"
+uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
+version = "1.3.4"
+
+[[deps.RecursiveArrayTools]]
+deps = ["Adapt", "ArrayInterface", "DocStringExtensions", "GPUArraysCore", "IteratorInterfaceExtensions", "LinearAlgebra", "RecipesBase", "SparseArrays", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables"]
+git-tree-sha1 = "e1d18e3f1e7c66133acd00f0ae2964f9eedefb0b"
+uuid = "731186ca-8d62-57ce-b412-fbd966d074cd"
+version = "3.5.1"
+
+    [deps.RecursiveArrayTools.extensions]
+    RecursiveArrayToolsFastBroadcastExt = "FastBroadcast"
+    RecursiveArrayToolsMeasurementsExt = "Measurements"
+    RecursiveArrayToolsMonteCarloMeasurementsExt = "MonteCarloMeasurements"
+    RecursiveArrayToolsTrackerExt = "Tracker"
+    RecursiveArrayToolsZygoteExt = "Zygote"
+
+    [deps.RecursiveArrayTools.weakdeps]
+    FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
+    Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
+    MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca"
+    Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
+    Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
+
+[[deps.RecursiveFactorization]]
+deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "PrecompileTools", "StrideArraysCore", "TriangularSolve"]
+git-tree-sha1 = "8bc86c78c7d8e2a5fe559e3721c0f9c9e303b2ed"
+uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4"
+version = "0.2.21"
+
+[[deps.Reexport]]
+git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
+uuid = "189a3867-3050-52da-a836-e630ba90ab69"
+version = "1.2.2"
+
+[[deps.RelocatableFolders]]
+deps = ["SHA", "Scratch"]
+git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864"
+uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
+version = "1.0.1"
+
+[[deps.Requires]]
+deps = ["UUIDs"]
+git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
+uuid = "ae029012-a4dd-5104-9daa-d747884805df"
+version = "1.3.0"
+
+[[deps.RingLists]]
+deps = ["Random"]
+git-tree-sha1 = "f39da63aa6d2d88e0c1bd20ed6a3ff9ea7171ada"
+uuid = "286e9d63-9694-5540-9e3c-4e6708fa07b2"
+version = "0.2.8"
+
+[[deps.Rmath]]
+deps = ["Random", "Rmath_jll"]
+git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b"
+uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
+version = "0.7.1"
+
+[[deps.Rmath_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "6ed52fdd3382cf21947b15e8870ac0ddbff736da"
+uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
+version = "0.4.0+0"
+
+[[deps.Roots]]
+deps = ["ChainRulesCore", "CommonSolve", "Printf", "Setfield"]
+git-tree-sha1 = "0f1d92463a020321983d04c110f476c274bafe2e"
+uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
+version = "2.0.22"
+
+    [deps.Roots.extensions]
+    RootsForwardDiffExt = "ForwardDiff"
+    RootsIntervalRootFindingExt = "IntervalRootFinding"
+    RootsSymPyExt = "SymPy"
+    RootsSymPyPythonCallExt = "SymPyPythonCall"
+
+    [deps.Roots.weakdeps]
+    ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
+    IntervalRootFinding = "d2bf35a9-74e0-55ec-b149-d360ff49b807"
+    SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6"
+    SymPyPythonCall = "bc8888f7-b21e-4b7c-a06a-5d9c9496438c"
+
+[[deps.RoundingEmulator]]
+git-tree-sha1 = "40b9edad2e5287e05bd413a38f61a8ff55b9557b"
+uuid = "5eaf0fd0-dfba-4ccb-bf02-d820a40db705"
+version = "0.2.1"
+
+[[deps.RuntimeGeneratedFunctions]]
+deps = ["ExprTools", "SHA", "Serialization"]
+git-tree-sha1 = "6aacc5eefe8415f47b3e34214c1d79d2674a0ba2"
+uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47"
+version = "0.5.12"
+
+[[deps.SHA]]
+uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+version = "0.7.0"
+
+[[deps.SIMDTypes]]
+git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c"
+uuid = "94e857df-77ce-4151-89e5-788b33177be4"
+version = "0.1.0"
+
+[[deps.SLEEFPirates]]
+deps = ["IfElse", "Static", "VectorizationBase"]
+git-tree-sha1 = "3aac6d68c5e57449f5b9b865c9ba50ac2970c4cf"
+uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa"
+version = "0.6.42"
+
+[[deps.SciMLBase]]
+deps = ["ADTypes", "ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FillArrays", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "PrecompileTools", "Preferences", "Printf", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables", "TruncatedStacktraces"]
+git-tree-sha1 = "e54bd4dbce5e7081ba429f4800f21d0414d46636"
+uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
+version = "2.17.1"
+
+    [deps.SciMLBase.extensions]
+    SciMLBaseChainRulesCoreExt = "ChainRulesCore"
+    SciMLBasePartialFunctionsExt = "PartialFunctions"
+    SciMLBasePyCallExt = "PyCall"
+    SciMLBasePythonCallExt = "PythonCall"
+    SciMLBaseRCallExt = "RCall"
+    SciMLBaseZygoteExt = "Zygote"
+
+    [deps.SciMLBase.weakdeps]
+    ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2"
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b"
+    PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
+    PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
+    RCall = "6f49c342-dc21-5d91-9882-a32aef131414"
+    Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
+
+[[deps.SciMLOperators]]
+deps = ["ArrayInterface", "DocStringExtensions", "Lazy", "LinearAlgebra", "Setfield", "SparseArrays", "StaticArraysCore", "Tricks"]
+git-tree-sha1 = "51ae235ff058a64815e0a2c34b1db7578a06813d"
+uuid = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
+version = "0.3.7"
+
+[[deps.Scratch]]
+deps = ["Dates"]
+git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386"
+uuid = "6c6a2e73-6563-6170-7368-637461726353"
+version = "1.2.1"
+
+[[deps.Serialization]]
+uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
+
+[[deps.SetRounding]]
+git-tree-sha1 = "d7a25e439d07a17b7cdf97eecee504c50fedf5f6"
+uuid = "3cc68bcd-71a2-5612-b932-767ffbe40ab0"
+version = "0.2.1"
+
+[[deps.Setfield]]
+deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"]
+git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac"
+uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46"
+version = "1.1.1"
+
+[[deps.ShaderAbstractions]]
+deps = ["ColorTypes", "FixedPointNumbers", "GeometryBasics", "LinearAlgebra", "Observables", "StaticArrays", "StructArrays", "Tables"]
+git-tree-sha1 = "db0219befe4507878b1a90e07820fed3e62c289d"
+uuid = "65257c39-d410-5151-9873-9b3e5be5013e"
+version = "0.4.0"
+
+[[deps.SharedArrays]]
+deps = ["Distributed", "Mmap", "Random", "Serialization"]
+uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"
+
+[[deps.Showoff]]
+deps = ["Dates", "Grisu"]
+git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
+uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
+version = "1.0.3"
+
+[[deps.SignedDistanceFields]]
+deps = ["Random", "Statistics", "Test"]
+git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9"
+uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96"
+version = "0.4.0"
+
+[[deps.SimpleGraphs]]
+deps = ["AbstractLattices", "Combinatorics", "DataStructures", "IterTools", "LightXML", "LinearAlgebra", "LinearAlgebraX", "Optim", "Primes", "Random", "RingLists", "SimplePartitions", "SimplePolynomials", "SimpleRandom", "SparseArrays", "Statistics"]
+git-tree-sha1 = "f65caa24a622f985cc341de81d3f9744435d0d0f"
+uuid = "55797a34-41de-5266-9ec1-32ac4eb504d3"
+version = "0.8.6"
+
+[[deps.SimpleNonlinearSolve]]
+deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "MaybeInplace", "PrecompileTools", "Reexport", "SciMLBase", "StaticArraysCore"]
+git-tree-sha1 = "8d672bd91dc432fb286b6d4bcf1a5dc417e932a3"
+uuid = "727e6d20-b764-4bd8-a329-72de5adea6c7"
+version = "1.2.0"
+
+    [deps.SimpleNonlinearSolve.extensions]
+    SimpleNonlinearSolvePolyesterForwardDiffExt = "PolyesterForwardDiff"
+
+    [deps.SimpleNonlinearSolve.weakdeps]
+    PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b"
+
+[[deps.SimplePartitions]]
+deps = ["AbstractLattices", "DataStructures", "Permutations"]
+git-tree-sha1 = "e9330391d04241eafdc358713b48396619c83bcb"
+uuid = "ec83eff0-a5b5-5643-ae32-5cbf6eedec9d"
+version = "0.3.1"
+
+[[deps.SimplePolynomials]]
+deps = ["Mods", "Multisets", "Polynomials", "Primes"]
+git-tree-sha1 = "7063828369cafa93f3187b3d0159f05582011405"
+uuid = "cc47b68c-3164-5771-a705-2bc0097375a0"
+version = "0.2.17"
+
+[[deps.SimpleRandom]]
+deps = ["Distributions", "LinearAlgebra", "Random"]
+git-tree-sha1 = "3a6fb395e37afab81aeea85bae48a4db5cd7244a"
+uuid = "a6525b86-64cd-54fa-8f65-62fc48bdc0e8"
+version = "0.3.1"
+
+[[deps.SimpleTraits]]
+deps = ["InteractiveUtils", "MacroTools"]
+git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231"
+uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
+version = "0.9.4"
+
+[[deps.SimpleUnPack]]
+git-tree-sha1 = "58e6353e72cde29b90a69527e56df1b5c3d8c437"
+uuid = "ce78b400-467f-4804-87d8-8f486da07d0a"
+version = "1.1.0"
+
+[[deps.Sixel]]
+deps = ["Dates", "FileIO", "ImageCore", "IndirectArrays", "OffsetArrays", "REPL", "libsixel_jll"]
+git-tree-sha1 = "2da10356e31327c7096832eb9cd86307a50b1eb6"
+uuid = "45858cf5-a6b0-47a3-bbea-62219f50df47"
+version = "0.1.3"
+
+[[deps.Sockets]]
+uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
+
+[[deps.SortingAlgorithms]]
+deps = ["DataStructures"]
+git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085"
+uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
+version = "1.2.1"
+
+[[deps.SparseArrays]]
+deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
+uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
+version = "1.10.0"
+
+[[deps.SparseDiffTools]]
+deps = ["ADTypes", "Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "PackageExtensionCompat", "Random", "Reexport", "SciMLOperators", "Setfield", "SparseArrays", "StaticArrayInterface", "StaticArrays", "Tricks", "UnPack", "VertexSafeGraphs"]
+git-tree-sha1 = "c281e11db4eacb36a292a054bac83c5a0aca2a26"
+uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
+version = "2.15.0"
+
+    [deps.SparseDiffTools.extensions]
+    SparseDiffToolsEnzymeExt = "Enzyme"
+    SparseDiffToolsSymbolicsExt = "Symbolics"
+    SparseDiffToolsZygoteExt = "Zygote"
+
+    [deps.SparseDiffTools.weakdeps]
+    Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
+    Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
+    Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
+
+[[deps.Sparspak]]
+deps = ["Libdl", "LinearAlgebra", "Logging", "OffsetArrays", "Printf", "SparseArrays", "Test"]
+git-tree-sha1 = "342cf4b449c299d8d1ceaf00b7a49f4fbc7940e7"
+uuid = "e56a9233-b9d6-4f03-8d0f-1825330902ac"
+version = "0.3.9"
+
+[[deps.SpecialFunctions]]
+deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
+git-tree-sha1 = "e2cfc4012a19088254b3950b85c3c1d8882d864d"
+uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
+version = "2.3.1"
+weakdeps = ["ChainRulesCore"]
+
+    [deps.SpecialFunctions.extensions]
+    SpecialFunctionsChainRulesCoreExt = "ChainRulesCore"
+
+[[deps.StableHashTraits]]
+deps = ["Compat", "SHA", "Tables", "TupleTools"]
+git-tree-sha1 = "5a26dfe46e2cb5f5eca78114c7d49548b9597e71"
+uuid = "c5dd0088-6c3f-4803-b00e-f31a60c170fa"
+version = "1.1.3"
+
+[[deps.StackViews]]
+deps = ["OffsetArrays"]
+git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
+uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
+version = "0.1.1"
+
+[[deps.Static]]
+deps = ["IfElse"]
+git-tree-sha1 = "f295e0a1da4ca425659c57441bcb59abb035a4bc"
+uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
+version = "0.8.8"
+
+[[deps.StaticArrayInterface]]
+deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "Requires", "SparseArrays", "Static", "SuiteSparse"]
+git-tree-sha1 = "5d66818a39bb04bf328e92bc933ec5b4ee88e436"
+uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718"
+version = "1.5.0"
+weakdeps = ["OffsetArrays", "StaticArrays"]
+
+    [deps.StaticArrayInterface.extensions]
+    StaticArrayInterfaceOffsetArraysExt = "OffsetArrays"
+    StaticArrayInterfaceStaticArraysExt = "StaticArrays"
+
+[[deps.StaticArrays]]
+deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"]
+git-tree-sha1 = "fba11dbe2562eecdfcac49a05246af09ee64d055"
+uuid = "90137ffa-7385-5640-81b9-e52037218182"
+version = "1.8.1"
+weakdeps = ["ChainRulesCore", "Statistics"]
+
+    [deps.StaticArrays.extensions]
+    StaticArraysChainRulesCoreExt = "ChainRulesCore"
+    StaticArraysStatisticsExt = "Statistics"
+
+[[deps.StaticArraysCore]]
+git-tree-sha1 = "36b3d696ce6366023a0ea192b4cd442268995a0d"
+uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
+version = "1.4.2"
+
+[[deps.Statistics]]
+deps = ["LinearAlgebra", "SparseArrays"]
+uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
+version = "1.10.0"
+
+[[deps.StatsAPI]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed"
+uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
+version = "1.7.0"
+
+[[deps.StatsBase]]
+deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
+git-tree-sha1 = "1d77abd07f617c4868c33d4f5b9e1dbb2643c9cf"
+uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
+version = "0.34.2"
+
+[[deps.StatsFuns]]
+deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
+git-tree-sha1 = "f625d686d5a88bcd2b15cd81f18f98186fdc0c9a"
+uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
+version = "1.3.0"
+
+    [deps.StatsFuns.extensions]
+    StatsFunsChainRulesCoreExt = "ChainRulesCore"
+    StatsFunsInverseFunctionsExt = "InverseFunctions"
+
+    [deps.StatsFuns.weakdeps]
+    ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
+    InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
+
+[[deps.StrideArraysCore]]
+deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface", "ThreadingUtilities"]
+git-tree-sha1 = "d6415f66f3d89c615929af907fdc6a3e17af0d8c"
+uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da"
+version = "0.5.2"
+
+[[deps.StructArrays]]
+deps = ["Adapt", "ConstructionBase", "DataAPI", "GPUArraysCore", "StaticArraysCore", "Tables"]
+git-tree-sha1 = "0a3db38e4cce3c54fe7a71f831cd7b6194a54213"
+uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
+version = "0.6.16"
+
+[[deps.SuiteSparse]]
+deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
+uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
+
+[[deps.SuiteSparse_jll]]
+deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"]
+uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
+version = "7.2.1+1"
+
+[[deps.SymbolicIndexingInterface]]
+git-tree-sha1 = "74502f408d99fc217a9d7cd901d9ffe45af892b1"
+uuid = "2efcf032-c050-4f8e-a9bb-153293bab1f5"
+version = "0.3.3"
+
+[[deps.TOML]]
+deps = ["Dates"]
+uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.3"
+
+[[deps.TableTraits]]
+deps = ["IteratorInterfaceExtensions"]
+git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
+uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
+version = "1.0.1"
+
+[[deps.Tables]]
+deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"]
+git-tree-sha1 = "cb76cf677714c095e535e3501ac7954732aeea2d"
+uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
+version = "1.11.1"
+
+[[deps.Tar]]
+deps = ["ArgTools", "SHA"]
+uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
+version = "1.10.0"
+
+[[deps.TensorCore]]
+deps = ["LinearAlgebra"]
+git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
+uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
+version = "0.1.1"
+
+[[deps.Test]]
+deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
+uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[[deps.ThreadingUtilities]]
+deps = ["ManualMemory"]
+git-tree-sha1 = "eda08f7e9818eb53661b3deb74e3159460dfbc27"
+uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5"
+version = "0.5.2"
+
+[[deps.TiffImages]]
+deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "ProgressMeter", "UUIDs"]
+git-tree-sha1 = "34cc045dd0aaa59b8bbe86c644679bc57f1d5bd0"
+uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
+version = "0.6.8"
+
+[[deps.TranscodingStreams]]
+git-tree-sha1 = "1fbeaaca45801b4ba17c251dd8603ef24801dd84"
+uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
+version = "0.10.2"
+weakdeps = ["Random", "Test"]
+
+    [deps.TranscodingStreams.extensions]
+    TestExt = ["Test", "Random"]
+
+[[deps.TriangularSolve]]
+deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "Static", "VectorizationBase"]
+git-tree-sha1 = "fadebab77bf3ae041f77346dd1c290173da5a443"
+uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf"
+version = "0.1.20"
+
+[[deps.Tricks]]
+git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f"
+uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775"
+version = "0.1.8"
+
+[[deps.TriplotBase]]
+git-tree-sha1 = "4d4ed7f294cda19382ff7de4c137d24d16adc89b"
+uuid = "981d1d27-644d-49a2-9326-4793e63143c3"
+version = "0.1.0"
+
+[[deps.TruncatedStacktraces]]
+deps = ["InteractiveUtils", "MacroTools", "Preferences"]
+git-tree-sha1 = "ea3e54c2bdde39062abf5a9758a23735558705e1"
+uuid = "781d530d-4396-4725-bb49-402e4bee1e77"
+version = "1.4.0"
+
+[[deps.TupleTools]]
+git-tree-sha1 = "155515ed4c4236db30049ac1495e2969cc06be9d"
+uuid = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6"
+version = "1.4.3"
+
+[[deps.UUIDs]]
+deps = ["Random", "SHA"]
+uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
+
+[[deps.UnPack]]
+git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
+uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
+version = "1.0.2"
+
+[[deps.Unicode]]
+uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
+
+[[deps.UnicodeFun]]
+deps = ["REPL"]
+git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
+uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
+version = "0.4.1"
+
+[[deps.VectorizationBase]]
+deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static", "StaticArrayInterface"]
+git-tree-sha1 = "7209df901e6ed7489fe9b7aa3e46fb788e15db85"
+uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f"
+version = "0.21.65"
+
+[[deps.VertexSafeGraphs]]
+deps = ["Graphs"]
+git-tree-sha1 = "8351f8d73d7e880bfc042a8b6922684ebeafb35c"
+uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f"
+version = "0.2.0"
+
+[[deps.WoodburyMatrices]]
+deps = ["LinearAlgebra", "SparseArrays"]
+git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511"
+uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
+version = "1.0.0"
+
+[[deps.XML2_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"]
+git-tree-sha1 = "801cbe47eae69adc50f36c3caec4758d2650741b"
+uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
+version = "2.12.2+0"
+
+[[deps.XSLT_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
+git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
+uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
+version = "1.1.34+0"
+
+[[deps.Xorg_libX11_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
+git-tree-sha1 = "afead5aba5aa507ad5a3bf01f58f82c8d1403495"
+uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
+version = "1.8.6+0"
+
+[[deps.Xorg_libXau_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "6035850dcc70518ca32f012e46015b9beeda49d8"
+uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
+version = "1.0.11+0"
+
+[[deps.Xorg_libXdmcp_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "34d526d318358a859d7de23da945578e8e8727b7"
+uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
+version = "1.1.4+0"
+
+[[deps.Xorg_libXext_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
+git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
+uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
+version = "1.3.4+4"
+
+[[deps.Xorg_libXrender_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
+git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
+uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
+version = "0.9.10+4"
+
+[[deps.Xorg_libpthread_stubs_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "8fdda4c692503d44d04a0603d9ac0982054635f9"
+uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
+version = "0.1.1+0"
+
+[[deps.Xorg_libxcb_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
+git-tree-sha1 = "b4bfde5d5b652e22b9c790ad00af08b6d042b97d"
+uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
+version = "1.15.0+0"
+
+[[deps.Xorg_xtrans_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "e92a1a012a10506618f10b7047e478403a046c77"
+uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
+version = "1.5.0+0"
+
+[[deps.Zlib_jll]]
+deps = ["Libdl"]
+uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
+version = "1.2.13+1"
+
+[[deps.isoband_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "51b5eeb3f98367157a7a12a1fb0aa5328946c03c"
+uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4"
+version = "0.2.3+0"
+
+[[deps.libaec_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl"]
+git-tree-sha1 = "eddd19a8dea6b139ea97bdc8a0e2667d4b661720"
+uuid = "477f73a3-ac25-53e9-8cc3-50b2fa2566f0"
+version = "1.0.6+1"
+
+[[deps.libaom_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4"
+uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b"
+version = "3.4.0+0"
+
+[[deps.libass_jll]]
+deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
+git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
+uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
+version = "0.15.1+0"
+
+[[deps.libblastrampoline_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
+version = "5.8.0+1"
+
+[[deps.libevent_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll"]
+git-tree-sha1 = "f04ec6d9a186115fb38f858f05c0c4e1b7fc9dcb"
+uuid = "1080aeaf-3a6a-583e-a51c-c537b09f60ec"
+version = "2.1.13+1"
+
+[[deps.libfdk_aac_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
+uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
+version = "2.0.2+0"
+
+[[deps.libpng_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"]
+git-tree-sha1 = "93284c28274d9e75218a416c65ec49d0e0fcdf3d"
+uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
+version = "1.6.40+0"
+
+[[deps.libsixel_jll]]
+deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "libpng_jll"]
+git-tree-sha1 = "d4f63314c8aa1e48cd22aa0c17ed76cd1ae48c3c"
+uuid = "075b6546-f08a-558a-be8f-8157d0f608a5"
+version = "1.10.3+0"
+
+[[deps.libvorbis_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
+git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c"
+uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
+version = "1.3.7+1"
+
+[[deps.nghttp2_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
+version = "1.52.0+1"
+
+[[deps.p7zip_jll]]
+deps = ["Artifacts", "Libdl"]
+uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
+version = "17.4.0+2"
+
+[[deps.prrte_jll]]
+deps = ["Artifacts", "Hwloc_jll", "JLLWrappers", "Libdl", "PMIx_jll", "libevent_jll"]
+git-tree-sha1 = "5adb2d7a18a30280feb66cad6f1a1dfdca2dc7b0"
+uuid = "eb928a42-fffd-568d-ab9c-3f5d54fc65b9"
+version = "3.0.2+0"
+
+[[deps.x264_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
+uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
+version = "2021.5.5+0"
+
+[[deps.x265_jll]]
+deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
+git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
+uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
+version = "3.5.0+0"
diff --git a/initialdata/Project.toml b/initialdata/Project.toml
index 2438906596a21320495e999e084dcb3e617a376f..dd43dc0852ede65783ae9609e34035d374979f06 100644
--- a/initialdata/Project.toml
+++ b/initialdata/Project.toml
@@ -1,6 +1,8 @@
 [deps]
 CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
-Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
+DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
+HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
+OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
+Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
 Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
-VimBindings = "51b3953f-5e5d-4a6b-bd62-c64b6fa1518a"
-dg1d = "dfc8a8d9-21b0-4914-8ba8-32d2ec29f3fd"
+UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
diff --git a/initialdata/SphericalAccretion.c b/initialdata/SphericalAccretion.c
new file mode 100644
index 0000000000000000000000000000000000000000..e0c4fa66cae27c48792a88a37d0b71e6fc8cfab0
--- /dev/null
+++ b/initialdata/SphericalAccretion.c
@@ -0,0 +1,95 @@
+// copied from bamps/src/projects/grhd/initialdata/michel.c
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void main(int argc, char *argv[]) {
+
+    double M = 1.0;
+    double rc = 200.0*M;
+    double rhoc = 7e-4;
+    double gamma = 4.0/3.0;
+
+    double urc   = sqrt(.5 * M / rc);
+    double Vc2   = urc*urc / (1.-3.*urc*urc);
+
+    double K     = Vc2*(gamma-1.)*pow(rhoc,1.-gamma) / (gamma*(-Vc2+gamma-1.));
+
+    double hc    = 1. + gamma / (gamma-1.) * K * pow(rhoc,gamma-1.);
+    double c1    = rhoc * urc * rc * rc;
+    double c3    = hc * hc * (urc*urc + 1. - 2.*M / rc);
+
+    int nnn = 1000;
+    int i;
+    double r;
+    double rmin = 1.8*M, rmax = 200.0*M;
+    double dr = (rmax-rmin)/(nnn-1);
+
+    double *gr      = malloc(nnn*sizeof(double));
+    double *grho    = malloc(nnn*sizeof(double));
+    double *geps    = malloc(nnn*sizeof(double));
+    double *gp      = malloc(nnn*sizeof(double));
+    double *gvr     = malloc(nnn*sizeof(double));
+    double *gur     = malloc(nnn*sizeof(double));
+    double *gut2    = malloc(nnn*sizeof(double));
+
+    for(i=0; i<nnn; i++) {
+
+      r = rmax - dr*i;
+      gr[i] = r;
+
+      double ur    = sqrt(fabs(-1. + 2.*M / r) + 0.01);
+      double ut2, h, f, df;
+
+      int it=0;
+      for(it=0;it<100;it++) {
+
+        ut2 = (ur*ur+1.-2.*M/r);
+        h   = 1. + (gamma / (gamma-1.)) * K * pow(c1 / (ur*r*r), gamma-1.);
+        f   = h*h*ut2 - c3;
+        df = 2. * h * (-(h-1.)*(gamma-1.)/ur) * ut2 + 2. * h * h * ur;
+
+        ur = ur - f/df;
+
+        if(fabs(f/df)<1.e-14) break;
+
+      }
+
+      grho[i] = c1 / (ur*r*r);
+      gp[i]   = K * pow(grho[i],gamma);
+      geps[i] = gp[i] / (grho[i]*(gamma-1.));
+
+      ut2 = (ur*ur+1.-2.*M/r);
+      gur[i] = ur;
+      gut2[i] = ut2;
+
+      double alpha = sqrt(r / (r + 2.*M));
+      double betar = 2.*M / (r + 2.*M);
+      double ut    = (-2.*M * ur / r + sqrt(ut2)) / (-1.+2.*M/r);
+      double vr    = ur / (alpha*ut) + betar / alpha;
+
+      gvr[i] = vr;
+
+    }
+
+
+    FILE *io = fopen("bondi-acc-ref.txt", "w");
+    if (!io) {
+      printf("FAILED\n");
+      exit(-1);
+    }
+    for (i=nnn-1; i>=0; i--) {
+      fprintf(io, "% .6e % .6e % .6e % .6e % .6e % .6e % .6e\n", gr[i], grho[i], geps[i], gp[i], gvr[i], gur[i], gut2[i]);
+    }
+    fclose(io); io = NULL;
+
+    free(grho); grho = NULL;
+    free(geps); geps = NULL;
+    free(gp);   gp = NULL;
+    free(gvr);  gvr = NULL;
+    free(gr);   gr = NULL;
+    free(gur);  gur = NULL;
+    free(gut2); gut2 = NULL;
+
+}
diff --git a/initialdata/SphericalAccretion.jl b/initialdata/SphericalAccretion.jl
index 5b3cc8a095ec412651a6086c0e101c1b62eb3a22..15e4661f8044574c7635fc6d6be7cfae41bd49eb 100644
--- a/initialdata/SphericalAccretion.jl
+++ b/initialdata/SphericalAccretion.jl
@@ -1,5 +1,14 @@
+module SphericalAccretion
+
+
+
 using CairoMakie
+using CairoMakie.FileIO
+using DelimitedFiles
 using Printf
+using HDF5
+using Roots
+using UnPack
 
 
 """
@@ -7,53 +16,51 @@ Solution taken from Bugner [2017], section 4.2.
 
 Kerr-Schild coordinates allow use to go beyond horizon towards the singularity.
 However, it becomes more difficult for the Newton Rapshon solver to determine a solution
-once beyond the horizon. To this end, try increasing `N_rs` whenever you lower `rmin` and 
+once beyond the horizon. To this end, try increasing `N_rs` whenever you lower `rmin` and
 the solver aborts inside the horizon.
 Alternatively, one could also add an adaptive stepper.
 
 Note: We implicitly assume θ = π/2, because then sin(θ) = 1, although,
 the sines should cancel out everywhere.
 """
-function solve()
-
-  # parameters
-  M = 1.0
-  N_rs = 100000
-  rmin, rmax = 0.1*M, 200*M
-  rc, ρc, Γ = 200*M, 7e-4, 4/3
+function solve(; rmin, rmax, rc, ρc, Γ, M=1.0, N_rs=1000,
+                 urc_sign=1)
 
-  urc = sqrt(M / (2 * rc))
+  urc = urc_sign*sqrt(M /(2 * rc))
   # cannot find solutions within these regions, cf. Michel 1972
   @show urc
   @assert rc >= 6*M
-  @assert urc <= 1 / 3
+  @assert urc^2 <= 1 / 3
 
-  Vc2 = urc^2 / (1 - 3 * urc^2)
-  K = Vc2 * (Γ - 1) / ( (Γ - 1 - Vc2) * Γ * ρc^(Γ - 1) )
+  Vc = urc^2 / (1 - 3 * urc^2)
+  K = Vc * (Γ - 1) / ( (Γ - 1 - Vc) * Γ * ρc^(Γ - 1) )
+  @show K
 
   # here we set θ = π/2 so that sin(θ) = 1
-  C1 = rc^2 * ρc * urc
   hc = 1 + K * Γ * ρc^(Γ - 1) / (Γ - 1)
   u0c = sqrt(1 - 2 * M / rc + urc^2)
+  C1 = rc^2 * ρc * urc
+  C2 = rc^2 * ρc * hc * u0c * urc
   C3 = hc^2 * u0c^2
 
   function F(ur, r)
     ρ = C1 / (r^2 * ur)
     h = 1 + K * Γ * ρ^(Γ - 1) / (Γ - 1)
     u0 = sqrt(1 - 2 * M / r + ur^2)
-    u0 = sqrt(1 - 2 * M / r + ur^2)
     return h^2 * u0^2 - C3
   end
 
-  function dF(ur, r)
-    ρ = C1 / (r^2 * ur)
-    h = 1 + K * Γ * ρ^(Γ - 1) / (Γ - 1)
-    u0 = sqrt(1 - 2 * M / r + ur^2)
-    dρdur = - C1 / (r^2 * ur^2)
-    dhdρ = K * Γ * ρ^(Γ - 2)
-    du0dur = ur / u0
-    return 2 * (u0^2 * h * dhdρ * dρdur + h^2 * u0 * du0dur)
-  end
+  # manually compute derviative and
+  # use Roots.find_zero((F_at_r,dF_at_r), ur_guess, Roots.Newton()) below
+  # function dF(ur, r)
+  #   ρ = C1 / (r^2 * ur)
+  #   h = 1 + K * Γ * ρ^(Γ - 1) / (Γ - 1)
+  #   u0 = sqrt(1 - 2 * M / r + ur^2)
+  #   dρdur = - C1 / (r^2 * ur^2)
+  #   dhdρ = K * Γ * ρ^(Γ - 2)
+  #   du0dur = ur / u0
+  #   return 2 * (u0^2 * h * dhdρ * dρdur + h^2 * u0 * du0dur)
+  # end
 
   # radial domain over which we solve
   rs = collect(LinRange(rmin, rmax, N_rs))
@@ -65,52 +72,275 @@ function solve()
     # - use the previous result for the remaining radi
     # The following converges to the correct solution:
     if r > 2*M
-      ur_guess = sqrt(1 - 2 * M / r) # asymptotic value for ur
+      ur_guess = urc_sign*sqrt(1 - 2 * M / r) # = sqrt(1+gtt), =^= asymptotic value for ur when u0 -> 1
     else
       ur_guess = urs[idx+1] # use previous iterate where asymptotic value is not defined
     end
     F_at_r(ur) = F(ur, r)
-    dF_at_r(ur) = dF(ur, r)
+    # dF_at_r(ur) = dF(ur, r)
     ur = try
-      Roots.find_zero((F_at_r,dF_at_r), ur_guess, Roots.Newton())
+      # Roots.find_zero((F_at_r,dF_at_r), ur_guess, Roots.Newton())
+      Roots.find_zero(F_at_r, ur_guess)
     catch err
       println()
-      error("Could not determine solution for 'ur' at radius r = $r. " *
-            "Remaining error: $err")
+      @info("Could not determine solution for 'ur' at radius r = $r. ")
+      rethrow(err)
     end
     # @show (ur, r)
-    if ur < 0.0
-      @warn "Aborting due to ur becoming negative at r = $r." 
-      @info "$(N_rs - idx) points skipped ..."
-      break
-    end
+    # if ur < 0.0
+    #   @warn "Aborting due to ur becoming negative at r = $r."
+    #   @info "$(N_rs - idx) points skipped ..."
+    #   break
+    # end
     urs[idx] = ur
   end
 
   ρs = @. C1 / (rs^2 * urs)
   ps = @. K * ρs^Γ
   ϵs = @. ps / ((Γ - 1) * ρs)
-  βr = @. 2 * M / (rs + 2 * M)
+  βr = @. 2 * M / (rs + 2 * M) # = β^r
   α = @. sqrt( rs / (rs + 2 * M) )
-
-  gtt_uu = @. - (2 * M + rs) / rs
-  gtr_uu = @. 2 * M / rs
-  grr_uu = @. (rs - 2 * M) / rs
+  γrr   = @. 1 + 2*M/rs
+  γrr_uu = @. 1/γrr
+  gtt_uu = @. -1/α^2
+  gtr_uu = @. βr/α^2
+  grr_uu = @. γrr_uu - βr*βr/α^2
+  gtt   = @. -α^2 + γrr*βr*βr
+  gtr   = @. γrr * βr
+  grr   = @. γrr
   u0s_d = @. sqrt(1 - 2 * M / rs + urs^2)
   u0s_u = @. gtt_uu * u0s_d + gtr_uu / grr_uu * (urs - gtr_uu * u0s_d)
+  # u0s_u_v2 = @. (gtt_uu * u0s_d + gtr_uu*grr*urs)/(1-gtr*gtr_uu)
+  # @show(maximum(abs, u0s_u .- u0s_u_v2))
   vrs = @. urs / (α * u0s_u) + βr / α
+  vrs_d = @. γrr * vrs
+  hs = @. 1 + K * Γ * ρs^(Γ - 1) / (Γ - 1)
+  res_C1 = @. rs^2 * ρs * urs - C1
+  res_C2 = @. rs^2 * ρs * hs * u0s_d * urs - C2
+  res_C3 = @. hs^2 * u0s_d^2 - C3
+  vs = @. sqrt(γrr * vrs^2)
+
+  return (; rs, urs, vrs, ρs, ps, ϵs, res_C1, res_C2, res_C3, vs, vrs_d,
+            rmin, rmax, rc, Vc, ρc, Γ, M, N_rs, K)
+
+end
+
+
+function solve_ref()
+  # reference data from bugner's solver SphericalAccretion.c (extracted from bamps)
+  M = 1.0
+  rmin, rmax = 1.8*M, 200*M
+  rc, ρc, Γ = 200*M, 7e-4, 4/3
+  solve(; rmin, rmax, rc, ρc, Γ, M)
+end
+
+function solve_papadopoulus_1998()
+  # arXiv:gr-qc/9803087v1
+  # works with Eddington-Finkelstein coords (same form as Bugner; but Bugner calls them Kerr-Schild?)
+  M = 1.0
+  rmin, rmax = 0.5*M, 50*M
+  rc, ρc, Γ = 400*M, 1e-2, 4/3
+  solve(; rmin, rmax, rc, ρc, Γ, M)
+end
+
+function solve_papadopoulus_1999()
+  # arXiv:gr-qc/9902018v1
+  # works with ingoing Eddington-Finkelstein coords, but the equations appear to be the same
+  # compare with the 1998 paper, in these coordinates G(r) = 0
+  M = 1.0
+  rmin, rmax = 1.5*M, 30*M
+  rc, ρc, Γ = 200*M, 1e-2, 5/3
+  solve(; rmin, rmax, rc, ρc, Γ, M)
+end
+
+
+function save(fname, data)
+  # save
+  filename = joinpath(@__DIR__, fname)
+  h5open(filename, "w") do file
+    @info "Saving results to '$filename' ..."
+    g = create_group(file, "bondi_accretion")
+    HDF5.attributes(g)["rc"]   = data.rc
+    HDF5.attributes(g)["ρc"]   = data.ρc
+    HDF5.attributes(g)["Vc"]   = data.Vc
+    HDF5.attributes(g)["Γ"]    = data.Γ
+    HDF5.attributes(g)["M"]    = data.M
+    HDF5.attributes(g)["K"]    = data.K
+    HDF5.attributes(g)["rmin"] = data.rmin
+    HDF5.attributes(g)["rmax"] = data.rmax
+    g["r"]  = data.rs
+    g["ur"] = data.urs
+    g["vr"] = data.vrs
+    g["ρ"]  = data.ρs
+    g["p"]  = data.ps
+    g["ϵ"]  = data.ϵs
+  end
+  return
+end
+
+
+function plot(data)
+
+  @unpack M, ρs, ps, ϵs, vrs, rs, res_C1, res_C2, res_C3, vrs_d = data
 
   fig = Figure()
-  ax_ρ   = Axis(fig[1,1], xlabel="r", ylabel="ρ")
-  ax_p   = Axis(fig[1,2], xlabel="r", ylabel="p")
-  ax_ϵ   = Axis(fig[2,1], xlabel="r", ylabel="ϵ")
-  ax_v_r = Axis(fig[2,2], xlabel="r", ylabel="v_r")
+  ax_ρ      = Axis(fig[1,1], xlabel=L"r", ylabel=L"\rho")
+  ax_p      = Axis(fig[1,2], xlabel=L"r", ylabel=L"p")
+  ax_ϵ      = Axis(fig[2,1], xlabel=L"r", ylabel=L"\epsilon")
+  ax_v_r    = Axis(fig[2,2], xlabel=L"r", ylabel=L"v^r")
+  # ax_res_C1 = Axis(fig[3,1], xlabel=L"r", ylabel=L"R_{C_1}")
+  # ax_res_C2 = Axis(fig[3,2], xlabel=L"r", ylabel=L"R_{C_2}")
+  # ax_res_C3 = Axis(fig[4,1], xlabel=L"r", ylabel=L"R_{C_3}")
+  # ax_v_r_d  = Axis(fig[4,2], xlabel=L"r", ylabel=L"v_r")
+
+  rhor = 2*M # radius of horizon
 
   lines!(ax_ρ, rs, ρs)
   lines!(ax_p, rs, ps)
   lines!(ax_ϵ, rs, ϵs)
   lines!(ax_v_r, rs, vrs)
+  # lines!(ax_res_C1, rs, res_C1)
+  # lines!(ax_res_C2, rs, res_C2)
+  # lines!(ax_res_C3, rs, res_C3)
+  # lines!(ax_v_r_d, rs, vrs_d)
+  vlines!(ax_ρ, rhor, linestyle=:dash)
+  vlines!(ax_p, rhor, linestyle=:dash)
+  vlines!(ax_ϵ, rhor, linestyle=:dash)
+  vlines!(ax_v_r, rhor, linestyle=:dash)
+  # vlines!(ax_v_r_d, rhor, linestyle=:dash)
+
+  # xlims!(ax_ρ, (1.8,10.0))
+  # xlims!(ax_p, (1.8,10.0))
+  # xlims!(ax_ϵ, (1.8,10.0))
+  # xlims!(ax_v_r, (1.8,10.0))
 
   # use save("filename.pdf", fig) to save to pdf
   return fig
 end
+
+
+function plot_compare_ref()
+
+  mydata = solve_ref()
+  csv = readdlm(joinpath(@__DIR__, "bondi-acc-ref.txt"))
+  refdata = (; rs=csv[:,1],
+               ρs=csv[:,2],
+               ϵs=csv[:,3],
+               ps=csv[:,4],
+               vrs=csv[:,5],
+               urs=csv[:,6],
+               ut2=csv[:,7])
+
+  fig = Figure()
+  ax_ρ      = Axis(fig[1,1], xlabel=L"r", ylabel=L"\rho")
+  ax_p      = Axis(fig[1,2], xlabel=L"r", ylabel=L"p")
+  ax_ϵ      = Axis(fig[2,1], xlabel=L"r", ylabel=L"\epsilon")
+  ax_vr     = Axis(fig[2,2], xlabel=L"r", ylabel=L"v^r")
+  ax_ur     = Axis(fig[3,1], xlabel=L"r", ylabel=L"u^r")
+
+  lines!(ax_ρ,   mydata.rs,  mydata.ρs)
+  lines!(ax_p,   mydata.rs,  mydata.ps)
+  lines!(ax_ϵ,   mydata.rs,  mydata.ϵs)
+  lines!(ax_vr,  mydata.rs,  mydata.vrs)
+  lines!(ax_ur,  mydata.rs,  mydata.urs)
+  lines!(ax_ρ,   refdata.rs, refdata.ρs, linestyle=:dash)
+  lines!(ax_p,   refdata.rs, refdata.ps, linestyle=:dash)
+  lines!(ax_ϵ,   refdata.rs, refdata.ϵs, linestyle=:dash)
+  lines!(ax_vr,  refdata.rs, refdata.vrs, linestyle=:dash)
+  lines!(ax_ur,  refdata.rs, refdata.urs, linestyle=:dash)
+
+  rhor = 2*mydata.M
+  vlines!(ax_ρ, rhor, linestyle=:dash, color=:grey)
+  vlines!(ax_p, rhor, linestyle=:dash, color=:grey)
+  vlines!(ax_ϵ, rhor, linestyle=:dash, color=:grey)
+  vlines!(ax_vr, rhor, linestyle=:dash, color=:grey)
+  vlines!(ax_ur, rhor, linestyle=:dash, color=:grey)
+
+  return fig
+
+end
+
+
+function plot_compare_papadopoulus_1998()
+
+  mydata = solve_papadopoulus_1998()
+  img_p = load("bondi-acc_papadopoulos1998_p.png")
+  img_ρ = load("bondi-acc_papadopoulos1998_rho.png")
+  # v = sqrt(γ_rr) v^r; is called total velocity in the paper (hidden in text)
+  # the label in the plot is just 'Velocity'
+  img_v = load("bondi-acc_papadopoulos1998_v.png")
+
+  xmin, xmax = 0.0, 15.0
+  ymin_ρ, ymax_ρ = 0, 120.0
+  ymin_p, ymax_p = 0, 2.5
+  ymin_vr, ymax_vr = -0.3, -0.2
+
+  fig = Figure()
+  ax_p  = Axis(fig[1,1], xlabel=L"r", ylabel=L"p")
+  ax_ρ  = Axis(fig[2,1], xlabel=L"r", ylabel=L"\rho")
+  ax_vr = Axis(fig[3,1], xlabel=L"r", ylabel=L"v^r")
+
+  image!(ax_ρ, xmin..xmax, ymin_ρ..ymax_ρ, rotr90(img_ρ))
+  image!(ax_p, xmin..xmax, ymin_p..ymax_p, rotr90(img_p))
+  image!(ax_vr, xmin..xmax, ymin_vr..ymax_vr, rotr90(img_v))
+
+  lines!(ax_ρ,  mydata.rs, mydata.ρs, linestyle=:dash, color=:orange)
+  lines!(ax_p,  mydata.rs, mydata.ps, linestyle=:dash, color=:orange)
+  # don't understand why they plot with a minus here
+  # there seem to be ingoing and outgoing solutions (urc_sign parameter),
+  # but the value for v never fits
+  lines!(ax_vr, mydata.rs, -mydata.vs, linestyle=:dash, color=:orange)
+
+  xlims!(ax_ρ,   (xmin,xmax))
+  xlims!(ax_p,   (xmin,xmax))
+  xlims!(ax_vr,  (xmin,xmax))
+  ylims!(ax_ρ,   (ymin_ρ,ymax_ρ))
+  ylims!(ax_p,   (ymin_p,ymax_p))
+  ylims!(ax_vr,  (ymin_vr,ymax_vr))
+
+  return fig
+end
+
+
+function plot_compare_papadopoulus_1999()
+
+  mydata = solve_papadopoulus_1999()
+  img_ϵ = load("bondi-acc_papadopoulos1999_eps.png")
+  img_ρ = load("bondi-acc_papadopoulos1999_rho.png")
+  img_vr = load("bondi-acc_papadopoulos1999_vr.png")
+
+  xmin, xmax = 1.0, 10.0
+  ymin_ρ, ymax_ρ = 0, 10.0
+  ymin_ϵ, ymax_ϵ = 0, 0.25
+  ymin_vr, ymax_vr = -1.0, 0.0
+
+  fig = Figure()
+  ax_ϵ  = Axis(fig[1,1], xlabel=L"r", ylabel=L"\epsilon")
+  ax_ρ  = Axis(fig[2,1], xlabel=L"r", ylabel=L"\rho")
+  ax_vr = Axis(fig[3,1], xlabel=L"r", ylabel=L"u^r")
+
+  image!(ax_ρ, xmin..xmax, ymin_ρ..ymax_ρ, rotr90(img_ρ))
+  image!(ax_ϵ, xmin..xmax, ymin_ϵ..ymax_ϵ, rotr90(img_ϵ))
+  image!(ax_vr, xmin..xmax, ymin_vr..ymax_vr, rotr90(img_vr))
+
+  lines!(ax_ρ,  mydata.rs, mydata.ρs, linestyle=:dash, color=:orange)
+  lines!(ax_ϵ,  mydata.rs, mydata.ϵs, linestyle=:dash, color=:orange)
+  # don't understand why they plot with a minus here
+  # there seem to be ingoing and outgoing solutions (urc_sign parameter),
+  # but the value for ur never fits
+  lines!(ax_vr, mydata.rs, -mydata.urs, linestyle=:dash, color=:orange)
+  display(extrema(mydata.urs))
+
+  xlims!(ax_ρ,   (xmin,xmax))
+  xlims!(ax_ϵ,   (xmin,xmax))
+  xlims!(ax_vr,  (xmin,xmax))
+  ylims!(ax_ρ,   (ymin_ρ,ymax_ρ))
+  ylims!(ax_ϵ,   (ymin_ϵ,ymax_ϵ))
+  ylims!(ax_vr,  (ymin_vr,ymax_vr))
+
+  return fig
+end
+
+
+
+end # module
diff --git a/initialdata/TOV.jl b/initialdata/TOV.jl
index 1ceca0fe202eafa7561fdec9a961472768a153a1..ddf49ec3a4fc962df36709a7d04568cb3cb31f24 100644
--- a/initialdata/TOV.jl
+++ b/initialdata/TOV.jl
@@ -2,58 +2,65 @@ export TOV
 module TOV
 
 
-using dg1d
-using LaTeXStrings
-using Plots
+import CairoMakie
+import CairoMakie: @L_str
+using HDF5
+using OrdinaryDiffEq
 using Printf
 
 
 # array indices of state vector
-const idx_p, idx_m, idx_Ï•, idx_R, idx_r = 1, 2, 3, 4, 5
+const idx_p, idx_m, idx_ϕ, idx_λ = 1, 2, 3, 4
 
 
-function TOV_rhs!(du, u, r, eos::Polytrope)
+function TOV_rhs!(du, u, p, r)
+
+  # parameters for polytropic equation of state
+  (; K, Γ) = p
 
   if r == 0.0
     du .= 0.0
   else
     p, m = u[idx_p], u[idx_m]
 
-    ϵ = try
-      rho = eos(Density, Pressure, p)
-      eps = eos(InternalEnergy, Density, rho)
-      eos(TotalEnergy, Density, rho, InternalEnergy, eps)
+    e = try
+      ρ = (p/K)^(1/Γ)
+      ϵ = K / (Γ-1) * ρ^(Γ-1)
+      ρ*(1+ϵ)
     catch err
       if err isa DomainError
         0.0
       else
-        rethrow(e)
+        rethrow(err)
       end
     end
 
     # dp/dr
-    du[idx_p] = - (ϵ + p) * (m + 4.0 * π * r^3 * p) / (r * (r - 2.0 * m))
+    du[idx_p] = - (e + p) * (m + 4.0 * π * r^3 * p) / (r * (r - 2.0 * m))
     # dm/dr
-    du[idx_m] = 4.0 * π * r^2 * ϵ
+    du[idx_m] = 4.0 * π * r^2 * e
     # dϕ/dr
-    du[idx_ϕ] = - du[idx_p] / (ϵ + p)
-    # dR/dr
-    du[idx_R] = (1.0 - sqrt(1.0 - 2.0 * m / r)) / sqrt(r^2 - 2.0 * m * r)
+    du[idx_Ï•] = - du[idx_p] / (e + p)
+    # regular term of dR/dr ODE
+    du[idx_λ] = (1.0 - sqrt(1.0 - 2.0 * m / r)) / sqrt(r^2 - 2.0 * m * r)
   end
 
   return
 end
 
 
-function solve()
+"""
+Compute TOV solution for a polytropic equation of state.
+  - Γ: polytropic exponent
+  - K: polytropic constant
+  - ρc: central density
+  - rmax: [optional] maximum integration radius, increase when integration does not proceed till surface
+"""
+function solve(; Γ, K, ρc, rmax=30.0)
 
-  # equation of state
-  Γ = 2
-  K = 100
-  # ρc = 8.00 * 1e-3 # central rest mass density
-  ρc = 1.28 * 1e-3 # central rest mass density
-  eos = Polytrope(K = K, Gamma = Γ)
-  pc = eos(Pressure, Density, ρc, InternalEnergy, nothing)
+  # equation of state parameters
+  prms = (; K, Γ)
+  pc = K*ρc^Γ
 
   # initial values
   # Note: We put Ï•(0) = 0 as initial condition for the potential in the interior
@@ -70,155 +77,112 @@ function solve()
   u0[idx_p] = pc
   u0[idx_m] = 0.0
   u0[idx_Ï•] = 0.0
-  u0[idx_R] = 0.0
-
+  u0[idx_λ] = 0.0
 
   dr = 1e-2 # inital step width for r
-  r_range = [0.0, 30.0] # max integration range
-  ODE!(du, u, r) = TOV_rhs!(du, u, r, eos)
-
-
-  # post hook setup to 
-  #   - store solution
-  #   - terminate ODE solver if pressure drops below p_threshold
-  # solution = [u0..., r_range[1]]
-  storage_increment = 1000
-  n_variables = 5
-  solution = zeros(Float64, storage_increment, n_variables)
-  solution[1,:] .= [ u0..., r_range[1] ]
-  counter = 1
-  p_threshold = 1e-14
-  function post_hook(u, r)
-    counter += 1
-    if counter >= size(solution)[1]
-      zs = zeros(Float64, storage_increment, n_variables)
-      solution = vcat(solution, zs)
-    end
-    solution[counter, :] .= [ u..., r ]
-    p = u[idx_p]
-    return (p > p_threshold) # continue as long as this is true
+  r_range = [0.0, rmax] # max integration range
+  prob = ODEProblem(TOV_rhs!,u0,r_range,prms)
+
+  sol = OrdinaryDiffEq.solve(prob, Tsit5(), dt=dr, adaptive=false)
+
+  nsteps = length(sol)
+  p, m, ϕ, λ, r = Float64[], Float64[], Float64[], Float64[], Float64[]
+  for (i,(ui,ri)) in enumerate(zip(sol.u,sol.t))
+    ui[idx_p] < 0 && break
+    push!(p, ui[idx_p])
+    push!(m, ui[idx_m])
+    push!(Ï•, ui[idx_Ï•])
+    push!(λ, ui[idx_λ])
+    push!(r, ri)
   end
 
-  # solve ODE
-  pblm = dg1d.ODEProblem(:rk4)
-  dg1d.evolve_adaptive_ERK(pblm, ODE!, u0, dr, r_range[2], post_hook=post_hook)
+  ρ = @. (p/K)^(1/Γ)
+  ϵ = @. K / (Γ-1) * ρ^(Γ-1)
 
-  # chop off trailing zeros
-  solution = solution[1:counter,:]
+  # attach Schwarzschild solution exterior to star's surface
+  M      = m[end]
+  r_surf = r[end]
+  λ_surf = λ[end]
+  # potential difference (wrt Schwarzschild solution) at star's surface
+  Δϕ_surf = ϕ[end] - (0.5 * log(1.0 - 2.0 * M / r_surf))
+  # adjust interior potential to align with exterior at star's surface
+  ϕ .-= Δϕ_surf
 
-  M      = solution[end, idx_m]
-  r_surf = solution[end, idx_r]
-  R_surf = solution[end, idx_R]
-  @info "M = $M"
-  @info "r = $r_surf"
-  @info "R = $R_surf"
+  R = @. 0.5*r/r_surf * (sqrt(r_surf^2 - 2*M*r_surf) + r_surf - M) * exp(λ - λ_surf)
+  R_surf = R[end]
+  @show M, r_surf, R_surf
+
+  return (; K, Γ, ρc, M, dr, p, m, ϕ, R, ρ, ϵ, r)
+end
 
-  # potential at star's surface
-  Δϕ_surf = solution[end,idx_ϕ] - (0.5 * log(1.0 - 2.0 * M / r_surf))
-  # adjust interior potential to align with exterior at star's surface
-  solution[:,idx_ϕ] .-= Δϕ_surf
 
-  # fix integration constant between isotropic and schwarzschild coordinate
-  Rs = R_surf
-  rs = r_surf
-  r = solution[:,idx_r]
-  R = solution[:,idx_R]
-  @. solution[:,idx_R] = 0.5 * r / rs * (sqrt(rs^2 - 2 * M * rs) + rs - M) * exp(R - Rs)
+function solve_bugner_stable()
+  solve(Γ=2.0, K=100.0, ρc=1.28e-3)
+end
+function solve_bugner_unstable()
+  solve(Γ=2.0, K=100.0, ρc=8e-3)
+end
 
+
+function save(fname, data)
+  @assert endswith(fname, ".h5")
   # save
-  output_dir = dg1d.get_output_dir()
-  filename = joinpath(output_dir, "TOV.h5")
+  filename = joinpath(@__DIR__, fname)
   h5open(filename, "w") do file
     @info "Saving results to '$filename' ..."
     g = create_group(file, "TOV")
-    attributes(g)["Γ"]  = Γ
-    attributes(g)["K"]  = K
-    attributes(g)["ρc"] = ρc
-    attributes(g)["M"]  = M
-    g["Ï•"] = solution[:,idx_Ï•]
-    g["p"] = solution[:,idx_p]
-    g["m"] = solution[:,idx_m]
-    g["R"] = solution[:,idx_R]
-    g["r"] = solution[:,idx_r]
+    attributes(g)["Γ"]    = data.Γ
+    attributes(g)["K"]    = data.K
+    attributes(g)["ρc"]   = data.ρc
+    attributes(g)["M"]    = data.M
+    attributes(g)["dr"]   = data.dr
+    g["Ï•"] = data.Ï•
+    g["p"] = data.p
+    g["m"] = data.m
+    g["R"] = data.R
+    g["r"] = data.r
+    g["ρ"] = data.ρ
+    g["ϵ"] = data.ϵ
   end
-
   return
 end
 
 
+function plot(data)
 
-function read_data(filename)
-  return h5open(filename, "r") do file
-    g = file["TOV"]
-    Γ = read_attribute(g, "Γ")
-    K = read_attribute(g, "K")
-    ρc = read_attribute(g, "ρc")
-    M = read_attribute(g, "M")
-    Ï• = read(g, "Ï•")
-    p = read(g, "p")
-    m = read(g, "m")
-    R = read(g, "R")
-    r = read(g, "r")
-    (; Γ, K, ρc, M, ϕ, p, m, R, r)
-  end
-end
+  (; ρc, dr, M, r, R, ρ, ϵ, m, p, ϕ) = data
+
+  r_surf = r[end]
+  R_surf = R[end]
+  rmax = r_surf*3
+
+  Ï•int = Ï•
+  Λint = @. -0.5 * log(1.0-2.0*m/r)
+
+  rext = collect(range(r[end], rmax, step=dr))
+  Ï•ext = @. 0.5 * log(1.0-2.0*M/rext)
+  Λext = -ϕext
+
+  fig = CairoMakie.Figure(title="TOV star, $(@sprintf "ρc = %.5f, M = %.5f, R=%.5f" ρc M R_surf)")
+  ax_metric = CairoMakie.Axis(fig[1,1], xlabel=L"r")
+  ax_eos    = CairoMakie.Axis(fig[2,1], xlabel=L"r")
+  CairoMakie.linkxaxes!(ax_metric, ax_eos)
 
+  CairoMakie.lines!(ax_metric, r, @.(exp(2.0*Ï•int)), label=L"e^{2\phi_{int}}")
+  CairoMakie.lines!(ax_metric, r, @.(exp(-2.0*Λint)), label=L"e^{2\Lambda_{int}}")
+  CairoMakie.lines!(ax_metric, rext, @.(exp(2.0*Ï•ext)), label=L"e^{2\phi_{ext}}")
+  CairoMakie.lines!(ax_metric, rext, @.(exp(-2.0*Λext)), label=L"e^{2\Lambda_{ext}}")
+  CairoMakie.vlines!(ax_metric, r_surf, linestyle=:dash, color=:black, label=L"r_{surf}")
 
-function plot_potentials()
-
-  output_dir = dg1d.get_output_dir()
-  filename = joinpath(output_dir, "TOV.h5")
-  Γ, K, ρc, M, ϕ, p, m, R, r = read_data(filename)
-
-  eos = Polytrope(K = K, Gamma = Γ)
-  ρ   = @. eos(Density, InternalEnergy, nothing, Pressure, p)
-  ϵ   = @. eos(InternalEnergy, Density, ρ, Pressure, p)
-
-  r_ext = collect(range(r[end], 15.0, length=100))
-  M = m[end]
-  Ï•_ext = @. 0.5 * log(1.0 - 2.0 * M / r_ext)
-
-  Ï•_int = Ï•
-  Λ_int = @. - 0.5 * log(1.0 - 2.0 * m / r)
-  Λ_ext = - ϕ_ext
-
-  Plots.gr()
-  plt_metric = Plots.plot()
-  # Plots.plot(r, 100.0 * ρ, label="100 * ρ(r)")
-  # Plots.plot!(plt, r, 100.0 * ϵ, label="100 * ϵ(r)")
-  # Plots.plot!(plt, r, 100.0 * p, label="100 * p(r)")
-  # Plots.plot!(plt, r, Ï•_int, label="Ï•_int(r)")
-  # Plots.plot!(plt, r_ext, Ï•_ext, label="Ï•_ext(r)")
-  # Plots.plot!(plt, r, Λ_int, label="Λ_int(r)")
-  # Plots.plot!(plt, r_ext, Λ_ext, label="Λ_ext(r)")
-  # Plots.plot!(plt, r, @.(r/R), label="R")
-  # R_ext = @. 1/2 * (sqrt(r_ext^2 - 2 * M * r_ext) + r_ext - M)
-  # Plots.plot!(plt, r_ext, R_ext, label="R")
-  # Plots.plot!(plt, r, m, label="m")
-
-  #### potentials are continuous and differential at surface
-  Plots.plot!(plt_metric, r, @.( exp(2.0*Ï•_int) ), label=L"e^{2 \Phi_{int}}")
-  Plots.plot!(plt_metric, r, @.( exp(-2.0*Λ_int) ), label=L"e^{2 \Lambda_{int}}")
-  Plots.plot!(plt_metric, r_ext, @.( exp(2.0*Ï•_ext) ), label=L"e^{2 \Phi_{ext}}")
-  Plots.plot!(plt_metric, r_ext, @.( exp(-2.0*Λ_ext) ), label=L"e^{2 \Lambda_{ext}}")
-  rs = r[end]
-  Rs = R[end]
-  Plots.plot!(plt_metric, [rs, rs], [0,1], line=(:dash, :black), label=L"r=r_S")
-
-  plt_eos = Plots.plot()
-  Plots.plot!(plt_eos, r, p, label=L"p")
-  Plots.plot!(plt_eos, r, ρ, label=L"\rho")
-  # Plots.plot!(plt_eos, r, ϵ, label="ϵ")
-
-  plt = Plots.plot(plt_metric, plt_eos, layout=(2,1),
-                   xlabel="r",
-                   plot_title="TOV star, $(@sprintf "ρc = %.5f, M = %.5f, R = %.5f" ρc M Rs)",
-                   legendfontsize = 20, guidefontsize = 20,
-                   tickfontsize = 20, titlefontsize = 20,
-                   size=(1200,1200), xlims=(0.0, 15.0))
-  Plots.gui(plt)
+  CairoMakie.lines!(ax_eos, r, p.*100, label=L"100 p")
+  CairoMakie.lines!(ax_eos, r, ρ.*10, label=L"10 \rho")
+  CairoMakie.lines!(ax_eos, r, ϵ, label=L"\epsilon")
+  CairoMakie.vlines!(ax_eos, r_surf, linestyle=:dash, color=:black, label=L"r_{surf}")
 
+  CairoMakie.axislegend(ax_metric, orientation=:horizontal, position=:rb)
+  CairoMakie.axislegend(ax_eos, orientation=:horizontal, position=:rb)
 
+  return fig
 end
 
 
diff --git a/initialdata/TOV_stable.h5 b/initialdata/TOV_stable.h5
new file mode 100644
index 0000000000000000000000000000000000000000..cdb99101ad335f2475356fd026054b5a332b6d0e
Binary files /dev/null and b/initialdata/TOV_stable.h5 differ
diff --git a/initialdata/TOV_unstable.h5 b/initialdata/TOV_unstable.h5
new file mode 100644
index 0000000000000000000000000000000000000000..b94e0e5a6251b83a0d403bba81f5ec5ea7385405
Binary files /dev/null and b/initialdata/TOV_unstable.h5 differ
diff --git a/initialdata/bondi-acc_papadopoulos1998_p.png b/initialdata/bondi-acc_papadopoulos1998_p.png
new file mode 100644
index 0000000000000000000000000000000000000000..a49d8f52aac0312fec1ad2c55c9f8bab2c4a2a5b
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1998_p.png differ
diff --git a/initialdata/bondi-acc_papadopoulos1998_rho.png b/initialdata/bondi-acc_papadopoulos1998_rho.png
new file mode 100644
index 0000000000000000000000000000000000000000..2fc53584a0d475cadbc5d903a2f4e7e941c83275
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1998_rho.png differ
diff --git a/initialdata/bondi-acc_papadopoulos1998_v.png b/initialdata/bondi-acc_papadopoulos1998_v.png
new file mode 100644
index 0000000000000000000000000000000000000000..916b67cf88c47ddab62e8f4cb96cb53d1ed88f29
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1998_v.png differ
diff --git a/initialdata/bondi-acc_papadopoulos1999_eps.png b/initialdata/bondi-acc_papadopoulos1999_eps.png
new file mode 100644
index 0000000000000000000000000000000000000000..e3dfbe3c1494ddba97fef2a39b70b061f9fa01ef
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1999_eps.png differ
diff --git a/initialdata/bondi-acc_papadopoulos1999_rho.png b/initialdata/bondi-acc_papadopoulos1999_rho.png
new file mode 100644
index 0000000000000000000000000000000000000000..0351c8901242d18fe8224f17c166ff4efd0d326c
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1999_rho.png differ
diff --git a/initialdata/bondi-acc_papadopoulos1999_vr.png b/initialdata/bondi-acc_papadopoulos1999_vr.png
new file mode 100644
index 0000000000000000000000000000000000000000..1a163eba462c9d1a9bef70d9c364983030db5068
Binary files /dev/null and b/initialdata/bondi-acc_papadopoulos1999_vr.png differ
diff --git a/initialdata/bondi_accretion.h5 b/initialdata/bondi_accretion.h5
new file mode 100644
index 0000000000000000000000000000000000000000..9c447fc8b730f2dc1bef5ae0ee7be0b3a8d448f7
Binary files /dev/null and b/initialdata/bondi_accretion.h5 differ
diff --git a/math/3plus1.py b/math/3plus1.py
index a0f1ec877fb9891f8b187ef9f5c23e3f5c3541ed..eb5534e69606caca1008524b2dc03217f5c11a17 100644
--- a/math/3plus1.py
+++ b/math/3plus1.py
@@ -7,7 +7,7 @@
 #       extension: .py
 #       format_name: light
 #       format_version: '1.5'
-#       jupytext_version: 1.12.0
+#       jupytext_version: 1.16.0
 #   kernelspec:
 #     display_name: Python 3 (ipykernel)
 #     language: python
@@ -95,6 +95,10 @@ display(γ4ud)
 Γs = christoffels(γ_coords, γ, γinv)
 display(Γs)
 
+# $$
+#     \gamma_{ij} = \eta_{ij}
+# $$
+
 η_coords = coords[1:]
 display(η_coords)
 η = sp.diag(1, r**2, r**2 * sp.sin(θ)**2)
@@ -147,6 +151,20 @@ display(γhat.det())
 γhat_Γs = christoffels(γhat_coords, γhat, γhatinv)
 display(γhat_Γs)
 
+# $$
+#     \gamma_{ij} = r^{-8/3} \eta_{ij}
+# $$
+
+γhat_coords = coords[1:]
+display(γhat_coords)
+γhat = r**(sp.Rational(-8,3)) * η
+γhatinv = γhat.inv()
+display(γhat)
+display(γhatinv)
+display(γhat.det())
+γhat_Γs = christoffels(γhat_coords, γhat, γhatinv)
+display(γhat_Γs)
+
 
 # ## Extrinsic curvature
 #
@@ -195,7 +213,7 @@ for (c, Γ) in zip(sphere_coords, sphere_Γs):
             if Γij:
                 ci = sphere_coords[i];
                 cj = sphere_coords[j];
-                display(Math(f"\Gamma^{{ {c} }}_{{ {ci} {cj} }} = " + sp.latex(Γij)))
+                display(Math(fr"\Gamma^{{ {c} }}_{{ {ci} {cj} }} = " + sp.latex(Γij)))
                 # print(sp.latex(Γij))
 
 
diff --git a/math/gr_utils.py b/math/gr_utils.py
index 85a39d2c0504aae5c8198f82b58223594dd64340..5acf22afd367372b40bc574cd38a872707684fa1 100644
--- a/math/gr_utils.py
+++ b/math/gr_utils.py
@@ -3,9 +3,10 @@ import sympy_utils as spu
 
 
 def christoffels(coords, g, invg):
-    assert(len(coords) == 4)
-    assert(g.shape     == (4,4))
-    assert(invg.shape  == (4,4))
+    #assert(len(coords) == 4)
+    N = len(coords)
+    assert(g.shape     == (N,N))
+    assert(invg.shape  == (N,N))
     N = len(coords)
     gammas = [ sp.zeros(*g.shape) for i in range(N) ]
     for (k,gamma_k) in enumerate(gammas):
diff --git a/math/grhd1d_characteristics.py b/math/grhd1d_characteristics.py
index 0dac1c9f03b00f42bbb9a04db329ca3c6533cf1a..d88cffd1f1c4b4785f050d26f6ca55413f5d0150 100644
--- a/math/grhd1d_characteristics.py
+++ b/math/grhd1d_characteristics.py
@@ -7,9 +7,9 @@
 #       extension: .py
 #       format_name: light
 #       format_version: '1.5'
-#       jupytext_version: 1.11.3
+#       jupytext_version: 1.16.0
 #   kernelspec:
-#     display_name: Python 3
+#     display_name: Python 3 (ipykernel)
 #     language: python
 #     name: python3
 # ---
diff --git a/math/spherical_accretion.py b/math/spherical_accretion.py
index 80b214bb67317cd202e95b44514b23d07016bdeb..70b88cdb0790fcdd0ea59c06e4359aa5b52ccafa 100644
--- a/math/spherical_accretion.py
+++ b/math/spherical_accretion.py
@@ -6,7 +6,7 @@
 #       extension: .py
 #       format_name: light
 #       format_version: '1.5'
-#       jupytext_version: 1.13.7
+#       jupytext_version: 1.16.0
 #   kernelspec:
 #     display_name: Python 3 (ipykernel)
 #     language: python
@@ -17,12 +17,13 @@ import sympy as sp
 import sympy_utils as spu
 import gr_utils as gru
 import rewrite_utils as rwu
+sp.init_printing()
 
 # define parameters
-M = sp.symbols(r"M")
+M = sp.symbols(r"M", positive=True)
 
 # define coordinates
-coords = t, r, θ, ϕ = sp.symbols(r"t, r, \theta, \phi")
+coords = t, r, θ, ϕ = sp.symbols(r"t, r, \theta, \phi", positive=True)
 spu.display_math("(x^i) = ", coords)
 
 # metric
@@ -38,12 +39,136 @@ g = sp.Matrix([[ gtt, gtr, 0,     0 ],
 display(g)
 spu.display_tensor2("g_{{ {}{} }} = ", g, coords, symmetric=True)
 
+g.det()
+
 # inverse metric
 invg = g.inv()
 invg = sp.simplify(invg)
 display(invg)
 spu.display_tensor2("g^{{ {}{} }} = ", invg, coords, symmetric=True)
 
+
+# Christoffels
+def christoffels(coords, g, invg):
+    N = len(coords)
+    Γs = [ sp.zeros(*g.shape) for i in range(N) ]
+    for (k,Γk) in enumerate(Γs):
+        for i in range(N):
+            for j in range(N):
+                for l in range(N):
+                    Γk[i,j] += sp.Rational(1,2) * invg[k,l] * (sp.diff(g[j,l],coords[i]) + sp.diff(g[i,l],coords[j]) - sp.diff(g[i,j],coords[l]))
+                Γk[i,j] = sp.simplify(Γk[i,j])
+    return Γs
+
+
+print("Computing Christoffel symbols of metric ...")
+Γs = gru.christoffels(coords, g, invg)
+for (k, Γ_k) in enumerate(Γs):
+    Γ_k = sp.expand(Γ_k)
+    str_Γ_k = rf"\Gamma^{{{{{coords[k]}}}}}"
+    spu.display_tensor2(str_Γ_k+"_{{ {} {} }} = ", Γ_k, coords, symmetric=True)
+
+# # 3+1
+
+# +
+# normal vector
+alpha = sp.sqrt(r/(r+2*M))
+betar = 2*M/r
+betar_u = 2*M/(r+2*M)
+n = sp.Matrix([-alpha, 0, 0, 0])
+n_u = sp.Matrix([1/alpha, -betar_u/alpha, 0, 0])
+beta = sp.Matrix([0, betar, 0, 0])
+beta_u = sp.Matrix([0, betar_u, 0, 0])
+beta = g * beta_u
+gamma = g[1:,1:]
+invgamma = gamma.inv()
+dgammas = [ sp.zeros(3,3) for _ in range(3) ]
+for i in range(1,3):
+    c = coords[i]
+    for j in range(3):
+        for k in range(3):
+            dgammas[i-1][j,k] = sp.simplify(sp.diff(gamma[j,k],c))
+            
+
+dr_alpha = sp.simplify(sp.diff(alpha, r))
+dr_betar_u = sp.diff(betar_u, r)
+
+spu.display_math(r"\alpha = ", alpha)
+spu.display_math(r"\beta^r = ", betar_u)
+spu.display_tensor2(r"\gamma_{{ {}{} }} = ", gamma, coords[1:], symmetric=True)
+spu.display_math(r"\partial_r \alpha = ", dr_alpha)
+spu.display_math(r"\partial_r \beta^r = ", dr_betar_u)
+for (k, dgamma_k) in enumerate(dgammas):
+    dgamma_k = sp.expand(dgamma_k)
+    str_dgamma_k = rf"\partial_{{{{{coords[1+k]}}}}}\gamma"
+    spu.display_tensor2(str_dgamma_k+"_{{ {}{} }} = ", dgamma_k, coords[1:], symmetric=True)
+display(gamma.det())
+display(invgamma)
+# -
+
+display(invgamma[0,0])
+display(beta_u[1])
+display(alpha)
+
+sp.simplify(invgamma[0,0]-beta_u[1]*beta_u[1]/alpha**2)
+
+# sanity checks
+test_gtt = -alpha**2 + betar * betar_u
+sp.simplify(test_gtt - gtt)
+
+
+def delta(i,j):
+    return 1 if i == j else 0
+
+
+gamma_ud = sp.zeros(*g.shape)
+for i in range(len(coords)):
+    for j in range(len(coords)):
+        gamma_ud[i,j] = delta(i,j) + n_u[i] * n[j]
+        gamma_ud[i,j] = sp.simplify(gamma_ud[i,j])
+spu.display_tensor2(r"\gamma^{{ {} }}_{{ {} }} = ", gamma_ud, coords)
+
+gamma_ud
+
+# Extrinsic curvature
+# $$
+# K_{ij} = - \gamma_i^\mu \gamma_j^\nu \nabla_\mu n_\nu = - \gamma_i^\mu \gamma_j^\nu (\partial_\mu n_\nu - \Gamma^\lambda_{\mu\nu} n_\lambda)
+# $$
+
+# extrinsic curvature
+Dn = sp.zeros(*g.shape)
+for mu in range(len(coords)):
+    for nu in range(len(coords)):
+        tmp = sp.diff(n[nu], coords[mu])
+        #tmp = 0
+        for l in range(len(coords)):
+            tmp -= Γs[l][mu,nu] * n[l]
+        Dn[mu,nu] = sp.simplify(tmp)
+#spu.display_tensor2(r"(\nabla n)_{{ {}{} }} = ", Dn, coords)
+scoords = coords[1:]
+Kdd = sp.zeros(len(scoords),len(scoords))
+for i in range(len(scoords)):
+    for j in range(len(scoords)):
+        for mu in range(len(coords)):
+            for nu in range(len(coords)):
+                Kdd[i,j] += - gamma_ud[mu,1+i] * gamma_ud[nu,1+j] * Dn[mu,nu]
+        Kdd[i,j] = sp.simplify(Kdd[i,j])
+spu.display_tensor2("K_{{ {}{} }} = ", Kdd, scoords, symmetric=True)
+
+drKrrddd = sp.diff(Kdd[0,0],scoords[0])
+sp.simplify(drKrrddd)
+
+drKθddd = sp.diff(Kdd[1,1],scoords[0])
+sp.simplify(drKθddd)
+
+print("Computing Christoffel symbols of induced metric ...")
+scoords = coords[1:]
+hΓs = gru.christoffels(scoords, gamma, invgamma)
+for (k, hΓ_k) in enumerate(hΓs):
+    hΓ_k = sp.expand(hΓ_k)
+    str_hΓ_k_k = rf"\hat\Gamma^{{{{{scoords[k]}}}}}"
+    spu.display_tensor2(str_hΓ_k_k+"_{{ {} {} }} = ", hΓ_k, scoords, symmetric=True)
+
 # ## Hydrodynamics
 
 ρ, h, p, ϵ, Γ, K = sp.symbols(r"\rho h p \epsion \Gamma K")
@@ -77,4 +202,24 @@ u0
 du0dur = u0.diff(ur).simplify()
 du0dur
 
+# Stress-energy tensor for perfect fluid model
+# $$
+# T^{\mu\nu} = (\epsilon + p) u^\mu u^\nu + p g^{ij}
+# $$
+
+# perfect fluid model
+ϵ = sp.Function(r'\epsilon')(r)
+p = sp.Function('p')(r)
+ut_u = sp.Function('u^t')(r)
+ur_u = sp.Function('u^r')(r)
+u_u = sp.Matrix([ut_u, ur_u, 0, 0])
+T_uu = sp.zeros(*g.shape)
+N = len(coords)
+for i in range(N):
+    for j in range(N):
+        T_uu[i,j] = (ϵ + p) * u_u[i] * u_u[j] + p * invg[i,j]
+        T_uu[i,j] = sp.simplify(T_uu[i,j])
+T_uu = sp.simplify(T_uu)
+spu.display_tensor2("T^{{ {}{} }} = ", T_uu, coords, symmetric=True)
+
 
diff --git a/math/sympy_utils.py b/math/sympy_utils.py
index 580c81bd2f4db81a916d87447a43cf973190011f..2e4bb703fdcb14b936239d4d17b68f40bb1b3fc3 100644
--- a/math/sympy_utils.py
+++ b/math/sympy_utils.py
@@ -132,7 +132,7 @@ def display_nonzeros(T, coords, symmetric=False):
             i = ij % N
             j = int((ij - i) / N)
             if symmetric and i > j: continue
-            cij = (coords[i], coords[j])
+            cij = (coords[j], coords[i])
             display(Math(my_doprint(cij) + ": " + my_doprint(Tij)))
 
 
@@ -146,7 +146,7 @@ def display_tensor2(fmt_tensor, T, coords, symmetric=False):
             i = ij % N
             j = int((ij - i) / N)
             if symmetric and i > j: continue
-            component = fmt_tensor.format(coords[i], coords[j])
+            component = fmt_tensor.format(coords[j], coords[i])
             display(Math(component + my_doprint(Tij)))
     return
 
diff --git a/math/tov.py b/math/tov.py
index 7ae7b44544c356e1f3365a07695dce74056dbe0a..6eecf1c36ae04fa2308de9ee4e1fec797f608360 100644
--- a/math/tov.py
+++ b/math/tov.py
@@ -7,9 +7,9 @@
 #       extension: .py
 #       format_name: light
 #       format_version: '1.5'
-#       jupytext_version: 1.11.3
+#       jupytext_version: 1.16.0
 #   kernelspec:
-#     display_name: Python 3
+#     display_name: Python 3 (ipykernel)
 #     language: python
 #     name: python3
 # ---
diff --git a/src/GRHD/GRHD.jl b/src/GRHD/GRHD.jl
index f605c2a886202491661623ea6bd7f3bf7bdcd69d..b8eef07b753b29eee3eb523a16bff9f9a92ca6ab 100644
--- a/src/GRHD/GRHD.jl
+++ b/src/GRHD/GRHD.jl
@@ -3,10 +3,9 @@ module GRHD
 
 
 using dg1d
-using dg1d.EquationOfState
-using dg1d.Roots
+using Roots
 using LinearAlgebra
-using OrderedCollections
+using BasicInterpolators
 
 
 include("types.jl")
@@ -14,8 +13,8 @@ include("equation.jl")
 include("rhs.jl")
 include("initialdata.jl")
 include("callbacks.jl")
-include("boundaryconditions.jl")
 include("setup.jl")
+include("cons2prim.jl")
 
 
 #######################################################################
@@ -26,11 +25,9 @@ include("setup.jl")
 dg1d.project_type(::Val{:GRHD}) = Project
 
 # TODO Remove bdryconds
-dg1d.rhs!(env::Environment, P::Project, bdryconds) = rhs!(env, P, P.hrsc, bdryconds...)
+dg1d.rhs!(env::Environment, P::Project, bdryconds) = rhs!(env.mesh, P, P.hrsc)
 
-dg1d.plot(env::Environment, P::Project) = plot(env, P)
-
-dg1d.timestep!(env::Environment, P::Project) = timestep(env, P, P.hrsc)
+dg1d.timestep!(env::Environment, P::Project) = timestep(env.mesh, P, P.hrsc)
 
 dg1d.@parameters GRHD begin
 
@@ -39,19 +36,22 @@ dg1d.@parameters GRHD begin
   relative to the maximum of restmass density over the grid.
   """
   atm_factor = 1e-10
+  @check atm_factor > 0.0
 
   """
   Multiplicative factor to determine the cutoff restmass density below which
   we impose artificial atmosphere.
   """
   atm_threshold_factor = 100.0
+  @check atm_factor > 1.0
 
   """
   Available options:
   - `periodic`
-  - `from_initia_data`
+  - `from_id`
   """
   bc = "periodic"
+  @check bc in [ "periodic", "from_id" ]
 
   """
   Available options:
@@ -60,11 +60,10 @@ dg1d.@parameters GRHD begin
   - `atmosphere`
   """
   id = "atmosphere"
+  @check id in [ "tov", "bondi_accretion", "atmosphere" ]
 
   """
-  Path to an .h5 file containing initial data. Supported initial data types:
-  - `tov`
-  - `bondi_accretion`
+  Path to an .h5 file containing initial data.
   """
   id_filename = ""
 
@@ -72,6 +71,15 @@ dg1d.@parameters GRHD begin
   Restmass density for `atmosphere` initial data.
   """
   id_atmosphere_density = 1e-11
+  @check id_atmosphere_density > 0.0
+
+  """
+  Choice of formulation of evolution equations. Available options:
+  - `spherical1d` ... singular at `r=0`
+  - `rescaled_spherical1d` ... regular at `r=0`
+  """
+  formulation = "spherical1d"
+  @check formulation in [ "spherical1d", "rescaled_spherical1d" ]
 
 end
 
diff --git a/src/GRHD/boundaryconditions.jl b/src/GRHD/boundaryconditions.jl
deleted file mode 100644
index 1d3872258f5f88fdb199f662ea7acb7bef77aa0f..0000000000000000000000000000000000000000
--- a/src/GRHD/boundaryconditions.jl
+++ /dev/null
@@ -1,40 +0,0 @@
-function make_BoundaryConditions(env, equation, rsolver, prms)
-  @unpack bc = prms["GRHD"]
-  @unpack cache = env
-
-  broadcast_volume!(scaledcons2cons, equation, cache)
-
-  lhs_bc, rhs_bc = if bc == "periodic"
-    PeriodicBC(), PeriodicBC()
-  elseif bc == "from_initial_data"
-    @unpack sD, sSr, stau = get_dynamic_variables(cache)
-    @unpack D, Sr, tau, A, B, r, rho, vr, eps, p = get_static_variables(cache)
-    lhs_state = (sD[1], sSr[1], stau[1], p[1], rho[1], vr[1], eps[1],
-                 A[1], B[1], r[1])
-    rhs_state = (sD[end], sSr[end], stau[end], p[end], rho[end], vr[end], eps[end],
-                 A[end], B[end], r[end])
-    DirichletBC(lhs_state), DirichletBC(rhs_state)
-  else
-    error("GRHD: Boundary condition '$type' not implemented!")
-  end
-
-  return BoundaryConditions(lhs_bc, rhs_bc, rsolver)
-end
-
-
-function make_BoundaryConditions_LDG(env, equation, ldg_rsolver, prms)
-
-  @unpack bc = prms["GRHD"]
-
-  isnothing(ldg_rsolver) && return nothing
-
-  lhs_bc, rhs_bc = if bc == "periodic"
-    PeriodicBC(), PeriodicBC()
-  elseif bc == "from_initial_data"
-    OutflowBC(), OutflowBC()
-  else
-    error("GRHD: Boundary condition '$type' not implemented!")
-  end
-
-  return BoundaryConditions(lhs_bc, rhs_bc, ldg_rsolver)
-end
diff --git a/src/GRHD/callbacks.jl b/src/GRHD/callbacks.jl
index ba85cb32f59517d575827a22d8fe6ab41d53c96a..6bec2fcc58bb5750b3940d1587c9145acdd97415 100644
--- a/src/GRHD/callbacks.jl
+++ b/src/GRHD/callbacks.jl
@@ -1,11 +1,11 @@
-function make_callback(env, P::Project, bdryconds::BoundaryConditions)
-  cbfn_equation(u, t) = callback_equation(u, t, env, P, isperiodic(bdryconds), P.equation)
+function make_callback(env, P::Project, isperiodic::Bool)
+  cbfn_equation(u, t) = callback_equation(u, t, env, P, isperiodic, P.equation)
   cb_equation         = FunctionCallback(cbfn_equation,
                                          CallbackTiming(every_iteration=1,every_dt=0))
-  cbfn_tci(u, t)      = callback_tci(u, t, env, P, isperiodic(bdryconds), P.tci)
+  cbfn_tci(u, t)      = callback_tci(u, t, env, P, isperiodic, P.tci)
   cb_tci              = FunctionCallback(cbfn_tci,
                                          CallbackTiming(every_iteration=1, every_dt=0))
-  cbfn_hrsc(u, t)     = callback_hrsc(u, t, env, P, isperiodic(bdryconds), P.hrsc)
+  cbfn_hrsc(u, t)     = callback_hrsc(u, t, env, P, isperiodic, P.hrsc)
   cb_hrsc             = FunctionCallback(cbfn_hrsc,
                                          CallbackTiming(every_iteration=1,every_dt=0))
   callbackset = CallbackSet(cb_equation, cb_tci, cb_hrsc)
@@ -43,20 +43,24 @@ end
 
 
 function callback_hrsc(state_u, state_t, env, P, isperiodic, hrsc::HRSC.AbstractArtificialViscosity)
-  @unpack cache, mesh           = env
-  @unpack equation              = P
-  @unpack max_v                 = get_static_variables(cache)
-  @unpack mu, cellmax_v         = get_cell_variables(cache)
-  @unpack sD                    = get_dynamic_variables(cache)
-  broadcast_volume!(speed, equation, cache)
-  Npts, K = layout(mesh)
-  mat_cellmax_v = reshape(view(max_v, :), (Npts, K))
-  for k = 1:K
-    cellmax_v[k] = maximum(view(mat_cellmax_v, :, k))
+  @unpack cache, mesh   = env
+  @unpack equation      = P
+  @unpack max_v         = get_static_variables(cache)
+  @unpack mu, cellmax_v = get_cell_variables(cache)
+  @unpack D             = get_dynamic_variables(cache)
+
+  # prevent AV recomputation when callbacks are forced on initial data
+  # need this for shock tube tests so that we have non-zero viscosity in troublesome places
+  # although we start with smoothed initial data
+  t[1] <= tm1[1] && return
+
+  for (k,vi) in enumerate(eachcell(mesh, max_v))
+    cellmax_v[k] = maximum(vi)
   end
+
   HRSC.compute_viscosity!(
       mu,
-      sD, cellmax_v,
+      D, cellmax_v,
       hrsc)
 end
 
@@ -71,21 +75,9 @@ end
 function callback_hrsc(state_u, state_t, env, P, isperiodic, hrsc::HRSC.SmoothedArtificialViscosity)
   callback_hrsc(state_u, state_t, env, P, isperiodic, hrsc.av)
   @unpack cache, mesh = env
-  @unpack mu          = get_cell_variables(cache)
-  indices = findall(muk -> muk > 0.0, mu)
-  tmp = zeros(size(mu))
-  _, K = layout(mesh)
-  # artificially broaden viscosity
-  for k in indices
-    k_lhs, k_rhs = periodic_index(k-1, K), periodic_index(k+1, K)
-    muk = mu[k]
-    tmp[k_lhs] = max(muk, tmp[k_lhs])
-    tmp[k] = max(muk, tmp[k])
-    tmp[k_rhs] = max(muk, tmp[k_rhs])
-  end
-  @. mu = tmp
   @unpack smoothed_mu = get_static_variables(cache)
-  smoothed_mu .= vec(hrsc.smoother(mu, isperiodic))
+  @unpack mu          = get_cell_variables(cache)
+  hsrc.smoother(smoothed_mu, mu, mesh, false)
 end
 
 
@@ -135,6 +127,8 @@ function callback_tci(state_u, state_t, env, P, isperiodic,
     tci::Union{TCI.Diffusion, TCI.Minmod, TCI.Threshold,
                TCI.ModalDecayAverage, TCI.ModalDecayHighest})
 
+  TODO()
+
   @unpack cache, mesh                        = env
   @unpack sD, sSr, stau                      = get_dynamic_variables(cache)
   @unpack flag, sD_flag, sSr_flag, stau_flag = get_cell_variables(cache)
diff --git a/src/GRHD/cons2prim.jl b/src/GRHD/cons2prim.jl
new file mode 100644
index 0000000000000000000000000000000000000000..4d8e7d8581449c42fa7a5a38f9d8f38d2862578c
--- /dev/null
+++ b/src/GRHD/cons2prim.jl
@@ -0,0 +1,320 @@
+#######################################################################
+#                         Conservative fixing                         #
+#######################################################################
+
+
+@with_signature function conservative_fixing(equation::AbstractEquation)
+  @accepts D, S, Ï„, r
+
+  TODO()
+
+  @unpack atm_density, atm_threshold, eos = equation
+  # atm_density = equation.atmosphere.ρ
+  # atm_threshold = equation.atmosphere.threshold
+  ρmin = atm_density * atm_threshold
+
+  # B = 1.0 # in special relativity
+
+  #####
+  # conservative variable fixing following Deppe et al. arXiv:2109.12033
+  ######
+
+  fixed = false
+
+  if D < ρmin || τ < 0.0
+    D = ρmin
+    Ï„ = 1e-12
+    fixed = true
+  end
+
+  # if D < 0.001 * ρmin
+  #   # @warn "fixing D $D @ r = $r"
+  #   D = ρmin
+  #   fixed = true
+  # end
+  #
+  # if Ï„ < 0.0
+  #   # @warn "fixing Ï„ $Ï„ @ r = $r"
+  #   Ï„ = 1e-12
+  #   fixed = true
+  # end
+  # fix Ï„ such that v < 0.999
+  # if Ï„ < 0.0
+  #   @warn "fixing Ï„ $Ï„ @ r = $r"
+  #   # What = 1 + Ï„ / D = 1 / sqrt(1 - v^2)
+  #   v2 = 0.999
+  #   Ï„ = max(D * (1.0 / sqrt(1.0 - v2) - 1), 1e-12)
+  #   display(Ï„)
+  #   fixed = true
+  # end
+
+  # (48)-(50) in arXiv:2109.12033 we put B=0, ̂μ = 0
+  # solution to (52) is then
+  What = 1.0 + Ï„ / D
+
+  S2 = S^2
+  D2 = D^2
+  ϵs = 1e-12
+  factor = sqrt( (1.0-ϵs) * (What^2-1.0) * D2 / (S2 + D2 * 1e-16) )
+  # @show factor, What
+  if factor < 1.0 && What > 1.0
+    # @warn "fixing ..."
+    Sold = S
+    S = 0.99 * sign(S) * sqrt( (1.0-ϵs) * (What^2-1.0) * D2 - D2 * 1e-16 )
+    # @warn "S  = $Sold => $S @ r = $r"
+    S2 = S^2
+    factor = max(1.0, sqrt( (1.0-ϵs) * (What^2-1.0) * D2 / (S2 + D2 * 1e-16) ))
+    # @show factor
+    @assert factor >= 1.0
+    fixed = true
+  end
+
+  # h0 = 1e-3
+  # S2 = S^2 / B^2
+  # r2 = S2 / D^2
+  # z02 = r2 / h0^2
+  # v02 = z02 / (1.0 + z02)
+  # max_v2 = 0.999
+  # if v02 > max_v2
+  #   S = sign(S) * sqrt(max_v2/(1-max_v2) * h0^2 * D^2)
+  # end
+
+  flag_consfixed = Float64(fixed)
+
+  @returns D, S, Ï„, flag_consfixed
+end
+
+
+#######################################################################
+#                  cons2prim a la Kastaun et al 2021                  #
+#######################################################################
+
+
+@with_signature [simd=false] function cons2prim(equation::AbstractEquation)
+  @accepts D, Sr, Ï„, r
+  @accepts γrr
+  D, Sr, τ, ρ, vr, ϵ, p = cons2prim_kastaun_impl(equation, D, Sr, τ, r, γrr)
+  @returns D, Sr, τ, ρ, vr, ϵ, p
+end
+@with_signature [simd=false] function cons2prim_rescaled_spherical1d(equation::AbstractEquation)
+  @accepts D, Sr, Ï„, r
+  @accepts B
+  γrr = 1/B^2
+  D, Sr, τ, ρ, vr, ϵ, p = cons2prim_kastaun_impl(equation, D, Sr, τ, r, γrr)
+  # in case something was adjusted by cons2prim
+  rD  = r*B^3*D
+  rSr = r*B^3*Sr
+  rτ  = r*B^3*τ
+  @returns D, Sr, τ, rD, rSr, rτ, ρ, vr, ϵ, p
+end
+
+
+@inline function cons2prim_kastaun_impl(equation, D, Sr, τ, r, γrr)
+
+  rcoord = r
+
+  @unpack atm_density, atm_threshold, eos = equation
+  ρmin = atm_density * atm_threshold
+  @unpack K, Gamma = eos
+  pmin = K * ρmin^Gamma
+  ϵmin = pmin / ((Gamma-1)*ρmin)
+  ρmax = Inf
+  ρatm = atm_density
+  h0 = 1e-3
+
+  #### cons2prim from Kastaun et al. arXiv:2005.01821
+
+  γuurr = 1/γrr
+  q = Ï„ / D # (22)-(23)
+  rr = Sr / D # (22)-(23), Si := S_i is 3-vector
+  r2 = γuurr*rr*rr
+  r  = sqrt(r2)
+  z0 = r/h0
+  v0 = z0 / sqrt(1.0 + z0^2)
+  h02 = h0^2
+
+  if v0 > 1
+    error((v0,z0,Sr,D))
+  end
+
+  # What is not a question but rather W^hat, cf. (40)
+  fn_What = let r = r, v0 = v0
+    mu -> begin
+      vhat = min(mu * r, v0)
+      return 1.0 / sqrt(1.0 - vhat^2)
+    end
+  end
+
+  # setup bracket
+  mu_a = 0.0
+  # with no EM fields we can find the root of (49) analytically, because r = const.
+  mu_plus = 1.0 / sqrt(h02 + r2)
+  mu_b = r < h0 ? 1.0 / h0 : mu_plus
+
+  What_a = fn_What(mu_a)
+  What_b = fn_What(mu_b)
+  if D / What_b > ρmax
+    error("Invalid state encountered!")
+  end
+
+  if D < ρmin
+
+    @assert eos isa EquationOfState.Polytrope
+    @unpack K, Gamma = eos
+
+    # employ atmosphere values by taking the zero temperature limit
+    # for an ideal gas eos, we have that eos.Gamma becomes the Gamma for
+    # a polytrope, see grhd notes for derivation
+
+    ρ = ρatm
+    vr = 0.0
+    W = 1.0
+    p = K * ρ^Gamma
+    ϵ = p / ((Gamma-1)*ρ)
+    h = 1 + ϵ + p/ρ
+    D  = W*ρ
+    Sr = W^2*ρ*h*vr
+    τ  = W^2*ρ*h - p - D
+
+  else
+
+    # root bracket adjustment, cf. Appendix
+    if D / What_b < ρmax < D
+      # infamous closure bug ...
+      # https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured
+      fn_ρmax = let D = D, ρmax = ρmax
+        mu -> D / fn_What(mu) - ρmax
+      end
+      mu_b = find_zero(fn_ρmax, (mu_a, mu_plus), Roots.A42())
+      if isnan(mu_b)
+        error("Failed to correct upper interval bound")
+      end
+    end
+
+    if D / What_b < ρmin < D # yes, we need What_b here
+      # infamous closure bug ...
+      # https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured
+      fn_ρmin = let D = D, ρmin = ρmin
+        mu -> D / fn_What(mu) - ρmin
+      end
+      mu_a = find_zero(fn_ρmin, (mu_a, mu_b), Roots.A42())
+      if isnan(mu_b)
+        error("Failed to correct lower interval bound")
+      end
+    end
+
+    # infamous closure bug ...
+    # https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured
+    master_fn = let D = D, v0 = v0, r = r, q = q, r2 = r2
+      mu -> begin # eq (44)
+
+        _vhat = min(mu * r, v0)
+        _What = 1.0 / sqrt(1.0 - _vhat^2)
+        ρhat = D / _What
+
+        # eq (42)
+        ϵhat = _What * (q - mu * r2) + _vhat^2 * _What^2 / (1.0 + _What)
+
+        # TODO enforce EOS bounds - needed?
+
+        # compute thermodynamic vars
+        phat = eos(Pressure, Density, ρhat, InternalEnergy, ϵhat)
+        # hhat = eos(Enthalpy, Density, ρhat, InternalEnergy, ϵhat)
+        ahat = phat / (ρhat * (1.0 + ϵhat))
+
+        # eq (46)-(48)
+        nu_A = (1.0 + ahat) * (1.0 + ϵhat) / _What
+        nu_B = (1.0 + ahat) * (1.0 + q - mu * r2)
+        nu = max(nu_A, nu_B)
+
+        # eq (44)
+        f = mu - 1.0 / (nu + r2 * mu)
+        return f
+      end
+    end
+
+    # verify if there is a solution inside bracket
+    mf_a = master_fn(mu_a)
+    mf_b = master_fn(mu_b)
+    mf_ab = mf_a*mf_b
+    mu = find_zero(master_fn, (mu_a, mu_b), Roots.A42() #= =^= algorithm 748 =#)
+    if isnan(mu)
+      error("Failed to find root")
+    end
+
+    #### evaluate primitives
+
+    # eq (36) [Kastaun] : h*W = 1/mu
+    # eq (15) [Kastaun] : ρ*W = D
+    # ρhW2 = D / mu
+
+    # regularize velocity according to Dumbser et al arxiv:2307.06629
+    # eqs (82)-(84)
+    # y, y0 = ρhW2, 1e-4
+    # if y > y0
+      # v = S / mu
+      # compute v accoriding to eq (68) or (40) [Kasτn]
+      # vr = sign(Sr) * min(mu * r, v0)
+      # vr = sign(Sr) * min(abs(mu * rr), abs(v0))
+    # else
+    #   # @warn "limiting v"
+    #   # limit velocity ratio v/S
+    #   fy = 2.0 * (y/y0)^3 - 3.0 * (y/y0)^2 + 1.0
+    #   v = Si * y / (y^2 + fy * 5e-9)
+    # end
+
+    v = sqrt(mu^2 * γuurr*rr*rr)
+    v  = min(v, v0)
+    v2 = v^2
+    vr = sign(Sr) * sqrt(v2/γuurr)
+
+    # eq (68) or (40)
+    W = 1.0 / sqrt(1.0 - v2)
+    # eq (41)
+    ρ = D / W
+    # eq (42)
+    ϵ = W * (q - mu * r2) + v2 * W^2 / (1.0 + W)
+    # eq (38)
+    # ϵ2 = W * (q - mu * r2) + W - 1
+
+    # enforce EOS bounds
+
+    if ρ < ρmin
+      # atmosphere II
+
+      @assert eos isa EquationOfState.Polytrope
+      @unpack K, Gamma = eos
+
+      # employ atmosphere values by taking the zero temperature limit
+      # for an ideal gas eos, we have that eos.Gamma becomes the Gamma for
+      # a polytrope, see grhd notes for derivation
+
+      ρ = ρatm
+      vr = 0.0
+      W = 1.0
+      p = K * ρ^Gamma
+      ϵ = p / ((Gamma-1)*ρ)
+      h = 1 + ϵ + p/ρ
+      D  = W*ρ
+      Sr = W^2*ρ*h*vr
+      τ  = W^2*ρ*h - p - D
+
+    elseif ϵ < ϵmin
+      # error()
+      # adjusting Ï„ such that energy density is within bounds
+      # cf. 3rd paragraph in sec. III.A in Kastaun paper
+      ϵ = ϵmin
+      # invert this for τ: ϵ = W * (q - mu * r2) + v^2 * W^2 / (1.0 + W), q = τ / D
+      τ = (ϵ / W  - v2 * W / (1.0 + W) + mu * r2) * D
+    end
+
+    # compute thermodynamic vars
+    p = eos(Pressure, Density, ρ, InternalEnergy, ϵ)
+    if p < 0
+      error((ρ,ϵ))
+    end
+
+  end
+
+  return D, Sr, τ, ρ, vr, ϵ, p
+end
diff --git a/src/GRHD/cons2prim_implementations.jl b/src/GRHD/cons2prim_implementations.jl
deleted file mode 100644
index 32c930cb50b401d11767f576f6f5ab664cfcb628..0000000000000000000000000000000000000000
--- a/src/GRHD/cons2prim_implementations.jl
+++ /dev/null
@@ -1,319 +0,0 @@
-@with_signature function cons2prim(equation::Equation{<:HotEquationOfState})
-  @accepts D, Sr, tau, p, r, B
-  # S2   = (Sr/B)^2
-  # @unpack eos, cons2prim_newtonsolver, cons2prim_bisection = equation
-  # p, converged = find_pressure_insane(D, S2, tau, p, r, eos,
-  #                                     cons2prim_newtonsolver, cons2prim_bisection)
-  # if !converged && eltype(equation) == HybridEoS
-  #   rho, success = find_density_insane(D, S2, p, r, equation, eos,
-  #                                      cons2prim_newtonsolver, cons2prim_bisection)
-  #   if !success
-  #     error()
-  #   end
-  #   p    = eos(Pressure, Density, rho)
-  #   vr   = Formulae.vr(B, D, Sr, tau, p)
-  #   eps  = Formulae.ϵ(B, D, Sr, tau, p)
-  # else
-  #   rho  = Formulae.ρ(B, D, Sr, tau, p)
-  #   vr   = Formulae.vr(B, D, Sr, tau, p)
-  #   eps  = Formulae.ϵ(B, D, Sr, tau, p)
-  # end
-
-  D, Sr, tau = conservative_fixing(D, Sr, tau, B, equation)
-  rho, vr, eps, p = cons2prim_kastaun((D, Sr, tau, p, r, B), equation)
-  # rho, vr, eps, p, D, Sr, tau = atmosphering(rho, vr, eps, p, D, Sr, tau)
-  @returns rho, vr, eps, p, D, Sr, tau
-end
-
-
-@with_signature function cons2prim(equation::Equation{<:ColdEquationOfState})
-  @accepts D, Sr, tau, p, r, B
-  S2   = (Sr/B)^2
-  rho, success  = find_density_insane(D, S2, p, equation)
-  @unpack eos = equation
-  p    = eos(Pressure, Density, rho)
-  vr   = Formulae.vr(B, D, Sr, tau, p)
-  eps  = Formulae.ϵ(B, D, Sr, tau, p)
-  @returns rho, vr, eps, p
-end
-
-
-#######################################################################
-#           Insane version - bail out if anything is wrong            #
-#######################################################################
-
-
-function find_pressure_insane(D, S2, tau, p, r, eos::HotEquationOfState,
-  cons2prim_newtonsolver, cons2prim_bisection)
-
-  # upper limit on particle velocity
-  # omv2 = 1e-3 # = 1 - v^2
-
-  # pmin1 = - (tau + D) + sqrt(S2 + omv2) # √((τ + D + p)^2 - S^2) >= √(1 - vmax^2)
-  pmin1 = - (tau + D) + sqrt(S2) + 1e-10 # √((τ + D + p)^2 - S^2) >= √(1 - vmax^2)
-  pmin2 = 1e-10 # physical constraint
-  pmin = max(pmin1, pmin2)
-
-  floor_pressure(pnew) = max(pnew, pmin)
-  # p0 = 0.5 * (eos.gamma - 1) * (tau + D)
-  p0 = p
-
-  f = pp -> pressure_equation_insane(D, S2, tau, pp, r, eos)
-  p, err, converged, tol = find_root(f, p0, cons2prim_newtonsolver, sanitize=floor_pressure)
-  if !converged
-    # reset to guess
-    p = p0
-  end
-  p = max(pmin, p0)
-
-  return p, converged
-end
-
-
-function pressure_equation_insane(D, S2, tau, p, r, eos)
-
-  a = tau + p + D
-  a2mS2 = a^2 - S2
-  if a2mS2 < 0
-    return NaN
-  end
-  W = a / sqrt(a2mS2)
-  rho = D / W
-  # if rho < 0 #1e-15
-  #   # return NaN
-  #   # rho = 1e-10
-  # end
-  eps_rho = (a - W^2 * p) / W^2 - rho
-  if eps_rho < 0
-    # in low temperature limit we should switch to one parameter EoS
-    return NaN
-  end
-  eps = eps_rho / rho
-  eos_p = eos(Pressure, Density, rho, InternalEnergy, eps) + 1e-10
-  f = eos_p - p
-  return f
-end
-
-
-function find_density_insane(D, S2, rho, eos,
-    cons2prim_newtonsolver, cons2prim_bisection)
-
-  rhomin = 1e-10
-  rho_init = rho
-
-  floor_density(rhonew) = max(rhonew, rhomin)
-  g = rho -> density_equation(D, S2, rho, eos)
-  rho, err, converged, tol = find_root(g, rho_init, cons2prim_newtonsolver,
-                                       sanitize=floor_density)
-  if !converged
-    # try bisection
-    # Figure out brackets for a bisection method.
-    # if bisection failed reset
-    rho = rho_init
-  end
-
-  success = converged
-
-  return rho, success
-end
-
-
-function density_equation(D, S2, rho, eos)
-  D2 = D^2
-  h = eos(Enthalpy, Density, rho)
-  W = sqrt(1 + S2 / (D2 * h^2))
-  chi = eos(Derivative{Pressure,Density}, Density, rho)
-  g = W * rho - D
-  # assuming zero temperature limit: deps/drho = P / rho^2
-  dg = W - S2 * chi / (W * D2 * h^3)
-  return g, dg
-end
-
-
-#######################################################################
-#                  cons2prim a la Kastaun et al 2021                  #
-#######################################################################
-
-
-@with_signature function cons2prim_kastaun(equation::AbstractEquation)
-  @accepts D, Sr, tau, p, r, B
-
-  @unpack eos, atm_density, atm_threshold = equation
-  rhomin, rhomax = atm_density * atm_threshold, Inf
-  fn_epsmin, fn_epsmax = rho -> -(1-1e-10), rho -> Inf
-  h0 = 1e-3
-  rhoatm = atm_density
-
-  q = tau / D
-  S2 = (Sr/B)^2
-  s = sqrt(S2) / D # =^= r in paper, r already denotes radius here
-  z0 = s / h0
-  v0 = z0 / sqrt(1 + z0^2)
-  h02 = h0^2
-  s2 = s^2
-
-  # What is not a question but rather W^hat, cf. (40)
-  function fn_What(mu)
-    _vhat = min(mu * s, v0)
-    if _vhat < 0
-      error()
-      println((; q, _vhat, s, mu, v0))
-    end
-    return 1 / sqrt(1 - _vhat^2)
-  end
-
-  # setup bracket
-  mu_a = 0.0
-  # with no EM fields we can find the root of (49) analytically, because s = const.
-  mu_plus = 1 / sqrt(h02 + s2)
-  mu_b = r < h0 ? 1 / h0 : mu_plus
-
-  What_b = fn_What(mu_b)
-  if D / What_b > rhomax
-    error("Invalid state encountered at @ r = $(r)!")
-  end
-  if D < rhomin
-    # @info "Invalid state encountered at @ r = $(r)!"
-    # @info "Atmosphering ..."
-    # println((; D, rhomax, rhomin))
-    rho = rhoatm
-    eps = eos.cold_eos(InternalEnergy, Density, rho)
-    vr = 0.0
-    p = eos.cold_eos(Pressure, Density, rho)
-    # p = eos(Pressure, Density, rho, InternalEnergy, eps)
-  else
-
-    # do we have to adjust the bracket?
-    debug = false
-    # if D / What_b < rhomax < D
-    if rhomax < D
-      pblm_rhomax = Roots.ZeroProblem(mu -> D / fn_What(mu) - rhomax, (mu_a, mu_b))
-      mu_b = Roots.solve(pblm_rhomax, Roots.A42())
-      if isnan(mu_b)
-        error("Failed to correct upper interval bound")
-      end
-      debug = true
-    end
-    # if D / What_b < rhomin < D
-    if D / What_b < rhomin
-      mu_rng = collect(LinRange(mu_a, mu_b, 1000))
-      fn = @. D / fn_What(mu_rng) - rhomin
-      data = hcat(mu_rng, fn)
-      # display(data)
-      # display(D / What_b)
-      # display(D)
-      # display(rhomin)
-      pblm_rhomin = Roots.ZeroProblem(mu -> D / fn_What(mu) - rhomin, (mu_a, mu_b))
-      mu_b = Roots.solve(pblm_rhomin, Roots.A42())
-      if isnan(mu_b)
-        error("Failed to correct lower interval bound")
-      end
-      println("New interval: ($mu_a, $mu_b) @ r = $r")
-      debug = false
-    end
-
-    function master_fn(mu)
-      vhat = min(mu * s, v0)
-      What = 1 / sqrt(1 - vhat^2)
-      rhohat = D / What
-      eps_plus_one_over_What = What * (q - mu * s2)
-      epshat = eps_plus_one_over_What + vhat^2 * What^2 / (1 + What)
-      # enforce EOS bounds
-      _epsmin, _epsmax = fn_epsmin(rhohat), fn_epsmax(rhohat)
-      if rhohat < rhomin || epshat < _epsmin
-        # TODO Should we reset What here?
-        rhohat, epshat = rhomin, _epsmin
-      elseif rhohat > rhomax || epshat > _epsmax
-        rhohat, epshat = rhomax, _epsmax
-      end
-      # compute thermodynamic vars
-      phat = eos(Pressure, Density, rhohat, InternalEnergy, epshat)
-      ahat = phat / (rhohat * (1 + epshat))
-      hhat = eos(Enthalpy, Density, rhohat, InternalEnergy, epshat)
-      # compute master function
-      # extracted from (35), see hint in paragraph after (46)-(48)
-      nu_A = (1 + ahat) * eps_plus_one_over_What
-      nu_B = (1 + ahat) * (1 + q - mu * s2)
-      nu = max(nu_A, nu_B)
-      f = mu - 1 / (nu + s2 * mu)
-      return f
-    end
-
-    if debug
-      mu_rng = collect(LinRange(mu_a, mu_b, 1000))
-      fn = @. master_fn(mu_rng)
-      data = hcat(mu_rng, fn)
-      display(data)
-    end
-
-    mf_a = master_fn(mu_a)
-    mf_b = master_fn(mu_b)
-    if mf_a * mf_b >= 0
-      println((; D, Sr, tau, p, r, B, mf_a, mf_b, mu_a, mu_b))
-      error("Master function is ill conditioned, @ r = $(r)!")
-    end
-    pblm = Roots.ZeroProblem(master_fn, (mu_a, mu_b))
-    mu = Roots.solve(pblm, Roots.A42() #= =^= algorithm 748 =#)
-    if isnan(mu)
-      error("failed to find root")
-    end
-
-    # evaluate primitives
-    v = min(mu * s, v0)
-    W = 1 / sqrt(1 - v^2)
-    rho = D / W
-    eps_plus_one_over_W = W * (q - mu * s2)
-    eps = eps_plus_one_over_W + v^2 * W^2 / (1 + W)
-    # enforce EOS bounds
-    epsmin, epsmax = fn_epsmin(rho), fn_epsmax(rho)
-    if rho < rhomin || eps < epsmin
-      rho, eps = rhomin, epsmin
-    elseif rho > rhomax || eps > epsmax
-      rho, eps = rhomax, epsmax
-    end
-    # compute thermodynamic vars
-    p = eos(Pressure, Density, rho, InternalEnergy, eps)
-
-    vr = Sr*mu/D
-
-  end
-
-  @returns rho, vr, eps, p
-end
-
-
-#######################################################################
-#                    Conservative variable fixing                     #
-#######################################################################
-
-
-function conservative_fixing(D, Sr, tau, B, equation)
-
-  @unpack eos, atm_density, atm_threshold = equation
-  rhomin = atm_density * atm_threshold
-  rhoatm = atm_density
-
-  if D < rhomin
-    D = rhoatm
-  end
-
-  if tau < 0
-    tau = 1e-12
-  end
-
-  # (48)-(50) in Deppe paper where we put B=0
-  # that = tau / D
-  # muhat = 0
-  # Solution to (52) when B=0
-  What = 1 + tau / D
-
-  # in spherical symmetry: S^2 = S_r^2 / B^2
-  # Hence, Smax^2/S^2 = Srmax^2 / Sr^2
-  S2 = Sr^2 / B^2
-  factor = sqrt( (1-1e-12) * (What^2-1) * D^2 / (S2 + D^2 * 1e-16) )
-  if factor > 1
-    Sr /= factor * (1 + 1e-8)
-  end
-
-  return D, Sr, tau
-end
diff --git a/src/GRHD/equation.jl b/src/GRHD/equation.jl
index a5081108a866b6d02c613a72a0af645107c5fe1c..ccdd108e4535d4f91e9c7a93a0a2fc84ae69324f 100644
--- a/src/GRHD/equation.jl
+++ b/src/GRHD/equation.jl
@@ -1,240 +1,472 @@
-### TODO Move include to GRHD.jl or merge with this file?
-include("cons2prim_implementations.jl")
+function make_Equation(eos, prms, m::Mesh)
+  @unpack atm_factor, atm_threshold_factor = prms
+  if m isa Mesh1d
+    return Equation(eos, -1.0, atm_factor, atm_threshold_factor)
+  elseif m isa Mesh2d
+    TODO()
+  else
+    error("unknown mesh type encountered")
+  end
+end
 
 
-module Formulae
-  ### Auxilary functions
+#######################################################################
+#                             "spherical1d"                           #
+#           Spherical symmetry (1d) + spherical coordinates           #
+#######################################################################
 
-  # Lorentz factor
-  Wprim(B, ρ, vr, ϵ, p) = 1.0 / sqrt(1.0 - B^2 * vr^2)
-  Wcons(B, D, Sr, Ï„, p) = (Ï„ + p + D) / sqrt((Ï„ + p + D)^2 - (Sr / B)^2)
 
-  ### Primitive variables
-  # in terms of conservative ones
+@with_signature function flux_source_spherical1d(eq::Equation)
+  @accepts D, Sr, τ, ϵ, ρ, p, vr
+  @accepts α, ∂αr, βru, ∂βrrdu,
+           γrr, γθθ, γϕϕ, ∂γrrr, ∂γrθθ, ∂γrϕϕ, ∂γθϕϕ,
+           Γrrr, Γrθθ, Γrϕϕ, Γθrθ, Γθϕϕ, Γϕθϕ, Γϕrϕ,
+           Krr, Kθθ, Kϕϕ
+  @accepts flr_D, flr_Sr, flr_Ï„
+
+  γuurr = 1/γrr
+  γuuθθ = 1/γθθ
+  γuuϕϕ = 1/γϕϕ
+  Γkrk = Γrrr + Γθrθ + Γϕrϕ
+
+  gtt = -α^2 + γrr*βru*βru
+  gtr = γrr*βru
+  grr = γrr
+  guutt = -1/α^2
+  guutr = βru/α^2
+  guurr = γuurr - βru*βru/α^2
+  guuθθ = γuuθθ
+  guuϕϕ = γuuϕϕ
+
+  vru = γuurr*vr
+  v2 = vru*vr
+  W = 1/sqrt(1-v2)
+  ut = W/α
+  ur = W*(vru - βru/α)
+
+  h = 1 + ϵ + p/ρ
+  Tuutt = ρ*h*ut*ut + p*guutt
+  Tuutr = ρ*h*ut*ur + p*guutr
+  Tuurr = ρ*h*ur*ur + p*guurr
+  Tuuθθ = p*guuθθ
+  Tuuϕϕ = p*guuϕϕ
+  Tudtr = Tuutt*gtr + Tuutr*grr
+
+  flr_D  = α*D*(vru - βru/α)
+  flr_Sr = α*( Sr*(vru - βru/α) + p )
+  flr_τ  = α*( τ*(vru - βru/α) + p*vru )
+
+  src_D = - flr_D*Γkrk
+
+  # tmp1 = 1/2*(Tuutt*βru*βru + 2*Tuutr*βru + Tuurr) * (∂γrrr - 2*Γrrr*γrr)
+  tmp1 = 0 # because Dj γik = 0 (Levi-Civita connection)
+  tmp2 = Tudtr*(∂βrrdu + Γrrr*βru)
+  tmp3 = -Tuutt*α*∂αr
+  flθ_Sθ = α*p
+  flϕ_Sϕ = α*p
+  src_Sr = α*(tmp1 + tmp2 + tmp3) - flr_Sr*Γkrk + flr_Sr*Γrrr + flθ_Sθ*Γθrθ + flϕ_Sϕ*Γϕrϕ
+
+  src_τ = Tuutt*(βru*βru*Krr - βru*∂αr) + Tuutr*(2*βru*Krr - ∂αr) + Tuurr*Krr + Tuuθθ*Kθθ + Tuuϕϕ*Kϕϕ
+  src_τ *= α
+  src_τ += - flr_τ*Γkrk
+
+  @returns src_D, src_Sr, src_Ï„, flr_D, flr_Sr, flr_Ï„
+end
 
-  ρ(B, D, Sr, τ, p)  = D / Wcons(B, D, Sr, τ, p)
-  vr(B, D, Sr, Ï„, p) = Sr / (B^2 * (Ï„ + D + p))
-  ϵ(B, D, Sr, τ, p) = (sqrt((τ + p + D)^2 - (Sr/B)^2) - Wcons(B, D, Sr, τ, p) * p) / D - 1
 
-  ### Conservative variables
-  # in terms of primitive variables
+@with_signature function maxspeed(equation::Equation)
+  @accepts vr, ρ, ϵ
+  @accepts α, βru, γrr
+  @unpack eos = equation
+  cs2 = eos(SquareSpeedOfSound, Density, ρ, InternalEnergy, ϵ)
+  cs = sqrt(abs(cs2))
+  γuurr = 1/γrr
+  vru = γuurr * vr
+  v2 = vru*vr
+  λ0 = α*vru - βru
+  W = 1/sqrt(1-v2)
+  λp = α/(1-v2)*(vru*(1-cs2)+cs/W*sqrt((1-v2*cs2)*γuurr-vru^2*(1-cs2)))
+  λm = α/(1-v2)*(vru*(1-cs2)-cs/W*sqrt((1-v2*cs2)*γuurr-vru^2*(1-cs2)))
+  max_v = absmax(λm, λ0, λp)
+  @returns max_v
+end
 
-  D(B, ρ, vr, ϵ, p) = ρ * Wprim(B, ρ, vr, ϵ, p)
-  Sr(B, ρ, vr, ϵ, p) = ρ * (1 + ϵ + p / ρ) * Wprim(B, ρ, vr, ϵ, p)^2 * B^2 * vr
-  τ(B, ρ, vr, ϵ, p) = ρ * (1 + ϵ + p / ρ) * Wprim(B, ρ, vr, ϵ, p)^2 - p - ρ * Wprim(B, ρ, vr, ϵ, p)
 
-  ### Fluxes
-  # in terms of primitive variables
+@with_signature function llf(equation::Equation)
+  @accepts        D, flr_D, Sr, flr_Sr, Ï„, flr_Ï„, max_v, p
+  @accepts        α, βru, γrr
+  @accepts [bdry] bdry_D, bdry_Sr, bdry_τ, bdry_max_v, bdry_ρ, bdry_vr, bdry_ϵ, bdry_p
+  @accepts [bdry] nx
 
-  fD(B, ρ, vr, ϵ, p) = D(B, ρ, vr, ϵ, p) * vr
-  fSr(B, ρ, vr, ϵ, p) = Sr(B, ρ, vr, ϵ, p) * vr + p
-  fτ(B, ρ, vr, ϵ, p) = (τ(B, ρ, vr, ϵ, p) + p) * vr
+  vmax     = absmax(max_v, bdry_max_v)
+  γuurr    = 1/γrr
+  bdry_vru = γuurr * bdry_vr
 
-  #### Sources
+  bdry_flr_D  = α * bdry_D * (bdry_vru - βru/α)
+  bdry_flr_Sr = α * ( bdry_Sr * (bdry_vru - βru/α) + bdry_p )
+  bdry_flr_τ  = α * ( bdry_τ * (bdry_vru - βru/α) + bdry_p * bdry_vru )
 
-  function sD(r, A, A_r, B, B_r, ρ, vr, ϵ, p)
-    val = - A * B^3 * D(B, ρ, vr, ϵ, p) * vr
-    return val
-  end
+  nflr      = nx*flr_D
+  bdry_nflr = nx*bdry_flr_D
+  nflr_D    = LLF(nflr, bdry_nflr, D, bdry_D, vmax)
 
-  function sSr(r, A, A_r, B, B_r, ρ, vr, ϵ, p)
-    h = 1 + ϵ + p / ρ
-    Sr = Formulae.Sr(B, ρ, vr, ϵ, p)
-    W = Wprim(B, ρ, vr, ϵ, p)
-    v2 = B^2 * vr^2
-    ρhW2 = ρ * h * W^2
-    val = - (ρhW2 - p) * r * B^3 * A_r
-    val += A * B^4 * (r * B_r + B / 3) * (ρhW2 * vr^2 + 3 * p  / B^2)
-    val += - 4 / 3 * A * B^3 * Sr * vr
-    return val
-  end
+  nflr      = nx*flr_Sr
+  bdry_nflr = nx*bdry_flr_Sr
+  nflr_Sr   = LLF(nflr, bdry_nflr, Sr, bdry_Sr, vmax)
 
-  function sτ(r, A, A_r, B, B_r, ρ, vr, ϵ, p)
-    τ = Formulae.τ(B, ρ, vr, ϵ, p)
-    h = 1 + ϵ + p / ρ
-    W = Wprim(B, ρ, vr, ϵ, p)
-    ρhW2 = ρ * h * W^2
-    val = - r * B^3 * ρhW2 * vr * A_r - A * B^3 * (τ + p) * vr
-    return val
-  end
+  nflr      = nx*flr_Ï„
+  bdry_nflr = nx*bdry_flr_Ï„
+  nflr_Ï„    = LLF(nflr, bdry_nflr, Ï„, bdry_Ï„, vmax)
+
+  @returns [bdry] nflr_D, nflr_Sr, nflr_Ï„
 end
 
 
-@with_signature function flux(equation::Equation)
-  @accepts State(sD, sSr, stau), p, rho, vr, eps, A, B, r
-  rAB3     = r * A * B^3
-  flx_sD, flx_sSr, flx_stau = 0, 0, 0
-  try
-    flx_sD   = rAB3 * Formulae.fD(B, rho, vr, eps, p)
-    flx_sSr  = rAB3 * Formulae.fSr(B, rho, vr, eps, p)
-    flx_stau = rAB3 * Formulae.fτ(B, rho, vr, eps, p)
-  catch e
-    println("failed @ r = $r")
-    rethrow(e)
-  end
-  @returns flx_sD, flx_sSr, flx_stau
+@with_signature function bdryllf(equation::Equation)
+  @accepts        D, flr_D, Sr, flr_Sr, Ï„, flr_Ï„, max_v, vr, p
+  @accepts        init_D, init_Sr, init_Ï„, init_vr, init_max_v, init_p
+  @accepts        α, βru, γrr
+  @accepts [bdry] nx
+
+  vmax     = absmax(max_v, init_max_v)
+  γuurr    = 1/γrr
+  init_vru = γuurr * init_vr
+  vru      = γuurr * vr
+
+  # enforce dirichlet/neumann conditions following stability analysis
+  # see dg-notes/tex/evm.pdf
+  # Hesthaven, Numerical Methods for Conservation Laws uses same logic
+
+  # Dirichlet conditions
+  # ## if block for hand-tweaked outflow condition for bondi accretion at inner radius
+  # if nx > 0
+    bdry_D   = -D   + 2*init_D
+    bdry_Sr  = -Sr  + 2*init_Sr
+    bdry_Ï„   = -Ï„   + 2*init_Ï„
+    bdry_vru = -vru + 2*init_vru
+    bdry_p   = -p   + 2*init_p
+  # else
+  #   bdry_D   = D
+  #   bdry_Sr  = Sr
+  #   bdry_Ï„   = Ï„
+  #   bdry_vru = vru
+  #   bdry_p   = p
+  # end
+
+  # Neumann conditions
+  # bdry_D   = D
+  # bdry_Sr   = Sr
+  # bdry_Ï„ = Ï„
+
+  bdry_flr_D  = α * bdry_D * (bdry_vru - βru/α)
+  bdry_flr_Sr = α * ( bdry_Sr * (bdry_vru - βru/α) + bdry_p )
+  bdry_flr_τ  = α * ( bdry_τ * (bdry_vru - βru/α) + bdry_p * bdry_vru )
+
+  nflr      = nx*flr_D
+  bdry_nflr = nx*bdry_flr_D
+  nflr_D    = LLF(nflr, bdry_nflr, D, bdry_D, vmax)
+
+  nflr      = nx*flr_Sr
+  bdry_nflr = nx*bdry_flr_Sr
+  nflr_Sr   = LLF(nflr, bdry_nflr, Sr, bdry_Sr, vmax)
+
+  nflr      = nx*flr_Ï„
+  bdry_nflr = nx*bdry_flr_Ï„
+  nflr_Ï„    = LLF(nflr, bdry_nflr, Ï„, bdry_Ï„, vmax)
+
+  @returns [bdry] nflr_D, nflr_Sr, nflr_Ï„
 end
 
-
-@with_signature function speed(equation::Equation)
-  @accepts State(sD, sSr, stau), p, rho, vr, eps, A, B, r
-  # TODO Implement characteristics and derive maxiumum wave speeds.
-  # Might be as simple as adding a missing factor for the auxiliary metric to the
-  # eigenvalues, since ts is the only thing the generalized Valencia formulation adds
-  # to the principal part.
-  # for now we use speed of light
-  max_v = 0.999
-  @returns max_v
+@with_signature function fv_bdry_flux(equation::Equation)
+  @accepts D, Sr, Ï„, vr, p
+  @accepts init_D, init_Sr, init_Ï„, init_vr, init_p
+  @accepts α, βru, γrr
+  @accepts [bdry] nx
+
+  γuurr    = 1/γrr
+  init_vru = γuurr * init_vr
+  vru      = γuurr * vr
+
+  # Dirichlet conditions
+  # if nx < 0
+    bdry_D   = -D   + 2*init_D
+    bdry_Sr  = -Sr  + 2*init_Sr
+    bdry_Ï„   = -Ï„   + 2*init_Ï„
+    bdry_vru = -vru + 2*init_vru
+    bdry_p   = -p   + 2*init_p
+  # else
+  #   bdry_D   = D
+  #   bdry_Sr  = Sr
+  #   bdry_Ï„   = Ï„
+  #   bdry_vru = vru
+  #   bdry_p   = p
+  # end
+
+  nflr_D  = α * bdry_D * (bdry_vru - βru/α)
+  nflr_Sr = α * ( bdry_Sr * (bdry_vru - βru/α) + bdry_p )
+  nflr_τ  = α * ( bdry_τ * (bdry_vru - βru/α) + bdry_p * bdry_vru )
+
+  @returns [bdry] bdry_D, bdry_Sr, bdry_Ï„, nflr_D, nflr_Sr, nflr_Ï„
 end
 
 
-# @with_signature function impose_atmosphere(equation::Equation)
-#   @accepts rho, p, eps, v, D, S, tau
-#   @unpack atmosphere = equation
-#
-#   ρatm = atmosphere.rho
-#   patm = 0.0
-#   ϵatm = tau / ρatm
-#   sm = 1.0
-#   Watm = 1.0
-#   vatm = 1.0
-#
-#   if rho < atmosphere.rho * atmosphere.threshold
-#     rho = rhoatm
-#     p   = patm
-#     eps = epsatm
-#     v   = vatm
-#     D   = Formulae.D(rhoatm, vatm, epsatm, patm)
-#     S   = Formulae.S(rhoatm, vatm, epsatm, patm)
-#     tau = Formulae.Ï„(rhoatm, vatm, epsatm, patm)
-#   end
-#
-#   @returns rho, p, eps, v, D, S, tau
-# end
-
-
-@with_signature function primitives(equation::Equation)
-  @accepts D, Sr, tau, p, B
-  rho = Formulae.ρ(B, D, Sr, tau, p)
-  vr  = Formulae.vr(B, D, Sr, tau, p)
-  eps = Formulae.ϵ(B, D, Sr, tau, p)
-  @returns rho, vr, eps
-end
+#######################################################################
+#                       "rescaled_spherical1d"                        #
+#           Spherical symmetry (1d) + spherical coordinates           #
+#######################################################################
 
 
-@with_signature function prim2cons(equation::Equation)
-  @accepts rho, vr, eps, p, B
-  D   = Formulae.D(B, rho, vr, eps, p)
-  Sr  = Formulae.Sr(B, rho, vr, eps, p)
-  tau = Formulae.Ï„(B, rho, vr, eps, p)
-  @returns D, Sr, tau
-end
+@with_signature function flux_source_rescaled_spherical1d(eq::Equation)
+  @accepts D, Sr, Ï„, p, vr
+  @accepts A, ∂Ar, B, ∂Br, r
+
+  γuurr = 1/B^2
+  vru   = γuurr * vr
 
+  B3 = B^3
+  flr_rD  = r*A*B3 * D * vru
+  flr_rSr = r*A*B3 * (Sr*vru + p)
+  flr_rτ  = r*A*B3 * (τ + p) * vru
 
-@with_signature function entropy_variables(equation::Equation{EquationOfState.IdealGas})
-  @accepts rho, p, E, flx_E
-  TODO(entropy_variables)
-  # @unpack eos = equation
-  # γ     = eos.gamma
-  # E     = rho / (γ - 1) * log(p / rho^γ)
-  # flx_E = q * E / rho
-  @returns E, flx_E
+  src_rD  = - A*B3 * D * vru
+  # src_rSr = -(τ+p)*r*B3*∂Ar + A*B^2*(r*∂Br+B/3)*(Sr*vru+3*p) - 4/3*A*B3*Sr*vru
+  # src_rSr = -(τ+p)*r*B3*∂Ar + A*B^2*(r*∂Br+B/3)*(Sr*vru/A^2+3*p) - 4/3*A*B3*Sr*vru
+  src_rSr = -(τ+p)*r*B3*∂Ar + A*B^2*(r*∂Br+B/3)*(Sr*vru/A^2+3*p) - 4/3*A*B3*Sr*vru
+  # src_rτ  = -r*B*Sr*∂Ar - A*B3*(τ+p)*vru
+  src_rτ  = -r*B*Sr*∂Ar/A - A*B3*(τ+p)*vru
+
+  @returns src_rD, src_rSr, src_rτ, flr_rD, flr_rSr, flr_rτ
 end
 
+@with_signature function maxspeed_rescaled_spherical1d(equation::Equation)
+  @accepts vr, ρ, ϵ
+  @accepts B, A
+  @unpack eos = equation
+  cs2 = eos(SquareSpeedOfSound, Density, ρ, InternalEnergy, ϵ)
+  cs = sqrt(abs(cs2))
+  γuurr = 1/B^2
+  vru = γuurr * vr
+  v2 = vru*vr
+  λ0 = A*vru
+  W = 1/sqrt(1-v2)
+  λp = A/(1-v2)*(vru*(1-cs2)+cs/W*sqrt((1-v2*cs2)*γuurr-vru^2*(1-cs2)))
+  λm = A/(1-v2)*(vru*(1-cs2)-cs/W*sqrt((1-v2*cs2)*γuurr-vru^2*(1-cs2)))
+  max_v = absmax(λm, λ0, λp)
+  @returns max_v
+end
+
+@with_signature function llf_rescaled_spherical1d(equation::Equation)
+  @accepts        D, flr_rD, Sr, flr_rSr, τ, flr_rτ, max_v, p
+  @accepts        A, B, r
+  @accepts [bdry] bdry_D, bdry_Sr, bdry_Ï„, bdry_max_v, bdry_vr, bdry_p
+  @accepts [bdry] nx
+
+  vmax     = absmax(max_v, bdry_max_v)
+  γuurr    = 1/B^2
+  bdry_vru = γuurr * bdry_vr
+  B3       = B^3
+
+  rD       = r*B3*D
+  rSr      = r*B3*Sr
+  rτ       = r*B3*τ
+  bdry_rD  = r*B3*bdry_D
+  bdry_rSr = r*B3*bdry_Sr
+  bdry_rτ  = r*B3*bdry_τ
+
+  bdry_flr_rD  = r*A*B3 * bdry_D * bdry_vru
+  bdry_flr_rSr = r*A*B3 * ( bdry_Sr * bdry_vru + bdry_p )
+  bdry_flr_rτ  = r*A*B3 * ( (bdry_τ + bdry_p) * bdry_vru )
+
+  nflr      = nx*flr_rD
+  bdry_nflr = nx*bdry_flr_rD
+  nflr_rD   = LLF(nflr, bdry_nflr, rD, bdry_rD, vmax)
+
+  nflr      = nx*flr_rSr
+  bdry_nflr = nx*bdry_flr_rSr
+  nflr_rSr  = LLF(nflr, bdry_nflr, rSr, bdry_rSr, vmax)
+
+  nflr      = nx*flr_rτ
+  bdry_nflr = nx*bdry_flr_rτ
+  nflr_rτ   = LLF(nflr, bdry_nflr, rτ, bdry_rτ, vmax)
+
+  @returns [bdry] nflr_rD, nflr_rSr, nflr_rτ
+end
 
-@with_signature function sources(equation::Equation)
-  @accepts rho, vr, p, eps, r, A, A_r, B, B_r
-  src_sD   = Formulae.sD(r, A, A_r, B, B_r, rho, vr, eps, p)
-  src_sSr  = Formulae.sSr(r, A, A_r, B, B_r, rho, vr, eps, p)
-  src_stau = Formulae.sτ(r, A, A_r, B, B_r, rho, vr, eps, p)
-  @returns src_sD, src_sSr, src_stau
+@with_signature function bdryllf_rescaled_spherical1d(equation::Equation)
+  @accepts        D, flr_rD, Sr, flr_rSr, τ, flr_rτ, max_v, vr, p
+  @accepts        init_D, init_Sr, init_Ï„, init_vr, init_max_v, init_p
+  @accepts        A, B, r
+  @accepts [bdry] nx
+
+  vmax     = absmax(max_v, init_max_v)
+  γuurr    = 1/B^2
+  init_vru = γuurr * init_vr
+  vru      = γuurr * vr
+  B3       = B^3
+
+  # Dirichlet conditions
+  bdry_D   = -D   + 2*init_D
+  bdry_Sr  = -Sr  + 2*init_Sr
+  bdry_Ï„   = -Ï„   + 2*init_Ï„
+  bdry_vru = -vru + 2*init_vru
+  bdry_p   = -p   + 2*init_p
+
+  # Neumann conditions
+  # bdry_D   = D
+  # bdry_Sr   = Sr
+  # bdry_Ï„ = Ï„
+
+  rD       = r*B3*D
+  rSr      = r*B3*Sr
+  rτ       = r*B3*τ
+  bdry_rD  = r*B3*bdry_D
+  bdry_rSr = r*B3*bdry_Sr
+  bdry_rτ  = r*B3*bdry_τ
+
+  bdry_flr_rD  = r*A*B3 * bdry_D * bdry_vru
+  bdry_flr_rSr = r*A*B3 * ( bdry_Sr * bdry_vru + bdry_p )
+  bdry_flr_rτ  = r*A*B3 * (bdry_τ + bdry_p) * bdry_vru
+
+  nflr      = nx*flr_rD
+  bdry_nflr = nx*bdry_flr_rD
+  nflr_rD   = LLF(nflr, bdry_nflr, rD, bdry_rD, vmax)
+
+  nflr      = nx*flr_rSr
+  bdry_nflr = nx*bdry_flr_rSr
+  nflr_rSr  = LLF(nflr, bdry_nflr, rSr, bdry_rSr, vmax)
+
+  nflr      = nx*flr_rτ
+  bdry_nflr = nx*bdry_flr_rτ
+  nflr_rτ   = LLF(nflr, bdry_nflr, rτ, bdry_rτ, vmax)
+
+  @returns [bdry] nflr_rD, nflr_rSr, nflr_rτ
 end
 
 
-@with_signature function cons2scaledcons(equations::Equation)
-  @accepts D, Sr, tau, B, r
-  sD   = r * B^3 * D
-  sSr  = r * B^3 * Sr
-  stau = r * B^3 * tau
-  @returns sD, sSr, stau
+@with_signature function unscale_conservatives(equation::Equation)
+  @accepts rD, rSr, rτ
+  @accepts r, B
+  B3 = B^3
+  D  = rD/(r*B3)
+  Sr = rSr/(r*B3)
+  τ  = rτ/(r*B3)
+  @returns D, Sr, Ï„
 end
 
 
-@with_signature function scaledcons2cons(equations::Equation)
-  @accepts sD, sSr, stau, B, r
-  D   = sD / (r * B^3)
-  Sr  = sSr / (r * B^3)
-  tau = stau / (r * B^3)
-  @returns D, Sr, tau
+@with_signature function fv_bdry_flux_rescaled_spherical1d(equation::Equation)
+  @accepts D, Sr, Ï„, vr, p
+  @accepts init_D, init_Sr, init_Ï„, init_vr, init_p
+  @accepts A, B, ∂Br, r
+  @accepts [bdry] nx
+
+  γuurr    = 1/B^2
+  init_vru = γuurr * init_vr
+  vru      = γuurr * vr
+  B3       = B^3
+
+  # # Dirichlet conditions
+  bdry_D   = -D   + 2*init_D
+  bdry_Sr  = -Sr  + 2*init_Sr
+  bdry_Ï„   = -Ï„   + 2*init_Ï„
+  bdry_vru = -vru + 2*init_vru
+  bdry_p   = -p   + 2*init_p
+  # bdry_D   = init_D
+  # bdry_Sr  = init_Sr
+  # bdry_Ï„   = init_Ï„
+  # bdry_vru = init_vru
+  # bdry_p   = init_p
+
+  @show init_D, D
+
+  nflr_rD  = r*A*B3* bdry_D * bdry_vru
+  nflr_rSr = r*A*B3* (bdry_Sr * bdry_vru + bdry_p)
+  nflr_rτ  = r*A*B3* (bdry_τ + bdry_p) * bdry_vru
+
+  # FIXME We are abusing the bdry_D,Sr,Ï„ buffers to store the rescaled bdry values
+  bdry_D  *= r*B3
+  bdry_Sr *= r*B3
+  bdry_Ï„  *= r*B3
+
+  @returns [bdry] bdry_D, bdry_Sr, bdry_τ, nflr_rD, nflr_rSr, nflr_rτ
 end
 
 
-"""
-Postprocess points where we divided by zero in `scaledcons2cons`.
-Do so by interpolating value where x = 0 using symmetry/anti-symmetry
-"""
-function postprocess_scaledcons2cons!(cache::Cache, equations::Equation, mesh::Mesh)
+#######################################################################
+#            helpers to resolve coordinate singularities              #
+#            by imposing symmetry conditions at r=0                   #
+#######################################################################
 
-  @unpack x = mesh
-  Npts, K = layout(mesh)
 
-  if isodd(Npts) && isodd(K)
-    error("Cannot yet handle case where r = 0 falls into symmetric cell with even polynomial!")
-  end
+function impose_symmetry!(P::Project{:rescaled_spherical1d}, mesh::Mesh)
 
-  # find points where x coordinate is zero
-  idxs = findall(xi->abs(xi) < 1e-14, mesh.x)
+  @unpack cache = mesh
+  @unpack D, Sr, Ï„ = get_static_variables(cache)
+  L = layout(mesh)
+  Npts, _ = L
 
-  @unpack D, Sr, tau    = get_static_variables(cache)
+  vD  = dg1d.vreshape(D, L)
+  vSr = dg1d.vreshape(Sr, L)
+  vτ  = dg1d.vreshape(τ, L)
 
-  for con in (D, tau) # symmetric variables need to be interpolated
-    mat_con  = reshape(view(con, :), (Npts, K))
-    for idx in idxs
-      i, j = Tuple(idx)
-      mat_con[i,j] = 0 # remove nan, because we are computing inplace
-      Di = mesh.element.D[i,:] # derivative weights for ith point
-      Dii = Di[i]
-      mat_con[i,j] = - dot(Di, mat_con[:,j]) / Dii
-    end
-  end
-  for con in (Sr,) # asymmetric variables need to be set to zero
-    for idx in idxs
-      i, j = Tuple(idx)
-      con[i+(j-1)*Npts] = 0
+  # even variables are interpolated such that derivative vanishes at r=0
+  for var in (vD, vτ)
+    tmp = 0
+    for j = 2:Npts
+      tmp += mesh.element.D[1,j] * var[j,1]
     end
+    var[1,1] = -tmp/mesh.element.D[1,1]
   end
+  # odd variables are set to zero at r=0
+  Sr[1] = 0
+
+  return
 end
 
 
-#######################################################################
-#                                 LDG                                 #
-#######################################################################
+function impose_symmetry!(P::Project{:rescaled_spherical1d}, mesh::Mesh{FVElement})
 
+  @unpack cache = mesh
+  @unpack rD = get_dynamic_variables(cache)
+  @unpack D, Sr, Ï„, r = get_static_variables(cache)
+  L = layout(mesh)
+  Npts, _ = L
 
-@with_signature function ldg_flux(equations::Equation)
-  @accepts State(sD, sSr, stau)
-  flx_ldg_sD, flx_ldg_sSr, flx_ldg_stau = sD, sSr, stau
-  @returns flx_ldg_sD, flx_ldg_sSr, flx_ldg_stau
-end
-
+  @show rD[1], rD[2]
 
-@with_signature function ldg_speed(equations::Equation)
-  @accepts State(sD, sSr, stau)
-  v_ldg_sD, v_ldg_sSr, v_ldg_stau = 1, 1, 1
-  @returns v_ldg_sD, v_ldg_sSr, v_ldg_stau
-end
+  # symmetric variables are interpolated such that derivative vanishes at r=0
+  for var in (D, Ï„)
+    tmp = 0
+    # use quadratic interpolation around origin
+    var2, var3, r2, r3 = var[2], var[3], r[2], r[3]
+    var[1] = (r3^2*var2-r2^2*var3)/(r3^2-r2^2)
+  end
+  # asymmetric variables are set to zero at r=0
+  Sr[1] = 0
 
+  @show D[1], D[2]
 
-@with_signature function av_flux(equations::Equation)
-  @accepts State(ldg_sD, ldg_sSr, ldg_stau), smoothed_mu
-  flx_ldg_sD, flx_ldg_sSr, flx_ldg_stau =
-    smoothed_mu * ldg_sD, smoothed_mu * ldg_sSr, smoothed_mu * ldg_stau
-  @returns flx_ldg_sD, flx_ldg_sSr, flx_ldg_stau
+  return
 end
 
 
-@with_signature function av_speed(equations::Equation)
-  @accepts State(ldg_sD, ldg_sSr, ldg_stau), smoothed_mu
-  flx_ldg_sD, flx_ldg_sSr, flx_ldg_stau = smoothed_mu, smoothed_mu, smoothed_mu
-  @returns v_flx_ldg_sD, v_flx_ldg_sSr, v_flx_ldg_stau
+function impose_symmetry_sources!(P::Project{:spherical1d}, mesh::Mesh)
+  @unpack r = get_static_variables(mesh.cache)
+  r[1] ≈ 0.0 || return
+  @unpack src_D, src_Sr, src_Ï„ = get_static_variables(mesh.cache)
+  L = layout(mesh)
+  Npts, _ = L
+  v_src_D  = dg1d.vreshape(src_D, L)
+  v_src_Ï„  = dg1d.vreshape(src_Ï„, L)
+  # even variables are interpolated such that derivative vanishes at r=0
+  for var in (v_src_D, v_src_Ï„)
+    tmp = 0
+    for j = 2:Npts
+      tmp += mesh.element.D[1,j] * var[j,1]
+    end
+    var[1,1] = -tmp/mesh.element.D[1,1]
+  end
+  # odd variables are set to zero at r=0
+  src_Sr[1] = 0
+  return
 end
diff --git a/src/GRHD/initialdata.jl b/src/GRHD/initialdata.jl
index d473ee1dfed394307f41882fff4f10bf1b9004c4..c73c8f9d61db3243f13d52c755609836f9f4a7ab 100644
--- a/src/GRHD/initialdata.jl
+++ b/src/GRHD/initialdata.jl
@@ -1,14 +1,9 @@
 function initialdata!(env, P::Project, prms)
   @unpack id = prms
-  let
-    @unpack r = get_static_variables(env.cache)
-    @. r = env.mesh.x[:]
-  end
   initialdata_equation!(Val(Symbol(id)), env, P, prms)
-  return
-  # initialdata_entropy_variables!(id, P, prms)
-  initialdata_hrsc!(Val(Symbol(id)), env, P, P.hrsc, prms)
-  initialdata_tci!(Val(Symbol(id)), env, P, P.tci, prms)
+  # # initialdata_entropy_variables!(id, P, prms)
+  # initialdata_hrsc!(Val(Symbol(id)), env, P, P.hrsc, prms)
+  # initialdata_tci!(Val(Symbol(id)), env, P, P.tci, prms)
 end
 
 
@@ -17,291 +12,382 @@ end
 #######################################################################
 
 
-function initialdata_equation!(::Val{T}, env, P, parameters) where T
-  TODO(initialdata_equation!)
-end
-
+function initialdata_equation!(::Val{:bondi_accretion}, env, P::Project{:spherical1d}, prms)
 
-function initialdata_equation!(::Val{:bondi_accretion}, env, P, prms)
-  TODO(initialdata_equation!)
-end
+  @unpack mesh = env
+  @unpack equation = P
 
+  id_filename = prms["id_filename"]
+  if !isfile(id_filename)
+    error("GRHD: Failed to locate bondi_accretion initial data at $id_filename")
+  end
 
-function readdata_tov(filename)
-  return h5open(filename, "r") do file
-    g = file["TOV"]
-    Γ = read_attribute(g, "Γ")
-    K = read_attribute(g, "K")
+  data = h5open(id_filename, "r") do file
+    g = file["bondi_accretion"]
+    Γ  = read_attribute(g, "Γ")
+    K  = read_attribute(g, "K")
     ρc = read_attribute(g, "ρc")
-    M = read_attribute(g, "M")
-    Ï• = read(g, "Ï•")
-    p = read(g, "p")
-    m = read(g, "m")
-    R = read(g, "R")
-    r = read(g, "r")
-    (; Γ, K, ρc, M, ϕ, p, m, R, r)
+    rc = read_attribute(g, "rc")
+    M  = read_attribute(g, "M")
+    r  = read(g, "r")
+    ρ  = read(g, "ρ")
+    p  = read(g, "p")
+    ϵ  = read(g, "ϵ")
+    vr = read(g, "vr")
+    (; Γ, K, ρc, rc, M, r, ρ, ϵ, p, vr)
   end
+
+  @assert data.K ≈ equation.eos.K
+  @assert data.Γ ≈ equation.eos.Gamma
+
+  @unpack D, Sr, Ï„ = get_dynamic_variables(mesh.cache)
+  @unpack ρ, p, ϵ, vr, r, max_v,
+          init_D, init_Sr, init_Ï„, init_vr, init_p,
+          init_max_v = get_static_variables(mesh.cache)
+  @unpack α, βru, ∂αr, ∂βrrdu,
+          γrr, γθθ, γϕϕ, ∂γrrr, ∂γrθθ, ∂γrϕϕ, ∂γθϕϕ,
+          Γrrr, Γrθθ, Γrϕϕ, Γθrθ, Γθϕϕ, Γϕrϕ, Γϕθϕ,
+          Krr, Kθθ, Kϕϕ = get_static_variables(mesh.cache)
+
+  p   .= interpolate(r, data.r, data.p)
+  ρ   .= interpolate(r, data.r, data.ρ)
+  ϵ   .= interpolate(r, data.r, data.ϵ)
+  vru  = interpolate(r, data.r, data.vr)
+
+  equation.atm_density = maximum(ρ) * equation.atm_factor
+  equation.atm_factor = prms["atm_factor"]
+  equation.atm_threshold = prms["atm_threshold_factor"]
+
+  # to avoid problems with 1/sin(θ) etc., this is also done in initialdata/SphericalAccretion.jl
+  θ = π/2
+  @unpack M = data
+
+  @. α   = sqrt(r/(r+2*M))
+  @. βru = 2*M/(r+2*M) # = β^r
+  @. ∂αr = M / sqrt(r*(2*M+r)^3)
+  @. ∂βrrdu = - 2*M/(2*M+r)^2
+
+  # γ_ij
+  @. γrr = 1 + 2*M/r
+  @. γθθ = r^2
+  @. γϕϕ = r^2 * sin(θ)^2
+
+  # # γijuu = γ^ij
+  # γrruu = @. 1/γrr
+  # γθθuu = @. 1/γθθ
+  # γϕϕuu = @. 1/γϕϕ
+
+  # ∂iγjk := ∂γijk
+  @. ∂γrrr = -2*M/r^2
+  @. ∂γrθθ = 2*r
+  @. ∂γrϕϕ = 2*r*sin(θ)^2
+  @. ∂γθϕϕ = r^2 * sin(θ)*cos(θ)
+
+  # Γijk := Γ^i_jk wrt γ_ij
+  @. Γrrr = -M/(r*(2*M+r))
+  @. Γrθθ = -r^2/(2*M+r)
+  @. Γrϕϕ = -r^2*sin(θ)^2/(2*M+r)
+  @. Γθrθ = 1/r
+  @. Γθϕϕ = -sin(θ)*cos(θ)
+  @. Γϕrϕ = 1/r
+  @. Γϕθϕ = cos(θ)/sin(θ)
+
+  # Kij := K_ij
+  @. Krr = -2*M*(M+r)/sqrt(r^5*(2*M+r))
+  @. Kθθ = 2*M*sqrt(r/(2*M+r))
+  @. Kϕϕ = 2*M*sqrt(r/(2*M+r))*sin(θ)^2
+
+  # # ∂Kijk = ∂_i K_jk
+  # ∂Krrr = @. 2*M*(5*M^2+2*r^2+6*M*r)/sqrt(r^7*(2*M+r)^3)
+  # ∂Krθθ = @. 2*M^2/sqrt(r*(2*M+r)^3)
+  # ∂Krϕϕ = @. ∂Krθθ * sin(θ)^2
+
+  # # verify trace of K
+  # trK_v1 = @. Krr*γrruu + Kθθ*γθθuu + Kϕϕ*γϕϕuu
+  # trK_v2 = @. 2*M*α^3/r^2*(1+3*M/r)
+  # @show(extrema(trK_v1.-trK_v2))
+
+
+  # from initialdata/SphericalAccretion.jl
+  # also see Papadopoulos and Font 1998, arXiv:gr-qc/9803087, eq (5)
+  v2  = @. γrr*vru^2
+  W   = @. 1/sqrt(1-v2)  # = αu^t, Lorentz factor
+  @. vr = γrr * vru # = γ_rr v^r
+
+  h = @. 1 + ϵ + p/ρ
+  @. D  = W * ρ
+  @. Sr = W^2 * ρ * h * vr
+  @. τ  = W^2 * ρ * h - p - D
+
+  broadcast_volume!(cons2prim, equation, mesh)
+  broadcast_volume!(maxspeed, equation, mesh)
+  broadcast_volume!(flux_source_spherical1d, equation, mesh)
+
+  @. init_D     = D
+  @. init_Sr    = Sr
+  @. init_Ï„     = Ï„
+  @. init_vr    = vr
+  @. init_p     = p
+  @. init_max_v = max_v
+
+  return
 end
 
 
-function initialdata_equation!(::Val{:tov}, env, P, prms)
+function initialdata_equation!(::Val{:tov}, env, P::Project{:spherical1d}, prms)
 
   filename = prms["id_filename"]
-  if length(filename) == 0
-    error("GRHD: Missing filename for TOV output, include with GRHD.id_filename = 'tov'")
-  end
-  filename = joinpath(get_output_dir(), filename)
-
-  # read TOV result from file
-  # should only contain solution in star interior
-  # output_dir = dg1d.get_output_dir()
-  # data  = TOV.read_data(joinpath(output_dir, "TOV.h5"))
-  data  = readdata_tov(filename)
-  Ï•int  = data.Ï•
-  Rint  = data.R
-  rint  = data.r
-  pint  = data.p
-  K     = data.K
-  Γ     = data.Γ
-  M     = data.M
-  Rsurf = Rint[end]
-
-  # interpolate data onto our grid
-  # we don't assume a special grid layout for the loaded data
-
-  @unpack cache, mesh = env
-  @unpack Npts = mesh.element
-
-  intrp_R = vec(mesh.x) # DG coordinates
-  NN = length(intrp_R)
-
-  # determine if grid contains r = 0 point
-  R_ismirrored = intrp_R[1] ≈ -intrp_R[end]
-
-  if !R_ismirrored
-    idx_origin = findall(Ri -> isapprox(Ri, 0), intrp_R)
-    @assert length(idx_origin) > 0 "Non-symmetric grids must include coordinate origin"
+  if !isfile(filename)
+    error("GRHD: Failed to locate TOV initial data at id_filename = $filename")
   end
 
-  # determine our grid setup
-  R_includes_origin = (
-    !R_ismirrored # LGL grids always contain bdry points
-    || (
-      iseven(mesh.K) ||  # origin falls at interface between two cells
-      (isodd(mesh.K) && isodd(mesh.element.Npts)) # origin sits in the center
-                                                  # of a cell with a point in the center
-    )
-  )
-  R_origin_isdoubled = (
-    R_ismirrored && # only happens for mirrored domains
-    iseven(mesh.K)  # and origin falls at interface between two cells
-  )
-  # if r = 0 only covered by one point we have to exclude the boundary
-  # point when mirroring/refelcting back
-  exclude_origin = !R_origin_isdoubled && R_includes_origin
-
-  # on a mirrored grid we only do interpolation on one half and then
-  # mirror/reflect onto the other
-  @show NN
-  @show R_ismirrored
-  @show R_origin_isdoubled
-  @show R_includes_origin
-  if R_ismirrored
-    idx_innermost_R = if R_origin_isdoubled
-      Int64(NN/2) + 1
-    elseif R_includes_origin
-      Int64((NN+1)/2)
-    else
-      Int64(NN/2) + 1
-    end
-    intrp_R = intrp_R[idx_innermost_R:end]
-  end
-  Rmax = maximum(intrp_R) # star's radius
-
-  @info "TOV star surface located at R = $Rsurf"
-
-  #### setup metric functions A, B and derivatives in isotropic coordinates
-
-  # star interior solution
-  Aint = exp.(Ï•int)
-  # B := r / R, needs special treatment of coordinate singularity.
-  Bint = [ (ri == 0) ? 1.0 : ri / Ri for (ri, Ri) in zip(rint, Rint) ]
-  # use linear interpolation to obtain value at r = R = 0.
-  Bint[1] = (Bint[3] - Bint[2]) / (Rint[3] - Rint[2]) * (0.0 - Rint[2]) + Bint[2]
-
-  # derivatives
-  dAint = dg1d.FD.central_dx(Aint, Rint)
-  dBint = dg1d.FD.central_dx(Bint, Rint)
-
-  # star exterior solution =^= Schwarzschild solution
-  Npts_ext = 1000 # number of points used for interpolation of exterior solution
-  Rext = collect(LinRange(Rsurf, Rmax, Npts_ext))
-  Aext, Bext = schwarzschild_solution_isotropic_coordinates(Rext, M)
-
-  # merge interior and exterior solutions
-  # note: exclude surface point in one of the arrays when merging
-  R = cat(Rint, Rext[2:end], dims=1)
-  A = cat(Aint, Aext[2:end], dims=1)
-  B = cat(Bint, Bext[2:end], dims=1)
-
-  # derivatives
-  dA = dg1d.FD.central_dx(A, R)
-  dB = dg1d.FD.central_dx(B, R)
-
-  intrp_A   = interpolate(intrp_R[:], R, A)
-  intrp_B   = interpolate(intrp_R[:], R, B)
-  intrp_A_r  = interpolate(intrp_R[:], R, dA)
-  intrp_B_r  = interpolate(intrp_R[:], R, dB)
-
-  if R_ismirrored
-    intrp_A    = mirror(intrp_A, exclude_origin)
-    intrp_B    = mirror(intrp_B, exclude_origin)
-    intrp_A_r  = reflect(intrp_A_r, exclude_origin)
-    intrp_B_r  = reflect(intrp_B_r, exclude_origin)
+  data = h5open(filename, "r") do file
+    g = file["TOV"]
+    Γ  = read_attribute(g, "Γ")
+    K  = read_attribute(g, "K")
+    ρc = read_attribute(g, "ρc")
+    M  = read_attribute(g, "M")
+    rsch = read(g, "r") # schwarzschild radius coordinate
+    riso = read(g, "R") # isotropic radius coordinate
+    ρ   = read(g, "ρ")
+    p   = read(g, "p")
+    ϵ   = read(g, "ϵ")
+    Ï•   = read(g, "Ï•")
+    m   = read(g, "m")
+
+    # metric potentials: ds^2 = -A^2 dt^2 + B^2 γij dx^i dx^j
+    A = @. exp(Ï•)
+    B = @. rsch / riso
+    # B[1] is nan, because rsch = riso = 0 there
+    # use a parabola to interpolate data point at riso = 0
+    # this also ensures that B is symmetric arcoss riso = 0
+    B2, B3, r2, r3 = B[2], B[3], riso[2], riso[3]
+    B[1] = (r3^2*B2-r2^2*B3)/(r3^2-r2^2)
+
+    (; Γ, K, ρc, M, riso, ρ, ϵ, p, A, B)
   end
 
-  @assert all(map(X->all(isfinite.(X)), [intrp_A, intrp_B, intrp_A_r, intrp_B_r])) == true ""
-    "Initial data interpolation failed!"
-
-  @unpack A, B, A_r, B_r = get_static_variables(cache)
-  A   .= intrp_A
-  B   .= intrp_B
-  A_r .= intrp_A_r
-  B_r .= intrp_B_r
-
-  ### setup hydrodynamic variables
   @unpack equation = P
-  # @unpack atmosphere = equation
-  eos = Polytrope(K=K, Gamma=Γ)
-
-  # apply atmosphere treatment
-  pmax = maximum(pint)
-  ρmax = eos(Density, Pressure, pmax)
-  ρatm = equation.atm_factor * ρmax
-  # initialize atmosphere
-  equation.atm_density = ρatm
-  patm = eos(Pressure, Density, ρatm)
-  pint[@.(pint < 0)] .= 0.0 # just to be sure, they will be replace with patm below anyways
-  ρint = @. eos(Density, Pressure, pint)
-  idxatm_treatment = @. ρint < ρatm * equation.atm_threshold
-  pint[idxatm_treatment] .= patm
-  ρint[idxatm_treatment] .= ρatm
-  vint = zeros(size(Rint))
-  ϵint = @. eos(InternalEnergy, Density, ρint)
-
-  # star exterior data
-  ρext = ρatm * ones(size(Rext))
-  pext = @. eos(Pressure, Density, ρext)
-  vext = zeros(size(Rext))
-  ϵext = @. eos(InternalEnergy, Density, ρext)
-
-  # merge interior and exterior solutions
-  p  = cat(pint, pext[2:end], dims=1)
-  ρ  = cat(ρint, ρext[2:end], dims=1)
-  vr = cat(vint, vext[2:end], dims=1)
-  ϵ  = cat(ϵint, ϵext[2:end], dims=1)
-
-  intrp_p  = interpolate(intrp_R[:], R, p)
-  intrp_ρ  = interpolate(intrp_R[:], R, ρ)
-  intrp_vr = interpolate(intrp_R[:], R, vr)
-  intrp_ϵ  = interpolate(intrp_R[:], R, ϵ)
-
-  if R_ismirrored
-    intrp_p  = mirror(intrp_p, exclude_origin)
-    intrp_ρ  = mirror(intrp_ρ, exclude_origin)
-    intrp_vr = reflect(intrp_vr, exclude_origin)
-    intrp_ϵ  = mirror(intrp_ϵ, exclude_origin)
-  end
-
-  @unpack p, vr, rho, eps = get_static_variables(cache)
-  @unpack sD, sSr, stau   = get_dynamic_variables(cache)
-  @unpack D, Sr, tau,     = get_static_variables(cache)
-
-  p .= intrp_p
-  rho .= intrp_ρ
-  vr .= intrp_vr
-  eps .= intrp_ϵ
-
-  broadcast_volume!(prim2cons, equation, cache)
-  broadcast_volume!(cons2scaledcons, equation, cache)
-
-  @assert all(map(X->all(isfinite.(X)),
-    [p, vr, rho, eps, D, Sr, tau, sD, sSr, stau])) == true "Initial data interpolation failed!"
+  @unpack mesh = env
+  @unpack eos = P.equation
+  @assert data.K ≈ eos.K
+  @assert data.Γ ≈ eos.Gamma
+
+  equation.atm_density = data.ρc * equation.atm_factor
+  equation.atm_factor = prms["atm_factor"]
+  equation.atm_threshold = prms["atm_threshold_factor"]
+
+  @unpack D, Sr, Ï„ = get_dynamic_variables(mesh.cache)
+  @unpack ρ, p, ϵ, vr, r, max_v,
+          init_D, init_Sr, init_Ï„, init_vr, init_p,
+          init_max_v = get_static_variables(mesh.cache)
+  @unpack α, βru, ∂αr, ∂βrrdu,
+          γrr, γθθ, γϕϕ, ∂γrrr, ∂γrθθ, ∂γrϕϕ, ∂γθϕϕ,
+          Γrrr, Γrθθ, Γrϕϕ, Γθrθ, Γθϕϕ, Γϕrϕ, Γϕθϕ,
+          Krr, Kθθ, Kϕϕ = get_static_variables(mesh.cache)
+
+  # need to split initial data into portion that lies inside and outside of star,
+  # because derivatives of the hydro variables are discontinuous at the surface
+  # although metric functions are supposed to be better conditioned there,
+  # we also split them for the interpolation, because of potential contamination
+  # with numerical error from patching
+  rmax = data.riso[end]
+  idx_exterior = findfirst(ri -> ri > rmax, r) |> something
+  @assert idx_exterior > 0
+  interior = 1:idx_exterior-1
+  exterior = idx_exterior:length(mesh)
+
+  rint = view(r, interior)
+  rext = view(r, exterior)
+  A, B, ∂Ar, ∂Br = [ similar(r) for _ in 1:4 ]
+
+  ρ[interior] .= interpolate(rint, data.riso, data.ρ)
+  ϵ[interior] .= interpolate(rint, data.riso, data.ϵ)
+  p[interior] .= interpolate(rint, data.riso, data.p)
+  A[interior] .= interpolate(rint, data.riso, data.A)
+  B[interior] .= interpolate(rint, data.riso, data.B)
+
+  ρ[exterior] .= equation.atm_density
+  p[exterior] .= @. eos(Pressure, Density, ρ[exterior])
+  ϵ[exterior] .= @. eos(InternalEnergy, Density, ρ[exterior])
+  # metric potentials of Schwarzschild solution in isotropic coordinates:
+  #   ds^2 = -A^2 dt^2 + B^2 γij dx^i dx^j
+  @unpack M = data
+  A[exterior] .= @. (1-M/(2*rext))/(1+M/(2*rext))
+  B[exterior] .= @. (1+M/(2*rext))^2
+
+  # BasicInterpolators.jl cannot differentiate ...  so we diff numerically
+  ∂Ar .= dg1d.differentiate(A, mesh)
+  ∂Br .= dg1d.differentiate(B, mesh)
+
+  θ = π/2
+
+  @. α = A
+  @. βru = 0.0
+  @. ∂αr = ∂Ar
+  @. ∂βrrdu = 0
+
+  @. γrr = B^2
+  @. γθθ = B^2*r^2
+  @. γϕϕ = B^2*r^2*sin(θ)^2
+
+  @. ∂γrrr = 2*B*∂Br
+  @. ∂γrθθ = 2*(r*B^2+B*∂Br*r^2)
+  @. ∂γrϕϕ = ∂γrθθ * sin(θ)^2
+  @. ∂γθϕϕ = 0.0
+
+  @. Γrrr = ∂Br/B
+  @. Γrθθ = (-r^2*B*∂Br-r*B^2)/B^2
+  @. Γrϕϕ = Γrθθ*sin(θ)^2
+  @. Γθrθ = (r^2*B*∂Br+r*B^2)/(r^2*B^2)
+  @. Γθϕϕ = -sin(θ)*cos(θ)
+  @. Γϕrϕ = (r^2*B*∂Br+r*B^2)/(r^2*B^2)
+  @. Γϕθϕ = cos(θ)/sin(θ)
+
+  @. Krr = 0.0
+  @. Kθθ = 0.0
+  @. KÏ•Ï• = 0.0
+
+  @. vr = 0
+  W = 1.0
+  h = @. 1 + ϵ + p/ρ
+  @. D  = W * ρ
+  @. Sr = W^2 * ρ * h * vr
+  @. τ  = W^2 * ρ * h - p - D
+
+  broadcast_volume!(cons2prim, equation, mesh)
+  broadcast_volume!(maxspeed, equation, mesh)
+  broadcast_volume!(flux_source_spherical1d, equation, mesh)
+  impose_symmetry_sources!(P, mesh)
+
+  @. init_D     = D
+  @. init_Sr    = Sr
+  @. init_Ï„     = Ï„
+  @. init_vr    = vr
+  @. init_p     = p
+  @. init_max_v = max_v
 
-  return
-end
-
-
-function schwarzschild_solution_isotropic_coordinates(R, M)
-  Rmin = minimum(R)
-  @assert 2 * Rmin >= M
-  A = @. (1 - 0.5 * M / R) / (1 + 0.5 * M / R)
-  B = @. (1 + 0.5 * M / R)^2
-  return A, B
 end
 
 
-function interpolate(x, x_ref, y_ref)
-  x_intrp = LinearInterpolation(x_ref, y_ref, extrapolation_bc=Line())
-  y = [ x_intrp(xi) for xi in x ]
-  return y
-end
+function initialdata_equation!(::Val{:tov}, env, P::Project{:rescaled_spherical1d}, prms)
 
-
-function mirror(A, exclude_bdry::Bool)
-  if exclude_bdry
-    return cat(A[end:-1:2], A, dims=1)
-  else
-    return cat(A[end:-1:1], A, dims=1)
+  filename = prms["id_filename"]
+  if !isfile(filename)
+    error("GRHD: Failed to locate TOV initial data at id_filename = $filename")
   end
-end
 
-
-function reflect(A, exclude_bdry::Bool)
-  if exclude_bdry
-    return cat(-A[end:-1:2], A, dims=1)
-  else
-    return cat(-A[end:-1:1], A, dims=1)
+  data = h5open(filename, "r") do file
+    g = file["TOV"]
+    Γ  = read_attribute(g, "Γ")
+    K  = read_attribute(g, "K")
+    ρc = read_attribute(g, "ρc")
+    M  = read_attribute(g, "M")
+    rsch = read(g, "r") # schwarzschild radius coordinate
+    riso = read(g, "R") # isotropic radius coordinate
+    ρ   = read(g, "ρ")
+    p   = read(g, "p")
+    ϵ   = read(g, "ϵ")
+    Ï•   = read(g, "Ï•")
+    m   = read(g, "m")
+
+    # metric potentials: ds^2 = -A^2 dt^2 + B^2 γij dx^i dx^j
+    A = @. exp(Ï•)
+    B = @. rsch / riso
+    # B[1] is nan, because rsch = riso = 0 there
+    # use a parabola to interpolate data point at riso = 0
+    # this also ensures that B is symmetric arcoss riso = 0
+    B2, B3, r2, r3 = B[2], B[3], riso[2], riso[3]
+    B[1] = (r3^2*B2-r2^2*B3)/(r3^2-r2^2)
+
+    (; Γ, K, ρc, M, riso, ρ, ϵ, p, A, B)
   end
-end
-
 
-function initialdata_equation!(::Val{:atmosphere}, env, P, prms)
-
-  @unpack cache, mesh = env
   @unpack equation = P
-  @unpack Npts = mesh.element
-  @unpack eos = equation
-  @unpack A, B, A_r, B_r = get_static_variables(P.cache)
-  R = vec(mesh.x)
-
-  # minkowski metric
-  A   .= ones(size(R))
-  B   .= ones(size(R))
-  A_r .= zeros(size(R))
-  B_r .= zeros(size(R))
+  @unpack mesh = env
+  @unpack eos = P.equation
+  @assert data.K ≈ eos.K
+  @assert data.Γ ≈ eos.Gamma
+
+  equation.atm_density = data.ρc * equation.atm_factor
+  equation.atm_factor = prms["atm_factor"]
+  equation.atm_threshold = prms["atm_threshold_factor"]
+
+  @unpack rD, rSr, rτ = get_dynamic_variables(mesh.cache)
+  @unpack ρ, p, ϵ, vr, r, max_v,
+          D, Sr, Ï„,
+          init_D, init_Sr, init_Ï„,
+          init_vr, init_p, init_max_v = get_static_variables(mesh.cache)
+  @unpack A, ∂Ar, B, ∂Br = get_static_variables(mesh.cache)
+
+  # need to split initial data into portion that lies inside and outside of star,
+  # because derivatives of the hydro variables are discontinuous at the surface
+  # although metric functions are supposed to be better conditioned there,
+  # we also split them for the interpolation, because of potential contamination
+  # with numerical error from patching
+  rmax = data.riso[end]
+  idx_exterior = findfirst(ri -> ri > rmax, r) |> something
+  @assert idx_exterior > 0
+  interior = 1:idx_exterior-1
+  exterior = idx_exterior:length(mesh)
+
+  rint = view(r, interior)
+  rext = view(r, exterior)
+
+  ρ[interior] .= interpolate(rint, data.riso, data.ρ)
+  ϵ[interior] .= interpolate(rint, data.riso, data.ϵ)
+  p[interior] .= interpolate(rint, data.riso, data.p)
+  A[interior] .= interpolate(rint, data.riso, data.A)
+  B[interior] .= interpolate(rint, data.riso, data.B)
+
+  ρ[exterior] .= equation.atm_density
+  p[exterior] .= @. eos(Pressure, Density, ρ[exterior])
+  ϵ[exterior] .= @. eos(InternalEnergy, Density, ρ[exterior])
+  # metric potentials of Schwarzschild solution in isotropic coordinates:
+  #   ds^2 = -A^2 dt^2 + B^2 γij dx^i dx^j
+  @unpack M = data
+  A[exterior] .= @. (1-M/(2*rext))/(1+M/(2*rext))
+  B[exterior] .= @. (1+M/(2*rext))^2
+
+  # BasicInterpolators.jl cannot differentiate ...  so we diff numerically
+  ∂Ar .= dg1d.differentiate(A, mesh)
+  ∂Br .= dg1d.differentiate(B, mesh)
+
+  @. vr = 0
+  W = 1.0
+  h = @. 1 + ϵ + p/ρ
+  @. D  = W * ρ
+  @. Sr = W^2 * ρ * h * vr
+  @. τ  = W^2 * ρ * h - p - D
+  @. rD  = r*B^3*D
+  @. rSr = r*B^3*Sr
+  @. rτ  = r*B^3*τ
+
+  broadcast_volume!(unscale_conservatives, equation, mesh)
+  impose_symmetry!(P, mesh)
+  broadcast_volume!(cons2prim_rescaled_spherical1d, equation, mesh)
+  broadcast_volume!(flux_source_rescaled_spherical1d, equation, mesh)
+  broadcast_volume!(maxspeed_rescaled_spherical1d, equation, mesh)
+
+  @. init_D     = D
+  @. init_Sr    = Sr
+  @. init_Ï„     = Ï„
+  @. init_vr    = vr
+  @. init_p     = p
+  @. init_max_v = max_v
 
-  # low density atmosphere
-  # rho_atm = query(prms, "density", default=1e-11)
-  rho_atm = prms["id_atmosphere_density"]
-  @assert rho_atm > 0.0
-  @assert eos isa Polytrope "Require model for cold atmosphere"
-
-  @unpack rho, vr, p, eps = get_static_variables(P.cache)
+end
 
-  NN = length(mesh)
-  @. rho = rho_atm * $ones(NN)
-  @. p   = eos(Pressure, Density, rho, InternalEnergy, eps)
-  @. eps = eos(InternalEnergy, Density, rho, Pressure, p)
-  @. vr  = $zeros(NN)
 
-  @assert all(map(X->all(isfinite.(X)), [rho, p, eps, vr])) == true ""
-    "Invalid initial data encountered!"
+function interpolate(x, x_ref, y_ref)
+  intrp = CubicSplineInterpolator(x_ref, y_ref)
+  return intrp.(x)
+end
 
-  broadcast_volume!(prim2cons, equation, P.cache)
-  broadcast_volume!(cons2scaledcons, equation, P.cache)
 
-  return
+function interpolate_derivative(x, x_ref, y_ref)
+  intrp = CubicSplineInterpolator(x_ref, y_ref)
+  return intrp.(x)
 end
 
 
diff --git a/src/GRHD/parameters.jl b/src/GRHD/parameters.jl
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/GRHD/rhs.jl b/src/GRHD/rhs.jl
index ffa15f282461cbe451d8c0f752db674af4bc3356..6f6d85327a6d6b12821f0a1161d3df569f58396c 100644
--- a/src/GRHD/rhs.jl
+++ b/src/GRHD/rhs.jl
@@ -2,49 +2,51 @@
 #                              Timestep                               #
 #######################################################################
 
+function compute_maxspeed(::Project{:spherical1d}, equation, mesh)
+  broadcast_volume!(maxspeed, equation, mesh)
+end
+function compute_maxspeed(::Project{:rescaled_spherical1d}, equation, mesh)
+  broadcast_volume!(maxspeed_rescaled_spherical1d, equation, mesh)
+end
 
-function timestep(env, P::Project, hrsc::Maybe{HRSC.AbstractHRSC})
-  @unpack cache, mesh = env
-  @unpack equation = P
-  @unpack max_v = get_static_variables(cache)
-
-  broadcast_volume!(cons2prim, equation, cache)
-  broadcast_volume!(speed, equation, cache)
-  vmax = dg1d.absolute_maximum(max_v)
-  vmax_limit = 0.9999
+function get_maxspeed(mesh, equation)
+  @unpack max_v = get_static_variables(mesh.cache)
+  vmax = maximum(abs, max_v)
+  vmax_limit = 0.99999999999
   if vmax > vmax_limit
     @warn "Limiting timestep due to maximum speed exceeding $vmax_limit"
     vmax = vmax_limit
   end
+  return vmax
+end
 
-  @unpack dl, x, element = mesh
-  @unpack N = element
-
-  dt = dl / (N^2 * vmax)
+function timestep(mesh, P::Project, hrsc::Maybe{HRSC.AbstractHRSC})
+  compute_maxspeed(P, P.equation, mesh)
+  vmax = get_maxspeed(mesh, P.equation)
+  dl = min_grid_spacing(mesh)
+  dt = dl / (vmax * dtfactor(mesh))
   return dt
 end
+dtfactor(mesh::Mesh1d{FVElement}) = 2
+dtfactor(mesh::Mesh1d{SpectralElement}) = mesh.element.N
 
 
-function timestep(env, P::Project, hrsc::HRSC.AbstractArtificialViscosity)
-  @unpack cache, mesh = env
+function timestep(mesh, P::Project, hrsc::HRSC.AbstractArtificialViscosity)
+  @unpack cache = mesh
   @unpack equation = P
 
-  broadcast_volume!(cons2prim, equation, cache)
-  broadcast_volume!(speed, equation, cache)
-  max_v = get_variable(cache, :max_v)
-  vmax = dg1d.absolute_maximum(view(max_v,:))
-  vmax_limit = 0.9999
-  if vmax > vmax_limit
-    @warn "Limiting timestep due to maximum speed exceeding $vmax_limit"
-    vmax = vmax_limit
-  end
-  smoothed_mu = get_variable(cache, :smoothed_mu)
-  mumax = dg1d.absolute_maximum(view(smoothed_mu, :))
+  compute_maxspeed(P, P.equation, mesh)
+  vmax = get_maxspeed(mesh, P.equation)
+  @unpack mu = get_static_variables
+  mumax = maximum(abs, mu)
 
-  @unpack dl, x, element = mesh
+  @unpack element = mesh
   @unpack N = element
+  L, = dg1d.widths(mesh)
+  K, = mesh.tree.dims
+  dL = L/K
 
-  dt = 1 / (vmax * N / dl + mumax * N^3 / dl^2)
+  dt = 1 / (vmax * N / dL + mumax * N^3 / dL^2)
   dt_limit = 1e-7
   if dt < dt_limit
     @warn "Limiting timestep due to dt being smaller than $dt_limit"
@@ -59,38 +61,140 @@ end
 #######################################################################
 
 
-function rhs!(env, P::Project, hrsc::Nothing, bdryconds, ldg_bdryconds, av_bdryconds)
+function rhs!(mesh::Mesh1d{FVElement}, P::Project{:spherical1d}, hrsc::Nothing)
 
-  @unpack cache, mesh = env
-  @unpack equation, rsolver = P
+  @unpack cache = mesh
+  @unpack equation = P
 
-  @unpack sD, sSr, stau             = get_dynamic_variables(cache)
-  @unpack flx_sD, flx_sSr, flx_stau = get_static_variables(cache)
-  @unpack rhs_sD, rhs_sSr, rhs_stau = get_rhs_variables(cache)
-  @unpack lhs_numflx_sD,   rhs_numflx_sD,
-          lhs_numflx_sSr,  rhs_numflx_sSr,
-          lhs_numflx_stau, rhs_numflx_stau = get_bdry_variables(cache)
+  @unpack D, Sr, Ï„                = get_dynamic_variables(cache)
+  @unpack flr_D, flr_Sr, flr_Ï„,
+          max_v, ρ, ϵ, vr, p,
+          src_D, src_Sr, src_Ï„    = get_static_variables(cache)
+  @unpack rhs_D, rhs_Sr, rhs_Ï„    = get_rhs_variables(cache)
+  @unpack nflr_D, nflr_Sr, nflr_Ï„,
+          bdry_D, bdry_Sr, bdry_Ï„ = get_bdry_variables(cache)
 
-  broadcast_volume!(scaledcons2cons, equation, cache)
-  postprocess_scaledcons2cons!(cache, equation, mesh)
-  broadcast_volume!(cons2prim, equation, cache)
-  broadcast_volume!(flux, equation, cache)
-  broadcast_volume!(sources, equation, cache)
-  broadcast_faces!(lax_friedrich_flux, rsolver, cache, mesh)
-  broadcast_boundaryconditions!(lax_friedrich_flux, bdryconds, cache, mesh, 0.0)
+  broadcast_volume!(cons2prim, equation, mesh)
+  broadcast_volume!(maxspeed, equation, mesh)
+  broadcast_volume!(flux_source_spherical1d, equation, mesh)
+  broadcast_bdry!(fv_bdry_flux, equation, mesh)
 
-  @unpack p, vr, rho, eps = get_static_variables(cache)
+  dt = timestep(mesh, P, hrsc)
+  fv_update_step!(rhs_D,  D,  flr_D,  src_D,  bdry_D,  nflr_D,  dt, mesh)
+  fv_update_step!(rhs_Sr, Sr, flr_Sr, src_Sr, bdry_Sr, nflr_Sr, dt, mesh)
+  fv_update_step!(rhs_Ï„,  Ï„,  flr_Ï„,  src_Ï„,  bdry_Ï„,  nflr_Ï„,  dt, mesh)
+
+  return
+end
+
+
+function rhs!(mesh::Mesh1d, P::Project{:spherical1d}, hrsc::Nothing)
+
+  @unpack cache = mesh
+  @unpack equation = P
+
+  @unpack D, Sr, Ï„                    = get_dynamic_variables(cache)
+  @unpack rhs_D, rhs_Sr, rhs_Ï„        = get_rhs_variables(cache)
+  @unpack flr_D, flr_Sr, flr_Ï„,
+          max_v, vr, p,
+          src_D, src_Sr, src_Ï„        = get_static_variables(cache)
+  @unpack nflr_D, nflr_Sr, nflr_Ï„,
+          bdry_D, bdry_Sr, bdry_Ï„,
+          bdry_max_v, bdry_vr, bdry_p = get_bdry_variables(cache)
+
+  broadcast_volume!(cons2prim, equation, mesh)
+  broadcast_volume!(maxspeed, equation, mesh)
+
+  dg1d.interpolate_face_data!(mesh, D,     bdry_D)
+  dg1d.interpolate_face_data!(mesh, Sr,    bdry_Sr)
+  dg1d.interpolate_face_data!(mesh, Ï„,     bdry_Ï„)
+  dg1d.interpolate_face_data!(mesh, max_v, bdry_max_v)
+  dg1d.interpolate_face_data!(mesh, vr,    bdry_vr)
+  dg1d.interpolate_face_data!(mesh, p,     bdry_p)
+
+  broadcast_volume!(flux_source_spherical1d, equation, mesh)
+  impose_symmetry_sources!(P, mesh)
+  broadcast_faces!(llf, equation, mesh)
+  broadcast_bdry!(bdryllf, equation, mesh)
+
+  compute_rhs_weak_form!(rhs_D,  flr_D,  src_D,  nflr_D,  mesh)
+  compute_rhs_weak_form!(rhs_Sr, flr_Sr, src_Sr, nflr_Sr, mesh)
+  compute_rhs_weak_form!(rhs_Ï„,  flr_Ï„,  src_Ï„,  nflr_Ï„,  mesh)
+
+  return
+end
 
-  compute_rhs_weak_form!(rhs_sD,   flx_sD,    lhs_numflx_sD,   rhs_numflx_sD,   mesh)
-  compute_rhs_weak_form!(rhs_sSr,  flx_sSr,   lhs_numflx_sSr,  rhs_numflx_sSr,  mesh)
-  compute_rhs_weak_form!(rhs_stau, flx_stau,  lhs_numflx_stau, rhs_numflx_stau, mesh)
+
+function rhs!(mesh::Mesh1d{FVElement}, P::Project{:rescaled_spherical1d}, hrsc::Nothing)
+
+  @unpack cache = mesh
+  @unpack equation = P
+
+  @unpack rD, rSr, rτ                = get_dynamic_variables(cache)
+  @unpack flr_rD, flr_rSr, flr_rτ,
+          D, Sr, Ï„,
+          src_rD, src_rSr, src_rτ    = get_static_variables(cache)
+  @unpack rhs_rD, rhs_rSr, rhs_rτ    = get_rhs_variables(cache)
+  @unpack nflr_rD, nflr_rSr, nflr_rτ,
+          bdry_D, bdry_Sr, bdry_Ï„ = get_bdry_variables(cache)
+
+  broadcast_volume!(unscale_conservatives, equation, mesh)
+  impose_symmetry!(P, mesh)
+  broadcast_volume!(cons2prim_rescaled_spherical1d, equation, mesh)
+  broadcast_volume!(maxspeed_rescaled_spherical1d, equation, mesh)
+  broadcast_volume!(flux_source_rescaled_spherical1d, equation, mesh)
+  broadcast_bdry!(fv_bdry_flux_rescaled_spherical1d, equation, mesh)
+
+  dt = timestep(mesh, P, hrsc)
+  fv_update_step!(rhs_rD,  rD,  flr_rD,  src_rD,  bdry_D,  nflr_rD,  dt, mesh)
+  fv_update_step!(rhs_rSr, rSr, flr_rSr, src_rSr, bdry_Sr, nflr_rSr, dt, mesh)
+  fv_update_step!(rhs_rτ,  rτ,  flr_rτ,  src_rτ,  bdry_τ,  nflr_rτ,  dt, mesh)
+
+  return
+end
+
+
+function rhs!(mesh::Mesh1d, P::Project{:rescaled_spherical1d}, hrsc::Nothing)
+
+  @unpack cache = mesh
+  @unpack equation = P
+
+  @unpack rD, rSr, rτ                    = get_dynamic_variables(cache)
+  @unpack rhs_rD, rhs_rSr, rhs_rτ        = get_rhs_variables(cache)
+  @unpack flr_rD, flr_rSr, flr_rτ,
+          max_v, vr, p, D, Sr, Ï„,
+          src_rD, src_rSr, src_rτ        = get_static_variables(cache)
+  @unpack nflr_rD, nflr_rSr, nflr_rτ,
+          bdry_D, bdry_Sr, bdry_Ï„,
+          bdry_max_v, bdry_vr, bdry_p = get_bdry_variables(cache)
+
+  broadcast_volume!(unscale_conservatives, equation, mesh)
+  impose_symmetry!(P, mesh)
+  broadcast_volume!(cons2prim_rescaled_spherical1d, equation, mesh)
+  broadcast_volume!(maxspeed_rescaled_spherical1d, equation, mesh)
+
+  dg1d.interpolate_face_data!(mesh, D,     bdry_D)
+  dg1d.interpolate_face_data!(mesh, Sr,    bdry_Sr)
+  dg1d.interpolate_face_data!(mesh, Ï„,     bdry_Ï„)
+  dg1d.interpolate_face_data!(mesh, max_v, bdry_max_v)
+  dg1d.interpolate_face_data!(mesh, vr,    bdry_vr)
+  dg1d.interpolate_face_data!(mesh, p,     bdry_p)
+
+  broadcast_volume!(flux_source_rescaled_spherical1d, equation, mesh)
+  broadcast_faces!(llf_rescaled_spherical1d, equation, mesh)
+  broadcast_bdry!(bdryllf_rescaled_spherical1d, equation, mesh)
+
+  compute_rhs_weak_form!(rhs_rD,  flr_rD,  src_rD,  nflr_rD,  mesh)
+  compute_rhs_weak_form!(rhs_rSr, flr_rSr, src_rSr, nflr_rSr, mesh)
+  compute_rhs_weak_form!(rhs_rτ,  flr_rτ,  src_rτ,  nflr_rτ,  mesh)
 
   return
 end
 
 
-function rhs!(env, P::Project, hrsc::HRSC.AbstractReconstruction,
-    bdryconds, ldg_bdryconds, av_bdryconds)
+function rhs!(env, P::Project, hrsc::HRSC.AbstractReconstruction)
+
+  TODO()
 
   @unpack cache, mesh = env
   @unpack equation, rsolver = P
@@ -122,8 +226,9 @@ function rhs!(env, P::Project, hrsc::HRSC.AbstractReconstruction,
 end
 
 
-function rhs!(env, P::Project, hrsc::HRSC.AbstractArtificialViscosity,
-    bdryconds, ldg_bdryconds, av_bdryconds)
+function rhs!(env, P::Project, hrsc::HRSC.AbstractArtificialViscosity)
+
+  TODO()
 
   @unpack cache, mesh = env
   @unpack equation, rsolver, ldg_rsolver, av_rsolver = P
diff --git a/src/GRHD/setup.jl b/src/GRHD/setup.jl
index 92c0a10fc93ab933fa583aeb1d99ed22154c237f..f46e1199927a630f5ea4de3de7c43aa47875b00f 100644
--- a/src/GRHD/setup.jl
+++ b/src/GRHD/setup.jl
@@ -2,87 +2,28 @@ function Project(env::Environment, prms)
 
   # construct Project
   eos = EquationOfState.make_EquationOfState(prms["EquationOfState"])
-  equation = Equation(eos, prms["GRHD"])
+  equation = make_Equation(eos, prms["GRHD"], env.mesh)
   tci  = TCI.make_TCI(env.mesh, prms["TCI"])
   hrsc = HRSC.make_HRSC(env.mesh, prms["HRSC"])
-  rsolver = ApproxRiemannSolver(flux, speed, equation)
-  ldg_rsolver, av_rsolver = if hrsc isa AbstractArtificialViscosity
-    ApproxRiemannSolver(ldg_flux, ldg_speed, equation),
-    ApproxRiemannSolver(av_flux, av_flux, equation)
-  else
-    nothing, nothing
-  end
 
-  P = Project(equation, hrsc, tci, rsolver, ldg_rsolver, av_rsolver)
+  fixedprms = (;)
+  formulation = prms["GRHD"]["formulation"]
+  P = Project(Symbol(formulation), equation, hrsc, tci, fixedprms)
 
   # register variables
-  # TODO add a ::Nothing overload for register_variables!
-  # TODO Somehow replace _register_variables! with register_variables!
   @unpack cache = env
-  _register_variables!(cache, P)
-  register_variables!(cache, rsolver)
-  !isnothing(ldg_rsolver) && register_variables!(cache, ldg_rsolver)
-  !isnothing(av_rsolver) && register_variables!(cache, av_rsolver, dont_register=true)
+  register!(cache, P)
   display(cache)
 
   # setup initial data
   initialdata!(env, P, prms["GRHD"])
 
-  # TODO Bdry conditions should be moved to project and should only be just a 'lightweight'
-  # descriptor. Furthermore, they should also register variables in cache themselves.
-  # Note: Atm, only the 'from_initial_data' option would require a place to store the data
-  # somewhere. For periodic BCs we don't need extra storage at all.
-  # But what other types of boundary conditions will be needed in the future?
-
-  # setup boundary conditions
-  bdryconds = make_BoundaryConditions(env, equation, rsolver, prms)
-  ldg_bdryconds, av_bdryconds = if hrsc isa AbstractArtificialViscosity
-    make_BoundaryConditions_LDG(env, equation, ldg_rsolver, prms),
-    make_BoundaryConditions_LDG(env, equation, av_rsolver, prms)
-  else
-    nothing, nothing
-  end
-
   # setup callbacks
-  projectcb = make_callback(env, P, bdryconds)
-
-  # artificially smooth initial data
-  # TODO Move this into make_callback
-  smoother_called = false
-  function id_smoother_fn(u, t)
-    if !smoother_called
-      println("Smoothing initial data...")
-      @unpack sD, sSr, stau = get_dynamic_variables(cache)
-      @unpack flag          = get_cell_variables(cache)
-      id_hrsc = HRSC.BernsteinReconstruction(env.mesh)
-      HRSC.reconstruct!(sD,    flag, id_hrsc, isperiodic=isperiodic(bdryconds))
-      HRSC.reconstruct!(sSr,   flag, id_hrsc, isperiodic=isperiodic(bdryconds))
-      HRSC.reconstruct!(stau,  flag, id_hrsc, isperiodic=isperiodic(bdryconds))
-      smoother_called = true
-      broadcast_volume!(cons2prim, equation, cache)
-    end
-  end
-  id_smoother_cb = FunctionCallback(id_smoother_fn,
-                                    CallbackTiming(every_iteration=1))
-
-  append!(env.callbacks, CallbackSet(projectcb.callbacks..., id_smoother_cb))
-
-  return P, (bdryconds, ldg_bdryconds, av_bdryconds)
-end
+  projectcb = make_callback(env, P, isperiodic(env.mesh))
 
+  append!(env.callbacks, CallbackSet(projectcb.callbacks...))
 
-function Equation(eos, prms)
-  @unpack atm_factor, atm_threshold_factor = prms
-  if atm_factor < 0
-    error("GRHD: atm_factor must be positive, found 'atm_factor = $atm_factor'")
-  end
-  if atm_threshold_factor < 0
-    error("GRHD: atm_threshold_factor must be positive, found 'atm_threshold_factor = $atm_threshold_factor'")
-  end
-  cons2prim_newtonsolver = dg1d.NewtonSolver(approx_derivative=true)
-  cons2prim_bisection = dg1d.Bisection()
-  return Equation(eos, -1.0, atm_factor, atm_threshold_factor,
-                  cons2prim_newtonsolver, cons2prim_bisection)
+  return P, nothing
 end
 
 
@@ -91,64 +32,113 @@ end
 #######################################################################
 
 
-# Julia limitation/bug: Overloading imported functions without their Module prefix shadows their
-# definition in this module without a warning or error. This does not happen for methods
-# defined in Base.
-# Because of that we prefix with _ below.
-# Cf. https://github.com/JuliaLang/julia/issues/15510
-function _register_variables!(cache, P::Project)
+function register!(cache, P::Project)
+  register_evolution!(cache, P)
+  register_metricvars!(cache, P)
+  register_hrsc!(cache, P, P.hrsc)
+  register_tci!(cache, P, P.tci)
+end
+
+
+function register_evolution!(cache, P::Project{:spherical1d})
+  register_variables!(cache,
+    dynamic_variablenames = (:D, :Sr, :Ï„,),
+    rhs_variablenames     = (:rhs_D, :rhs_Sr, :rhs_Ï„), # rhs of conservatives
+    static_variablenames  = (:flr_D, :flr_Sr, :flr_Ï„,  # conservatives' fluxes
+                             :src_D, :src_Sr, :src_Ï„,  # sources
+                             :ρ, :vr, :p, :ϵ,          # primitives
+                             :max_v, :r,               # maximum charactersitic speed, radius
+                             :init_D, :init_Sr, :init_Ï„, :init_max_v, :init_vr, :init_p),
+    bdry_variablenames    = (:bdry_D, :bdry_Sr, :bdry_Ï„,
+                             :bdry_ρ, :bdry_ϵ, :bdry_vr, :bdry_p,
+                             :bdry_max_v,
+                             :nflr_D, :nflr_Sr, :nflr_Ï„),
+    cell_variablenames    = (:cellmax_v,),
+    global_variablenames  = (:t, :tm1) # time steps
+  )
+  @unpack r, x = get_static_variables(cache)
+  r .= x
+end
+function register_evolution!(cache, P::Project{:rescaled_spherical1d})
   register_variables!(cache,
-    dynamic_variablenames = (:sD, :sSr, :stau,),            # 'scaled' conservatives
-    rhs_variablenames     = (:rhs_sD, :rhs_sSr, :rhs_stau), # rhs of conservatives
-    static_variablenames  = (:flx_sD, :flx_sSr, :flx_stau,  # conservatives' fluxes
-                             :src_sD, :src_sSr, :src_stau,  # sources
-                             :D, :Sr, :tau,                 # true hydrodynamic conservatives
-                             :rho, :vr, :p, :eps,        # primitives
-                             :max_v, :r,                 # maximum charactersitic speed, grid
-                             :E, :Em1,                   # entropy
-                             :flx_E, :flx_Em1,           # entropy flux
-                             :A, :B, :A_r, :B_r),        # metric fields and derivatives
+    dynamic_variablenames = (:rD, :rSr, :rτ,),            # we evolve rescaled variables
+    rhs_variablenames     = (:rhs_rD, :rhs_rSr, :rhs_rτ), # rhs of conservatives
+    static_variablenames  = (:flr_rD, :flr_rSr, :flr_rτ,  # conservatives' fluxes
+                             :src_rD, :src_rSr, :src_rτ,  # sources
+                             :D, :Sr, :Ï„,                 # conserved variables
+                             :ρ, :vr, :p, :ϵ,             # primitives
+                             :max_v, :r,                  # maximum charactersitic speed, radius
+                             :init_D, :init_Sr, :init_Ï„, :init_max_v, :init_vr, :init_p),
+    bdry_variablenames    = (:bdry_D, :bdry_Sr, :bdry_Ï„,
+                             :bdry_ρ, :bdry_ϵ, :bdry_vr, :bdry_p,
+                             :bdry_max_v,
+                             :nflr_rD, :nflr_rSr, :nflr_rτ),
     cell_variablenames    = (:cellmax_v,),
     global_variablenames  = (:t, :tm1) # time steps
   )
-  _register_variables!(cache, P.hrsc)
-  _register_variables!(cache, P.tci)
-  # @unpack r = get_static_variables(cache)
+  @unpack r, x = get_static_variables(cache)
+  r .= x
 end
 
 
-function _register_variables!(P, tci_or_hrsc::Nothing) end
+function register_metricvars!(cache, P::Project{:spherical1d})
+  register_variables!(cache,
+    static_variablenames = (:α, :βru,
+                            :γrr, :γθθ, :γϕϕ,
+                            :Krr, :Kθθ, :Kϕϕ,
+                            :Γrrr, :Γrθθ, :Γrϕϕ, :Γθrθ, :Γθϕϕ, :Γϕrϕ, :Γϕθϕ,
+                            :∂αr, :∂βrrdu,
+                            :∂γrrr, :∂γrθθ, :∂γrϕϕ, :∂γθϕϕ,)
+  )
+end
+function register_metricvars!(cache, P::Project{:rescaled_spherical1d})
+  register_variables!(cache,
+    static_variablenames = (:A, :∂Ar, :B, :∂Br)
+  )
+end
 
 
-_register_variables!(P, hrsc::AbstractHRSC) = 
-  error("_register_variables: Not implemented for hrsc of type '$(typeof(hrsc))'")
+# TODO Where to put these? Can be needed by either HRSC or TCI.
+# :E, :Em1,                   # entropy
+# :flx_E, :flx_Em1,           # entropy flux
 
-_register_variables!(P, hrsc::HRSC.AbstractReconstruction) = nothing
 
+#######################################################################
+#                                HRSC                                 #
+#######################################################################
 
-function _register_variables!(cache, hrsc::HRSC.AbstractArtificialViscosity)
+
+register_hrsc!(cache, P, hrsc::Nothing) = nothing
+register_hrsc!(cache, P, hrsc::AbstractHRSC) = TODO(hrsc)
+function register_hrsc!(cache, P, hrsc::HRSC.AbstractArtificialViscosity)
+  TODO(hrsc)
   register_variables!(cache,
     static_variablenames  = (:ldg_sD, :ldg_sSr, :ldg_stau,              # local DG variable
                              :flx_ldg_sD, :flx_ldg_sSr, :flx_ldg_stau), # local DG flux
     cell_variablenames    = (:mu,), # 'one viscosity to rule them all'
     )
 end
-
-
-function _register_variables!(cache, hrsc::HRSC.SmoothedArtificialViscosity)
-  _register_variables!(cache, hrsc.av)
+function register_hrsc!(cache, P, hrsc::HRSC.SmoothedArtificialViscosity)
+  TODO(hrsc)
+  register_hrsc!(cache, P, hrsc.av)
   register_variables!(cache,
     static_variablenames  = (:smoothed_mu,)
   )
 end
 
 
-function _register_variables!(cache, tci::TCI.AbstractTCI)
-  register_variables!(cache, cell_variablenames = (:flag,:sD_flag,:sSr_flag,:stau_flag))
-end
+#######################################################################
+#                                 TCI                                 #
+#######################################################################
 
 
-function _register_variables!(cache, tci::TCI.EntropyProduction)
+register_tci!(cache, P, tci::Maybe{HRSC.AbstractReconstruction}) = nothing
+function register_tci!(cache, P, tci::TCI.AbstractTCI)
+  TODO(tci)
+  register_variables!(cache, cell_variablenames = (:flag,:sD_flag,:sSr_flag,:stau_flag))
+end
+function register_tci!(cache, P, tci::TCI.EntropyProduction)
+  TODO(tci)
   register_variables!(cache,
                       cell_variablenames = (:flag,),
                       static_variablenames = (:EP,), # entropy production
diff --git a/src/GRHD/types.jl b/src/GRHD/types.jl
index 06831cc382a930e0bcb298c7614c0211883c6d02..d22aeed25be7c0b7a4755aca36fe5c571da1adae 100644
--- a/src/GRHD/types.jl
+++ b/src/GRHD/types.jl
@@ -3,21 +3,20 @@ mutable struct Equation{T_EoS<:AbstractEquationOfState} <: AbstractEquation
   atm_density::Float64
   atm_factor::Float64
   atm_threshold::Float64
-  cons2prim_newtonsolver::dg1d.NewtonSolver
-  cons2prim_bisection::dg1d.Bisection
 end
 
 
-struct Project{T_HRSC         <:Maybe{HRSC.AbstractHRSC},
-               T_TCI          <:Maybe{TCI.AbstractTCI},
-               T_RSolver      <:AbstractRiemannSolver,
-               T_LDG_RSolver  <:Maybe{AbstractRiemannSolver},
-               T_AV_RSolver   <:Maybe{AbstractRiemannSolver}} <: dg1d.AbstractProject
-
-  equation::Equation
+struct Project{Formulation,
+               T_Eq    <:AbstractEquation,
+               T_HRSC  <:Maybe{HRSC.AbstractHRSC},
+               T_TCI   <:Maybe{TCI.AbstractTCI},
+               T_Prms}
+  equation::T_Eq
   hrsc::T_HRSC
   tci::T_TCI
-  rsolver::T_RSolver
-  ldg_rsolver::T_LDG_RSolver
-  av_rsolver::T_AV_RSolver
+  prms::T_Prms
 end
+Project(formulation, fields...) = Project{formulation,typeof.(fields)...}(fields...)
+
+
+formulation(::Project{F}) where F = F
diff --git a/src/SRHD/SRHD.jl b/src/SRHD/SRHD.jl
index bb48cc903c25f5a6c052b5c573daa6d55538fa71..4e60be28d17f0f3ba5d55a61bc76a7a29080db9c 100644
--- a/src/SRHD/SRHD.jl
+++ b/src/SRHD/SRHD.jl
@@ -1,3 +1,4 @@
+export SRHD
 module SRHD
 
 
diff --git a/src/dg1d.jl b/src/dg1d.jl
index e237e3374eeccbaf004d35777e2c51f65c05feb0..fe3ecd54a630cc042a38f0c91645a32ea44c24af 100644
--- a/src/dg1d.jl
+++ b/src/dg1d.jl
@@ -151,7 +151,7 @@ include("ScalarEq/ScalarEq.jl")
 include("HeatEq/HeatEq.jl")
 include("EulerEq/EulerEq.jl")
 include("SRHD/SRHD.jl")
-# include("GRHD/GRHD.jl")
+include("GRHD/GRHD.jl")
 
 
 end # module
diff --git a/src/fv_rhs.jl b/src/fv_rhs.jl
index 3c30ffca60ccb848cacc2c0f5d02a6cf4a0f373d..f0c7f5141e0b658ee202ad598d234ee3c917d0eb 100644
--- a/src/fv_rhs.jl
+++ b/src/fv_rhs.jl
@@ -27,20 +27,7 @@ function fv_update_step!(up1, u, f, bdry_u, bdry_f, dt, mesh::Mesh1d{FVElement})
 end
 
 
-function fv_update_step!(up1, u, f, s, bdry_u, bdry_f, bdry_s, dt, mesh::Mesh1d{FVElement})
-  TODO()
-  @unpack invjac = mesh
-  @unpack K = mesh
-  dl = widths(mesh)[1] / K
-  dtdl = dt/dl
-  @turbo for j = 2:K-1
-    up1[j] = (u[j+1] + 2*u[j] + u[j-1])/4 - dtdl/2 * (f[j+1] - f[j-1]) + s[j]
-  end
-  if mesh.tree.periodic[1]
-    up1[1]   = (u[2] + 2*u[1]   + u[end])/4   - dtdl/2 * (f[2] - f[end]) + s[1]
-    up1[end] = (u[1] + 2*u[end] + u[end-1])/4 - dtdl/2 * (f[1] - f[end-1]) + s[end]
-  else
-    TODO()
-  end
-  return
+function fv_update_step!(up1, u, f, s, bdry_u, bdry_f, dt, mesh::Mesh1d{FVElement})
+  fv_update_step!(up1, u, f, bdry_u, bdry_f, dt, mesh)
+  up1 .+= s
 end
diff --git a/src/mesh.jl b/src/mesh.jl
index 3420cedc22b8311076e7b1fb51153e37ec0c0324..7c57d21f6c1e7f70779570ced81fcfbb53534a52 100644
--- a/src/mesh.jl
+++ b/src/mesh.jl
@@ -404,6 +404,41 @@ norm_L2(u, mesh::Mesh) = sqrt(broken_inner_product(u, u, mesh))
 norm_L1(u, mesh::Mesh) = broken_inner_product(abs.(u), ones(Float64, size(u)), mesh)
 
 
+function differentiate!(du, u, mesh::Mesh1d)
+  @unpack invdetJ = get_static_variables(mesh.cache)
+  for (duk,uk,invdetJk) in zip(eachcell(mesh,du),eachcell(mesh,u),eachcell(mesh,invdetJ))
+    differentiate!(duk, uk, mesh.element)
+    duk .*= invdetJk
+  end
+end
+function differentiate!(du, u, mesh::Mesh1d{FVElement})
+  @unpack x, invdetJ = get_static_variables(mesh.cache)
+  K, = mesh.tree.dims
+  for k in 2:K-1
+    du[k] = (u[k+1]-u[k-1])/(x[k+1]-x[k-1])
+  end
+  x1, x2, x3 = x[1], x[2], x[3]
+  M = [ 1 x1 x1^2;
+        1 x2 x2^2;
+        1 x3 x3^2 ]
+  uu = u[1:3]
+  b = M \ uu
+  du[1] = b[2] + 2*b[3]*x1
+  x1, x2, x3 = x[end], x[end-1], x[end-2]
+  M = [ 1 x1 x1^2;
+        1 x2 x2^2;
+        1 x3 x3^2 ]
+  uu = u[end:-1:end-2]
+  b = M \ uu
+  du[end] = b[2] + 2*b[3]*x1
+end
+function differentiate(u, mesh)
+  du = similar(u)
+  differentiate!(du, u, mesh)
+  return du
+end
+
+
 """
     find_nearest(xi, mesh::Mesh)
 
@@ -571,7 +606,7 @@ end
 
 struct CellDataIterator{M<:AbstractMesh,A<:AbstractArray}
   mesh::M
-  data::A
+  data::A # TODO Replace with NTuple{N,A} to allow iterating multiple arrays at once
   function CellDataIterator(m::AbstractMesh, a::AbstractArray)
     @toggled_assert length(m) == length(a)
     return new{typeof(m),typeof(a)}(m,a)
diff --git a/src/sandbox.jl b/src/sandbox.jl
index 403fd0a18eb24cf8bf0d2682e45ea737de88a99f..c748c9b70d161d0d341cefd4a2a429a35ee1bfb6 100644
--- a/src/sandbox.jl
+++ b/src/sandbox.jl
@@ -6,6 +6,8 @@ const BLACKLISTED_TOKENS = [ "function", "using", "import", "struct", "mutable",
                              "if", "else", "elseif", "try", "catch", "Main", "module",
                              "dg1d", "println", "print", "display", "show" ]
 
+const ROOTDIR = joinpath(@__DIR__, "..")
+
 
 # rudimentary protection against arbitrary code execution
 function has_blacklisted_tokens(str)
diff --git a/src/spectralelement.jl b/src/spectralelement.jl
index 66170c38fa008eecbcec1c125dc7c7f8f0652e5e..ded604c114482d2c9008ad30622c274a4b51d238 100644
--- a/src/spectralelement.jl
+++ b/src/spectralelement.jl
@@ -93,3 +93,12 @@ end
     return GLGL.integrate(el.w, el.v, el.D, u)
   end
 end
+
+
+@inline function differentiate(u, el::SpectralElement)
+  return el.D * u
+end
+
+@inline function differentiate!(du, u, el::SpectralElement)
+  mul!(du, el.D, u)
+end
diff --git a/test/IntegrationTests/refs/grhd_bondi_accretion/grhd_bondi_accretion.toml b/test/IntegrationTests/refs/grhd_bondi_accretion/grhd_bondi_accretion.toml
new file mode 100644
index 0000000000000000000000000000000000000000..1a2307c96587e30c88859822c8679baa76c4db57
--- /dev/null
+++ b/test/IntegrationTests/refs/grhd_bondi_accretion/grhd_bondi_accretion.toml
@@ -0,0 +1,25 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 0.02143872868864732
+polytrope_gamma = "$(4/3)"
+
+[GRHD]
+bc = "from_id"
+id = "bondi_accretion"
+id_filename = "$(joinpath(ROOTDIR,\"initialdata\",\"bondi_accretion.h5\"))"
+
+[Mesh]
+range = [ 1.8, 10.0 ]
+n = 4
+k = 35
+basis = "lgl"
+periodic = false
+
+[Output]
+variables  = [ "D", "Sr", "τ", "p", "ρ", "ϵ", "vr" ]
+aligned_ts = "$(collect(range(0.5,5.0,step=0.5)))"
+enable1d   = true
+
+[Evolution]
+cfl = 0.8
+tend = 5.0
diff --git a/test/IntegrationTests/refs/grhd_bondi_accretion/output.h5 b/test/IntegrationTests/refs/grhd_bondi_accretion/output.h5
new file mode 100644
index 0000000000000000000000000000000000000000..9e2ba67bd0addbc97f8b1d709e6986c23bd3eb6f
Binary files /dev/null and b/test/IntegrationTests/refs/grhd_bondi_accretion/output.h5 differ
diff --git a/test/IntegrationTests/refs/grhd_tov_spherical1d/grhd_tov_spherical1d.toml b/test/IntegrationTests/refs/grhd_tov_spherical1d/grhd_tov_spherical1d.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7f8831e034a5c00bfe73e8d7d189f5e1b0db35d7
--- /dev/null
+++ b/test/IntegrationTests/refs/grhd_tov_spherical1d/grhd_tov_spherical1d.toml
@@ -0,0 +1,27 @@
+[EquationOfState]
+eos = "polytrope"
+polytrope_k = 100.0
+polytrope_gamma = 2.0
+
+[GRHD]
+bc = "from_id"
+id = "tov"
+id_filename = "$(joinpath(ROOTDIR,\"initialdata\",\"TOV_stable.h5\"))"
+atm_factor = 1e-8
+formulation = "spherical1d"
+
+[Mesh]
+range = [ 0.0, 20.0 ]
+n = 4
+k = 124
+basis = "lgl"
+periodic = false
+
+[Output]
+variables = [ "D", "Sr", "Ï„" ]
+aligned_ts = "$(collect(range(2.5,10.0,step=2.5)))"
+enable1d  = true
+
+[Evolution]
+cfl = 0.4
+tend = 10.0
diff --git a/test/IntegrationTests/refs/grhd_tov_spherical1d/output.h5 b/test/IntegrationTests/refs/grhd_tov_spherical1d/output.h5
new file mode 100644
index 0000000000000000000000000000000000000000..4353a721e47d3775bca4ff8ab9f466a689e37a1a
Binary files /dev/null and b/test/IntegrationTests/refs/grhd_tov_spherical1d/output.h5 differ
diff --git a/test/IntegrationTests/refs/testconfig.toml b/test/IntegrationTests/refs/testconfig.toml
index 68dda7e2c57a4d9106bfc7e3238eb2cc084cccf2..e3f1893e1adbe2c2b87bfdedff865bf6c204a1e2 100644
--- a/test/IntegrationTests/refs/testconfig.toml
+++ b/test/IntegrationTests/refs/testconfig.toml
@@ -76,6 +76,14 @@ reltol = 1e-6
 variables = [ "D", "S", "tau" ]
 reltol = 1e-6
 
+[grhd_bondi_accretion]
+# runs into discontinuity
+variables  = [ "D", "Sr", "τ", "p", "ρ", "ϵ", "vr" ]
+
+[grhd_tov_spherical1d]
+# test does not use any hrsc method, so we can encounter garbage
+# but we are happy when it runs
+variables  = []
 
 # 2D tests