TVB斜率限制器

本文参考源程序来自Fluidity。

简介

TVB斜率限制器最早由Cockburn和Shu(1989)提出,主要特点是提出了修正minmod函数

\[\tilde{m}(a_1, a_2, \cdots, a_n) = \left\{
\begin{array}{ll}
a_1 & \text{if} \, \left| a_1 \right| \le Mh^2, \cr
m\left(a_1, a_2, \cdots, a_n\right) & \text{otherwise}, \end{array}\right.\]

其中\(m\left(a_1, a_2, \cdots, a_n\right)\)为原始minmod函数,\(M\)为系数。

高维TVB限制器

针对高维情形可以参考Cockburn和Shu[2]的研究,高维情形与一维类似,但是主要区别在于构造修正minmod函数的两个参数

\[\begin{equation}
a_1 = \tilde{u}_h(m_i, K_0), \quad a_2 = v\Delta\bar{u}_h(m_i, K_0)
\end{equation}\]

其中 \(\tilde{u}_h(m_i, K_0)\) 为边界中点处近似解与单元均值之差 \(u_h(m_i, K_0) - \bar{u}_{K_0}\),\(\bar{u}_{K_0}\) 为单元 \(K_0\) 的单元均值。而这个 \(\Delta\bar{u}_h(m_i, K_0)\) 则是根据几何坐标插值后得到的边界中心值 \(u_h(m_1)\) 与 \(\bar{u}_{K_0}\) 之间差值,\(v\) 为大于1的系数,一般取1.5左右。

几何插值系数根据三个单元间坐标关系而定。如在计算边中点 \(m_1\) 的系数时,首先需确定除 \(b_0\) 和 \(b_1\) 外要取哪个单元进行插值(\(b_2\) 或 \(b_3\)),其中选取原则为以下两点

  1. 单元 \(b_1\) 所占比例尽量大
  2. 中点 \(m_1\) 尽量在两条射线 \(b_0 - b_1\) 与 \(b_0 - b_2\) 之间

在确定第三个单元之后,我们便可以确定中点 \(m_1\) 插值系数。插值公式为

\[\begin{equation}
u_h(m_1) - u_h(b_0) = \alpha_1 \left( u_h(b_1) - u_h(b_0) \right) + \alpha_2 \left( u_h(b_2) - u_h(b_0) \right)
\end{equation}\]

其中插值系数根据三个三角形单元形心坐标而定

\[\begin{equation}
\left\{ \begin{array}{ll}
x_{m_1} - x_{b_0} = \alpha_1 \left( x_{b_1} - x_{b_0} \right) + \alpha_2 \left( x_{b_2} - x_{b_0} \right) \cr
y_{m_1} - y_{b_0} = \alpha_1 \left( y_{b_1} - y_{b_0} \right) + \alpha_2 \left( y_{b_2} - y_{b_0} \right)
\end{array} \right.
\end{equation}\]

在得到修正后的边界值与均值之差后,修正过程并没有结束。因为可能TVB限制器只修正了三个边中某两个边中点值,而剩下的边中点值保持不变,若此时采用新的三个边中点值进行重构,得到的重构值均值区别于原始单元均值,造成单元不守恒。

为解决此问题,需要对修正后的插值进行修正。假设 \(\Delta_i\) 为限制器得到的解

\[\begin{equation}
\Delta_i = \tilde{m}\left(\tilde{u}_h(m_i, K_0), v\Delta\bar{u}_h(m_i, K_0)\right)
\end{equation}\]

由于 \(\Delta_i\) 代表限制后边界中点值与单元均值之差,因此应当满足 \(\sum_{i=1}^3 \Delta_i = 0\)。若 \(\sum_{i=1}^3 \Delta_i \neq 0\),计算修正系数 \(\theta^+\) 与 \(\theta^-\)

\[\begin{equation}
\begin{array}{ll}
pos = \sum_{i=1}^3 \text{max} \left(0, \Delta_i\right), \quad neg = \sum_{i=1}^3 \text{max} \left(0, -\Delta_i\right) \cr
\theta^+ = \text{min} \left(1, \frac{neg}{pos} \right), \quad \theta^- = \text{min} \left(1, \frac{pos}{neg} \right)
\end{array}
\end{equation}\]

其中 \(pos\) 与 \(neg\) 分别是 \(\Delta_i\) 中正系数与负系数总和。采用 \(\theta^+\) 与 \(\theta^-\) 修正后限制值为

\[\begin{equation}
\hat{\Delta}_i = \theta^+ \text{max} \left(0, \Delta_i\right) - \theta^- \text{max} \left(0, -\Delta_i\right)
\end{equation}\]

此时满足 \(\sum_{i=1}^3 \hat{\Delta}_i = 0\),根据 \(\hat{\Delta}_i\) 进行重构便可得到限制后的解。

代码

源程序文件为/assemble/Slope_limiters_DG.F90。

subroutine cockburn_shu_setup_ele(ele, T, X)
integer, intent(in) :: ele
type(scalar_field), intent(inout) :: T
type(vector_field), intent(in) :: X integer, dimension(:), pointer :: neigh, x_neigh
real, dimension(X%dim) :: ele_centre, face_2_centre
real :: max_alpha, min_alpha, neg_alpha
integer :: ele_2, ni, nj, face, face_2, i, nk, ni_skip, info, nl
real, dimension(X%dim, ele_loc(X,ele)) :: X_val, X_val_2
real, dimension(X%dim, ele_face_count(T,ele)) :: neigh_centre,&
& face_centre
real, dimension(X%dim) :: alpha1, alpha2
real, dimension(X%dim,X%dim) :: alphamat
real, dimension(X%dim,X%dim+1) :: dx_f, dx_c
integer, dimension(mesh_dim(T)) :: face_nodes X_val=ele_val(X, ele) ele_centre=sum(X_val,2)/size(X_val,2) neigh=>ele_neigh(T, ele)
! x_neigh/=t_neigh only on periodic boundaries.
x_neigh=>ele_neigh(X, ele) searchloop: do ni=1,size(neigh) !----------------------------------------------------------------------
! Find the relevant faces.
!----------------------------------------------------------------------
ele_2=neigh(ni) ! Note that although face is calculated on field U, it is in fact
! applicable to any field which shares the same mesh topology.
face=ele_face(T, ele, ele_2)
face_nodes=face_local_nodes(T, face) face_centre(:,ni) = sum(X_val(:,face_nodes),2)/size(face_nodes) if (ele_2<=0) then
! External face.
neigh_centre(:,ni)=face_centre(:,ni)
cycle
end if X_val_2=ele_val(X, ele_2) neigh_centre(:,ni)=sum(X_val_2,2)/size(X_val_2,2)
if (ele_2/=x_neigh(ni)) then
! Periodic boundary case. We have to cook up the coordinate by
! adding vectors to the face from each side.
face_2=ele_face(T, ele_2, ele)
face_2_centre = &
sum(face_val(X,face_2),2)/size(face_val(X,face_2),2)
neigh_centre(:,ni)=face_centre(:,ni) + &
(neigh_centre(:,ni) - face_2_centre)
end if end do searchloop do ni = 1, size(neigh)
dx_c(:,ni)=neigh_centre(:,ni)-ele_centre !Vectors from ni centres to
! !ele centre
dx_f(:,ni)=face_centre(:,ni)-ele_centre !Vectors from ni face centres
!to ele centre
end do alpha_construction_loop: do ni = 1, size(neigh)
!Loop for constructing Delta v(m_i,K_0) as described in C&S
alphamat(:,1) = dx_c(:,ni) max_alpha = -1.0
ni_skip = 0 choosing_best_other_face_loop: do nj = 1, size(neigh)
!Loop over the other faces to choose best one to use
!for linear basis across face if(nj==ni) cycle !Construct a linear basis using all faces except for nj
nl = 1
do nk = 1, size(neigh)
if(nk==nj.or.nk==ni) cycle
nl = nl + 1
alphamat(:,nl) = dx_c(:,nk)
end do !Solve for basis coefficients alpha
alpha2 = dx_f(:,ni)
call solve(alphamat,alpha2,info) if((.not.any(alpha2<0.0)).and.alpha2(1)/norm2(alpha2)>max_alpha) &
& then
alpha1 = alpha2
ni_skip = nj
max_alpha = alpha2(1)/norm2(alpha2)
end if end do choosing_best_other_face_loop if(max_alpha<0.0) then
if(tolerate_negative_weights) then
min_alpha = huge(0.0)
ni_skip = 0
choosing_best_other_face_neg_weights_loop: do nj = 1, size(neigh)
!Loop over the other faces to choose best one to use
!for linear basis across face if(nj==ni) cycle !Construct a linear basis using all faces except for nj
nl = 1
do nk = 1, size(neigh)
if(nk==nj.or.nk==ni) cycle
nl = nl + 1
alphamat(:,nl) = dx_c(:,nk)
end do !Solve for basis coefficients alpha
alpha2 = dx_f(:,ni)
call solve(alphamat,alpha2,info) neg_alpha = 0.0
do i = 1, size(alpha2)
if(alpha2(i)<0.0) then
neg_alpha = neg_alpha + alpha2(i)**2
end if
end do
neg_alpha = sqrt(neg_alpha) if(min_alpha>neg_alpha) then
alpha1 = alpha2
ni_skip = nj
min_alpha = neg_alpha
end if
end do choosing_best_other_face_neg_weights_loop
else
FLAbort('solving for alpha failed')
end if
end if alpha(ele,ni,:) = 0.0
alpha(ele,ni,ni) = alpha1(1)
nl = 1
do nj = 1, size(neigh)
if(nj==ni.or.nj==ni_skip) cycle
nl = nl + 1
alpha(ele,ni,nj) = alpha1(nl)
end do dx2(ele,ni) = norm2(dx_c(:,ni)) end do alpha_construction_loop end subroutine cockburn_shu_setup_ele
subroutine limit_slope_ele_cockburn_shu(ele, T, X)
!!< Slope limiter according to Cockburn and Shu (2001)
!!< http://dx.doi.org/10.1023/A:1012873910884
integer, intent(in) :: ele
type(scalar_field), intent(inout) :: T
type(vector_field), intent(in) :: X integer, dimension(:), pointer :: neigh, x_neigh, T_ele
real :: ele_mean
real :: pos, neg
integer :: ele_2, ni, face
real, dimension(ele_loc(T,ele)) :: T_val, T_val_2
real, dimension(ele_face_count(T,ele)) :: neigh_mean, face_mean
real, dimension(mesh_dim(T)+1) :: delta_v
real, dimension(mesh_dim(T)+1) :: Delta, new_val
integer, dimension(mesh_dim(T)) :: face_nodes T_val=ele_val(T, ele) ele_mean=sum(T_val)/size(T_val) neigh=>ele_neigh(T, ele)
! x_neigh/=t_neigh only on periodic boundaries.
x_neigh=>ele_neigh(X, ele) searchloop: do ni=1,size(neigh) !----------------------------------------------------------------------
! Find the relevant faces.
!----------------------------------------------------------------------
ele_2=neigh(ni) ! Note that although face is calculated on field U, it is in fact
! applicable to any field which shares the same mesh topology.
face=ele_face(T, ele, ele_2)
face_nodes=face_local_nodes(T, face) face_mean(ni) = sum(T_val(face_nodes))/size(face_nodes) if (ele_2<=0) then
! External face.
neigh_mean(ni)=face_mean(ni)
cycle
end if T_val_2=ele_val(T, ele_2) neigh_mean(ni)=sum(T_val_2)/size(T_val_2) end do searchloop delta_v = matmul(alpha(ele,:,:),neigh_mean-ele_mean) delta_loop: do ni=1,size(neigh) Delta(ni)=TVB_minmod(face_mean(ni)-ele_mean, &
Limit_factor*delta_v(ni), dx2(ele,ni)) end do delta_loop if (abs(sum(Delta))>1000.0*epsilon(0.0)) then
! Coefficients do not sum to 0.0 pos=sum(max(0.0, Delta))
neg=sum(max(0.0, -Delta)) Delta = min(1.0,neg/pos)*max(0.0,Delta) &
-min(1.0,pos/neg)*max(0.0,-Delta) end if new_val=matmul(A,Delta+ele_mean) ! Success or non-boundary failure.
T_ele=>ele_nodes(T,ele) call set(T, T_ele, new_val) end subroutine limit_slope_ele_cockburn_shu

[1] COCKBURN B, SHU C-W. TVB Runge-Kutta local projection discontinuous Galerkin finite element method for conservation laws. II. General framework[J]. Mathematics of Computation, 1989, 52(186): 411–411.

[2] COCKBURN B, SHU C-W. The Runge-Kutta discontinuous Galerkin method for conservation laws. V. Multidimensional systems[J]. Journal of Computational Physics, 1998, 141(2): 199–224.

TVB斜率限制器的更多相关文章

  1. BJ2 斜率限制器

    BJ2 斜率限制器 本文介绍斜率限制器取自于 Anastasiou 与 Chan (1997)[1]研究,其所利用的斜率限制器也是 Barth 与 Jespersen 限制器的一种修正形式,并且包含一 ...

  2. 流量限制器(Flux Limiter)

    内容翻译自Wikipedia Flux limiter 流量限制器(Flux limiters)应用在高精度格式中-这种数值方法用来求解科学与工程问题,特别是由偏微分方程(PDE's)描述的流体动力学 ...

  3. 感谢 git

    今天对程序大修了一下,顺便把所有算例测试了一遍,突然发现二维浅水方程有些算例出现了明显的错误. 这次突然出现的错误让我有点措手不及,因为一直没有修改过浅水方程求解器,所以这些算例很久没有测试过了.硬着 ...

  4. Hermite WENO 重构格式

    Hermite WENO 单元重构 本文主要介绍采用 Hermite WENO 重构方法作为斜率限制器应用于二维或高维单元中. 1.简介[1] ENO格式最早由 Harten 等[2]提出,ENO格式 ...

  5. BZOJ 1597: [Usaco2008 Mar]土地购买 [斜率优化DP]

    1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4026  Solved: 1473[Submit] ...

  6. [斜率优化DP]【学习笔记】【更新中】

    参考资料: 1.元旦集训的课件已经很好了 http://files.cnblogs.com/files/candy99/dp.pdf 2.http://www.cnblogs.com/MashiroS ...

  7. BZOJ 1010: [HNOI2008]玩具装箱toy [DP 斜率优化]

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 9812  Solved: 3978[Submit][St ...

  8. 单调队列 && 斜率优化dp 专题

    首先得讲一下单调队列,顾名思义,单调队列就是队列中的每个元素具有单调性,如果是单调递增队列,那么每个元素都是单调递增的,反正,亦然. 那么如何对单调队列进行操作呢? 是这样的:对于单调队列而言,队首和 ...

  9. 【BZOJ2442】 [Usaco2011 Open]修剪草坪 斜率优化DP

    第一次斜率优化. 大致有两种思路: 1.f[i]表示第i个不选的最优情况(最小损失和)f[i]=f[j]+e[i] 显然n^2会T,但是可以发现f的移动情况可以用之前单调队列优化,就优化成O(n)的了 ...

随机推荐

  1. Vue CLI 5 和 vite 创建 vue3.x 项目以及 Vue CLI 和 vite 的区别

    这几天进入 Vue CLI 官网,发现不能选择 Vue CLI 的版本,也就是说查不到 vue-cli 4 以下版本的文档. 如果此时电脑上安装了 Vue CLI,那么旧版安装的 vue 项目很可能会 ...

  2. UltraSoft - Beta - Scrum Meeting 3

    20200519会议纪要 Date: May 19th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 暂无 Liuzh 前端 暂无 Kkkk 前端 完成了前端 ...

  3. 安装pytorch的细节记录

    1.根据教程安装pytorch的时候发现太慢了,无法容忍,根据https://blog.csdn.net/zzq060143/article/details/88042075z在Ancona Prom ...

  4. android tcp通讯

    Andoird TCP通讯 前言 最近在写一个即时通讯的项目,有一些心得,写出来给大家分享指正一下. 简单描述一下这个项目: 实时查询车辆运行状态的项目,走TCP通迅. 接口采用GZIP压缩. 后台是 ...

  5. STM32中断编程三步曲教你弄会中断设置以及中断优先级设置

    中断作为stm32中必不可少的一个功能,其重要性是不言而喻的因此把中断学习好是根本. 所以今天就来好好啃一下中断配置的知识,俗话说:磨刀不误砍柴工.问题是什么呢?项目中我用到了一个触摸键盘TTP229 ...

  6. OpenWrt编译问题记录

    错误一.config.status: error: cannot find input file: `xmetadataretriever/Makefile.in' configure: creati ...

  7. 像素反转 牛客网 程序员面试金典 C++ Python

    像素反转 牛客网 程序员面试金典 题目描述 有一副由NxN矩阵表示的图像,这里每个像素用一个int表示,请编写一个算法,在不占用额外内存空间的情况下(即不使用缓存矩阵),将图像顺时针旋转90度. 给定 ...

  8. Python展示文件下载进度条

    前言 大家在用Python写一些小程序的时候,经常都会用到文件下载,对于一些较小的文件,大家可能不太在乎文件的下载进度,因为一会就下载完毕了. 但是当文件较大,比如下载chromedriver的时候, ...

  9. 记一次 Java 导出大批量 Excel 优化

    常用的excel导出方案,详情见Spring Boot 入门(十二):报表导出,对比poi.jxl和esayExcel的效率,其中jxl.esayEscel 底层都是基于 poi,它们仅仅是对 poi ...

  10. python与C结构体之间二进制数据转换

    python与C结构体之间数据转换 前言 在实际应用中,可能会遇到直接和C进行二进制字节流协议通信,这时要把数据解包成python数据,如果可能,最好与C定义的结构体完全对应上. python中有2种 ...