From eeaf318be2041eb93183bba325c103df2476f0d8 Mon Sep 17 00:00:00 2001
From: Florian Atteneder <florian.atteneder@uni-jena.de>
Date: Fri, 6 Sep 2024 20:45:22 +0000
Subject: [PATCH] dg1d: Add limiters.jl
 (https://git.tpi.uni-jena.de/dg/dg1d.jl/-/merge_requests/221)

- Collect most of the limiter implementations into `limiters.jl` (there still remain bits in `ScalarEq`)
- Add new limiter `limit_slope_preserve_continuity!` that is tailored towards the Bspline approximation (although its not working well)
- Add new limiter `limit_slope_convex_hull!` that is tailored towards the Bspline approximation
- Add new reftests `burgers_sine_bspline1_limit_slope_convex_hull` and ``burgers_sine_bspline2_limit_slope_convex_hull`
- Fix Bspline integration
---
 src/EulerEq/rhs.jl                            |  24 +-
 src/GRHD/rhs.jl                               |  28 +--
 src/HRSC/mda.jl                               |   2 +-
 src/SRHD/rhs.jl                               |  24 +-
 src/ScalarEq/callbacks.jl                     |   3 +-
 src/ScalarEq/rhs.jl                           |  39 +--
 src/ScalarEq/setup.jl                         |   3 +-
 src/TCI/minmod.jl                             |   4 +-
 src/TCI/modaldecayaverage.jl                  |   2 +-
 src/bspline.jl                                |   8 +-
 src/dg1d.jl                                   |   2 +
 src/limiters.jl                               | 222 ++++++++++++++++++
 src/mesh.jl                                   |  56 -----
 ...sine_bspline1_limit_slope_convex_hull.toml |  23 ++
 .../output1d.h5                               | Bin 0 -> 33032 bytes
 ...sine_bspline2_limit_slope_convex_hull.toml |  23 ++
 .../output1d.h5                               | Bin 0 -> 33928 bytes
 test/IntegrationTests/refs/testconfig.toml    |   5 +
 18 files changed, 302 insertions(+), 166 deletions(-)
 create mode 100644 src/limiters.jl
 create mode 100644 test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/burgers_sine_bspline1_limit_slope_convex_hull.toml
 create mode 100644 test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/output1d.h5
 create mode 100644 test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/burgers_sine_bspline2_limit_slope_convex_hull.toml
 create mode 100644 test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/output1d.h5

diff --git a/src/EulerEq/rhs.jl b/src/EulerEq/rhs.jl
index 2d788945..f8891df8 100644
--- a/src/EulerEq/rhs.jl
+++ b/src/EulerEq/rhs.jl
@@ -203,7 +203,7 @@ function step_fv_muscl!(P::Project, mesh::Mesh1d{FVElement}, state)
 
     # limit slope and compute left (L) and (R) interface values
     for k in 1:K
-      dvL = limit_slope(dv₊[k], dv₋[k], dl, prms_slope_limiter)
+      dvL = dg1d.limit_slope(dv₊[k], dv₋[k], dl, prms_slope_limiter)
       vL[k] = v[k] - dvL/2
       vR[k] = v[k] + dvL/2
     end
@@ -317,28 +317,6 @@ function step_fv_muscl!(P::Project, mesh::Mesh1d{FVElement}, state)
 end
 
 
-@inline function limit_slope(a, b, dx, prms)
-  if prms.method === :none
-    return 0.0
-  elseif prms.method === :minmod
-    return TCI.minmod(a, b)
-  elseif prms.method === :muscl
-    return TCI.minmod((a+b)/2, 2*a, 2*b)
-  elseif prms.method === :superbee
-    return TCI.minmod(TCI.maxmod(a,b),TCI.minmod(2*a,2*b))
-  elseif prms.method === :van_albada
-    c = dx^3
-    return TCI.minmod( ((a^2+c^2)*b+(b^2+c^2)*a)/(a^2+b^2+c^2), 2*a, 2*b )
-  elseif prms.method === :van_leer
-    return TCI.minmod(2*a*b/(a+b), 2*a, 2*b)
-  elseif prms.method === :tvb
-    return TCI.minmod_M(dx, prms.tvb_M, (a+b)/2, 2*a, 2*b)
-  else
-    TODO(prms.method)
-  end
-end
-
-
 #######################################################################
 #                               DG rhs                                #
 #######################################################################
diff --git a/src/GRHD/rhs.jl b/src/GRHD/rhs.jl
index 09187952..6a1b8636 100644
--- a/src/GRHD/rhs.jl
+++ b/src/GRHD/rhs.jl
@@ -452,7 +452,7 @@ function step_fv_slope_limiter!(mesh, P::Project{:spherical1d}, state)
       k₋, k₊ = k-1, k+1
       w₋, w₀, w₊ = w[k₋], w[k], w[k₊]
       dw₊[k], dw₋[k] = w₊-w₀, w₀-w₋
-      dwL = limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
+      dwL = dg1d.limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
       wL[k] = w[k] - dwL/2
       wR[k] = w[k] + dwL/2
     end
@@ -725,7 +725,7 @@ function step_fv_slope_limiter!(mesh, P::Project{:doublecartoon}, state)
       k₋, k₊ = k-1, k+1
       w₋, w₀, w₊ = w[k₋], w[k], w[k₊]
       dw₊[k], dw₋[k] = w₊-w₀, w₀-w₋
-      dwL = limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
+      dwL = dg1d.limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
       wL[k] = w[k] - dwL/2
       wR[k] = w[k] + dwL/2
     end
@@ -1129,30 +1129,6 @@ end
 end
 
 
-@inline function limit_slope(a, b, dx, prms)
-  if prms.method === :none
-    return 0.0
-  elseif prms.method === :minmod
-    return TCI.minmod(a, b)
-  elseif prms.method === :muscl
-    return TCI.minmod((a+b)/2, 2*a, 2*b)
-  elseif prms.method === :superbee
-    return TCI.minmod(TCI.maxmod(a,b),TCI.minmod(2*a,2*b))
-  elseif prms.method === :van_albada
-    c = dx^3
-    return TCI.minmod( ((a^2+c^2)*b+(b^2+c^2)*a)/(a^2+b^2+c^2), 2*a, 2*b )
-  elseif prms.method === :van_leer
-    return TCI.minmod(2*a*b/(a+b), 2*a, 2*b)
-  elseif prms.method === :tvb
-    return TCI.minmod_M(dx, prms.tvb_M, (a+b)/2, 2*a, 2*b)
-  elseif prms.method === :mc
-    return dg1d.MC(b, a)
-  else
-    TODO(prms.method)
-  end
-end
-
-
 #######################################################################
 #                               DG RHS                                #
 #######################################################################
diff --git a/src/HRSC/mda.jl b/src/HRSC/mda.jl
index a85e51f2..18779814 100644
--- a/src/HRSC/mda.jl
+++ b/src/HRSC/mda.jl
@@ -88,7 +88,7 @@ function compute_viscosity!(
     @. data_y = log(skylined_mod_uh)
     @. data_y = max(data_y, -20.0)
     _, _, tau = dg1d.least_sqr_linear(data_x, data_y)
-    isnan(tau) && error("undesired nan encountered")
+    !isfinite(tau) && error("undesired nan encountered")
 
     mu[j] *= v[j]
     if tau > n_high
diff --git a/src/SRHD/rhs.jl b/src/SRHD/rhs.jl
index 271cf2ff..58ac2239 100644
--- a/src/SRHD/rhs.jl
+++ b/src/SRHD/rhs.jl
@@ -221,7 +221,7 @@ function step_fv_muscl!(P::Project, mesh::Mesh1d{FVElement}, state)
 
     # limit slope and compute left (L) and (R) interface values
     for k in 1:K
-      dwL = limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
+      dwL = dg1d.limit_slope(dw₊[k], dw₋[k], dl, prms_slope_limiter)
       wL[k] = w[k] - dwL/2
       wR[k] = w[k] + dwL/2
     end
@@ -334,28 +334,6 @@ function step_fv_muscl!(P::Project, mesh::Mesh1d{FVElement}, state)
 end
 
 
-@inline function limit_slope(a, b, dx, prms)
-  if prms.method === :none
-    return 0.0
-  elseif prms.method === :minmod
-    return TCI.minmod(a, b)
-  elseif prms.method === :muscl
-    return TCI.minmod((a+b)/2, 2*a, 2*b)
-  elseif prms.method === :superbee
-    return TCI.minmod(TCI.maxmod(a,b),TCI.minmod(2*a,2*b))
-  elseif prms.method === :van_albada
-    c = dx^3
-    return TCI.minmod( ((a^2+c^2)*b+(b^2+c^2)*a)/(a^2+b^2+c^2), 2*a, 2*b )
-  elseif prms.method === :van_leer
-    return TCI.minmod(2*a*b/(a+b), 2*a, 2*b)
-  elseif prms.method === :tvb
-    return TCI.minmod_M(dx, prms.tvb_M, (a+b)/2, 2*a, 2*b)
-  else
-    TODO(prms.method)
-  end
-end
-
-
 #######################################################################
 #                               DG rhs                                #
 #######################################################################
diff --git a/src/ScalarEq/callbacks.jl b/src/ScalarEq/callbacks.jl
index 49af0837..48a1f43d 100644
--- a/src/ScalarEq/callbacks.jl
+++ b/src/ScalarEq/callbacks.jl
@@ -246,7 +246,6 @@ end
 #######################################################################
 
 
-# TODO
 callback_analyze(state_u, state_t, env, P, mesh::Mesh) = nothing
 
 
@@ -255,6 +254,8 @@ function callback_analyze(state_u, state_t, env, P, mesh::Mesh1d)
   @unpack u_norm2 = get_global_variables(mesh)
   u_norm2 .= dg1d.norm_L2(u, mesh)^2
 end
+# TODO Make this use dg1d.limit_slope!
+# after moving src/ScalarEq/rhs.jl:limit_slope! to src/limters.jl
 function callback_analyze(state_u, state_t, env, P, mesh::Mesh1d{<:FVElement})
   @unpack u = get_dynamic_variables(mesh)
   @unpack u_norm2 = get_global_variables(mesh)
diff --git a/src/ScalarEq/rhs.jl b/src/ScalarEq/rhs.jl
index 9cd9b0e5..e1f3cc61 100644
--- a/src/ScalarEq/rhs.jl
+++ b/src/ScalarEq/rhs.jl
@@ -132,6 +132,7 @@ function rhs_fv_muscl!(env, mesh::Mesh1d{FVElement}, P::Project)
 end
 
 
+# TODO Move this to src/limiters.jl
 function limit_slope!(P::Project, mesh::Mesh1d{FVElement}, u)
   @unpack equation = P
   @unpack uL, uR,
@@ -158,7 +159,7 @@ function limit_slope!(P::Project, mesh::Mesh1d{FVElement}, u)
 
   # limit slope and compute left (L) and (R) interface values
   for k in 1:K
-    duL = limit_slope(du₊[k], du₋[k], dl, prms_slope_limiter)
+    duL = dg1d.limit_slope(du₊[k], du₋[k], dl, prms_slope_limiter)
     uL[k] = u[k] - duL/2
     uR[k] = u[k] + duL/2
   end
@@ -240,28 +241,6 @@ function step_fv_muscl!(P::Project, mesh::Mesh1d{FVElement}, u)
 end
 
 
-@inline function limit_slope(a, b, dx, prms)
-  if prms.method === :none
-    return 0.0
-  elseif prms.method === :minmod
-    return TCI.minmod(a, b)
-  elseif prms.method === :muscl
-    return TCI.minmod((a+b)/2, 2*a, 2*b)
-  elseif prms.method === :superbee
-    return TCI.minmod(TCI.maxmod(a,b),TCI.minmod(2*a,2*b))
-  elseif prms.method === :van_albada
-    c = dx^3
-    return TCI.minmod( ((a^2+c^2)*b+(b^2+c^2)*a)/(a^2+b^2+c^2), 2*a, 2*b )
-  elseif prms.method === :van_leer
-    return TCI.minmod(2*a*b/(a+b), 2*a, 2*b)
-  elseif prms.method === :tvb
-    return TCI.minmod_M(dx, prms.tvb_M, (a+b)/2, 2*a, 2*b)
-  else
-    TODO(prms.method)
-  end
-end
-
-
 #######################################################################
 #                               DG RHS                                #
 #######################################################################
@@ -269,14 +248,14 @@ end
 
 function rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
   if mesh.element.kind ∈ (:modal_bspline2, :modal_bspline1)
-    modal_rhs!(env, mesh, P, hrsc)
+    modal_rhs!(env, mesh, P)
   else
-    nodal_rhs!(env, mesh, P, hrsc)
+    nodal_rhs!(env, mesh, P)
   end
 end
 
 
-function nodal_rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
+function nodal_rhs!(env, mesh::Mesh1d, P::Project)
   @unpack flx_u, src_u   = get_static_variables(mesh)
   @unpack u              = get_dynamic_variables(mesh)
   @unpack rhs_u          = get_rhs_variables(mesh)
@@ -291,7 +270,7 @@ function nodal_rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
 end
 
 
-function modal_rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
+function modal_rhs!(env, mesh::Mesh1d, P::Project)
   @unpack flx_u, src_u,
           u_modal, flx_u_modal,
           src_u_modal    = get_static_variables(mesh)
@@ -299,6 +278,11 @@ function modal_rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
   @unpack rhs_u          = get_rhs_variables(mesh)
   @unpack nflx_u, bdry_u = get_bdry_variables(mesh)
 
+  if P.prms.hrsc === :slope_limiter
+    @unpack flag = get_cell_variables(mesh)
+    dg1d.limit_slope_convex_hull!(u, flag, P.prms.workspace, mesh)
+  end
+
   u_modal .= u
   for (v_u, v_u_modal) in zip(eachcell(mesh,u),eachcell(mesh,u_modal))
     mul!(v_u, P.prms.V_bspline, v_u_modal)
@@ -315,6 +299,7 @@ function modal_rhs!(env, mesh::Mesh1d, P::Project, hrsc::Nothing)
     mul!(v_src_u_modal, P.prms.invV_bspline, v_src_u)
   end
   compute_rhs_weak_form!(rhs_u, flx_u_modal, src_u_modal, nflx_u, mesh)
+
   u .= u_modal
 
   return
diff --git a/src/ScalarEq/setup.jl b/src/ScalarEq/setup.jl
index 727b4242..0d1f7926 100644
--- a/src/ScalarEq/setup.jl
+++ b/src/ScalarEq/setup.jl
@@ -24,10 +24,11 @@ function Project(env::Environment, mesh::Mesh1d, prms)
   else
     V_bspline, invV_bspline = nothing, nothing
   end
+  workspace = dg1d.Workspace()
   fixedprms = (; bernstein, av_derivative_scheme, av_drag, hrsc, muscl_omega,
                  slope_limiter_method, slope_limiter_tvb_M,
                  av_recompute_substeps,
-                 V_bernstein, V_bspline, invV_bspline,
+                 V_bernstein, V_bspline, invV_bspline, workspace,
                  analyze_error, analyze_error_norm)
 
   # construct Project
diff --git a/src/TCI/minmod.jl b/src/TCI/minmod.jl
index c87c0a01..2efdea49 100644
--- a/src/TCI/minmod.jl
+++ b/src/TCI/minmod.jl
@@ -11,8 +11,6 @@ function compute_indicator!(
     tci::Minmod)
 
   @unpack mesh       = tci
-  @unpack invdetJ    = get_static_variables(mesh.cache)
-
   Npts, K = layout(mesh)
   L,      = dg1d.widths(mesh)
   dL      = L/K
@@ -23,7 +21,7 @@ function compute_indicator!(
 
   @unpack threshold = tci
   # fill flag by applying minmod criterion
-  for k in 1:K # loop over cells
+  for k in 1:K
     # assuming periodic grid
     k_lhs, k_rhs = periodic_index(k-1, K), periodic_index(k+1, K)
     uavg, uavg_lhs, uavg_rhs = u_averages[k], u_averages[k_lhs], u_averages[k_rhs]
diff --git a/src/TCI/modaldecayaverage.jl b/src/TCI/modaldecayaverage.jl
index 12b20c65..e8bacc4e 100644
--- a/src/TCI/modaldecayaverage.jl
+++ b/src/TCI/modaldecayaverage.jl
@@ -81,7 +81,7 @@ function compute_indicator!(
     @views for m in 1:N
       uh_skylined = maximum(uh_mod[min(m,N-1):end])
       log_uh = log(uh_skylined)
-      lsq_y[m] = isinf(log_uh) ? - 20.0 : log_uh
+      lsq_y[m] = !isfinite(log_uh) ? - 20.0 : log_uh
     end
 
     # estimate effective decay rate by least square fit of modal coefficients, (3.9)
diff --git a/src/bspline.jl b/src/bspline.jl
index 3919fd54..fe51f567 100644
--- a/src/bspline.jl
+++ b/src/bspline.jl
@@ -352,7 +352,7 @@ end
 function integrate(f::AbstractVector, bs::Bspline1)
   @toggled_assert length(f) == bs.Npts
   sum = 0.0
-  @inbounds for i in bs.Npts
+  @inbounds for i in 1:bs.Npts
     fi, xl, xr = f[i], bs.xs[i], bs.xs[i+2]
     sum += fi * (xr-xl)/2
   end
@@ -361,7 +361,7 @@ end
 function integrate(f::Function, idxs::AbstractVector{<:Integer}, bs::Bspline1)
   @toggled_assert length(idxs) == bs.Npts
   sum = 0.0
-  @inbounds for i in bs.Npts
+  @inbounds for i in 1:bs.Npts
     fi, xl, xr = f(idxs[i]), bs.xs[i], bs.xs[i+2]
     sum += fi * (xr-xl)/2
   end
@@ -374,7 +374,7 @@ end
 function integrate(f::AbstractVector, bs::Bspline2)
   @toggled_assert length(f) == bs.Npts+1
   sum = 0.0
-  @inbounds for i in bs.Npts+1
+  @inbounds for i in 1:bs.Npts+1
     fi, xl, xr = f[i], bs.xs[i], bs.xs[i+3]
     sum += fi * (xr-xl)/3
   end
@@ -383,7 +383,7 @@ end
 function integrate(f::Function, idxs::AbstractVector{<:Integer}, bs::Bspline2)
   @toggled_assert length(idxs) == bs.Npts+1
   sum = 0.0
-  @inbounds for i in bs.Npts+1
+  @inbounds for i in 1:bs.Npts+1
     fi, xl, xr = f(idxs[i]), bs.xs[i], bs.xs[i+3]
     sum += fi * (xr-xl)/3
   end
diff --git a/src/dg1d.jl b/src/dg1d.jl
index 48be5deb..d52d1f48 100644
--- a/src/dg1d.jl
+++ b/src/dg1d.jl
@@ -88,6 +88,8 @@ export Mesh, Mesh1d, Mesh2d, MeshInterpolator, layout, n_points, n_cells, dimens
        min_grid_spacing
 include("mesh.jl")
 
+include("limiters.jl")
+
 export AbstractEquation
 include("equations.jl")
 
diff --git a/src/limiters.jl b/src/limiters.jl
new file mode 100644
index 00000000..c6c388ec
--- /dev/null
+++ b/src/limiters.jl
@@ -0,0 +1,222 @@
+@inline function limit_slope(a, b, dx, prms)
+  if prms.method === :none
+    return 0.0
+  elseif prms.method === :minmod
+    return TCI.minmod(a, b)
+  elseif prms.method === :muscl
+    return TCI.minmod((a+b)/2, 2*a, 2*b)
+  elseif prms.method === :superbee
+    return TCI.minmod(TCI.maxmod(a,b),TCI.minmod(2*a,2*b))
+  elseif prms.method === :van_albada
+    c = dx^3
+    return TCI.minmod( ((a^2+c^2)*b+(b^2+c^2)*a)/(a^2+b^2+c^2), 2*a, 2*b )
+  elseif prms.method === :van_leer
+    return TCI.minmod(2*a*b/(a+b), 2*a, 2*b)
+  elseif prms.method === :tvb
+    return TCI.minmod_M(dx, prms.tvb_M, (a+b)/2, 2*a, 2*b)
+  elseif prms.method === :mc
+    return dg1d.MC(b, a)
+  else
+    TODO(prms.method)
+  end
+end
+
+
+#######################################################################
+#                  slope limiters for FVElement mesh                  #
+#######################################################################
+
+
+# TODO Merge this with ScalarEq/rhs.jl:limit_slope!
+function limit_slope!(δu, u, mesh::Mesh1d{<:FVElement}, @nospecialize(prms::NamedTuple))
+  @unpack hrsc = prms
+  if hrsc === :muscl
+    limit_slope_muscl!(δu, u, mesh, prms)
+  elseif hrsc === :fv_central
+    # TODO Not sure if correct. The discussion in Hesthaven book 2018, sec 10.3 does not
+    # specify how to compute the slope. The only requirement seems to be that
+    # the slope obeys δu_j/h = du/dx(x_j) + O(h). And in the codes they provide they
+    # seem to reuse the same slope limiters as for the MUSCL scheme etc.
+    prms = (hrsc = :muscl, muscl_omega=0)
+    limit_slope_muscl!(δu, u, mesh, prms)
+  else
+    TODO(hrsc)
+  end
+end
+
+
+function limit_slope_muscl!(δu, u, mesh::Mesh1d{<:FVElement}, prms::NamedTuple)
+  # assume that FV solution in jth cell [x_(j-1/2),x_(j+1/2)] can be approximated by
+  #   u_j ≈ ̄u_j + δu_j (x-x_j)/h
+  # where δu_j is the slope at x_j and
+  #   x_j = x_j-1/2 + h/2
+  #   h   = x_j+1/2 - x_j-1/2
+  # Compare discussion in Hesthaven book 2018, sec 10.2
+  @unpack muscl_omega = prms
+  ω = muscl_omega
+  # TODO Enabling upwinding in fv_muscl_burgers_sine (ω = 1.0) gives asymmetric results.
+  # Do we need to compute two slopes like in the slope limiter implementations in EulerEq etc?
+  K, = mesh.tree.dims
+  @turbo for k = 2:K-1
+    k₋, k₊ = k-1, k+1
+    u₋, u₀, u₊ = u[k₋], u[k], u[k₊]
+    Δ⁻u = u₀-u₋
+    Δ⁺u = u₊-u₀
+    # (10.12) in Hesthaven book 2018, sec 10.2
+    δu[k] = (1+ω)/2*Δ⁻u + (1-ω)/2*Δ⁺u
+  end
+  if isperiodic(mesh)
+    for k in (1,K)
+      k₋, k₊ = periodic_index(k-1,K), periodic_index(k+1,K)
+      u₋, u₀, u₊ = u[k₋], u[k], u[k₊]
+      Δ⁻u = u₀-u₋
+      Δ⁺u = u₊-u₀
+      δu[k] = (1+ω)/2*Δ⁻u + (1-ω)/2*Δ⁺u
+    end
+  else
+    TODO("bdry conditions")
+  end
+end
+
+
+#######################################################################
+#            slope limiter that preserves C^0 constraints             #
+#######################################################################
+
+
+function limit_slope_preserve_continuity!(var::AbstractArray, mask::AbstractArray, ws::Workspace, mesh::Mesh1d{<:DGElement})
+  @toggled_assert mesh.element.kind === :modal_bspline1
+  enter(ws) do
+
+    @unpack x = get_static_variables(mesh)
+    Npts = mesh.element.Npts
+    K = mesh.tree.dims[1]
+    tmp_var  = borrow(ws, Npts*K)
+    avgs     = borrow(ws, Npts+1)
+    δs       = borrow(ws, Npts+1)
+    lim_avgs = borrow(ws, Npts-1)
+    lim_δs   = borrow(ws, Npts-1)
+    mat_A    = borrow(ws, (Npts-1)*(Npts-1))
+    b        = borrow(ws, Npts-1)
+    A        = reshape(mat_A,(Npts-1,Npts-1))
+
+    for k in 1:K
+      if k == 1 || k == K || mask[k] ≈ 0.0
+        # skip bdry cells, but backup data because we restore the whole vector at once later
+        idxs = cellindices(mesh, k)
+        view(tmp_var, idxs) .= view(var, idxs)
+        continue
+      end
+
+      idxs_lhs, idxs, idxs_rhs = cellindices.(Ref(mesh), (k-1,k,k+1))
+      vvar_lhs, vvar, vvar_rhs = view.(Ref(var), (idxs_lhs,idxs,idxs_rhs))
+      vx_lhs,   vx,   vx_rhs   = view.(Ref(x),   (idxs_lhs,idxs,idxs_rhs))
+      vtmp_var                 = view(tmp_var, idxs)
+
+      # determine averages and slopes, including neighbors
+      v1, v2 = vvar_lhs[end-1], vvar_lhs[end]
+      x1, x2 = vx_lhs[end-1], vx_lhs[end]
+      avgs[1] = (v1+v2)/2; δs[1] = (v2-v1)/(x2-x1)
+      v1, v2 = vvar_rhs[1], vvar_rhs[2]
+      x1, x2 = vx_rhs[1], vx_rhs[2]
+      avgs[end] = (v1+v2)/2; δs[end] = (v2-v1)/(x2-x1)
+      for i in 1:Npts-1
+        v1, v2 = vvar[i], vvar[i+1]
+        x1, x2 = vx[i], vx[i+1]
+        avgs[1+i] = (v1+v2)/2; δs[1+i] = (v2-v1)/(x2-x1)
+      end
+
+      # limit slopes
+      for i in 2:Npts
+        # lim_δs[i-1] = TCI.minmod(δs[i-1],δs[i],δs[i+1])
+        x1, x2 = vx[i-1], vx[i]
+        dx = x2-x1
+        M = 0.1
+        δl, δc, δr = δs[i-1], δs[i], δs[i+1]
+        lim_δs[i-1] = TCI.minmod_M(dx, M, δc, δl, δr)
+      end
+
+      # recompute avgs so that continuity and total avg is preserved
+      fill!(A, 0.0) # because we use lu! below
+      for i in 1:Npts-2
+        x1, x2, x3 = vx[i], vx[i+1], vx[i+2]
+        dx1, dx2 = x2-x1, x3-x2
+        A[i,i]   = 1.0
+        A[i,i+1] = -1.0
+        b[i] = - 0.5*dx1*lim_δs[i] - 0.5*dx2*lim_δs[i+1]
+      end
+      A[end,:] .= 1.0
+      v_avgs = view(avgs, 2:Npts)
+      b[end] = sum(v_avgs)
+
+      # solve the equations
+      F = lu!(A)
+      ldiv!(lim_avgs, F, b)
+
+      # resample data
+      x1, x2 = vx[1], vx[2]
+      dx = x2-x1
+      vtmp_var[1] = lim_avgs[1] - 0.5*dx*lim_δs[1]
+      x1, x2 = vx[end-1], vx[end]
+      dx = x2-x1
+      vtmp_var[end] = lim_avgs[end] + 0.5*dx*lim_δs[end]
+      for i in 2:Npts-1
+        x1, x2 = vx[i], vx[i+1]
+        dx = x2-x1
+        vtmp_var[i] = lim_avgs[i] - 0.5*dx*lim_δs[i]
+      end
+    end
+
+    copyto!(var, tmp_var)
+  end
+end
+
+
+function limit_slope_convex_hull!(var::AbstractArray, mask::AbstractArray,
+                                   ws::Workspace, mesh::Mesh1d{<:DGElement})
+  enter(ws) do
+
+    @unpack x = get_static_variables(mesh)
+    Npts = mesh.element.Npts
+    K = mesh.tree.dims[1]
+    tmp_var = borrow(ws, Npts*K)
+    dvar = borrow(ws, Npts-1)
+    w = 0.5
+
+    for k in 1:K
+
+      idxs = cellindices(mesh, k)
+      vvar     = view(var, idxs)
+      vx       = view(x, idxs)
+      vtmp_var = view(tmp_var, idxs)
+
+      if k == 1 || k == K || mask[k] ≈ 0.0
+        # skip bdry cells, but backup data because we restore the whole vector at once later
+        vtmp_var .= vvar
+        continue
+      end
+
+      for i in 1:Npts-1
+        dvar[i] = vvar[i+1]-vvar[i]
+      end
+      if abs(sum(sign, dvar)) ≈ Float64(Npts-1)
+        vtmp_var .= vvar
+        continue
+      end
+
+      idxs_lhs, idxs_rhs = cellindices.(Ref(mesh), (k-1,k+1))
+      vvar_lhs, vvar_rhs = view.(Ref(var), (idxs_lhs,idxs_rhs))
+
+      vtmp_var[1] = vvar[1] + (vvar_lhs[end]-vvar[1])*w
+      vtmp_var[end] = vvar[end] + (vvar_rhs[1]-vvar[end])*w
+      for i in 2:Npts-1
+        ul, uc, ur = vvar[i-1], vvar[i], vvar[i+1]
+        xl, xc, xr = vx[i-1], vx[i], vx[i+1]
+        um = ul + (ur-ul)/(xr-xl)*(xc-xl)
+        vtmp_var[i] = uc + (um-uc)*w
+      end
+    end
+
+    copyto!(var, tmp_var)
+  end
+end
diff --git a/src/mesh.jl b/src/mesh.jl
index d400bfd9..9ef12398 100644
--- a/src/mesh.jl
+++ b/src/mesh.jl
@@ -920,59 +920,3 @@ function interpolate_face_data!(mesh::Mesh2d, var::AbstractVector, bdrybuf::Abst
     bo += Nptsx
   end
 end
-
-
-#######################################################################
-#                  slope limiters for FVElement mesh                  #
-#######################################################################
-
-
-function limit_slope!(δu, u, mesh::Mesh1d{<:FVElement}, @nospecialize(prms::NamedTuple))
-  @unpack hrsc = prms
-  if hrsc === :muscl
-    limit_slope_muscl!(δu, u, mesh, prms)
-  elseif hrsc === :fv_central
-    # TODO Not sure if correct. The discussion in Hesthaven book 2018, sec 10.3 does not
-    # specify how to compute the slope. The only requirement seems to be that
-    # the slope obeys δu_j/h = du/dx(x_j) + O(h). And in the codes they provide they
-    # seem to reuse the same slope limiters as for the MUSCL scheme etc.
-    prms = (hrsc = :muscl, muscl_omega=0)
-    limit_slope_muscl!(δu, u, mesh, prms)
-  else
-    TODO(hrsc)
-  end
-end
-
-
-function limit_slope_muscl!(δu, u, mesh::Mesh1d{<:FVElement}, prms::NamedTuple)
-  # assume that FV solution in jth cell [x_(j-1/2),x_(j+1/2)] can be approximated by
-  #   u_j ≈ ̄u_j + δu_j (x-x_j)/h
-  # where δu_j is the slope at x_j and
-  #   x_j = x_j-1/2 + h/2
-  #   h   = x_j+1/2 - x_j-1/2
-  # Compare discussion in Hesthaven book 2018, sec 10.2
-  @unpack muscl_omega = prms
-  ω = muscl_omega
-  # TODO Enabling upwinding in fv_muscl_burgers_sine (ω = 1.0) gives asymmetric results.
-  # Do we need to compute two slopes like in the slope limiter implementations in EulerEq etc?
-  K, = mesh.tree.dims
-  @turbo for k = 2:K-1
-    k₋, k₊ = k-1, k+1
-    u₋, u₀, u₊ = u[k₋], u[k], u[k₊]
-    Δ⁻u = u₀-u₋
-    Δ⁺u = u₊-u₀
-    # (10.12) in Hesthaven book 2018, sec 10.2
-    δu[k] = (1+ω)/2*Δ⁻u + (1-ω)/2*Δ⁺u
-  end
-  if isperiodic(mesh)
-    for k in (1,K)
-      k₋, k₊ = periodic_index(k-1,K), periodic_index(k+1,K)
-      u₋, u₀, u₊ = u[k₋], u[k], u[k₊]
-      Δ⁻u = u₀-u₋
-      Δ⁺u = u₊-u₀
-      δu[k] = (1+ω)/2*Δ⁻u + (1-ω)/2*Δ⁺u
-    end
-  else
-    TODO("bdry conditions")
-  end
-end
diff --git a/test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/burgers_sine_bspline1_limit_slope_convex_hull.toml b/test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/burgers_sine_bspline1_limit_slope_convex_hull.toml
new file mode 100644
index 00000000..fc3b95a3
--- /dev/null
+++ b/test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/burgers_sine_bspline1_limit_slope_convex_hull.toml
@@ -0,0 +1,23 @@
+[Evolution]
+cfl = 0.8
+tend = 0.24
+
+[ScalarEq]
+equation = "burgers"
+id = "sine"
+hrsc = "slope_limiter"
+
+[TCI]
+variables = ["u"]
+method = "mda"
+
+[Output]
+aligned_ts = "$(collect(range(0.02,0.24,step=0.02)))"
+variables1d = ["u"]
+
+[Mesh]
+dg_kind = "modal_bspline1"
+range = [0, 1]
+k = 13
+basis = "lgl"
+n = 7
diff --git a/test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/output1d.h5 b/test/IntegrationTests/refs/burgers_sine_bspline1_limit_slope_convex_hull/output1d.h5
new file mode 100644
index 0000000000000000000000000000000000000000..79ea9422160d52f88919d291a01f34d97a283563
GIT binary patch
literal 33032
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
Uz<i1e^tmgD6CAKu5I69D06;hx-T(jq

literal 0
HcmV?d00001

diff --git a/test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/burgers_sine_bspline2_limit_slope_convex_hull.toml b/test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/burgers_sine_bspline2_limit_slope_convex_hull.toml
new file mode 100644
index 00000000..2849e536
--- /dev/null
+++ b/test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/burgers_sine_bspline2_limit_slope_convex_hull.toml
@@ -0,0 +1,23 @@
+[Evolution]
+cfl = 0.8
+tend = 0.24
+
+[ScalarEq]
+equation = "burgers"
+id = "sine"
+hrsc = "slope_limiter"
+
+[TCI]
+variables = ["u"]
+method = "mda"
+
+[Output]
+aligned_ts = "$(collect(range(0.02,0.24,step=0.02)))"
+variables1d = ["u"]
+
+[Mesh]
+dg_kind = "modal_bspline2"
+range = [0, 1]
+k = 14
+basis = "lgl"
+n = 7
diff --git a/test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/output1d.h5 b/test/IntegrationTests/refs/burgers_sine_bspline2_limit_slope_convex_hull/output1d.h5
new file mode 100644
index 0000000000000000000000000000000000000000..5e6c34bba2e750a0ed685d6e25bcb2ab679188c1
GIT binary patch
literal 33928
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

literal 0
HcmV?d00001

diff --git a/test/IntegrationTests/refs/testconfig.toml b/test/IntegrationTests/refs/testconfig.toml
index fd03eac8..e9e6bbd4 100644
--- a/test/IntegrationTests/refs/testconfig.toml
+++ b/test/IntegrationTests/refs/testconfig.toml
@@ -61,6 +61,11 @@ variables1d = [ "u" ]
 # this test now runs into the discontinuity
 [burgers_sine_avmda]
 variables1d = [ "u" ]
+# bspline tests
+[burgers_sine_bspline1_limit_slope_convex_hull]
+variables1d = [ "u" ]
+[burgers_sine_bspline2_limit_slope_convex_hull]
+variables1d = [ "u" ]
 
 [balancedburgers_kink_avmda]
 variables1d = [ "u" ]
-- 
GitLab