メインコンテンツに移動

解答例3

まずmain()ですね.

#include <iostream>
#include "heat.hpp"
int main(int argc, const char * argv[]) {
  int N=50,nt=0;
  double dt=0.1;
  Heat Solver(N,dt);
  Solver.vtk(nt);
  double errmax=1e-5,err;
  while (errmax<(err=Solver.Step(nt++)))
  {
    Solver.vtk(nt);
    std::cout << "nt= " << nt << " err= " << err << std::endl;
  }
  return 0;
}

Heatクラスの仕様は上で完全に決定しているので,あとは実装するだけですわ.

#include <sstream>
#include <boost/filesystem.hpp>
#include "libSPARSE.hpp"
#include "myArray.hpp"
class Heat
{
  double xmax=1.;
  double u_x0=0.,u_x1=0.,u_y0=1.,u_y1=0.; //境界条件
  double dx,dt,cfl;
  myArray<double> mySOL;
  SPARSE::Coef myMAT;
public:
  Heat(int N,double dt):mySOL(N-1,N-1)
  {
    dx=xmax/N;
    cfl=dt/dx/dx;
    for(int i=0; i<mySOL.size(0);i++)
    for(int j=0; j<mySOL.size(1);j++)
    {
      double x=(i+1)*dx,y=(j+1)*dx;
      mySOL(i,j)=(1+y-2*y*y)*(1-4*(x-0.5)*(x-0.5));
    }
    //行列サイズは mySOL.size()xmySOL.size()になる
    for(int k=0;k<mySOL.size();k++) myMAT.New(k,1.0+4*cfl);//対角成分は 1+4*cfl
    for(int k=0;k<mySOL.size();k++) myMAT[k][myMAT.Dimension()]=0.;
    for(int k=0;k<mySOL.size();k++)//他の要素を入れる
    {
      int i=mySOL.index(0,k); //k番目の未知数のi
      int j=mySOL.index(1,k); //k番目の未知数のj
      if (i==0) myMAT[k][myMAT.Dimension()]+=cfl*u_x0;
      else myMAT[k][mySOL.serial(i-1,j)]=-cfl;
      if (i==mySOL.size(0)-1) myMAT[k][myMAT.Dimension()]+=cfl*u_x1;
      else myMAT[k][mySOL.serial(i+1,j)]=-cfl;
      if (j==0) myMAT[k][myMAT.Dimension()]+=cfl*u_y0;
      else myMAT[k][mySOL.serial(i,j-1)]=-cfl;
      if (j==mySOL.size(1)-1) myMAT[k][myMAT.Dimension()]+=cfl*u_y1;
      else myMAT[k][mySOL.serial(i,j+1)]=-cfl;
    }
    boost::filesystem::path folder=getenv("HOME");
    boost::filesystem::current_path(folder/"tes_test");
  }
  double Step(int nt)
  {
    auto thisMAT=myMAT;
    for(int k=0;k<mySOL.size();k++)
      thisMAT[k][thisMAT.Dimension()]+=mySOL[k];
    thisMAT.MakeIndex();
    thisMAT.EraseUp();
    thisMAT.EraseDown();
    thisMAT.ClearIndex();
    double err=0.0;
    for(int k=0;k<mySOL.size();k++)
    {
      err=std::max(std::abs(thisMAT[k][thisMAT.Dimension()]-mySOL[k]),err);
      mySOL[k]=thisMAT[k][thisMAT.Dimension()];
    }
    return err;
  }
  void vtk(int nt)
  {
    std::ostringstream oss;
    oss << "vtk_" <<  std::setfill('0') << std::right << std::setw(6) << nt << ".vtk";
    std::ofstream vout(oss.str());
    vout << "# vtk DataFile Version 2.0" << std::endl << "ひゃっほう" << std::endl << "ASCII" << std::endl;
    //Geometry指定
    vout << "DATASET STRUCTURED_POINTS" << std::endl;
    vout << "DIMENSIONS " << mySOL.size(0)+2 << " " << mySOL.size(1)+2 << " " << 1 << std::endl;
    vout << "ORIGIN 0 0 0" << std::endl;
    vout << "SPACING " << 1.0/(mySOL.size(0)+1) << " " << 1.0/(mySOL.size(1)+1) << " " << 1.0 << std::endl;
    //DataSet指定
    vout << "POINT_DATA " << (mySOL.size(0)+2)*(mySOL.size(1)+2) << std::endl;
    vout << "SCALARS U double" << std::endl;
    vout << "LOOKUP_TABLE default" << std::endl;
    for(int j=0;j<mySOL.size(1)+2;j++)
    for(int i=0;i<mySOL.size(0)+2;i++)
    {
      if (i==0) vout << u_x0 <<std::endl;
      else if (i==mySOL.size(0)+1) vout << u_x1 <<std::endl;
      else
      {
        if (j==0) vout << u_y0 <<std::endl;
        else if (j==mySOL.size(1)+1) vout << u_y1 <<std::endl;
        else vout << mySOL(i-1,j-1) <<std::endl;
      }
    }
  }
};
#endif /* heat_hpp */

新しい文法要素はありませんね.念のためmyArray.hppも示しておきます:

#ifndef myArray_hpp
#define myArray_hpp
#include <iostream>
#include <vector>
template <class T> class myArray
{
  std::vector<int> _sizes;
  std::vector<int> _upto;
  std::vector<T> _data;
public:
  T* data() {return _data.data();}
  const int size(){return _upto.back();}
  const int size(const int index){return _sizes.at(index);}
  T& operator[](const int k){return _data[k];}
  typename std::vector<T>::iterator begin(){return _data.begin();}
  typename std::vector<T>::iterator end(){return _data.end();}
  const int index(const int dim,const int k)
  {
    int _index=k;
    for(int i=0;i<dim;i++) _index/=_sizes[i];
    if (dim==_sizes.size()-1) return _index;
    return _index%_sizes[dim];
  }
  myArray(const int n0,const int n1)
  {
    _sizes.resize(2); //2次元配列である
    _upto.resize(2);
    _sizes[0]=n0; _sizes[1]=n1;_upto[0]=n0; _upto[1]=_upto[0]*n1;
    _data.resize(size());
  }
  const int serial(const int i0,const int i1){return i0+_upto[0]*i1;}
  T& operator()(const int i0,const int i1){return _data[serial(i0,i1)];}
  myArray(const int n0,const int n1,const int n2)
  {
    _sizes.resize(3); //3次元配列である
    _upto.resize(3);
    _sizes[0]=n0; _sizes[1]=n1; _sizes[2]=n2;_upto[0]=n0; _upto[1]=_upto[0]*n1; _upto[2]=_upto[1]*n2;
    _data.resize(size());
  }
  const int serial(const int i0,const int i1,const int i2){return i0+_upto[0]*i1+_upto[1]*i2;}
  T& operator()(const  int i0,const int i1,const int i2){return _data[serial(i0,i1,i2)];}
};
#endif /* myArray_hpp */

以上