Program Listing for File QCM.cpp

Return to documentation for file (src_qcm/QCM.cpp)

//
//  QCM.cpp
//  qcm3
//
//  Created by David Sénéchal on 16-11-22.
//  Copyright © 2016 David Sénéchal. All rights reserved.
//

#include <memory>
#include <iostream>
#include <fstream>
#ifdef _OPENMP
  #include <omp.h>
#endif

#include "QCM.hpp"
#include "global_parameter.hpp"
#include "lattice_model.hpp"
#include "lattice_model_instance.hpp"
#include "parser.hpp"
#include "qcm_ED.hpp"
#include "parameter_set.hpp"
#include "model.hpp"
#include "model_instance_base.hpp"

//==============================================================================
// global variables

shared_ptr<lattice_model> qcm_model = nullptr; // pointer to the unique lattice model of the library
map<int, unique_ptr<lattice_model_instance>> lattice_model_instances; // list of instances

extern map<string, shared_ptr<model>> models;
extern map<size_t, shared_ptr<model_instance_base>> model_instances;

vector<double> grid_freqs; // optional imaginary frequency grid for discrete integrals
vector<double> grid_weights; // weights associated with grid_freqs

// per-direction wavevector grid sizes set via QCM::set_wavevector_grid().
// A value of 0 means "not set: fall back to global_int(\"kgrid_side\")".
int wavevector_grid_nx = 0;
int wavevector_grid_ny = 0;
int wavevector_grid_nz = 0;

//==============================================================================
namespace QCM{


void set_wavevector_grid(int nkx, int nky, int nkz){
  wavevector_grid_nx = nkx;
  wavevector_grid_ny = nky;
  wavevector_grid_nz = nkz;
}


void get_wavevector_grid(int& nkx, int& nky, int& nkz){
  int def = (int)global_int("kgrid_side");
  nkx = wavevector_grid_nx > 0 ? wavevector_grid_nx : def;
  nky = wavevector_grid_ny > 0 ? wavevector_grid_ny : def;
  nkz = wavevector_grid_nz > 0 ? wavevector_grid_nz : def;
}


void great_reset(){
  for(auto& x:lattice_model_instances) x.second.reset();
  lattice_model_instances.clear();
  for(auto& x:models) x.second.reset();
  models.clear();
  qcm_model->sector_strings.clear();
  qcm_model->param_set.reset();
  parameter_set::parameter_set_defined = false;
  lattice_model::model_consolidated = false;
  qcm_model.reset();
  qcm_model = make_shared<lattice_model>();
}


void erase_lattice_model_instance(size_t label){
    size_t nsys = qcm_model->nsys;
    for(size_t i=0; i < nsys; i++){
      model_instances.erase(label*nsys+i);
    }
    lattice_model_instances.erase(label);
}




  void check_instance(int label)
  {
    if(lattice_model_instances.find(label) == lattice_model_instances.end())
      qcm_throw("The instance # "+to_string(label)+" does not exist.");
  }



  void print_model(const string& filename, bool asy_operators, bool asy_labels, bool asy_orb, bool asy_neighbors, bool asy_working_basis)
  {
    ofstream fout(filename);
    if (!fout.good()) qcm_throw("failed to open file " + filename);
    qcm_model->print(fout, asy_operators, asy_labels, asy_orb, asy_neighbors, asy_working_basis);
    fout.close();
  }




  void new_model_instance(int label)
  {
    if(qcm_model->param_set == nullptr) qcm_throw("The parameters have not been specified yet.");
    lattice_model_instances[label] = unique_ptr<lattice_model_instance>(new lattice_model_instance(qcm_model, label));
  }




  void set_parameters(vector<pair<string,double>>& val, vector<tuple<string, double, string>>& equiv)
  {
    qcm_model->param_set = make_shared<parameter_set>(qcm_model, val, equiv);
  }


  void set_parameter(const string& name, double value)
  {
    if(qcm_model->param_set == nullptr) qcm_throw("The parameters have not been specified yet.");
    qcm_model->param_set->set_value(name, value);
  }



  void set_multiplier(const string& name, double value)
  {
    if(qcm_model->param_set == nullptr) qcm_throw("The parameters have not been specified yet.");
    qcm_model->param_set->set_multiplier(name, value);
  }



  map<string,double> parameters()
  {
    if(qcm_model->param_set == nullptr) qcm_throw("The parameters have not been specified yet.");
    return qcm_model->param_set->value_map();
  }


  map<string,double> instance_parameters(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->params;
  }



