RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 625225
Accepted
beginner
beginner
Asked:2020-02-08 23:45:40 +0000 UTC2020-02-08 23:45:40 +0000 UTC 2020-02-08 23:45:40 +0000 UTC

求解输运方程时的代码错误

  • 772

更新了问题的内容,因为我自己理解并纠正了一些地方。因此有以下变量:

hx (шаг по пространству)= 0.1

ht (шаг по времени) = 0.5

Nx (Количество шагов по пространству) = 10;

Nt (Количество шагов по времени) = 12;

wx[i] - массив содержит все шаги по пространству

wt[j] - массив содержит все шаги по времени

wht[j][i]-двумерный массив по которому будет строится результирующий график;

![在此处输入图片描述

于是发现了几个问题:

1)在代码中找到

for(int i = 0; i < Nx; i++)        
{
    wx[i+1] = wx[i] + hx;      //массив 
    wht[0][i] = fn(T, i * hx); //i * hx//Исправлено.
}

它在哪里fn:

//Функция Хэвисайда - Начальное условие(Граничное условие) а начальное 0-1
public:static double fn(int T, double x)
{
    if (x >= 0) 
        return T;
    else if(x < 0)
        return 0;  
}

我设置的初始条件不正确

就像图表上的酒一样,在耻辱中,一般解决方案“wave”在某处可见,但其余部分是错误的,因为我在代码中错误地设置了初始条件

2)循环和数组,即:

调用了数组中不存在的元素,结果出现了可怕的数字和图表中的跳跃,但我无法更改索引,因为存在特定的公式。

for(int j = 0;j<Nt;j++)
{
    for(int i = 1;i<Nx-1;i++)///Исправлено с помощью ответа пользователя Denis Protopopov(и график немного изменился)
    {
        wht[j+1][i] = 
            ((wht[j + 1][i] - wht[j][i]) / ht) + a * ((wht[j][i+1] - wht[j][i]) / hx);
        wht[j+1][i] = -a * (ht * (wht[j][i+1] + wht[j][i]) / hx) + (wht[j][i]);
    }
}

如果我写而不是i = 0,i = 2或j = 2,那么图形的绘制将很糟糕。

所有代码:

public:static double qx0(double x)//ось пространства
           {
               if (x<=0) 
                   return 0;
               else
                   return x;
           }

    public:static double qt0(double t)//ось по времени
           {
               if (t<=0) 
                   return 0;
               else
                   return t;
           }

    public:static double fn(int T,double x)//Функция Хэвисайда - Начальное условие
           {
               if (x>=0)
                   return T;
               else if(x<0)
                   return 0;  
           }

public: void drawfunc(double T)
            {
                double xmin = -5;
                double xmax = 10;
                for(double x = xmin;x<xmax;x+=0.01)
                {       
            chart1->Series["Функция Хэвисайда"]->BorderWidth=3;
            chart1->Series["Функция Хэвисайда"]->Points->AddXY(x,fn(T,x));                       
                }                                       
            }


    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
             { 
                 ///-------Переменные для работы с разностными схемами
                 double a;//скорость переноса
                 double hx,ht;//шаги по пространству и времени
                 int Nx,Nt;//На сколько частей разбивае отрезок сетки
                 int T;//Входной параметр для искомой функции(Хэвисайд)
                 double wx[20]={0};//массив точек x
                 double wt[20]={0};//массив точек t
                 double wht[20][20]={0};// массив для разностной схемы(сетки) 
                 //double res[20][20]={0};//результирующий массив

                 if(textBox1->Text!="" && textBox2->Text!="" && textBox3->Text!="" && textBox4->Text!="" && textBox5->Text!="" && textBox6->Text!="" && textBox6->Text!="")
                 {

                     ///-----Ввод данных-----
                     a=Convert::ToDouble(textBox1->Text);
                     hx=Convert::ToDouble(textBox2->Text);
                     q=Convert::ToDouble(textBox3->Text);
                     ht=Convert::ToDouble(textBox4->Text);
                     Nx=Convert::ToInt32(textBox5->Text);
                     Nt=Convert::ToInt32(textBox6->Text);
                     T=Convert::ToInt32(textBox7->Text);

                     //----Построение сетки,узлов
                     for(int i = 0;i<Nx;i++)        
                     {
                         wx[i+1]=wx[i]+hx;//массив 
                         wht[0][i]=qx0(wx[i]);                       
                     }   

                     for(int j = 0;j<Nt;j++) //
                     {                                                       
                         wt[j+1]=wt[j]+ht;
                         wht[j+1][0] = qt0(wt[j+1]);                     
                     }


                     ///-----------------Вычисление основых формул с разностной схемой

                     for(int j = 0;j<Nt;j++)
                     {
                         for(int i = 1;i<Nx-1;i++)///Вывод формул wht[j+1][i] 
                         {                           
        wht[j+1][i]=((wht[j+1][i]-wht[j][i])/ht)+a*((wht[j][i+1]-wht[j][i])/hx);
        wht[j+1][i]=-a*(ht*(wht[j][i+1] + wht[j][i])/hx) + (wht[j][i])+ht*fn(wt[j],hx); 
                         }
                     }

                     //----Для записи в простой текстовый файл                  
                     String^ fileName = "results.txt";
                     StreamWriter^ sw = gcnew StreamWriter(fileName);
                     for(int j = 0;j<Nt;j++)    
                     {
                         for(int i = 0 ;i<Nx;i++)
                         {
                             sw->Write("{0} ",wht[j][i]);
                         }
                         sw->WriteLine();
                     }
                     sw->Close(); 


                     //Тестовые функции для отображения
                     drawfunc(T);// Вызов функции для рисования

                     ///---------------Построение графика                        

                              for(int j = 0;j<Nt;j++)
                     {
                          for(int i = 0;i<Nx-1;i++)
                         {  
                        chart2->Series["Series2"]->BorderWidth=3;           
                        chart2->Series["Series2"]->Points->AddXY(i,wht[j][i]);
                         }
                     }                                           
                 }
                 else MessageBox::Show("Ошибка!Не все поля заполнены!");
             }
