# Different boson number cutoffs for different sites

I have a system with two different types of degrees of freedom - one is high energy, and the other low energy. Therefore a good description for the low energy eigenstates of the system can probably be obtained by only keeping a few basis states for the high energy degrees of freedom, but keeping more states for the low energy degrees of freedom. I'm wondering how to implement such a thing? Here is my existing custom class. I'm envisioning having adim and edim, as opposed to just dim, and then constructing new operators based on those dimensions. Thanks!

namespace itensor {

class ExcitonSite;

using Exciton = BasicSiteSet<ExcitonSite>;

class ExcitonSite
{
IQIndex s;
int dim;
public:

ExcitonSite() { }

ExcitonSite(IQIndex I) : s(I) { }

ExcitonSite(int n, Args const& args = Args::global())
{
dim = args.getInt("on_site_dim", 5);
auto v = stdx::reserve_vector<IndexQN>(2 * dim + 1);
for (int j = -dim; j <= dim; ++j)
{
auto i = Index(std::to_string(j), 1, Site);
auto q = QN("Sz=", j);
v.emplace_back(i, q);
}
s = IQIndex(nameint("site=",n), std::move(v), Out, 0);
}

IQIndex
index() const { return s; }

IQIndexVal
state(std::string const& state)
{
int j = -dim;
while (j <= dim)
{
j++;
if (state == std::to_string(j))
{
return s(j + 1 + dim);
break;
}
}
if (j == dim+1)
{
Error("State " + state + " not recognized");
}
return IQIndexVal{};
}

IQTensor
op(std::string const& opname,
Args const& args) const
{
auto sP = prime(s);
auto Op = IQTensor(dag(s),sP);

if (opname == "n")
{
for (int j = -dim; j<= dim; ++j)
{
Op.set(s(j + 1 + dim), sP(j + 1 + dim), (float)j);
}
}
else
if (opname == "nsq")
{
for (int j = -dim; j<= dim; ++j)
{
Op.set(s(j + 1 + dim), sP(j + 1 + dim), (float)(j * j));
}
}
else
if (opname == "gp")
{
for (int j = -dim; j<= dim - 1; ++j)
{
Op.set(s(j + 1 + dim), sP(j + 2 + dim), +1.0);
}
}
else
if (opname == "igp")
{
for (int j = -dim; j<= dim-1; ++j)
{
Op.set(s(j + 1 + dim), sP(j + 2 + dim), +1.0_i);
}
}
else
if (opname == "gm")
{
for (int j = -dim + 1; j<= dim; ++j)
{
Op.set(s(j + 1 + dim), sP(j + dim), +1.0);
}
}
else
if (opname == "igm")
{
for (int j = -dim + 1; j<= dim; ++j)
{
Op.set(s(j + 1 + dim), sP(j + dim), +1.0_i);
}
}
else
{
Error("Operator \"" + opname + "\" name not recognized");
}

return Op;
}
};

} //namespace itensor

#endif

commented by (44.9k points)
Hi, would you be willing to write this code based on version 3.0 of ITensor? I think you'd find the design of site sets and QNs specifically much easier and nicer. It's one of the key things we improved over version 2.
commented by (350 points)
Gotcha - will look into that thank you.

+1 vote
selected by

Just to begin answering this question - it’s a good question.

Yes you can definitely create two different types of sites when making your own site set in ITensor. This is easier to do and works better in version 3 of ITensor.

Essentially all you have to do is to first follow the procedure for making each type of site separately, using classes like BosonSite as an example, but adjust the dimension of the site index and/or range of the quantum numbers to what you want.

Now that you have two different site classes, “AType” and “BType” say, you can make your site set as:
using MySiteSet = MixedSiteSet<AType,BType>;
which will make the odd-numbered sites be AType sites and the even-numbered sites BType sites.

See the sample/mixedspin.cc sample code for an example of this using in action.

Alternatively, if the AType and BType sites are similar enough in their design, you could have them be just the same type and control their properties through passing named arguments (Args) and looking at the site number when constructing them. But this could ultimately make things more complicated, since when getting operators you will also have to put in checks about what kind of site you are making operators for.

Which of the above two ways to go depends then on the details.

Good luck!

Miles

commented by (350 points)
This is very helpful, thank you Miles!