GithubHelp home page GithubHelp logo

freude / nanonet Goto Github PK

View Code? Open in Web Editor NEW
30.0 5.0 14.0 3.29 MB

The project represents an extendable Python framework for the electronic structure computations based on the tight-binding method and transport modeling based on the non-equilibrium Green's function (NEGF) method. The code can deal with both finite and periodic system translated in one, two or three dimensions.

License: MIT License

Jupyter Notebook 61.29% Python 38.71%
physics chemistry electronic-structure band-structure tight-binding

nanonet's Introduction

NanoNET

License: MIT codecov CodeFactor Codacy Badge PyPI version

Introduction

The project NanoNET (Nanoscale Non-equilibrium Electron Transport) represents an extendable Python framework for the electronic structure computations based on the tight-binding method. The code can deal with both finite and periodic systems translated in one, two or three dimensions.

All computations can be governed by means of the python application programming interface (pyAPI) or the command line interface (CLI).

Getting Started

Requirements

NanoNet requires openmpi to be installed in the system:

Ubuntu

sudo apt-get install libopenmpi-dev

MacOS

brew install open-mpi

Installing from PiPy

The easiest way to install NanoNet without tests is from the PiPy repository:

pip install nano-net

Installing from sources

The source distribution can be obtained from GitHub:

git clone https://github.com/freude/NanoNet.git
cd NanoNet

All other dependencies can be installed at once by invoking the following command from within the source directory:

pip install -r requirements.txt

In order to install the package Nanonet just invoke the following line in the bash from within the source directory:

pip install .

Running the tests

If the source distribution is available, all tests may be run by invoking the following command in the root directory:

nosetests --with-doctest

Examples of usage

Python interface

Below is a short example demonstrating usage of the tb package. More illustrative examples can be found in the ipython notebooks in the directory jupyter_notebooks inside the source directory.

Below we demonstrate band structure computation for a nanoribbon with four atoms per unit cell:

--A--
  |
--A--
  |
--A--
  |
--A--
  1. If the package is properly installed, the work starts with the import of all necessary modules:

    import numpy as np
    import matplotlib.pyplot as plt
    import nanonet.tb as tb
    from nanonet.negf.recursive_greens_functions import recursive_gf
    from nanonet.negf.greens_functions import surface_greens_function
  2. First, one needs to specify atomic species and corresponding basis sets. We assume that each atom has one s-type atomic orbital with energy -1 eV. It is also possible to use predefined basis sets as is shown in examples in the ipython notebooks.

    orb = tb.Orbitals('A')
    orb.add_orbital(title='s', energy=-1.0)
  3. Set tight-binding parameters:

    tb.set_tb_params(PARAMS_A_A={"ss_sigma": 1.0})
  4. Define atomic coordinates for the unit cell:

    input_file = """4
                    Nanostrip
                    A1 0.0 0.0 0.0
                    A2 0.0 1.0 0.0
                    A3 0.0 2.0 0.0
                    A4 0.0 3.0 0.0
                 """
  5. Make instance of the Hamiltonian class and specify periodic boundary conditions if any:

    h = tb.Hamiltonian(xyz=input_file, nn_distance=1.4)
    h.initialize()
    h.set_periodic_bc([[0, 0, 1.0]])
    h_l, h_0, h_r = h.get_hamiltonians()
  6. Compute DOS and transmission using Green's functions:

    energy = np.linspace(-5.0, 5.0, 150)
    dos = np.zeros((energy.shape[0]))
    tr = np.zeros((energy.shape[0]))
    
    for j, E in enumerate(energy):
        # compute surface Green's functions
        L, R = surface_greens_function(E, h_l, h_0, h_r)
        # recursive Green's functions
        g_trans, grd, grl, gru, gr_left = recursive_gf(E, [h_l], [h_0 + L + R], [h_r])
        # compute DOS
        dos[j] = np.real(np.trace(1j * (grd[0] - grd[0].conj().T)))
        # compute left-lead coupling
        gamma_l = 1j * (L - L.conj().T)
        # compute right-lead coupling
        gamma_r = 1j * (R - R.conj().T)
        # compute transmission
        tr[j] = np.real(np.trace(gamma_l @ g_trans @ gamma_r @ g_trans.conj().T)))
  7. Plot DOS and transmission spectrum:

    fig, ax = plt.subplots(1, 2)
    ax[0].plot(energy, dos, 'k')
    ax[0].set_ylabel(r'DOS (a.u)')
    ax[0].set_xlabel(r'Energy (eV)')
    
    ax[1].plot(energy, tr, 'k')
    ax[1].set_ylabel(r'Transmission (a.u.)')
    ax[1].set_xlabel(r'Energy (eV)')
    fig.tight_layout()
    plt.show()
  8. Done. The result will appear on the screen.

