votca 2024.2-dev
Loading...
Searching...
No Matches
radial_euler_maclaurin_rule.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "A_ol I_ol" BA_olI_ol,
14 * WITHOUT WARRANTIE_ol OR CONDITION_ol OF ANY KIND, either express or implied.
15 * olee_ the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Third party includes
21#include <boost/math/constants/constants.hpp>
22
23// Local VOTCA includes
24#include "votca/xtp/aobasis.h"
25#include "votca/xtp/aomatrix.h"
28
29namespace votca {
30namespace xtp {
31
33 const std::string& element) {
34 std::vector<double> r;
35 // get Bragg-Slater Radius for this element
36 double BSradius = BraggSlaterRadii_.at(element);
37 // row type of element
38 Index RowType = pruning_set_.at(element);
39
40 if (RowType == 1) {
41 r.push_back(0.25 * BSradius);
42 r.push_back(0.5 * BSradius);
43 r.push_back(1.0 * BSradius);
44 r.push_back(4.5 * BSradius);
45 } else if (RowType == 2) {
46 r.push_back(0.1667 * BSradius);
47 r.push_back(0.5 * BSradius);
48 r.push_back(0.9 * BSradius);
49 r.push_back(3.5 * BSradius);
50 } else if (RowType == 3) {
51 r.push_back(0.1 * BSradius);
52 r.push_back(0.4 * BSradius);
53 r.push_back(0.8 * BSradius);
54 r.push_back(2.5 * BSradius);
55 } else {
56 throw std::runtime_error(
57 "EulerMaclaurinGrid::CalculatePruningIntervals:Pruning unsupported for "
58 "RowType");
59 }
60 return r;
61}
62
64 const QMMolecule& atoms,
65 double eps) {
66 std::map<std::string, min_exp>::iterator it;
67 for (const QMAtom& atom : atoms) {
68 std::string name = atom.getElement();
69 // is this element already in map?
70 it = element_ranges_.find(name);
71 // only proceed, if element data does not exist yet
72 if (it == element_ranges_.end()) {
73 min_exp this_atom;
74 double range_max = std::numeric_limits<double>::min();
75 double decaymin = std::numeric_limits<double>::max();
76 Index lvalue = std::numeric_limits<Index>::min();
77 const std::vector<const AOShell*> shells =
78 aobasis.getShellsofAtom(atom.getId());
79 // and loop over all shells to figure out minimum decay constant and
80 // angular momentum of this function
81 for (const AOShell* shell : shells) {
82 Index lmax = Index(shell->getL());
83 if (shell->getMinDecay() < decaymin) {
84 decaymin = shell->getMinDecay();
85 lvalue = lmax;
86 }
87 double range = DetermineCutoff(2 * decaymin, 2 * lvalue + 2, eps);
88 if (range > range_max) {
89 this_atom.alpha = decaymin;
90 this_atom.l = lvalue;
91 this_atom.range = range;
92 range_max = range;
93 }
94 } // shells
95 element_ranges_[name] = this_atom;
96 } // new element
97 } // atoms
98}
99
101 const QMMolecule& atoms,
102 double eps) {
103 AOOverlap overlap;
104 overlap.Fill(aobasis);
105
106 // get collapsed index list
107 std::vector<Index> idxstart;
108 const std::vector<Index>& idxsize = aobasis.getFuncPerAtom();
109 Index start = 0;
110 for (Index size : idxsize) {
111 idxstart.push_back(start);
112 start += size;
113 }
114 // refining by going through all atom combinations
115 for (Index i = 0; i < atoms.size(); ++i) {
116 const QMAtom& atom_a = atoms[i];
117 Index a_start = idxstart[i];
118 Index a_size = idxsize[i];
119 double range_max = std::numeric_limits<double>::min();
120 // get preset values for this atom type
121 double alpha_a = element_ranges_.at(atom_a.getElement()).alpha;
122 Index l_a = element_ranges_.at(atom_a.getElement()).l;
123 const Eigen::Vector3d& pos_a = atom_a.getPos();
124 // Cannot iterate only over j<i because it is not symmetric due to shift_2g
125 for (Index j = 0; j < atoms.size(); ++j) {
126 if (i == j) {
127 continue;
128 }
129 const QMAtom& atom_b = atoms[j];
130 Index b_start = idxstart[j];
131 Index b_size = idxsize[j];
132 const Eigen::Vector3d& pos_b = atom_b.getPos();
133 // find overlap block of these two atoms
134 Eigen::MatrixXd overlapblock =
135 overlap.Matrix().block(a_start, b_start, a_size, b_size);
136 // determine abs max of this block
137 double s_max = overlapblock.cwiseAbs().maxCoeff();
138
139 if (s_max > 1e-5) {
140 double range = DetermineCutoff(
141 alpha_a + element_ranges_.at(atom_b.getElement()).alpha,
142 l_a + element_ranges_.at(atom_b.getElement()).l + 2, eps);
143 // now do some update trickery from Gaussian product formula
144 double dist = (pos_b - pos_a).norm();
145 double shift_2g =
146 dist * alpha_a /
147 (alpha_a + element_ranges_.at(atom_b.getElement()).alpha);
148 range += (shift_2g + dist);
149 if (range > range_max) {
150 range_max = range;
151 }
152 }
153 }
154 if (std::round(range_max) > element_ranges_.at(atom_a.getElement()).range) {
155 element_ranges_.at(atom_a.getElement()).range = std::round(range_max);
156 }
157 }
158}
159
161 const QMMolecule& atoms,
162 const std::string& gridtype) {
163
164 double eps = Accuracy[gridtype];
165 FillElementRangeMap(aobasis, atoms, eps);
166 RefineElementRangeMap(aobasis, atoms, eps);
167 return;
168}
169
170std::map<std::string, GridContainers::radial_grid>
172 const QMMolecule& atoms,
173 const std::string& type) {
174
175 CalculateRadialCutoffs(aobasis, atoms, type);
176 std::map<std::string, GridContainers::radial_grid> result;
177 for (const auto& element : element_ranges_) {
178 result[element.first] = CalculateRadialGridforAtom(type, element);
179 }
180 return result;
181}
182
184 const std::string& type, const std::pair<std::string, min_exp>& element) {
186 Index np = getGridParameters(element.first, type);
187 double cutoff = element.second.range;
188 result.radius = Eigen::VectorXd::Zero(np);
189 result.weight = Eigen::VectorXd::Zero(np);
190 double alpha =
191 -cutoff /
192 (log(1.0 - std::pow((1.0 + double(np)) / (2.0 + double(np)), 3)));
193 double factor = 3.0 / (1.0 + double(np));
194
195 for (Index i = 0; i < np; i++) {
196 double q = double(i + 1) / (double(np) + 1.0);
197 double r = -alpha * std::log(1.0 - std::pow(q, 3));
198 double w = factor * alpha * r * r / (1.0 - std::pow(q, 3)) * std::pow(q, 2);
199 result.radius[i] = r;
200 result.weight[i] = w;
201 }
202 return result;
203}
204
205double EulerMaclaurinGrid::DetermineCutoff(double alpha, Index l, double eps) {
206 // determine norm of function
207 /* For a function f(r) = r^k*exp(-alpha*r^2) determine
208 the radial distance r such that the fraction of the
209 function norm that is neglected if the 3D volume
210 integration is terminated at a distance r is less
211 than or equal to eps. */
212
213 double cutoff = 1.0; // initial value
214 double increment = 0.5; // increment
215
216 while (increment > 0.01) {
217 double residual = CalcResidual(alpha, l, cutoff);
218 if (residual > eps) {
219 cutoff += increment;
220 } else {
221 cutoff -= increment;
222 if (cutoff < 0.0) {
223 cutoff = 0.0;
224 }
225 increment = 0.5 * increment;
226 cutoff += increment;
227 }
228 }
229 return cutoff;
230}
231
232double EulerMaclaurinGrid::CalcResidual(double alpha, Index l, double cutoff) {
233 return RadialIntegral(alpha, l + 2, cutoff) /
234 RadialIntegral(alpha, l + 2, 0.0);
235}
236
238 double cutoff) {
239 const double pi = boost::math::constants::pi<double>();
240 Index ilo = l % 2;
241 double value = 0.0;
242 double valexp;
243 if (ilo == 0) {
244 double expo = std::sqrt(alpha) * cutoff;
245 if (expo <= 40.0) {
246 value = 0.5 * std::sqrt(pi / alpha) * std::erfc(expo);
247 }
248 }
249 double exponent = alpha * cutoff * cutoff;
250 if (exponent > 500.0) {
251 valexp = 0.0;
252 value = 0.0;
253 } else {
254 valexp = std::exp(-exponent);
255 value = valexp / 2.0 / alpha;
256 }
257 for (Index i = ilo + 2; i <= l; i += 2) {
258 value = (double(i - 1) * value + std::pow(cutoff, i - 1) * valexp) / 2.0 /
259 alpha;
260 }
261 return value;
262}
263
265 const std::string& type) {
266 if (type == "medium") {
267 return MediumGrid.at(element);
268 } else if (type == "coarse") {
269 return CoarseGrid.at(element);
270 } else if (type == "xcoarse") {
271 return XcoarseGrid.at(element);
272 } else if (type == "fine") {
273 return FineGrid.at(element);
274 } else if (type == "xfine") {
275 return XfineGrid.at(element);
276 }
277 throw std::runtime_error("Grid type " + type + " is not implemented");
278 return -1;
279}
280} // namespace xtp
281} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
const std::vector< const AOShell * > getShellsofAtom(Index AtomId) const
Definition aobasis.cc:63
const std::vector< Index > & getFuncPerAtom() const
Definition aobasis.h:72
void Fill(const AOBasis &aobasis) final
const Eigen::MatrixXd & Matrix() const
Definition aomatrix.h:52
std::vector< double > CalculatePruningIntervals(const std::string &element)
std::map< std::string, GridContainers::radial_grid > CalculateAtomicRadialGrids(const AOBasis &aobasis, const QMMolecule &atoms, const std::string &type)
std::map< std::string, Index > pruning_set_
void FillElementRangeMap(const AOBasis &aobasis, const QMMolecule &atoms, double eps)
Index getGridParameters(const std::string &element, const std::string &type)
std::map< std::string, Index > FineGrid
GridContainers::radial_grid CalculateRadialGridforAtom(const std::string &type, const std::pair< std::string, min_exp > &element)
double DetermineCutoff(double alpha, Index l, double eps)
std::map< std::string, double > Accuracy
std::map< std::string, Index > CoarseGrid
void CalculateRadialCutoffs(const AOBasis &aobasis, const QMMolecule &atoms, const std::string &gridtype)
std::map< std::string, min_exp > element_ranges_
void RefineElementRangeMap(const AOBasis &aobasis, const QMMolecule &atoms, double eps)
double CalcResidual(double alpha, Index l, double cutoff)
std::map< std::string, Index > XcoarseGrid
std::map< std::string, double > BraggSlaterRadii_
double RadialIntegral(double alpha, Index l, double cutoff)
std::map< std::string, Index > MediumGrid
std::map< std::string, Index > XfineGrid
container for QM atoms
Definition qmatom.h:37
const Eigen::Vector3d & getPos() const
Definition qmatom.h:55
const std::string & getElement() const
Definition qmatom.h:63
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26