Package: lattpy
LattPy - Simple Lattice Modeling in Python:warning:WARNING: This project is still in development and might change significantly in the future!LattPyis a simple and efficient Python package for modeling Bravais lattices and
constructing (finite) lattice structures in any dimension.
It provides an easy interface for constructing lattice structures by simplifying the
configuration of the unit cell and the neighbor connections - making it possible to
construct complex models in just a few lines of code and without the headache of
adding neighbor connections manually. You will save time and mental energy for more important matters.MasterDev🔧 InstallationLattPy is available onPyPI:pip install lattpyAlternatively, it can be installed viaGitHubpip install git+https://github.com/dylanljones/lattpy.git@VERSIONwhereVERSIONis a release or tag. The project can also be
cloned/forked and installed viapython setup.py install📖 DocumentationRead the documentation on ReadTheDocs!🚀 Quick-StartSee thetutorialfor more information and examples.Features:Basis transformationsConfigurable unit cellEasy neighbor configurationGeneral lattice structuresFinite lattice models in world or lattice coordinatesPeriodic boundary conditions along any axisConfigurationA new instance of a lattice model is initialized using the unit-vectors of the Bravais lattice.
After the initialization the atoms of the unit-cell need to be added. To finish the configuration
the connections between the atoms in the lattice have to be set. This can either be done for
each atom-pair individually by callingadd_connectionor for all possible pairs at once by
calllingadd_connections. The argument is the number of unique
distances of neighbors. Setting a value of1will compute only the nearest
neighbors of the atom.importnumpyasnpfromlattpyimportLatticelatt=Lattice(np.eye(2))# Construct a Bravais lattice with square unit-vectorslatt.add_atom(pos=[0.0,0.0])# Add an Atom to the unit cell of the latticelatt.add_connections(1)# Set the maximum number of distances between all atomslatt=Lattice(np.eye(2))# Construct a Bravais lattice with square unit-vectorslatt.add_atom(pos=[0.0,0.0],atom="A")# Add an Atom to the unit cell of the latticelatt.add_atom(pos=[0.5,0.5],atom="B")# Add an Atom to the unit cell of the latticelatt.add_connection("A","A",1)# Set the max number of distances between A and Alatt.add_connection("A","B",1)# Set the max number of distances between A and Blatt.add_connection("B","B",1)# Set the max number of distances between B and Blatt.analyze()Configuring all connections using theadd_connections-method will call theanalyze-method
directly. Otherwise this has to be called at the end of the lattice setup or by usinganalyze=Truein the last call ofadd_connection. This will compute the number of neighbors,
their distances and their positions for each atom in the unitcell.To speed up the configuration prefabs of common lattices are included. The previous lattice
can also be created withfromlattpyimportsimple_squarelatt=simple_square(a=1.0,neighbors=1)# Initializes a square lattice with one atom in the unit-cellSo far only the lattice structure has been configured. To actually construct a (finite) model of the lattice
the model has to be built:latt.build(shape=(5,3))This will compute the indices and neighbors of all sites in the given shape and store the data.After building the lattice periodic boundary conditions can be set along one or multiple axes:latt.set_periodic(axis=0)To view the built lattice theplot-method can be used:importmatplotlib.pyplotaspltlatt.plot()plt.show()General lattice attributesAfter configuring the lattice the attributes are available.
Even without building a (finite) lattice structure all attributes can be computed on the fly for a given lattice vector,
consisting of the translation vectornand the atom indexalpha. For computing the (translated) atom positions
theget_positionmethod is used. Also, the neighbors and the vectors to these neighbors can be calculated.
Thedist_idx-parameter specifies the distance of the neighbors (0 for nearest neighbors, 1 for next nearest neighbors, ...):fromlattpyimportsimple_squarelatt=simple_square()# Get position of atom alpha=0 in the translated unit-cellpositions=latt.get_position(n=[0,0],alpha=0)# Get lattice-indices of the nearest neighbors of atom alpha=0 in the translated unit-cellneighbor_indices=latt.get_neighbors(n=[0,0],alpha=0,distidx=0)# Get vectors to the nearest neighbors of atom alpha=0 in the translated unit-cellneighbor_vectors=latt.get_neighbor_vectors(alpha=0,distidx=0)Also, the reciprocal lattice vectors can be computedrvecs=latt.reciprocal_vectors()or used to construct the reciprocal lattice:rlatt=latt.reciprocal_lattice()The 1. Brillouin zone is the Wigner-Seitz cell of the reciprocal lattice:bz=rlatt.wigner_seitz_cell()The 1.BZ can also be obtained by calling the explicit method of the direct lattice:bz=latt.brillouin_zone()Finite lattice dataIf the lattice has been built the needed data is cached. The lattice sites of the
structure then can be accessed by a simple indexi. The syntax is the same as before,
just without theget_prefix:latt.build((5,2))i=2# Get position of the atom with index i=2positions=latt.position(i)# Get the atom indices of the nearest neighbors of the atom with index i=2neighbor_indices=latt.neighbors(i,distidx=0)# the nearest neighbors can also be found by calling (equivalent to dist_idx=0)neighbor_indices=latt.nearest_neighbors(i)Data mapThe lattice model makes it is easy to construct the (tight-binding) Hamiltonian of a non-interacting model:importnumpyasnpfromlattpyimportsimple_chain# Initializes a 1D lattice chain with a length of 5 atoms.latt=simple_chain(a=1.0)latt.build(shape=4)n=latt.num_sites# Construct the non-interacting (kinetic) Hamiltonian-matrixeps,t=0.,1.ham=np.zeros((n,n))foriinrange(n):ham[i,i]=epsforjinlatt.nearest_neighbors(i):ham[i,j]=tSince we loop over all sites of the lattice the construction of the hamiltonian is slow.
An alternative way of mapping the lattice data to the hamiltonian is using theDataMapobject returned by themap()method of the lattice data. This stores the atom-types,
neighbor-pairs and corresponding distances of the lattice sites. Using the built-in
masks the construction of the hamiltonian-data can be vectorized:fromscipyimportsparse# Vectorized construction of the hamiltonianeps,t=0.,1.dmap=latt.data.map()# Build datamapvalues=np.zeros(dmap.size)# Initialize array for data of Hvalues[dmap.onsite(alpha=0)]=eps# Map onsite-energies to arrayvalues[dmap.hopping(distidx=0)]=t# Map hopping-energies to array# The indices and data array can be used to construct a sparse matrixham_s=sparse.csr_matrix((values,dmap.indices))ham=ham_s.toarray()Both construction methods will create the following Hamiltonian-matrix:[[0. 1. 0. 0. 0.]
 [1. 0. 1. 0. 0.]
 [0. 1. 0. 1. 0.]
 [0. 0. 1. 0. 1.]
 [0. 0. 0. 1. 0.]]🔥 PerformanceEven thoughlattpyis written in pure python, it achieves high performance and
a low memory footprint by making heavy use of numpy's vectorized operations and scipy's
cKDTree. As an example the build times and memory usage in the build process for different
lattices are shown in the following plots:Build timeBuild memoryNote that the overhead of the multi-thread neighbor search results in a slight
increase of the build time for small systems. By usingnum_jobs=1in thebuild-method
this overhead can be eliminated for small systems. By passingnum_jobs=-1all cores
of the system are used.💻 DevelopmentSee theCHANGELOGfor
the recent changes of the project.If you encounter an issue or want to contribute to pyrekordbox, please feel free to
get in touch,create an issueor open a pull request! A guide for contributing tolattpyand the commit-message style can be found inCONTRIBUTING