Skip to content

Commit 73ae3ce

Browse files
committed
WIP oscillation suppression
1 parent bc18042 commit 73ae3ce

File tree

3 files changed

+264
-3
lines changed

3 files changed

+264
-3
lines changed

src/libcadet/Weno_DG.hpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// =============================================================================
2+
// CADET
3+
//
4+
// Copyright © 2008-2022: The CADET Authors
5+
// Please see the AUTHORS and CONTRIBUTORS file.
6+
//
7+
// All rights reserved. This program and the accompanying materials
8+
// are made available under the terms of the GNU Public License v3.0 (or, at
9+
// your option, any later version) which accompanies this distribution, and
10+
// is available at http://www.gnu.org/licenses/gpl.html
11+
// =============================================================================
12+
13+
/**
14+
* @file
15+
* Implements the WENO method
16+
*/
17+
18+
#ifndef LIBCADET_WENODG_HPP_
19+
#define LIBCADET_WENODG_HPP_
20+
21+
#include "AutoDiff.hpp"
22+
#include "MathUtil.hpp"
23+
#include "Memory.hpp"
24+
#include "common/CompilerSpecific.hpp"
25+
#include "cadet/Exceptions.hpp"
26+
27+
#include <algorithm>
28+
29+
namespace cadet
30+
{
31+
32+
//template<typename StateType> // todo
33+
class WENOLimiter {
34+
public:
35+
virtual ~WENOLimiter() {}
36+
virtual double call(double u0, double u1, double u2) = 0;
37+
virtual double call(active u0, active u1, active u2) = 0;
38+
};
39+
40+
class FullLimiter : public WENOLimiter {
41+
42+
public:
43+
FullLimiter() {}
44+
double call(double u0, double u1, double u2) override {
45+
return 0.0;
46+
}
47+
double call(active u0, active u1, active u2) override {
48+
return 0.0;
49+
}
50+
};
51+
52+
class MinmodWENO : public WENOLimiter {
53+
54+
public:
55+
MinmodWENO() {}
56+
double call(double u0, double u1, double u2) override {
57+
if (std::signbit(u0) == std::signbit(u1) && std::signbit(u0) == std::signbit(u2))
58+
return std::copysign(std::min(std::abs(u0), std::min(std::abs(u1), std::abs(u2))), u0);
59+
else
60+
return 0.0;
61+
}
62+
double call(active u0, active u1, active u2) override {
63+
if (std::signbit(u0.getValue()) == std::signbit(u1.getValue()) && std::signbit(u0.getValue()) == std::signbit(u2.getValue())) {
64+
if (std::signbit(u0.getValue())) // i.e. negative sign
65+
return -static_cast<double>(u0);
66+
else
67+
return static_cast<double>(u0);
68+
}
69+
else
70+
return 0.0;
71+
}
72+
};
73+
74+
class TVBMinmodWENO : public WENOLimiter {
75+
76+
public:
77+
TVBMinmodWENO() {}
78+
double call(double u0, double u1, double u2) override {
79+
if (std::abs(u0) <= M * h * h)
80+
return u0;
81+
else
82+
return minmod.call(u0, u1, u2);
83+
}
84+
double call(active u0, active u1, active u2) override {
85+
if (std::abs(u0.getValue()) <= M * h * h)
86+
return static_cast<double>(u0);
87+
else
88+
return minmod.call(u0, u1, u2);
89+
}
90+
private:
91+
MinmodWENO minmod;
92+
active h;
93+
active M;
94+
};
95+
96+
/**
97+
* @brief Implements the WENO scheme for convection
98+
* @details This scheme is based on upwind stencils and provides WENO methods 1-1, 2-3, and 3-5.
99+
* In general, WENO achieves order \f$ r \f$ using a stencil with \f$ (2r-1) \f$ points
100+
* that is subdivided into \f$ r \f$ smaller stencils having \f$ r \f$ points each.
101+
* WENO combines all substencils with an estimate of the smoothness of the solution (also obtained from the
102+
* substencils) in order to achieve a non-oscillatory high order reconstruction of the face values given
103+
* volume averages (cell boundary fluxes in finite volume schemes).
104+
* For details see \cite Liu1994 and \cite Jiang1996.
105+
*/
106+
class WenoDG
107+
{
108+
public:
109+
110+
/**
111+
* @brief Boundary treatment method determines how the reconstruction handles insufficient available elements (i.e., less elements available than stencil size)
112+
*/
113+
enum class BoundaryTreatment : int
114+
{
115+
ReduceOrder = 0, //!< Reduce the order of the WENO method such that the stencil is small enough
116+
ZeroWeights = 1, //!< Set weights of WENO method to 0 for unavailable elements
117+
ZeroWeightsForPnotZero = 2, //!< Set weights of WENO method to 0 for unavailable elements, except for the first cell (order is reduced to 1)
118+
LargeGhostNodes = 3,
119+
};
120+
121+
/**
122+
* @brief Creates the WENO scheme
123+
*/
124+
//WenoDG() : _order(maxOrder()), _boundaryTreatment(BoundaryTreatment::ReduceOrder), _intermediateValues(3 * maxOrder() * sizeof(active)) { }
125+
126+
~WenoDG() CADET_NOEXCEPT
127+
{
128+
delete[] _weno_gamma;
129+
delete[] _w;
130+
delete[] _wHat;
131+
delete[] _beta;
132+
delete[] _troubled_cells;
133+
}
134+
135+
void init(const double eps, const double r, const double gamma, const unsigned int nCells, const unsigned int nComp, const bool trackTroubledCells = false) {
136+
137+
_weno_gamma = new double[3]{ (1 - gamma) / 2.0, gamma, (1 - gamma) / 2.0 };
138+
_weno_r = r;
139+
_weno_eps = eps;
140+
if (trackTroubledCells)
141+
_troubled_cells = new double[nCells * nComp];
142+
else
143+
_troubled_cells = nullptr;
144+
}
145+
146+
inline double* troubledCells() const CADET_NOEXCEPT { return &_troubled_cells[0]; }
147+
148+
//private:
149+
150+
// indicator for troubled cells
151+
std::unique_ptr<WENOLimiter> weno_limiter;
152+
153+
// WENO parameters
154+
double* _weno_gamma;
155+
double _weno_r = 2.0;
156+
double _weno_eps = 1e-6;
157+
// weights, smoothness indicator, integral values.
158+
active* _wHat = new active[3]{ 0.0, 0.0, 0.0 };
159+
active* _w = new active[3]{ 0.0, 0.0, 0.0 };
160+
active _wSum = 0.0;
161+
active* _beta = new active[3]{ 0.0, 0.0, 0.0 };
162+
active _pAvg0 = 0.0;
163+
active _pAvg1 = 0.0;
164+
active _pAvg2 = 0.0;
165+
// limiter inputs
166+
active _avgUdeltaPlus = 0.0;
167+
active _avgUdeltaMinus = 0.0;
168+
active _uTilde = 0.0;
169+
active _u2Tilde = 0.0;
170+
// mark troubled cells (smoothness indicator)
171+
double* _troubled_cells;
172+
173+
};
174+
175+
} // namespace cadet
176+
177+
#endif // LIBCADET_WENODG_HPP_

