Program Listing for File convention.cpp

Return to documentation for file (SeQuant/domain/mbpt/convention.cpp)

//
// Created by Eduard Valeyev on 2019-04-01.
//

#include <SeQuant/domain/mbpt/convention.hpp>
#include <SeQuant/domain/mbpt/op.hpp>
#include <SeQuant/domain/mbpt/rules/df.hpp>
#include <SeQuant/domain/mbpt/space_qns.hpp>
#include <SeQuant/domain/mbpt/spin.hpp>

#include <SeQuant/core/context.hpp>
#include <SeQuant/core/index.hpp>
#include <SeQuant/core/space.hpp>

#include <cassert>
#include <cstdlib>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

namespace sequant {
namespace mbpt {

void load(Convention conv, SpinConvention spconv) {
  std::shared_ptr<IndexSpaceRegistry> isr;
  switch (conv) {
    case Convention::Minimal:
      isr = make_min_sr_spaces(spconv);
      break;
    case Convention::SR:
      isr = make_sr_spaces(spconv);
      break;
    case Convention::MinimalMR:
      isr = make_min_mr_spaces(spconv);
      break;
    case Convention::MR:
      isr = make_mr_spaces(spconv);
      break;
    case Convention::F12:
      isr = make_F12_sr_spaces(spconv);
      break;
    case Convention::QCiFS:
      isr = make_legacy_spaces(spconv);
      break;
  }
  set_default_context({.index_space_registry_shared_ptr = isr,
                       .vacuum = Vacuum::SingleProduct});
}

void add_fermi_spin(IndexSpaceRegistry& isr) {
  IndexSpaceRegistry result = isr.clone();

  for (auto&& space : isr) {
    if (space.base_key() != L"") {
      IndexSpace spin_up(spinannotation_add(space.base_key(), Spin::alpha),
                         space.type(), Spin::alpha, space.approximate_size());
      IndexSpace spin_down(spinannotation_add(space.base_key(), Spin::beta),
                           space.type(), Spin::beta, space.approximate_size());
      result.add(spin_up);
      result.add(spin_down);
    }
  }
  const bool nulltype_ok = true;
  result.reference_occupied_space(isr.reference_occupied_space(nulltype_ok));
  result.vacuum_occupied_space(isr.vacuum_occupied_space(nulltype_ok));
  result.particle_space(isr.particle_space(nulltype_ok));
  result.hole_space(isr.hole_space(nulltype_ok));
  result.complete_space(isr.complete_space(nulltype_ok));

  isr = std::move(result);
}

void add_ao_spaces(std::shared_ptr<IndexSpaceRegistry>& isr, bool vbs,
                   bool abs) {
  // matches the MPQC layout, see spindex.h
  // this will not work for MR
  auto obs_lcao = isr->retrieve(vbs ? L"m" : L"p");
  isr->add(IndexSpace{L"μ", obs_lcao.type(), LCAOQNS::ao});  // OBS AO
  if (vbs) {
    auto vbs_lcao = isr->retrieve(L"e");
    isr->add(IndexSpace{L"Α", vbs_lcao.type(), LCAOQNS::ao})  // VBS AO
        .add_union(L"Γ", {L"μ", L"Α"});  // VBS+ = OBS + VBS
  }
  if (abs) {
    auto abs_lcao = isr->retrieve(L"α'");
    isr->add(IndexSpace{L"σ", abs_lcao.type(),
                        LCAOQNS::ao})  // ABS AO in F12 methods
        .add_union(L"ρ", {L"μ", L"σ"});
    if (vbs)                               // ABS+ = OBS + ABS
      isr->add_union(L"Ρ", {L"Γ", L"σ"});  // VABS+ = VBS+ + ABS
  }
}

void add_pao_spaces(std::shared_ptr<IndexSpaceRegistry>& isr) {
  auto uocc_space = isr->particle_space(/* nulltype_ok = */ false);
  isr->add(IndexSpace{L"μ̃", uocc_space, LCAOQNS::pao})  // OBS PAO
      ;
}

void add_df_spaces(std::shared_ptr<IndexSpaceRegistry>& isr) {
  // matches the MPQC layout, see spindex.h
  isr->add(IndexSpace{L"Κ", 0b00001, TensorFactorizationQNS::df});  // DFBS AO
}

void add_batching_spaces(std::shared_ptr<IndexSpaceRegistry>& isr) {
  isr->add(IndexSpace{L"z", 0b100000, BatchingQNS::batch});  // Batching Space
}

void add_thc_spaces(std::shared_ptr<IndexSpaceRegistry>& isr) {
  isr->add(IndexSpace{L"L", 0b000001, TensorFactorizationQNS::thc})  // THC AO
      ;
}

std::shared_ptr<IndexSpaceRegistry> make_min_sr_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"i", 0b01, spin_any, is_vacuum_occupied, is_reference_occupied,
           is_hole)
      .add(L"a", 0b10, spin_any, is_particle)
      .add_union(L"p", {L"i", L"a"}, is_complete);
  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

// Multireference supspace uses a subset of its occupied orbitals to define a
// vacuum occupied subspace.
//  this leaves an active space which is partially occupied/unoccupied. This
//  definition is convenient when coupled with SR vacuum.
std::shared_ptr<IndexSpaceRegistry> make_mr_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"o", 0b00001, spin_any)
      .add(L"i", 0b00010, spin_any)
      .add(L"u", 0b00100, spin_any)
      .add(L"a", 0b01000, spin_any)
      .add(L"g", 0b10000, spin_any)
      .add_union(L"O", {L"o", L"i"}, is_vacuum_occupied)
      .add_union(L"M", {L"o", L"i", L"u"}, is_reference_occupied)
      .add_union(L"I", {L"i", L"u"}, is_hole)
      .add_union(L"E", {L"u", L"a", L"g"})
      .add_union(L"A", {L"u", L"a"}, is_particle)
      .add_union(L"p", {L"M", L"E"}, is_complete);

  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

