void OneD_Node_Mesh<std::complex<double>, double>::remesh1( const DenseVector<double>& newX ) { #ifdef PARANOID if ( std::abs( X[ 0 ] - newX[ 0 ] ) > 1.e-10 || std::abs( X[ X.size() - 1 ] - newX[ newX.size() - 1 ] ) > 1.e-10 ) { std::string problem; problem = " The OneD_Node_Mesh.remesh method has been called with \n"; problem += " a passed coordinate vector that has different start and/or \n"; problem += " end points from the instantiated object. \n"; throw ExceptionRuntime( problem ); } for ( std::size_t i = 0; i < newX.size() - 1; ++i ) { if ( newX[ i ] >= newX[ i + 1 ] ) { std::string problem; problem = " The OneD_Node_Mesh.remesh method has been passed \n"; problem += " a non-monotonic coordinate vector. \n"; throw ExceptionRuntime( problem ); } } #endif // copy current state of this mesh DenseVector<std::complex<double> > copy_of_vars( VARS ); // resize the local storage VARS.resize( newX.size() * NV ); // first nodal values are assumed to be untouched // loop thru destination mesh node at a time for ( std::size_t node = 1; node < newX.size() - 1; ++node ) { // loop through the source mesh and find the bracket-nodes for ( std::size_t i = 0; i < X.size(); ++i ) { if ( ( X[ i ] <= newX[ node ] ) && ( newX[ node ] < X[ i + 1 ] ) ) { // linearly interpolate each variable in the mesh for ( std::size_t var = 0; var < NV; ++var ) { double dX = newX[ node ] - X[ i ]; // if the paranoid checks above are satisfied, then the X[ i + 1 ] should still be in bounds std::complex<double> dvarsdX = ( copy_of_vars[ ( i+1 )*NV + var ] - copy_of_vars[ i*NV + var ] ) / ( X[ i + 1 ] - X[ i ] ); VARS[ node * NV + var ] = copy_of_vars[ i * NV + var ] + dX * dvarsdX; } } } } // add the last nodal values to the resized vector for ( std::size_t var = 0; var < NV; ++var ) { VARS[ ( newX.size() - 1 ) * NV + var ] = copy_of_vars[ ( X.size() - 1 ) * NV + var ]; } // replace the old nodes with the new ones X = newX; }
_Type OneD_Node_Mesh<_Type, _Xtype>::integral4( std::size_t var ) const { if ( ( X.size() ) % 2 == 0 ) { std::string problem; problem = " The OneD_Node_Mesh.Simpson_integral method is trying to run \n"; problem += " on a mesh with an even number of points. \n"; throw ExceptionRuntime( problem ); } _Type f0, f1, f2; _Xtype x0, x1, x2; _Type sum = 0.0; // sum interior segments for ( std::size_t node = 0; node < X.size() - 2; node += 2 ) { x0 = X[ node ]; x1 = X[ node + 1 ]; x2 = X[ node + 2 ]; f0 = VARS[ node * NV + var ]; f1 = VARS[ ( node+1 ) * NV + var ]; f2 = VARS[ ( node+2 ) * NV + var ]; sum += ( x2 - x0 ) * ( f1 * pow( x0 - x2, 2 ) + f0 * ( x1 - x2 ) * ( 2. * x0 - 3. * x1 + x2 ) - f2 * ( x0 - x1 ) * ( x0 - 3. * x1 + 2. * x2 ) ) / ( 6. * ( x0 - x1 ) * ( x1 - x2 ) ); // sum += (x1-x0)*( f0 + 4*f1 + f2 ) / 3.0 for equal spacing } // return the value return sum; }
DenseVector<double> OneD_Node_Mesh<std::complex<double>, double >::find_roots1( const std::size_t &var, double value ) const { std::string problem; problem = " The OneD_Node_Mesh.find_roots1 method has been called with \n"; problem += " a mesh containing complex data.\n"; throw ExceptionRuntime( problem ); }
DenseVector<std::complex<double> > OneD_Node_Mesh<std::complex<double>, double>::get_interpolated_vars( const double& x_pos ) const { for ( unsigned node = 0; node < X.size() - 1; ++node ) { // find bracketing nodes - incl shameless hack for evaluations at the boundary if ( ( X[ node ] < x_pos || std::abs( X[ node ] - x_pos ) < 1.e-7 ) && ( X[ node + 1 ] > x_pos || std::abs( X[ node + 1 ] - x_pos ) < 1.e-7 ) ) { // distance from left node double delta_x( x_pos - X[ node ] ); // empty data to return DenseVector<std::complex<double> > left; DenseVector<std::complex<double> > right; DenseVector<std::complex<double> > deriv; // interpolate data linearly left = get_nodes_vars( node ); right = get_nodes_vars( node + 1 ); deriv = ( right - left ) / ( X[ node + 1 ] - X[ node ] ); // overwrite right right = left + deriv * delta_x; return right; } } std::cout << "You asked for a position of " << x_pos << " in a range " << X[ 0 ] << " to " << X[ X.size() - 1 ] << "\n"; std::string problem; problem = "You have asked the OneD_Node_Mesh class to interpolate data at\n"; problem += "a point that is outside the range covered by the mesh object.\n"; throw ExceptionRuntime( problem ); }
void OneD_Node_Mesh<std::complex<double>, std::complex<double> >::remesh1( const DenseVector<std::complex<double> >& z ) { std::string problem; problem = " The OneD_Node_Mesh.remesh method has been called with \n"; problem += " a complex data set on a complex mesh.\n"; throw ExceptionRuntime( problem ); }
void LinearSystem_base::solve() { std::string problem; problem = "The solve method has not been implemented for\n"; problem += "the container class you are using here.\n"; throw ExceptionRuntime( problem ); }
DenseMatrix<D_complex> DenseLinearEigenSystem<_Type>::get_tagged_eigenvectors() const { if ( TAGGED_INDICES.size() == 0 ) { std::string problem; problem = "In DenseLinearEigenSystem.get_tagged_eigenvectors() : there are\n"; problem += "no eigenvalues that have been tagged. This set is empty.\n"; throw ExceptionRuntime( problem ); } // order of the problem std::size_t N = EIGENVALUES_ALPHA.size(); // eigenvector storage : size() eigenvectors each of length N DenseMatrix<D_complex> evecs( TAGGED_INDICES.size(), N, 0.0 ); std::size_t row = 0; // loop through the tagged set for ( iter p = TAGGED_INDICES.begin(); p != TAGGED_INDICES.end(); ++p ) { // get the index of the relevant eigenvalue from the set std::size_t j = *p; // put the eigenvector in the matrix evecs[ row ] = ALL_EIGENVECTORS[ j ]; // next row/eigenvector ++row; } return evecs; }
void OneD_Node_Mesh<_Type, _Xtype>::set_vars_from_vector( const DenseVector<_Type>& vec ) { #ifdef PARANOID if ( vec.size() != NV * X.size() ) { std::string problem; problem = "The set_vars_from_vector method has been passed a vector\n"; problem += "of a length that is of an incompatible size for this mesh object\n"; throw ExceptionRuntime( problem ); } #endif VARS = vec; }
void TwoD_Mapped_Node_Mesh<_Type>::set_nodes_vars(const std::size_t nodex, const std::size_t nodey, const DenseVector<_Type>& U) { #ifdef PARANOID if(U.size() > m_nv) { std::string problem; problem = " The TwoD_Mapped_Node_Mesh.set_nodes_vars method is trying to use a \n"; problem += " vector that has more entries than variables stored in the mesh. \n"; throw ExceptionRuntime(problem); } #endif // assign contents of U to the member data std::size_t offset((nodex * m_ny + nodey) * m_nv); for(std::size_t var = 0; var < m_nv; ++var) { m_vars[ offset++ ] = U[ var ]; } }
DenseVector<std::complex<double> > OneD_Node_Mesh<std::complex<double>, std::complex<double> >::get_interpolated_vars( const std::complex<double>& pos ) const { double x_pos( pos.real() ); #ifdef PARANOID std::cout << "WARNING: You are interpolating complex data on a complex mesh with 'get_interpolated_vars'.\n"; std::cout << " This does a simple piecewise linear interpolating assuming a single valued path. \n"; #endif for ( unsigned node = 0; node < X.size() - 1; ++node ) { // find bracketing nodes - incl shameless hack for evaluations at the boundary if ( ( X[ node ].real() < x_pos || std::abs( X[ node ].real() - x_pos ) < 1.e-7 ) && ( X[ node + 1 ].real() > x_pos || std::abs( X[ node + 1 ].real() - x_pos ) < 1.e-7 ) ) { // distance from left node -- real coordinate is given. We also need to // interpolate between the two complex nodes -- hence imaginary coordinate is implict from // bracketing (complex) nodes std::complex<double> delta_z = ( X[ node + 1 ] - X[ node ] ) * ( x_pos - X[ node ].real() ) / ( X[ node + 1 ].real() - X[ node ].real() ); // empty data to return DenseVector<std::complex<double> > left; DenseVector<std::complex<double> > right; DenseVector<std::complex<double> > deriv; // interpolate data linearly left = get_nodes_vars( node ); right = get_nodes_vars( node + 1 ); // derivative of the data deriv = ( right - left ) / ( X[ node + 1 ] - X[ node ] ); // overwrite right right = left + deriv * delta_z; return right; } } std::cout << "You asked for a position of " << x_pos << " in a range " << X[ 0 ] << " to " << X[ X.size() - 1 ] << "\n"; std::string problem; problem = "You have asked the OneD_Node_Mesh class to interpolate data at\n"; problem += "a point that is outside the range covered by the mesh object.\n"; problem += "Even for complex nodes we assume the path is single valued.\n"; throw ExceptionRuntime( problem ); }
DenseVector<D_complex> DenseLinearEigenSystem<_Type>::get_tagged_eigenvalues() const { if ( TAGGED_INDICES.size() == 0 ) { std::string problem; problem = "In DenseLinearEigenSystem.get_tagged_eigenvalues() : there are\n"; problem += "no eigenvalues that have been tagged. This set is empty.\n"; throw ExceptionRuntime( problem ); } // storage for the eigenvalues DenseVector<D_complex> evals; // loop through the tagged set for ( iter p = TAGGED_INDICES.begin(); p != TAGGED_INDICES.end(); ++p ) { // get the index of the relevant eigenvalue from the set std::size_t j = *p; // work out the complex eigenvalue associated with this index // and add it to the vector evals.push_back( EIGENVALUES_ALPHA[ j ] / EIGENVALUES_BETA[ j ] ); } // return the complex vector of eigenvalues return evals; }
void Newton<_Type>::arclength_solve(DenseVector<_Type>& x) { #ifdef PARANOID if(!this -> INITIALISED) { std::string problem; problem = "The Newton.arclength_solve method has been called, but \n"; problem += " you haven't called the arc_init method first. This means \n"; problem += " that a starting solution & derivatives thereof are unknown. \n"; problem += " Please initialise things appropriately! "; throw ExceptionRuntime(problem); } #endif #ifdef DEBUG std::cout.precision(6); std::cout << "[ DEBUG ] : Entering arclength_solve of the Newton class with\n"; std::cout << "[ DEBUG ] : a parameter of " << *(this -> p_PARAM) << "\n"; #endif // backup the state/system in case we fail DenseVector<_Type> backup_state(x); _Type backup_parameter(*(this -> p_PARAM)); int det_sign(1); // init some local vars bool step_succeeded(false); unsigned itn(0); // make a guess at the next solution *(this -> p_PARAM) = this -> LAST_PARAM + this -> PARAM_DERIV_S * this -> DS; x = this -> LAST_X + this -> X_DERIV_S * this -> DS; // the order of the system unsigned N = this -> p_RESIDUAL -> get_order(); DenseMatrix<_Type> J(N, N, 0.0); DenseVector<_Type> R1(N, 0.0); DenseVector<_Type> R2(N, 0.0); DenseVector<_Type> dR_dp(N, 0.0); // do { // update the residual object to the current guess this -> p_RESIDUAL -> update(x); // get the Jacobian of the system J = this -> p_RESIDUAL -> jacobian(); R1 = this -> p_RESIDUAL -> residual(); // get the residual of the EXTRA arclength residual double E1 = this -> arclength_residual(x); // compute derivatives w.r.t the parameter *(this -> p_PARAM) += this -> DELTA; this -> p_RESIDUAL -> residual_fn(x, R2); double E2 = this -> arclength_residual(x); *(this -> p_PARAM) -= this -> DELTA; dR_dp = (R2 - R1) / this -> DELTA; _Type dE_dp = (E2 - E1) / this -> DELTA; // bordering algorithm DenseVector<_Type> y(-R1); DenseVector<_Type> z(-dR_dp); #ifdef LAPACK DenseLinearSystem<_Type> sys1(&J, &y, "lapack"); #else DenseLinearSystem<_Type> sys1(&J, &y, "native"); #endif sys1.set_monitor_det(MONITOR_DET); try { sys1.solve(); det_sign = sys1.get_det_sign(); } catch ( const ExceptionExternal &error ) { break; } // the solve will have overwritten the LHS, so we need to replace it J = this -> p_RESIDUAL -> jacobian(); #ifdef LAPACK DenseLinearSystem<_Type> sys2(&J, &z, "lapack"); #else DenseLinearSystem<_Type> sys2(&J, &z, "native"); #endif try { sys2.solve(); } catch( const ExceptionExternal &error ) { break; } DenseVector<_Type> JacE(this -> Jac_arclength_residual(x)); _Type delta_p = - (E1 + Utility::dot(JacE, y)) / (dE_dp + Utility::dot(JacE, z)); DenseVector<_Type> delta_x = y + z * delta_p; double max_correction = std::max(delta_x.inf_norm(), std::abs(delta_p)); if(max_correction < this -> TOL) { step_succeeded = true; break; } // add the corrections to the state variables x += delta_x; *(this -> p_PARAM) += delta_p; ++itn; if(itn > MAX_STEPS) { step_succeeded = false; break; } } while(true); // is this a successful step? if(!step_succeeded) { #ifdef DEBUG std::cout << "[ DEBUG ] : REJECTING STEP \n"; #endif // if not a successful step then restore things x = backup_state; *(this -> p_PARAM) = backup_parameter; // restore the residual object to its initial state this -> p_RESIDUAL -> update(x); // reduce our step length this -> DS /= this -> ARCSTEP_MULTIPLIER; } else { // update the variables needed for arc-length continuation this -> update(x); if(LAST_DET_SIGN * det_sign < 0) { LAST_DET_SIGN = det_sign; std::string problem; problem = "[ INFO ] : Determinant monitor has changed signs in the Newton class.\n"; problem += "[ INFO ] : Bifurcation detected.\n"; throw ExceptionBifurcation(problem); } else { LAST_DET_SIGN = det_sign; } #ifdef DEBUG std::cout << "[ DEBUG ] : Number of iterations = " << itn << "\n"; std::cout << "[ DEBUG ] : Parameter p = " << *(this -> p_PARAM) << "; arclength DS = " << this -> DS << "\n"; #endif if(itn >= 7) { // converging too slowly, so decrease DS this -> DS /= this -> ARCSTEP_MULTIPLIER; #ifdef DEBUG std::cout << "[ DEBUG ] : I decreased DS to " << this -> DS << "\n"; #endif } if(itn <= 2) { if(std::abs(this -> DS * this -> ARCSTEP_MULTIPLIER) < this -> MAX_DS) { // converging too quickly, so increase DS this -> DS *= this -> ARCSTEP_MULTIPLIER; #ifdef DEBUG std::cout << "[ DEBUG ] : I increased DS to " << this -> DS << "\n"; #endif } } } }
void ODE_EVP<_Type>::assemble_dense_problem() { // clear the A & B matrices, as they could have been filled with // pivoting if this is a second solve. p_A_DENSE -> assign(0.0); p_B_DENSE -> assign(0.0); // eqn order unsigned order(p_EQUATION -> get_order()); // Jacobian matrix for the equation DenseMatrix<_Type> jac_midpt(order, order, 0.0); // local state variable and functions // the problem has to be linear, so this is a dummy vector. DenseVector<_Type> temp_dummy(order, 0.0); // number of nodes in the mesh std::size_t num_of_nodes(NODES.size()); // row counter std::size_t row(0); // update the BC residuals for the current iteration p_LEFT_RESIDUAL -> update(temp_dummy); // add the (linearised) LHS BCs to the matrix problem for(unsigned i = 0; i < p_LEFT_RESIDUAL -> get_order(); ++i) { // loop thru variables at LHS of the domain for(unsigned var = 0; var < order; ++var) { (*p_A_DENSE)(row, var) = p_LEFT_RESIDUAL -> jacobian()(i, var); (*p_B_DENSE)(row, var) = 0.0; } ++row; } // inner nodes of the mesh, node = 0,1,2,...,num_of_nodes-2 for(std::size_t node = 0; node <= num_of_nodes - 2; ++node) { const std::size_t lnode = node; const std::size_t rnode = node + 1; // get the current step length double h = NODES[ rnode ] - NODES[ lnode ]; // reciprocal of the spatial step const double invh(1. / h); // mid point of the independent variable double x_midpt = 0.5 * (NODES[ lnode ] + NODES[ rnode ]); p_EQUATION -> coord(0) = x_midpt; // Update the equation to the mid point position p_EQUATION -> update(temp_dummy); // loop over all the variables and fill the matrix for(unsigned var = 0; var < order; ++var) { std::size_t placement_row(row + var); // deriv at the MID POINT between nodes (*p_A_DENSE)(placement_row, order * rnode + var) = invh; (*p_A_DENSE)(placement_row, order * lnode + var) = -invh; // add the Jacobian terms to the linearised problem for(unsigned i = 0; i < order; ++i) { (*p_A_DENSE)(placement_row, order * lnode + i) -= 0.5 * p_EQUATION -> jacobian()(var, i); (*p_A_DENSE)(placement_row, order * rnode + i) -= 0.5 * p_EQUATION -> jacobian()(var, i); } // RHS for(unsigned i = 0; i < order; ++i) { (*p_B_DENSE)(placement_row, order * lnode + i) -= 0.5 * p_EQUATION -> matrix1()(var, i); (*p_B_DENSE)(placement_row, order * rnode + i) -= 0.5 * p_EQUATION -> matrix1()(var, i); } } // increment the row row += order; } // update the BC residuals for the current iteration p_RIGHT_RESIDUAL -> update(temp_dummy); // add the (linearised) LHS BCs to the matrix problem for(unsigned i = 0; i < p_RIGHT_RESIDUAL -> get_order(); ++i) { // loop thru variables at LHS of the domain for(unsigned var = 0; var < order; ++var) { (*p_A_DENSE)(row, order * (num_of_nodes - 1) + var) = p_RIGHT_RESIDUAL -> jacobian()(i, var); (*p_B_DENSE)(row, order * (num_of_nodes - 1) + var) = 0.0; } ++row; } if(row != num_of_nodes * order) { std::string problem("\n The ODE_BVP has an incorrect number of boundary conditions. \n"); throw ExceptionRuntime(problem); } }