c++-cli
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Dmitri Chubarov
    2020-02-24T21:00:12Z2020-02-24T21:00:12Z

    为了回答为什么波浪不在图表上运行,您必须先处理数值方法,然后再处理 C++ 代码。数值分析理论不包括在本网站讨论的主题范围内,但简要参考可能会有用。

    1.差分方案的一个小题外话

    所以,我们正在寻找一个函数 u(x,t) 来解决偏微分方程的 Cauchy 问题

      d u       d u
      --- = - a ---       (1)
      d t       d x
    

    有初始条件

      u(x,0) = f(x)       (2)
    

    方程 (1) 称为输运方程,因为我们问题的解是u(x,t) = f(x-at)。这是一个函数,其图形随时间向右移动,速度为a。

    将函数 f(x-at) 代入等式 (1) 中的 u 并计算偏导数以检查它确实是解。

    老师教导学生不要寻找简单的方法,而是要用有限差分法来解这个方程。可以提出等式(1)的几个差分近似。我们被邀请使用其中之一。很快就会清楚,这是一个非常不幸的选择。

    因此,让我们考虑一种方案,其中关于 的导数t由差分算子 近似Dt u。

        Dt u = (u(x,t+dt) - u(x,t))/dt.
    

    该运算符具有一阶近似值。

    x我们近似于差分算子的导数Dx u

        Dx u = (u(x+dx,t) - u(x,t))/dx.
    

    得到

        Dt u = -a Dx u.
    

    数值分析人员很清楚这个方案在 dt 和 dx 上有一个一阶近似,并且也是绝对不稳定的。这意味着该方案以指数方式增加任何小的扰动。

    u(x,t)让我们将函数替换为q^(t/dt) e^(ipx/dx)。代入,我们看到如果这个函数是差分方程的解,那么|q| > 1 如果sin p/2 != 0。也就是说,这种形状的任何小扰动都会随着 t 的增长而增长。这种研究差分格式稳定性的方法称为冯·诺依曼方法。

    所以,这个方案是绝对不稳定的,因此不满足Lax定理的条件,所以不能指望按这个方案计算出的函数收敛于原偏微分方程问题的解。

    x有趣的是,如果我们根据公式计算导数

       D'x u = (u(x,t) - u(x-dx,t))/dt,
    

    然后我们得到一个稳定的方案。

    2. 限定区间内的问题陈述

    我们不希望在整个数值轴上寻找解决方案,而是在有限的区间内寻找解决方案 [xmin,xmax]。为了使函数f(x-at)成为我们问题的解决方案,有必要用以下边界条件补充问题。

        u(xmin,t) = f(xmin - a*t)        (3)
        u(xmax,t) = f(xmax - a*t)        (4)
    

    现在我们可以根据一阶近似的显式方案来编写解决问题(1-4)的方法。

    三、软件实现

    以下仅是方法本身的示例实现。与可视化相关的一切都是单独决定的。

    第一个代码块是边界条件的定义。

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    
    using namespace std;
    
    const double T = 1.0;
    const double a = 0.5;
    
    inline double f(double x){
            if (x>=0)
                    return T;
            return 0;
    }
    
    inline double u0(double x){
            return f(x);
    }
    
    inline double u1(double xmin, double t){
            return f(xmin - a * t);
    }
    
    inline double u2(double xmax, double t){
            return f(xmax - a * t);
    }
    

    下一个代码块包含一个计算解决方案并将其存储在数组中的函数。我们的函数将任务的参数作为参数 - 计算区域边界的坐标和对应保存结果的数组的引用。

    void run(double xmin,double xmax, double tmax, int N,double u[][M]){
            double ht = tmax/N;
            double hx = (xmax - xmin)/M;
    
            for(int i=0; i<N;i++){
                    u[0][i] = u0(xmin + i*hx);
            }
    
            for(int j=0; j < N-1; j++){
                    u[j+1][0] = u1(xmin,j*ht);
                    for(int i=1; i<N; i++){
                            double dudx = (u[j][i] - u[j][i-1])/hx;
                            u[j+1][i] = -a * dudx * ht + u[j][i];
                    }
            }
    }
    

    在这里,实现了一个具有稳定方案的变体——差分算子D'x

    4. 结果

    下图为和,和的函数值u(x,t)。a=0.5t=0t=5.0t=10.0

    用向后差分方案计算的解的图

    可以看出,波浪与其说是在运行,不如说是在空间中被涂抹。

    现在让我们用一个实现由 operator 定义的绝对不稳定方案的循环替换主循环Dx。

        for(int j=0; j < N-1; j++){
                for(int i=0; i<N-1; i++){
                        double dudx = (u[j][i+1] - u[j][i])/hx;
                        u[j+1][i] = -a * dudx * ht + u[j][i];
                }
                u[j+1][N-1] = u2(xmax,j*ht);
        }
    

    结果看起来像这样

    使用前向差分方案计算的解图

    这个结果一点也不像是向右跑的台阶。

    5.结论

    我希望这个例子说明在查找代码中的错误之前,有必要研究算法的属性。

    • 3
  2. GHosT
    2020-02-23T06:06:23Z2020-02-23T06:06:23Z

    既然没有人愿意处理这个问题,我就敢说出我的想法。

    问题是缺少一段代码,即:

    1. 数组的所有元素wx,wt和都未设置wht。当一个数组被声明时,内存中的一个位置被分配给它,如果在声明之后你没有为数组的元素设置值,那么当你访问它们时,你会得到那里的东西。这就是这些“可怕”含义的来源。))
    2. 变量声明在哪里T??
    3. 变量声明在哪里a??

    稍微修改的代码:

    double hx = 0.1;    // Шаг по пространству
    double ht = 0.5;    // Шаг по времени
    int Nx = 10;        // Количество шагов по пространству
    int Nt = 12;        // Количество шагов по времени
    double wx[Nx];      // Массив содержит все шаги по пространству
    double wt[Nt];      // Массив содержит все шаги по времени
    double wht[Nt][Nx]; // Двумерный массив, по которому будет строится результирующий график
    
    for (int i = 0, step = 0; i < Nx; i++, step += hx)
    {
        wx[i] = step; // Заполняем массив. Каждый шаг больше предыдущего на hx.
    
        //wht[0][i] = fn(T, i * hx); — Непонятно назначение метода fn. Проще сделать так:
        wht[0][i] = (T < 0) ? 0 : i * hx;
    
        // В этом цикле заполняется только массив `wx` и первая строка массива `wht`, 
        // а где задаются значения остальных элементов массивов `wht` и `wt` ??
    } 
    
    for (int j = 0; j < Nt; j++)
    {
        for (int i = 0; i < Nx; i++)
        {
            // Если в данном цикле использовать индекс j+1 или i+1, то это обязательно вызовет 
            // ошибку, т.к. индекс выйдет за пределы массива. Ошибка как раз будет в конце 
            // перебора массива. Думаю, этим и вызваны возникновение "страшных цифр" и скачок 
            // графика.
            wht[j + 1][i] = ((wht[j + 1][i] - wht[j][i]) / ht) + a * ((wht[j][i + 1] - wht[j][i]) / hx);
            wht[j + 1][i] = -a * (ht * (wht[j][i + 1] + wht[j][i]) / hx) + (wht[j][i]);
        }
    }
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5