Example #1
0
def test_construction():
    """
    Test that we can construct a NEGF instance, without performing
    any operation.
    """
    foo = pynegf.PyNegf()
    assert(foo is not None)
Example #2
0
def test_current_conservation_dephasing(coupling=None):
    """ Test that we have current conservation at the electrodes """
    currents = []
    for orthogonal in [True, False]:
        for (ni, nf) in [(1, 2), (2, 1)]:
            negf = pynegf.PyNegf()
            # Build the sparse hamiltonian for the nearest-neighbor linear chain.
            mat_csr = utils.orthogonal_linear_chain(nsites=50,
                                                    contact_size=10,
                                                    coupling=1.0)
            if orthogonal:
                negf.set_hamiltonian(mat_csr)
                # Set an identity overlap matrix.
                negf.set_identity_overlap(50)
            else:
                negf.set_hamiltonian(mat_csr)
                mat_csr = utils.orthogonal_linear_chain(nsites=50,
                                                        contact_size=10,
                                                        coupling=0.1,
                                                        onsite=1.0)
                # This is to make sure that S is positive definite.
                numpy.linalg.cholesky(mat_csr.todense())
                # Set an identity overlap matrix.
                negf.set_overlap(mat_csr)

            # Initialize the system structure.
            negf.init_structure(2, numpy.array([39, 49]), numpy.array([29,
                                                                       39]))

            # Initialize parameters relevant for the transmission.
            negf.params.ec = -5.0
            negf.params.emin = -0.2
            negf.params.emax = 0.2
            negf.params.estep = 0.005
            negf.params.mu[0] = 0.1
            negf.params.mu[1] = -0.1
            # IMPORTANT: ni and nf must be both defined.
            negf.params.ni[0] = ni
            negf.params.ni[1] = nf
            negf.params.nf[0] = nf
            negf.params.nf[1] = ni
            negf.params.kbt_t[1] = 0.01
            negf.params.kbt_t[0] = 0.01
            negf.params.np_real[0] = 50
            negf.verbosity = 0
            negf.set_params()
            coupling = 0.1
            negf.set_diagonal_elph_dephasing(numpy.array([coupling] * 30))

            negf.solve_landauer()
            tmp_currents = negf.currents()
            assert tmp_currents[0] == pytest.approx(-tmp_currents[1], 1e-9)
            currents.append(tmp_currents[0])

        assert currents[0] == pytest.approx(-currents[1], 1e-9)
