如何与量子谐振子波函数进行数值积分?

时间:2009-03-01 10:39:21

标签: physics numerical numerical-methods numerical-analysis numerical-integration

如何对无限范围内的一维积分进行数值积分(使用什么数值方法,以及使用什么技巧),其中被积函数中的一个或多个函数为1d quantum harmonic oscillator wave功能。其中我想在谐振子基础上计算某些函数的矩阵元素:

  

phi n (x)= N n H n (x)exp(-x 2 / 2)
  其中H n (x)为Hermite polynomial

     

V m,n = \ int _ { - infinity} ^ {infinity} phi m (x)V(x)phi n (x)dx

同样存在具有不同宽度的量子谐波波函数。

问题是波函数phi n (x)具有振荡行为,这是大 n 的问题,以及来自GSL的自适应Gauss-Kronrod积分算法( GNU科学库)需要很长时间才能计算出来,并且有很大的错误。

6 个答案:

答案 0 :(得分:8)

一个不完整的答案,因为我现在的时间有点短;如果其他人无法完成图片,我可以在以后提供更多细节。

  1. 随时随地应用波函数的正交性。这应该会大大减少计算量。

  2. 尽可能地分析。提升常数,按部分分割积分,无论如何。隔离感兴趣的区域;大多数波函数都是带限的,减少感兴趣的区域将为保存工作做很多工作。

  3. 对于正交本身,您可能希望将波函数分成三部分并将它们分别整合:中心的振荡位加上两侧的指数衰减尾部。如果波函数是奇数,你会很幸运,尾巴会相互抵消,这意味着你只需要担心中心。对于偶数波函数,你只需要将它加一个并加倍(对称性很好!)。否则,使用高阶高斯 - 拉盖尔积分法则对尾部进行积分。您可能必须自己计算规则;我不知道表格是否列出了高斯 - 拉盖尔规则,因为它们不经常使用。您可能还希望检查错误行为,因为规则中的节点数量会增加;自从我使用Gauss-Laguerre规则以来已经很长时间了,我不记得它们是否表现出Runge的现象。使用您喜欢的任何方法集成中心部分;当然,Gauss-Kronrod是一个可靠的选择,但也有Fejer积分(有时可以更好地扩展到大量节点,这可能在振荡积分上更好)甚至梯形规则(它具有某些振荡函数的惊人精度) )。选一个然后尝试一下;如果结果不佳,可以另外给出一个方法。

  4. 最难的问题是什么?几乎没有:)

答案 1 :(得分:4)

我建议其他一些事情:

  1. 尝试将函数转换为有限域,以使集成更易于管理。
  2. 尽可能使用对称性 - 将其分解为从负无穷大到零和零到无穷大的两个积分之和,并查看函数是对称还是反对称。它可以使您的计算更容易。
  3. 查看Gauss-Laguerre quadrature并查看它是否对您有帮助。

答案 2 :(得分:1)

WKB近似值?

答案 3 :(得分:0)

我现在不打算解释或限定任何此类内容。此代码按原样编写,可能不正确。我甚至不确定它是否是我正在寻找的代码,我只记得几年前我做了这个问题,在搜索我的档案时我发现了这个。您需要自己绘制输出,提供一些指令。我会说无限范围内的积分是我解决的一个问题,并且在执行代码时它会在'无限'处指出舍入误差(在数值上意味着很大)。

// compile g++ base.cc -lm
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <math.h>

using namespace std;

int main ()
        {
        double xmax,dfx,dx,x,hbar,k,dE,E,E_0,m,psi_0,psi_1,psi_2;
        double w,num;
        int n,temp,parity,order;
        double last;
        double propogator(double E,int parity);
        double eigen(double E,int parity);
         double f(double x, double psi, double dpsi);
        double g(double x, double psi, double dpsi);
        double rk4(double x, double psi, double dpsi, double E);

        ofstream datas ("test.dat");

        E_0= 1.602189*pow(10.0,-19.0);// ev joules conversion
        dE=E_0*.001;
//w^2=k/m                 v=1/2 k x^2             V=??? = E_0/xmax   x^2      k-->
//w=sqrt( (2*E_0)/(m*xmax) );
//E=(0+.5)*hbar*w;

        cout << "Enter what energy level your looking for, as an (0,1,2...) INTEGER: ";
        cin >> order;

        E=0;
        for (n=0; n<=order; n++)
                {
                parity=0;
//if its even parity is 1 (true)
                temp=n;
                if ( (n%2)==0 ) {parity=1; }
                cout << "Energy " << n << " has these parameters: ";
                E=eigen(E,parity);
                if (n==order)
                        {
                        propogator(E,parity);
                        cout <<" The postive values of the wave function were written to sho.dat \n";
                        cout <<" In order to plot the data should be reflected about the y-axis \n";
                        cout <<"  evenly for even energy levels and oddly for odd energy levels\n";
                        }
                E=E+dE;
                }
        }

