Commits (30)
......@@ -11,10 +11,11 @@ The principal developers of Kwant are
The authors can be reached at authors@kwant-project.org.
Other contributors to Kwant include
Contributors to Kwant include
* Mathieu Istas (INAC/CEA Grenoble)
* Daniel Jaschke (INAC/CEA Grenoble)
* Bas Nijholt (TU Delft)
* Michał Nowak (TU Delft)
* Viacheslav Ostroukh (Leiden University)
* Adrien Sorgniard (INAC/CEA Grenoble)
......
......@@ -152,7 +152,7 @@ root.
1. Install the required packages. On Debian-based systems like Ubuntu this can
be done by running the command ::
sudo apt-get install python-dev python-scipy python-matplotlib python-nose g++ gfortran libopenblas-dev liblapack-dev libmumps-scotch-dev
sudo apt-get install python3-dev python3-scipy python3-matplotlib python3-nose g++ gfortran libopenblas-dev liblapack-dev libmumps-scotch-dev
2. Unpack Tinyarray, enter its directory. To build and install, run ::
......
......@@ -50,6 +50,8 @@ help:
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo
@echo "Append SPHINXOPTS='-A website_deploy=True' to include web analytics code."
clean:
-rm -rf $(BUILDDIR)/* $(GENERATEDPDF)
......
......@@ -223,9 +223,6 @@ latex_documents = [
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
latex_use_modindex = False
# This is needed too.
latex_domain_indices = False
......
What's new in Kwant 1.1
=======================
This article explains the user-visible changes in Kwant 1.1, released on 21 October 2015.
Please consult the `full list of changes in Kwant <http://git.kwant-project.org/kwant/log/?h=stable>`_ for all the changes up to the most recent bugfix release.
This article explains the user-visible changes in Kwant 1.1.0, released on 21
October 2015. See also the `full list of changes up to the most recent bugfix
release of the 1.1 series
<https://gitlab.kwant-project.org/kwant/kwant/compare/v1.1.0...latest-1.1>`_.
Harmonize `~kwant.physics.Bands` with `~kwant.physics.modes`
------------------------------------------------------------
......
What's new in Kwant 1.2
=======================
This article explains the user-visible changes in Kwant 1.2, released on 9
December 2015. Please consult the `full list of changes in Kwant
<https://gitlab.kwant-project.org/kwant/kwant/compare/v1.2.2...stable>`_ for
all the changes up to the most recent bugfix release.
This article explains the user-visible changes in Kwant 1.2.2, released on 9
December 2015. See also the `full list of changes up to the most recent bugfix
release of the 1.2 series
<https://gitlab.kwant-project.org/kwant/kwant/compare/v1.2.2...latest-1.2>`_.
Kwant 1.2 is identical to Kwant 1.1 except that it has been updated to run on
Python 3.4 and above. Bugfix releases for the 1.1 and 1.2 series will mirror
......
......@@ -209,5 +209,25 @@
{%- endif %}
</div>
{%- endblock %}
{%- if website_deploy %}
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.kwant-project.org"]);
_paq.push(["trackPageView"]);
_paq.push(["enableLinkTracking"]);
(function() {
var u=(("https:" == document.location.protocol) ? "https" : "http") + "://piwik.kwant-project.org/";
_paq.push(["setTrackerUrl", u+"piwik.php"]);
_paq.push(["setSiteId", "1"]);
var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><img src="http://piwik.kwant-project.org/piwik.php?idsite=1&amp;rec=1" style="border:0" alt="" /></noscript>
<!-- End Piwik Code: Analytics are used by us to improve the site, and not sent to anyone. -->
{%- endif %}
</body>
</html>
......@@ -134,7 +134,7 @@ class SiteFamily(metaclass=abc.ABCMeta):
try:
return self.canonical_repr != other.canonical_repr
except AttributeError:
return False
return True
@abc.abstractmethod
def normalize_tag(self, tag):
......@@ -648,7 +648,7 @@ class Builder:
Print the value of a site.
>>> print builder[site]
>>> print(builder[site])
Define a hopping.
......@@ -1059,6 +1059,9 @@ class Builder:
The lead numbering starts from zero and increments from there, i.e.
the leads are numbered in the order in which they are attached.
"""
if self.symmetry.num_directions:
raise ValueError("Leads can only be attached to finite systems.")
if add_cells < 0 or int(add_cells) != add_cells:
raise ValueError('add_cells must be an integer >= 0.')
......
......@@ -198,22 +198,22 @@ def setup_linsys(h_cell, h_hop, tol=1e6, stabilization=None):
if (n_nonsing == n and stabilization is None):
# The hopping matrix is well-conditioned and can be safely inverted.
# Hence the regular transfer matrix may be used.
hop_inv = la.inv(h_hop)
h_hop_sqrt = sqrt(np.linalg.norm(h_hop))
A = h_hop / h_hop_sqrt
B = h_hop_sqrt
B_H_inv = 1.0 / B # just a real scalar here
A_inv = la.inv(A)
A = np.zeros((2*n, 2*n), dtype=np.common_type(h_cell, h_hop))
A[:n, :n] = dot(hop_inv, -h_cell)
A[:n, n:] = -hop_inv
A[n:, :n] = h_hop.T.conj()
# The function that can extract the full wave function psi from the
# projected one. Here it is almost trivial, but used for simplifying
# the logic.
lhs = np.zeros((2*n, 2*n), dtype=np.common_type(h_cell, h_hop))
lhs[:n, :n] = -dot(A_inv, h_cell) * B_H_inv
lhs[:n, n:] = -A_inv * B
lhs[n:, :n] = A.T.conj() * B_H_inv
def extract_wf(psi, lmbdainv):
return np.copy(psi[:n])
return B_H_inv * np.copy(psi[:n])
matrices = (A, None)
v_out = None
matrices = (lhs, None)
v_out = h_hop_sqrt * np.eye(n)
else:
if stabilization is None:
stabilization = [None, False]
......@@ -578,8 +578,8 @@ def modes(h_cell, h_hop, tol=1e6, stabilization=None):
raise ValueError("Incompatible matrix sizes for h_cell and h_hop.")
if not complex_any(h_hop):
v = np.zeros((0, m))
return (PropagatingModes(np.zeros((0, n)), np.zeros((0,)),
v = np.zeros((m, 0))
return (PropagatingModes(np.zeros((n, 0)), np.zeros((0,)),
np.zeros((0,))),
StabilizedModes(np.zeros((0, 0)), np.zeros((0, 0)), 0, v))
......
......@@ -224,7 +224,7 @@ def test_modes():
v = 2 * t * np.sin(k)
prop, stab = leads.modes(np.array([[h]]), np.array([[t]]))
assert stab.nmodes == 1
assert stab.sqrt_hop is None
assert stab.sqrt_hop[0] == np.sqrt(np.linalg.norm(t))
np.testing.assert_almost_equal(prop.velocities, [-v, v])
np.testing.assert_almost_equal(prop.momenta, [k, -k])
# Test for normalization by current.
......@@ -255,7 +255,7 @@ def test_algorithm_equivalence():
u, v = u * np.sqrt(s), vh.T.conj() * np.sqrt(s)
prop_vecs = []
evan_vecs = []
algos = [None] + list(product(*(2 * [(True, False)])))
algos = [None, (True, True), (True, False), (False, True), (False, False)]
for algo in algos:
result = leads.modes(h, t, stabilization=algo)[1]
......@@ -266,7 +266,9 @@ def test_algorithm_equivalence():
vecs = np.dot(v, vecs)
np.testing.assert_almost_equal(result.sqrt_hop, v)
else:
vecslmbdainv = np.dot(v.T.conj(), vecslmbdainv)
vecslmbdainv = (np.dot(v.T.conj(), vecslmbdainv) /
np.sqrt(np.linalg.norm(t)))
vecs = vecs * np.sqrt(np.linalg.norm(t))
full_vecs = np.r_[vecslmbdainv, vecs]
prop_vecs.append(full_vecs[:, : 2 * result.nmodes])
......@@ -324,3 +326,34 @@ def test_dtype_linsys():
lsys = kwant.physics.leads.setup_linsys(h_cell - 0.3*np.eye(2),
h_hop)
assert lsys.eigenproblem[0].dtype == np.complex128
def test_zero_hopping():
h_cell = np.identity(2)
h_hop = np.zeros((2, 1))
expected = (leads.PropagatingModes(np.zeros((2, 0)), np.zeros((0,)),
np.zeros((0,))),
leads.StabilizedModes(np.zeros((0, 0)), np.zeros((0, 0)), 0,
np.zeros((1, 0))))
actual = leads.modes(h_cell, h_hop)
assert all(np.alltrue(getattr(actual[1], attr) ==
getattr(expected[1], attr)) for attr
in ('vecs', 'vecslmbdainv', 'nmodes', 'sqrt_hop'))
assert all(np.alltrue(getattr(actual[0], attr) ==
getattr(expected[0], attr)) for attr
in ('wave_functions', 'velocities', 'momenta'))
def make_clean_lead(W, E, t):
syst = kwant.Builder(kwant.TranslationalSymmetry((1, 0)))
lat = kwant.lattice.square()
syst[(lat(0, j) for j in range(W))] = E
syst[lat.neighbors()] = -t
return syst.finalized()
def test_momenta():
"""Test whether the two systems have the same momenta,
these should not change when the Hamiltonian is scaled."""
momenta = [make_clean_lead(10, s, s).modes()[0].momenta for s in [1, 1e20]]
assert_almost_equal(*momenta)
......@@ -16,6 +16,7 @@ system in two or three dimensions.
from collections import defaultdict
import warnings
import random
import numpy as np
import tinyarray as ta
from scipy import spatial, interpolate
......@@ -79,6 +80,11 @@ def nparray_if_array(var):
return np.asarray(var) if isarray(var) else var
def _sample_array(array, n_samples):
la = len(array)
return array[random.sample(range(la), min(n_samples, la))]
if mpl_enabled:
class LineCollection(collections.LineCollection):
def __init__(self, segments, reflen=None, **kwargs):
......@@ -1174,7 +1180,7 @@ def plot(sys, num_lead_cells=2, unit='nn',
# If no hoppings are present, use for the same purpose distances
# from ten randomly selected points to the remaining points in the
# system.
points = sites_pos[np.random.randint(len(sites_pos), size=10)].T
points = _sample_array(sites_pos, 10).T
distances = (sites_pos.T.reshape(1, -1, dim) -
points.reshape(-1, 1, dim)).reshape(-1, dim)
distances = np.sort(np.sum(distances**2, axis=1))
......@@ -1424,7 +1430,8 @@ def mask_interpolate(coords, values, a=None, method='nearest', oversampling=3):
tree = spatial.cKDTree(coords)
points = coords[np.random.randint(len(coords), size=10)]
# Select 10 sites to compare -- comparing them all is too costly.
points = _sample_array(coords, 10)
min_dist = np.min(tree.query(points, 2)[0][:, 1])
if min_dist < 1e-6 * np.linalg.norm(cmax - cmin):
warnings.warn("Some sites have nearly coinciding positions, "
......
......@@ -8,7 +8,7 @@
import warnings
from random import Random
from nose.tools import assert_raises
from nose.tools import assert_raises, assert_not_equal
from numpy.testing import assert_equal, assert_almost_equal
import tinyarray as ta
import kwant
......@@ -102,6 +102,12 @@ def test_site_families():
assert_equal(sys[ofam(1)], 123)
assert_raises(KeyError, sys.__getitem__, yafam(1))
# test site families compare equal/not-equal
assert_equal(fam, ofam)
assert_not_equal(fam, yafam)
assert_not_equal(fam, None)
assert_not_equal(fam, 'a')
class VerySimpleSymmetry(builder.Symmetry):
def __init__(self, period):
......
......@@ -151,18 +151,15 @@ def test_map():
with warnings.catch_warnings():
warnings.simplefilter("ignore")
plotter.map(sys.finalized(), range(len(sys.sites())),
file=out)
file=out)
nose.tools.assert_raises(ValueError, plotter.map, sys,
range(len(sys.sites())), file=out)
def test_mask_interpolate():
# A coordinate array with coordinates of two points almost coinciding.
coords = np.random.rand(10, 2)
coords[5] *= 1e-8
coords[5] += coords[0]
coords = np.array([[0, 0], [1e-7, 1e-7], [1, 1], [1, 0]])
warnings.simplefilter("ignore")
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
plotter.mask_interpolate(coords, np.ones(len(coords)), a=1)
......@@ -170,7 +167,9 @@ def test_mask_interpolate():
assert issubclass(w[-1].category, RuntimeWarning)
assert "coinciding" in str(w[-1].message)
assert_raises(ValueError, plotter.mask_interpolate,
coords, np.ones(len(coords)))
assert_raises(ValueError, plotter.mask_interpolate,
coords, np.ones(2 * len(coords)))
with warnings.catch_warnings():
warnings.simplefilter("ignore")
assert_raises(ValueError, plotter.mask_interpolate,
coords, np.ones(len(coords)))
assert_raises(ValueError, plotter.mask_interpolate,
coords, np.ones(2 * len(coords)))
[egg_info]
tag_build =
tag_build =
tag_date = 0
tag_svn_revision = 0
......@@ -30,13 +30,20 @@ from setuptools import setup, find_packages, Extension, Command
from sysconfig import get_platform
from distutils.errors import DistutilsError, DistutilsModuleError, \
CCompilerError
from distutils.command.build import build
from setuptools.command.sdist import sdist
from setuptools.command.build_ext import build_ext
from distutils.command.build import build as build_orig
from setuptools.command.sdist import sdist as sdist_orig
from setuptools.command.build_ext import build_ext as build_ext_orig
from setuptools.command.test import test as test_orig
def banner(title=''):
starred = title.center(79, '*')
return '\n' + starred if title else starred
try:
import numpy
except ImportError:
print(banner(' Caution '), 'NumPy header directory cannot be determined'
' ("import numpy" failed).', banner(), sep='\n', file=sys.stderr)
include_dirs = []
else:
include_dirs = [numpy.get_include()]
......@@ -98,10 +105,6 @@ if use_cython:
distr_root = os.path.dirname(os.path.abspath(__file__))
def banner(title=''):
starred = title.center(79, '*')
return '\n' + starred if title else starred
error_msg = """{header}
The compilation of Kwant has failed. Please examine the error message
above and consult the installation instructions in README.rst.
......@@ -115,7 +118,7 @@ Build configuration was:
error_msg = error_msg.format(header=banner(' Error '), sep=banner())
class kwant_build_ext(build_ext):
class build_ext(build_ext_orig):
def run(self):
if not config_file_present:
# Create an empty config file if none is present so that the
......@@ -126,7 +129,7 @@ class kwant_build_ext(build_ext):
f.write('# Created by setup.py - feel free to modify.\n')
try:
build_ext.run(self)
build_ext_orig.run(self)
except (DistutilsError, CCompilerError):
print(error_msg.format(file=CONFIG_FILE, summary=build_summary),
file=sys.stderr)
......@@ -136,7 +139,7 @@ class kwant_build_ext(build_ext):
print(banner())
class kwant_build_tut(Command):
class build_tut(Command):
description = "build the tutorial scripts"
user_options = []
......@@ -162,11 +165,11 @@ class kwant_build_tut(Command):
# Even though the tutorial is not necessary for installation, and "build" is
# supposed to make everything needed to install, this is a robust way to ensure
# that the tutorial is present.
class kwant_build(build):
sub_commands = [('build_tut', None)] + build.sub_commands
class build(build_orig):
sub_commands = [('build_tut', None)] + build_orig.sub_commands
def run(self):
build.run(self)
build_orig.run(self)
write_version(os.path.join(self.build_lib, *STATIC_VERSION_PATH))
......@@ -189,8 +192,8 @@ def git_lsfiles():
# distribution in the current state actually builds. It also makes sure that
# the Cython-made C files and the tutorial will be included in the source
# distribution and that they will be up-to-date.
class kwant_sdist(sdist):
sub_commands = [('build', None)] + sdist.sub_commands
class sdist(sdist_orig):
sub_commands = [('build', None)] + sdist_orig.sub_commands
def run(self):
"""
......@@ -222,7 +225,7 @@ class kwant_sdist(sdist):
f.write(''.join([' ', a, sep, stem, dot, 'c']))
f.write('\n')
sdist.run(self)
sdist_orig.run(self)
if names is None:
print(banner(' Caution '),
......@@ -231,10 +234,23 @@ source distribution. The old {} was used.""".format(MANIFEST_IN_FILE),
banner(), sep='\n', file=sys.stderr)
def make_release_tree(self, base_dir, files):
sdist.make_release_tree(self, base_dir, files)
sdist_orig.make_release_tree(self, base_dir, files)
write_version(os.path.join(base_dir, *STATIC_VERSION_PATH))
# The only purpose of this class is to provide a better error message when
# "nose" is not available.
class test(test_orig):
def run(self):
try:
import nose
except ImportError:
print('The Python package "nose" is required to run tests.',
file=sys.stderr)
exit(1)
test_orig.run(self)
def write_version(fname):
# This could be a hard link, so try to delete it first. Is there any way
# to do this atomically together with opening?
......@@ -468,20 +484,21 @@ def main():
author='C. W. Groth (CEA), M. Wimmer, '
'A. R. Akhmerov, X. Waintal (CEA), and others',
author_email='authors@kwant-project.org',
description="Package for numerical quantum transport calculations.",
description=("Package for numerical quantum transport calculations "
"(Python 3 version)"),
long_description=long_description(),
platforms=["Unix", "Linux", "Mac OS-X", "Windows"],
url="http://kwant-project.org/",
license="BSD",
packages=find_packages('.'),
test_suite = 'nose.collector',
cmdclass={'build': kwant_build,
'sdist': kwant_sdist,
'build_ext': kwant_build_ext,
'build_tut': kwant_build_tut},
cmdclass={'build': build,
'sdist': sdist,
'build_ext': build_ext,
'build_tut': build_tut,
'test': test},
ext_modules=ext_modules(extensions()),
include_dirs=include_dirs,
setup_requires=['numpy > 1.6.1', 'nose >= 1.0'],
install_requires=['numpy > 1.6.1', 'scipy >= 0.9', 'tinyarray'],
extras_require={'plotting': 'matplotlib >= 1.2'},
classifiers=[c.strip() for c in CLASSIFIERS.split('\n')])
......