CppNoddy  0.92
Loading...
Searching...
No Matches
OneD_TVDLF_Mesh.cpp
Go to the documentation of this file.
1/// \file OneD_TVDLF_Mesh.cpp
2/// Implementation of an object that represents a one dimensional
3/// mesh for TVD LF methods.
4
5#include <vector>
6
7#include <Types.h>
8#include <OneD_TVDLF_Elt.h>
9#include <OneD_Node_Mesh.h>
11#include <OneD_TVDLF_Mesh.h>
12
13namespace CppNoddy {
14 /// Constructor for the Finite Volume Mesh using linear elements
15 /// \param X A vector of nodal locations at which the element
16 /// FACES will positioned
19 fn_ptr init_ptr) {
20 MESH_TIME = 0.0;
21#ifdef DEBUG
22 std::cout << "DEBUG: Starting construction of a OneD_TVDLF_Mesh object. \n";
23#endif
24 unsigned N = X.size();
25 if(N <= 2) {
26 std::string problem;
27 problem = " The OneD_TVDLF_Mesh object is trying to construct itself \n";
28 problem += " with just one element! \n";
29 throw ExceptionRuntime(problem);
30 }
31#ifdef DEBUG
32 std::cout << "\nDEBUG: configuration of the black mesh \n";
33#endif
34 // set up the fn ptr to the initial conditions fn
35 p_Q_INIT = init_ptr;
36 // store the order of the conservative system here for simplicity
37 ORDER_OF_SYSTEM = ptr -> get_order();
38
39 // set up the black elements
40 {
41 // first elt
42 BLACK_ELTS.push_back(OneD_TVDLF_Elt(X[0], X[1], ptr, true, -1));
43 for(std::size_t i = 1; i <= N - 3; ++i) {
44 // interior elts
45 BLACK_ELTS.push_back(OneD_TVDLF_Elt(X[i], X[i+1], ptr));
46 }
47 // last elt
48 BLACK_ELTS.push_back(OneD_TVDLF_Elt(X[N-2], X[N-1], ptr, true, 1));
49 }
50#ifdef DEBUG
51 std::cout << "\nDEBUG: configuration of the red mesh \n";
52#endif
53 // set up the red elements
54 {
55 // first elt
56 RED_ELTS.push_back(OneD_TVDLF_Elt(X[0], (X[1] + X[0]) / 2, ptr, true, -1));
57 // interior elts
58 for(std::size_t i = 1; i <= N - 2; ++i) {
59 // interior elts
60 RED_ELTS.push_back(OneD_TVDLF_Elt((X[i-1] + X[i]) / 2, (X[i] + X[i+1]) / 2, ptr));
61 }
62 // last elt
63 RED_ELTS.push_back(OneD_TVDLF_Elt((X[N-2] + X[N-1]) / 2, X[N-1], ptr, true, 1));
64 }
65#ifdef DEBUG
66 std::cout << "\nDEBUG: linking the two meshes \n";
67#endif
68 // the only tricky part for this scheme is the mesh interconnections
69 // black to red is easy enough
70 elt_iter er = RED_ELTS.begin();
71 elt_iter eb = BLACK_ELTS.begin();
72 DenseVector<double> s_left(2, 0.);
73 s_left[ 0 ] = -1.;
74 s_left[ 1 ] = 0.;
75 DenseVector<double> s_right(2, 0.);
76 s_right[ 0 ] = 0.;
77 s_right[ 1 ] = 1.;
78 DenseVector<double> s_whole(2, 0.);
79 s_whole[ 0 ] = -1.;
80 s_whole[ 1 ] = 1.;
81 DenseVector<double> s_gen(2, 0.);
82 // loop over red elts -- and define which black elts contribute
83 // this is straightforward, even for nonuniform meshes.
84 while(er != RED_ELTS.end()) {
85 if(er -> get_external_flag()) {
86 // if its an external elt
87 if(er -> get_external_face_i() < 0) {
88 // and external face is left
89 er -> add_contribution(&(*eb), s_left, 1);
90 ++er;
91 } else {
92 // and external face is right
93 er -> add_contribution(&(*eb), s_right, -1);
94 ++er;
95 }
96 } else {
97 //internal elt
98 er -> add_contribution(&(*eb), s_right, -1);
99 ++eb;
100 er -> add_contribution(&(*eb), s_left, 1);
101 ++er;
102 }
103 }
104 // loop over all black elts and define which red elts contribute
105 // this is more involved if we allow for non-uniform meshes.
106 eb = BLACK_ELTS.begin();
107 er = RED_ELTS.begin();
108 while(eb != BLACK_ELTS.end()) {
109 if(eb -> get_external_flag()) {
110 // if its an external elt
111 if(eb -> get_external_face_i() < 0) {
112 // and external face is left
113 eb -> add_contribution(&(*er), s_whole, 0);
114 ++er;
115 double s = er -> get_s(eb -> get_x(1.0));
116 s_gen[ 0 ] = -1.0;
117 s_gen[ 1 ] = s;
118 eb -> add_contribution(&(*er), s_gen, 1);
119 ++eb;
120 } else {
121 // and external face is right
122 double s = er -> get_s(eb -> get_x(-1.0));
123 s_gen[ 0 ] = s;
124 s_gen[ 1 ] = 1.0;
125 eb -> add_contribution(&(*er), s_gen, -1);
126 ++er;
127 eb -> add_contribution(&(*er), s_whole, 0);
128 ++eb;
129 }
130 } else {
131 // internal elt
132 double s = er -> get_s(eb -> get_x(-1.0));
133 s_gen[ 0 ] = s;
134 s_gen[ 1 ] = 1.0;
135 eb -> add_contribution(&(*er), s_gen, -1);
136 ++er;
137 s = er -> get_s(eb -> get_x(1.0));
138 s_gen[ 0 ] = -1.0;
139 s_gen[ 1 ] = s;
140 eb -> add_contribution(&(*er), s_gen, 1);
141 ++eb;
142 }
143 }
144
145#ifdef DEBUG
146 std::cout << "DEBUG: Setting the initial state of the meesh. \n";
147#endif
148 // set the initial condition for each elt
149 eb = BLACK_ELTS.begin();
150 while(eb != BLACK_ELTS.end()) {
151 DenseVector<double> Q(ORDER_OF_SYSTEM, 0.0);
152 p_Q_INIT(eb -> get_x(0.0), Q);
153 eb -> set_Q_mid(Q);
154 ++eb;
155 }
156
157 //eb = BLACK_ELTS.end();
158 //--eb;
159 //std::cout << "Last elt = " << eb -> get_Q( 0.0 )[ 1 ] << "\n";
160 //std::cout << "size = " << eb -> get_dx() << "\n";
161 //--eb;
162 //std::cout << "Last elt = " << eb -> get_Q( 0.0 )[ 1 ] << "\n";
163 //std::cout << "size = " << eb -> get_dx() << "\n";
164
165 //DenseVector<double> x( get_mid_node_vector() );
166 //OneD_Mesh<double> soln( x );
167 //soln.set_nvars( ORDER_OF_SYSTEM );
168 //for ( std::size_t i = 0; i < x.size(); ++i )
169 //{
170 //soln.set_nodes_vars( i, BLACK_ELTS[i].get_Q( 0.0 ) );
171 //std::cout << "Get_soln Q = " << soln.get_nodes_vars( i )[ 1 ] << " at x = " << x[i] << "\n";
172 //}
173
174 // default limiter = 0 (minmod)
175 LIMITER = 0;
176 calc_slopes(&BLACK_ELTS);
177
178#ifdef DEBUG
179 std::cout << "DEBUG: Finished construction of a OneD_TVDLF_Mesh object. \n";
180#endif
181 }
182
184 {}
185
188 celt_iter e = BLACK_ELTS.begin();
189 while(e != BLACK_ELTS.end()) {
190 X.push_back(e -> get_x(0.0));
191 ++e;
192 }
193 return X;
194 }
195
198 celt_iter e = BLACK_ELTS.begin();
199 while(e != BLACK_ELTS.end()) {
200 X.push_back(e -> get_x(-1.0));
201 ++e;
202 }
203 --e;
204 X.push_back(e -> get_x(1.0));
205 return X;
206 }
207
209 LIMITER = id;
210 }
211
212 double OneD_TVDLF_Mesh::update(const double& CFL, const double& max_dt) {
213 double first_dt = update_to_red(CFL, max_dt / 2.0);
214 double second_dt = update_to_black(CFL, max_dt - first_dt);
215 return first_dt + second_dt;
216 }
217
218 void OneD_TVDLF_Mesh::update_to(const double& CFL, const double& t_end) {
219 do {
220 update(CFL, std::abs(t_end - MESH_TIME));
221 } while(MESH_TIME < t_end);
222 }
223
224 const double& OneD_TVDLF_Mesh::get_time() const {
225 return MESH_TIME;
226 }
227
229 celt_iter e = BLACK_ELTS.begin();
230 DenseVector<double> sum(ORDER_OF_SYSTEM, 0.0);
231 while(e != BLACK_ELTS.end()) {
232 sum += e -> get_Q(0.0) * e -> get_dx();
233 ++e;
234 }
235 return sum;
236 }
237
238 OneD_Node_Mesh<double> OneD_TVDLF_Mesh::get_soln(std::string location, std::string mesh_colour) {
239 vector_of_elts* elts(get_elts_from_colour(mesh_colour));
241 if(location == "centre") {
243 soln = OneD_Node_Mesh<double>(X, ORDER_OF_SYSTEM);
244 for(std::size_t i = 0; i < X.size(); ++i) {
245 soln.set_nodes_vars(i, (*elts)[i].get_Q(0.0));
246 }
247 } else if(location == "face_average") {
249 soln = OneD_Node_Mesh<double>(X, ORDER_OF_SYSTEM);
250 std::size_t N = X.size() - 1;
251 soln.set_nodes_vars(0, (*elts)[0].get_Q(-1.0));
252 for(std::size_t i = 1; i < N; ++i) {
253 soln.set_nodes_vars(i, ((*elts)[i-1].get_Q(1.0) + (*elts)[i].get_Q(-1.0)) / 2);
254 }
255 soln.set_nodes_vars(N, (*elts)[N-1].get_Q(1.0));
256 } else {
257 std::string problem;
258 problem = " In OneD_TVDLF_Mesh::get_soln you have passed an unrecognised ";
259 problem += " location for data output. Use 'centre' or 'face_average'. \n";
260 throw ExceptionRuntime(problem);
261 }
262
263 return soln;
264 }
265
266 void OneD_TVDLF_Mesh::calc_slopes(vector_of_elts* elt_vector) {
267 set_boundary_Q(elt_vector);
268 elt_iter e = elt_vector -> begin();
269 DenseVector<double> slope(ORDER_OF_SYSTEM, 0.0);
270 // having computed the right-slope in elt-i we know the left-slope in elt-i+1
271 DenseVector<double> left = left_diff(e);
272 DenseVector<double> right(ORDER_OF_SYSTEM, 0.0);
273 switch(LIMITER) {
274 case 0:
275 while(e != elt_vector -> end()) {
276 // minmod
277 right = right_diff(e);
278 slope = minmod(left, right);
279 e -> set_slope(slope);
280 left = right;
281 ++e;
282 }
283 break;
284 case 1:
285 while(e != elt_vector -> end()) {
286 right = right_diff(e);
287 slope = maxmod(
288 minmod(right, left * 2.),
289 minmod(right * 2., left)
290 );
291 left = right;
292 e -> set_slope(slope);
293 ++e;
294 }
295 break;
296 default:
297 std::string problem;
298 problem = " The OneD_TVDLF_Mesh object has an unrecognised 'limiter' identifier. \n";
299 throw ExceptionRuntime(problem);
300 }
301 }
302
303 std::vector<OneD_TVDLF_Elt>* OneD_TVDLF_Mesh::get_elts_from_colour(std::string mesh_colour) {
304 vector_of_elts* elts;
305 if(mesh_colour == "black") {
306 elts = &BLACK_ELTS;
307 } else if(mesh_colour == "red") {
308 elts = &RED_ELTS;
309 } else {
310 std::string problem;
311 problem = " The TwoD_TVDLF_Mesh object has been passed an unrecognised mesh identifier. \n";
312 problem += " valid options are 'black' or 'red'.\n";
313 throw ExceptionRuntime(problem);
314 }
315 return elts;
316 }
317
318 void OneD_TVDLF_Mesh::set_boundary_Q(vector_of_elts* elts) {
319 // loop over all elts
320 elt_iter e(elts -> begin());
321 while(e != elts -> end()) {
322 // only consider the external elts
323 if(e -> get_external_flag()) {
324 // get local coord and index of the external 'face'
325 double s;
326 int face;
327 if(e -> get_external_face_i() < 0) {
328 // left is external
329 face = -1;
330 s = -1.0;
331 } else {
332 // right is external
333 face = 1;
334 s = 1.0;
335 }
336 // get the edge value
337 DenseVector<double> Qe(e -> get_Q(s));
338 // allow the user to overwrite this value
339 std::vector<bool> inflow = e -> system_ptr -> edge_values(face, e -> get_x(s), Qe, MESH_TIME);
340 DenseVector<double> Qm(e -> get_Q(0.0));
341 // if the value has been specified as inflow
342 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
343 // make the nodal value the edge value
344 if(inflow[ i ] == true) {
345 Qm[ i ] = Qe[ i ];
346 }
347 }
348 e -> set_Q_mid(Qm);
349 }
350 ++e;
351 }
352 }
353
354 DenseVector<double> OneD_TVDLF_Mesh::left_diff(elt_iter e) {
355 DenseVector<double> diff(ORDER_OF_SYSTEM, 0.0);
356 if(e -> get_external_face_i() < 0) {
357 // interior difference
358 diff = right_diff(e);
359 // now set the deriv to zero for any inflow BCs
360 //
361 // get the edge value
362 DenseVector<double> Qe(e -> get_Q(-1.0));
363 // allow the user to overwrite this value
364 std::vector<bool> inflow = e -> system_ptr -> edge_values(-1, e -> get_x(-1.0), Qe, MESH_TIME);
365 // if the value has been specified as inflow
366 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
367 // set a zero slope as per Levy & Tadmor (1997)
368 if(inflow[ i ] == true) {
369 diff[ i ] = 0.0;
370 }
371 }
372 } else {
373 // We're not on an edge, so we can difference
374 elt_iter j(e);
375 --j;
376 diff = (e -> get_Q(0.0) - j -> get_Q(0.0))
377 / (e -> get_x(0.0) - j -> get_x(0.0));
378 }
379 return diff;
380 }
381
382 DenseVector<double> OneD_TVDLF_Mesh::right_diff(elt_iter e) {
383 DenseVector<double> diff(ORDER_OF_SYSTEM, 0.0);
384 //if ( ( e -> get_external_flag() ) && ( e -> get_external_face_i() > 0 ) )
385 if(e -> get_external_face_i() > 0) {
386 // interior difference
387 diff = left_diff(e);
388 // now set the deriv to zero for any inflow BCs
389 //
390 // get the edge value
391 DenseVector<double> Qe(e -> get_Q(1.0));
392 // allow the user to overwrite this value
393 std::vector<bool> inflow = e -> system_ptr -> edge_values(1, e -> get_x(1.0), Qe, MESH_TIME);
394 DenseVector<double> Qm(e -> get_Q(0.0));
395 // if the value has been specified as inflow
396 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
397 // set a zero slope as per Levy & Tadmor (1997)
398 if(inflow[ i ] == true) {
399 diff[ i ] = 0.0;
400 }
401 }
402 } else {
403 // We're not on an edge, so we can difference
404 elt_iter j(e);
405 ++j;
406 diff = (j -> get_Q(0.0) - e -> get_Q(0.0))
407 / (j -> get_x(0.0) - e -> get_x(0.0));
408 }
409 return diff;
410 }
411
412 int OneD_TVDLF_Mesh::sgn(double a) {
413 if(a > 0.0) {
414 return 1;
415 } else if(a < 0.0) {
416 return -1;
417 } else {
418 return 0;
419 }
420 }
421
422 double OneD_TVDLF_Mesh::minmod(double a, double b) {
423 return 0.5 * (sgn(a) + sgn(b))
424 * std::min(std::abs(a), std::abs(b));
425 }
426
427 double OneD_TVDLF_Mesh::maxmod(double a, double b) {
428 return 0.5 * (sgn(a) + sgn(b))
429 * std::max(std::abs(a), std::abs(b));
430 }
431
432 DenseVector<double> OneD_TVDLF_Mesh::minmod(DenseVector<double> A, DenseVector<double> B) {
433 DenseVector<double> MM;
434 for(std::size_t i = 0; i < A.size(); ++i) {
435 MM.push_back(0.5 * (sgn(A[i]) + sgn(B[i]))
436 * std::min(std::abs(A[i]), std::abs(B[i])));
437 }
438 return MM;
439 }
440
441 DenseVector<double> OneD_TVDLF_Mesh::maxmod(DenseVector<double> A, DenseVector<double> B) {
442 DenseVector<double> MM;
443 for(std::size_t i = 0; i < A.size(); ++i) {
444 MM.push_back(0.5 * (sgn(A[i]) + sgn(B[i]))
445 * std::max(std::abs(A[i]), std::abs(B[i])));
446 }
447 return MM;
448 }
449
450}
A specification for a one dimensional mesh object.
Specification of a one dimensional linear element for use in a TVD Lax-Friedrichs scheme.
Specification of an object that represents a one dimensional mesh for TVD LX methods.
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
void push_back(const _Type &fill)
A pass-thru definition of push_back.
Definition: DenseVector.h:310
std::size_t size() const
A pass-thru definition to get the size of the vector.
Definition: DenseVector.h:330
A generic runtime exception.
Definition: Exceptions.h:158
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.
A Linear Element class.
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.
OneD_TVDLF_Mesh(const DenseVector< double > &X, OneD_Hyperbolic_System *ptr, fn_ptr init_ptr)
Constructor for the Finite Volume Mesh using linear elements.
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.
DenseVector< double > get_face_pos_vector() const
Get the positions of the element faces.
double A(1.0)
initial hump amplitude
double s
relative rotation rate
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt