Can not converge to a homogeneous groundstate of topological SSH model with DMRG

Hello everyone!

I want to use DMRG to get the groundstate of topological SSH model.
It’s Hamilitonian has been posted below.

\hat{H}_{SSH}=-j_1\sum_{i=odd}(\hat{a}^{\dagger}_i\hat{a}_{i+1}+H.c.)-j_2\sum_{i=even}(\hat{a}^{\dagger}_i\hat{a}_{i+1}+H.c.)

For the case that j_1>j_2, the system is topologically trivial; for the case that j_1<j_2, it is topological.

It’s groundstate density distribution should be homogeneous for both trivial and non-trivial case.

In my tests, the density of topological case can not converge to be homogeneous and have large difference between the left egde and right edge (with open condition) even after many sweeps. The
trivial case is homogeneous after several sweeps.

Here is the density after after 10 sweeps when the length of sites is 12, j1=0.2, j2=1 and inital state is “1010…”,

After 20 sweeps, it converge to a almost homogenous state.

It seems like much sweeps brings better results.
But when the length of sites goes up to 24, even after 100 sweeps, its density is still not homogenous.
This situation also occurs in other initial states like “0101”, “1001”

So did DMRG stuck in a locally optimal solution?
Here is my code and other parameters.

using ITensors
using Parsers
let
    L=Parsers.parse(Int,ARGS[1])
    t1=Parsers.parse(Float64,ARGS[2])
    ratio=Parsers.parse(Float64,ARGS[3])
    filling=ARGS[4]
    dimerization=Parsers.parse(Int,ARGS[5])
    condition=ARGS[6]
    additional=Parsers.parse(Int,ARGS[7])

    t2=t1*ratio
    @show t1

    sites=siteinds("Fermion",L;conserve_qns=true)

    state=[]
    if  filling=="1010"
        for n=1:L
            if isodd(n)
                push!(state,"1")
            elseif iseven(n)
                push!(state,"0")
            end
        end
        if additional==1
            state[Int(L/2)]="1"
        end
        if additional==-1
            state[Int(L/2-1)]="0"
        end
        @show state
    elseif filling=="0101"
        for n=1:L
            if isodd(n)
                push!(state,"0")
            elseif iseven(n)
                push!(state,"1")
            end
        end
        if additional==1
            state[Int(L/2-1)]="1"
        end
        if additional==-1
            state[Int(L/2)]="0"
        end
        @show state
    elseif filling=="1001"
        for n=1:L/2
            if isodd(n)
                push!(state,"1")
            elseif iseven(n)
                push!(state,"0")
            end
        end
        for n=L/2+1:L
            if isodd(n)
                push!(state,"0")
            elseif iseven(n)
                push!(state,"1")
            end
        end
        if additional==1
            state[Int(L/2)]="1"
        end
        if additional==-1
            state[Int(L/2-1)]="0"
        end
        @show state
    elseif filling=="0110"
        for n=1:L/2
            if isodd(n)
                push!(state,"0")
            elseif iseven(n)
                push!(state,"1")
            end
        end
        for n=L/2+1:L
            if isodd(n)
                push!(state,"1")
            elseif iseven(n)
                push!(state,"0")
            end
        end
        if additional==1
            state[Int(L/2-1)]="1"
        end
        if additional==-1
            state[Int(L/2)]="0"
        end
        @show state
    elseif filling=="1100"
        for n=1:L/2
            push!(state,"1")
        end
        for n=L/2+1:L
            push!(state,"0")
        end
        if additional==1
            state[Int(L/2+1)]="1"
        end
        if additional==-1
            state[Int(L/2)]="0"
        end
        @show state
    end
   
    psi0=MPS(sites,state)
    @show flux(psi0)
    
    if dimerization==1
        j1=t1
        j2=t2
    elseif dimerization==2
        j1=t2
        j2=t1
    end

    ampo=OpSum()
    for i=1:L-1
        if isodd(i)
            ampo += -j1,"Cdag",i+1,"C",i
            ampo += -j1,"Cdag",i,"C",i+1
        elseif iseven(i)
            ampo += -j2,"Cdag",i+1,"C",i
            ampo += -j2,"Cdag",i,"C",i+1
        end
    end
    if condition=="periodic"
        ampo += -j2,"Cdag",1,"C",L
        ampo += -j2,"Cdag",L,"C",1
    elseif condition=="open"
    end
    H=MPO(ampo,sites)
    # @show H

    sweep=Sweeps(10)
    setmaxdim!(sweep,120,250,400,600,800,1200,2000,2400,2600,3000)
    setcutoff!(sweep,1e-8,1e-9,1e-9,1e-10,1e-11,1e-12,1e-14,1e-14,1e-14)

    energy,psi=dmrg(H,psi0,sweep)

    density=expect(psi,"N")
    @show density

    total=0
    for i in eachindex(density)
        total += density[i]
    end
    @show total
    return
