Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/macis/model/hubbard.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <macis/types.hpp>

namespace macis {

/**
* @brief Generate Hamiltonian Data for 1D Hubbard
*/
void hubbard_1d(size_t nsites, double t, double U, std::vector<double>& T,
std::vector<double>& V);

}
1 change: 1 addition & 0 deletions src/macis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_library( macis
orbital_rotation_utilities.cxx
orbital_hessian.cxx
orbital_steps.cxx
model/hubbard.cxx
)

target_include_directories( macis PUBLIC
Expand Down
29 changes: 29 additions & 0 deletions src/macis/model/hubbard.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <macis/model/hubbard.hpp>

namespace macis {

void hubbard_1d(size_t nsites, double t, double U, std::vector<double>& T,
std::vector<double>& V) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For model Hamiltonians like this one, it will make sense to add a new HamiltonianGenerator class that implements the single/double search instead of the double loop (Incidentally, it could make sense to add it to this branch. I could take charge of that, since I've already implemented something in these lines). This is especially true since many of the model systems have an extremely sparse V tensor, which makes this type of Hamiltonian build very efficient. To this end, we could consider the option of having these "integral building functions" return a vector listing the orbitals which have a non-sparse V sub-tensor. In the example of the Hubbard model, this will always be empty, since V is completely diagonal, and hence does not generate any double (or single) excitations. For an impurity model, this would be just the impurity.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, If you can mock something up and push to this branch, that would be helpful. We can iterate on the design once something is in place.

Re Sparse vs dense storage, that's a good point. I'm hesitant to do this ad hoc though, if we're going to support sparse integrals, we should build up proper sparse tensor infrastructure (sparsexx can already cover the Matrix case, we would just need to generalize the CSR/CSV/COO to tensors which is relatively straight forward). However, even for some the largest cases that folks can do ED on for these types of problems (26-28 sites), integral storage is trivial compared to the CI vectors, so this kind of optimization may be premature. But I can definitely see the desire to have this in general, so we should figure out how to do it properly - I would say we should punt on that for a bit and maybe open an issue so we don't forget to cover it eventually.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll put what I have and push it in.

I didn't mean using a sparse tensor for the V's, I agree that's a bit premature (though useful at some point). I was thinking of storing the dense V, full of zeros, but having the HamiltonianGenerator instance only look for doubles/singles among a subset of orbitals. For example, in the Hubbard model, you want to tell it to look for singles everywhere, but for doubles nowhere (there are no doubles, at least in real space). This will dramatically reduce the cost of the Hamiltonian build. For impurity models, you want to look for singles everywhere, and for doubles only among the impurity orbitals (since the bath is non-interacting by construction, at least in DMFT). Since the impurity is typically much smaller than the bath, this again is an important speed-up.



T.resize(nsites * nsites);
V.resize(nsites * nsites * nsites * nsites);


for(size_t p = 0; p < nsites; ++p) {
// Half-filling Chemical Potential
T[p * (nsites+1)] = -U/2;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be worth making the chemical potential an argument with default value? I could imagine people wanting to shift it, even if it's a finite 1d-chain.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was something I wasn't sure on, glad to know it's a flexible parameter. Is there a general form for this Hamiltonian that we could document so we can be precise in what we're supposed to be doing here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A common form for the interaction in the particle-hole symmetric case is:

U/2 \sum_i (n_i - 1)^2

Where n_i is the full particle number operator in site i, adding spin up and down. This automatically adds the chemical potential term of -U/2, and also a constant energy term of U/2 which of course does not affect the physics. So, a meaningful option would be to accept the chemical potential deviation away from half-filling as input, in other words a \mu such that the full Hamiltonian is

[hopping] + U/2 \sum_i (n_i - 1)^2 + mu \sum_i n_i

What do you think?


// On-Site Interaction
V[p * (nsites*nsites*nsites + nsites*nsites + nsites + 1)] = U;

// Hopping
if(p < nsites-1) {
T[p + (p+1)*nsites] = -t;
T[(p+1) + p*nsites] = -t;
}
}

}

}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_executable( macis_test
mcscf.cxx
asci.cxx
dist_quickselect.cxx
hubbard.cxx
)
target_link_libraries( macis_test PUBLIC macis Catch2::Catch2 )
target_include_directories( macis_test PUBLIC ${PROJECT_BINARY_DIR}/tests )
Expand Down
48 changes: 48 additions & 0 deletions tests/hubbard.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@


#include <iostream>
#include <spdlog/sinks/null_sink.h>
#include <spdlog/spdlog.h>

#include <macis/model/hubbard.hpp>

#include "ut_common.hpp"

TEST_CASE("Hubbard") {
ROOT_ONLY(MPI_COMM_WORLD);

const size_t nsites = 4;
const size_t nsites2 = nsites*nsites;
const size_t nsites3 = nsites2*nsites;
const double t = 1.0, U = 4.0;
std::vector<double> T,V;

SECTION("1D") {
macis::hubbard_1d( nsites, t, U, T, V );

// Check two-body term
for(int p = 0; p < nsites; ++p)
for(int q = 0; q < nsites; ++q)
for(int r = 0; r < nsites; ++r)
for(int s = 0; s < nsites; ++s) {
const auto mat_el = V[p + nsites*q + nsites2*r + nsites3*s];
if(p==q and p==r and p==s)
REQUIRE(mat_el == U);
else
REQUIRE(mat_el == 0.0);
}

// Check 1-body term
for(int p = 0; p < nsites; ++p)
for(int q = 0; q < nsites; ++q) {
const auto mat_el = T[p + q*nsites];
if(p == q)
REQUIRE(mat_el == Approx(-U/2));
else if( std::abs(p-q) == 1 )
REQUIRE(mat_el == -t);
else
REQUIRE(mat_el == 0.0);
}
}

}