CppNoddy  0.92
Loading...
Searching...
No Matches
reversed_BL.cpp
Go to the documentation of this file.
1/// \file reversed_BL.cpp
2
3#include <string>
4#include <cassert>
5
6#include <reversed_BL.h>
8#include <Equation_2matrix.h>
9#include <Exceptions.h>
10#include <Utility.h>
11#include <Timer.h>
12
13//#define DEBUG
14
15namespace CppNoddy {
16 template <typename _Type>
18 Equation_3matrix<_Type >* ptr_to_equation,
19 const DenseVector<double> &xnodes,
20 const DenseVector<double> &ynodes,
21 Residual_with_coords<_Type>* ptr_to_bottom_residual,
22 Residual_with_coords<_Type>* ptr_to_top_residual) :
23 TOL(1.e-8),
24 T(0.0),
25 MAX_ITERATIONS(30),
26 p_EQUATION(ptr_to_equation),
27 p_BOTTOM_RESIDUAL(ptr_to_bottom_residual),
28 p_TOP_RESIDUAL(ptr_to_top_residual),
29 UPDATED(false) {
30 // create the 2D mesh for the current time level and previous time level
31 SOLN = TwoD_Node_Mesh<_Type>(xnodes, ynodes, p_EQUATION -> get_order());
32 // copy construct the previous solution's storage
33 PREV_SOLN = SOLN;
34 // initialise the eqn object
35 p_EQUATION -> coord(2) = xnodes[0];
36#ifdef TIME
37 // timers
38 T_ASSEMBLE = Timer("Assembling of the matrix (incl. equation updates):");
39 T_SOLVE = Timer("Solving of the matrix:");
40#endif
41 }
42
43 template <typename _Type>
45#ifdef TIME
46 std::cout << "\n";
47 T_ASSEMBLE.stop();
48 T_ASSEMBLE.print();
49 T_SOLVE.stop();
50 T_SOLVE.print();
51#endif
52 }
53
54 template <typename _Type>
55 void reversed_BL<_Type>::step2(const double& dt) {
56 DT = dt;
57 if(!UPDATED) {
58 std::string problem;
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.";
64 throw ExceptionRuntime(problem);
65 }
66 // the order of the problem
67 unsigned order(p_EQUATION -> get_order());
68 // get the number of nodes in the mesh
69 // -- this may have been refined by the user since the last call.
70 unsigned nx(SOLN.get_nnodes().first);
71 unsigned ny(SOLN.get_nnodes().second);
72 // measure of maximum residual
73 double max_residual(1.0);
74 // the current solution moves to the previous solution
75 // ANY LARGE STORAGE USED IN THE MAIN LOOP IS
76 // DEFINED HERE TO AVOID REPEATED CONSTRUCTION.
77 // Note we blank the A matrix after every iteration.
78 //
79 // Banded LHS matrix - max obove diagonal band width is
80 // from first variable at node i to last variable at node i+1
81 BandedMatrix<_Type> a(ny * order, 2 * order - 1, 0.0);
82 // RHS
83 DenseVector<_Type> b(ny * order, 0.0);
84 // linear solver definition
85#ifdef LAPACK
86 BandedLinearSystem<_Type> system(&a, &b, "lapack");
87#else
88 BandedLinearSystem<_Type> system(&a, &b, "native");
89#endif
90 unsigned jfail = 0;
91 for(std::size_t j = 0; j < nx - 1; ++j) {
92 // iteration counter
93 int counter = 0;
94 // loop until converged or too many iterations
95 do {
96 // iteration counter
97 ++counter;
98 // time the assemble phase
99#ifdef TIME
100 T_ASSEMBLE.start();
101#endif
102 assemble_matrix_problem(a, b, j);
103 max_residual = b.inf_norm();
104#ifdef DEBUG
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";
107#endif
108#ifdef TIME
109 T_ASSEMBLE.stop();
110 T_SOLVE.start();
111#endif
112 jfail = j;
113 // linear solver
114 system.solve();
115 // keep the solution in a OneD_GenMesh object
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 ];
119 }
120 }
121#ifdef TIME
122 T_SOLVE.stop();
123#endif
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");
128 throw ExceptionItn(problem, counter, max_residual);
129 }
130 }
131 // set the time to the updated level
132 T += DT;
133#ifdef DEBUG
134 std::cout << "[DEBUG] solved at t = " << T << "\n";
135#endif
136 UPDATED = false;
137 }
138
139
140 template <typename _Type>
142 DT = dt;
143 if(!UPDATED) {
144 std::string problem;
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.";
150 throw ExceptionRuntime(problem);
151 }
152 // the order of the problem
153 unsigned order(p_EQUATION -> get_order());
154 // get the number of nodes in the mesh
155 // -- this may have been refined by the user since the last call.
156 unsigned nx(SOLN.get_nnodes().first);
157 unsigned ny(SOLN.get_nnodes().second);
158 // measure of maximum residual
159 double max_residual(1.0);
160 // the current solution moves to the previous solution
161 // ANY LARGE STORAGE USED IN THE MAIN LOOP IS
162 // DEFINED HERE TO AVOID REPEATED CONSTRUCTION.
163 // Note we blank the A matrix after every iteration.
164 //
165 // Banded LHS matrix - max obove diagonal band width is
166 // from first variable at node i to last variable at node i+1
167 BandedMatrix<_Type> a(ny * order, 2 * order - 1, 0.0);
168 // RHS
169 DenseVector<_Type> b(ny * order, 0.0);
170 // linear solver definition
171#ifdef LAPACK
172 BandedLinearSystem<_Type> system(&a, &b, "lapack");
173#else
174 BandedLinearSystem<_Type> system(&a, &b, "native");
175#endif
176 // which node did convergence fail?
177 unsigned jfail = 0;
178 // step from j=0 to j=nx-3 ... at each we assemble and solve for j+1
179 // which covers the positions j=1,2,...,nx-2. Note that the solution
180 // at j=0 and nx-1 are defined in the bidirectional problem.
181 for(std::size_t j = 0; j < nx - 2; ++j) {
182 //// next x-soln guess is the previous x-soln
183 //for ( std::size_t i = 0; i < ny; ++i )
184 //{
185 //for ( std::size_t var = 0; var < order; ++var )
186 //{
187 //SOLN( j + 1, i, var ) = SOLN( j, i, var );
188 //}
189 //}
190 // iteration counter
191 int counter = 0;
192 // loop until converged or too many iterations
193 do {
194 // iteration counter
195 ++counter;
196 // time the assemble phase
197#ifdef TIME
198 T_ASSEMBLE.start();
199#endif
200 // *** hardwired velocity direction/shear hackery
201 // if ( SOLN( j+2, 0, 2) > 0.0 )
202
203 bool reversed(false);
204 if(SOLN(j+2, 0, 2) < 0.0) {
205 reversed = true;
206 }
207
208 if(!reversed) {
209 assemble_matrix_problem(a, b, j);
210 } else {
211
212 //std::cout << SOLN.coord(j+2,0).first << " Reversed \n";
213 bidirectional_assemble_matrix_problem(a, b, j);
214 }
215 max_residual = b.inf_norm();
216#ifdef DEBUG
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";
219#endif
220#ifdef TIME
221 T_ASSEMBLE.stop();
222 T_SOLVE.start();
223#endif
224 jfail = j;
225 // linear solver
226 system.solve();
227 // write the solution back into the TwoD_Node_Mesh object
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 ];
231 }
232 }
233#ifdef TIME
234 T_SOLVE.stop();
235#endif
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");
240 throw ExceptionItn(problem, counter, max_residual);
241 }
242 }
243 // set the time to the updated level
244 T += DT;
245#ifdef DEBUG
246 std::cout << "[DEBUG] solved at t = " << T << "\n";
247#endif
248 UPDATED = false;
249 }
250
251
252
253
254 template <typename _Type>
258 const std::size_t& j) {
259 //std::cout << " Reversed assemble j = " << j << "\n";
260 // clear the Jacobian matrix
261 a.assign(0.0);
262 // inverse of the t-step
263 const double inv_dt(1. / DT);
264 // inverse of the x-step
265 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
266 // the x variable
267 const double x = SOLN.coord(j + 1, 0).first;
268 // the order of the problem
269 const unsigned order(p_EQUATION -> get_order());
270 // number of spatial nodes in the y-direction
271 //const unsigned nx( SOLN.get_nnodes().first );
272 const unsigned ny(SOLN.get_nnodes().second);
273 // row counter
274 std::size_t row(0);
275 // local state variables
276 //DenseVector<_Type> Q_state( order, 0.0 );
277 DenseVector<_Type> Qh_state(order, 0.0);
278 DenseVector<_Type> P_state(order, 0.0);
279 DenseVector<_Type> R_state(order, 0.0);
280 DenseVector<_Type> state_dx(order, 0.0);
281 DenseVector<_Type> state_dt(order, 0.0);
282 DenseVector<_Type> state_dy(order, 0.0);
283 // Current and old state
284 DenseVector<_Type> F_midpt(order, 0.0);
285 DenseVector<_Type> O_midpt(order, 0.0);
286 // these store the Jacobian of the mass matrices times a state vector
287 DenseMatrix<_Type> h1(order, order, 0.0);
288 DenseMatrix<_Type> h2(order, order, 0.0);
289 // set the x-t coordinates in the BC
290 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
291 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
292 // update the BC residuals for the current iteration
293 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
294 // add the (linearised) bottom BCs to the matrix problem
295 for(unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
296 // loop thru variables at LHS of the domain
297 for(unsigned var = 0; var < order; ++var) {
298 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
299 }
300 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
301 ++row;
302 }
303 // inner nodes of the mesh, node = 0,1,2,...,ny-2
304 for(std::size_t node = 0; node <= ny - 2; ++node) {
305 // bottom and top nodes of the mid-y-point we're considering
306 const std::size_t b_node = node;
307 const std::size_t t_node = node + 1;
308 //
309 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
310 // work out state, state_dx, state_dt, state_dy
311 // in this case the _midpt variable indicates that it is a mid-point in y evaluation
312 for(unsigned var = 0; var < order; ++var) {
313 const double Fj_midpt = (SOLN(j, b_node, var) + SOLN(j, t_node, var)) / 2;
314 //const double Oj_midpt = ( PREV_SOLN( j, b_node, var ) + PREV_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;
318 //
319 // zig-zag modification
320 //Qh_state[ var ] = ( Fjp1_midpt + Ojp1_midpt + Fj_midpt + Ojp2_midpt ) / 4;
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;
324 //
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;
329 }
330 //
331 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
332 // set the coord in the equation object
333 p_EQUATION -> coord(0) = y_midpt;
334 p_EQUATION -> coord(1) = T + DT / 2.;
335 p_EQUATION -> coord(2) = x;
336 // Update the equation to the mid point position - averaged in the zig-zag scheme
337 p_EQUATION -> update(Qh_state);
338 // evaluate the Jacobian of mass contribution multiplied by state_dx
339 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(Qh_state, state_dx, h2);
340 // matrix 2 times state_dx
341 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().multiply(state_dx));
342 // Update the equation to the mid point position - without upstream influence
343 p_EQUATION -> update(Qh_state);
344 // evaluate the Jacobian of mass contribution multiplied by state_dt
345 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(Qh_state, state_dt, h1);
346 // mass matrix 2 times state_dt
347 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().multiply(state_dt));
348 // loop over all the variables
349 // il = position for (0, b_node*order)
350 typename BandedMatrix<_Type>::elt_iter b_iter(a.get_elt_iter(0, b_node * order));
351 // ir = position for (0, t_node*order)
352 typename BandedMatrix<_Type>::elt_iter t_iter(a.get_elt_iter(0, t_node * order));
353 for(unsigned var = 0; var < order; ++var) {
354 // offset for (r,c) -> (r+row, c+var)
355 const std::size_t offset(var * a.noffdiag() * 3 + row);
356 // deriv at the MID POINT between nodes
357 //a( row, order * b_node + var ) = -inv_dy;
358 *(b_iter + offset) = -inv_dy;
359 //a( row, order * t_node + var ) = inv_dy;
360 *(t_iter + offset) = inv_dy;
361 // add the matrix mult terms to the linearised problem
362 for(unsigned i = 0; i < order; ++i) { // dummy index
363 const std::size_t offset(i * a.noffdiag() * 3 + row);
364 const typename BandedMatrix<_Type>::elt_iter bottom(b_iter + offset);
365 const typename BandedMatrix<_Type>::elt_iter top(t_iter + offset);
366 // add the Jacobian terms
367 //a( row, order * b_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
368 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
369 //a( row, order * t_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
370 *top -= p_EQUATION -> jacobian()(var, i) / 2;
371 // add the Jacobian of mass terms
372 //a( row, order * b_node + i ) += h1( var, i ) * .5;
373 *bottom += h1(var, i) * .25;
374 //a( row, order * t_node + i ) += h1( var, i ) * .5;
375 *top += h1(var, i) * .25;
376 // add the Jacobian of mass terms
377 //a( row, order * b_node + i ) += h2( var, i ) * .5;
378 *bottom += h2(var, i) * .5;
379 //a( row, order * t_node + i ) += h2( var, i ) * .5;
380 *top += h2(var, i) * .5;
381 // add the mass matrix terms
382 //a( row, order * b_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dx;
383 *bottom += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
384 //a( row, order * t_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dx;
385 *top += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
386 //a( row, order * b_node + i ) += p_EQUATION -> mass2()( var, i ) * inv_dt;
387 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
388 //a( row, order * t_node + i ) += p_EQUATION -> mass2()( var, i ) * inv_dt;
389 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
390 }
391 // RHS
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 ];
395 b[ row ] *= 2;
396 // increment the row
397 row += 1;
398 }
399 }
400 // set the x-t coordinates in the BC
401 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
402 p_TOP_RESIDUAL -> coord(1) = T + DT;
403 // update the BC residuals for the current iteration
404 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
405 // add the (linearised) RHS BCs to the matrix problem
406 for(unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
407 // loop thru variables at RHS of the domain
408 for(unsigned var = 0; var < order; ++var) {
409 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
410 }
411 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
412 ++row;
413 }
414#ifdef PARANOID
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);
418 }
419#endif
420 }
421
422
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) {
428 //std::cout << "Unidirectional assemble, j=" << j << "\n";
429 // clear the Jacobian matrix
430 a.assign(0.0);
431 // inverse of the t-step
432 const double inv_dt(1. / DT);
433 // inverse of the x-step
434 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
435 // mid point of the x variable
436 const double x_midpt = 0.5 * (SOLN.coord(j + 1, 0).first + SOLN.coord(j, 0).first);
437 // the order of the problem
438 const unsigned order(p_EQUATION -> get_order());
439 // number of spatial nodes in the y-direction
440 const unsigned ny(SOLN.get_nnodes().second);
441 // row counter
442 std::size_t row(0);
443 // local state variables
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);
448 // Current and old state
449 DenseVector<_Type> F_midpt(order, 0.0);
450 DenseVector<_Type> O_midpt(order, 0.0);
451 // these store the Jacobian of the mass matrices times a state vector
452 DenseMatrix<_Type> h1(order, order, 0.0);
453 DenseMatrix<_Type> h2(order, order, 0.0);
454 // set the x-t coordinates in the BC
455 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
456 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
457 // update the BC residuals for the current iteration
458 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
459 // add the (linearised) bottom BCs to the matrix problem
460 for(unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
461 // loop thru variables at LHS of the domain
462 for(unsigned var = 0; var < order; ++var) {
463 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
464 }
465 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
466 ++row;
467 }
468 // inner nodes of the mesh, node = 0,1,2,...,ny-2
469 for(std::size_t node = 0; node <= ny - 2; ++node) {
470 // bottom and top nodes of the mid-y-point we're considering
471 const std::size_t b_node = node;
472 const std::size_t t_node = node + 1;
473 //
474 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
475 // work out state, state_dx, state_dt, state_dy ... all at the mid-point in x,y,t.
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;
488 }
489 //
490 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
491 // set the coord in the equation object
492 p_EQUATION -> coord(0) = y_midpt;
493 p_EQUATION -> coord(1) = T + DT / 2.;
494 p_EQUATION -> coord(2) = x_midpt;
495 // Update the equation to the mid point position
496 p_EQUATION -> update(state);
497 // evaluate the Jacobian of mass contribution multiplied by state_dt
498 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(state, state_dt, h1);
499 // evaluate the Jacobian of mass contribution multiplied by state_dx
500 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(state, state_dx, h2);
501 // mass matrix 1 times state_dt
502 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().multiply(state_dt));
503 // mass matrix 2 times state_dx
504 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().multiply(state_dx));
505 // loop over all the variables
506 // il = position for (0, b_node*order)
507 typename BandedMatrix<_Type>::elt_iter b_iter(a.get_elt_iter(0, b_node * order));
508 // ir = position for (0, t_node*order)
509 typename BandedMatrix<_Type>::elt_iter t_iter(a.get_elt_iter(0, t_node * order));
510 for(unsigned var = 0; var < order; ++var) {
511 // offset for (r,c) -> (r+row, c+var)
512 const std::size_t offset(var * a.noffdiag() * 3 + row);
513 // deriv at the MID POINT between nodes
514 //a( row, order * b_node + var ) = -inv_dy;
515 *(b_iter + offset) = -inv_dy;
516 //a( row, order * t_node + var ) = inv_dy;
517 *(t_iter + offset) = inv_dy;
518 // add the matrix mult terms to the linearised problem
519 for(unsigned i = 0; i < order; ++i) { // dummy index
520 const std::size_t offset(i * a.noffdiag() * 3 + row);
521 typename BandedMatrix<_Type>::elt_iter bottom(b_iter + offset);
522 typename BandedMatrix<_Type>::elt_iter top(t_iter + offset);
523 // add the Jacobian terms
524 //a( row, order * b_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
525 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
526 //a( row, order * t_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
527 *top -= p_EQUATION -> jacobian()(var, i) / 2;
528 // add the Jacobian of matrix terms
529 //a( row, order * b_node + i ) += h1( var, i ) * .5;
530 *bottom += h1(var, i) * .5;
531 //a( row, order * t_node + i ) += h1( var, i ) * .5;
532 *top += h1(var, i) * .5;
533 //a( row, order * b_node + i ) += h2( var, i ) * .5;
534 *bottom += h2(var, i) * .5;
535 //a( row, order * t_node + i ) += h2( var, i ) * .5;
536 *top += h2(var, i) * .5;
537 // add the mass matrix terms
538 //a( row, order * b_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dt;
539 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
540 //a( row, order * t_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dt;
541 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
542 //a( row, order * b_node + i ) += p_EQUATION -> mass0()( var, i ) * inv_dx;
543 *bottom += p_EQUATION -> matrix2()(var, i) * inv_dx;
544 //a( row, order * t_node + i ) += p_EQUATION -> mass0()( var, i ) * inv_dx;
545 *top += p_EQUATION -> matrix2()(var, i) * inv_dx;
546 }
547 // RHS
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 ];
551 b[ row ] *= 4;
552 // increment the row
553 row += 1;
554 }
555 }
556 // set the x-t coordinates in the BC
557 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
558 p_TOP_RESIDUAL -> coord(1) = T + DT;
559 // update the BC residuals for the current iteration
560 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
561 // add the (linearised) RHS BCs to the matrix problem
562 for(unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
563 // loop thru variables at RHS of the domain
564 for(unsigned var = 0; var < order; ++var) {
565 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
566 }
567 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
568 ++row;
569 }
570#ifdef PARANOID
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);
574 }
575#endif
576 }
577
578
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) {
584 // clear the Jacobian matrix
585 a.assign(0.0);
586 // inverse of the t-step
587 const double inv_dt(1. / DT);
588 // inverse of the x-step
589 const double inv_dx(1. / (SOLN.coord(j + 1, 0).first - SOLN.coord(j, 0).first));
590 // the x variable
591 const double x = SOLN.coord(j + 1, 0).first;
592 // the order of the problem
593 const unsigned order(p_EQUATION -> get_order());
594 // number of spatial nodes in the y-direction
595 // const unsigned nx( SOLN.get_nnodes().first );
596 const unsigned ny(SOLN.get_nnodes().second);
597 // row counter
598 std::size_t row(0);
599 // local state variables
600 //DenseVector<_Type> Q_state( order, 0.0 );
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);
607 // Current and old state
608 DenseVector<_Type> F_midpt(order, 0.0);
609 DenseVector<_Type> O_midpt(order, 0.0);
610 // these store the Jacobian of the mass matrices times a state vector
611 DenseMatrix<_Type> h1(order, order, 0.0);
612 DenseMatrix<_Type> h2(order, order, 0.0);
613 // set the x-t coordinates in the BC
614 p_BOTTOM_RESIDUAL -> coord(0) = SOLN.coord(j + 1, 0).first;
615 p_BOTTOM_RESIDUAL -> coord(1) = T + DT;
616 // update the BC residuals for the current iteration
617 p_BOTTOM_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, 0));
618 // add the (linearised) bottom BCs to the matrix problem
619 for(unsigned i = 0; i < p_BOTTOM_RESIDUAL-> get_order(); ++i) {
620 // loop thru variables at LHS of the domain
621 for(unsigned var = 0; var < order; ++var) {
622 a(row, var) = p_BOTTOM_RESIDUAL -> jacobian()(i, var);
623 }
624 b[ row ] = -p_BOTTOM_RESIDUAL -> residual()[ i ];
625 ++row;
626 }
627 // inner nodes of the mesh, node = 0,1,2,...,ny-2
628 for(std::size_t node = 0; node <= ny - 2; ++node) {
629 // bottom and top nodes of the mid-y-point we're considering
630 const std::size_t b_node = node;
631 const std::size_t t_node = node + 1;
632 //
633 const double inv_dy = 1. / (SOLN.coord(j, t_node).second - SOLN.coord(j, b_node).second);
634 // work out state, state_dx, state_dt, state_dy
635 // in this case the _midpt variable indicates that it is a mid-point in y evaluation
636 for(unsigned var = 0; var < order; ++var) {
637 const double Fj_midpt = (SOLN(j, b_node, var) + SOLN(j, t_node, var)) / 2;
638 //const double Oj_midpt = ( PREV_SOLN( j, b_node, var ) + PREV_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;
642 //
643 // zig-zag modification
644 //Qh_state[ var ] = ( Fjp1_midpt + Ojp1_midpt + Fj_midpt + Ojp2_midpt ) / 4;
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;
648 //
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;
653 }
654 //
655 double y_midpt = 0.5 * (SOLN.coord(j, b_node).second + SOLN.coord(j, t_node).second);
656 // set the coord in the equation object
657 p_EQUATION -> coord(0) = y_midpt;
658 p_EQUATION -> coord(1) = T + DT / 2.;
659 p_EQUATION -> coord(2) = x;
660 // Update the equation to the mid point position - averaged in the zig-zag scheme
661 p_EQUATION -> update(Qh_state);
662 // evaluate the Jacobian of mass contribution multiplied by state_dx
663 p_EQUATION -> get_jacobian_of_matrix2_mult_vector(Qh_state, state_dx, h2);
664 // matrix 2 times state_dx
665 const DenseVector<_Type> m2_times_state_dx(p_EQUATION -> matrix2().multiply(state_dx));
666 // Update the equation to the mid point position - without upstream influence
667 p_EQUATION -> update(Qh_state);
668 // evaluate the Jacobian of mass contribution multiplied by state_dt
669 p_EQUATION -> get_jacobian_of_matrix1_mult_vector(Qh_state, state_dt, h1);
670 // mass matrix 2 times state_dt
671 const DenseVector<_Type> m1_times_state_dt(p_EQUATION -> matrix1().multiply(state_dt));
672 // loop over all the variables
673 // il = position for (0, b_node*order)
674 typename BandedMatrix<_Type>::elt_iter b_iter(a.get_elt_iter(0, b_node * order));
675 // ir = position for (0, t_node*order)
676 typename BandedMatrix<_Type>::elt_iter t_iter(a.get_elt_iter(0, t_node * order));
677 for(unsigned var = 0; var < order; ++var) {
678 // offset for (r,c) -> (r+row, c+var)
679 const std::size_t offset(var * a.noffdiag() * 3 + row);
680 // deriv at the MID POINT between nodes
681 //a( row, order * b_node + var ) = -inv_dy;
682 *(b_iter + offset) = -inv_dy;
683 //a( row, order * t_node + var ) = inv_dy;
684 *(t_iter + offset) = inv_dy;
685 // add the matrix mult terms to the linearised problem
686 for(unsigned i = 0; i < order; ++i) { // dummy index
687 const std::size_t offset(i * a.noffdiag() * 3 + row);
688 const typename BandedMatrix<_Type>::elt_iter bottom(b_iter + offset);
689 const typename BandedMatrix<_Type>::elt_iter top(t_iter + offset);
690 // add the Jacobian terms
691 //a( row, order * b_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
692 *bottom -= p_EQUATION -> jacobian()(var, i) / 2;
693 //a( row, order * t_node + i ) -= p_EQUATION -> jacobian()( var, i ) / 2;
694 *top -= p_EQUATION -> jacobian()(var, i) / 2;
695 // add the Jacobian of mass terms
696 //a( row, order * b_node + i ) += h1( var, i ) * .5;
697 *bottom += h1(var, i) * .25;
698 //a( row, order * t_node + i ) += h1( var, i ) * .5;
699 *top += h1(var, i) * .25;
700 // add the Jacobian of mass terms
701 //a( row, order * b_node + i ) += h2( var, i ) * .5;
702 *bottom += h2(var, i) * .5;
703 //a( row, order * t_node + i ) += h2( var, i ) * .5;
704 *top += h2(var, i) * .5;
705 // add the mass matrix terms
706 //a( row, order * b_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dx;
707 *bottom += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
708 //a( row, order * t_node + i ) += p_EQUATION -> mass1()( var, i ) * inv_dx;
709 *top += -0.5*p_EQUATION -> matrix2()(var, i) * inv_dx;
710 //a( row, order * b_node + i ) += p_EQUATION -> mass2()( var, i ) * inv_dt;
711 *bottom += p_EQUATION -> matrix1()(var, i) * inv_dt;
712 //a( row, order * t_node + i ) += p_EQUATION -> mass2()( var, i ) * inv_dt;
713 *top += p_EQUATION -> matrix1()(var, i) * inv_dt;
714 }
715 // RHS
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 ];
719 b[ row ] *= 2;
720 // increment the row
721 row += 1;
722 }
723 }
724 // set the x-t coordinates in the BC
725 p_TOP_RESIDUAL -> coord(0) = SOLN.coord(j + 1, ny - 1).first;
726 p_TOP_RESIDUAL -> coord(1) = T + DT;
727 // update the BC residuals for the current iteration
728 p_TOP_RESIDUAL -> update(SOLN.get_nodes_vars(j + 1, ny - 1));
729 // add the (linearised) RHS BCs to the matrix problem
730 for(unsigned i = 0; i < p_TOP_RESIDUAL -> get_order(); ++i) {
731 // loop thru variables at RHS of the domain
732 for(unsigned var = 0; var < order; ++var) {
733 a(row, order * (ny - 1) + var) = p_TOP_RESIDUAL -> jacobian()(i, var);
734 }
735 b[ row ] = - p_TOP_RESIDUAL -> residual()[ i ];
736 ++row;
737 }
738#ifdef PARANOID
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);
742 }
743#endif
744 }
745
746
747
748
749 // the templated versions that we require are:
750 template class reversed_BL<double>
751 ;
752
753} // end namespace
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.
Definition: BandedMatrix.h:16
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...
Definition: BandedMatrix.h:227
void assign(_Type elt)
Assign a value the matrix so that it has the same geometry, but zero entries in all locations includi...
Definition: BandedMatrix.h:106
DenseVector< _Type >::elt_iter elt_iter
Definition: BandedMatrix.h:20
elt_iter get_elt_iter(std::size_t row, std::size_t col)
Definition: BandedMatrix.h:127
A matrix class that constructs a DENSE matrix as a row major std::vector of DenseVectors.
Definition: DenseMatrix.h:25
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
double inf_norm() const
Infinity norm.
Definition: DenseVector.cpp:59
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...
Definition: Exceptions.h:90
A generic runtime exception.
Definition: Exceptions.h:158
A base class to be inherited by objects that define residuals.
A simple CPU-clock-tick timer for timing metods.
Definition: Timer.h:19
A two dimensional mesh utility object.
A templated object for real/complex vector system of unsteady equations.
Definition: reversed_BL.h:24
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.
Definition: reversed_BL.cpp:17
void step2(const double &dt)
A Crank-Nicolson 'time' stepper.
Definition: reversed_BL.cpp:55
~reversed_BL()
Destructor.
Definition: reversed_BL.cpp:44
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,...
Definition: Utility.cpp:225
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.

© 2012

R.E. Hewitt