std::shared_ptr<IndexSpaceRegistry> make_min_mr_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"i", 0b0001, spin_any, is_vacuum_occupied)
      .add(L"u", 0b0010, spin_any)
      .add(L"a", 0b0100, spin_any)
      .add_union(L"I", {L"i", L"u"}, is_reference_occupied, is_hole)
      .add_union(L"A", {L"u", L"a"}, is_particle)
      .add_union(L"p", {L"I", L"a"}, is_complete);

  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

std::shared_ptr<IndexSpaceRegistry> make_sr_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"o", 0b0001, spin_any)
      .add(L"i", 0b0010, spin_any, is_hole)
      .add(L"a", 0b0100, spin_any, is_particle)
      .add(L"g", 0b1000, spin_any)
      .add_union(L"m", {L"o", L"i"}, is_vacuum_occupied, is_reference_occupied)
      .add_union(L"e", {L"a", L"g"})
      .add_union(L"x", {L"i", L"a"})
      .add_union(L"p", {L"m", L"e"}, is_complete);
  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

std::shared_ptr<IndexSpaceRegistry> make_F12_sr_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"o", 0b00001, spin_any)
      .add(L"i", 0b00010, spin_any, is_hole)
      .add(L"a", 0b00100, spin_any, is_particle)
      .add(L"g", 0b01000, spin_any)
      .add(L"α'", 0b10000, spin_any)
      .add_union(L"m", {L"o", L"i"}, is_vacuum_occupied, is_reference_occupied)
      .add_union(L"e", {L"a", L"g"})
      .add_union(L"x", {L"i", L"a"})
      .add_union(L"p", {L"m", L"e"})
      .add_unIon(L"h", {L"x", L"g"})
      .add_unIon(L"c", {L"g", L"α'"})
      .add_union(L"α", {L"e", L"α'"})
      .add_union(L"H", {L"i", L"α"})
      .add_union(L"κ", {L"p", L"α'"}, is_complete);
  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

std::shared_ptr<IndexSpaceRegistry> make_legacy_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto spin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"o", 0b0000001, spin_any)
      .add(L"n", 0b0000010, spin_any)
      .add(L"i", 0b0000100, spin_any, is_hole)
      .add(L"u", 0b0001000, spin_any)
      .add(L"a", 0b0010000, spin_any, is_particle)
      .add(L"g", 0b0100000, spin_any)
      .add(L"α'", 0b1000000, spin_any)
      .add_union(L"m", {L"o", L"n", L"i"}, is_vacuum_occupied,
                 is_reference_occupied)
      .add_union(L"M", {L"m", L"u"})
      .add_union(L"e", {L"a", L"g"})
      .add_union(L"E", {L"u", L"e"})
      .add_union(L"x", {L"i", L"u", L"a"})
      .add_union(L"p", {L"m", L"x", L"e"})
      .add_union(L"κ", {L"p", L"α'"}, is_complete);

  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  isr->physical_particle_attribute_mask(bitset_t(spin_any));

  return isr;
}

std::pair<std::shared_ptr<IndexSpaceRegistry>,
          std::shared_ptr<IndexSpaceRegistry>>
make_fermi_and_bose_spaces(SpinConvention spconv) {
  auto isr = std::make_shared<IndexSpaceRegistry>();

  const auto fspin_any = IndexSpace::QuantumNumbers{
      spconv == SpinConvention::Legacy ? Spin::null : Spin::any};
  isr->add(L"i", 0b001, fspin_any)    // fermi occupied
      .add(L"a", 0b010, fspin_any)    // fermi unoccupied
      .add_union(L"p", {L"i", L"a"})  // fermi all
      ;
  if (spconv == SpinConvention::Default) add_fermi_spin(*isr);
  const auto bspin_any = IndexSpace::QuantumNumbers{Spin::any};
  isr->add(L"β", 0b100, bspin_any);  // bose

  auto fermi_isr = std::make_shared<IndexSpaceRegistry>(isr->spaces());
  fermi_isr->vacuum_occupied_space(L"i");
  fermi_isr->reference_occupied_space(L"i");
  fermi_isr->hole_space(L"i");
  fermi_isr->particle_space(L"a");
  fermi_isr->complete_space(L"p");
  fermi_isr->physical_particle_attribute_mask(bitset_t(fspin_any));

  auto bose_isr = std::make_shared<IndexSpaceRegistry>(isr->spaces());
  bose_isr->vacuum_occupied_space(IndexSpace::null);
  bose_isr->reference_occupied_space(IndexSpace::null);
  bose_isr->hole_space(IndexSpace::null);
  bose_isr->particle_space(L"β");
  bose_isr->complete_space(L"β");
  bose_isr->physical_particle_attribute_mask(bitset_t(bspin_any));

  return std::make_pair(std::move(fermi_isr), std::move(bose_isr));
}

}  // namespace mbpt
}  // namespace sequant