  vector<double> momentum_profile(const string& op, const vector<vector3D<double>> &k_set, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    if(qcm_model->term.find(op) == qcm_model->term.end()) qcm_throw("The lattice operator "+op+" does not exist.");
    return lattice_model_instances.at(label)->momentum_profile_per(*qcm_model->term.at(op), k_set);
  }



  vector<pair<double,string>> ground_state(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->ground_state();
  }



  matrix<complex<double>> cluster_Green_function(size_t i, complex<double> w, bool spin_down, int label, bool blocks)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->cluster_Green_function(i, w, spin_down, blocks);
  }


  matrix<complex<double>> cluster_self_energy(size_t i, complex<double> w, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->cluster_self_energy(i, w, spin_down);
  }



  matrix<complex<double>> cluster_hopping_matrix(size_t i, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->cluster_hopping_matrix(i, spin_down);
  }





  matrix<complex<double>> hybridization_function(complex<double> w, bool spin_down, size_t i, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->hybridization_function(i, w, spin_down);
  }




  matrix<complex<double>> Green_integral(bool spin_down, int clus, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->Green_integral(spin_down, clus);
  }






  matrix<complex<double>> CPT_Green_function(const complex<double> w, const vector3D<double> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    vector3D<double> K = mod.superdual.to(mod.physdual.from(k));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    Green_function_k M(G, K);
    lattice_model_instances.at(label)->set_Gcpt(M);
    return M.Gcpt;
  }


  vector<matrix<complex<double>>> CPT_Green_function(const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances[label]->model;
    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = mod.superdual.to(mod.physdual.from(k[i]));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    vector<matrix<Complex>> R(k.size());
    for(size_t i = 0; i< k.size(); i++) {
      Green_function_k M(G, K[i]);
      lattice_model_instances.at(label)->set_Gcpt(M);
      R[i] = M.Gcpt;
    }
    return R;
  }


  matrix<complex<double>> CPT_Green_function(int iw, int ik, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    if(mod.hybrid == nullptr) qcm_throw("CPT_Green_function(iw, ik, ...) requires an external hybridization (hybrid_file)");
    lattice_hybrid& H = *mod.hybrid;
    if(iw < 0 || (size_t)iw >= H.nw) qcm_throw("frequency index iw out of range");
    if(ik < 0 || (size_t)ik >= H.nk) qcm_throw("wavevector index ik out of range");
    Complex w(0.0, H.w[iw]);
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, false);
    G.iw = iw;
    Green_function_k M(G, H.k[ik], ik);
    lattice_model_instances.at(label)->set_Gcpt(M);
    cout << "k (read) = " << H.k[ik] << "\tw = " << w << endl; // TEMPO
    cout << "gamma = \n" << mod.lattice_hybridization(M.G.iw, M.ik) << endl; // TEMPO
    return M.Gcpt;
  }


  matrix<complex<double>> V_matrix(const complex<double> w, const vector3D<double> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    vector3D<double> K = mod.superdual.to(mod.physdual.from(k));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    Green_function_k M(G, K);
    lattice_model_instances.at(label)->set_V(M);
    return M.V;
  }


  vector<matrix<complex<double>>> CPT_Green_function_inverse(const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances[label]->model;
    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = mod.superdual.to(mod.physdual.from(k[i]));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    G.G.inverse();
    vector<matrix<Complex>> R(k.size());
    for(size_t i = 0; i< k.size(); i++) {
      Green_function_k M(G, K[i]);
      lattice_model_instances.at(label)->inverse_Gcpt(G.G, M);
      R[i] = M.V;
    }
    return R;
  }


  matrix<complex<double>> tk(const vector3D<double> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(Complex(0,0.1), false, spin_down);
    Green_function_k M(G, k);
    lattice_model_instances.at(label)->set_V(M);
    return M.t;
  }


  vector<matrix<complex<double>>> tk(const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances[label]->model;
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(Complex(0., 0.1), false, spin_down);
    vector<matrix<Complex>> R(k.size());
    for(size_t i = 0; i< k.size(); i++) {
      Green_function_k M(G, k[i]);
      lattice_model_instances.at(label)->set_Gcpt(M);
      R[i] = M.t;
    }
    return R;
  }


  vector<double> dos(const complex<double> w, int label, bool use_grid)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->dos(w, use_grid);
  }


  double spectral_average(const string& name, const complex<double> w, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->spectral_average(name, w);
  }



  matrix<complex<double>> periodized_Green_function(const complex<double> w, const vector3D<double> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    vector3D<double> K = qcm_model->superdual.to(qcm_model->physdual.from(k));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    Green_function_k M(G, K);
    lattice_model_instances.at(label)->periodized_Green_function(M);
    return M.g;
  }


  matrix<complex<double>> band_Green_function(const complex<double> w, const vector3D<double> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    vector3D<double> K = qcm_model->superdual.to(qcm_model->physdual.from(k));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    Green_function_k M(G, K);
    lattice_model_instances.at(label)->periodized_Green_function(M);

    return lattice_model_instances.at(label)->band_Green_function(M);
  }




  vector<matrix<complex<double>>> periodized_Green_function(const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = qcm_model->superdual.to(qcm_model->physdual.from(k[i]));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    vector<matrix<Complex>> R;
    R.reserve(K.size());
    for(size_t i = 0; i< K.size(); i++) {
      Green_function_k M(G, K[i]);
      lattice_model_instances.at(label)->periodized_Green_function(M);
      R.push_back(M.g);
    }
    return R;
  }


  vector<matrix<complex<double>>> band_Green_function(const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = qcm_model->superdual.to(qcm_model->physdual.from(k[i]));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    vector<matrix<Complex>> R;
    R.reserve(K.size());
    for(size_t i = 0; i< K.size(); i++) {
      Green_function_k M(G, K[i]);
      lattice_model_instances.at(label)->periodized_Green_function(M);
      R.push_back(lattice_model_instances.at(label)->band_Green_function(M));
    }
    return R;
  }


