ProCreations's picture
Publish validated GP-FVM reproduction
c711202 verified
Raw
History Blame Contribute Delete
11.2 kB
"""
Functional definitions and sparse precision building for nonlinear SWE.
Key structures:
- Primary state (h, hu, hv): evals, cell integrals, face integrals, face midpoint evals
- Auxiliary flux (P, K_x, K_y, C): face integrals, face midpoint evals
"""
using GPFiniteVolume
using FunctionalGPs
using GaussianMarkovRandomFields
using SparseArrays, LinearAlgebra
import FunctionalGPs: ⊗
"""
GridInfo
Holds grid dimensions and derived quantities.
"""
struct GridInfo
N_x::Int
N_y::Int
N_grid::Int
n_cells_x::Int
n_cells_y::Int
N_cells::Int
n_vert_faces::Int
n_horiz_faces::Int
Δx::Float64
Δy::Float64
end
function GridInfo(xs, ys)
N_x, N_y = length(xs), length(ys)
Δx = xs[2] - xs[1]
Δy = ys[2] - ys[1]
GridInfo(
N_x, N_y,
N_x * N_y,
N_x - 1, N_y - 1,
(N_x - 1) * (N_y - 1),
N_x * (N_y - 1), # vertical faces
(N_x - 1) * N_y, # horizontal faces
Δx, Δy
)
end
"""
build_functionals(xs, ys, x_intervals, y_intervals)
Build all functionals needed for the nonlinear SWE.
Returns named tuple with:
- L_eval: point evaluations at grid corners
- L_int: cell integrals
- L_vert: vertical face integrals
- L_horiz: horizontal face integrals
- L_vert_face_eval: evaluations at vertical face midpoints
- L_horiz_face_eval: evaluations at horizontal face midpoints
- vert_face_midpoints: grid for vertical face midpoints
- horiz_face_midpoints: grid for horizontal face midpoints
"""
function build_functionals(xs, ys, x_intervals, y_intervals)
# Convert to vectors for consistent types
xs_vec = collect(Float64, xs)
ys_vec = collect(Float64, ys)
grid = FactorizedGrid(xs_vec, ys_vec)
cells_2d = x_intervals ⊗ y_intervals
n_cells_y = length(y_intervals)
n_cells_x = length(x_intervals)
# Face midpoints
y_cell_mids = [0.5*(ys[j] + ys[j+1]) for j in 1:n_cells_y]
x_cell_mids = [0.5*(xs[i] + xs[i+1]) for i in 1:n_cells_x]
vert_face_midpoints = FactorizedGrid(xs_vec, y_cell_mids)
horiz_face_midpoints = FactorizedGrid(x_cell_mids, ys_vec)
return (
grid = grid,
cells_2d = cells_2d,
xs = xs_vec,
ys = ys_vec,
L_eval = EvaluationFunctional(grid),
L_int = VectorizedLebesgueIntegral(cells_2d),
L_vert = EvaluationFunctional(xs_vec) ⊗ VectorizedLebesgueIntegral(y_intervals),
L_horiz = VectorizedLebesgueIntegral(x_intervals) ⊗ EvaluationFunctional(ys_vec),
L_vert_face_eval = EvaluationFunctional(vert_face_midpoints),
L_horiz_face_eval = EvaluationFunctional(horiz_face_midpoints),
vert_face_midpoints = vert_face_midpoints,
horiz_face_midpoints = horiz_face_midpoints,
)
end
"""
build_primary_precision(funcs, kernel, ρ; name=:h)
Build sparse precision for a primary variable (h, hu, or hv).
Returns SparseGMRFApproximation with functionals:
- eval, int, vert, horiz, vert_face, horiz_face
"""
function build_primary_precision(funcs, kernel, ρ; name=:h)
sparse_precision([
Symbol(name) => funcs.L_eval,
Symbol(name, :_int) => funcs.L_int,
Symbol(name, :_vert) => funcs.L_vert,
Symbol(name, :_horiz) => funcs.L_horiz,
Symbol(name, :_vert_face) => funcs.L_vert_face_eval,
Symbol(name, :_horiz_face) => funcs.L_horiz_face_eval,
], kernel; ρ=ρ, ordering=:integrals_coarsest)
end
"""
build_flux_precision(funcs, kernel, ρ; name=:P)
Build sparse precision for an auxiliary flux variable (P, Kx, Ky, or C).
Returns SparseGMRFApproximation with functionals:
- vert, horiz (face integrals for FVM)
- vert_face, horiz_face (face midpoint evals for nonlinear constraints)
"""
function build_flux_precision(funcs, kernel, ρ; name=:P)
sparse_precision([
Symbol(name, :_vert) => funcs.L_vert,
Symbol(name, :_horiz) => funcs.L_horiz,
Symbol(name, :_vert_face) => funcs.L_vert_face_eval,
Symbol(name, :_horiz_face) => funcs.L_horiz_face_eval,
], kernel; ρ=ρ, ordering=:integrals_coarsest)
end
"""
PrecisionInfo
Holds all sparse precision approximations and the joint precision.
"""
struct PrecisionInfo
approx_h::Any
approx_hu::Any
approx_hv::Any
approx_P::Any
approx_Kx::Any
approx_Ky::Any
approx_C::Any
Q_space::SparseMatrixCSC{Float64, Int64}
N_space::Int
end
"""
build_all_precisions(funcs, k_primary, k_flux, ρ; verbose=false)
Build all sparse precisions and combine into block-diagonal joint precision.
"""
function build_all_precisions(funcs, k_primary, k_flux, ρ; verbose=false)
verbose && println("Building sparse precisions (ρ = )...")
approx_h = build_primary_precision(funcs, k_primary, ρ; name=:h)
verbose && println(" h: ", approx_h)
approx_hu = build_primary_precision(funcs, k_primary, ρ; name=:hu)
verbose && println(" hu: ", approx_hu)
approx_hv = build_primary_precision(funcs, k_primary, ρ; name=:hv)
verbose && println(" hv: ", approx_hv)
approx_P = build_flux_precision(funcs, k_flux, ρ; name=:P)
verbose && println(" P: ", approx_P)
approx_Kx = build_flux_precision(funcs, k_flux, ρ; name=:Kx)
verbose && println(" Kx: ", approx_Kx)
approx_Ky = build_flux_precision(funcs, k_flux, ρ; name=:Ky)
verbose && println(" Ky: ", approx_Ky)
approx_C = build_flux_precision(funcs, k_flux, ρ; name=:C)
verbose && println(" C: ", approx_C)
Q_space = blockdiag(
sparse(approx_h.Q),
sparse(approx_hu.Q),
sparse(approx_hv.Q),
sparse(approx_P.Q),
sparse(approx_Kx.Q),
sparse(approx_Ky.Q),
sparse(approx_C.Q)
)
return PrecisionInfo(
approx_h, approx_hu, approx_hv,
approx_P, approx_Kx, approx_Ky, approx_C,
Q_space, size(Q_space, 1)
)
end
"""
build_spatial_layout(ginfo::GridInfo)
Build the layout for the spatial state (single timestep, no time derivatives).
"""
function build_spatial_layout(ginfo::GridInfo)
layout((
# Primary h
h = ginfo.N_grid,
h_int = ginfo.N_cells,
h_vert = ginfo.n_vert_faces,
h_horiz = ginfo.n_horiz_faces,
h_vert_face = ginfo.n_vert_faces,
h_horiz_face = ginfo.n_horiz_faces,
# Primary hu
hu = ginfo.N_grid,
hu_int = ginfo.N_cells,
hu_vert = ginfo.n_vert_faces,
hu_horiz = ginfo.n_horiz_faces,
hu_vert_face = ginfo.n_vert_faces,
hu_horiz_face = ginfo.n_horiz_faces,
# Primary hv
hv = ginfo.N_grid,
hv_int = ginfo.N_cells,
hv_vert = ginfo.n_vert_faces,
hv_horiz = ginfo.n_horiz_faces,
hv_vert_face = ginfo.n_vert_faces,
hv_horiz_face = ginfo.n_horiz_faces,
# Auxiliary P
P_vert = ginfo.n_vert_faces,
P_horiz = ginfo.n_horiz_faces,
P_vert_face = ginfo.n_vert_faces,
P_horiz_face = ginfo.n_horiz_faces,
# Auxiliary Kx
Kx_vert = ginfo.n_vert_faces,
Kx_horiz = ginfo.n_horiz_faces,
Kx_vert_face = ginfo.n_vert_faces,
Kx_horiz_face = ginfo.n_horiz_faces,
# Auxiliary Ky
Ky_vert = ginfo.n_vert_faces,
Ky_horiz = ginfo.n_horiz_faces,
Ky_vert_face = ginfo.n_vert_faces,
Ky_horiz_face = ginfo.n_horiz_faces,
# Auxiliary C
C_vert = ginfo.n_vert_faces,
C_horiz = ginfo.n_horiz_faces,
C_vert_face = ginfo.n_vert_faces,
C_horiz_face = ginfo.n_horiz_faces,
))
end
"""
build_full_state_layout(ginfo::GridInfo)
Build the layout for the full IWP state: [spatial; d/dt spatial].
The IWP prior needs time derivatives for ALL spatial components to model
temporal evolution. This doubles the state size.
"""
function build_full_state_layout(ginfo::GridInfo)
# Full IWP state: [spatial_state; d/dt spatial_state]
layout((
# ===== SPATIAL STATE =====
# Primary h
h = ginfo.N_grid,
h_int = ginfo.N_cells,
h_vert = ginfo.n_vert_faces,
h_horiz = ginfo.n_horiz_faces,
h_vert_face = ginfo.n_vert_faces,
h_horiz_face = ginfo.n_horiz_faces,
# Primary hu
hu = ginfo.N_grid,
hu_int = ginfo.N_cells,
hu_vert = ginfo.n_vert_faces,
hu_horiz = ginfo.n_horiz_faces,
hu_vert_face = ginfo.n_vert_faces,
hu_horiz_face = ginfo.n_horiz_faces,
# Primary hv
hv = ginfo.N_grid,
hv_int = ginfo.N_cells,
hv_vert = ginfo.n_vert_faces,
hv_horiz = ginfo.n_horiz_faces,
hv_vert_face = ginfo.n_vert_faces,
hv_horiz_face = ginfo.n_horiz_faces,
# Auxiliary P
P_vert = ginfo.n_vert_faces,
P_horiz = ginfo.n_horiz_faces,
P_vert_face = ginfo.n_vert_faces,
P_horiz_face = ginfo.n_horiz_faces,
# Auxiliary Kx
Kx_vert = ginfo.n_vert_faces,
Kx_horiz = ginfo.n_horiz_faces,
Kx_vert_face = ginfo.n_vert_faces,
Kx_horiz_face = ginfo.n_horiz_faces,
# Auxiliary Ky
Ky_vert = ginfo.n_vert_faces,
Ky_horiz = ginfo.n_horiz_faces,
Ky_vert_face = ginfo.n_vert_faces,
Ky_horiz_face = ginfo.n_horiz_faces,
# Auxiliary C
C_vert = ginfo.n_vert_faces,
C_horiz = ginfo.n_horiz_faces,
C_vert_face = ginfo.n_vert_faces,
C_horiz_face = ginfo.n_horiz_faces,
# ===== TIME DERIVATIVES OF SPATIAL STATE =====
# d/dt Primary h
dh_dt = ginfo.N_grid,
dh_int_dt = ginfo.N_cells,
dh_vert_dt = ginfo.n_vert_faces,
dh_horiz_dt = ginfo.n_horiz_faces,
dh_vert_face_dt = ginfo.n_vert_faces,
dh_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Primary hu
dhu_dt = ginfo.N_grid,
dhu_int_dt = ginfo.N_cells,
dhu_vert_dt = ginfo.n_vert_faces,
dhu_horiz_dt = ginfo.n_horiz_faces,
dhu_vert_face_dt = ginfo.n_vert_faces,
dhu_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Primary hv
dhv_dt = ginfo.N_grid,
dhv_int_dt = ginfo.N_cells,
dhv_vert_dt = ginfo.n_vert_faces,
dhv_horiz_dt = ginfo.n_horiz_faces,
dhv_vert_face_dt = ginfo.n_vert_faces,
dhv_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Auxiliary P
dP_vert_dt = ginfo.n_vert_faces,
dP_horiz_dt = ginfo.n_horiz_faces,
dP_vert_face_dt = ginfo.n_vert_faces,
dP_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Auxiliary Kx
dKx_vert_dt = ginfo.n_vert_faces,
dKx_horiz_dt = ginfo.n_horiz_faces,
dKx_vert_face_dt = ginfo.n_vert_faces,
dKx_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Auxiliary Ky
dKy_vert_dt = ginfo.n_vert_faces,
dKy_horiz_dt = ginfo.n_horiz_faces,
dKy_vert_face_dt = ginfo.n_vert_faces,
dKy_horiz_face_dt = ginfo.n_horiz_faces,
# d/dt Auxiliary C
dC_vert_dt = ginfo.n_vert_faces,
dC_horiz_dt = ginfo.n_horiz_faces,
dC_vert_face_dt = ginfo.n_vert_faces,
dC_horiz_face_dt = ginfo.n_horiz_faces,
))
end