这两个代码有什么区别? [关闭]

问题描述 投票:-1回答:2

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

第一个也是用于求解微分系统,所以基本上它使用的矢量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

c++ differential-equations
2个回答
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] + ...


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 ;    
  }
© www.soinside.com 2019 - 2024. All rights reserved.