end

1 Like

Hi, our FAQ on “Ensuring a DMRG Calculation is Converged” may be helpful here.

In particular, I’d recommending turning on the “noise term” i.e. setting a non-zero value of the noise parameter for DMRG, such as:

setnoise!(sweep,1E-8)

Also I would recommend making plots of the density (especially at different stages of the DMRG calculation if you want to get fancy with it) to visually see what it looks like and how imbalanced it is or not. Good luck!

Thank you very much for offering your advice. I have tried to add noise terms in my codes, but unfortunately they did not work out as expected.

sweeps = Sweeps(sweep_times)
    maxdim!(sweeps,10,20,100,100,200,400,800,1000,1500,2000)
    cutoff!(sweeps,1E-8,1E-8,1E-10,1E-10,1E-12,1E-12,1E-13,1E-14,1E-14,1E-14)
    setnoise!(sweeps,1E-6,1E-6,1E-8,1E-8,1E-10,1E-12,1E-14,1E-14,0,0)

After 100 or 200 sweeps, it still doesn’t converge to a homogeneous state.
density_100
density_200

And I have tried different initial states, unfortunately it doesn’t get better.
Here are the results of “0101…1010” inital state in a system with 24 sites.
density_40_0110
density_100_0110

Looking forward to your response!

Are you sure the system should be perfectly uniform when using open boundaries? It does look quite uniform in the bulk (far from the boundaries), then one would generally expect there to be edge effects such that the density and other local properties deviate from the bulk near the edges.

Also it’s quite important here to note that the SSH model and other topological models can host non-trivial edge states which might be what you are seeing depending on your choice of parameters.

I have checked the density distributions in small size systems which are uniform. Open boundary condition could certainly affect the particles on the edge, but not so extremely like the graphs show. I also use DMRG function in ITensorTDVP.jl to check the results, but the same problems occur.

When the length of the chain is 14, its density is perfectly uniform after 100 sweeps.
tdvp_14_100

But by enlarging the length to just 16, the density is no more uniform.
tdvp_16_200
The converge parameters of ITensorTDVP.dmrg() I use to get the groundstate is below.

 nsite = 2
 nsweeps = sweep_times
  maxdim = [400,400,400,600,800,1200,2000,2400,2600,3000]
  cutoff = [1e-10,1e-10,1e-12,1e-12,1e-12,1e-12,1e-14,1e-14,1e-14,1e-14]
  # noise = [1e-8,1e-8,1e-10,1e-12,1e-12,1e-14,1e-14,0,0,0]
  order=2
  # energy,psi=dmrg(H,psi0,sweep)
  psi = ITensorTDVP.dmrg(H, psi0;reverse_step=false,nsweeps,maxdim,cutoff,nsite,order)
 # psi = ITensorTDVP.dmrg(H, psi0;reverse_step=false,nsweeps,maxdim,cutoff,noise,nsite,order)
  density=expect(psi,"N")
  @show density

Also, why can not I set the noise terms for ITensorTDVP.dmrg()?
The error information shows that ITensorTDVP.dmrg() has a candidate named “noise”.

