47 throw std::runtime_error(
49 " must always be region 0. Currently only one qm region is possible.");
62 if (prop.
exists(
"statetracker")) {
69 throw std::runtime_error(
70 "No statetracker options for excited states found");
76 if (prop.
exists(
"statetracker")) {
83 throw std::runtime_error(
"No statetracker options for KS states found");
88 prop.
get(
"grid_for_potential").
as<std::string>();
96 if (prop.
get(
"dftpackage.xtpdft.dft_in_dft.activeatoms")
103 if (prop.
exists(
"environment_screening")) {
115 throw std::runtime_error(
116 "environment_screening with state " +
initstate_.ToString() +
117 ": the charged DFT state would be polarized in the QM/MM loop and "
118 "screened again in GW. Run the neutral molecule and ask for the "
119 "quasiparticle level instead: state pqpN (or dqpN) with N the "
120 "HOMO or LUMO index.");
123 throw std::runtime_error(
124 "environment_screening is implemented for closed-shell GW-BSE "
125 "only; the unrestricted exciton state " +
126 initstate_.ToString() +
" is not supported.");
129 throw std::runtime_error(
130 "environment_screening needs a GW-BSE state (an exciton or a "
131 "quasiparticle level); " +
132 initstate_.ToString() +
" has no GW-BSE calculation to screen.");
141 throw std::runtime_error(
142 "environment_screening: site_width must be >= 0 (0 for point "
148 std::replace(shells.begin(), shells.end(),
',',
' ');
149 std::istringstream in(shells);
155 <<
" Environment screening on: ground-state QM/MM loop, then one "
156 "screened GW-BSE run. K_reac "
165 if (
orb_.isOpenShell()) {
166 throw std::runtime_error(
"GWBSE not implemented for open-shell systems");
169 Index active_electrons =
orb_.getNumOfActiveElectrons();
171 if (active_electrons % 2 != 0) {
172 throw std::runtime_error(
173 "DFT-in-DFT embedded GWBSE currently supports only closed-shell "
174 "active spaces with an even number of electrons");
179 const Index active_occ = active_electrons / 2;
182 orb_.setNumberOfOccupiedLevels(active_occ);
183 orb_.setNumberOfOccupiedLevelsBeta(active_occ);
184 orb_.setNumberOfAlphaElectrons(active_occ);
185 orb_.setNumberOfBetaElectrons(active_occ);
186 orb_.setChargeAndSpin(
orb_.getCharge(), 1);
192 return orb_.getExcitedStateEnergy(state);
197 return orb_.getExcitedStateEnergy(state);
199 return -
orb_.getExcitedStateEnergy(state);
203 const std::vector<std::unique_ptr<Region> >& regions)
const {
208 bool have_damp =
false;
210 for (
const std::unique_ptr<Region>& reg : regions) {
211 if (reg->identify() != Polardummy.
identify()) {
225 throw std::runtime_error(
226 "environment_screening: the explicit polar regions respond as one "
227 "coupled Thole system and must share exp_damp; found " +
228 std::to_string(env.
exp_damp) +
" and " +
229 std::to_string(polar.
ExpDamp()) +
".");
237 const bool is_polar = std::any_of(
238 regions.begin(), regions.end(),
239 [&](
const std::unique_ptr<Region>& reg) {
240 return reg->getId() == id && reg->identify() == Polardummy.identify();
243 throw std::runtime_error(
"environment_screening: shell region " +
245 " is not a polar region of this job.");
251 <<
" WARNING: environment_screening is on but there is no polar "
252 "region; GW-BSE runs unscreened."
262 !
dftoptions_.get(
"auxbasisset").as<std::string>().empty()) {
263 return dftoptions_.get(
"auxbasisset").as<std::string>();
266 !
gwbseoptions_.get(
"auxbasisset").as<std::string>().empty()) {
269 return "aux-" +
dftoptions_.get(
"basisset").as<std::string>();
273 const std::vector<std::unique_ptr<Region> >& regions)
const {
292 <<
TimeStamp() <<
" Checking the screening environment (" << auxname
293 <<
", " << auxbasis.
AOBasisSize() <<
" functions)" << std::flush;
297 throw std::runtime_error(
298 "environment_screening: 1 + R is not positive definite (lowest "
300 std::to_string(check.
lowest) +
301 "): the environment would screen some charge fluctuation of the QM "
302 "region by more than the fluctuation itself. Diagnosis:\n" +
306 <<
TimeStamp() <<
" Screening environment is stable: lowest eigenvalue "
307 <<
"of R " << check.
lowest <<
" (must be > -1)" << std::flush;
312 std::vector<std::unique_ptr<Region> >& regions) {
316 if (
orb_.getCalculationType() ==
"Truncated") {
317 throw std::runtime_error(
318 "environment_screening is not implemented for truncated active "
325 <<
TimeStamp() <<
" Running environment-screened GW-BSE" << std::flush;
326 const double e_dft =
orb_.getDFTTotalEnergy();
338 <<
" eV, region energy " << energy <<
" Hartree" << std::flush;
356 auto qp = [&](
Index level) {
357 const std::string kind =
orb_.hasQPdiag() ?
"dqp" :
"pqp";
358 return orb_.getExcitedStateEnergy(
QMState(kind + std::to_string(level)));
376 std::vector<const Eigen::Vector3d*> src =
ewaldgrid_.getGridpoints();
377 std::vector<Eigen::Vector3d> dst(src.size());
378 std::transform(src.begin(), src.end(), dst.begin(),
379 [](
const Eigen::Vector3d* v) { return *v; });
399 if (
orb_.QMAtoms().size() == 0) {
400 throw std::runtime_error(
401 "QMRegion::PrepareEwaldPotentialGrid: the region holds no atoms. The "
402 "grid is built over the QM molecule, so this must run after the "
403 "region has been filled.");
405 std::string dftbasis_name =
dftoptions_.get(
"basisset").as<std::string>();
406 std::string grid_name =
407 dftoptions_.get(
"xtpdft.integration_grid").as<std::string>();
410 bs.
Load(dftbasis_name);
412 dftbasis.
Fill(bs, mol);
413 ewaldgrid_.GridSetup(grid_name, mol, dftbasis);
415 <<
TimeStamp() <<
" Constructed Grid for Integration of Ewald Potential"
427 const double Echange =
E_hist_.getDiff();
428 const Eigen::MatrixXd diff_ao =
Dmat_hist_.getDiff();
429 const double n = double(diff_ao.cols());
435 const bool orthonormal =
overlap_sqrt_.rows() == diff_ao.rows();
436 const Eigen::MatrixXd diff =
439 const double Dchange = diff.norm() / n;
440 const double Dmax = diff.cwiseAbs().maxCoeff();
441 std::string info =
"not converged";
442 bool converged =
false;
447 std::ostringstream measure;
449 measure <<
" (orthonormal basis; AO basis: RMS " << diff_ao.norm() / n
450 <<
" Max " << diff_ao.cwiseAbs().maxCoeff() <<
")";
452 measure <<
" (AO basis)";
455 <<
" Region:" << this->
identify() <<
" " << this->
getId() <<
" is "
456 << info <<
" deltaE=" << Echange <<
" RMS Dmat=" << Dchange
457 <<
" MaxDmat=" << Dmax << measure.str() << std::flush;
465 std::accumulate(interact_energies.begin(), interact_energies.end(), 0.0);
468 <<
" Calculated interaction potentials with other regions. E[hrt]= "
469 << e_ext << std::flush;
490 throw std::runtime_error(
"QMEwald can only run with XTP as qmpackage.");
498 const bool warm_start =
E_hist_.filled() &&
orb_.hasMOs();
530 if (!Logfile_parse) {
532 errormsg_ =
"Parsing DFT logfile failed.";
536 if (!Orbfile_parse) {
538 errormsg_ =
"Parsing DFT orbfile failed.";
542 if (
orb_.isOpenShell()) {
543 throw std::runtime_error(
544 "MO localization not implemented for open-shell systems");
551 if (
orb_.isOpenShell()) {
552 throw std::runtime_error(
553 "DFT-in-DFT not implemented for open-shell systems");
556 std::unique_ptr<QMPackage> xtpdft =
558 xtpdft->setLog(&
log_);
567 xtpdft->setCharge(
charge);
569 std::vector<double> energies = std::vector<double>(regions.size(), 0.0);
570 for (std::unique_ptr<Region>& reg : regions) {
571 Index id = reg->getId();
572 if (
id == this->
getId()) {
579 <<
TimeStamp() <<
" Evaluating interaction between "
581 << reg->identify() <<
" " << reg->getId() << std::flush;
582 if (reg->identify() == Staticdummy.
identify()) {
584 xtpdft->AddRegion(*staticregion);
585 }
else if (reg->identify() == Polardummy.
identify()) {
587 xtpdft->AddRegion(*polarregion);
589 throw std::runtime_error(
590 "Interaction of regions with types:" + this->
identify() +
" and " +
591 reg->identify() +
" not implemented");
595 e_ext = std::accumulate(interact_energies.begin(), interact_energies.end(),
599 <<
" Calculated interaction potentials with other regions. E[hrt]= "
600 << e_ext << std::flush;
602 xtpdft->WriteInputFile(
orb_);
603 bool active_run = xtpdft->RunActiveRegion();
605 throw std::runtime_error(
"\n DFT in DFT embedding failed. Stopping!");
607 Logfile_parse = xtpdft->ParseLogFile(
orb_);
608 if (!Logfile_parse) {
609 throw std::runtime_error(
"\n Parsing DFT logfile failed. Stopping!");
614 double energy =
orb_.getDFTTotalEnergy();
620 energy +=
orb_.getExcitedStateEnergy(state);
623 energy -=
orb_.getExcitedStateEnergy(state);
640 if (
orb_.getCalculationType() ==
"Truncated") {
641 orb_.MOs().eigenvectors() =
orb_.getTruncMOsFullBasis();
642 orb_.QMAtoms().clearAtoms();
643 orb_.QMAtoms() = originalmol;
644 orb_.SetupDftBasis(
orb_.getDftBasis().Name());
645 orb_.SetupAuxBasis(
orb_.getAuxBasis().Name());
660 orb_.getDFTbasisName().empty()) {
666 }
catch (
const std::runtime_error&) {
672 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(overlap.
Matrix());
674 es.eigenvalues().cwiseMax(0.0).cwiseSqrt().asDiagonal() *
675 es.eigenvectors().transpose();
679 if (
orb_.QMAtoms().size() == 0) {
680 orb_.QMAtoms() = mol;
682 orb_.QMAtoms().AddContainer(mol);
692 nuccharge += a.getNuccharge();
695 Index electrons =
orb_.getNumberOfAlphaElectrons();
696 if (
orb_.isOpenShell()) {
697 electrons +=
orb_.getNumberOfBetaElectrons();
702 charge = double(nuccharge - electrons);
729 std::string dft_package_name =
dftoptions_.get(
"name").as<std::string>();
744 throw std::runtime_error(
745 "QMRegion-QMRegion interaction is not implemented yet.");
764#pragma omp parallel for
765 for (
Index i = 0; i <
Index(segments.size()); ++i) {
771 std::vector<PolarSegment>& segments)
const {
785 Eigen::MatrixXd dmat =
orb_.DensityMatrixFull(state);
789 double N_comp = dmat.cwiseProduct(overlap.
Matrix()).sum();
790 if (std::abs(Ngrid - N_comp) > 0.001) {
793 <<
"WARNING: Calculated Densities at Numerical Grid, Number of "
795 << Ngrid <<
" is far away from the the real value " << N_comp
796 <<
", you should increase the accuracy of the integration grid."
799#pragma omp parallel for
800 for (
Index i = 0; i <
Index(segments.size()); ++i) {
823 orb_.WriteBasisSetsToCpt(v);
841 r(state,
"initial_state");
845 orb_.ReadFromCpt(rr);
846 orb_.ReadBasisSetsFromCpt(rr);
891 points.push_back(atom.getPos());
893 const Eigen::VectorXd phi_all = region.
PotentialAt(points);
894 const Eigen::VectorXd phi = phi_all.head(n_grid);
895 const Eigen::VectorXd phi_nuclei = phi_all.tail(phi_all.size() - n_grid);
906 values.resize(std::size_t(n_box));
907 for (
Index p = 0; p < n_box; ++p) {
908 values[std::size_t(p)] = phi[offset + p];
912 if (offset != phi.size()) {
913 throw std::runtime_error(
914 "QMRegion::InteractwithEwaldRegion: the grid holds " +
915 std::to_string(offset) +
" points across its boxes but " +
916 std::to_string(phi.size()) +
917 " potential values were evaluated. getGridpoints() and the box "
918 "walk above disagree about the point ordering.");
void WriteContainer(T &container)
Container to hold Basisfunctions for all atoms.
Index AOBasisSize() const
void Fill(const BasisSet &bs, const QMMolecule &atoms)
void Fill(const AOBasis &aobasis) final
const Eigen::MatrixXd & Matrix() const
void push_back(const T &atom)
void Load(const std::string &name)
CheckpointReader openChild(const std::string &childName) const
CheckpointWriter openChild(const std::string &childName) const
Eigen::Vector3d IntegrateField(const Eigen::Vector3d &rvector) const
double IntegrateDensity(const Eigen::MatrixXd &density_matrix)
static Eigen::MatrixXd Metric(const AOBasis &auxbasis)
T for an auxiliary basis on its own: the metric TCMatrix_gwbse::Fill folds into the three-centre inte...
static ScreeningCheck Check(const AOBasis &auxbasis, const QMMolecule &atoms, const ScreeningEnvironment &env, const Eigen::MatrixXd &T, Index n_modes=3)
Builds R for env and reports whether 1 + R is positive definite, and why not.
The periodic Ewald background, as a Region.
Eigen::VectorXd PotentialAt(const std::vector< Eigen::Vector3d > &points) const
Electronic excitations from GW-BSE.
void setScreeningEnvironment(const ScreeningEnvironment &env)
void Initialize(tools::Property &options)
void setLogger(Logger *pLog)
const std::vector< Eigen::Vector3d > & getGridPoints() const
std::vector< double > & getPotentialValues()
std::vector< T >::iterator begin()
std::vector< T >::iterator end()
void computePML(Orbitals &orbitals)
std::string identify() const override
Class to represent Atom/Site in electrostatic+polarization.
void AppendResult(tools::Property &prop) const override
StateTracker statetracker_
hist< Eigen::MatrixXd > Dmat_hist_
void PrepareEwaldPotentialGrid()
std::string grid_accuracy_for_ext_interaction_
std::string identify() const override
void AddNucleiFields(std::vector< PolarSegment > &segments, const StaticSegment &seg) const
std::shared_ptr< DFTSetupCache > setup_cache_
std::unique_ptr< QMPackage > qmpackage_
bool screening_include_kreac_
void push_back(const QMMolecule &mol)
void WriteToCpt(CheckpointWriter &w) const override
double InteractwithStaticRegion(const StaticRegion ®ion) override
void EvaluateScreenedGWBSE(std::vector< std::unique_ptr< Region > > ®ions)
void AppendScreenedSiteEnergies(tools::Property &prop) const
std::string ScreeningAuxBasisName() const
double ewald_nuclear_energy_
double InteractwithPolarRegion(const PolarRegion ®ion) override
QMRegion(Index id, Logger &log, std::string workdir)
double StateEnergy(const QMState &state) const
void WritePDB(csg::PDBWriter &writer) const override
double InteractwithEwaldRegion(const EwaldRegion ®ion) override
void ReadFromCpt(CheckpointReader &r) override
ScreeningEnvironment BuildScreeningEnvironment(const std::vector< std::unique_ptr< Region > > ®ions) const
bool Converged() const override
void Evaluate(std::vector< std::unique_ptr< Region > > ®ions) override
tools::Property localize_options_
std::vector< Eigen::Vector3d > copyEwaldGrid()
void PrepareOrbitalsForGWBSE()
double InteractwithQMRegion(const QMRegion ®ion) override
void ApplyQMFieldToPolarSegments(std::vector< PolarSegment > &segments) const
bool ewald_potential_evaluated_
Eigen::MatrixXd overlap_sqrt_
double screening_shell_dielectric_
void Initialize(const tools::Property &prop) override
std::vector< Index > screening_shell_regions_
double charge() const override
double screening_site_width_
void CheckScreeningEnvironment(const std::vector< std::unique_ptr< Region > > ®ions) const
tools::Property dftoptions_
tools::Property gwbseoptions_
bool isSingleParticleState() const
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
std::string ToString() const
const QMStateType & Type() const
std::vector< double > ApplyInfluenceOfOtherRegions(std::vector< std::unique_ptr< Region > > ®ions)
std::string identify() const override
Class to represent Atom/Site in electrostatic.
Timestamp returns the current time as a string Example: cout << TimeStamp().
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Mediates interaction between polar and static sites.
#define XTP_LOG(level, log)
Charge transport classes.
ClassicalSegment< PolarSite > PolarSegment
ClassicalSegment< StaticSite > StaticSegment
Provides a means for comparing floating point numbers.
Outcome of EnvironmentScreening::Check: whether 1 + R is positive definite, and a human-readable acco...
The polarizable environment a GW-BSE calculation is screened by: what a QM/MM job hands to GWBSE (GWB...
std::vector< PolarSegment > explicit_segments
std::vector< PolarSegment > shell_segments