6

Jak wykonać integrację numeryczną numerycznej integracji (jaka metoda numeryczna i jakich metod użyć) do jednowymiarowej integracji w nieskończonym zakresie, w którym jedna lub więcej funkcji w funkcjach całkowych to funkcje falowe 1d quantum harmonic oscillator. Między innymi, że aby obliczyć elementów macierzy pewnego funkcjonowania w oparciu oscylatora harmonicznego:Jak wykonać integrację numeryczną z funkcją falową oscylatora kwantowego?

phi n (x) = N n H n (x) exp (-x/2)
gdzie H n (x) jest Hermite polynomial

V m, n = \ _ int {-}^{nieskończoność nieskończoność} phim (x) V (X) phi n (x) dx

Również w przypadku, gdy nie są kwantowe funkcje falowe harmonicznych o różnych szerokościach.

Problemem jest to, że funkcje falowe phi n (x) ma zachowanie oscylacyjne, co jest problemem w przypadku dużych n i algorytm jak adaptacyjnego Gaussa-Kronrod kwadraturze z GSL (biblioteka Scientific GNU) trwa długo, aby obliczyć i mają duże błędy.

+1

Czy to jest najtrudniejsze pytanie na SO? – MrTelly

+4

Nie dotyczy to tylko domeny, która jest najbardziej nieznana, ezoterycznej! = Trudnej. – Saem

+0

Gauss-Laguerre już wprowadzono do [GSL2.3] (https://www.gnu.org/software/gsl/doc/html/integration.html) – zmwang

Odpowiedz

8

Odpowiedź niekompletna, ponieważ w tej chwili jestem trochę za krótka; jeśli inni nie mogą dokończyć zdjęcia, mogę podać więcej szczegółów później.

  1. Zastosuj ortogonalność funkcji falowych zawsze i wszędzie, gdzie to możliwe. To powinno znacznie zmniejszyć ilość obliczeń.

  2. Wykonuj analitycznie wszystko, co możliwe. Podnieś stałe, podziel całki po częściach, cokolwiek. Wyizoluj region zainteresowania; większość funkcji falowych jest ograniczona przez pasmo, a zmniejszenie obszaru zainteresowania znacznie przyczyni się do zaoszczędzenia pracy.

  3. W przypadku kwadratury, prawdopodobnie chcesz podzielić funkcje falowe na trzy części i zintegrować je oddzielnie: brzęczyk oscylacyjny w centrum plus grzbiet rozkładający się wykładniczo po obu stronach. Jeśli funkcja falowa jest dziwna, masz szczęście i ogony się anulują, co oznacza, że ​​musisz martwić się o centrum. Nawet w przypadku funkcji wavefunctions wystarczy zintegrować jeden i podwoić (hooray dla symetrii!). W przeciwnym razie połącz ogony za pomocą reguły kwadratury Gaussa-Laguerre'a o wysokim porządku. Być może będziesz musiał sam obliczyć zasady; Nie wiem, czy tabele zawierają dobre zasady Gaussa-Laguerre'a, ponieważ nie są używane zbyt często. Prawdopodobnie chcesz również sprawdzić zachowanie błędu, gdy liczba węzłów w regule wzrasta; Minęło dużo czasu odkąd użyłem zasad Gaussa-Laguerre'a i nie pamiętam, czy wykazują one zjawisko Runge'a. Zintegruj centralną część za pomocą dowolnej metody; Gauss-Kronrod to oczywiście porządny wybór, ale istnieje również kwadratura Fejera (która czasami lepiej się skaluje do dużej liczby węzłów, które mogą działać lepiej na integratorze oscylacyjnym), a nawet reguła trapezoidalna (która wykazuje zadziwiającą dokładność przy pewnych funkcjach oscylacyjnych;). Wybierz jeden i wypróbuj go; jeśli wyniki są słabe, daj innej metodzie strzał.

Najtrudniejsze pytanie na zawsze? Trudno :)

0

Nie zamierzam teraz wyjaśniać tego ani kwalifikować. Ten kod jest zapisany tak jak jest i prawdopodobnie niepoprawny. Nie jestem nawet pewien, czy to kod, którego szukałem. Pamiętam, że lata temu zrobiłem ten problem i po przeszukaniu moich archiwów znalazłem to. Będziesz musiał wydrukować dane wyjściowe, niektóre instrukcje są dostarczane. Powiem, że integracja w nieskończonym zakresie jest problemem, do którego się odezwałem, a po wykonaniu kodu podaje błąd zaokrąglania w "nieskończoności" (który liczbowo oznacza po prostu duży).

// 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); 
     } 

Jeśli ten kod wydaje się być poprawny, zły, interesujący lub masz pytania, zadaj je, a ja na nie odpowiem.

4

polecam kilka innych rzeczy:

  1. Spróbuj przekształcenie funkcji na skończonym domeny, aby integracja łatwiejsze.
  2. Użyj symetrii, gdzie to możliwe - podziel ją na sumę dwóch całek od ujemnej nieskończoności do zera i od zera do nieskończoności i zobacz, czy funkcja jest symetryczna czy antysymetryczna. Może to ułatwić twoją pracę komputerową.
  3. Zajrzyj do Gauss-Laguerre quadrature i sprawdź, czy może ci pomóc.
0

Jestem studentem specjalizującym się w fizyce, a także napotkałem problem. Obecnie myślę o tym pytaniu i dostaję własną odpowiedź. Myślę, że może ci pomóc rozwiązać to pytanie.

1.W gls, istnieją funkcje mogą pomóc w integracji funkcji oscylacyjnej - qawo & qawf. Może możesz ustawić wartość, a. I integracja może być podzielona na części do ciągnięcia, [0,] i [] [, poz_infinity]. W pierwszym przedziale możesz użyć dowolnej funkcji integracji gsl, a w drugim interwale możesz użyć qawo lub qawf.

2.Or można zintegrować funkcję do górnej granicy, b, który jest zintegrowany w [0, b]. Tak więc integrację można obliczyć za pomocą legendarnej metody Gaussa, którą podaje się w gsl. Chociaż może być pewna różnica między wartością rzeczywistą a wartością obliczoną, ale jeśli ustawisz odpowiednio b, różnica może zostać pominięta. Tak długo, jak różnica jest mniejsza niż wymagana dokładność. Ta metoda używająca funkcji gsl jest wywoływana tylko raz i może być użyta wiele razy, ponieważ wartość zwracana to punkt i odpowiadająca mu waga, a integracja to tylko suma f (xi) * wi, więcej szczegółów można znaleźć w legendzie gaussa kwadratura na wikipedia. Operacja wielokrotnego dodawania jest znacznie szybsza niż integracja.

3. Istnieje również funkcja, która może obliczyć integrację obszaru nieskończoności - qagi, możesz przeszukać ją w podręczniku użytkownika gsl. Ale jest to nazywane za każdym razem, gdy trzeba obliczyć integrację, a to może spowodować trochę czasu, ale nie jestem pewien, jak długo będzie on używany w twoim programie.

Proponuję wybór nr 2, który zaoferowałem.

0

Jeśli zamierzasz pracować z Harmonic funkcji oscylatora mniej niż n = 100 może chcesz spróbować:

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

Program oblicza integralną poprzez Gaussa-Hermite'a kwadraturze ze 100 zerami i ciężarów (zerami H_100). Po przejściu przez Hermite_100 całki nie są tak dokładne.

Za pomocą tej metody integracji napisałem program obliczający dokładnie to, co chcesz obliczyć i działa całkiem dobrze. Poza tym może istnieć sposób na wyjście poza n = 100 przy użyciu asymptotycznej formy zer wielomianowych zer, ale nie przyjrzałem się temu.