这2个代码有什么区别?

时间:2017-12-14 12:27:21

标签: c++ differential-equations

我使用预测校正器方法编写了两个用于解决差分问题的代码。

第一个也是用于求解微分系统,所以基本上它使用大小等于系统中要解决的等式数的向量y,所以这个基本上被覆盖每一步和不会存储之前的步骤。

第二个使用大小等于步数的向量,因此很容易控制我们使用的元素。

我写了两个不同的(但基本相同的)函数:一个用于第一个例程,第二个用于第二个例程

我做了很多调试,但我不明白我做错了什么。

以下是解算器的两个不同版本:

# include <iostream>
# include <functional>
# include <vector>
# include <string>
# include <cmath>
# include <fstream>
# include <valarray>


using namespace std;


std::vector<std::function<const double(const double t , std::valarray<double> u)>> func ;


auto f2      = [](double t , double u) {return -20*u+20*sin(t)+cos(t) ; } ;

auto numFun  = [](double t , std::valarray<double> u) {return -20*u[0]+20*sin(t)+cos(t) ; } ;


int main (){

      double t0 = 0.0 ;
      double tf = 2.5 ;
      double dt = 0.01;


      const int N = (tf-t0)/dt;

      func.push_back(numFun);

      auto& f  =    func ;

      double t1 ;
      std::valarray<double> y1 ; 
      y1.resize(func.size()) ;   // size = 1  
      std::valarray<double> yp1 ; 
      yp1.resize(func.size()) ;  // size = 1


      std::vector<double> t2(N+1)  ;
      std::vector<double> y2(N+1)  ;
      std::vector<double> yp2(N+1) ;



      std::vector<double> u(1);
      u.at(0) = 1.0 ;

      t1  = t0 ;

      for(auto i=0; i< u.size() ; i++)
      {  
         y1[i]= u.at(i);
         yp1[i] = u.at(i);   
      }


      ofstream fn("output1.dat", ios::out);



      for(auto i=1 ; i <=N ; i++ )
      {

         fn << t1 << " " ;
         for(auto j =0 ; j < y1.size() ; j++ )
           fn << y1[j] << " " ;
         fn << endl ;

         for(auto j=0 ; j < y1.size() ; j++)
         {
            yp1[j] = yp1[j] + dt * f[j](t1 , y1) ;      

            y1[j] += dt/2 * ( f[j](t1 , y1) + f[j]( t1+dt , yp1 ));

         }
         t1+=dt ;    
      }
      fn.close();

/* --------------------          Vector version      --------------------------------- */      

      ofstream fn2("output2.dat", ios::out);

      t2.at(0) = t0 ;

      y2.at(0) = u.at(0) ;
      yp2.at(0) = u.at(0) ;


      fn2 << t2.at(0) << " " ;
      fn2 << y2.at(0) << " " ;
      fn2 << endl ;

      for(auto i=1; i <= N  ; i++ )
      {
         t2.at(i) = t2.at(i-1) + dt ;

        // Predictor step (Exp Euler) 

         yp2.at(i) = y2.at(i-1) + dt * f2(t2.at(i-1), y2.at(i-1)) ;  

         y2.at(i) = y2.at(i-1) + dt/2 * ( f2(t2.at(i-1), y2.at(i-1)) + f2(t2.at(i), yp2.at(i)) ) ;


         fn2 << t2.at(i) << ' ' << y2.at(i) << " " ;

         fn2 << endl;    
      }

      fn2.close();



  return 0;
}

我在输出文件中得到了两个不同的结果: this

2 个答案:

答案 0 :(得分:3)

对于第一个处理向量值ODE的方法,您需要将这三个步骤分成三个循环,对应于第二个方法中的向量运算。请注意,第二种方法在y1的更新中包含隐式中间向量,因为在将y1复制到y1之前,首先使用旧值 for(auto i=1 ; i <=N ; i++ ) { fn << t1 << " " ; for(auto j =0 ; j < y1.size() ; j++ ) fn << y1[j] << " " ; fn << (exp(-20*t1) + sin(t1)) << " "; fn << endl ; for(auto j=0 ; j < y1.size() ; j++) { yp1[j] = y1[j] + dt * f[j](t1 , y1) ; } for(auto j=0 ; j < y1.size() ; j++) { yc1[j] = y1[j] + dt/2 * ( f[j](t1 , y1) + f[j]( t1+dt , yp1 )); } for(auto j=0 ; j < y1.size() ; j++) { y1[j] = yc1[j]; } t1+=dt ; } 完全计算右侧。

{{1}}

答案 1 :(得分:0)

尝试以这种方式使用3个矢量!

         for(t=t0() ; t < tf() ; t+= dt()  )
         {
           f << t << ' ' ; 
           for(auto i=0 ; i< u.size() ; i++) 
               f << u[i] << " " ; 
           f << std::endl ;

           for( auto i=0 ; i < u.size() ; i++)        
           {      
                  up[i] = uc[i] + dt() * rhs.f[i](t , u) ;   


                  uc[i] += dt()/2 * ( rhs.f[i](t , u) + rhs.f[i]( t +dt() , up ) ); 

                   u[i] = uc[i] ;
           }             

         } 

所以基本上预测变量必须是uc[i] + ...,并且不能像标准欧拉公式中那样+=(在这种情况下,他写了yp1[j] = yp1[j] + ...yp1[j] = y[j] + ...