CppNoddy  0.92
All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Modules Pages
ODE_BVP.cpp
Go to the documentation of this file.
1/// \file ODE_BVP.cpp
2/// An implementation of a class for an \f$ n^{th} \f$-order ODE BVP defined by
3/// \f[ {\underline f}^\prime (x) = {\underline R}( {\underline f}(x), x )\,, \f]
4/// subject to \f$ n \f$ Dirichlet conditions defined at \f$ x = x_{left} \f$ or
5/// \f$ x_{right} \f$ for some components of \f$ {\underline f}(x) \f$. The system
6/// is solved by applying Newton iteration, with the intermediate problem:
7/// \f[ {\underline g}^\prime (x) - \frac{\partial {\underline R}}{\partial \underline f} \Big \vert_{\underline F} \,\,{\underline g}(x) = {\underline R}( {\underline F}(x), x) - {\underline F}^\prime (x) \,, \f]
8/// for the corrections \f$ \underline g(x) \f$ to the current approximation
9/// to the solution \f$ {\underline F}(x) \f$.The numerical scheme can be
10/// run for any given distribution of nodes and can adapt the nodal
11/// positions based on residual evaluations (including both refinement and unrefinement).
12
13#include <string>
14#include <utility>
15
16#include <ODE_BVP.h>
18#include <ArcLength_base.h>
19#include <BandedLinearSystem.h>
20#include <Residual.h>
21#include <Utility.h>
22#include <Exceptions.h>
23#include <Timer.h>
24#include <OneD_Node_Mesh.h>
25#include <Equation_1matrix.h>
26#include <Equation_2matrix.h>
27
28namespace CppNoddy {
29
30 template <typename _Type, typename _Xtype>
32 const DenseVector<_Xtype> &nodes,
33 Residual<_Type>* ptr_to_left_residual,
34 Residual<_Type>* ptr_to_right_residual) :
35 ArcLength_base<_Type> (),
36 MAX_ITERATIONS(12),
37 TOL(1.e-8),
38 LAST_DET_SIGN(0),
39 p_EQUATION(ptr_to_equation),
40 p_LEFT_RESIDUAL(ptr_to_left_residual),
41 p_RIGHT_RESIDUAL(ptr_to_right_residual),
42 MONITOR_DET(true) {
43 // set up the solution mesh using these nodes
44 SOLUTION = OneD_Node_Mesh<_Type, _Xtype>(nodes, p_EQUATION -> get_order());
45 if((p_LEFT_RESIDUAL -> get_number_of_vars() != p_EQUATION -> get_order()) ||
46 (p_RIGHT_RESIDUAL -> get_number_of_vars() != p_EQUATION -> get_order()) ||
47 (p_LEFT_RESIDUAL -> get_order() + p_RIGHT_RESIDUAL -> get_order() != p_EQUATION -> get_order())) {
48 std::cout << "order " << p_EQUATION -> get_order() << "\n";
49 std::cout << "left nvars " << p_LEFT_RESIDUAL -> get_number_of_vars() << "\n";
50 std::cout << "right nvars " << p_RIGHT_RESIDUAL -> get_number_of_vars() << "\n";
51 std::cout << "left order " << p_LEFT_RESIDUAL -> get_order() << "\n";
52 std::cout << "right order " << p_RIGHT_RESIDUAL -> get_order() << "\n";
53 std::string problem;
54 problem = "It looks like the ODE_BVP equation and boundary conditions are\n";
55 problem += "not well posed. The number of variables for each boundary condition\n";
56 problem += "has to be the same as the order of the equation. Also the order of\n";
57 problem += "both boundary conditions has to sum to the order of the equation.\n";
58 throw ExceptionRuntime(problem);
59 }
60#ifdef TIME
61 // timers
62 T_ASSEMBLE = Timer("ODE_BVP: Assembling of the matrix (incl. equation updates):");
63 T_SOLVE = Timer("ODE_BVP: Solving of the matrix:");
64 T_REFINE = Timer("ODE_BVP: Refining the mesh:");
65#endif
66 }
67
68 template <typename _Type, typename _Xtype>
70#ifdef TIME
71 std::cout << "\n";
72 //T_ASSEMBLE.stop();
73 T_ASSEMBLE.print();
74 //T_SOLVE.stop();
75 T_SOLVE.print();
76 //T_REFINE.stop();
77 T_REFINE.print();
78#endif
79 }
80
82 template <typename _Type, typename _Xtype>
84 // the order of the problem
85 unsigned order(p_EQUATION -> get_order());
86 // get the number of nodes in the mesh
87 // -- this may have been refined by the user since the
88 // last call.
89 unsigned n(SOLUTION.get_nnodes());
90 // measure of maximum residual
91 double max_residual(1.0);
92 // iteration counter
93 int counter = 0;
94 // determinant monitor
95 int det_sign(LAST_DET_SIGN);
96
97 // ANY LARGE STORAGE USED IN THE MAIN LOOP IS
98 // DEFINED HERE TO AVOID REPEATED CONSTRUCTION.
99 // Note we blank the A matrix after every iteration.
100 //
101 // Banded LHS matrix - max obove diagonal band width is
102 // from first variable at node i to last variable at node i+1
103 BandedMatrix<_Type> a(n * order, 2 * order - 1, 0.0);
104 // RHS
105 DenseVector<_Type> b(n * order, 0.0);
106 // linear solver definition
107#ifdef LAPACK
108 BandedLinearSystem<_Type> system(&a, &b, "lapack");
109#else
110 BandedLinearSystem<_Type> system(&a, &b, "native");
111#endif
112 // pass the local monitor_det flag to the linear system
113 system.set_monitor_det(MONITOR_DET);
114
115 // loop until converged or too many iterations
116 do {
117 // iteration counter
118 ++counter;
119#ifdef TIME
120 T_ASSEMBLE.start();
121#endif
122 assemble_matrix_problem(a, b);
123 actions_before_linear_solve(a, b);
124 max_residual = b.inf_norm();
125#ifdef DEBUG
126 std::cout << " ODE_BVP.solve : Residual_max = " << max_residual << " tol = " << TOL << "\n";
127#endif
128#ifdef TIME
129 T_ASSEMBLE.stop();
130 T_SOLVE.start();
131#endif
132 // linear solver
133 system.solve();
134 // keep the solution in a OneD_Node_Mesh object
135 for(std::size_t var = 0; var < order; ++var) {
136 for(std::size_t i = 0; i < n; ++i) {
137 SOLUTION(i, var) += b[ i * order + var ];
138 }
139 }
140#ifdef TIME
141 T_SOLVE.stop();
142#endif
143 } while((max_residual > TOL) && (counter < MAX_ITERATIONS));
144 if(counter >= MAX_ITERATIONS) {
145 std::string problem("\n The ODE_BVP.solve2 method took too many iterations. \n");
146 throw ExceptionItn(problem, counter, max_residual);
147 }
148
149 // last_det_sign is set to be 0 in ctor, it must be +/-1 when calculated
150 if(MONITOR_DET) {
151 det_sign = system.get_det_sign();
152 if(det_sign * LAST_DET_SIGN < 0) {
153 LAST_DET_SIGN = det_sign;
154 std::string problem;
155 problem = "[ INFO ] : Determinant monitor has changed signs in ODE_BVP.\n";
156 problem += "[ INFO ] : Bifurcation detected.\n";
157 throw ExceptionBifurcation(problem);
158 }
159 LAST_DET_SIGN = det_sign;
160 }
161 }
162
163 template <typename _Type, typename _Xtype>
164 double ODE_BVP<_Type, _Xtype>::arclength_solve(const double& step) {
165 this -> ds() = step;
166 // order of the equation
167 unsigned order(p_EQUATION -> get_order());
168 // the number of nodes in the BVP
169 unsigned n(SOLUTION.get_nnodes());
170 // Banded Jacobian
171 BandedMatrix<_Type> Jac(n * order, 2 * order - 1, 0.0);
172 // residuals over all nodes vectors
173 DenseVector<_Type> Res1(n * order, 0.0);
174 DenseVector<_Type> Res2(n * order, 0.0);
175 // RHS vectors for the linear solver(s)
176 DenseVector<_Type> y(n * order, 0.0);
177 DenseVector<_Type> z(n * order, 0.0);
178#ifdef LAPACK
179 BandedLinearSystem<_Type> system1(&Jac, &y, "lapack");
180 BandedLinearSystem<_Type> system2(&Jac, &z, "lapack");
181#else
182 BandedLinearSystem<_Type> system1(&Jac, &y, "native");
183 BandedLinearSystem<_Type> system2(&Jac, &z, "native");
184#endif
185 // we use the member data 'monitor_det' to set the linear system determinant monitor
186 system1.set_monitor_det(MONITOR_DET);
187 // make backups in case we can't find a converged solution
188 DenseVector<_Type> backup_state(SOLUTION.vars_as_vector());
189 _Type backup_parameter(*(this -> p_PARAM));
190 // we can generate a 1st-order guess for the next state and parameter
191 DenseVector<_Type> x(this -> LAST_X + this -> X_DERIV_S * this -> DS);
192 *(this -> p_PARAM) = this -> LAST_PARAM + this -> PARAM_DERIV_S * this -> DS;
193 // the class keeps the solution in a OneD_mesh object, so we update it here
194 SOLUTION.set_vars_from_vector(x);
195 // determinant monitor
196 int det_sign(0);
197 // a flag to indicate if we have made a successful step
198 bool step_succeeded(false);
199 // iteration counter
200 int counter = 0;
201 // loop until converged or too many iterations
202 do {
203 /// \todo y & z should be solved for simultaneously - but to do this
204 /// we'd have to extend the LAPACK interface and/or provide the
205 /// same feature for the native solver.
206 ++counter;
207 // extra constraint corresponding to the new unknow parameter (arclength)
208 double E1 = this -> arclength_residual(x);
209 // construct the Jacobian/residual matrix problem
210 assemble_matrix_problem(Jac, Res1);
211 actions_before_linear_solve(Jac, Res1);
212 //BandedMatrix<_Type> Jac_copy( Jac );
213 y = Res1;
214#ifdef DEBUG
215 //std::cout << " [ DEBUG ] : max_residual = " << Res1.inf_norm() << "\n";
216#endif
217 if(Res1.inf_norm() < TOL && counter > 1) {
218 step_succeeded = true;
219 break;
220 }
221 try {
222 system1.solve();
223 det_sign = system1.get_det_sign();
224 } catch(const ExceptionExternal &error) {
225 step_succeeded = false;
226 break;
227 }
228 // derivs w.r.t parameter
229 const double delta(1.e-8);
230 *(this -> p_PARAM) += delta;
231 // we actually just want the Res2 & e2 vectors, so we still
232 // use the original Jacobian j ... but it was overwritten by the
233 // previous solve.
234 assemble_matrix_problem(Jac, Res2);
235 //Jac = Jac_copy;
236 double E2 = this -> arclength_residual(x);
237 actions_before_linear_solve(Jac, Res2);
238 *(this -> p_PARAM) -= delta;
239 DenseVector<_Type> dRes_dp((Res2 - Res1) / delta);
240 double dE_dp = (E2 - E1) / delta;
241 z = dRes_dp;
242 try {
243 system2.solve();
244 } catch(const ExceptionExternal& error) {
245 step_succeeded = false;
246 break;
247 }
248 // this is the extra (full) row in the augmented matrix problem
249 // bottom row formed from dE/dx_j
250 DenseVector<_Type> Jac_E(this -> Jac_arclength_residual(x));
251 // given the solutions y & z, the bordering algo provides the
252 // solution to the full sparse system via
253 _Type delta_p = - (E1 + Utility::dot(Jac_E, y)) /
254 (dE_dp + Utility::dot(Jac_E, z));
255 DenseVector<_Type> delta_x = y + z * delta_p;
256#ifdef DEBUG
257 std::cout << " [ DEBUG ] : Arclength_solve, dp = " << delta_p
258 << " dx.inf_norm() = " << delta_x.inf_norm()
259 << " theta = " << this -> THETA << "\n";
260#endif
261 // update the state variables and the parameter with corrections
262 x += delta_x;
263 *(this -> p_PARAM) += delta_p;
264 // the corrections must be put back into the mesh container
265 SOLUTION.set_vars_from_vector(x);
266 // converged?
267 if(delta_x.inf_norm() < TOL) {
268 step_succeeded = true;
269 break;
270 }
271 // too many iterations?
272 if ((counter > MAX_ITERATIONS) || (delta_x.inf_norm() > 100 )) {
273 step_succeeded = false;
274 break;
275 }
276 } while(true);
277 //
278 if(!step_succeeded) {
279 // if not a successful step then restore things
280 SOLUTION.set_vars_from_vector(backup_state);
281 *(this -> p_PARAM) = backup_parameter;
282 // reduce our step length
283 this -> DS /= this -> ARCSTEP_MULTIPLIER;
284#ifdef DEBUG
285 std::cout << "[ DEBUG ] : REJECTING STEP \n";
286 std::cout << "[ DEBUG ] : I decreased DS to " << this -> DS << "\n";
287#endif
288 } else {
289 // update the variables needed for arc-length continuation
290 this -> update(SOLUTION.vars_as_vector());
291 if(LAST_DET_SIGN * det_sign < 0) {
292 // a change in the sign of the determinant of the Jacobian
293 // has been found
294 LAST_DET_SIGN = det_sign;
295 std::string problem;
296 problem = "[ INFO ] : Determinant monitor has changed signs in the Newton class.\n";
297 problem += "[ INFO ] : Bifurcation detected.\n";
298 throw ExceptionBifurcation(problem);
299 }
300
301#ifdef DEBUG
302 std::cout << " [ DEBUG ] : Number of iterations = " << counter << "\n";
303 std::cout << " [ DEBUG ] : Parameter p = " << *(this -> p_PARAM)
304 << "; arclength DS = " << this -> DS << "\n";
305 std::cout << " [ DEBUG ] : Arclength THETA = " << this -> THETA << "\n";
306#endif
307 if(counter > 8 || std::abs(this -> DS) > this -> MAX_DS) {
308 // converging too slowly, so decrease DS
309 this -> DS /= this -> ARCSTEP_MULTIPLIER;
310#ifdef DEBUG
311 std::cout << " [ DEBUG ] : I decreased DS to " << this -> DS << "\n";
312#endif
313 }
314 if(counter < 4) {
315 if(std::abs(this -> DS * this -> ARCSTEP_MULTIPLIER) < this -> MAX_DS) {
316 // converging too quickly, so increase DS
317 this -> DS *= this -> ARCSTEP_MULTIPLIER;
318#ifdef DEBUG
319 std::cout << " [ DEBUG ] : I increased DS to " << this -> DS << "\n";
320#endif
321 }
322 }
323 }
324 return this -> DS;
325 }
326
327 template <typename _Type, typename _Xtype>
329 SOLUTION.set_vars_from_vector(state);
330 try {
331 solve2();
332 } catch(const ExceptionBifurcation &bifn) {
333 // dont throw from this routine, it's only needed for
334 // the arclength_base class
335 }
336 state = SOLUTION.vars_as_vector();
337 }
338
339
340 template <typename _Type, typename _Xtype>
341 void ODE_BVP<_Type, _Xtype>::assemble_matrix_problem(BandedMatrix<_Type>& a, DenseVector<_Type>& b) {
342 // clear the Jacobian matrix, since not all elts will be overwritten
343 // in the routine below.
344 a.assign(0.0);
345 // the order of the problem
346 unsigned order(p_EQUATION -> get_order());
347 // get the number of nodes in the mesh
348 unsigned n(SOLUTION.get_nnodes());
349 // row counter
350 std::size_t row(0);
351 // Jacobian matrix for the equation
352 DenseMatrix<_Type> Jac_midpt(order, order, 0.0);
353 // local state variable and functions
354 DenseVector<_Type> F_midpt(order, 0.0);
355 DenseVector<_Type> R_midpt(order, 0.0);
356 DenseVector<_Type> state_dy(order, 0.0);
357 // a matrix that is used in the Jacobian of the mass matrix terms
358 DenseMatrix<_Type> h0(order, order, 0.0);
359 // update the BC residuals for the current iteration
360 p_LEFT_RESIDUAL -> update(SOLUTION.get_nodes_vars(0));
361 // add the (linearised) LHS BCs to the matrix problem
362 for(unsigned i = 0; i < p_LEFT_RESIDUAL -> get_order(); ++i) {
363 // loop thru variables at LHS of the domain
364 for(unsigned var = 0; var < order; ++var) {
365 a(row, var) = p_LEFT_RESIDUAL -> jacobian()(i, var);
366 }
367 b[ row ] = - p_LEFT_RESIDUAL -> residual()[ i ];
368 ++row;
369 }
370 // inner nodes of the mesh, node = 0,1,2,...,N-2
371 for(std::size_t node = 0; node <= n - 2; ++node) {
372 const std::size_t lnode = node;
373 const std::size_t rnode = node + 1;
374 // inverse of step size
375 const _Xtype invh = 1. / (SOLUTION.coord(rnode) - SOLUTION.coord(lnode));
376 // set the current solution at this node by 2nd order evaluation at mid point
377 for(unsigned var = 0; var < order; ++var) {
378 F_midpt[ var ] = (SOLUTION(lnode, var) + SOLUTION(rnode, var)) / 2.;
379 state_dy[ var ] = (SOLUTION(rnode, var) - SOLUTION(lnode, var)) * invh;
380 }
381 // mid point of the independent variable
382 _Xtype y_midpt = (SOLUTION.coord(lnode) + SOLUTION.coord(rnode)) / 2.;
383 // set the equation coord
384 p_EQUATION -> coord(0) = y_midpt;
385 // Update the equation to the mid point position
386 p_EQUATION -> update(F_midpt);
387
388 // evaluate the Jacobian of mass contribution multiplied by state_dy
389 p_EQUATION -> get_jacobian_of_matrix0_mult_vector(F_midpt, state_dy, h0);
390
391 // loop over all the variables
392 for(unsigned var = 0; var < order; ++var) {
393 // add the matrix mult terms to the linearised problem
394 for(unsigned i = 0; i < order; ++i) { // dummy index
395 // Jac of matrix * F_y * g terms
396 a(row, order * lnode + i) += h0(var, i)/2.;
397 a(row, order * rnode + i) += h0(var, i)/2.;
398 // Matrix * g_y terms
399 a(row, order * lnode + i) -= p_EQUATION -> matrix0()(var, i) * invh;
400 a(row, order * rnode + i) += p_EQUATION -> matrix0()(var, i) * invh;
401 // Jacobian of RHS terms
402 a(row, order * lnode + i) -= p_EQUATION -> jacobian()(var, i)/2.;
403 a(row, order * rnode + i) -= p_EQUATION -> jacobian()(var, i)/2.;
404 }
405 // RHS
406 b[ row ] = p_EQUATION -> residual()[ var ] - Utility::dot(p_EQUATION -> matrix0()[ var ], state_dy);
407 // increment the row
408 row += 1;
409 }
410 }
411 // update the BC residuals for the current iteration
412 p_RIGHT_RESIDUAL -> update(SOLUTION.get_nodes_vars(n - 1));
413 // add the (linearised) RHS BCs to the matrix problem
414 for(unsigned i = 0; i < p_RIGHT_RESIDUAL -> get_order(); ++i) {
415 // loop thru variables at RHS of the domain
416 for(unsigned var = 0; var < order; ++var) {
417 a(row, order * (n - 1) + var) = p_RIGHT_RESIDUAL -> jacobian()(i, var);
418 }
419 b[ row ] = - p_RIGHT_RESIDUAL -> residual()[ i ];
420 ++row;
421 }
422#ifdef PARANOID
423 if(row != n * order) {
424 std::string problem("\n The ODE_BVP has an incorrect number of boundary conditions. \n");
425 throw ExceptionRuntime(problem);
426 }
427#endif
428 }
429
430 // specialise to remove adaptivity from problems in the complex plane
431 template<>
432 std::pair< unsigned, unsigned > ODE_BVP<std::complex<double>, std::complex<double> >::adapt(const double& adapt_tol) {
433 std::string problem;
434 problem = " The ODE_BVP.adapt method has been called for a \n";
435 problem += " problem in the complex plane. This doesn't make sense \n";
436 problem += " as the path is not geometrically defined. \n";
437 throw ExceptionRuntime(problem);
438 }
439
440 // specialise to remove adaptivity from problems in the complex plane
441 template<>
442 std::pair< unsigned, unsigned > ODE_BVP<double, std::complex<double> >::adapt(const double& adapt_tol) {
443 std::string problem;
444 problem = " The ODE_BVP.adapt method has been called for a \n";
445 problem += " problem in the complex plane. This doesn't make sense \n";
446 problem += " as the path is not geometrically defined. \n";
447 throw ExceptionRuntime(problem);
448 }
449
450 // specialise to remove adaptivity from problems in the complex plane
451 template<>
452 void ODE_BVP<std::complex<double>, std::complex<double> >::adapt_until(const double& adapt_tol) {
453 std::string problem;
454 problem = " The ODE_BVP.adapt method has been called for a \n";
455 problem += " problem in the complex plane. This doesn't make sense \n";
456 problem += " as the path is not geometrically defined. \n";
457 throw ExceptionRuntime(problem);
458 }
459
460 // specialise to remove adaptivity from problems in the complex plane
461 template<>
462 void ODE_BVP<double, std::complex<double> >::adapt_until(const double& adapt_tol) {
463 std::string problem;
464 problem = " The ODE_BVP.adapt method has been called for a \n";
465 problem += " problem in the complex plane. This doesn't make sense \n";
466 problem += " as the path is not geometrically defined. \n";
467 throw ExceptionRuntime(problem);
468 }
469
470 template< typename _Type, typename _Xtype>
471 void ODE_BVP<_Type, _Xtype>::adapt_until(const double& adapt_tol) {
472 std::pair< unsigned, unsigned > changes;
473 do {
474 changes = adapt(adapt_tol);
475 solve2();
476 std::cout << "[INFO] Adapting: " << changes.first << " " << changes.second << "\n";
477 } while(changes.first + changes.second != 0);
478 }
479
480 template <typename _Type, typename _Xtype>
481 std::pair< unsigned, unsigned > ODE_BVP<_Type, _Xtype>::adapt(const double& adapt_tol) {
482#ifdef TIME
483 T_REFINE.start();
484#endif
485 // the order of the problem
486 unsigned order(p_EQUATION -> get_order());
487 // get the number of nodes in the mesh
488 // -- this may have been refined by the user since the
489 // last call.
490 unsigned N(SOLUTION.get_nnodes());
491 // row counter
492 //std::size_t row( 0 );
493 // local state variable and functions
494 DenseVector<_Type> F_node(order, 0.0);
495 DenseVector<_Type> R_node(order, 0.0);
496 // make sure (un)refine flags vector is sized
497 std::vector< bool > refine(N, false);
498 std::vector< bool > unrefine(N, false);
499 // Residual vector at interior nodes
500 DenseVector<double> Res2(N, 0.0);
501 // reset row counter
502 //row = 0;
503 // inner nodes of the mesh, node = 1,2,...,N-2
504 for(std::size_t node = 1; node <= N - 2; node += 2) {
505 // set the current solution at this node
506 for(unsigned var = 0; var < order; ++var) {
507 //F_node[ var ] = SOLUTION[ var ][ node ];
508 F_node[ var ] = SOLUTION(node, var);
509 }
510 // set the y-pos in the eqn
511 p_EQUATION -> coord(0) = SOLUTION.coord(node);
512 // Update the equation to the nodal position
513 p_EQUATION -> update(F_node);
514 //// evaluate the RHS at the node
515 //p_EQUATION -> get_residual( R_node );
516 // step size centred at the node
517 _Xtype invh = 1. / (SOLUTION.coord(node + 1) - SOLUTION.coord(node - 1));
518 // loop over all the variables
519 DenseVector<_Type> temp(order, 0.0);
520 for(unsigned var = 0; var < order; ++var) {
521 // residual
522 //temp[ var ] = p_EQUATION -> residual()[ var ] - ( SOLUTION[ var ][ node + 1 ] - SOLUTION[ var ][ node - 1 ] ) * invh;
523 temp[ var ] = p_EQUATION -> residual()[ var ] - (SOLUTION(node + 1, var) - SOLUTION(node - 1, var)) * invh;
524 }
525 Res2[ node ] = temp.inf_norm();
526 if(Res2[ node ] > adapt_tol) {
527 refine[ node ] = true;
528 } else if(Res2[ node ] < TOL / 10.) {
529 unrefine[ node ] = true;
530 }
531 }
532
533 std::size_t no_refined(0), no_unrefined(0);
534 for(std::size_t i = 0; i < refine.size(); ++i) {
535 if(refine[ i ] == true) {
536 no_refined += 1;
537 }
538 if(unrefine[ i ] == true) {
539 no_unrefined += 1;
540 }
541 }
542#ifdef DEBUG
543 std::cout << "[ DEBUG ] Refinements = " << no_refined << "\n";
544 std::cout << "[ DEBUG ] Unrefinements = " << no_unrefined << "\n";
545#endif
546
547 // make a new refined/unrefined mesh
548 DenseVector<_Xtype> X(SOLUTION.nodes());
550 newX.push_back(X[ 0 ]);
551 for(std::size_t i = 1; i < N - 1; ++i) {
552 if(refine[ i ]) {
553 if(!refine[ i - 1 ]) {
554 // have not already refined to the left
555 // so refine left AND right with new nodes
556 _Xtype left(X[ i - 1 ]);
557 _Xtype right(X[ i + 1 ]);
558 _Xtype here(X[ i ]);
559 newX.push_back((left + here) / 2.);
560 newX.push_back(here);
561 newX.push_back((right + here) / 2.);
562 } else {
563 // already left refined, so just refine right
564 _Xtype right(X[ i + 1 ]);
565 _Xtype here(X[ i ]);
566 newX.push_back(here);
567 newX.push_back((right + here) / 2.);
568 }
569 } else if(!unrefine[ i ]) {
570 newX.push_back(X[ i ]);
571 }
572 }
573 newX.push_back(X[ N - 1 ]);
574
575 // remesh the current solution to this (un)refined mesh
576 SOLUTION.remesh1(newX);
577#ifdef TIME
578 T_REFINE.stop();
579#endif
580 // adding nodes will screw up the sign of the determinant of the Jacobian
581 // so here we'll just make it zero
582 LAST_DET_SIGN = 0;
583
584 std::pair< unsigned, unsigned > feedback;
585 feedback.first = no_refined;
586 feedback.second = no_unrefined;
587 return feedback;
588 }
589
590 // the templated versions that we require are:
591 template class ODE_BVP<double>;
592 template class ODE_BVP<std::complex<double> >;
593 template class ODE_BVP<std::complex<double>, std::complex<double> >;
594
595
596} // end namespace
597
A base class for arclength-capable solvers.
Specification of the linear system class.
A templated class for equations that can be inherited from to allow instantiation of PDE_IBVP objects...
A templated class for equations that can be inherited from to allow instantiation of PDE_double_IBVP ...
The collection of CppNoddy exceptions.
A specification of a class for an -order ODE BVP defined by.
A specification for a one dimensional mesh object.
A specification of a (double/complex) VECTOR residual class.
A specification of a (double/complex) residual class that not only defines a vector residual of a vec...
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.
void set_monitor_det(bool flag)
Store the sign of the determinant of the LHS matrix every time a solve is requested on a real system.
int get_det_sign() const
Get the sign of the determinant of the LHS matrix from the linear system just computed.
A matrix class that constructs a BANDED matrix.
Definition: BandedMatrix.h:16
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
double inf_norm() const
Infinity norm.
Definition: DenseVector.cpp:59
void assign(const std::size_t n, const _Type elem)
A pass-thru definition of assign.
Definition: DenseVector.h:190
An equation object base class used in the IBVP classes (and others).
An exception to indicate that an error has been detected in an external (LAPACK) routine.
Definition: Exceptions.h:20
A generic runtime exception.
Definition: Exceptions.h:158
A templated object for real/complex vector system of first-order ordinary differential equations.
Definition: ODE_BVP.h:37
double arclength_solve(const double &step)
Arc-length solve the system.
Definition: ODE_BVP.cpp:164
void adapt_until(const double &adapt_tol)
Adaptively solve the system until no refinements or unrefinements are applied.
Definition: ODE_BVP.cpp:471
virtual ~ODE_BVP()
Destructor.
Definition: ODE_BVP.cpp:69
ODE_BVP(Equation_1matrix< _Type, _Xtype > *ptr_to_equation, const DenseVector< _Xtype > &nodes, Residual< _Type > *ptr_to_left_residual, Residual< _Type > *ptr_to_right_residual)
The class is defined by a vector function for the system.
Definition: ODE_BVP.cpp:31
std::pair< unsigned, unsigned > adapt(const double &adapt_tol)
Adapt the computational mesh ONCE.
Definition: ODE_BVP.cpp:481
void solve2()
Formulate and solve the ODE using Newton iteration and a second-order finite difference scheme.
Definition: ODE_BVP.cpp:83
A one dimensional mesh utility object.
A base class to be inherited by objects that define residuals.
Definition: Residual.h:15
A simple CPU-clock-tick timer for timing metods.
Definition: Timer.h:19
_Type dot(const DenseVector< _Type > &X, const DenseVector< _Type > &Y)
Templated dot product.
Definition: Utility.h:314
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt