16 template <
typename _Type>
26 p_EQUATION(ptr_to_equation),
27 p_BOTTOM_RESIDUAL(ptr_to_bottom_residual),
28 p_TOP_RESIDUAL(ptr_to_top_residual),
35 p_EQUATION -> coord(2) = xnodes[0];
38 T_ASSEMBLE =
Timer(
"Assembling of the matrix (incl. equation updates):");
39 T_SOLVE =
Timer(
"Solving of the matrix:");
43 template <
typename _Type>
54 template <
typename _Type>
59 problem =
" You have called the reversed_BL::step2 method without calling\n";
60 problem +=
" the reversed_BL::update_previous_solution method first. This\n";
61 problem +=
" method is required to copy/store the previous time level's solution\n";
62 problem +=
" and then allow you to specify/alter the x-initial condition by\n";
63 problem +=
" for the current time level.";
67 unsigned order(p_EQUATION -> get_order());
70 unsigned nx(SOLN.get_nnodes().first);
71 unsigned ny(SOLN.get_nnodes().second);
73 double max_residual(1.0);
91 for(std::size_t j = 0; j < nx - 1; ++j) {
102 assemble_matrix_problem(a, b, j);
105 std::cout.precision(12);
106 std::cout <<
" reversed_BL.step2 : x_j = " << SOLN.coord(j,0).first <<
" Residual_max = " << max_residual <<
" tol = " << TOL <<
" counter = " << counter <<
"\n";
116 for(std::size_t i = 0; i < ny; ++i) {
117 for(std::size_t var = 0; var < order; ++var) {
118 SOLN(j + 1, i, var) += b[ i * order + var ];
124 }
while((max_residual > TOL) && (counter < MAX_ITERATIONS));
125 if(counter >= MAX_ITERATIONS) {
126 std::cout <<
" reversed_BL.step2 : x_j = " << SOLN.coord(jfail,0).first <<
"\n";
127 std::string problem(
"\n The reversed_BL.step2 method took too many iterations. \n");
134 std::cout <<
"[DEBUG] solved at t = " << T <<
"\n";
140 template <
typename _Type>
145 problem =
" You have called the reversed_BL::bidirectional_step2 method without calling\n";
146 problem +=
" the reversed_BL::update_previous_solution method first. This\n";
147 problem +=
" method is required to copy/store the previous time level's solution\n";
148 problem +=
" and then allow you to specify/alter the x-initial condition by\n";
149 problem +=
" for the current time level.";
153 unsigned order(p_EQUATION -> get_order());
156 unsigned nx(SOLN.get_nnodes().first);
157 unsigned ny(SOLN.get_nnodes().second);
159 double max_residual(1.0);
181 for(std::size_t j = 0; j < nx - 2; ++j) {
203 bool reversed(
false);
204 if(SOLN(j+2, 0, 2) < 0.0) {
209 assemble_matrix_problem(a, b, j);
213 bidirectional_assemble_matrix_problem(a, b, j);
217 std::cout.precision(12);
218 std::cout <<
" reversed_BL.bidirectional_step2 : x_j = " << SOLN.coord(j,0).first <<
" Residual_max = " << max_residual <<
" tol = " << TOL <<
" counter = " << counter <<
"\n";
228 for(std::size_t i = 0; i < ny; ++i) {
229 for(std::size_t var = 0; var < order; ++var) {
230 SOLN(j + 1, i, var) += b[ i * order + var ];
236 }
while((max_residual > TOL) && (counter < MAX_ITERATIONS));
237 if(counter >= MAX_ITERATIONS) {
238 std::cout <<
" reversed_BL.bidirectional_step2 : x_j = " << SOLN.coord(jfail,0).first <<
"\n";
239 std::string problem(
"\n The reversed_BL.bidirectional_step2 method took too many iterations. \n");
246 std::cout <<
"[DEBUG] solved at t = " << T <<
"\n";
254 template <
typename _Type>
258 const std::size_t& j) {
263 const double inv_dt(1. / DT);
265 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
267 const double x = SOLN.coord(j + 1, 0).first;
269 const unsigned order(p_EQUATION -> get_order());
272 const unsigned ny(SOLN.get_nnodes().second);
290 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
291 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
293 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
295 for(
unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
297 for(
unsigned var = 0; var < order; ++var) {
298 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
300 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
304 for(std::size_t node = 0; node <= ny - 2; ++node) {
306 const std::size_t b_node = node;
307 const std::size_t t_node = node + 1;
309 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
312 for(
unsigned var = 0; var < order; ++var) {
313 const double Fj_midpt = (SOLN(j, b_node, var) + SOLN(j, t_node, var)) / 2;
315 const double Fjp1_midpt = (SOLN(j + 1, b_node, var) + SOLN(j + 1, t_node, var)) / 2;
316 const double Ojp1_midpt = (PREV_SOLN(j + 1, b_node, var) + PREV_SOLN(j + 1, t_node, var)) / 2;
317 const double Ojp2_midpt = (PREV_SOLN(j + 2, b_node, var) + PREV_SOLN(j + 2, t_node, var)) / 2;
321 Qh_state[ var ] = (Fjp1_midpt + Ojp1_midpt) / 2;
322 P_state[ var ] = (Fjp1_midpt + Fj_midpt) / 2;
323 R_state[ var ] = (Ojp2_midpt + Ojp1_midpt) / 2;
325 state_dx[ var ] = ((Ojp2_midpt - Ojp1_midpt) * inv_dx + (Fjp1_midpt - Fj_midpt) * inv_dx) / 2;
326 state_dt[ var ] = (Fjp1_midpt - Ojp1_midpt) * inv_dt;
327 state_dy[ var ] = (SOLN(j + 1, t_node, var) - SOLN(j + 1, b_node, var)
328 + PREV_SOLN(j + 1, t_node, var) - PREV_SOLN(j + 1, b_node, var)) * inv_dy / 2;
331 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
333 p_EQUATION -> coord(0) = y_midpt;
334 p_EQUATION -> coord(1) = T + DT / 2.;
335 p_EQUATION -> coord(2) = x;
337 p_EQUATION -> update(Qh_state);
339 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(Qh_state, state_dx, h2);
341 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().
multiply(state_dx));
343 p_EQUATION -> update(Qh_state);
345 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(Qh_state, state_dt, h1);
347 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().
multiply(state_dt));
353 for(
unsigned var = 0; var < order; ++var) {
355 const std::size_t offset(var * a.
noffdiag() * 3 + row);
358 *(b_iter + offset) = -inv_dy;
360 *(t_iter + offset) = inv_dy;
362 for(
unsigned i = 0; i < order; ++i) {
363 const std::size_t offset(i * a.
noffdiag() * 3 + row);
368 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
370 *top -= p_EQUATION -> jacobian()(var, i) / 2;
373 *bottom += h1(var, i) * .25;
375 *top += h1(var, i) * .25;
378 *bottom += h2(var, i) * .5;
380 *top += h2(var, i) * .5;
383 *bottom += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
385 *top += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
387 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
389 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
392 b[ row ] = p_EQUATION -> residual()[ var ] - state_dy[ var ];
393 b[ row ] -= m2_times_state_dx[ var ];
394 b[ row ] -= m1_times_state_dt[ var ];
401 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
402 p_TOP_RESIDUAL -> coord(1) = T + DT;
404 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
406 for(
unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
408 for(
unsigned var = 0; var < order; ++var) {
409 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
411 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
415 if(row != ny * order) {
416 std::string problem(
"\n The ODE_BVP has an incorrect number of boundary conditions. \n");
417 throw ExceptionRuntime(problem);
423 template <
typename _Type>
424 void reversed_BL<_Type>::assemble_matrix_problem(
425 BandedMatrix<_Type>& a,
426 DenseVector<_Type>& b,
427 const std::size_t& j) {
432 const double inv_dt(1. / DT);
434 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
436 const double x_midpt = 0.5 * (SOLN.coord(j + 1, 0).first + SOLN.coord(j, 0).first);
438 const unsigned order(p_EQUATION -> get_order());
440 const unsigned ny(SOLN.get_nnodes().second);
444 DenseVector<_Type> state(order, 0.0);
445 DenseVector<_Type> state_dx(order, 0.0);
446 DenseVector<_Type> state_dt(order, 0.0);
447 DenseVector<_Type> state_dy(order, 0.0);
449 DenseVector<_Type> F_midpt(order, 0.0);
450 DenseVector<_Type> O_midpt(order, 0.0);
452 DenseMatrix<_Type> h1(order, order, 0.0);
453 DenseMatrix<_Type> h2(order, order, 0.0);
455 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
456 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
458 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
460 for(
unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
462 for(
unsigned var = 0; var < order; ++var) {
463 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
465 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
469 for(std::size_t node = 0; node <= ny - 2; ++node) {
471 const std::size_t b_node = node;
472 const std::size_t t_node = node + 1;
474 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
476 for(
unsigned var = 0; var < order; ++var) {
477 const double Fj_midpt = (SOLN(j, b_node, var) + SOLN(j, t_node, var)) / 2;
478 const double Oj_midpt = (PREV_SOLN(j, b_node, var) + PREV_SOLN(j, t_node, var)) / 2;
479 const double Fjp1_midpt = (SOLN(j + 1, b_node, var) + SOLN(j + 1, t_node, var)) / 2;
480 const double Ojp1_midpt = (PREV_SOLN(j + 1, b_node, var) + PREV_SOLN(j + 1, t_node, var)) / 2;
481 state[ var ] = (Fj_midpt + Fjp1_midpt + Oj_midpt + Ojp1_midpt) / 4;
482 state_dx[ var ] = (Fjp1_midpt - Fj_midpt + Ojp1_midpt - Oj_midpt) * inv_dx / 2;
483 state_dt[ var ] = (Fjp1_midpt + Fj_midpt - Ojp1_midpt - Oj_midpt) * inv_dt / 2;
484 state_dy[ var ] = (SOLN(j + 1, t_node, var) - SOLN(j + 1, b_node, var)
485 + SOLN(j, t_node, var) - SOLN(j, b_node, var)
486 + PREV_SOLN(j + 1, t_node, var) - PREV_SOLN(j + 1, b_node, var)
487 + PREV_SOLN(j, t_node, var) - PREV_SOLN(j, b_node, var)) * inv_dy / 4;
490 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
492 p_EQUATION -> coord(0) = y_midpt;
493 p_EQUATION -> coord(1) = T + DT / 2.;
494 p_EQUATION -> coord(2) = x_midpt;
496 p_EQUATION -> update(state);
498 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(state, state_dt, h1);
500 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(state, state_dx, h2);
502 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().
multiply(state_dt));
504 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().
multiply(state_dx));
510 for(
unsigned var = 0; var < order; ++var) {
512 const std::size_t offset(var * a.noffdiag() * 3 + row);
515 *(b_iter + offset) = -inv_dy;
517 *(t_iter + offset) = inv_dy;
519 for(
unsigned i = 0; i < order; ++i) {
520 const std::size_t offset(i * a.noffdiag() * 3 + row);
525 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
527 *top -= p_EQUATION -> jacobian()(var, i) / 2;
530 *bottom += h1(var, i) * .5;
532 *top += h1(var, i) * .5;
534 *bottom += h2(var, i) * .5;
536 *top += h2(var, i) * .5;
539 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
541 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
543 *bottom += p_EQUATION -> matrix2()(var, i) * inv_dx;
545 *top += p_EQUATION -> matrix2()(var, i) * inv_dx;
548 b[ row ] = p_EQUATION -> residual()[ var ] - state_dy[ var ];
549 b[ row ] -= m1_times_state_dt[ var ];
550 b[ row ] -= m2_times_state_dx[ var ];
557 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
558 p_TOP_RESIDUAL -> coord(1) = T + DT;
560 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
562 for(
unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
564 for(
unsigned var = 0; var < order; ++var) {
565 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
567 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
571 if(row != ny * order) {
572 std::string problem(
"\n The ODE_BVP has an incorrect number of boundary conditions. \n");
573 throw ExceptionRuntime(problem);
579 template <
typename _Type>
580 void reversed_BL<_Type>::first_order_assemble_matrix_problem(
581 BandedMatrix<_Type>& a,
582 DenseVector<_Type>& b,
583 const std::size_t& j) {
587 const double inv_dt(1. / DT);
589 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
591 const double x = SOLN.coord(j + 1, 0).first;
593 const unsigned order(p_EQUATION -> get_order());
596 const unsigned ny(SOLN.get_nnodes().second);
601 DenseVector<_Type> Qh_state(order, 0.0);
602 DenseVector<_Type> P_state(order, 0.0);
603 DenseVector<_Type> R_state(order, 0.0);
604 DenseVector<_Type> state_dx(order, 0.0);
605 DenseVector<_Type> state_dt(order, 0.0);
606 DenseVector<_Type> state_dy(order, 0.0);
608 DenseVector<_Type> F_midpt(order, 0.0);
609 DenseVector<_Type> O_midpt(order, 0.0);
611 DenseMatrix<_Type> h1(order, order, 0.0);
612 DenseMatrix<_Type> h2(order, order, 0.0);
614 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
615 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
617 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
619 for(
unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
621 for(
unsigned var = 0; var < order; ++var) {
622 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
624 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
628 for(std::size_t node = 0; node <= ny - 2; ++node) {
630 const std::size_t b_node = node;
631 const std::size_t t_node = node + 1;
633 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
636 for(
unsigned var = 0; var < order; ++var) {
637 const double Fj_midpt = (SOLN(j, b_node, var) + SOLN(j, t_node, var)) / 2;
639 const double Fjp1_midpt = (SOLN(j + 1, b_node, var) + SOLN(j + 1, t_node, var)) / 2;
640 const double Ojp1_midpt = (PREV_SOLN(j + 1, b_node, var) + PREV_SOLN(j + 1, t_node, var)) / 2;
641 const double Ojp2_midpt = (PREV_SOLN(j + 2, b_node, var) + PREV_SOLN(j + 2, t_node, var)) / 2;
645 Qh_state[ var ] = (Fjp1_midpt + Ojp1_midpt) / 2;
646 P_state[ var ] = (Fjp1_midpt + Fj_midpt) / 2;
647 R_state[ var ] = (Ojp2_midpt + Ojp1_midpt) / 2;
649 state_dx[ var ] = ((Ojp2_midpt - Ojp1_midpt) * inv_dx + (Fjp1_midpt - Fj_midpt) * inv_dx) / 2;
650 state_dt[ var ] = (Fjp1_midpt - Ojp1_midpt) * inv_dt;
651 state_dy[ var ] = (SOLN(j + 1, t_node, var) - SOLN(j + 1, b_node, var)
652 + PREV_SOLN(j + 1, t_node, var) - PREV_SOLN(j + 1, b_node, var)) * inv_dy / 2;
655 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
657 p_EQUATION -> coord(0) = y_midpt;
658 p_EQUATION -> coord(1) = T + DT / 2.;
659 p_EQUATION -> coord(2) = x;
661 p_EQUATION -> update(Qh_state);
663 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(Qh_state, state_dx, h2);
665 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().
multiply(state_dx));
667 p_EQUATION -> update(Qh_state);
669 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(Qh_state, state_dt, h1);
671 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().
multiply(state_dt));
677 for(
unsigned var = 0; var < order; ++var) {
679 const std::size_t offset(var * a.noffdiag() * 3 + row);
682 *(b_iter + offset) = -inv_dy;
684 *(t_iter + offset) = inv_dy;
686 for(
unsigned i = 0; i < order; ++i) {
687 const std::size_t offset(i * a.noffdiag() * 3 + row);
692 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
694 *top -= p_EQUATION -> jacobian()(var, i) / 2;
697 *bottom += h1(var, i) * .25;
699 *top += h1(var, i) * .25;
702 *bottom += h2(var, i) * .5;
704 *top += h2(var, i) * .5;
707 *bottom += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
709 *top += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
711 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
713 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
716 b[ row ] = p_EQUATION -> residual()[ var ] - state_dy[ var ];
717 b[ row ] -= m2_times_state_dx[ var ];
718 b[ row ] -= m1_times_state_dt[ var ];
725 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
726 p_TOP_RESIDUAL -> coord(1) = T + DT;
728 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
730 for(
unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
732 for(
unsigned var = 0; var < order; ++var) {
733 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
735 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
739 if(row != ny * order) {
740 std::string problem(
"\n The ODE_BVP has an incorrect number of boundary conditions. \n");
741 throw ExceptionRuntime(problem);
750 template class reversed_BL<double>
Specification of the linear system class.
A templated class for equations that can be inherited from to allow instantiation of PDE_double_IBVP ...
The collection of CppNoddy exceptions.
A spec for the CppNoddy Timer object.
A spec for a collection of utility functions.
A linear system class for vector right-hand sides.
void solve()
Solve the banded system.
A matrix class that constructs a BANDED matrix.
std::size_t noffdiag() const
Get the number of off-diagonal elements where the total INPUT band width is 2*noffdiag+1 since the ba...
void assign(_Type elt)
Assign a value the matrix so that it has the same geometry, but zero entries in all locations includi...
DenseVector< _Type >::elt_iter elt_iter
elt_iter get_elt_iter(std::size_t row, std::size_t col)
A matrix class that constructs a DENSE matrix as a row major std::vector of DenseVectors.
An DenseVector class – a dense vector object.
double inf_norm() const
Infinity norm.
An equation object base class used in the PDE_double_IBVP class.
An exception class that is thrown if too many Newton steps are taken in either the scalar or vector N...
A generic runtime exception.
A base class to be inherited by objects that define residuals.
A simple CPU-clock-tick timer for timing metods.
A two dimensional mesh utility object.
A templated object for real/complex vector system of unsteady equations.
reversed_BL(Equation_3matrix< _Type > *equation_ptr, const DenseVector< double > &xnodes, const DenseVector< double > &ynodes, Residual_with_coords< _Type > *ptr_to_bottom_residual, Residual_with_coords< _Type > *ptr_to_top_residual)
The class is defined by a vector function for the system.
void step2(const double &dt)
A Crank-Nicolson 'time' stepper.
~reversed_BL()
Destructor.
void bidirectional_step2(const double &dt)
A Crank-Nicolson 'time' stepper.
DenseMatrix< double > multiply(DenseMatrix< double > &A, DenseMatrix< double > &B)
BLAS wrapper to do DOUBLE DENSE A_{MxK} * B_{KxN} = C_{MxN} Since this is a Fortran library,...
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...
An implementation of the zig-zag modification for unsteady parabolic marching with reverse flow.