30 template <
typename _Type,
typename _Xtype>
39 p_EQUATION(ptr_to_equation),
40 p_LEFT_RESIDUAL(ptr_to_left_residual),
41 p_RIGHT_RESIDUAL(ptr_to_right_residual),
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";
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";
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:");
68 template <
typename _Type,
typename _Xtype>
82 template <
typename _Type,
typename _Xtype>
85 unsigned order(p_EQUATION -> get_order());
89 unsigned n(SOLUTION.get_nnodes());
91 double max_residual(1.0);
95 int det_sign(LAST_DET_SIGN);
113 system.set_monitor_det(MONITOR_DET);
122 assemble_matrix_problem(a, b);
123 actions_before_linear_solve(a, b);
124 max_residual = b.inf_norm();
126 std::cout <<
" ODE_BVP.solve : Residual_max = " << max_residual <<
" tol = " << TOL <<
"\n";
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 ];
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);
151 det_sign = system.get_det_sign();
152 if(det_sign * LAST_DET_SIGN < 0) {
153 LAST_DET_SIGN = det_sign;
155 problem =
"[ INFO ] : Determinant monitor has changed signs in ODE_BVP.\n";
156 problem +=
"[ INFO ] : Bifurcation detected.\n";
157 throw ExceptionBifurcation(problem);
159 LAST_DET_SIGN = det_sign;
163 template <
typename _Type,
typename _Xtype>
167 unsigned order(p_EQUATION -> get_order());
169 unsigned n(SOLUTION.get_nnodes());
189 _Type backup_parameter(*(
this -> p_PARAM));
192 *(
this -> p_PARAM) =
this -> LAST_PARAM +
this -> PARAM_DERIV_S *
this -> DS;
194 SOLUTION.set_vars_from_vector(x);
198 bool step_succeeded(
false);
208 double E1 =
this -> arclength_residual(x);
210 assemble_matrix_problem(Jac, Res1);
211 actions_before_linear_solve(Jac, Res1);
217 if(Res1.
inf_norm() < TOL && counter > 1) {
218 step_succeeded =
true;
225 step_succeeded =
false;
229 const double delta(1.e-8);
230 *(
this -> p_PARAM) += delta;
234 assemble_matrix_problem(Jac, Res2);
236 double E2 =
this -> arclength_residual(x);
237 actions_before_linear_solve(Jac, Res2);
238 *(
this -> p_PARAM) -= delta;
240 double dE_dp = (E2 - E1) / delta;
245 step_succeeded =
false;
257 std::cout <<
" [ DEBUG ] : Arclength_solve, dp = " << delta_p
258 <<
" dx.inf_norm() = " << delta_x.
inf_norm()
259 <<
" theta = " <<
this -> THETA <<
"\n";
263 *(
this -> p_PARAM) += delta_p;
265 SOLUTION.set_vars_from_vector(x);
268 step_succeeded =
true;
272 if ((counter > MAX_ITERATIONS) || (delta_x.
inf_norm() > 100 )) {
273 step_succeeded =
false;
278 if(!step_succeeded) {
280 SOLUTION.set_vars_from_vector(backup_state);
281 *(
this -> p_PARAM) = backup_parameter;
283 this -> DS /=
this -> ARCSTEP_MULTIPLIER;
285 std::cout <<
"[ DEBUG ] : REJECTING STEP \n";
286 std::cout <<
"[ DEBUG ] : I decreased DS to " <<
this -> DS <<
"\n";
290 this -> update(SOLUTION.vars_as_vector());
291 if(LAST_DET_SIGN * det_sign < 0) {
294 LAST_DET_SIGN = det_sign;
296 problem =
"[ INFO ] : Determinant monitor has changed signs in the Newton class.\n";
297 problem +=
"[ INFO ] : Bifurcation detected.\n";
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";
307 if(counter > 8 || std::abs(
this -> DS) >
this -> MAX_DS) {
309 this -> DS /=
this -> ARCSTEP_MULTIPLIER;
311 std::cout <<
" [ DEBUG ] : I decreased DS to " <<
this -> DS <<
"\n";
315 if(std::abs(
this -> DS *
this -> ARCSTEP_MULTIPLIER) <
this -> MAX_DS) {
317 this -> DS *=
this -> ARCSTEP_MULTIPLIER;
319 std::cout <<
" [ DEBUG ] : I increased DS to " <<
this -> DS <<
"\n";
327 template <
typename _Type,
typename _Xtype>
329 SOLUTION.set_vars_from_vector(state);
332 }
catch(
const ExceptionBifurcation &bifn) {
336 state = SOLUTION.vars_as_vector();
340 template <
typename _Type,
typename _Xtype>
341 void ODE_BVP<_Type, _Xtype>::assemble_matrix_problem(BandedMatrix<_Type>& a, DenseVector<_Type>& b) {
346 unsigned order(p_EQUATION -> get_order());
348 unsigned n(SOLUTION.get_nnodes());
352 DenseMatrix<_Type> Jac_midpt(order, order, 0.0);
354 DenseVector<_Type> F_midpt(order, 0.0);
355 DenseVector<_Type> R_midpt(order, 0.0);
356 DenseVector<_Type> state_dy(order, 0.0);
358 DenseMatrix<_Type> h0(order, order, 0.0);
360 p_LEFT_RESIDUAL -> update(SOLUTION.get_nodes_vars(0));
362 for(
unsigned i = 0; i < p_LEFT_RESIDUAL -> get_order(); ++i) {
364 for(
unsigned var = 0; var < order; ++var) {
365 a(row, var) = p_LEFT_RESIDUAL -> jacobian()(i, var);
367 b[ row ] = - p_LEFT_RESIDUAL -> residual()[ i ];
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;
375 const _Xtype invh = 1. / (SOLUTION.coord(rnode) - SOLUTION.coord(lnode));
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;
382 _Xtype y_midpt = (SOLUTION.coord(lnode) + SOLUTION.coord(rnode)) / 2.;
384 p_EQUATION -> coord(0) = y_midpt;
386 p_EQUATION -> update(F_midpt);
389 p_EQUATION -> get_jacobian_of_matrix0_mult_vector(F_midpt, state_dy, h0);
392 for(
unsigned var = 0; var < order; ++var) {
394 for(
unsigned i = 0; i < order; ++i) {
396 a(row, order * lnode + i) += h0(var, i)/2.;
397 a(row, order * rnode + i) += h0(var, i)/2.;
399 a(row, order * lnode + i) -= p_EQUATION -> matrix0()(var, i) * invh;
400 a(row, order * rnode + i) += p_EQUATION -> matrix0()(var, i) * invh;
402 a(row, order * lnode + i) -= p_EQUATION -> jacobian()(var, i)/2.;
403 a(row, order * rnode + i) -= p_EQUATION -> jacobian()(var, i)/2.;
406 b[ row ] = p_EQUATION -> residual()[ var ] -
Utility::dot(p_EQUATION -> matrix0()[ var ], state_dy);
412 p_RIGHT_RESIDUAL -> update(SOLUTION.get_nodes_vars(n - 1));
414 for(
unsigned i = 0; i < p_RIGHT_RESIDUAL -> get_order(); ++i) {
416 for(
unsigned var = 0; var < order; ++var) {
417 a(row, order * (n - 1) + var) = p_RIGHT_RESIDUAL -> jacobian()(i, var);
419 b[ row ] = - p_RIGHT_RESIDUAL -> residual()[ i ];
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);
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";
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";
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";
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";
470 template<
typename _Type,
typename _Xtype>
472 std::pair< unsigned, unsigned > changes;
474 changes = adapt(adapt_tol);
476 std::cout <<
"[INFO] Adapting: " << changes.first <<
" " << changes.second <<
"\n";
477 }
while(changes.first + changes.second != 0);
480 template <
typename _Type,
typename _Xtype>
486 unsigned order(p_EQUATION -> get_order());
490 unsigned N(SOLUTION.get_nnodes());
497 std::vector< bool > refine(N,
false);
498 std::vector< bool > unrefine(N,
false);
504 for(std::size_t node = 1; node <= N - 2; node += 2) {
506 for(
unsigned var = 0; var < order; ++var) {
508 F_node[ var ] = SOLUTION(node, var);
511 p_EQUATION -> coord(0) = SOLUTION.coord(node);
513 p_EQUATION -> update(F_node);
517 _Xtype invh = 1. / (SOLUTION.coord(node + 1) - SOLUTION.coord(node - 1));
520 for(
unsigned var = 0; var < order; ++var) {
523 temp[ var ] = p_EQUATION -> residual()[ var ] - (SOLUTION(node + 1, var) - SOLUTION(node - 1, var)) * invh;
526 if(Res2[ node ] > adapt_tol) {
527 refine[ node ] =
true;
528 }
else if(Res2[ node ] < TOL / 10.) {
529 unrefine[ node ] =
true;
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) {
538 if(unrefine[ i ] ==
true) {
543 std::cout <<
"[ DEBUG ] Refinements = " << no_refined <<
"\n";
544 std::cout <<
"[ DEBUG ] Unrefinements = " << no_unrefined <<
"\n";
551 for(std::size_t i = 1; i < N - 1; ++i) {
553 if(!refine[ i - 1 ]) {
556 _Xtype left(X[ i - 1 ]);
557 _Xtype right(X[ i + 1 ]);
564 _Xtype right(X[ i + 1 ]);
569 }
else if(!unrefine[ i ]) {
576 SOLUTION.remesh1(newX);
584 std::pair< unsigned, unsigned > feedback;
585 feedback.first = no_refined;
586 feedback.second = no_unrefined;
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.
An DenseVector class – a dense vector object.
void push_back(const _Type &fill)
A pass-thru definition of push_back.
double inf_norm() const
Infinity norm.
void assign(const std::size_t n, const _Type elem)
A pass-thru definition of assign.
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.
A generic runtime exception.
A templated object for real/complex vector system of first-order ordinary differential equations.
double arclength_solve(const double &step)
Arc-length solve the system.
void adapt_until(const double &adapt_tol)
Adaptively solve the system until no refinements or unrefinements are applied.
virtual ~ODE_BVP()
Destructor.
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.
std::pair< unsigned, unsigned > adapt(const double &adapt_tol)
Adapt the computational mesh ONCE.
void solve2()
Formulate and solve the ODE using Newton iteration and a second-order finite difference scheme.
A one dimensional mesh utility object.
A base class to be inherited by objects that define residuals.
A simple CPU-clock-tick timer for timing metods.
_Type dot(const DenseVector< _Type > &X, const DenseVector< _Type > &Y)
Templated dot product.
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...