vector<complex<double>> periodized_Green_function_element(int r, int c, const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
{
  #ifdef QCM_DEBUG
check_instance(label);
#endif
  vector<vector3D<double>> K(k.size());
  for(size_t i = 0; i< K.size(); i++) K[i] = qcm_model->superdual.to(qcm_model->physdual.from(k[i]));
  Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
  vector<Complex> R;
  R.reserve(K.size());
  for(size_t i = 0; i< K.size(); i++) {
    Green_function_k M(G, K[i]);
    lattice_model_instances.at(label)->periodized_Green_function(M);
    R.push_back(M.g(r,c));
  }
  return R;
}




  vector<vector<double>> dispersion(const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model_instance& inst = *lattice_model_instances.at(label);

    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = mod.superdual.to(mod.physdual.from(k[i]));
    Green_function G = inst.cluster_Green_function({0.0,0.05}, false, spin_down);

    vector<vector<double>> R(K.size());
    for(size_t i = 0; i< K.size(); i++) {
      Green_function_k M(G, K[i]);
      R[i] = inst.dispersion(M);
    }
    return R;
  }




  matrix<complex<double>> compact_tiling(const matrix<complex<double>>& A, const vector3D<double>& k)
  {
    lattice_model& mod = *qcm_model;
    return mod.compact_tiling(A, k);
  }


  ED::CombinedMCF_data get_combined_mcf_k(const vector3D<double>& k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    QCM_ASSERT(mod.clusters.size() == 1);

    // Convert to superdual basis (same convention as set_V / periodize)
    vector3D<double> K = mod.superdual.to(mod.physdual.from(k));

    // Build a dummy Green_function_k to retrieve V(k)
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(Complex(0, 0.1), false, spin_down);
    Green_function_k M(G, K);
    lattice_model_instances.at(label)->set_V(M);

    // Get combined MCF from the ED layer
    size_t sys_label = mod.nsys * label + mod.clusters[0].sys_start;
    auto D = ED::get_combined_mcf(spin_down, sys_label);

    // Add inter-cluster hopping into the first diagonal block
    D.A[0].v += M.V.v;

    int nA = (int)D.A.size();
    int nB = (int)D.B.size();

    // Apply compact_tiling to A[j>=1] and B[j>=1]
    for(int j = 1; j < nA; ++j)
      D.A[j] = mod.compact_tiling(D.A[j], K);
    for(int j = 1; j < nB; ++j)
      D.B[j] = mod.compact_tiling(D.B[j], K);

    // Periodize all blocks into the band basis
    ED::CombinedMCF_data Dper;
    Dper.A.resize(nA);
    Dper.B.resize(nB);
    for(int j = 0; j < nA; ++j)
      Dper.A[j] = mod.periodize(K, D.A[j]);
    for(int j = 0; j < nB; ++j)
      Dper.B[j] = mod.periodize(K, D.B[j]);
    Dper.W = mod.periodize(K, D.W);

    return Dper;
  }


  vector<matrix<Complex>> epsilon(const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model_instance& inst = *lattice_model_instances.at(label);

    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = mod.superdual.to(mod.physdual.from(k[i]));
    Green_function G = inst.cluster_Green_function({0.0,0.05}, false, spin_down);

    vector<matrix<Complex>> R(K.size());
    for(size_t i = 0; i< K.size(); i++) {
      Green_function_k M(G, K[i]);
      R[i] = inst.epsilon(M);
    }
    return R;
  }



  vector<matrix<complex<double>>> self_energy(const complex<double> w, const vector<vector3D<double>> &k, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model& mod = *lattice_model_instances.at(label)->model;
    vector<vector3D<double>> K(k.size());
    for(size_t i = 0; i< K.size(); i++) K[i] = mod.superdual.to(mod.physdual.from(k[i]));
    Green_function G = lattice_model_instances.at(label)->cluster_Green_function(w, false, spin_down);
    vector<matrix<Complex>> R;
    R.reserve(K.size());
    for(size_t i = 0; i< K.size(); i++) {
      Green_function_k M(G, K[i]);
      lattice_model_instances.at(label)->self_energy(M);
      R.push_back(M.sigma);
    }
    return R;
  }




  double Potthoff_functional(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->Potthoff_functional();
  }



  double potential_energy(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->potential_energy();
  }



  double kinetic_energy(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->E_kin;
  }



  vector<pair<string,double>> averages(const vector<string> &_ops, int label)
  {
    return lattice_model_instances.at(label)->averages(_ops);
  }



  matrix<complex<double>> projected_Green_function(const complex<double> w, bool spin_down, int label)
  {
    return lattice_model_instances.at(label)->projected_Green_function(w, spin_down);
  }



  size_t Green_function_dimension()
  {
    return qcm_model->dim_GF;
  }


  size_t reduced_Green_function_dimension()
  {
    char periodization = global_char("periodization");
    if(periodization == 'N') return qcm_model->dim_GF;
    else return qcm_model->dim_reduced_GF;
  }


  int spatial_dimension()
  {
    return qcm_model->spatial_dimension;
  }



  int mixing()
  {
    return qcm_model->mixing;
  }



  double Berry_flux(vector<vector3D<double>>& k, int orb, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->Berry_flux(k, orb, false);
  }





  vector<double> Berry_curvature(vector3D<double>& k1, vector3D<double>& k2, int nk, int orb, bool rec, int dir, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->Berry_curvature(k1, k2, nk, orb, rec, dir);
  }



  void add_cluster(const vector3D<int64_t> &cpos, const vector<vector3D<int64_t>> &pos, int ref, bool conj)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created. Ignoring.");
      return;
    }
    for(size_t i=0; i<pos.size(); i++) qcm_model->sites.push_back({qcm_model->clusters.size(), i, 0, pos[i]+cpos});
    if(ref == -1) ref = qcm_model->clusters.size();
    qcm_model->clusters.push_back({pos.size(), qcm_model->sites.size(), cpos, ref, 0, conj, 0, 0});
    // n_sites, n_bath, offset, name, position, ref, mixing, sys_start, nsys
  }


  void add_system(const string &name, const int clus)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created. Ignoring.");
      return;
    }
    if(clus > qcm_model->clusters.size())
      qcm_throw("This system cannot be added to the cluster (out of range, or maybe clusters not yet added to lattice model)");

    auto tmp = ED::model_size(name);
    if(get<0>(tmp) != qcm_model->clusters[clus].n_sites) qcm_throw("The number of sites of cluster "+name+" is inconsistent with the cluster model");
    if(get<1>(tmp) > 0) qcm_model->bath_exists = true;
    // n_sites, n_bath, name, clus, mixing, n_sym
    qcm_model->systems.push_back({get<0>(tmp), get<1>(tmp), name, clus, 0, get<2>(tmp)});
  }



  void new_lattice_model(const string &name, vector<int64_t> &superlattice, vector<int64_t> &unit_cell, const string &latt_hybrid)
  {
    if(qcm_model==nullptr) qcm_throw("no cluster has been added to the model!");
    if(qcm_model->is_closed){
      qcm_warning("model already created. Ignoring.");
      return;
    }
    qcm_model->name = name;
    qcm_model->superlattice = lattice3D(superlattice);
    qcm_model->unit_cell = lattice3D(unit_cell);
    qcm_model->phys.trivial();
    qcm_model->hybrid_file = latt_hybrid;
    qcm_model->hybrid = nullptr;
    qcm_model->pre_operator_consolidate();
  }


  void set_basis(vector<double> &basis)
  {
    qcm_model->phys = basis3D(basis);
    qcm_model->phys.inverse();
    qcm_model->phys.dual(qcm_model->physdual);
    qcm_model->physdual.init();
  }


  void interaction_operator(const string &name, vector3D<int64_t> &link, double amplitude, int orb1, int orb2, const string &type)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->interaction_operator(name, link, amplitude, orb1-1, orb2-1, type);
  }


  void hopping_operator(const string &name, vector3D<int64_t> &link, double amplitude, int orb1, int orb2, int tau, int sigma)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->hopping_operator(name, link, amplitude, orb1-1, orb2-1, tau, sigma);
  }


  void current_operator(const string &name, vector3D<int64_t> &link, double amplitude, int orb1, int orb2, int dir, bool pau)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->current_operator(name, link, amplitude, orb1-1, orb2-1, dir, pau);
  }


  void anomalous_operator(const string &name, vector3D<int64_t> &link, complex<double> amplitude, int orb1, int orb2, const string& type)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->anomalous_operator(name, link, amplitude, orb1-1, orb2-1, type);
  }

  void density_wave(const string &name, vector3D<int64_t> &link, complex<double> amplitude, int orb, vector3D<double> Q, double phase, const string& type)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->density_wave(name, link, amplitude, orb-1, Q, phase, type);
  }

  void explicit_operator(const string &name, const string &type, const vector<tuple<vector3D<int64_t>, vector3D<int64_t>, complex<double>>> &elem, int tau, int sigma)
  {
    if(qcm_model->is_closed){
      qcm_warning("model already created and closed. Ignoring operator creation.");
      return;
    }
    qcm_model->explicit_operator(name, type, elem, tau, sigma);
  }


  vector<tuple<string, int, int, int, int>> cluster_info()
  {
    vector<tuple<string, int, int, int, int>> info(qcm_model->clusters.size());
    for(int i=0; i<info.size(); i++){
      get<0>(info[i]) = (int)qcm_model->clusters[i].n_sites;
      get<1>(info[i]) = (int)qcm_model->clusters[i].nsys;
      get<2>(info[i]) = (int)qcm_model->clusters[i].sys_start;
      get<3>(info[i]) = (int)qcm_model->clusters[i].n_sites*qcm_model->n_mixed;
    }
    return info;
  }



  vector<tuple<string, int, int, int>> systems_info()
  {
    vector<tuple<string, int, int, int>> info(qcm_model->systems.size());
    for(int i=0; i<info.size(); i++){
      get<0>(info[i]) = qcm_model->systems[i].name;
      get<1>(info[i]) = (int)qcm_model->systems[i].n_sites;
      get<2>(info[i]) = (int)qcm_model->systems[i].n_bath;
      get<3>(info[i]) = (int)qcm_model->systems[i].clus;
    }
    return info;
  }



  pair<vector<array<double,9>>, vector<array<complex<double>, 11>>> site_and_bond_profile(int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    auto& M = *lattice_model_instances[label];
    return M.site_and_bond_profile();
  }



  vector<pair<vector<double>, vector<double>>> Lehmann_Green_function(vector<vector3D<double>> &k, int orb, bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    for(size_t i = 0; i< k.size(); i++) k[i] = qcm_model->superdual.to(qcm_model->physdual.from(k[i]));
    return lattice_model_instances[label]->Lehmann_Green_function(k, orb, spin_down);
  }


  void Green_function_solve(int label){
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model_instances.at(label)->Green_function_solve();
  }

  void CDMFT_variational_set(vector<vector<string>>& varia){
    if(qcm_model->param_set == nullptr) qcm_throw("The parameters have not been specified yet.");
    qcm_model->param_set->CDMFT_variational_set(varia);
  }

  void CDMFT_host(const vector<double>& freqs, const vector<double>& weights, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model_instances.at(label)->CDMFT_host(freqs, weights);
  }

  void set_CDMFT_host(int label, const vector<double>& freqs, const int clus, const vector<matrix<Complex>>& H, const bool spin_down)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    lattice_model_instances.at(label)->set_CDMFT_host(freqs, clus, H, spin_down);
  }


  vector<vector<matrix<Complex>>> get_CDMFT_host(bool spin_down, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->get_CDMFT_host(spin_down);
  }

  double CDMFT_distance(const vector<double>& p, int clus, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->CDMFT_distance(p, clus);
  }

  vector<double> CDMFT_residuals(const vector<double>& p, int clus, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->CDMFT_residuals(p, clus);
  }

  vector<double> CDMFT_gradient(const vector<double>& p, int clus, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->CDMFT_gradient(p, clus);
  }

  double monopole(vector3D<double>& k, double a, int nk, int orb, bool rec, int label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->monopole(k, a, nk, orb, rec);
  }


  bool complex_HS(size_t label)
  {
    #ifdef QCM_DEBUG
    check_instance(label);
    #endif
    return lattice_model_instances.at(label)->complex_HS;
  }

}