ERROR: LoadError: UndefVarError: phi not defined
Stacktrace:
  [1] tdvp_site_update!(nsite_val::Val{2}, reverse_step_val::Val{false}, solver::ITensorTDVP.var"#solver#46"{ITensorTDVP.var"#solver#45#47"{Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order), Tuple{Bool, Int64, Vector{Int64}, Vector{Float64}, Vector{Float64}, Int64, Int64}}}}}, PH::ProjMPO, psi::MPS, b::Int64; current_time::Float64, outputlevel::Int64, time_step::Float64, normalize::Bool, direction::Base.Order.ForwardOrdering, noise::Float64, which_decomp::Nothing, svd_alg::String, cutoff::Float64, maxdim::Int64, mindim::Int64, maxtruncerr::Float64)
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_step.jl:311
  [2] tdvp_site_update!(solver::ITensorTDVP.var"#solver#46"{ITensorTDVP.var"#solver#45#47"{Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order), Tuple{Bool, Int64, Vector{Int64}, Vector{Float64}, Vector{Float64}, Int64, Int64}}}}}, PH::ProjMPO, psi::MPS, b::Int64; nsite::Int64, reverse_step::Bool, current_time::Float64, outputlevel::Int64, time_step::Float64, normalize::Bool, direction::Base.Order.ForwardOrdering, noise::Float64, which_decomp::Nothing, svd_alg::String, cutoff::Float64, maxdim::Int64, mindim::Int64, maxtruncerr::Float64)
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_step.jl:157
  [3] tdvp_sweep(direction::Base.Order.ForwardOrdering, solver::Function, PH::ProjMPO, time_step::Float64, psi::MPS; kwargs::Base.Pairs{Symbol, Real, NTuple{10, Symbol}, NamedTuple{(:current_time, :reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order, :sweep, :mindim), Tuple{Float64, Bool, Int64, Int64, Float64, Float64, Int64, Int64, Int64, Int64}}})
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_step.jl:80
  [4] tdvp_step(order::ITensorTDVP.TDVPOrder{2, Base.Order.ForwardOrdering()}, solver::Function, PH::ProjMPO, time_step::Float64, psi::MPS; current_time::Float64, kwargs::Base.Pairs{Symbol, Real, NTuple{9, Symbol}, NamedTuple{(:reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order, :sweep, :mindim), Tuple{Bool, Int64, Int64, Float64, Float64, Int64, Int64, Int64, Int64}}})
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_step.jl:9
  [5] macro expansion
    @ C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_generic.jl:84 [inlined]
  [6] macro expansion
    @ .\timing.jl:382 [inlined]
  [7] tdvp(solver::Function, PH::ProjMPO, t::Float64, psi0::MPS; kwargs::Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order), Tuple{Bool, Int64, Vector{Int64}, Vector{Float64}, Vector{Float64}, Int64, Int64}}})
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_generic.jl:83
  [8] tdvp(solver::Function, H::MPO, t::Float64, psi0::MPS; kwargs::Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:reverse_step, :nsweeps, :maxdim, :cutoff, :noise, :nsite, :order), Tuple{Bool, Int64, Vector{Int64}, Vector{Float64}, Vector{Float64}, Int64, Int64}}})
    @ ITensorTDVP C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\tdvp_generic.jl:150
  [9] #dmrg#48
    @ C:\Users\Wang\.julia\packages\ITensorTDVP\xjpcf\src\dmrg.jl:22 [inlined]
 [10] top-level scope
    @ F:\data\superlattice\julia_example\SSHmodel\SSH.jl:169

Looks like a bug which would be simple to fix, just changing phi to phi1 on this line:

Could you raise an issue at Issues · ITensor/ITensorTDVP.jl · GitHub with a minimal code that reproduces that error?

Regarding your results, I’m confident that DMRG is working correctly for you. Your DMRG parameters are chosen well.

Most likely what’s happening is analogous to the S=1 Heisenberg chain, which also has degenerate edge states. For that system, on small system sizes the edge states are able to mix and lower the energy by a very tiny amount, an amount which becomes exponentially small with system size. For larger systems this tiny mixing becomes so small that normal DMRG calculations can’t resolve it (e.g. imagine it gets so small it falls below the precision of double floating point numbers), so the edge states no longer mix. One can debate whether the results with the edge states mixed (flat density) are “more physical” or the unmixed ones are more physical, but really the best way to understand the system is to study the multiple ground states and understand that the ground state manifold is degenerate and then just include this in your analysis of the system. I’m not 100% sure that’s what is going on here, but I hope you see my larger point about needing to handle edge states carefully and how smaller systems can behave differently from larger ones.

1 Like