double propogator(double E,int parity)
        {
        ofstream datas ("sho.dat") ;

        double hbar =1.054*pow(10.0,-34.0);
        double m =9.109534*pow(10.0,-31.0);
        double E_0= 1.602189*pow(10.0,-19.0);
        double dx =pow(10.0,-10);
        double xmax= 100*pow(10.0,-10.0)+dx;
        double dE=E_0*.001;
        double last=1;
        double x=dx;
        double psi_2=0.0;
        double psi_0=0.0;
        double psi_1=1.0;
//      cout <<parity << " parity passsed \n";
        psi_0=0.0;
        psi_1=1.0;
        if (parity==1)
                {
                psi_0=1.0;
                psi_1=m*(1.0/(hbar*hbar))* dx*dx*(0-E)+1 ;
                }

        do
                {
                datas << x << "\t" << psi_0 << "\n";
                psi_2=(2.0*m*(dx/hbar)*(dx/hbar)*(E_0*(x/xmax)*(x/xmax)-E)+2.0)*psi_1-psi_0;
//cout << psi_1 << "=psi_1\n";
                psi_0=psi_1;
                psi_1=psi_2;
                x=x+dx;
                } while ( x<= xmax);
//I return 666 as a dummy value sometimes to check the function has run
        return 666;
        }


   double eigen(double E,int parity)
        {
        double hbar =1.054*pow(10.0,-34.0);
        double m =9.109534*pow(10.0,-31.0);
        double E_0= 1.602189*pow(10.0,-19.0);
        double dx =pow(10.0,-10);
        double xmax= 100*pow(10.0,-10.0)+dx;
        double dE=E_0*.001;
        double last=1;
        double x=dx;
        double psi_2=0.0;
        double psi_0=0.0;
        double psi_1=1.0;
        do
                {
                psi_0=0.0;
                psi_1=1.0;

                if (parity==1)
                        {double psi_0=1.0; double psi_1=m*(1.0/(hbar*hbar))* dx*dx*(0-E)+1 ;}
                x=dx;
                do
                        {
                        psi_2=(2.0*m*(dx/hbar)*(dx/hbar)*(E_0*(x/xmax)*(x/xmax)-E)+2.0)*psi_1-psi_0;
                        psi_0=psi_1;
                        psi_1=psi_2;
                        x=x+dx;
                        } while ( x<= xmax);


                if ( sqrt(psi_2*psi_2)<=1.0*pow(10.0,-3.0))
                        {
                        cout << E << " is an eigen energy and " << psi_2 << " is psi of 'infinity'  \n";
                        return E;
                        }
                else
                        {
                        if ( (last >0.0 && psi_2<0.0) ||( psi_2>0.0 && last<0.0) )
                                {
                                E=E-dE;
                                dE=dE/10.0;
                                }
                        }
                last=psi_2;
                E=E+dE;
                } while (E<=E_0);
        }

如果这段代码看起来是正确的,错误的,有趣的,或者你确实有特定的问题,我会回答它们。

答案 4 :(得分:0)

我是一名物理专业的学生,​​我也遇到过这个问题。这些天我一直在思考这个问题并得到我自己的答案。我认为它可以帮助您解决这个问题。

1.在gsl中,有一些功能可以帮助你整合振荡功能 - qawo&amp; qawf。也许你可以设置一个值 a 。并且可以将集成分成两个部分,[0, a ]和[ a ,pos_infinity]。在第一个时间间隔中,您可以使用任何所需的gsl积分函数,在第二个时间间隔中,您可以使用qawo或qawf。

2.或者您可以将功能集成到上限 b ,它集成在[0, b ]中。因此,可以使用高斯传奇方法计算积分,这在gsl中提供。虽然实际值和计算值之间可能存在一些差异,但如果正确设置 b ,则可以忽略差异。只要差异小于您想要的准确度。并且这个使用gsl函数的方法只调用一次并且可以多次使用,因为返回值是point及其相应的权重,而积分只是f(xi)* wi的总和,更多细节你可以搜索gauss legendre维基百科上的正交。多次和加法操作比集成快得多。

3.还有一个可以计算无限区域积分的函数 - qagi,你可以在gsl-user的指南中搜索它。但是每次你需要计算集成时都会调用它,这可能会耗费一些时间,但我不确定它会在你的程序中使用多长时间。

我建议我提供第二选择。

答案 5 :(得分:0)

如果您打算使用低于n = 100的谐波振荡器功能,您可能需要尝试:

http://www.mymathlib.com/quadrature/gauss_hermite.html

程序通过高斯 - 英米正交计算积分,其中有100个零和权重(H_100的零)。一旦你浏览了Hermite_100,积分就不那么准确了。

使用这种集成方法,我编写了一个程序,准确计算出你想要计算的内容,并且它运行得相当好。此外,通过使用Hermite多项式零的渐近形式,可能有一种方法超越n = 100,但我还没有调查它。