on github (download).

"""Examples using segment boundary conditions

This code shows the general structure of DMRG with segment boundary conditions, which allows
to find topologically non-trivial excitations on a "finite" segment between two different
degenerate ground states.

For production, you should probalby use the
:class:`~tenpy.simulations.GroundStateSearch.OrthogonalExcitations` class,
but this example might be helpful to see the general idea.
# Copyright 2022 TeNPy Developers, GNU GPLv3

import numpy as np

from tenpy.models.tf_ising import TFIChain
from tenpy.networks.mps import MPS
from tenpy.algorithms import dmrg
import matplotlib.pyplot as plt
from import Config

import tenpy.linalg.np_conserved as npc

def calc_infinite_groundstates(dmrg_params, g=0.1):
    L = 2
    model_params = dict(L=L, J=1., g=g, bc_MPS='infinite', conserve=None, verbose=0)

    model = TFIChain(model_params)
    plus_x = np.array([1., 1.]) / np.sqrt(2)
    minus_x = np.array([1., -1.]) / np.sqrt(2)
    psi_plus = MPS.from_product_state(, [plus_x] * L,
    psi_minus = MPS.from_product_state(, [minus_x] * L,

    engine_plus = dmrg.TwoSiteDMRGEngine(psi_plus, model, dmrg_params)
    print("<Sx> =", psi_plus.expectation_value("Sigmax"))
    engine_minus = dmrg.TwoSiteDMRGEngine(psi_minus, model, dmrg_params)
    print("<Sx> =", psi_minus.expectation_value("Sigmax"))

    data_plus = {'psi': psi_plus}
    data_minus = {'psi': psi_minus}

    return model, data_plus, data_minus

def prepare_segment(model, data_L, data_R, repeat_L=20, repeat_R=20):

    psi_L = data_L['psi'].copy()
    psi_R = data_R['psi'].copy()
    psi_L.bc = "segment"
    psi_R.bc = "segment"

    model.enlarge_mps_unit_cell(repeat_L + repeat_R) = "segment"
    model.H_MPO.bc = "segment"

    init_env_data = {
        'init_LP': data_L['init_LP'],
        'age_LP': data_L['age_LP'],
        'init_RP': data_R['init_RP'],
        'age_RP': data_R['age_RP'],
    Bs_L = [psi_L.get_B(i) for i in range(psi_L.L)]
    Bs_R = [psi_R.get_B(i) for i in range(psi_R.L)]

    joint = npc.Array.from_func(np.ones,
                                [Bs_L[-1].get_leg('vR').conj(), Bs_R[0].get_leg('vL').conj()],
                                labels=['vL', 'vR'])
    Bs_L[-1] = npc.tensordot(Bs_L[-1], joint, axes=['vR', 'vL'])
    S = psi_L._S[:-1] + psi_R._S

    psi = MPS(psi_L.sites + psi_R.sites, Bs_L + Bs_R, S, 'segment')
    # UL, UR = psi.canonical_form_finite()

    return psi, model, init_env_data

def calc_segment_groundstate(psi, model, dmrg_params):
    engine = dmrg.TwoSiteDMRGEngine(psi, model, dmrg_params)
    E, psi =
    return psi

def plot(psi, filename):
    x = np.arange(psi.L)
    meas = psi.expectation_value("Sigmax")
    fig = plt.figure()
    ax = plt.gca()
    ax.plot(x, meas)
    print("saved to " + filename)

if __name__ == "__main__":
    dmrg_params = Config(
            'trunc_params': {
                'chi_max': 50,
                'svd_min': 1.e-10,
                'trunc_cut': None
            'update_env': 0,
            'start_env': 2,
            'max_E_err': 1.e-6,
            'max_S_err': 1.e-5,
            'max_sweeps': 100,
            'verbose': 1,
            'mixer': False
        }, "DMRG")

    model, psi_plus, psi_minus = calc_infinite_groundstates(dmrg_params)
    psi, model, init_env_data = prepare_segment(model, psi_plus, psi_minus)
    dmrg_params['init_env_data'] = init_env_data
    results = calc_segment_groundstate(psi, model, dmrg_params)
    plot(results, 'tfi_segment.pdf')