示例#1
0
  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;

  }
示例#2
0
  _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;
  }
示例#3
0
 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 );
 }
示例#4
0
 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 );
 }
示例#5
0
 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 );
 }
示例#6
0
 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 );
 }
示例#7
0
 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;
 }
示例#8
0
  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;
  }
示例#9
0
  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 ];
    }
  }
示例#10
0
  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 );
  }
示例#11
0
 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;
 }
示例#12
0
  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
        }
      }
    }
  }
示例#13
0
  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);
    }

  }