Thomas算法求解热方程

Solution of heat equation by Thomas algorithm

我正在尝试使用 Thomas 算法求解微分热方程。

物理问题:我们有插头,左边温度0,右边温度1

对于 Thomas 算法,我写了一个函数,它接受三个 QVectorint 值的方程。

这是我的代码:

#include <QCoreApplication>
#include <QVector>
#include <QDebug>
#include <iostream>
using std::cin;

void enterIn(QVector<float> &Array, int Amount_of_elements){
    int transit;
    for(int i=0;i<Amount_of_elements;i++){
        cin>>transit;
        Array.push_back(transit);
    }
}

QVector<float> shuttle_method(const QVector<float> &below_main_diagonal,
                              QVector<float> &main_diagonal,
                              const QVector<float> &beyond_main_diagonal,
                              const QVector<float> &free_term,
                              const int N){
    QVector <float> c;
    QVector <float> d;

    for(int i=0;i<N;i++){
        main_diagonal[i]*=(-1);
    }

    QVector<float> x; //result

    c.push_back(beyond_main_diagonal[0]/main_diagonal[0]);
    d.push_back(-free_term[0]/main_diagonal[0]);

    for(int i=1;i<=N-2;i++){
        c.push_back(beyond_main_diagonal[i]/(main_diagonal[i]-below_main_diagonal[i]*c[i-1]));
        d.push_back(  (below_main_diagonal[i]*d[i-1]  -  free_term[i])  /  (main_diagonal[i]-  below_main_diagonal[i]*c[i-1])  );
    }

    x.resize(N);
    //qDebug()<<x.size()<<endl;

    int n=N-1;
    x[n]=(below_main_diagonal[n]*d[n-1]-free_term[n])/(main_diagonal[n]-below_main_diagonal[n]*c[n-1]);

    for(int i=n-1;i>=0;i--){
        x[i]=c[i]*x[i+1]+d[i];
        // qDebug()<<x[i]<<endl;
    }

    return x;
}

int main()
{    
    QVector <float> alpha;  // below
    QVector <float> beta;   // main diagonal * (-1)
    QVector <float> gamma;  // beyond
    QVector <float> b;      // free term

    QVector<float> T;

    int cells_x=40;         //amount of equations
    alpha.resize(cells_x);
    beta.resize(cells_x);
    gamma.resize(cells_x);
    b.resize(cells_x);
    T.resize(cells_x);

    float dt=0.2,h=0.1;

    alpha[0]=0;
    for(int i=1;i<cells_x;i++){
        alpha[i]= -dt/(h*h);
    }

    for(int i=0;i<cells_x;i++){
        beta[i] = (2*dt)/(h*h)+1;
    }
    for(int i=0;i<cells_x-1;i++){
        gamma[i]= -dt/(h*h);
    }
    gamma[cells_x-1]=0;

    qDebug()<<"alpha= "<<endl<<alpha.size()<<alpha<<endl<<"beta = "<<endl<<beta.size()<<beta<<endl<<"gamma= "<<gamma.size()<<gamma<<endl;


    for(int i=0;i<cells_x-1;i++){
        T[i]=0;
    }
    T[cells_x-1]=1;
    qDebug()<<endl<<endl<<T<<endl;

    //qDebug()<< shuttle_method(alpha,beta,gamma,b,N);

    QVector<float> Tn;
    Tn.resize(cells_x);
    Tn = shuttle_method(alpha,beta,gamma,T,cells_x);
    Tn[0]=0;Tn[cells_x-1]=1;
    for(int stepTime = 0; stepTime < 50; stepTime++){
        Tn = shuttle_method(alpha,beta,gamma,Tn,cells_x);
        Tn[0]=0;
        Tn[cells_x-1]=1;
        qDebug()<<Tn<<endl;
    }
    return 0;
}

我的问题是: 当我编译并 运行 它时,我得到这个:

Tn  <20 items>  QVector<float>
0   float
0.000425464 float
0.000664658 float
0.000937085 float
0.00125637  float
0.00163846  float
0.00210249  float
0.00267163  float
0.00337436  float
0.00424581  float
0.00532955  float
0.00667976  float
0.00836396  float
0.0104664   float
0.0130921   float
0.0163724   float
0.0204714   float
0.0255939   float
0.0319961   float

Tn  <20 items>  QVector<float>
0   float
-0.000425464    float
0.000643385 float
-0.000926707    float
0.00120951  float
-0.00161561 float
0.00202056  float
-0.00263167 float
0.00324078  float
-0.00418065 float
0.00511726  float
-0.00657621 float
0.00802998  float
-0.0103034  float
0.0125688   float
-0.0161171  float
0.0196527   float
-0.0251945  float
0.0307164   float
1   float

Tn  <20 items>  QVector<float>
0   float
0.000425464 float
0.000664658 float
0.000937085 float
0.00125637  float
0.00163846  float
0.00210249  float
0.00267163  float
0.00337436  float
0.00424581  float
0.00532955  float
0.00667976  float
0.00836396  float
0.0104664   float
0.0130921   float
0.0163724   float
0.0204714   float
0.0255939   float
0.0319961   float

Tn  <20 items>  QVector<float>
0   float
-0.000425464    float
0.000643385 float
-0.000926707    float
0.00120951  float
-0.00161561 float
0.00202056  float
-0.00263167 float
0.00324078  float
-0.00418065 float
0.00511726  float
-0.00657621 float
0.00802998  float
-0.0103034  float
0.0125688   float
-0.0161171  float
0.0196527   float
-0.0251945  float
0.0307164   float
1   float

周而复始。
我不知道为什么我会得到这个。

也许我的错误在于我的 Thomas 方法函数的赋值 Tn 结果?
或实现托马斯方法?还是在边界条件下?

