CppNoddy  0.92
Loading...
Searching...
No Matches
TwoD_TVDLF_Mesh.cpp
Go to the documentation of this file.
1
2/// \file TwoD_TVDLF_Mesh.cpp
3/// Implementation of an object that represents a two dimensional
4/// mesh for TVD LF methods.
5
6#include <vector>
7#include <algorithm>
8
9#include <Types.h>
10#include <TwoD_TVDLF_Elt.h>
12#include <TwoD_TVDLF_Mesh.h>
13
14namespace CppNoddy {
15
18 fn_ptr init_ptr) {
19
20#ifdef DEBUG
21 std::cout << "DEBUG: Starting construction of a TwoD_TVDLF_Mesh object. \n";
22#endif
23 MESH_TIME = 0.0;
24 NX = X.size();
25 NY = Y.size();
26 if(std::min(NX - 1, NY - 1) <= 1) {
27 std::string problem;
28 problem = " The TwoD_TVDLF_Mesh object is trying to construct itself \n";
29 problem += " with just one element in one of the directions! \n";
30 throw ExceptionRuntime(problem);
31 }
32
33#ifdef DEBUG
34 std::cout << "DEBUG: configuration of the black mesh \n";
35#endif
36
37 // reserve appropriate space to avoid re-allocation later
38 BLACK_ELTS.reserve((NX - 1) * (NY - 1));
39 RED_ELTS.reserve(NX * NY);
40
41 // set up the fn ptr to the initial conditions fn
42 p_Q_INIT = init_ptr;
43 // default limiter
44 LIMITER = 0;
45 // store the order of the conservative system here for simplicity
46 ORDER_OF_SYSTEM = ptr -> get_order();
47
48 // face index of edges
49 std::set<int> faces_s;
50 faces_s.insert(0);
51 std::set<int> faces_e;
52 faces_e.insert(1);
53 std::set<int> faces_n;
54 faces_n.insert(2);
55 std::set<int> faces_w;
56 faces_w.insert(3);
57 // face indices of corners
58 std::set<int> faces_se(faces_s);
59 faces_se.insert(1);
60 std::set<int> faces_ne(faces_n);
61 faces_ne.insert(1);
62 std::set<int> faces_nw(faces_n);
63 faces_nw.insert(3);
64 std::set<int> faces_sw(faces_s);
65 faces_sw.insert(3);
66 // set up the black elements
67 {
68 // southern row
69 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[0], X[1], Y[0], Y[1], ptr, true, faces_sw));
70 for(std::size_t i = 1; i <= NX - 3; ++i) {
71 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[i], X[i+1], Y[0], Y[1], ptr, true, faces_s));
72 }
73 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[NX-2], X[NX-1], Y[0], Y[1], ptr, true, faces_se));
74 // interior elts
75 for(std::size_t j = 1; j <= NY - 3; ++j) {
76 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[0], X[1], Y[j], Y[j+1], ptr, true, faces_w));
77 for(std::size_t i = 1; i <= NX - 3; ++i) {
78 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[i], X[i+1], Y[j], Y[j+1], ptr));
79 }
80 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[NX-2], X[NX-1], Y[j], Y[j+1], ptr, true, faces_e));
81 }
82 // northern row
83 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[0], X[1], Y[NY-2], Y[NY-1], ptr, true, faces_nw));
84 for(std::size_t i = 1; i <= NX - 3; ++i) {
85 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[i], X[i+1], Y[NY-2], Y[NY-1], ptr, true, faces_n));
86 }
87 BLACK_ELTS.push_back(TwoD_TVDLF_Elt(X[NX-2], X[NX-1], Y[NY-2], Y[NY-1], ptr, true, faces_ne));
88 }
89
90#ifdef DEBUG
91 std::cout << "DEBUG: configuration of the red mesh \n";
92#endif
93
94 // set up the red elements
95 {
96 // southern row
97 RED_ELTS.push_back(TwoD_TVDLF_Elt(X[0], (X[1] + X[0]) / 2, Y[0], (Y[0] + Y[1]) / 2, ptr, true, faces_sw));
98 for(std::size_t i = 1; i <= NX - 2; ++i) {
99 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[i-1] + X[i]) / 2, (X[i] + X[i+1]) / 2, Y[0], (Y[0] + Y[1]) / 2, ptr, true, faces_s));
100 }
101 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[NX-2] + X[NX-1]) / 2, X[NX-1], Y[0], (Y[0] + Y[1]) / 2, ptr, true, faces_se));
102 // interior elts
103 for(std::size_t j = 1; j <= NY - 2; ++j) {
104 RED_ELTS.push_back(TwoD_TVDLF_Elt(X[0], (X[1] + X[0]) / 2, (Y[j-1] + Y[j]) / 2, (Y[j] + Y[j+1]) / 2, ptr, true, faces_w));
105 for(std::size_t i = 1; i <= NX - 2; ++i) {
106 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[i-1] + X[i]) / 2, (X[i] + X[i+1]) / 2, (Y[j-1] + Y[j]) / 2, (Y[j] + Y[j+1]) / 2, ptr));
107 }
108 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[NX-2] + X[NX-1]) / 2, X[NX-1], (Y[j-1] + Y[j]) / 2, (Y[j] + Y[j+1]) / 2, ptr, true, faces_e));
109 }
110 // northern row
111 RED_ELTS.push_back(TwoD_TVDLF_Elt(X[0], (X[1] + X[0]) / 2, (Y[NY-2] + Y[NY-1]) / 2, Y[NY-1], ptr, true, faces_nw));
112 for(std::size_t i = 1; i <= NX - 2; ++i) {
113 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[i-1] + X[i]) / 2, (X[i] + X[i+1]) / 2, (Y[NY-2] + Y[NY-1]) / 2, Y[NY-1], ptr, true, faces_n));
114 }
115 RED_ELTS.push_back(TwoD_TVDLF_Elt((X[NX-2] + X[NX-1]) / 2, X[NX-1], (Y[NY-2] + Y[NY-1]) / 2, Y[NY-1], ptr, true, faces_ne));
116 }
117
118#ifdef DEBUG
119 std::cout << "DEBUG: computing black to red projection \n";
120#endif
121
122 // Now we need to pre-compute the mesh projection from black-red-black.
123 // Each element needs to know which element in the other mesh contributes
124 // to it in the projection scheme. It also needs to know which of its faces
125 // the element contributes to in the flux computation.
126 // We assume the constructor is not required to be efficient & just brute
127 // force it here rather than working out all the index mappings by hand.
128 //
129 // loop through all the black elts
130 elt_iter eb = BLACK_ELTS.begin();
131 while(eb != BLACK_ELTS.end()) {
132 // local coordinates of the corners
133 DenseVector<double> ne(2, 1.0);
134 DenseVector<double> sw(-ne);
135 DenseVector<double> se(2, 1.0);
136 se[ 1 ] = -1.0;
137 DenseVector<double> nw(-se);
138 // global coordinates of the corners
139 DenseVector<double> bx_sw = eb -> get_x(sw);
140 DenseVector<double> bx_ne = eb -> get_x(ne);
141 DenseVector<double> bx_nw = eb -> get_x(nw);
142 DenseVector<double> bx_se = eb -> get_x(se);
143 // get an iterator to the red elt that contains each corner
144 // & add it as a contribution
145 //
146 // nw corner
147 {
148 //elt_iter er = get_elt_iter_from_x( bx_nw, "red" );
149 elt_iter er = get_elt_iter_from_elt_iter(eb, "red", 3);
150 DenseVector<double> s = er -> get_s(bx_nw);
151 DenseVector<double> s1(2, 0.0);
152 s1[ 0 ] = s[ 0 ];
153 s1[ 1 ] = -1.0;
154 DenseVector<double> s2(2, 0.0);
155 s2[ 0 ] = 1.0;
156 s2[ 1 ] = s[ 1 ];
157 eb -> add_contribution(&(*er), s1, s2, faces_nw);
158 }
159 // sw corner
160 {
161 //elt_iter er = get_elt_iter_from_x( bx_sw, "red" );
162 elt_iter er = get_elt_iter_from_elt_iter(eb, "red", 0);
163 DenseVector<double> s = er -> get_s(bx_sw);
164 DenseVector<double> s1(2, 0.0);
165 s1[ 0 ] = s[ 0 ];
166 s1[ 1 ] = s[ 1 ];
167 DenseVector<double> s2(2, 0.0);
168 s2[ 0 ] = 1.0;
169 s2[ 1 ] = 1.0;
170 eb -> add_contribution(&(*er), s1, s2, faces_sw);
171 }
172 // ne corner
173 {
174 //elt_iter er = get_elt_iter_from_x( bx_ne, "red" );
175 elt_iter er = get_elt_iter_from_elt_iter(eb, "red", 2);
176 DenseVector<double> s = er -> get_s(bx_ne);
177 DenseVector<double> s1(2, 0.0);
178 s1[ 0 ] = -1.0;
179 s1[ 1 ] = -1.0;
180 DenseVector<double> s2(2, 0.0);
181 s2[ 0 ] = s[ 0 ];
182 s2[ 1 ] = s[ 1 ];
183 eb -> add_contribution(&(*er), s1, s2, faces_ne);
184 }
185 // se corner
186 {
187 //elt_iter er = get_elt_iter_from_x( bx_se, "red" );
188 elt_iter er = get_elt_iter_from_elt_iter(eb, "red", 1);
189 DenseVector<double> s = er -> get_s(bx_se);
190 DenseVector<double> s1(2, 0.0);
191 s1[ 0 ] = -1.0;
192 s1[ 1 ] = s[ 1 ];
193 DenseVector<double> s2(2, 0.0);
194 s2[ 0 ] = s[ 0 ];
195 s2[ 1 ] = 1.0;
196 eb -> add_contribution(&(*er), s1, s2, faces_se);
197 }
198 ++eb;
199 }
200
201#ifdef DEBUG
202 std::cout << "DEBUG: computing red to black projection \n";
203#endif
204
205 // now we need to set up the projection from red to black elts.
206 // it's a little more tricky here as we have to avoid the external nodes.
207 elt_iter er = RED_ELTS.begin();
208 while(er != RED_ELTS.end()) {
209 // local coordinates of the corners
210 DenseVector<double> ne(2, 1.0);
211 DenseVector<double> sw(-ne);
212 DenseVector<double> se(2, 1.0);
213 se[ 1 ] = -1.0;
214 DenseVector<double> nw(-se);
215 // global coordinates of the corners
216 DenseVector<double> bx_sw = er -> get_x(sw);
217 DenseVector<double> bx_ne = er -> get_x(ne);
218 DenseVector<double> bx_nw = er -> get_x(nw);
219 DenseVector<double> bx_se = er -> get_x(se);
220 //
221 std::set<int> external = er -> get_external_faces();
222 if((external.find(2) == external.end()) &&
223 (external.find(3) == external.end())) {
224 // nw corner is internal
225 //elt_iter eb = get_elt_iter_from_x( bx_nw, "black" );
226 elt_iter eb = get_elt_iter_from_elt_iter(er, "black", 3);
227 DenseVector<double> s = eb -> get_s(bx_nw);
228 DenseVector<double> s1(2, 0.0);
229 s1[ 0 ] = s[ 0 ];
230 s1[ 1 ] = -1.0;
231 DenseVector<double> s2(2, 0.0);
232 s2[ 0 ] = 1.0;
233 s2[ 1 ] = s[ 1 ];
234 er -> add_contribution(&(*eb), s1, s2, faces_nw);
235 }
236 if((external.find(0) == external.end()) &&
237 (external.find(3) == external.end())) {
238 // sw corner is internal
239 //elt_iter eb = get_elt_iter_from_x( bx_sw, "black" );
240 elt_iter eb = get_elt_iter_from_elt_iter(er, "black", 0);
241 DenseVector<double> s = eb -> get_s(bx_sw);
242 DenseVector<double> s1(2, 0.0);
243 s1[ 0 ] = s[ 0 ];
244 s1[ 1 ] = s[ 1 ];
245 DenseVector<double> s2(2, 0.0);
246 s2[ 0 ] = 1.0;
247 s2[ 1 ] = 1.0;
248 er -> add_contribution(&(*eb), s1, s2, faces_sw);
249 }
250 if((external.find(1) == external.end()) &&
251 (external.find(2) == external.end())) {
252 // ne corner is internal
253 //elt_iter eb = get_elt_iter_from_x( bx_ne, "black" );
254 elt_iter eb = get_elt_iter_from_elt_iter(er, "black", 2);
255 DenseVector<double> s = eb -> get_s(bx_ne);
256 DenseVector<double> s1(2, 0.0);
257 s1[ 0 ] = -1.0;
258 s1[ 1 ] = -1.0;
259 DenseVector<double> s2(2, 0.0);
260 s2[ 0 ] = s[ 0 ];
261 s2[ 1 ] = s[ 1 ];
262 er -> add_contribution(&(*eb), s1, s2, faces_ne);
263 }
264 if((external.find(0) == external.end()) &&
265 (external.find(1) == external.end())) {
266 // se corner is internal
267 //elt_iter eb = get_elt_iter_from_x( bx_se, "black" );
268 elt_iter eb = get_elt_iter_from_elt_iter(er, "black", 1);
269 DenseVector<double> s = eb -> get_s(bx_se);
270 DenseVector<double> s1(2, 0.0);
271 s1[ 0 ] = -1.0;
272 s1[ 1 ] = s[ 1 ];
273 DenseVector<double> s2(2, 0.0);
274 s2[ 0 ] = s[ 0 ];
275 s2[ 1 ] = 1.0;
276 er -> add_contribution(&(*eb), s1, s2, faces_se);
277 }
278 ++er;
279 }
280
281#ifdef DEBUG
282 std::cout << "DEBUG: setting up pointers to NESW elts in black mesh\n";
283#endif
284
285 // we need to set the pointers to neighbouring elts in both meshes
286 eb = BLACK_ELTS.begin();
287 while(eb != BLACK_ELTS.end()) {
288 // the offset for computing N & S elts is no. of faces minus one
289 const std::size_t offset(NX - 1);
290 // get a set of external faces
291 std::set< int > faces(eb -> get_external_faces());
292 if(eb -> face_is_internal(0)) {
293 // southern face is internal
294 eb -> set_ptrs(0, &(*eb) - offset);
295 }
296 if(eb -> face_is_internal(1)) {
297 // eastern face is internal
298 eb -> set_ptrs(1, &(*eb) + 1);
299 }
300 if(eb -> face_is_internal(2)) {
301 // northern face is internal
302 eb -> set_ptrs(2, &(*eb) + offset);
303 }
304 if(eb -> face_is_internal(3)) {
305 // western face is internal
306 eb -> set_ptrs(3, &(*eb) - 1);
307 }
308 ++eb;
309 }
310
311#ifdef DEBUG
312 std::cout << "DEBUG: setting up pointers to NESW elts in red mesh\n";
313#endif
314
315 // we need to set the pointers to neighbouring elts in both meshes
316 er = RED_ELTS.begin();
317 while(er != RED_ELTS.end()) {
318 // the offset for computing N & S elts is no. of faces
319 // as the red mesh has an extra elt per row
320 const std::size_t offset(NX);
321 // get a set of external faces
322 std::set< int > faces(er -> get_external_faces());
323 if(er -> face_is_internal(0)) {
324 // southern face is internal
325 er -> set_ptrs(0, &(*er) - offset);
326 }
327 if(er -> face_is_internal(1)) {
328 // eastern face is internal
329 er -> set_ptrs(1, &(*er) + 1);
330 }
331 if(er -> face_is_internal(2)) {
332 // northern face is internal
333 er -> set_ptrs(2, &(*er) + offset);
334 }
335 if(er -> face_is_internal(3)) {
336 // western face is internal
337 er -> set_ptrs(3, &(*er) - 1);
338 }
339 ++er;
340 }
341
342#ifdef DEBUG
343 std::cout << "DEBUG: initialising the black mesh \n";
344#endif
345
346 // now all that remains is to initialise the starting (black) mesh
347 eb = BLACK_ELTS.begin();
348 while(eb != BLACK_ELTS.end()) {
349 DenseVector<double> s(2, 0.0);
350 // compute to the east
351 s[ 0 ] = 1.0;
352 s[ 1 ] = 0.0;
353 DenseVector<double> xe(eb -> get_x(s));
355 p_Q_INIT(xe[0], xe[1], Qe);
356 // compute to the west
357 s[ 0 ] = -1.0;
358 s[ 1 ] = 0.0;
359 DenseVector<double> xw(eb -> get_x(s));
361 p_Q_INIT(xw[0], xw[1], Qw);
362 // compute to the north
363 s[ 0 ] = 0.0;
364 s[ 1 ] = 1.0;
365 DenseVector<double> xn(eb -> get_x(s));
367 p_Q_INIT(xn[0], xn[1], Qn);
368 // compute to the north
369 s[ 0 ] = 0.0;
370 s[ 1 ] = -1.0;
371 DenseVector<double> xs(eb -> get_x(s));
373 p_Q_INIT(xs[0], xs[1], Qs);
374 // difference for the slopes
375 eb -> set_slope_x((Qe - Qw) / (xe[0] - xw[0]));
376 eb -> set_slope_y((Qn - Qs) / (xn[1] - xs[1]));
377 // set the mid value
378 eb -> set_Q_mid((Qe + Qw + Qn + Qs) / 4);
379 ++eb;
380 }
381
382#ifdef DEBUG
383 std::cout << "DEBUG: mesh constructor complete \n";
384#endif
385
386 // now all that remains is to initialise the starting (black) mesh
387 eb = BLACK_ELTS.begin();
388 while(eb != BLACK_ELTS.end()) {
389 DenseVector<double> x(2, 0.0);
390 DenseVector<double> s(2, 0.0);
391 x = eb -> get_x(s);
393 p_Q_INIT(x[0], x[1], Q);
394 eb -> set_Q_mid(Q);
395 ++eb;
396 }
397
399
400 }
401
403 {}
404
405 void TwoD_TVDLF_Mesh::dump_gnu(std::string filename) {
406 std::ofstream dump;
407 dump.open(filename.c_str());
408 dump.precision(6);
409 DenseVector<double> s(2, 0.0);
410 {
411 elt_iter e(BLACK_ELTS.begin());
412 while(e != BLACK_ELTS.end()) {
413 dump << e -> get_x(s)[0] << " " << e -> get_x(s)[1] << " ";
414 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
415 dump << e -> get_Q(s)[i] << " ";
416 }
417 dump << e -> get_max_dt();
418 // for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
419 // dump << e -> get_slope_x()[i] << " ";
420 // }
421 // for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
422 // dump << e -> get_slope_y()[i] << " ";
423 // }
424 dump << "\n";
425 if(e -> face_is_external(1))
426 dump << "\n";
427 ++e;
428 }
429 }
430 dump.close();
431 }
432
433 void TwoD_TVDLF_Mesh::dump_nodes_x(std::string filename) const {
434 std::ofstream dump;
435 dump.open(filename.c_str());
436 dump.precision(6);
437 DenseVector<double> s(2, 0.0);
438 celt_iter e;
439 {
440 e = BLACK_ELTS.begin();
441 for(unsigned i = 0; i < NX - 1; ++i) {
442 dump << e -> get_x(s)[0] << "\n";
443 ++e;
444 }
445 }
446 dump.close();
447 }
448
449 void TwoD_TVDLF_Mesh::dump_nodes_y(std::string filename) const {
450 std::ofstream dump;
451 dump.open(filename.c_str());
452 dump.precision(6);
453 DenseVector<double> s(2, 0.0);
454 celt_iter e;
455 {
456 e = BLACK_ELTS.begin();
457 for(unsigned i = 0; i < NY - 1; ++i) {
458 dump << e -> get_x(s)[1] << "\n";
459 e += NX - 1;
460 }
461 }
462 dump.close();
463 }
464
465 void TwoD_TVDLF_Mesh::dump_data(std::string filename) {
466 std::ofstream dump;
467 dump.open(filename.c_str());
468 dump.precision(6);
469 elt_iter e;
470 DenseVector<double> s(2, 0.0);
471 {
472 e = BLACK_ELTS.begin();
473 while(e != BLACK_ELTS.end()) {
474 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
475 dump << e -> get_Q(s)[i] << " ";
476 }
477 dump << e -> get_max_dt() << " ";
478 // for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
479 // dump << e -> get_slope_x()[i] << " ";
480 // }
481 // for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
482 // dump << e -> get_slope_y()[i] << " ";
483 // }
484 dump << "\n";
485 ++e;
486 }
487 }
488 dump.close();
489 }
490
493 DenseVector<double> s(e-> get_s(x));
494 return e -> get_Q(s);
495 }
496
497 void TwoD_TVDLF_Mesh::set_limiter(const unsigned& id) {
498 LIMITER = id;
499 }
500
501 double TwoD_TVDLF_Mesh::update(const double& CFL, const double& max_dt) {
502 // integrate the black mesh data onto the red mesh
503 std::cout << "[DEBUG] in update with MESH_TIME = " << MESH_TIME << "\n";
504 std::cout << "[DEBUG] in update with max_dt = " << max_dt << "\n";
505
506 {
507 elt_iter e = RED_ELTS.begin();
508 while(e != RED_ELTS.end()) {
509 e -> set_Q_mid(e -> contributed_Q() / e -> get_dA());
510 ++e;
511 }
512 }
514
515 // determine the first time step from the CFL constraint
516 double first_dt;
517 {
518 elt_iter e = BLACK_ELTS.begin();
519 first_dt = e -> get_max_dt();
520 ++e;
521 while(e != BLACK_ELTS.end()) {
522 first_dt = std::min(first_dt, e -> get_max_dt());
523 ++e;
524 }
525 std::cout << "[DEBUG] in update with first_dt = " << first_dt << "\n";
526 first_dt *= CFL;
527 std::cout << "[DEBUG] in update with first_dt*CFL = " << first_dt << "\n";
528 }
529 if(first_dt > max_dt / 2) {
530 first_dt = max_dt / 2;
531 }
532 std::cout << "[DEBUG] in update with final first_dt = " << first_dt << "\n";
533
535 // do the time step
536 {
537 elt_iter e = RED_ELTS.begin();
538 while(e != RED_ELTS.end()) {
539 // add to the corrections
540 e -> add_flux_contributions(first_dt);
541 ++e;
542 }
543 }
545 MESH_TIME += first_dt;
546 std::cout << "[DEBUG] in update with MESH_TIME = " << MESH_TIME << "\n";
547
548 // integrate the red mesh data onto the black mesh
549 {
550 elt_iter e = BLACK_ELTS.begin();
551 while(e != BLACK_ELTS.end()) {
552 e -> set_Q_mid(e -> contributed_Q() / e -> get_dA());
553 ++e;
554 }
555 }
557
558 // determine the first time step from the CFL constraint
559 double second_dt;
560 {
561 elt_iter e = RED_ELTS.begin();
562 second_dt = e -> get_max_dt();
563 ++e;
564 while(e != RED_ELTS.end()) {
565 second_dt = std::min(second_dt, e -> get_max_dt());
566 ++e;
567 }
568 std::cout << "[DEBUG] in update with second_dt = " << second_dt << "\n";
569 second_dt *= CFL;
570 std::cout << "[DEBUG] in update with second_dt*CFL = " << second_dt << "\n";
571 }
572 if(first_dt + second_dt > max_dt) {
573 second_dt = max_dt - first_dt;
574 }
575 std::cout << "[DEBUG] in update with final second_dt = " << second_dt << "\n";
576
577 actions_before_time_step2(second_dt);
578 // do the time step
579 {
580 elt_iter e = BLACK_ELTS.begin();
581 while(e != BLACK_ELTS.end()) {
582 // add to the corrections
583 e -> add_flux_contributions(second_dt);
584 ++e;
585 }
586 }
588 MESH_TIME += second_dt;
589 std::cout << "[DEBUG] in update with MESH_TIME = " << MESH_TIME << "\n";
590
591 return first_dt + second_dt;
592 }
593
594 void TwoD_TVDLF_Mesh::update_to(const double& CFL, const double& t_end) {
595 do {
596 std::cout << " computing to " << t_end << "\n";
597 update(CFL, std::abs(t_end - MESH_TIME));
598 } while(MESH_TIME < t_end);
599 }
600
601 const double& TwoD_TVDLF_Mesh::get_time() const {
602 return MESH_TIME;
603 }
604
606 vector_of_elts* elts(get_elts_from_colour(mesh_colour));
607 elt_iter e = elts -> begin();
609 while(e != elts -> end()) {
610 const DenseVector<double> sw(2, -1.0);
611 const DenseVector<double> ne(2, 1.0);
612 I += e -> get_int_Q(sw, ne);
613 ++e;
614 }
615 return I;
616 }
617
618 std::vector<TwoD_TVDLF_Elt>::iterator TwoD_TVDLF_Mesh::get_elt_iter_from_x(const DenseVector<double>& x, std::string mesh_colour) {
619 elt_iter found_elt;
620 vector_of_elts* elts(get_elts_from_colour(mesh_colour));
621 std::size_t Mx(get_number_elts_in_x(mesh_colour));
622
623 elt_iter e = elts -> begin();
624 while(e != elts -> end()) {
625 // local coordinates of the NE and SW corners
626 DenseVector<double> ne(2, 1.0);
627 DenseVector<double> sw(-ne);
628 double west = e -> get_x(sw)[ 0 ];
629 double east = e -> get_x(ne)[ 0 ];
630 if((x[ 0 ] >= west) && (x[ 0 ] <= east)) {
631 break;
632 }
633 ++e;
634 }
635
636 while(true) {
637 // local coordinates of the NE and SW corners
638 DenseVector<double> ne(2, 1.0);
639 DenseVector<double> sw(-ne);
640 double south = e -> get_x(sw)[ 1 ];
641 double north = e -> get_x(ne)[ 1 ];
642 if((x[ 1 ] >= south) && (x[ 1 ] <= north)) {
643 break;
644 }
645 if(e + Mx < elts -> end()) {
646 e += Mx;
647 } else {
648 // if we are here, then we're looking for a point outside the mesh
649 std::string problem;
650 problem = "The TwoD_TVDLF_Mesh::get_elt_iter_from_x method has been called\n";
651 problem += "for a position that is outside the boundaries of the mesh.\n";
652 throw ExceptionRuntime(problem);
653 }
654 }
655 // if we get to here, then we've found the elt.
656 return e;
657 }
658
659
660 std::vector<TwoD_TVDLF_Elt>* TwoD_TVDLF_Mesh::get_elts_from_colour(std::string mesh_colour) {
661 vector_of_elts* elts;
662 if(mesh_colour == "black") {
663 elts = &BLACK_ELTS;
664 } else if(mesh_colour == "red") {
665 elts = &RED_ELTS;
666 } else {
667 std::string problem;
668 problem = " The TwoD_TVDLF_Mesh object has been passed an unrecognised mesh identifier. \n";
669 problem += " valid options are 'black' or 'red'.\n";
670 throw ExceptionRuntime(problem);
671 }
672 return elts;
673 }
674
675 std::size_t TwoD_TVDLF_Mesh::get_number_elts_in_x(std::string mesh_colour) {
676 std::size_t N;
677 if(mesh_colour == "black") {
678 N = NX - 1;
679 } else if(mesh_colour == "red") {
680 N = NX;
681 } else {
682 std::string problem;
683 problem = " The TwoD_TVDLF_Mesh object has been passed an unrecognised mesh identifier. \n";
684 problem += " valid options are 'black' or 'red'.\n";
685 throw ExceptionRuntime(problem);
686 }
687 return N;
688 }
689
691 set_boundary_Q(elt_vector);
692 elt_iter e(elt_vector -> begin());
693 DenseVector<double> slope_east(ORDER_OF_SYSTEM, 0.0);
694 DenseVector<double> slope_west(ORDER_OF_SYSTEM, 0.0);
695 DenseVector<double> slope_north(ORDER_OF_SYSTEM, 0.0);
696 DenseVector<double> slope_south(ORDER_OF_SYSTEM, 0.0);
697 switch(LIMITER) {
698 case 0:
699 // minmod
700 while(e != elt_vector -> end()) {
701 slope_east = east_diff(e);
702 slope_west = west_diff(e);
703 slope_south = south_diff(e);
704 slope_north = north_diff(e);
705 e -> set_slope_x(minmod(slope_east, slope_west));
706 e -> set_slope_y(minmod(slope_north, slope_south));
707 ++e;
708 }
709 break;
710 case 1:
711 // MC
712 while(e != elt_vector -> end()) {
713 slope_east = east_diff(e);
714 slope_west = west_diff(e);
715 DenseVector<double> slope_ew(EW_diff(e));
716 slope_south = south_diff(e);
717 slope_north = north_diff(e);
718 DenseVector<double> slope_ns(NS_diff(e));
719 const DenseVector<double> temp_x(minmod(slope_east * 2, slope_west * 2));
720 const DenseVector<double> slope_x(minmod(temp_x, slope_ew));
721 const DenseVector<double> temp_y(minmod(slope_north * 2, slope_south * 2));
722 const DenseVector<double> slope_y(minmod(temp_y, slope_ns));
723 e -> set_slope_x(slope_x);
724 e -> set_slope_y(slope_y);
725 ++e;
726 }
727 case 2:
728 /// superbee
729 while(e != elt_vector -> end()) {
730 slope_east = east_diff(e);
731 slope_west = west_diff(e);
732 slope_south = south_diff(e);
733 slope_north = north_diff(e);
734 const DenseVector<double> slope_x = maxmod(
735 minmod(slope_east, slope_west * 2.),
736 minmod(slope_east * 2., slope_west)
737 );
738 e -> set_slope_x(slope_x);
739 const DenseVector<double> slope_y = maxmod(
740 minmod(slope_north, slope_south * 2.),
741 minmod(slope_north * 2., slope_south)
742 );
743 e -> set_slope_y(slope_y);
744 ++e;
745 }
746 break;
747 default:
748 std::string problem;
749 problem = " The TwoD_TVDLF_Mesh object has an unrecognised 'LIMITER' identifier. \n";
750 throw ExceptionRuntime(problem);
751 }
752 }
753
756 std::set< int > faces(e -> get_external_faces());
757 const int face_index(1);
758 if(e -> face_is_external(face_index)) {
759 // interior difference
760 diff = west_diff(e);
761 boundary_diff(e, face_index, diff);
762 } else {
763 // We're not on an edge, so we can difference
764 elt_iter j(e -> get_ptrs(face_index));
765 diff = (j -> get_Q_mid() - e -> get_Q_mid())
766 / (j -> get_x_mid()[0] - e -> get_x_mid()[0]);
767 }
768 return diff;
769 }
770
773 std::set< int > faces(e -> get_external_faces());
774 const int face_index(3);
775 if(e -> face_is_external(face_index)) {
776 // interior difference
777 diff = east_diff(e);
778 boundary_diff(e, face_index, diff);
779 } else {
780 // We're not on an edge, so we can difference
781 elt_iter j(e -> get_ptrs(face_index));
782 diff = (e -> get_Q_mid() - j -> get_Q_mid())
783 / (e -> get_x_mid()[0] - j -> get_x_mid()[0]);
784 }
785 return diff;
786 }
787
790 std::set< int > faces(e -> get_external_faces());
791 const int face_index(2);
792 if(e -> face_is_external(face_index)) {
793 // interior difference
794 diff = south_diff(e);
795 boundary_diff(e, face_index, diff);
796 } else {
797 // We're not on an edge, so we can difference
798 elt_iter j(e -> get_ptrs(face_index));
799 diff = (j -> get_Q_mid() - e -> get_Q_mid())
800 / (j -> get_x_mid()[1] - e -> get_x_mid()[1]);
801 }
802 return diff;
803 }
804
807 std::set< int > faces(e -> get_external_faces());
808 const int face_index(0);
809 if(e -> face_is_external(face_index)) {
810 // interior difference
811 diff = north_diff(e);
812 boundary_diff(e, face_index, diff);
813 } else {
814 // We're not on an edge, so we can difference
815 elt_iter j(e -> get_ptrs(face_index));
816 diff = (e -> get_Q_mid() - j -> get_Q_mid())
817 / (e -> get_x_mid()[1] - j -> get_x_mid()[1]);
818 }
819 return diff;
820 }
821
824 std::set< int > faces(e -> get_external_faces());
825 if(e -> face_is_external(0)) {
826 // interior difference
827 diff = north_diff(e);
828 boundary_diff(e, 0, diff);
829 } else if(e -> face_is_external(2)) {
830 // interior difference
831 diff = south_diff(e);
832 boundary_diff(e, 2, diff);
833 } else {
834 // We're not on an edge, so we can difference
835 elt_iter jS(e -> get_ptrs(0));
836 elt_iter jN(e -> get_ptrs(2));
837 diff = (jN -> get_Q_mid() - jS -> get_Q_mid())
838 / (jN -> get_x_mid()[1] - jS -> get_x_mid()[1]);
839 }
840 return diff;
841 }
842
845 std::set< int > faces(e -> get_external_faces());
846 if(e -> face_is_external(1)) {
847 // interior difference
848 diff = west_diff(e);
849 boundary_diff(e, 1, diff);
850 } else if(e -> face_is_external(3)) {
851 // interior difference
852 diff = east_diff(e);
853 boundary_diff(e, 3, diff);
854 } else {
855 // We're not on an edge, so we can difference
856 elt_iter jE(e -> get_ptrs(1));
857 elt_iter jW(e -> get_ptrs(3));
858 diff = (jE -> get_Q_mid() - jW -> get_Q_mid())
859 / (jE -> get_x_mid()[0] - jW -> get_x_mid()[0]);
860 }
861 return diff;
862 }
863
864 int TwoD_TVDLF_Mesh::sgn(double a) const {
865 if(a > 0.0) {
866 return 1;
867 } else if(a < 0.0) {
868 return -1;
869 } else {
870 return 0;
871 }
872 }
873
876 for(std::size_t i = 0; i < A.size(); ++i) {
877 MM.push_back(0.5 * (sgn(A[i]) + sgn(B[i]))
878 * std::min(std::abs(A[i]), std::abs(B[i])));
879 }
880 return MM;
881 }
882
885 for(std::size_t i = 0; i < A.size(); ++i) {
886 MM.push_back(0.5 * (sgn(A[i]) + sgn(B[i]))
887 * std::max(std::abs(A[i]), std::abs(B[i])));
888 }
889 return MM;
890 }
891
892 void TwoD_TVDLF_Mesh::boundary_diff(elt_iter e, const int& face_index, DenseVector<double>& diff) const {
893 DenseVector<double> se(2, 0.0);
894 // get the appropriate local coordinate for the mid point on the edge
895 switch(face_index) {
896 case 0:
897 // south
898 se[ 0 ] = 0.0;
899 se[ 1 ] = -1.0;
900 break;
901 case 1:
902 // east
903 se[ 0 ] = 1.0;
904 se[ 1 ] = 0.0;
905 break;
906 case 2:
907 // north
908 se[ 0 ] = 0.0;
909 se[ 1 ] = 1.0;
910 break;
911 case 3:
912 // west
913 se[ 0 ] = -1.0;
914 se[ 1 ] = 0.0;
915 break;
916 }
917 // for the edge value
918 DenseVector<double> Q(e -> get_Q(se));
919 // look at the user-defined BCs for any defined Dirichlet conditions
920 std::vector<bool> inflow = e -> p_system -> edge_values(face_index, e -> get_x(se), Q);
921 // the default is a zero slope in accordance with Levy & Tadmor (1997)
923 // allow the user to override the zero slope
924 e -> p_system -> edge_slopes(face_index, e -> get_x(se), sigma_n);
925 // use edge values for inflow conditions
926 for(std::size_t i = 0; i < ORDER_OF_SYSTEM; ++i) {
927 if(inflow[ i ] == true) {
928 // set a zero slope as per Levy & Tadmor (1997)?
929 diff[ i ] = sigma_n[ i ];// ( Qe[ i ] - Qm[ i ] ) / delta;
930 //std::cout << face_index << " " << diff[ i ] << "\n";
931 }
932 }
933 }
934
935}
Specification of a two dimensional linear element for use in a TVD Lax-Friedrichs scheme.
Specification of an object that represents a two dimensional mesh for TVD LF 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 two-dimensional hyperbolic system of equations.
A Linear Element class.
vector_of_elts * get_elts_from_colour(std::string mesh_colour)
Given a choice of black or red mesh, return a pointer to the appropriate vector of elements.
vector_of_elts RED_ELTS
An STL vector of linear elements – the red mesh.
virtual void actions_before_time_step1(const double &time_step)
A virtual method that is run before the first time update.
DenseVector< double > get_point_values(const DenseVector< double > &x)
Get the vector of unknowns at a point in the 2D mesh.
std::size_t get_number_elts_in_x(std::string mesh_colour)
Given a choice of black or red mesh, return the number of elements in the x-direction.
void dump_gnu(std::string filename)
Dump the data to a given filename in a gnuplot format.
DenseVector< double > minmod(DenseVector< double > A, DenseVector< double > B) const
A vector version of the minmod operator.
void calc_slopes(vector_of_elts *elt_vector)
Use the appropriate limiter to approximate the slope in each element in the mesh.
DenseVector< double > integrate(std::string mesh_colour="black")
Integrate the concentration values across the entire mesh.
void update_to(const double &CFL, const double &t_end)
Update the mesh object to a set time level.
unsigned LIMITER
Slope limiter method.
DenseVector< double > EW_diff(elt_iter e)
Compute a finite difference approximation of the derivative in the compass direction.
DenseVector< double > west_diff(elt_iter e) const
Compute a finite difference approximation of the derivative in the compass direction.
DenseVector< double > east_diff(elt_iter e) const
Compute a finite difference approximation of the derivative in the compass direction.
DenseVector< double > south_diff(elt_iter e) const
Compute a finite difference approximation of the derivative in the compass direction.
TwoD_TVDLF_Mesh(const DenseVector< double > &X, const DenseVector< double > &Y, TwoD_Hyperbolic_System *ptr, fn_ptr init_ptr)
Constructor for the Finite Volume Mesh using linear elements.
void dump_data(std::string filename)
Dump the data over the nodal positions to a given filename.
void boundary_diff(elt_iter e, const int &face_index, DenseVector< double > &diff) const
Given an element iterator and the local coordinate this will return zero for any components specified...
vector_of_elts BLACK_ELTS
An STL vector of linear elements – the black mesh.
elt_iter get_elt_iter_from_elt_iter(elt_iter e, std::string target_colour, int corner_index)
Given an element in the INITIAL STRUCTURED MESH, this method will return an iterator to an element in...
fn_ptr p_Q_INIT
function pointer to a funnction that defines the initial distribution
std::size_t ORDER_OF_SYSTEM
order of the conservative system
int sgn(double a) const
Sign of a double.
void set_boundary_Q(vector_of_elts *elts)
Loops over all boundary elements and sets the Q values in each one to be the value specified by the e...
const double & get_time() const
Get a const reference to the time value for the current mesh.
vector_of_elts::const_iterator celt_iter
void dump_nodes_y(std::string filename) const
Dump the y-nodal positions to a given filename.
double update(const double &CFL, const double &max_dt=std::numeric_limits< long double >::max())
Update the mesh object.
DenseVector< double > NS_diff(elt_iter e)
Compute a finite difference approximation of the derivative in the compass direction.
DenseVector< double > maxmod(DenseVector< double > A, DenseVector< double > B) const
A vector version of the maxmod operator.
void dump_nodes_x(std::string filename) const
Dump the x-nodal positions to a given filename.
std::size_t NX
number of faces in the x & y directions
DenseVector< double > north_diff(elt_iter e) const
Compute a finite difference approximation of the derivative in the compass direction.
virtual ~TwoD_TVDLF_Mesh()
Empty desctructor.
void set_limiter(const unsigned &id)
Set the limiter type to be applied in the slope values.
double MESH_TIME
the time level of the mesh
virtual void actions_before_time_step2(const double &time_step)
A virtual method that is run before the second time update.
vector_of_elts::iterator elt_iter
std::vector< TwoD_TVDLF_Elt > vector_of_elts
iterators for the vector of elements
elt_iter get_elt_iter_from_x(const DenseVector< double > &x, std::string mesh_colour="black")
Given a global coordinate, return a pointer to the elt that contains that point.
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt