Source code for qtealeaves.modeling.plaquetteterm2d

# This code is part of qtealeaves.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Plaquette (4-body) interactions in a two-dimensional system.
"""
import numpy as np

from qtealeaves.tooling import QTeaLeavesError, map_selector

from .baseterm import _ModelTerm

__all__ = ["PlaquetteTerm2D"]


[docs] class PlaquetteTerm2D(_ModelTerm): """ The plaquette term is applied to 2x2 nearest-neighbor sites in a 2d model. If symmetries are used, none of the operators is allowed to change a symmetry sector (block diagonal). **Arguments** operators : list of two strings String identifier for the operators. Before launching the simulation, the python API will check that the operator is defined. strength : str, callable, numeric (optional) Defines the coupling strength of the local terms. It can be parameterized via a value in the dictionary for the simulation or a function. Default to 1. prefactor : numeric, scalar (optional) Scalar prefactor, e.g., in order to take into account signs etc. Default to 1. has_obc : bool or list of bools, optional Defines the boundary condition along each spatial dimension. If scalar is given, the boundary condition along each spatial dimension is assumed to be equal. Default to True If [False, True], the topology is a strip on the x axis If [True, False], the topology is a strip on the y axis If [False,False], the topology is a thorus mask : callable or ``None``, optional The true-false-mask allows to apply the Hamiltonians terms only to specific plaquettes, i.e., with true values. The function takes the dictionary with the simulation parameters as an argument. The mask is applied to the site where the lower-left corner of the plaquette operator is acting on. Default to ``None`` (all sites have the interaction) The order of the operators is for the shifts (0,0), (0,1), (1,0), (1,1) """ # pylint: disable-next=too-many-arguments def __init__(self, operators, strength=1, prefactor=1, has_obc=True, mask=None): super().__init__() self.operators = operators self.strength = strength self.prefactor = prefactor self.mask = mask # Will be set when adding Hamiltonian terms self.map_type = None if isinstance(has_obc, bool): self.has_obc = [has_obc] * 2 else: self.has_obc = has_obc
[docs] @staticmethod def check_dim(dim): """ Only available in 2d systems. """ if dim != 2: raise QTeaLeavesError("Dimension does not match.")
[docs] def collect_operators(self): """ All the required operators are returned to ensure that they are written by fortran. """ yield self.operators[0], None yield self.operators[1], None yield self.operators[2], None yield self.operators[3], None
# pylint: disable-next=too-many-locals
[docs] def get_interactions(self, ll, params, **kwargs): """ Description of interactions close to the TPO formulation. It works for both Periodic and Open Boundary conditions, depending on the argument has_obc. NOTE the order of the operators is (x2,y2) ---- (x4,y4) | | | | (x1,y1) ---- (x3,y3) **Arguments** ll : list of ints Number of sites along the dimensions, i.e., not the total number of sites. Assuming list of sites along all dimension. params : dictionary Contains the simulation parameters. """ map_to_1d = map_selector(2, ll, self.map_type) if self.mask is None: local_mask = np.ones(ll, dtype=bool) else: local_mask = self.mask(params) elem = {"operators": self.operators} for x1 in range(ll[0]): for y1 in range(ll[1]): if x1 < ll[0] - 1: x2 = x1 x3 = x1 + 1 x4 = x1 + 1 else: if not self.has_obc[0]: # Periodic boundary conditions on x. # The right part of the plaquette is on the left side of the lattice, # i.e. x3=x4=0 x2 = x1 x3 = 0 x4 = 0 else: continue if y1 < ll[1] - 1: y2 = y1 + 1 y3 = y1 y4 = y1 + 1 else: if not self.has_obc[1]: # Periodic boundary conditions on y. # The upper part of the plaquette is on the lower side of the lattice, # i.e. y2=y4=0 y2 = 0 y3 = y1 y4 = 0 else: continue if not local_mask[x1, y1]: continue coords_1d = [ map_to_1d[elem] for elem in [(x1, y1), (x2, y2), (x3, y3), (x4, y4)] ] yield elem, coords_1d
[docs] def get_fortran_str(self, ll, params, operator_map, param_map): """ Get the string representation needed to write a Fortran input file. """ str_repr = "" param_repr = self.get_param_repr(param_map) op_str = [operator_map[(elem, None)] for elem in self.operators] counter = 0 for _, coords in self.get_interactions(ll, params): counter += 1 if coords[0] == coords[1]: raise QTeaLeavesError("Same site ...") if coords[0] == coords[2]: raise QTeaLeavesError("Same site ...") if coords[0] == coords[3]: raise QTeaLeavesError("Same site ...") if coords[1] == coords[2]: raise QTeaLeavesError("Same site ...") if coords[1] == coords[3]: raise QTeaLeavesError("Same site ...") if coords[2] == coords[3]: raise QTeaLeavesError("Same site ...") inds = np.argsort(np.array(coords)) for ii in range(4): str_repr += "%d %d\n" % (coords[inds[ii]] + 1, op_str[inds[ii]]) str_repr += param_repr + " %30.15E\n" % (self.prefactor) # Now we can write the information for the first lines (order is correct) str_repr = "%d\n" % (4) + str_repr str_repr = "%d\n" % (counter) + str_repr return str_repr