CppNoddy  0.92
Loading...
Searching...
No Matches
OneD_TVDLF_Mesh.h
Go to the documentation of this file.
1/// \file OneD_TVDLF_Mesh.h
2/// Specification of an object that represents a one dimensional
3/// mesh for TVD LX methods.
4
5#ifndef ONED_TVDLF_MESH_H
6#define ONED_TVDLF_MESH_H
7
8#include <vector>
9#include <fstream>
10#include <limits>
11
12#include <Types.h>
13#include <OneD_TVDLF_Elt.h>
14#include <OneD_Node_Mesh.h>
16
17namespace CppNoddy {
18
20 /// iterators for the vector of elements
21 typedef std::vector<OneD_TVDLF_Elt> vector_of_elts;
22 typedef vector_of_elts::const_iterator celt_iter;
23 typedef vector_of_elts::iterator elt_iter;
24 /// function pointer used in the initial conditions
25 typedef void (*fn_ptr)(const double&, DenseVector<double>&);
26
27 public:
28
29 /// Constructor for the Finite Volume Mesh using linear elements
30 /// \param X A vector of nodal locations at which the element
31 /// FACES will positioned
32 /// \param ptr A pointer to the hyperbolic system applied to this mesh
33 /// \param init_ptr A pointer to a function that defines the initial conditions
34 OneD_TVDLF_Mesh(const DenseVector<double>& X, OneD_Hyperbolic_System* ptr, fn_ptr init_ptr);
35
36 /// Empty desctructor
38
39 /// Get the nodal positions in the middle of each element
40 /// \return An NVector<double> of the nodal points
42
43 /// Get the positions of the element faces
44 /// \return An NVector<double> of the spatial points
46
47 /// Set the limiter type to be applied in the slope
48 /// values. 0 is no limiter, 1 is Lax-Wendroff, 2 is
49 /// Beam-Warming, 3 is MC and 4 is Superbee.
50 /// \param id The identifier of the limiter.
51 void set_limiter(unsigned id);
52
53 /// Update all the elements in this mesh to
54 /// a new time step.
55 /// \param CFL The CFL value to be used to determine the time step
56 /// \param max_dt Do not take a time step larger than this irrespective
57 /// of the CFL value
58 double update(const double& CFL, const double& max_dt = std::numeric_limits<long double>::max());
59
60 /// Update all the elements in this mesh to a USER SPECIFIED time step.
61 /// \param CFL The CFL value to be used to determine the time step
62 /// \param t_end The time level to compute to
63 void update_to(const double& CFL, const double& t_end);
64
65 double update_to_red(const double& CFL, const double& max_dt) {
66 // the black mesh slopes are set in the constructor
67 // and at the end of every 'update' call
68
69 // integrate the black mesh data onto the red mesh
70 {
71 elt_iter er = RED_ELTS.begin();
72 while(er != RED_ELTS.end()) {
73 er -> set_Q_mid(er -> contributed_Q() / er -> get_dx());
74 ++er;
75 }
76 }
77
78 // step thru the black elements to find a max time step
79 double first_dt;
80 {
81 elt_iter eb = BLACK_ELTS.begin();
82 first_dt = eb -> get_max_dt();
83 ++eb;
84 while(eb != BLACK_ELTS.end()) {
85 first_dt = std::min(first_dt, eb -> get_max_dt());
86 ++eb;
87 }
88 first_dt *= CFL;
89 }
90 if(first_dt > max_dt) {
91 first_dt = max_dt;
92 }
93
94 calc_slopes(&RED_ELTS);
95 // compute the fluxes through the element boundaries
96 // in the red mesh, using the nodal values of the black mesh
97 // then update the concentrations in the red mesh elements
98 {
99 elt_iter er = RED_ELTS.begin();
100 DenseVector<double> flux_in_left(ORDER_OF_SYSTEM, 0.0);
101 DenseVector<double> flux_out_right(ORDER_OF_SYSTEM, 0.0);
102 // start with the left most elt & work out the flux in from the left
103 er -> contributed_flux_in_left(first_dt, flux_in_left, MESH_TIME);
104 while(er != RED_ELTS.end()) {
105 // work out the flux out to the right
106 er -> contributed_flux_out_right(first_dt, flux_out_right, MESH_TIME);
107 // we now have the flux difference
108 DenseVector<double> deltaQ = (flux_in_left - flux_out_right) * first_dt / er -> get_dx();
109 // contribution from the source integral
110 {
111 double x_mid(er -> get_x(0.0));
112 DenseVector<double> slope(er -> get_slope());
113 DenseVector<double> q_mid(er -> get_Q(0.0));
114 q_mid += (er -> get_source_fn(0.0)
115 - er -> get_Jac_flux_fn(0.0).multiply(slope)) * 0.5 * first_dt;
116 DenseVector<double> r_mid(ORDER_OF_SYSTEM, 0.0);
117 er -> system_ptr -> source_fn(x_mid, q_mid, slope, r_mid);
118 deltaQ += r_mid * first_dt;
119 }
120 er -> set_Q_mid(er -> get_Q(0.0) + deltaQ);
121 // the flux out right in this elt is the flux in left of the next one
122 flux_in_left = flux_out_right;
123 ++er;
124 }
125 }
126
127 // compute the slopes using the specified limiter for the red elements
128 calc_slopes(&RED_ELTS);
129 MESH_TIME += first_dt;
130 return first_dt;
131 }
132
133 double update_to_black(const double& CFL, const double& max_dt) {
134 // integrate the red mesh data back onto the black mesh
135 {
136 elt_iter eb = BLACK_ELTS.begin();
137 while(eb != BLACK_ELTS.end()) {
138 eb -> set_Q_mid(eb -> contributed_Q() / eb -> get_dx());
139 ++eb;
140 }
141 }
142 // step thru the red elements to find a max time step
143 double second_dt;
144 {
145 elt_iter er = RED_ELTS.begin();
146 second_dt = er -> get_max_dt();
147 ++er;
148 while(er != RED_ELTS.end()) {
149 second_dt = std::min(second_dt, er -> get_max_dt());
150 ++er;
151 }
152 second_dt *= CFL;
153 }
154 if(second_dt > max_dt) {
155 second_dt = max_dt;
156 }
157
158 calc_slopes(&BLACK_ELTS);
159 // compute the fluxes through the element boundaries
160 // in the black mesh, using the nodal values of the red mesh
161 // then update the concentrations in the black mesh elements
162 {
163 elt_iter eb = BLACK_ELTS.begin();
164 DenseVector<double> flux_in_left(ORDER_OF_SYSTEM, 0.0);
165 DenseVector<double> flux_out_right(ORDER_OF_SYSTEM, 0.0);
166 // start with the left most elt & work out the flux in from the left
167 eb -> contributed_flux_in_left(second_dt, flux_in_left, MESH_TIME);
168 while(eb != BLACK_ELTS.end()) {
169 // work out the flux out to the right
170 eb -> contributed_flux_out_right(second_dt, flux_out_right, MESH_TIME);
171 // we now have the flux difference
172 DenseVector<double> deltaQ = (flux_in_left - flux_out_right) * second_dt / eb -> get_dx();
173 // contribution from the source integral
174 {
175 double x_mid(eb -> get_x(0.0));
176 DenseVector<double> q_mid(eb -> get_Q(0.0));
177 DenseVector<double> slope(eb -> get_slope());
178 q_mid += (eb -> get_source_fn(0.0)
179 - eb -> get_Jac_flux_fn(0.0).multiply(slope)) * 0.5 * second_dt;
180 DenseVector<double> r_mid(ORDER_OF_SYSTEM, 0.0);
181 eb -> system_ptr -> source_fn(x_mid, q_mid, slope, r_mid);
182 deltaQ += r_mid * second_dt;
183 }
184 eb -> set_Q_mid(eb -> get_Q(0.0) + deltaQ);
185 // the flux out right in this elt is the flux in left of the next one
186 flux_in_left = flux_out_right;
187 ++eb;
188 }
189 }
190
191 // compute the slopes using the specified limiter
192 // for the black elements
193 calc_slopes(&BLACK_ELTS);
194 MESH_TIME += second_dt;
195 return second_dt;
196
197 }
198
199 /// Get a const reference to the time value for the current mesh.
200 /// \return time The time level at which the data in the mesh applies.
201 const double& get_time() const;
202
203 /// Integrate the concentration values across the entire mesh.
204 /// \return The values of the integral of each component.
206
207 /// Get a OneD_Mesh<double> object containing the one dimensional
208 /// data in the usual format.
209 /// \param location Use "centre" for mid-elt values and "face_average" for
210 /// the average values at the (discontinuous) element boundaries
211 /// \param colour Which mesh to output, unless debugging, this should be "black"
212 /// otherwise time values will be slightly out
213 /// \return The required mesh object
214 OneD_Node_Mesh<double> get_soln(std::string location = "centre", std::string colour = "black");
215
217 vector_of_elts* elts(get_elts_from_colour("black"));
219 // the variables are the slope for each variable
220 OneD_Node_Mesh<double> slope_mesh(X, ORDER_OF_SYSTEM);
221 for(std::size_t i = 0; i < X.size(); ++i) {
222 slope_mesh.set_nodes_vars(i, (*elts)[i].get_slope());
223 }
224 return slope_mesh;
225 }
226
227 private:
228
229 /// Loops through all the elements. For any elements on the
230 /// boundary, we set the mid-nodal concentration to be the value
231 /// on the wall, as specified by the edge_values method
232 /// of the Hyperbolic sytem object.
233 /// \param elts A vector of elts to be looped through
234 void set_boundary_Q(vector_of_elts* elts);
235
236 /// Given a choice of black or red mesh, return a pointer
237 /// to the appropriate vector of elements.
238 /// \param mesh_colour A mesh identifier (black or red)
239 /// \return A pointer to a std::vector of elements
240 vector_of_elts* get_elts_from_colour(std::string mesh_colour);
241
242 /// Use the appropriate limiter to approximate the slope in each
243 /// element in the mesh. The slopes will be sent down to the element
244 /// objects.
245 /// \param elt_vector The vector of elements to set the slope for
246 void calc_slopes(vector_of_elts* elt_vector);
247
248 /// Compute the left-face difference.
249 /// We dont worry about which way is up/down wind because
250 /// we will only use limiters that treat up/down symmetrically.
251 /// \param e An iterator reference to an element
252 /// \return An approximation to the leftward differece
253 DenseVector<double> left_diff(elt_iter e);
254
255 /// Compute the right-face difference.
256 /// We dont worry about which way is up/down wind because
257 /// we will only use limiters that treat up/down symmetrically.
258 /// \param k An iterator reference to an element
259 /// \return An approximation to the rightward differece
260 DenseVector<double> right_diff(elt_iter e);
261
262 /// Sign of a double.
263 /// \param a The value to return the sign of
264 /// \return The sign of the value
265 int sgn(double a);
266
267 /// Returns the minimum of the absolute value of the two arguments
268 /// if both arguments are of the same sign.
269 /// \param a First element to compare
270 /// \param b Second element to compare
271 /// \return a if |a|<|b| and a*b > 0, b if |b|<|a| and a*b >0,
272 /// otherwise return zero
273 double minmod(double a, double b);
274
275 /// Returns the maximum of the absolute value of the two arguments
276 /// if both arguments are of the same sign.
277 /// \param a First element to compare
278 /// \param b Second element to compare
279 /// \return a if |a|>|b| and a*b > 0, b if |b|>|a| and a*b >0,
280 /// otherwise return zero
281 double maxmod(double a, double b);
282
283 /// A vector version of the minmod operator
284 /// \param A A vector to compare
285 /// \param B A vector to compare
286 /// \return A component-wise minmod vector, i.e., each component
287 /// of the returned vector is the minmod of the components of A & B.
289
290 /// A vector version of the maxmod operator
291 /// \param A A vector to compare
292 /// \param B A vector to compare
293 /// \return A component-wise maxmod vector, i.e., each component
294 /// of the returned vector is the maxmod of the components of A & B.
296
297 /// The time level of this mesh solution
298 double MESH_TIME;
299 /// Slope limiter method
300 unsigned LIMITER;
301 /// order of the conservative system
302 std::size_t ORDER_OF_SYSTEM;
303
304 /// An STL vector of linear elements -- the black mesh
305 vector_of_elts BLACK_ELTS;
306 /// An STL vector of linear elements -- the red mesh
307 vector_of_elts RED_ELTS;
308 /// function pointer to a function that defines the initial distribution
309 fn_ptr p_Q_INIT;
310
311 };
312
313}
314
315#endif // end OneD_TVDLF_Mesh_H
A specification for a one dimensional mesh object.
Specification of a one dimensional linear element for use in a TVD Lax-Friedrichs scheme.
Some standard typedefs.
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
std::size_t size() const
A pass-thru definition to get the size of the vector.
Definition: DenseVector.h:330
A class to represent a one dimensional hyperbolic system of equations.
A one dimensional mesh utility object.
void set_nodes_vars(const std::size_t node, const DenseVector< _Type > &u)
Set the variables stored at A SPECIFIED node.
void update_to(const double &CFL, const double &t_end)
Update all the elements in this mesh to a USER SPECIFIED time step.
const double & get_time() const
Get a const reference to the time value for the current mesh.
OneD_Node_Mesh< double > get_soln(std::string location="centre", std::string colour="black")
Get a OneD_Mesh<double> object containing the one dimensional data in the usual format.
double update_to_black(const double &CFL, const double &max_dt)
double update_to_red(const double &CFL, const double &max_dt)
~OneD_TVDLF_Mesh()
Empty desctructor.
double update(const double &CFL, const double &max_dt=std::numeric_limits< long double >::max())
Update all the elements in this mesh to a new time step.
DenseVector< double > get_mid_node_vector() const
Get the nodal positions in the middle of each element.
void set_limiter(unsigned id)
Set the limiter type to be applied in the slope values.
DenseVector< double > integrate() const
Integrate the concentration values across the entire mesh.
OneD_Node_Mesh< double > get_slope()
DenseVector< double > get_face_pos_vector() const
Get the positions of the element faces.
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt