Efficient and customizable code to run Cartesian wavepacket dynamics using the split operator method. Supports arbitrary number of electronic states and nuclear degrees of freedom (*: the output is limited to 3D, but in the future I'll extend it). Supports GPU.
Currently pywp only supports diabatic basis.
Requires python >= 3.5, numpy >= 1.9 and (for GPU only) cupy >= 9.5.
Here is an example of running pywp with built-in potential (Tully1):
import pywp
app = pywp.Application(potential=pywp.get_potential('test.Tully1')())
app.set_args(box=[16,4], grid=[256,64], mass=2000, init_r=[-5,0], init_p=[20,0], sigma=[1,1], init_c=[1.0,0], Nstep=10000, dt=0.1, output=2, traj='tully1.traj')
result = app.run()
To view your running result:
snapshot = pywp.snapshot.load_file('tully1.traj')
pywp.visualize.visualize_snapshot_1d(snapshot)
All arguments are set through set_args()
function. Most of them are self-explanatory. Here is a full list:
- box:
list[float]
. The simulation box. For example, [L1,L2,L3] will make the actual box x=[-L1/2, L1/2], y=[-L2/2, L2/2], z=[-L3/3, L3/3]. - grid:
list[int]
. The grid number in each dimension. - mass:
float
. Mass of the nuclei. Currently it's a scalar. - init_r:
list[float]
. Initial position of the wavepacket (the center of the gaussian). - init_p:
list[float]
. Initial momentum of the wavepacket. - sigma:
list[float]
. The initial standard deviation of the wavepacket. The wavefunction will be exp(-x^2/sigmax^2-y^2/sigmay^2...). - init_c:
list[float]
orint
. Initial amplitude or surface label. - Nstep:
int
. Maximum number of step for simulation. - dt:
float
. Integration time interval. - output_step:
int
. Interval between outputs, analysis and writing trajectory. - checkend:
int
. Whether using the checkend algorithm. Will terminate the simulation if the fraction of wavepacket that goes beyond xwall_left or xwall_right in the first dimension is greater than rtol. Default: True. - xwall_left:
float
. The relative value of the leftwall for checkend. The actual wall will be located atbox[0]/2*xwall_left
. Default: -0.9. - xwall_right:
float
. The relative value of the rightwall for checkend. The actual wall will be located atbox[0]/2*xwall_right
. Default: 0.9. - rtol:
float
. The relative tolerance for checkend. Default: 0.05. - output:
int
. The output level to the console. 0: no output; 1: output population; 2: output population, position and momentum. - traj:
str
. Filename of trajectory. If empty then will not write trajectory. Note the trajectory file size can grow dramatically when the nuclear degrees of freedom increases. - gpu:
bool
. True/False. PyWP depends on package cupy for GPU functions.
The Potential passed to Application
must derive pywp.Potential
. The potential class has six functions, and you may override part of them, or all or them.
- The constructor: Receives the parameter from
--potential_params
. Must callsuper().__init__()
before returning. - get_H(R): R is a list with Ndof (= get_kdim()) elements. Each element is a Ngrid_1 x Ngrid_2 x ... x Ngrid_Ndof array, representing the value of first, second, ... nuclear coord in the grid. It is just like what you get in
meshgrid(..., indexing=ij)
. The returned Hamiltonian has shape Ngrid_1 x Ngrid_2 x ... x Ngrid_Ndof x Nel x Nel. The last two are electronic dimensions. - get_kdim(), get_dim(): Return nuclear DOF and electronic DOF. You don't need to override them if you have already passed them in
super().__init__()
. - get_phase(), has_get_phase(): These are depracated.
To use your own boundary instead of the default one, pass a boundary
in pywp.Application()
. The boundary takes a list of position array (as if generated by meshgrid('ij')
) and return a boolean array (0 -> out of boundary and 1 -> inside boundary).
Often one is interested in the population in a specific region (e.g., transmitted/reflected). By default, pywp will do the statistics over three region: Overall, R[0]>0 (transmission) and R[0]< 0 (reflection). These region can be customized by passing partitioner
and partition_titles
when creating an Application
. Paritioner is a list, each takes a list of position array (as if generated by meshgrid('ij')
) and return a boolean array (1 -> inside the region). Partition_titles are the titles for each partition, used in output.
If on-the-fly analysis is desired (this is usually due to a too large trajectory), one can pass analyzer
when creating an Application
. Analyzer is a list, each takes (R:list[array], P:list[array], psi:array, cuda_backend:bool)
. Anything returned will be stored and included in the return of Application.run()
. Note for psi
, electronic dimension is the last dimension. If GPU is used, cupy.array
will be given instead of numpy.array
.
The return of run()
is a list of tuples: (time:float, population:array, average_position:array, average_momentum:array, analysis_results:list).
If anything other than gaussian is desired, one can pass wp_generator
when creating an Application
. It takes the position and return a wavepacket on a single surface.
The wavefunction can be retrieved by snapshot.get_snapshot()
. The position and momentum grids can be retrieved by snapshot.get_R_grid()
and snapshot.get_P_grid()
.
PyWP comes with a powerful visualizing support, which make it easy to test custom potentials. Most functions are in pywp.visualize
.
- visualize_pe_1d, visualize_pe_2d and visualize_pe_2d_surf plot the potential surface in one or two specific dimension(s).
- visualize_snapshot_1d, visualize_snapshot_2d plot the wavepacket in one or two specific dimension(s).
- imshow, imshow_multiple, surf_multiple are wrappers around matplotlib functions, which can quickly plot 2D data.
python -m pywp.tools.show1d
and python -m pywp.tools.show2d
are command line wrappers for visualizing snapshots.