The following the model is described in the paper:
@article{Escalante_2024,
title={Vertically averaged and moment equations: New derivation, efficient numerical solution and comparison with other physical approximations for modeling non-hydrostatic free surface flows},
volume={504},
ISSN={00219991},
DOI={10.1016/j.jcp.2024.112882},
journal={Journal of Computational Physics},
author={Escalante, C. and Morales De Luna, T. and Cantero-Chinchilla, F. and Castro-Orgaz, O.},
year={2024},
month=may,
pages={112882},
language={en}
}
Imports
Load packages
import osimport numpy as npimport jaxfrom jax import numpy as jnpimport pytestfrom types import SimpleNamespacefrom sympy import cos, pi, symbols, Derivative, Function, exp, I, Rational, Derivative, init_printing, Matrix, sqrt, difffrom sympy import Matrix, sqrt, Derivative, Rationalfrom time import time as gettimefrom attr import define, fieldfrom typing import Callableimport paramfrom functools import partialfrom zoomy_jax.fvm.solver_jax import HyperbolicSolver, PoissonSolver, Settingsfrom zoomy_core.fvm.ode import RK1import zoomy_core.fvm.timestepping as timesteppingimport zoomy_core.fvm.flux as fluximport zoomy_core.fvm.nonconservative_flux as nc_fluxfrom zoomy_core.model.boundary_conditions import BoundaryConditionfrom zoomy_core.model.models.basisfunctions import Basisfunction, Legendre_shiftedfrom zoomy_core.model.models.basismatrices import Basismatricesfrom zoomy_jax.fvm.solver_jax import newton_solver, log_callback_hyperbolic, log_callback_execution_timefrom zoomy_core.fvm.ode import RK1from zoomy_core.model.basemodel import Modelfrom zoomy_core.misc.misc import Zstruct, ZArrayimport zoomy_core.model.initial_conditions as ICimport zoomy_core.model.boundary_conditions as BCimport zoomy_core.misc.io as iofrom zoomy_core.mesh.mesh import compute_derivativesfrom zoomy_tests.swashes import plots_paperimport zoomy_core.model.analysis as analysisimport zoomy_core.mesh.mesh as petscMeshinit_printing(use_latex=True)
class VAMHyperbolic(Model):# Parameters replace attrs fields dimension = param.Integer(default=1)# Passing int=6 creates default variables q_0...q_5 variables = param.Parameter(default=6)# Aux variables defined by name aux_variables = param.Parameter( default=["hw2", "p0", "p1", "dbdx", "dhdx", "dhp0dx", "dhp1dx"] ) parameters = param.Parameter(default={"g": 9.81})def flux(self): fx = Matrix([0for i inrange(self.n_variables)])# Access aux variables via dot notation (ZStruct) hw2 =self.aux_variables.hw2# Access variables by index (generated from default=6) h =self.variables[0] hu0 =self.variables[1] hu1 =self.variables[2] hw0 =self.variables[3] hw1 =self.variables[4] u0 = hu0 / h u1 = hu1 / h w0 = hw0 / h w1 = hw1 / h fx[0] = hu0 fx[1] = hu0 * u0 + Rational(1, 3) * hu1 * u1 fx[2] =2* hu0 * u1 fx[3] = hu0 * w0 + Rational(1, 3) * hu1 * w1 fx[4] = hu0 * w1 + u1 * (hw0 + Rational(2, 5) * hw2)# FIX: Return ZArray(fx) directly for 1D to get shape (n, 1).# ZArray([fx]) would create shape (1, n, 1).return ZArray(fx)def nonconservative_matrix(self):# We need to construct the matrix with shape (n, n, dimension) = (n, n, 1) nc_val = Matrix( [[0for i inrange(self.n_variables)] for j inrange(self.n_variables)] ) hw2 =self.aux_variables.hw2 h =self.variables[0] hw0 =self.variables[3] p =self.parameters u0 =self.variables[1] / h w0 = hw0 / h w2 = hw2 / h nc_val[1, 0] = p.g * h nc_val[1, 5] = p.g * h nc_val[2, 2] =-u0 nc_val[4, 2] =+Rational(1, 5) * w2 - w0# FIX: Ensure output is (n, n, 1)# ZArray(nc_val) gives (n, n). We explicitly shape it. nc = ZArray.zeros(self.n_variables, self.n_variables, self.dimension) nc[:, :, 0] = ZArray(nc_val)return ncdef eigenvalues(self): ev = Matrix([0for i inrange(self.n_variables)]) h =self.variables[0] hu0 =self.variables[1] hu1 =self.variables[2] p =self.parameters u0 = hu0 / h u1 = hu1 / h ev[0] = u0 ev[1] = u0 +1/ sqrt(3) * u1 ev[2] = u0 -1/ sqrt(3) * u1 ev[3] = u0 + sqrt(p.g * h + u1**2) ev[4] = u0 - sqrt(p.g * h + u1**2) ev[5] =0return ZArray(ev)def source(self): R = Matrix([0for i inrange(self.n_variables)]) p0 =self.aux_variables.p0 p1 =self.aux_variables.p1 dbdx =self.aux_variables.dbdx dhdx =self.aux_variables.dhdx dhp0dx =self.aux_variables.dhp0dx dhp1dx =self.aux_variables.dhp1dx R[0] =0 R[1] = dhp0dx +2* p1 * dbdx R[2] = dhp1dx - (3* p0 - p1) * dhdx -6* (p0 - p1) * dbdx R[3] =-2* p1 R[4] =6* (p0 - p1) R[5] =0return ZArray(-R)def constraints(self): C = Matrix([0for i inrange(3)]) x =self.position[0] q0 =self.variables[0] q1 =self.variables[1] q2 =self.variables[2] q3 =self.variables[3] q4 =self.variables[4] q5 =self.variables[5] h = q0 u0 = q1 / h u1 = q2 / h w0 = q3 / h w1 = q4 / h b = q5 w2 =self.aux_variables.hw2 / q0 C[0] = ( h * Derivative(u0, x)+ Rational(1, 3) * Derivative(h * u1, x)+ Rational(1, 3) * u1 * Derivative(h, x)+2* (w0 - u0 * Derivative(b, x)) ) C[1] = ( h * Derivative(u0, x)+ u1 * Derivative(h, x)+2* (u1 * Derivative(b, x) - w1) ) C[2] = ( h * Derivative(u0, x)+ u1 * Derivative(h, x)+2* (w0 + w2 - u0 * Derivative(b, x)) )return ZArray(C)class VAMPoisson(Model): dimension = param.Integer(default=1)# Defined explicitly by name variables = param.Parameter(default=["p0", "p1"]) aux_variables = param.Parameter( default=["dp0dx","ddp0dxx","dp1dx","ddp1dxx","d4p0dx4","d4p1dx4","h","dbdx","ddbdxx","dhdx","ddhdxx","u0","du0dx","w0","w1","u1","du1dx","dt", ] ) parameters = param.Parameter(default={"g": 9.81})def residual(self): R = Matrix([0for i inrange(self.n_variables)]) h =self.aux_variables.h# Access variables via dot notation (ZStruct) p0 =self.variables.p0 p1 =self.variables.p1 dt =self.aux_variables.dt dbdx =self.aux_variables.dbdx ddbdxx =self.aux_variables.ddbdxx dhdx =self.aux_variables.dhdx ddhdxx =self.aux_variables.ddhdxx dp0dx =self.aux_variables.dp0dx dp1dx =self.aux_variables.dp1dx ddp0dxx =self.aux_variables.ddp0dxx ddp1dxx =self.aux_variables.ddp1dxx# Note: Values from the middle state after hyperbolic step oldu0 =self.aux_variables.u0 doldu0dx =self.aux_variables.du0dx oldw1 =self.aux_variables.w1 oldw0 =self.aux_variables.w0 oldu1 =self.aux_variables.u1 doldu1dx =self.aux_variables.du1dx I1 = (-Rational(1, 3)* dt* (-(3* p0 - p1) * ddhdxx- (6* p0 -6* p1) * ddbdxx- (3* dp0dx - dp1dx) * dhdx- (6* dp0dx -6* dp1dx) * dbdx+ h * ddp1dxx+ p1 * ddhdxx+2* dhdx * dp1dx )-2* (-dt * (h * dp0dx + p0 * dhdx +2* p1 * dbdx) + h * oldu0) * dbdx / h+ Rational(1, 3)* (-dt* (-(3* p0 - p1) * dhdx- (6* p0 -6* p1) * dbdx+ h * dp1dx+ p1 * dhdx )+ h * oldu1 )* dhdx/ h+2* (2* dt * p1 + h * oldw0) / h+ (-(-dt * (h * dp0dx + p0 * dhdx +2* p1 * dbdx) + h * oldu0)* dhdx/ h**2+ (-dt* ( h * ddp0dxx+ p0 * ddhdxx+2* p1 * ddbdxx+2* dbdx * dp1dx+2* dhdx * dp0dx )+ h * doldu0dx+ oldu0 * dhdx )/ h )* h+ Rational(1, 3) * h * doldu1dx+ Rational(1, 3) * oldu1 * dhdx ) I2 = (-2* (-dt * (6* p0 -6* p1) + h * oldw1) / h+2* (-dt* (-(3* p0 - p1) * dhdx- (6* p0 -6* p1) * dbdx+ h * dp1dx+ p1 * dhdx )+ h * oldu1 )* dbdx/ h+ (-dt* (-(3* p0 - p1) * dhdx- (6* p0 -6* p1) * dbdx+ h * dp1dx+ p1 * dhdx )+ h * oldu1 )* dhdx/ h+ (-(-dt * (h * dp0dx + p0 * dhdx +2* p1 * dbdx) + h * oldu0)* dhdx/ h**2+ (-dt* ( h * ddp0dxx+ p0 * ddhdxx+2* p1 * ddbdxx+2* dbdx * dp1dx+2* dhdx * dp0dx )+ h * doldu0dx+ oldu0 * dhdx )/ h )* h ) R[0] = I1 R[1] = I2return ZArray(R)def eigenvalues(self): ev = Matrix([0for i inrange(self.n_variables)])return ZArray(ev)