我明白了!

边界条件必须作用于向量

QVector<float> below_main_diagonal, 
QVector<float>  main_diagonal, 
QVector<float>  beyond_main_diagonal

所以T[0]一定是0,T[N-1]一定是1。我们可以这样:

main_diagonal.first()=1;
main_diagonal.last()=1;
beyond_main_diagonal.first()=0;
below_main_diagonal.last()=0;

因此,T[0] 将始终等于 0,而 T[N-1] 将始终等于 1;

在我读到 Thomas 方法的文章中,第一步是取反主对角线,我已经做到了,但是在函数的最后我必须做相反的事情,所以:

for(int i(0);i<N;++i){
   main_diagonal[i]*=(-1);
}

我们可以再次使用这个功能,这不是绝对最优,但它工作稳定。

然后,整个代码将如下所示:

#include <QCoreApplication>
#include <QVector>
#include <QDebug>
#include <iostream>


QVector<float> Thomas_Algorithm( QVector<float> &below_main_diagonal ,
                                     QVector<float> &main_diagonal  ,
                                     QVector<float> &beyond_main_diagonal ,
                                     QVector<float> &free_term,
                                     const  int N){

        QVector<float> x; //vector of result

        // checking of input data
        if(below_main_diagonal.size()!=main_diagonal.size()||
                main_diagonal.size()!=beyond_main_diagonal.size()||
                free_term.size()!=main_diagonal.size())
        { qDebug()<<"Error!\n"
                    "Error with accepting Arrays! Dimensities are different!"<<endl;
            x.resize(0);
            return x;
        }
        if(below_main_diagonal[0]!=0){
            qDebug()<< "Error!\n"
                       "First element of below_main_diagonal must be equal to zero!"<<endl;
            x.resize(0);
            return x;
        }
        if(beyond_main_diagonal.last()!=0){
            qDebug()<< "Error!\n"
                       "Last element of beyond_main_diagonal must be equal to zero!"<<endl;
            x.resize(0);
            return x;

        }
        // end of checking

        QVector <float> c;
        QVector <float> d;

        for(int i=0;i<N;i++){
            main_diagonal[i]*=(-1);
        }

        c.push_back(beyond_main_diagonal[0]/main_diagonal[0]);
        d.push_back(-free_term[0]/main_diagonal[0]);

        for(int i=1;i<=N-2;i++){
            c.push_back(beyond_main_diagonal[i]/(main_diagonal[i]-below_main_diagonal[i]*c[i-1]));
            d.push_back(  (below_main_diagonal[i]*d[i-1]  -  free_term[i])  /
                    (main_diagonal[i]-  below_main_diagonal[i]*c[i-1])  );
        }

        x.resize(N);

        int n=N-1;
        x[n]=(below_main_diagonal[n]*d[n-1]-free_term[n])/(main_diagonal[n]-below_main_diagonal[n]*c[n-1]);

        for(int i=n-1;i>=0;i--){
            x[i]=c[i]*x[i+1]+d[i];
        }

        for(int i(0);i<N;++i){
           main_diagonal[i]*=(-1);
        }

        return x;
    }

    int main()
    { 
        QVector <float> alpha;  // below
        QVector <float> beta;   // main diagonal * (-1)
        QVector <float> gamma;  // beyond
        QVector <float> b;      // free term


        QVector<float> T;

        int cells_x=30;         // amount of steps
        alpha.resize(cells_x);
        beta.resize(cells_x);
        gamma.resize(cells_x);
        T.resize(cells_x );

        float dt=0.2,h=0.1;

        alpha[0]=0;
        for(int i=1;i<cells_x-1;i++){
            alpha[i]= -dt/(h*h);
        }
        alpha[cells_x-1]=0;

        beta[0]=1;
        for(int i=1;i<cells_x-1;i++){
            beta[i] = (2*dt)/(h*h)+1;
        }
        beta[cells_x-1]=1;
        gamma[0]=0;
        for(int i=1;i<cells_x-1;i++){
            gamma[i]= -dt/(h*h);
        }
        gamma[cells_x-1]=0;  

        for(int i=0;i<cells_x-1;i++){
            T[i]=0;
        }
        T[cells_x-1]=1;

        QVector<float>Tn;
        Tn.resize(cells_x);
        Tn=  Thomas_Algorithm(alpha,beta,gamma,T,cells_x);
        // boundary conditions!
        beta.first()=1;
        beta.last()=1;
        gamma.first()=0;
        alpha.last()=0;
        // and then due to bc we always have T[0]=0 and T[n]=1

        for(int stepTime=0;stepTime<100;stepTime++){
            Tn = Thomas_Algorithm(alpha,beta,gamma,Tn,cells_x);

            qDebug()<<"stepTime = "<<stepTime<<endl<<endl;
            qDebug()<<Tn<<endl;

            // boundary conditions!
            beta.first()=1;
            beta.last()=1;
            gamma.first()=0;
            alpha.last()=0;
            // and then due to bc we always have T[0]=0 and T[n]=1
        }

        return 0;
    }

在最后一步中,我们绝对会得到 "physical" 结果:

Tn  <30 items>  QVector<float>
                0   float
                0.0344828   float
                0.0689656   float
                0.103448    float
                0.137931    float
                0.172414    float
                0.206897    float
                0.24138 float
                0.275862    float
                0.310345    float
                0.344828    float
                0.379311    float
                0.413793    float
                0.448276    float
                0.482759    float
                0.517242    float
                0.551724    float
                0.586207    float
                0.62069 float
                0.655173    float
                0.689655    float
                0.724138    float
                0.758621    float
                0.793104    float
                0.827586    float
                0.862069    float
                0.896552    float
                0.931035    float
                0.965517    float
                1   float