src/libcadet/model/parts/ConvectionDispersionOperatorDG.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ AxialConvectionDispersionOperatorBaseDG::~AxialConvectionDispersionOperatorBaseD
5555
delete _dispersionDep;
5656

5757
delete[] _DGjacAxDispBlocks;
58-
//delete[] _wenoDerivatives; // todo weno
5958
}
6059

6160
/**
@@ -121,6 +120,44 @@ bool AxialConvectionDispersionOperatorBaseDG::configureModelDiscretization(IPara
121120
else
122121
_dispersionDep = helper.createParameterParameterDependence("CONSTANT_ONE");
123122

123+
paramProvider.pushScope("discretization");
124+
_OSmode = 0;
125+
// Read oscillation suppression settings and apply them
126+
if (paramProvider.exists("oscillation_suppression")) {
127+
128+
paramProvider.pushScope("oscillation_suppression");
129+
130+
std::string osMethod = paramProvider.getString("METHOD");
131+
132+
if (osMethod == "WENO")
133+
{
134+
LOG(Debug) << "WENO used as oscillation suppression mechanism.";
135+
136+
_OSmode = 1;
137+
double eps = paramProvider.exists("WENO_EPS") ? paramProvider.getDouble("WENO_EPS") : 1e-6;
138+
double r = paramProvider.exists("WENO_R") ? paramProvider.getDouble("WENO_R") : 2.0;
139+
double gamma = paramProvider.exists("WENO_GAMMA") ? paramProvider.getDouble("WENO_GAMMA") : 0.998;
140+
bool write_smoothness_indicator = paramProvider.exists("RETURN_SMOOTHNESS_INDICATOR") ? static_cast<bool>(paramProvider.getInt("RETURN_SMOOTHNESS_INDICATOR")) : false;
141+
142+
_weno.init(eps, r, gamma, _nCells, _nComp, write_smoothness_indicator);
143+
}
144+
else if (osMethod == "SUBCELL_LIMITING")
145+
{
146+
LOG(Debug) << "Subcell limiting used as oscillation suppression mechanism.";
147+
148+
_OSmode = 2;
149+
int order = paramProvider.getInt("FV_ORDER");
150+
// @TODO Subcell limiting
151+
throw InvalidParameterException("Oscillation suppression mechanism " + osMethod + " not implemented yet");
152+
153+
}
154+
else if (osMethod != "NONE")
155+
throw InvalidParameterException("Unknown oscillation suppression mechanism " + osMethod + " in oscillation_suppression_mode");
156+
157+
paramProvider.popScope();
158+
}
159+
paramProvider.popScope();
160+
124161
return true;
125162
}
126163

@@ -388,6 +425,36 @@ int AxialConvectionDispersionOperatorBaseDG::residualImpl(const IModel& model, d
388425
Eigen::Map<Vector<ResidualType, Dynamic>, 0, InnerStride<>> _h(reinterpret_cast<ResidualType*>(&_h[0]), _nPoints, InnerStride<>(1));
389426
Eigen::Map<Vector<StateType, Dynamic>, 0, InnerStride<>> _g(reinterpret_cast<StateType*>(&_g[0]), _nPoints, InnerStride<>(1));
390427

428+
////ResidualType _pAvg0 = reinterpret_cast<ResidualType>(_weno._pAvg0);
429+
////ResidualType _pAvg1 = reinterpret_cast<ResidualType>(_weno._pAvg1);
430+
////ResidualType _pAvg2 = reinterpret_cast<ResidualType>(_weno._pAvg2);
431+
432+
//// calculate smoothness indicator, if oscillation suppression is active
433+
//if (_OSmode != 0)
434+
//{
435+
// if (_OSmode == 1) // WENO
436+
// {
437+
// for (unsigned int cell = 0; cell < _nCells; cell++)
438+
// {
439+
// if (cell > 0 && cell < _nCells - 1) // todo boundary treatment
440+
// {
441+
// // todo store weights additionally to inverse
442+
// // todo overwrite values instead of recalculation
443+
// _weno._pAvg0 = 1.0 / static_cast<ParamType>(_deltaZ) * (_invWeights.cwiseInverse().cast<StateType>().array() * _C.segment((cell - 1) * _nNodes, _nNodes).array()).sum();
444+
// _weno._pAvg1 = 1.0 / static_cast<ParamType>(_deltaZ) * (_invWeights.cwiseInverse().cast<StateType>().array() * _C.segment(cell * _nNodes, _nNodes).array()).sum();
445+
// _weno._pAvg2 = 1.0 / static_cast<ParamType>(_deltaZ) * (_invWeights.cwiseInverse().cast<StateType>().array() * _C.segment((cell + 1) * _nNodes, _nNodes).array()).sum();
446+
447+
448+
// // mark troubled cell
449+
// if (true)
450+
// {
451+
// int hm = 0;
452+
// }
453+
// }
454+
// }
455+
// }
456+
//}
457+
391458
// Add time derivative to bulk residual
392459
if (yDot)
393460
{

src/libcadet/model/parts/ConvectionDispersionOperatorDG.hpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "ParamIdUtil.hpp"
2222
#include "AutoDiff.hpp"
2323
#include "Memory.hpp"
24-
//#include "Weno.hpp" // todo weno DG
24+
#include "Weno_DG.hpp"
2525
#include "SimulationTypes.hpp"
2626
#include <ParamReaderHelper.hpp>
2727
#include "linalg/BandedEigenSparseRowIterator.hpp"
@@ -123,6 +123,11 @@ namespace cadet
123123
inline bool hasSmoothnessIndicator() const CADET_NOEXCEPT { return static_cast<bool>(_OSmode); } // only zero if no oscillation suppression
124124
inline double* smoothnessIndicator() const CADET_NOEXCEPT
125125
{
126+
if (_OSmode == 1)
127+
return _weno.troubledCells();
128+
//else if (_OSmode == 2) // todo subcell limiting
129+
// return _subcell.troubledCells();
130+
else
126131
return nullptr;
127132
}
128133

@@ -180,6 +185,11 @@ namespace cadet
180185
Eigen::Vector<active, Eigen::Dynamic> _surfaceFlux; //!< stores the surface flux values
181186
Eigen::Vector<active, 4> _boundary; //!< stores the boundary values from Danckwert boundary conditions
182187

188+
// non-linear oscillation prevention mechanism
189+
int _OSmode; //!< oscillation suppression mode; 0 : none, 1 : WENO, 2 : Subcell limiting
190+
WenoDG _weno; //!< WENO operator
191+
//SucellLimiter _subcellLimiter; // todo
192+
183193
// Simulation parameters
184194
active _colLength; //!< Column length \f$ L \f$
185195
active _crossSection; //!< Cross section area
@@ -194,7 +204,14 @@ namespace cadet
194204
int _curSection; //!< current section index
195205
bool _newStaticJac; //!< determines wether static analytical jacobian needs to be computed (every section)
196206

207+
// todo weno
208+
//ArrayPool _stencilMemory; //!< Provides memory for the stencil
209+
//double* _wenoDerivatives; //!< Holds derivatives of the WENO scheme
210+
//Weno _weno; //!< The WENO scheme implementation
211+
//double _wenoEpsilon; //!< The @f$ \varepsilon @f$ of the WENO scheme (prevents division by zero)
212+
197213
bool _dispersionCompIndep; //!< Determines whether dispersion is component independent
214+
198215
IParameterParameterDependence* _dispersionDep;
199216

200217
/* ===================================================================================
@@ -1298,4 +1315,4 @@ namespace cadet
12981315
} // namespace model
12991316
} // namespace cadet
13001317

1301-
#endif // LIBCADET_CONVECTIONDISPERSIONOPERATORDG_HPP_
1318+
#endif // LIBCADET_CONVECTIONDISPERSIONOPERATORDG_HPP_

0 commit comments

Comments
 (0)