gh_img

Authors

  • Mykhailo V. Klymenko ([email protected])
  • Jackson S. Smith
  • Jesse A. Vaitkus
  • Jared H. Cole

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

We acknowledge support of the RMIT University, Australian Research Council through grant CE170100026, and National Computational Infrastructure, which is supported by the Australian Government.

References

M.V. Klymenko, J.A. Vaitkus, J.S. Smith, and J.H. Cole, "NanoNET: An extendable Python framework for semi-empirical tight-binding models," Computer Physics Communications, Volume 259, 107676 (2021)

nanonet's People

Contributors

codacy-badger avatar drvaitkus avatar freude avatar sglambert avatar stripey-tiger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nanonet's Issues

duplicate of the function "get_neighbours"

why are there two copies of this function? i have highlighted the second copy, which is superfluous (see below)

def get_neighbours(self, query):
if isinstance(query, list):
ans = self._kd_tree.query(query,
k=5,
distance_upper_bound=self._nn_distance)
elif isinstance(query, int):
ans = self._kd_tree.query(self.atom_list.items()[query][1],
k=5,
distance_upper_bound=self._nn_distance)
elif isinstance(query, str):
ans = self._kd_tree.query(self.atom_list[query],
k=5,
distance_upper_bound=self._nn_distance)
else:
raise TypeError('Wrong input type for query')
ans1 = [ans[1][0]]
for item in zip(ans[0], ans[1]):
if self._nn_distance * 0.25 < item[0] < self._nn_distance:
ans1.append(item[1])
return ans1

[Bug] There is a small bug about function d_me

The d_me fuction:

def d_me(N, l, m1, m2):
"""Computes rotational matrix elements according to
A.V. Podolskiy and P. Vogl, Phys. Rev. B. 69, 233101 (2004)
Parameters
----------
N :
directional cosine relative to z-axis
l :
orbital quantum number
m1 :
magnetic quantum number
m2 :
magnetic quantum number
Returns
-------
type
rotational matrix element
"""

if N == -1.0 and m1 == m2:
    prefactor = math.sqrt(math.factorial(l + m2) * math.factorial(l - m2) *
                          math.factorial(l + m1) * math.factorial(l - m1))
else:
    prefactor = ((0.5 * (1 + N)) ** l) * (((1 - N) / (1 + N)) ** (m1 * 0.5 - m2 * 0.5)) * \
        math.sqrt(math.factorial(l + m2) * math.factorial(l - m2) *
                  math.factorial(l + m1) * math.factorial(l - m1))

ans = 0
for t in range(2 * l + 2):
    if l + m2 - t >= 0 and l - m1 - t >= 0 and t + m1 - m2 >= 0:
        if N == -1.0 and t == 0:
            ans += ((-1) ** t) / \
                   (math.factorial(l + m2 - t) * math.factorial(l - m1 - t) *
                    math.factorial(t) * math.factorial(t + m1 - m2))
        else:
            ans += ((-1) ** t) * (((1 - N) / (1 + N)) ** t) / \
                   (math.factorial(l + m2 - t) * math.factorial(l - m1 - t) *
                    math.factorial(t) * math.factorial(t + m1 - m2))

return np.nan_to_num(ans * prefactor)

if N, l, m1, m2 equals -1, 1, 0, 0 respectively, then (1 - N) / (1 + N) in the "and +=" line will raise an error of dividing by zero.
should there be a condition that excludes the N = -1?

About self-consistent NEGF calculation

Thanks for your work in providing such a convenient and efficient algorithm of Tight Binding framework under python.

I am wondering if the method of Podolskiy and Vogl can support an updating of TB hamiltonian due to the external potential?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.