Skip to content

Commit

Permalink
Fix BandsData issue related to the k-points labels (#2492)
Browse files Browse the repository at this point in the history
fixes #2491 

* fix problem with empty labels array
* Fix bands plotting

If the first and/or the last kpoint label does not point to the first and/or
the last kpoint - the plotted band structure was cut on the left and/or right
sides. To avoid this I add empty labels to the first and/or the last kpoints
if they are not labeled.

* Add documentation on how to use the BandsData object
  • Loading branch information
yakutovicha authored and ltalirz committed Feb 28, 2019
1 parent 28eea8c commit f757e55
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 2 deletions.
13 changes: 11 additions & 2 deletions aiida/orm/data/array/bands.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,12 @@ def _get_bandplot_data(self, cartesian, prettify_format=None, join_symbol=None,
plot_info['paths'] = []

if len(labels) > 1:
# I add an empty label that points to the first band if the first label does not do it
if labels[0][0] != 0:
labels.insert(0, (0, ''))
# I add an empty label that points to the last band if the last label does not do it
if labels[-1][0] != len(bands)-1 :
labels.append((len(bands)-1, ''))
for (position_from, label_from), (position_to, label_to) in zip(labels[:-1], labels[1:]):
if position_to - position_from > 1:
# Create a new path line only if there are at least two points,
Expand Down Expand Up @@ -801,10 +807,13 @@ def _matplotlib_get_dict(self, main_file_name="", comments=True, title="", legen

bands = plot_info['y']
x = plot_info['x']
the_bands = numpy.transpose(bands)
labels = plot_info['labels']
# prepare xticks labels
tick_pos, tick_labels = zip(*labels)
if labels:
tick_pos, tick_labels = zip(*labels)
else:
tick_pos = []
tick_labels = []

#all_data['bands'] = the_bands.tolist()
all_data['paths'] = plot_info['paths']
Expand Down
Binary file added docs/source/datatypes/bands.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 116 additions & 0 deletions docs/source/datatypes/bands.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
.. _bands:

BandsData
=========

``BandsData`` object is dedicated to store bands object of different types
(electronic bands, phonons). In this section we describe the usage of the
``BandsData`` to store the (part of) electronic band structure of silicon
and some logic behind its methods.

To start working with ``BandsData`` we should import it using the
``DataFactory`` and create an object of type ``BandsData``::

from aiida.orm import DataFactory
BandsData = DataFactory('array.bands')
bs = BandsData()

To import the bands we need to make sure to have two arrays: one
containing kpoints and another containing bands. The shape of the kpoints object
should be ``nkpoints * 3``, while the shape of the bands should be
``nkpoints * nstates``. Let's assume the number of kpoints is 12, and the number
of states is 5. So the kpoints and the bands array will look as follows::

import numpy as np
kpoints = np.array([[0. , 0. , 0. ], # array shape is 12 * 3
[0.1 , 0. , 0.1 ],
[0.2 , 0. , 0.2 ],
[0.3 , 0. , 0.3 ],
[0.4 , 0. , 0.4 ],
[0.5 , 0. , 0.5 ],
[0.5 , 0. , 0.5 ],
[0.525 , 0.05 , 0.525 ],
[0.55 , 0.1 , 0.55 ],
[0.575 , 0.15 , 0.575 ],
[0.6 , 0.2 , 0.6 ],
[0.625 , 0.25 , 0.625 ]])

bands = np.array([[-5.64024889, 6.66929678, 6.66929678, 6.66929678, 8.91047649], # array shape is 12 * 5, where 12 is the size of the kpoints mesh
[-5.46976726, 5.76113772, 5.97844699, 5.97844699, 8.48186734], # and 5 is the numbe of states
[-4.93870761, 4.06179965, 4.97235487, 4.97235488, 7.68276008],
[-4.05318686, 2.21579935, 4.18048674, 4.18048675, 7.04145185],
[-2.83974972, 0.37738276, 3.69024464, 3.69024465, 6.75053465],
[-1.34041116, -1.34041115, 3.52500177, 3.52500178, 6.92381041],
[-1.34041116, -1.34041115, 3.52500177, 3.52500178, 6.92381041],
[-1.34599146, -1.31663872, 3.34867603, 3.54390139, 6.93928289],
[-1.36769345, -1.24523403, 2.94149041, 3.6004033 , 6.98809593],
[-1.42050683, -1.12604118, 2.48497007, 3.69389815, 7.07537154],
[-1.52788845, -0.95900776, 2.09104321, 3.82330632, 7.20537566],
[-1.71354964, -0.74425095, 1.82242466, 3.98697455, 7.37979746]])
To insert kpoints and bands in the ``bs`` object we should employ
``set_kpoints()`` and ``set_bands()`` methods::

bs.set_kpoints(kpoints)
bs.set_bands(bands, units='eV')

bs.show_mpl() # to visualize the bands

From now the band structure can be visualized. Last thing that we may want to
add is the array of kpoint labels::

labels = [(0, u'GAMMA'),
(5, u'X'),
(6, u'X'),
(11, u'U')]

bs.labels = labels
bs.show_mpl() # to visualize the bands

The resulting band structure will look as follows

.. figure:: bands.png

.. warning:: Once the ``bs`` object is stored (``bs.store()``) -- it won't
accept any modifications.


Plotting the band structure
++++++++++++++++++++++++++++

You may notice that depending on how you assign the kpoints labels the output
of the ``show_mpl()`` method looks different. Please compare::

bs.labels = [(0, u'GAMMA'),
(5, u'X'),
(6, u'Y'),
(11, u'U')]
bs.show_mpl()

bs.labels = [(0, u'GAMMA'),
(5, u'X'),
(7, u'Y'),
(11, u'U')]
bs.show_mpl()

In the first case two neighboring kpoints with ``X`` and ``Y`` labels will look like
``X|Y``, while in the second case they will be separated by a certain distance.
The logic behind such a difference is the following. In the first case the
plotting method discovers the two neighboring kpoints and assumes them to be a
discontinuity point in the band structure (e.g. Gamma-X|Y-U). In the second case the
kpoints labelled ``X`` and ``Y`` are not neighbors anymore, so they are
plotted with a certain distance between them. The intervals between the kpoints on the X axis are
proportional to the cartesian distance between them.

Dealing with spins
++++++++++++++++++

The ``BandsData`` object can also deal with the results of spin-polarized calculations. Two
provide different bands for two different spins you should just merge them in
one array and import them again using the ``set_bands()`` method::

bands_spins = [bands, bands-0.3] # to distinguish the bands of different spins we substitite 0.3 from the second band structure
bs.set_bands(bands_spins, units='eV')
bs.show_mpl()

Now the shape of the bands array becomes ``nspins * nkpoints * nstates``
1 change: 1 addition & 0 deletions docs/source/working_with_aiida/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Data types

../datatypes/index
../datatypes/kpoints
../datatypes/bands
../datatypes/functionality

==========
Expand Down

0 comments on commit f757e55

Please sign in to comment.