Program Listing for File lattice_model_instance.cpp¶
↰ Return to documentation for file (src_qcm/lattice_model_instance.cpp)
#include <iomanip>
#include <fstream>
#include "lattice_model_instance.hpp"
#include "integrate.hpp"
#include "parser.hpp"
#include "QCM.hpp"
#ifdef _OPENMP
#include <omp.h>
#endif
extern vector<double> grid_freqs; // optional imaginary frequency grid for discrete integrals
extern vector<double> grid_weights; // weights associated with grid_freqs
string strip_at(const string& s)
{
string name = s;
size_t pos1 = name.rfind('@');
size_t pos2 = name.rfind('_');
if(pos1 != string::npos){
int label = from_string<int>(name.substr(pos2+1));
name.erase(pos1);
name += '_' + to_string(label);
}
return name;
}
//==============================================================================
lattice_model_instance::lattice_model_instance(shared_ptr<lattice_model> _model, int _label)
: label(_label), model(_model), complex_HS(false)
{
vector<map<string,double>> sys_values(model->nsys);
gs_solved = false;
gf_solved = false;
average_solved = false;
SEF_solved = false;
PE_solved = false;
E_pot = 0.0;
E_kin = 0.0;
if(model->sector_strings.size() == 0) qcm_throw("target sectors were not specified!");
params = model->param_set->value_map();
model->close_model();
for(auto& [pname, value] : params){
string name = pname; // copy: name_and_label may modify its argument
auto P = model->name_and_label(name, true);
if(P.second){
if(value != 0.0 or P.first == "mu"){
sys_values[P.second-1][P.first] = value;
}
}
else model->term.at(name)->is_active = true;
}
for(size_t s=0; s<model->nsys; s++){
if(sys_values[s].size() == 0) qcm_throw("system "+to_string(s)+" has no nonzero operators");
ED::new_model_instance(model->systems[s].name, sys_values[s], model->sector_strings[s], label*model->nsys + s);
model->clusters[model->systems[s].clus].mixing = ED::mixing(label*model->nsys + s);
}
if(model->GF_offset.size() == 0) model->post_parameter_consolidate(label);
#ifdef QCM_DEBUG
cout << "lattice model instance " << label << " created" << endl;
#endif
}
lattice_model_instance::~lattice_model_instance()
{
#ifdef QCM_DEBUG
cout << "lattice model instance #" << label << " deleted." << endl;
#endif
}
//==============================================================================
vector<pair<double,string>> lattice_model_instance::ground_state()
{
if(gs_solved) return gs;
static bool first_time = true;
clus_ave.resize(model->nsys);
gs.resize(model->nsys);
GS_energy.resize(model->clusters.size()+1);
GS_energy[0] = 0.0;
first_time = false;
int sc=0;
// When nsys > 1, solve sub-systems in parallel. Inner OMP regions (Hamiltonian
// build, Q-matrix irrep loop) will serialize under nested parallelism, but the
// outer loop exposes more coarse-grained work than the inner loops typically do.
#pragma omp parallel for schedule(dynamic,1) if(model->nsys > 1)
for(size_t s = 0; s < model->systems.size(); s++){
gs[s] = ED::ground_state_solve(model->nsys*label + s);
clus_ave[s] = ED::cluster_averages(model->nsys*label + s);
#pragma omp atomic
GS_energy[model->systems[s].clus+1] += gs[s].first;
}
for(size_t c = 0; c<model->clusters.size(); c++) GS_energy[c+1] /= model->clusters[c].nsys;
for(size_t s = 0; s<model->nsys; s++){
if(ED::complex_HS(model->nsys*label + s)) complex_HS = true;
}
gs_solved = true;
return gs;
}
//==============================================================================
void lattice_model_instance::build_H()
{
H.set_size(model->dim_GF);
if(model->mixing == HS_mixing::up_down) H_down.set_size(model->dim_GF);
for(auto& x : model->term){
lattice_operator& op = *x.second;
if(auto it = params.find(op.name); it != params.end()){
double pv = it->second;
for(auto& e : op.GF_elem) H(e.r, e.c) += e.v*pv;
if(model->mixing == HS_mixing::up_down) for(auto& e : op.GF_elem_down) H_down(e.r, e.c) += e.v*pv;
}
}
// building the cluster one-body matrices
build_cluster_H();
gf_solved = true;
}
//==============================================================================
void lattice_model_instance::Green_function_solve()
{
static bool first_time = true;
if(gf_solved) return;
if(!gs_solved) ground_state();
#pragma omp parallel for schedule(dynamic,1) if(model->nsys > 1)
for(size_t s = 0; s<model->nsys; s++) ED::Green_function_solve(model->nsys*label+s);
build_H();
}
//==============================================================================
void lattice_model_instance::build_cluster_H()
{
size_t n_clus = model->clusters.size();
Hc.block.assign(n_clus, matrix<Complex>());
for(size_t c = 0; c<n_clus; c++){
Hc.block[c].assign(cluster_hopping_matrix(c, false));
}
Hc.set_size();
if(model->mixing == HS_mixing::up_down){
Hc_down.block.assign(n_clus, matrix<Complex>());
for(size_t c = 0; c<n_clus; c++){
Hc_down.block[c].assign(cluster_hopping_matrix(c, true));
}
Hc_down.set_size();
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::cluster_Green_function_remix(size_t c, complex<double> w, bool spin_down, bool blocks)
{
if(model->clusters[c].nsys == 1) return ED::Green_function(w, spin_down, model->nsys*label + model->clusters[c].sys_start, blocks);
else{
// g is sized from the first system's GF (cluster-mixing dim, which may be
// smaller than GF_dims[c] when the lattice has anomalous/spin-flip mixing
// beyond what the cluster itself carries — the upgrade to lattice mixing
// happens later in cluster_Green_function()).
matrix<Complex> g;
for(int s=0; s<model->clusters[c].nsys; s++){
// ATTENTION : ICI ON DEVRAIT MOYENNER AVEC DES POIDS QUI DÉPENDENT de K
auto gs = ED::Green_function(w, spin_down, model->nsys*label + s + model->clusters[c].sys_start, blocks);
gs.inverse();
if(s == 0) g.set_size(gs.r, gs.c);
g.v += gs.v;
}
g.v *= 1.0/model->clusters[c].nsys;
g.inverse();
return g;
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::cluster_Green_function(size_t c, complex<double> w, bool spin_down, bool blocks)
{
if(c >= model->clusters.size()) qcm_throw("cluster label out of range");
int cr = model->clusters[c].ref;
if(cr != c){
if(model->clusters[c].conj) w = conjugate(w);
matrix<Complex> G = cluster_Green_function(cr, w, spin_down, blocks);
if(model->clusters[c].conj) G.cconjugate();
return G;
}
if(!gf_solved) Green_function_solve();
matrix<Complex> g = cluster_Green_function_remix(c, w, spin_down, blocks);
matrix<Complex> G;
int mix = model->clusters[c].mixing;
if(model->mixing == mix) return g;
// combinaisons 0:2, 0:4, 1:3, 1:5
else if(((model->mixing&1) == 0 and (mix&1) == 0) or ((model->mixing&1)==1 and (mix&1)==1)) {
G = upgrade_cluster_matrix(model->mixing, mix, g);
}
// combinaisons 0:1, 0:3, 0:5, 2:3
else if((model->mixing&1) == 1 and (mix&1) == 0){
auto gm = cluster_Green_function_remix(c, -w, spin_down, blocks);
if(model->clusters[c].conj) gm.cconjugate();
G = upgrade_cluster_matrix_anomalous(model->mixing, mix, g, gm);
}
else{
qcm_throw("undefined mixing combinations in cluster_Green_function()");
}
return G;
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::cluster_self_energy_remix(size_t c, complex<double> w, bool spin_down)
{
if(model->clusters[c].nsys == 1) return ED::self_energy(w, spin_down, model->nsys*label + model->clusters[c].sys_start);
else{
// g is sized from the first system's self-energy (cluster-mixing dim).
matrix<Complex> g;
for(int s=0; s<model->clusters[c].nsys; s++){
// ATTENTION : ICI ON DEVRAIT MOYENNER AVEC DES POIDS QUI DÉPENDENT de K
auto gs = ED::self_energy(w, spin_down, model->nsys*label + s + model->clusters[c].sys_start);
if(s == 0) g.set_size(gs.r, gs.c);
g += gs;
}
g.v *= 1.0/model->clusters[c].nsys;
return g;
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::cluster_self_energy(size_t c, complex<double> w, bool spin_down)
{
int cr = model->clusters[c].ref;
if(cr != c){
if(model->clusters[c].conj) w = conjugate(w);
matrix<Complex> G = cluster_self_energy(cr, w, spin_down);
if(model->clusters[c].conj) G.cconjugate();
return G;
}
if(c >= model->clusters.size()) qcm_throw("cluster label out of range");
if(!gf_solved) Green_function_solve();
matrix<Complex> g = cluster_self_energy_remix(cr, w, spin_down);
int mix = model->clusters[c].mixing;
if(model->mixing == mix) return g;
// combinaisons 0:2, 0:4, 1:3, 1:5
else if(((model->mixing&1) == 0 and (mix&1) == 0) or ((model->mixing&1)==1 and (mix&1)==1)) {
return upgrade_cluster_matrix(model->mixing, mix, g);
}
// combinaisons 0:1, 0:3, 0:5, 2:3
else if((model->mixing&1) == 1 and (mix&1) == 0){
auto gm = cluster_self_energy_remix(c, -w, spin_down);
if(model->clusters[c].conj) gm.cconjugate();
return upgrade_cluster_matrix_anomalous(model->mixing, mix, g, gm);
}
else{
qcm_throw("undefined mixing combinations in cluster_self_energy()");
matrix<complex<double>> empty;
return empty;
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::hybridization_function_remix(size_t c, complex<double> w, bool spin_down)
{
if(model->clusters[c].nsys==1) return ED::hybridization_function(w, spin_down, model->nsys*label + model->clusters[c].sys_start);
else{
// g is sized from the first system's hybridization (cluster-mixing dim).
matrix<Complex> g;
for(int s=0; s<model->clusters[c].nsys; s++){
// ATTENTION : ICI ON DEVRAIT MOYENNER AVEC DES POIDS QUI DÉPENDENT de K
auto gs = ED::hybridization_function(w, spin_down, model->nsys*label + s + model->clusters[c].sys_start);
if(s == 0) g.set_size(gs.r, gs.c);
g += gs;
}
g.v *= 1.0/model->clusters[c].nsys;
return g;
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::hybridization_function(size_t c, complex<double> w, bool spin_down)
{
int cr = model->clusters[c].ref;
if(cr != c){
if(model->clusters[c].conj) w = conjugate(w);
matrix<Complex> G = hybridization_function(cr, w, spin_down);
if(model->clusters[c].conj) G.cconjugate();
return G;
}
if(c >= model->clusters.size()) qcm_throw("cluster label out of range");
matrix<Complex> g = hybridization_function_remix(c, w, spin_down);
int mix = model->clusters[c].mixing;
if(model->mixing == mix) return g;
// combinaisons 0:2, 0:4, 1:3, 1:5
else if(((model->mixing&1) == 0 and (mix&1) == 0) or ((model->mixing&1)==1 and (mix&1)==1)) {
return upgrade_cluster_matrix(model->mixing, mix, g);
}
// combinaisons 0:1, 0:3, 0:5, 2:3
else if((model->mixing&1) == 1 and (mix&1) == 0){
auto gm = hybridization_function_remix(c, -w, spin_down);
if(model->clusters[c].conj) gm.cconjugate();
return upgrade_cluster_matrix_anomalous(model->mixing, mix, g, gm);
}
else{
qcm_throw("undefined mixing combinations in hybridization_function()");
matrix<complex<double>> empty;
return empty;
}
}
//==============================================================================
matrix<complex<double>> lattice_model_instance::cluster_hopping_matrix(size_t c, bool spin_down)
{
int cr = model->clusters[c].ref;
if(cr != c){
matrix<Complex> G = cluster_hopping_matrix(cr, spin_down);
if(model->clusters[c].conj) G.cconjugate();
return G;
}
if(c >= model->clusters.size()) qcm_throw("cluster label out of range");
matrix<Complex> g = ED::hopping_matrix(spin_down, model->nsys*label+model->clusters[c].sys_start);
int mix = model->clusters[c].mixing;
if(model->mixing == mix) return g;
// combinations 0:2, 0:4, 1:3, 1:5
else if(((model->mixing&1) == 0 and (mix&1) == 0) or ((model->mixing&1)==1 and (mix&1)==1)) {
return upgrade_cluster_matrix(model->mixing, mix, g);
}
// combinations 0:1, 0:3, 0:5, 2:3
else if((model->mixing&1) == 1 and (mix&1) == 0){
return upgrade_cluster_matrix_anomalous(model->mixing, mix, g, g);
}
else{
qcm_throw("undefined mixing combinations in cluster_hopping_matrix()");
matrix<complex<double>> empty;
return empty;
}
}
//==============================================================================
void lattice_model_instance::cluster_self_energy(Green_function& G)
{
size_t n_clus = model->clusters.size();
if(!gf_solved) Green_function_solve();
G.sigma.block.assign(n_clus, matrix<Complex>());
for(size_t c = 0; c<n_clus; c++){
auto S = cluster_self_energy(c, G.w, G.spin_down);
G.sigma.block[c].assign(S);
}
G.sigma.set_size();
}
//==============================================================================
Green_function lattice_model_instance::cluster_Green_function(Complex w, bool sig, bool spin_down)
{
size_t n_clus = model->clusters.size();
if(!gf_solved) Green_function_solve();
Green_function G;
G.w = w;
G.spin_down = spin_down;
G.G.block.resize(n_clus);
for(size_t c = 0; c<n_clus; c++){
G.G.block[c].assign(cluster_Green_function(c, w, spin_down, false));
}
G.G.set_size();
if(sig){
G.sigma.block.resize(n_clus);
for(size_t c = 0; c<n_clus; c++){
G.sigma.block[c].assign(cluster_self_energy(c, w, spin_down));
}
G.sigma.set_size();
}
if(model->bath_exists){
G.gamma.block.resize(n_clus);
for(size_t c = 0; c<n_clus; c++){
G.gamma.block[c].assign(hybridization_function(c, w, spin_down));
}
G.gamma.set_size();
}
return G;
}
//==============================================================================
double lattice_model_instance::Potthoff_functional()
{
if(SEF_solved) return omega;
if(!gf_solved) Green_function_solve();
double omega_clus=0.0;
for(size_t c=0; c<model->clusters.size(); c++){
int C = model->clusters[c].ref;
double omega_c = 0.0;
for(int s=0; s<model->clusters[c].nsys; s++)
omega_c += ED::Potthoff_functional(model->nsys*label + s + model->clusters[c].sys_start);
omega_clus += omega_c/model->clusters[c].nsys;
}
vector<double> Iv(1);
Iv[0] = 0.0;
if(grid_freqs.size() > 0){
// ---- Discrete (omega, k) grid path ----
// Mirrors the averages() pattern: build the cluster Green function once per
// frequency, then parallelize the k-sum via k_integral_grid. The cluster
// GF is captured by value into the lambda and read concurrently inside the
// OpenMP parallel region (no shared mutable state).
int nkx, nky, nkz;
QCM::get_wavevector_grid(nkx, nky, nkz);
if(global_bool("verb_integrals"))
cout << "computing SEF integral from a grid of " << grid_freqs.size() << " frequencies and "
<< nkx << "x" << nky << "x" << nkz << " k-points (dim=" << model->spatial_dimension << ")" << endl;
bool has_dn = (model->mixing == HS_mixing::up_down);
vector<double> Iw(1);
for(int iw = 0; iw < (int)grid_freqs.size(); iw++){
Complex wc(0, grid_freqs[iw]);
Green_function G_up = cluster_Green_function(wc, false, false);
Green_function G_dn;
if(has_dn) G_dn = cluster_Green_function(wc, false, true);
auto F_k = [this, G_up, G_dn, has_dn] (vector3D<double> &k, const int *nv, double *I) mutable {
SEF_integrand_k(G_up, has_dn ? &G_dn : nullptr, k, nv, I);
};
Iw[0] = 0.0;
QCM::k_integral_grid(model->spatial_dimension, nkx, nky, nkz, F_k, Iw);
Iv[0] += Iw[0] * grid_weights[iw];
}
}
else{
// ---- Adaptive cubature in (omega, k) ----
auto F = [this] (Complex w, vector3D<double> &k, const int *nv, double *I) {SEF_integrand(w, k, nv, I);};
QCM::wk_integral(model->spatial_dimension, F, Iv, global_double("accur_SEF"), global_bool("verb_integrals"));
}
double omega_trace = -Iv[0];
//-------------------------------------------------------------------------------
// contribution of the diagonal terms
double omega_diag=0.0;
for(size_t i=0; i<model->dim_GF; i++){
if(model->is_nambu_index[i]) omega_diag += realpart(H(i,i)-Hc(i,i));
else omega_diag -= realpart(H(i,i)-Hc(i,i));
}
if(model->mixing == HS_mixing::up_down){
for(size_t i=0; i<model->dim_GF; i++) omega_diag -= realpart(H_down(i,i)-Hc_down(i,i));
}
if(model->mixing == HS_mixing::normal) omega_diag *= 2.0;
omega_diag *= 0.5;
//-------------------------------------------------------------------------------
// Putting it all together
if(model->n_mixed == 4){ // If Nambu doubling, then your really have to divide by 2.
omega_diag *= 0.5;
omega_trace *= 0.5;
}
omega = omega_trace - omega_diag + omega_clus;
//-------------------------------------------------------------------------------
// We want the energy density (or per atom), so we divide by the number of cluster orbitals
omega /= model->sites.size();
SEF_solved = true;
return(omega);
}
//==============================================================================
void lattice_model_instance::SEF_integrand(Complex w, vector3D<double> &k, const int *nv, double *I){
check_signals();
Green_function G = cluster_Green_function(w, false, false);
if(model->mixing == HS_mixing::up_down){
Green_function G_down = cluster_Green_function(w, false, true);
SEF_integrand_k(G, &G_down, k, nv, I);
}
else SEF_integrand_k(G, nullptr, k, nv, I);
}
//==============================================================================
void lattice_model_instance::SEF_integrand_k(Green_function &G_up, Green_function *G_down, vector3D<double> &k, const int *nv, double *I){
matrix<Complex> VG(model->dim_GF);
Green_function_k K(G_up, k);
set_V(K);
G_up.G.mult_left(K.V, VG);
VG.add(Complex(-1.0,0));
I[0] = log(abs(VG.determinant()));
if(G_down){
VG.zero();
Green_function_k K_down(*G_down, k);
set_V(K_down);
G_down->G.mult_left(K_down.V, VG);
VG.add(Complex(-1.0,0));
I[0] += log(abs(VG.determinant()));
}
else if(model->mixing == HS_mixing::normal) I[0] *= 2.0;
}
//==============================================================================
void lattice_model_instance::print_parameters(ostream& out, print_format format)
{
size_t n_clus = model->clusters.size();
bool print_all = global_bool("print_all");
bool print_variances = global_bool("print_variances");
out << setprecision((int)global_int("print_precision"));
if(model->param_set == nullptr) return;
switch(format){
case print_format::names :
for(auto& x : params) if(model->param_set->is_dependent(x.first) == false or print_all==true) out << x.first << '\t';
for(auto& x : ave) out << "ave_" << x.first << '\t';
for(size_t i = 0; i<n_clus; i++){
if(model->clusters[i].ref != i) continue;
for(auto& x : clus_ave[i]) out << "ave_" << strip_at(get<0>(x)) << '\t';
}
for(size_t i = 0; i<n_clus; i++){
if(model->clusters[i].ref != i) continue;
if(print_variances) for(auto& x : clus_ave[i]) out << "var_" << strip_at(get<0>(x)) << '\t';
}
break;
case print_format::values :
for(auto& x : params) if(model->param_set->is_dependent(x.first) == false or print_all==true) out << chop(x.second, 1e-10) << '\t';
for(auto& x : ave) out << chop(x.second, 1e-10) << '\t';
for(size_t i = 0; i<n_clus; i++){
if(model->clusters[i].ref != i) continue;
for(auto& x : clus_ave[i]) out << chop(get<1>(x), 1e-10) << '\t';
}
if(print_variances) for(size_t i = 0; i<n_clus; i++){
if(model->clusters[i].ref != i) continue;
for(auto& x : clus_ave[i]) out << chop(get<2>(x), 1e-10) << '\t';
}
break;
default:
break;
}
}
//==============================================================================
vector<pair<vector<double>, vector<double>>> lattice_model_instance::Lehmann_Green_function(vector<vector3D<double>> &k, int orb, bool spin_down)
{
if(model->nsys != model->clusters.size()) qcm_throw("For the time being, Lehmann_Green_function() only works without subsystems");
if(orb >= model->n_mixed*model->n_band) qcm_throw("the lattice orbital label is out of range in Lehmann_Green_function");
vector<pair<vector<double>, vector<double>>> res(k.size());
auto G = cluster_Green_function(Complex(0., 1.0), false, spin_down);
vector<double> Lambda;
block_matrix<Complex> QB;
size_t nclus = model->clusters.size();
for(size_t c=0; c<nclus; c++){
auto q = ED::qmatrix(spin_down, nclus*label+c);
Lambda.insert(Lambda.end(), q.first.begin(), q.first.end());
matrix<Complex> Q(model->GF_dims[c], q.first.size());
Q.v = q.second;
QB.block.push_back(Q);
}
QB.set_size();
size_t m = Lambda.size();
const double threshold = 1e-6;
for(int i=0; i<k.size(); i++){
res[i].first.resize(m);
res[i].second.resize(m);
Green_function_k K(G, k[i]);
matrix<Complex> Qk(QB.r,QB.c);
matrix<Complex> Lk(m);
matrix<Complex> Uk(m);
set_V(K, true);
QB.simil(Lk,K.V);
Lk.add_to_diagonal(Lambda);
Lk.eigensystem(res[i].first,Uk);
QB.mult_left(Uk, Qk);
vector<Complex> qk(QB.r);
vector<Complex> psi(model->n_band);
for(size_t a=0; a<m; ++a){
Qk.extract_column(a,qk);
auto psi = model->periodize(K.k, qk);
res[i].second[a] = abs(psi[orb]*psi[orb])*model->Lc;
}
// cleaning up
vector<double>& e = res[i].first;
for(size_t a=1; a<m; ++a){
if(abs(e[a]-e[a-1]) < 1e-6){
e[a] = (e[a]+e[a-1])/2;
res[i].second[a] += res[i].second[a-1];
res[i].second[a-1] = 0.0;
}
}
vector<double> ep, rp;
ep.reserve(m);
rp.reserve(m);
for(size_t a=1; a<m; ++a){
if(res[i].second[a] > threshold){
ep.push_back(res[i].first[a]);
rp.push_back(res[i].second[a]);
}
}
res[i].first = ep;
res[i].second = rp;
}
return res;
}
//==============================================================================
matrix<Complex> lattice_model_instance::upgrade_cluster_matrix(int latt_mix, int clus_mix, matrix<Complex> &g)
{
int d = g.r;
if(clus_mix == HS_mixing::normal and latt_mix == HS_mixing::spin_flip){
matrix<Complex> G(d*2);
g.move_sub_matrix(d, d, 0, 0, 0, 0, G);
g.move_sub_matrix(d, d, 0, 0, d, d, G, 1.0);
return G;
}
else if(clus_mix == HS_mixing::normal and latt_mix == HS_mixing::up_down){
return g;
}
else if(clus_mix == HS_mixing::anomalous and latt_mix == HS_mixing::full){
matrix<Complex> G(d*2);
int h = d/2;
g.move_sub_matrix(h, h, 0, 0, 0, 0, G);
g.move_sub_matrix(h, h, 0, 0, h, h, G);
g.move_sub_matrix(h, h, h, h, d, d, G);
g.move_sub_matrix(h, h, h, h, d+h, d+h, G);
g.move_sub_matrix(h, h, h, 0, d+h, 0, G);
g.move_sub_matrix(h, h, h, 0, d, h, G, -1.0);
g.move_sub_matrix(h, h, h, 0, h, d, G, -1.0);
g.move_sub_matrix(h, h, h, 0, 0, d+h, G);
return G;
}
else{
qcm_throw("impossible combination of cluster and lattice mixings");
matrix<Complex> empty;
return empty;
}
}
//==============================================================================
matrix<Complex> lattice_model_instance::upgrade_cluster_matrix_anomalous(int latt_mix, int clus_mix, matrix<Complex> &g, matrix<Complex> &gm)
{
int d = g.r;
if(clus_mix == HS_mixing::normal and latt_mix == HS_mixing::anomalous){
matrix<Complex> G(d*2);
g.move_sub_matrix(d, d, 0, 0, 0, 0, G);
gm.move_sub_matrix_transpose(d, d, 0, 0, d, d, G, -1.0);
return G;
}
else if(clus_mix == HS_mixing::normal and latt_mix == HS_mixing::full){
matrix<Complex> G(d*4);
g.move_sub_matrix(d, d, 0, 0, 0, 0, G);
g.move_sub_matrix(d, d, 0, 0, d, d, G, 1.0);
gm.move_sub_matrix_transpose(d, d, 0, 0, 2*d, 2*d, G, -1.0);
gm.move_sub_matrix_transpose(d, d, 0, 0, 3*d, 3*d, G, -1.0);
return G;
}
else if(clus_mix == HS_mixing::spin_flip and latt_mix == HS_mixing::full){
matrix<Complex> G(d*2);
g.move_sub_matrix(d, d, 0, 0, 0, 0, G);
gm.move_sub_matrix_transpose(d, d, 0, 0, d, d, G, -1.0);
return G;
}
else{
qcm_throw("impossible combination of cluster and lattice mixings");
matrix<complex<double>> empty;
return empty;
}
}