Example #3
0
def test_density_linear_chain_neq_2d():
    """
    Test the density matrix calculation at non-equilibrium for a linear
    chain in full-band.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_square_2d_lattice(
        nblocks=20, block_size=5, n_contact_blocks=2, coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(
        2,
        numpy.array([89, 99]),
        numpy.array([79, 89]))

    # Set parameters relevant for the density matrix calculation.
    # We fully occupy all band and use mostly default values for
    # the integration contour.
    negf.params.ec = -5.0
    negf.params.mu[0] = 0.1
    negf.params.mu[1] = -0.1
    negf.params.kbt_dm = (.001, .001)
    negf.params.g_spin = 2.0
    # Not correctly initialized, setting explicitely.
    negf.params.np_real = tuple([50] * 11)
    negf.params.verbose = 0

    negf.set_params()

    # Calculate the density matrix.
    negf.solve_density()
    density_matrix = negf.density_matrix()
    diagonal = density_matrix.diagonal()

    # The system is ballistic, therefore we should have identical
    # occupation all over the chain when checking equivalent sites.
    for i in range(5):
        assert diagonal[i:80:5] == pytest.approx(diagonal[i], abs=1e-4)

    # The occupation should 1.
    assert diagonal[0] == pytest.approx(1.0, abs=1e-3)

    # We should have 2 particles (due to degeneracy) per site.
    diagonal = density_matrix.diagonal()

    # The contact density matrix is ignored, therefore it should be zero.
    assert diagonal[80:] == pytest.approx(0.0)
Example #4
0
def test_transmission_linear_chain():
    """ Test that we can calculate the transmission for an ideal linear chain. """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_linear_chain(
        nsites=100, contact_size=20, coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(
        2,
        numpy.array([79, 99]),
        numpy.array([59, 79]),
        numpy.array([14, 29, 44, 59]),
        numpy.array([3, 0]))

    # Initialize parameters relevant for the transmission.
    negf.params.g_spin = 1
    negf.params.emin = -3.0
    negf.params.emax = 3.0
    negf.params.estep = 0.01
    negf.params.mu[0] = -0.5
    negf.params.mu[1] = 0.5
    negf.set_params()
    # negf.print_tnegf()

    # Set also some local DOS intervals.
    negf.set_ldos_intervals(numpy.array([0, 30, 0]), numpy.array([59, 59, 29]))

    negf.solve_landauer()

    # Get transmission, dos and energies as numpy object
    energies = negf.energies()
    transmission = negf.transmission()
    ldos = negf.ldos()
    # The system is homogeneous, therefore the first LDOS should be equal to
    # the sum of the second and third.
    assert ldos[0, :] == pytest.approx(ldos[1, :] + ldos[2, :])
    # Check ldos shape.
    _check_ldos_shape(ldos, energies)

    # The current in ballistic current units should be equal the
    # spin degeneracy we set, i.e. 1
    currents = negf.currents()
    currents[0] == pytest.approx(1.0)

    # Check that the transmission has the right integer values.
    _check_transmission_values(transmission, energies)
Example #5
0
def test_density_linear_chain_neq_bias():
    """
    Test the density matrix calculation at non-equilibrium for a linear
    chain in full-band.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_linear_chain(
        nsites=100, contact_size=20, coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(
        2,
        numpy.array([79, 99]),
        numpy.array([59, 79]))

    # Set parameters relevant for the density matrix calculation.
    # We fully occupy all band and use mostly default values for
    # the integration contour.
    negf.params.ec = -2.5
    negf.params.mu[0] = 0.1
    negf.params.mu[1] = -0.1
    negf.params.kbt_dm = (.001, .001)
    negf.params.g_spin = 2.0
    negf.params.np_real[0] = 50
    negf.params.verbose = 0

    negf.set_params()

    # Calculate the density matrix.
    negf.solve_density()
    density_matrix = negf.density_matrix()
    diagonal = density_matrix.diagonal()

    # The system is ballistic, therefore we should have identical
    # occupation all over the chain.
    assert diagonal[:60] == pytest.approx(diagonal[0], abs=1e-4)

    # The occupation should 1.
    assert diagonal[0] == pytest.approx(1.0, abs=1e-4)

    # We should have 2 particles (due to degeneracy) per site.
    diagonal = density_matrix.diagonal()

    # The contact density matrix is ignored, therefore it should be zero.
    assert diagonal[60:] == pytest.approx(0.0)
Example #6
0
def test_transmission_automatic_partition_2d():
    """
    Test that we can calculate the transmission for a 2d hamiltonian.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_square_2d_lattice(
        nblocks=20, block_size=5, n_contact_blocks=2, coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(
        2,
        numpy.array([89, 99]),
        numpy.array([79, 89]))

    # Initialize parameters relevant for the transmission.
    negf.params.g_spin = 1
    negf.params.emin = -5.0
    negf.params.emax = 5.0
    negf.params.estep = 0.01
    negf.params.mu[0] = 0.05
    negf.params.mu[0] = -0.05
    negf.set_params()
    # negf.print_tnegf()

    # Set also some local DOS intervals.
    negf.set_ldos_intervals(numpy.array([0, 30, 0]), numpy.array([59, 59, 29]))

    negf.solve_landauer()

    # Get transmission, dos and energies as numpy object
    transmission = negf.transmission()
    ldos = negf.ldos()

    # The system is homogeneous, therefore the first LDOS should be equal to
    # the sum of the second and third.
    assert ldos[0, :] == pytest.approx(ldos[1, :] + ldos[2, :])

    # The current in ballistic current units should be equal the
    # spin degeneracy we set times 5 (number of bands) times delta_mu, i.e. 0.5
    currents = negf.currents()
    currents[0] == pytest.approx(0.5)

    # Check that the transmission peaks at 5.0.
    assert numpy.max(transmission[0, :]) == pytest.approx(5.0)
Example #7
0
def _density_linear_chain_dephasing(coupling=None, orthogonal=True):
    """
    Utility to calculate the density matrix in presence of diagonal
    dephasing for a nearest neighbor linear chain.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_linear_chain(nsites=50,
                                            contact_size=10,
                                            coupling=1.0)
    if orthogonal:
        negf.set_hamiltonian(mat_csr)
        # Set an identity overlap matrix.
        negf.set_identity_overlap(50)
    else:
        negf.set_hamiltonian(mat_csr)
        mat_csr = utils.orthogonal_linear_chain(nsites=50,
                                                contact_size=10,
                                                coupling=0.1,
                                                onsite=1.0)
        # This is to make sure that S is positive definite.
        numpy.linalg.cholesky(mat_csr.todense())
        # Set an identity overlap matrix.
        negf.set_overlap(mat_csr)

    # Initialize the system structure.
    negf.init_structure(2, numpy.array([39, 49]), numpy.array([29, 39]))

    # Initialize parameters relevant for the density matrix calculation.
    negf.params.ec = -3.5
    negf.params.mu[0] = -0.1
    negf.params.mu[1] = 0.1
    negf.params.kbt_dm[0] = 0.001
    negf.params.kbt_dm[1] = 0.001
    negf.params.np_real[0] = 50
    negf.params.verbose = 100
    negf.set_params()
    if coupling is not None:
        negf.set_diagonal_elph_dephasing(numpy.array([coupling] * 30))

    negf.solve_density()

    # Get the density matrix.
    density_matrix = negf.density_matrix()

    return density_matrix
Example #8
0
def test_density_linear_chain_eq():
    """
    Test the density matrix calculation at equilibrium for a linear
    chain in full-band.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_linear_chain(
        nsites=100, contact_size=20, coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(
        2,
        numpy.array([79, 99]),
        numpy.array([59, 79]))

    # Set parameters relevant for the density matrix calculation.
    # We fully occupy all band and use mostly default values for
    # the integration contour.
    negf.params.ec = -2.5
    negf.params.mu[0] = 0.0
    negf.params.mu[1] = 0.0
    negf.params.kbt_dm = (.001, .001)
    negf.params.g_spin = 2.0
    # Not correctly initialized, setting explicitely.
    negf.params.np_real = tuple([0] * 11)
    negf.params.verbose = 0

    negf.set_params()

    # Calculate the density matrix.
    negf.solve_density()
    density_matrix = negf.density_matrix()
    # We should have 1 particles (2 degeneracy, half band occupied) per site.
    diagonal = density_matrix.diagonal()
    assert diagonal[:60] == pytest.approx(1.0)

    # The contact density matrix is ignored, therefore it should be zero.
    assert diagonal[60:] == pytest.approx(0.0)
Example #9
0
def _transmission_linear_chain_dephasing(coupling=None):
    """
    Utility to calculate the transmission in presence of diagonal
    dephasing for a nearest neighbor linear chain.
    """
    negf = pynegf.PyNegf()
    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat_csr = utils.orthogonal_linear_chain(nsites=100,
                                            contact_size=10,
                                            coupling=1.0)

    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure.
    negf.init_structure(2, numpy.array([89, 99]), numpy.array([79, 89]))

    # Initialize parameters relevant for the transmission.
    negf.params.g_spin = 1
    negf.params.emin = -2.5
    negf.params.emax = 2.5
    negf.params.estep = 0.025
    negf.params.mu[0] = 2.1
    negf.params.mu[1] = -2.1
    negf.verbosity = 0
    negf.set_params()
    if coupling is not None:
        negf.set_diagonal_elph_dephasing(numpy.array([coupling] * 80))

    negf.solve_landauer()

    # Get transmission, dos and energies as numpy object
    energies = negf.energies()
    if coupling is None:
        transmission = negf.transmission()
    else:
        transmission = negf.energy_current()

    return energies, transmission
Example #10
0
def transmission_linear_chain():
    """
    Calculate the transmission for a linear chain model hamiltonian.
    """
    # Start an instance of the library.
    negf = pynegf.PyNegf()

    # Build the sparse hamiltonian for the nearest-neighbor linear chain.
    mat = numpy.zeros(shape=(100, 100), dtype='complex128')
    for ii in range(80):
        mat[ii, ii - 1] = 1.0
        mat[ii - 1, ii] = 1.0
    for ii in range(81, 100):
        mat[ii, ii - 1] = 1.0
        mat[ii - 1, ii] = 1.0
    mat[0, 80] = 1.0
    mat[80, 0] = 1.0

    mat_csr = scipy.sparse.csr_matrix(mat)
    mat_csr.sort_indices()

    # Pass the hamiltonian to libnegf.
    negf.set_hamiltonian(mat_csr)

    # Set an identity overlap matrix.
    negf.set_identity_overlap(100)

    # Initialize the system structure. Here we specify the following
    # parameters:
    #   number of contact: 2
    #   start-end index of first contact: numpy.array([80, 100])
    #   start-end index of second contact: numpy.array([60, 80])
    #   end-index of each layer, for the iterative algorithm: numpy.array([15, 30, 45, 60])
    #   index of bloks interacting with the contact: numpy.array([4, 1])
    negf.init_structure(
        2,
        numpy.array([80, 100]),
        numpy.array([60, 80]),
        numpy.array([15, 30, 45, 60]),
        numpy.array([4, 1]))

    # Initialize parameters relevant for the transmission.
    # the chemical potential mu is used for evaluating the current only.
    negf.params.emin = -3.0
    negf.params.emax = 3.0
    negf.params.estep = 0.01
    negf.params.mu[0] = 0.1
    negf.set_params()
    negf.print_tnegf()

    # Set also some local DOS intervals.
    negf.set_ldos_intervals(numpy.array([1, 31, 1]), numpy.array([60, 60, 30]))
    negf.solve_landauer()

    # Get transmission, dos and energies as numpy object.
    energies = negf.energies()
    print('energies', energies)
    trans = negf.transmission()
    ldos = negf.ldos()
    currents = negf.currents()
    print('Currents',currents)
    print('trans', trans)