Commit c00e0496 authored by Joseph Weston's avatar Joseph Weston

Merge branch 'ham_gen_fix' into 'stable-1.2'

Fix inconsistency in sympy symbols in Models

See merge request !11
parents 977967a8 29468282
Pipeline #23934 passed with stage
in 2 minutes and 41 seconds
......@@ -7,7 +7,7 @@ from copy import deepcopy
import tinyarray as ta
from .linalg import matrix_basis, nullspace, sparse_basis, family_to_vectors, rref, allclose
from .model import Model, BlochModel, _commutative_momenta, e, I
from .model import Model, BlochModel, BlochCoeff, _commutative_momenta, e, I
from .groups import PointGroupElement, ContinuousGroupGenerator, generate_group
from . import kwant_continuum
......@@ -33,9 +33,9 @@ def continuum_hamiltonian(symmetries, dim, total_power, all_powers=None,
Allowed powers of the momentum variables in the continuum Hamiltonian listed
for each spatial direction. If an integer is given, all powers below it are
included as well. If a list of integers is given, only these powers are used.
momenta : list of int or list of Sympy objects
Indices of momenta from ['k_x', 'k_y', 'k_z'] or a list of names for the
momentum variables. Default is ['k_x', 'k_y', 'k_z'].
momenta : iterable of strings or Sympy symbols
Names of momentum variables, default ``['k_x', 'k_y', 'k_z']`` or
corresponding sympy symbols.
sparse_linalg : bool
Whether to use sparse linear algebra. Using sparse solver can result in
performance increase for large, highly constrained families,
......@@ -285,7 +285,7 @@ def hamiltonian_from_family(family, coeffs=None, nsimplify=True, tosympy=True):
"""
if coeffs is None:
coeffs = list(sympy.symbols('c0:%d'%len(family), real=True))
coeffs = list(sympy.symbols('c0:%d'%len(family)))
else:
assert len(coeffs) == len(family), 'Length of family and coeffs do not match.'
# The order of multiplication is important here, so that __mul__ of 'term'
......@@ -571,6 +571,7 @@ def symmetrize_monomial(monomial, symmetries):
def bloch_family(hopping_vectors, symmetries, norbs, onsites=True,
momenta=_commutative_momenta,
symmetrize=True, prettify=True, num_digits=10,
bloch_model=False):
"""Generate a family of symmetric Bloch-Hamiltonians.
......@@ -589,9 +590,12 @@ def bloch_family(hopping_vectors, symmetries, norbs, onsites=True,
norbs : OrderedDict : {site : norbs_site} or tuple of tuples ((site, norbs_site), )
sites are ordered in the order specified, with blocks of size norbs_site
corresponding to each site.
onsites : bool
onsites : bool, default True
Whether to include on-site terms consistent with the symmetry.
symmetrize : bool
momenta : iterable of strings or Sympy symbols
Names of momentum variables, default ``['k_x', 'k_y', 'k_z']`` or
corresponding sympy symbols.
symmetrize : bool, default True
Whether to use the symmetrization strategy. This does not require
a full set of hoppings to start, all symmetry related hoppings
are generated. Otherwise the constraining strategy is used, this does
......@@ -670,16 +674,22 @@ def bloch_family(hopping_vectors, symmetries, norbs, onsites=True,
n, m = norbs[a], norbs[b]
block_basis = np.eye(n*m, n*m).reshape((n*m, n, m))
block_basis = np.concatenate((block_basis, 1j*block_basis))
# Hopping direction in real space
# Dot product with momentum vector
phase = sum([coordinate * momentum for coordinate, momentum in
zip(vec, _commutative_momenta[:dim])])
factor = e**(I*phase)
if bloch_model:
bloch_coeff = BlochCoeff(np.array(vec), sympy.sympify(1))
else:
# Hopping direction in real space
# Dot product with momentum vector
phase = sum([coordinate * momentum for coordinate, momentum in
zip(vec, momenta[:dim])])
factor = e**(I*phase)
hopfamily = []
for mat in block_basis:
matrix = np.zeros((N, N), dtype=complex)
matrix[ranges[a], ranges[b]] = mat
term = Model({factor: matrix}, momenta=('k_x', 'k_y', 'k_z')[:dim])
if bloch_model:
term = BlochModel({bloch_coeff: matrix}, momenta=momenta[:dim])
else:
term = Model({factor: matrix}, momenta=momenta[:dim])
term = term + term.T().conj()
hopfamily.append(term)
# If there are conserved quantities, constrain the hopping, it is assumed that
......@@ -687,10 +697,6 @@ def bloch_family(hopping_vectors, symmetries, norbs, onsites=True,
if conserved:
hopfamily = constrain_family(conserved, hopfamily)
family.extend(hopfamily)
# Use BlochModel objects instead of Model.
if bloch_model:
family = [BlochModel(member, momenta=member.momenta) for
member in family]
if symmetrize:
# Make sure that group is generated while keeping track of unitary part.
for g in pg:
......
......@@ -3,7 +3,7 @@ import scipy
import tinyarray as ta
import scipy.linalg as la
from itertools import product
from copy import copy, deepcopy
from copy import copy
from numbers import Number
from warnings import warn
from functools import lru_cache
......@@ -93,13 +93,14 @@ class BlochCoeff(tuple):
else:
raise NotImplementedError
def __deepcopy__(self, memo):
hop, coeff = self
return BlochCoeff(deepcopy(hop), deepcopy(coeff))
def __copy__(self):
return self.copy()
def copy(self):
hop, coeff = self
return BlochCoeff(copy(hop), copy(coeff))
# Do not copy 'coeff', as Sympy objects are immutable anyway,
# and making a copy breaks equality checking and hashing.
return BlochCoeff(copy(hop), coeff)
def tosympy(self, momenta, nsimplify=False):
hop, coeff = self
......@@ -241,7 +242,9 @@ class Model(UserDict):
# * splitting summands in keys
# * moving numerical factors to values
# * removing entries which values care np.allclose to zero
old_data = {copy(key): copy(val) for key, val in self.items()}
# Do not copy key, as Sympy objects are immutable anyway,
# and making a copy breaks equality checking and hashing.
old_data = {key: copy(val) for key, val in self.items()}
self.data = {}
for key, val in old_data.items():
for summand in key.expand().powsimp(combine='exp').as_ordered_terms():
......@@ -459,6 +462,9 @@ class Model(UserDict):
result.append('}')
return "".join(result)
def __copy__(self):
return self.copy()
def zeros_like(self):
"""Return an empty model object that inherits the other properties"""
result = type(self)(shape=self.shape,
......@@ -635,7 +641,9 @@ class Model(UserDict):
"""Return a copy."""
result = self.zeros_like()
# This is faster than deepcopy of the dict
result.data = {copy(k): copy(v) for k, v in self.items()}
# Do not copy the keys, as Sympy objects (and BlochCoeffs) are
# immutable anyway, and making a copy breaks equality checking and hashing.
result.data = {k: copy(v) for k, v in self.items()}
return result
def lambdify(self, nsimplify=False, *, onsite=False, hopping=False):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment