qsims is written in C++, in part because this allows the use of a vast array of pre-existing libraries and code. The same could be said of FORTRAN, but I use C++ because it is a much more modern language, and C++ compilers long ago caught up with FORTRAN in terms of the speed of the resulting executables. C++ allows object-oriented design, which makes qsims more extensible and maintainable. If you're a scientist who currently uses FORTRAN, please consider learning C++ or any other modern language. You won't regret it.
Classes and Inheritance
On the right is a diagram of the inheritence structure in qsims. Arrows point towards superclasses. Descriptions of the classes follow.
- A pure virtual class. Grids are the basic data objects, representing the motional wavefunction of the particle being simulated. Grids support an extensive array of mathematical operators, as well as Fourier transforms between position and momentum space.
- Inherits from Grid. FGrid is a pure virtual class, containing some methods specific to the FFTW Fourier Transform library. Since FFTW supports several different data formats (some of which confer performance advantages on certain platforms), FGrid does not store the actual wavefunction.
- Inherits from FGrid. FIDGrid is an implementation of the interface defined in FGrid and Grid, and stores the wavefunction as a multidimensional array of complex numbers (as opposed to separate arrays of the real and imaginary parts). For the purposes of speed, FIDGrid contains implementations of some methods that were implemented in the Grid class. By doing so, these methods can directly access the FIDGrid data structures, avoiding virtual function calls to an accessor.
- A pure virtual class. Declares the interface for "mathematical functions", for which the most important public method is
complex< double > calculate(const vector< double > tx).
calculate takes as input a vector of time and space coordinates (time being at vector index 0), and returns the value of the function at that point. Functions can be time-dependent or non-time-dependent. Time dependence is specified by a
map that maintains an ordered container of timeDep structs. Each timeDep indicates a start time, a scaling value, and a ramp-up time.
- ConstantFunction, Gaussian, Harmonic, HOEigenstate
- Various subclasses of Function. Their behavior is largely intuitive. HOEigenstate currently can only generate harmonic oscillator eigenstates up to 5--this is a bug due to the fact that we manually calculate Hermite polynomials, and have only bothered to enter the first five.
- A subclass of Function. CompositeFunctions internally store zero or more Function objects, which are summed when producing output via the
- A FunctionWrapper acts as a wrapper for a Function object. FunctionWrappers take a Grid as input, and return a grid with the same parameters but set to the value of the function at each point (the original Grid is unchanged). FunctionWrappers perform smart caching, and only recalculate the Grid returned if the time has changed and the function is time-dependent.
- A pure virtual class which declares the interface for a status display. A StatusCallback can be passed to a ChebychevSim object, and the ChebychevSim will update it to indicate the progress of a simulation.
- A subclass of StatusCallback. CLStatusCallback uses stdout to display the status.
- ChebychevSim is the core of the actual simulation. Time propagation is carried out here, and all the necessary grids are stored here. ChebychevSim is completely independent of any details of how user input is processed.
- SimWrapper contains a ChebychevSim, and takes care of all the input and output, as well as much of the initial setup of the ChebychevSim.
- An exception object.
How it all works
Upon launch, main() parses the command-line input, and figures out whether to display the help info, or to get parameters from a file, from the command-line, or via interactive mode. If the latter, then a SimWrapper is created via the default constructor. Otherwise, a SimWrapper is created via the stream constructor. Both constructors follow largely the same execution path, except that for the stream constructor, output is suppressed and input comes from the stream instead of cin.
The SimWrapper gets a few basic parameters (hbar, mass, number of levels, dimensions, dx, and length) from the input stream, then creates the ChebychevSim object. The ChebychevSim constructor creates one FIDGrid object per level. The SimWrapper then sets these Grids to the initial states specified by the user.
Next, SimWrapper creates the potential functions. Each function is stored in a FunctionWrapper, and pointers to the FunctionWrappers are passed to the ChebychevSim object, where they are stored in a vector.
Finally, the SimWrapper gets time step and energy parameters, then begins the simulation by calling the
propagate method of ChebychevSim. If a StatusCallback has been set, ChebychevSim is responsible for updating it. At appropriate intervals, the SimWrapper outputs Grids to files.
If you're a developer with C++ experience, or if you're a scientist with relevant experience, please consider helping out the qsims project. Contact trbeals at users d0t sourceforge d0t net for more information.
- A better and more portable Makefile system (e.g. autoconf / automake), with platform-specific optimizations
- Support for relative pathnames (e.g. globbing)
- A built-in self-test
- More Functions
- Man files and more extensive documentation
|qsims is hosted by
Last updated 6 April 2005
by Travis Beals.