Boost logo

Boost :

Subject: Re: [boost] [units] - learning to use, continued :)
From: Matthias Schabel (boost_at_[hidden])
Date: 2011-11-30 12:18:30


> But still I am quite happy today, because I managed to get a
> correctly working plots of this harmonic oscillator, but without
> units, unfortunately. One small problem is that I couldn't get to
> higher energies because double precision has limited factorials.
> I would need a working factorial of 100! which currently seems
> unlikely. And my currently maximum is only 25!

Using Stirling's approximation will help here; see below code. However, you will likely run into other problems with the Hermite polynomials at large n.

> So, for your pleasure I am presenting you with a harmonic oscillator code :)
>
> Unfortunately without units :) But if you will try to convert this to
> units, I might learn even more about using this library. Especially
> because dimension of wavefunction in 1 dimensional space is
> 1/sqrt(meter), and I have no idea how to declare this
> derived_dimension, this didn't work:

Here's a fully-unitized code for the 1D harmonic oscillator:

#include <complex>
#include <iostream>
#include <limits>

using namespace std;

#include <boost/mpl/list.hpp>

// use math constants
#include <boost/math/constants/constants.hpp>

// use math factorial
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/hermite.hpp>
#include <boost/typeof/std/complex.hpp>
 
#include <boost/units/cmath.hpp>

#include <boost/units/io.hpp>
#include <boost/units/pow.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/systems/si/codata/electron_constants.hpp>
#include <boost/units/systems/si/codata/physico-chemical_constants.hpp>
#include <boost/units/systems/si/codata/universal_constants.hpp>
 
using namespace boost::units;
using namespace boost::units::si;
 
// MCS - need codata namespace to find hbar
using namespace boost::units::si::constants::codata;

// MCS - derived_dimension only works with integer powers; use make_dimension_list here instead
typedef make_dimension_list<boost::mpl::list<dim<length_base_dimension,static_rational<-1,2> > > >::type quantum_wavefunction_1D_dimension;
typedef unit<quantum_wavefunction_1D_dimension,si::system> quantum_wavefunction_1D;

double factorial_to_minus_one_half(int n)
{
        if (n <= 10)
        {
                return 1./sqrt(boost::math::factorial<double>(n));
        }
        else
        {
                // use Stirling's approximation for n>10
                const double pi(boost::math::constants::pi<double>()),
                                logfac(log(2*pi*n)/2. + n*(log(n)-1));
                                                
                return exp(-0.5*logfac);
        }
}

// this function returns 1/sqrt(meter)
quantity<quantum_wavefunction_1D>
quantum_harmonic_oscillator_wavefunction_1d(int n,
                                                                                                 const quantity<mass>& m,
                                                                                                 const quantity<frequency>& omega,
                                                                                                 const quantity<length>& x)
{
        const double pi(boost::math::constants::pi<double>()),
                        prefac(pow(2.,-n/2.)*factorial_to_minus_one_half(n));
        
        const quantity<energy_time> h_(hbar);
        
        const double Hn(boost::math::hermite(n,root<2>(m*omega/h_)*x)),
                        gaussian(exp(-m*omega*pow<2>(x)/(2.*h_)));
        
        return prefac*root<4>(m*omega/(pi*h_))*gaussian*Hn;
}

int main()
{
        // MCS - change -1 -> +1 here otherwise loop doesn't run
        quantity<length> s(15*nano*meter),
                         ds(0.1*nano*meter);
        
        for (quantity<length> x=-s ; x<=s ; x+=ds)
        {
                const quantity<temperature> T(273.15*kelvin);
                const quantity<frequency> omega(k_B*T/hbar.value());
                
                std::cout << x.value() << "\t";
                
                for (int n=0;n<25;++n)
                {
                        const quantity<quantum_wavefunction_1D> psi(quantum_harmonic_oscillator_wavefunction_1d(n,m_e,omega,x));
                
                        std::cout << psi.value() << "\t";
                }
                
                std::cout << std::endl;
        }

    return 0;
}

and PDFs for n=0..25 :

Matthias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk