votca 2024.1-dev
Loading...
Searching...
No Matches
vxc_grid.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 "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Local VOTCA includes
21#include "votca/xtp/vxc_grid.h"
27
28namespace votca {
29namespace xtp {
30
32 const std::vector<std::vector<GridContainers::Cartesian_gridpoint> >&
33 grid) {
34 constexpr double boxsize = 1; // 1 bohr
35
36 Eigen::Array3d min =
37 Eigen::Array3d::Ones() * std::numeric_limits<double>::max();
38 Eigen::Array3d max =
39 Eigen::Array3d::Ones() * std::numeric_limits<double>::min();
40
41 for (const auto& atom_grid : grid) {
42 for (const auto& gridpoint : atom_grid) {
43 const Eigen::Vector3d& pos = gridpoint.grid_pos;
44 max = max.max(pos.array()).eval();
45 min = min.min(pos.array()).eval();
46 }
47 }
48
49 Eigen::Array3d molextension = max - min;
50 Eigen::Array<Index, 3, 1> numberofboxes =
51 (molextension / boxsize).ceil().cast<Index>();
52
54 boxes(numberofboxes.x(), numberofboxes.y(), numberofboxes.z());
55
56 for (const auto& atomgrid : grid) {
57 for (const auto& gridpoint : atomgrid) {
58 Eigen::Array3d pos = gridpoint.grid_pos - min.matrix();
59 Eigen::Array<Index, 3, 1> index = (pos / boxsize).floor().cast<Index>();
60 boxes(index.x(), index.y(), index.z()).push_back(&gridpoint);
61 }
62 }
63 for (auto& box : boxes) {
64 if (box.empty()) {
65 continue;
66 }
67 GridBox gridbox;
68 for (const auto& point : box) {
69 gridbox.addGridPoint(*point);
70 }
71 grid_boxes_.push_back(gridbox);
72 }
73 return;
74}
75
77
78#pragma omp parallel for
79 for (Index i = 0; i < getBoxesSize(); i++) {
80 grid_boxes_[i].FindSignificantShells(basis);
81 }
82
83 std::vector<GridBox> grid_boxes_copy;
84 // use vector of bool to indicate if a gridbox has already been merged into
85 // another
86 std::vector<bool> Merged = std::vector<bool>(grid_boxes_.size(), false);
87 for (Index i = 0; i < Index(grid_boxes_.size()); i++) {
88 if (Merged[i]) {
89 continue;
90 }
91 GridBox box = grid_boxes_[i];
92 if (box.Shellsize() < 1) {
93 continue;
94 }
95 Merged[i] = true;
96 for (Index j = i + 1; j < Index(grid_boxes_.size()); j++) {
98 Merged[j] = true;
99 box.addGridBox(grid_boxes_[j]);
100 }
101 }
102 grid_boxes_copy.push_back(box);
103 }
104
105 totalgridsize_ = 0;
106 for (auto& box : grid_boxes_copy) {
107 totalgridsize_ += box.size();
108 box.PrepareForIntegration();
109 }
110 grid_boxes_ = grid_boxes_copy;
111}
112
113std::vector<const Eigen::Vector3d*> Vxc_Grid::getGridpoints() const {
114 std::vector<const Eigen::Vector3d*> gridpoints;
115 gridpoints.reserve(this->getGridSize());
116 for (const auto& box : grid_boxes_) {
117 const std::vector<Eigen::Vector3d>& points = box.getGridPoints();
118 for (const Eigen::Vector3d& point : points) {
119 gridpoints.push_back(&point);
120 }
121 }
122 return gridpoints;
123}
124
125Eigen::MatrixXd Vxc_Grid::CalcInverseAtomDist(const QMMolecule& atoms) const {
126 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(atoms.size(), atoms.size());
127#pragma omp parallel for
128 for (Index i = 0; i < atoms.size(); ++i) {
129 const Eigen::Vector3d& pos_a = atoms[i].getPos();
130 for (Index j = 0; j < i; ++j) {
131 const Eigen::Vector3d& pos_b = atoms[j].getPos();
132 result(j, i) = 1 / (pos_a - pos_b).norm();
133 }
134 }
135 return result + result.transpose();
136}
137
138Index Vxc_Grid::UpdateOrder(LebedevGrid& sphericalgridofElement, Index maxorder,
139 std::vector<double>& PruningIntervals,
140 double r) const {
141 Index order;
142 Index maxindex = sphericalgridofElement.getIndexFromOrder(maxorder);
143 if (maxindex == 1) {
144 // smallest possible grid anyway, nothing to do
145 order = maxorder;
146 } else if (maxindex == 2) {
147 // only three intervals
148 if (r < PruningIntervals[0]) {
149 order = sphericalgridofElement.getOrderFromIndex(1); // 1;
150 } else if ((r >= PruningIntervals[0]) && (r < PruningIntervals[3])) {
151 order = sphericalgridofElement.getOrderFromIndex(2);
152 } else {
153 order = sphericalgridofElement.getOrderFromIndex(1);
154 } // maxorder == 2
155 } else {
156 // five intervals
157 if (r < PruningIntervals[0]) {
158 order = sphericalgridofElement.getOrderFromIndex(2);
159 } else if ((r >= PruningIntervals[0]) && (r < PruningIntervals[1])) {
160 order = sphericalgridofElement.getOrderFromIndex(4);
161 } else if ((r >= PruningIntervals[1]) && (r < PruningIntervals[2])) {
162 constexpr Index maximum = 4;
163 order = sphericalgridofElement.getOrderFromIndex(
164 std::max(maxindex - 1, maximum));
165 } else if ((r >= PruningIntervals[2]) && (r < PruningIntervals[3])) {
166 order = maxorder;
167 } else {
168 constexpr Index maximum = 1;
169 order = sphericalgridofElement.getOrderFromIndex(
170 std::max(maxindex - 1, maximum));
171 }
172 }
173 return order;
174}
175
177 const Eigen::Vector3d& atomA_pos, GridContainers::radial_grid& radial_grid,
178 GridContainers::spherical_grid& spherical_grid, Index i_rad,
179 Index i_sph) const {
181 double p = spherical_grid.phi[i_sph];
182 double t = spherical_grid.theta[i_sph];
183 const Eigen::Vector3d s =
184 Eigen::Vector3d{sin(p) * cos(t), sin(p) * sin(t), cos(p)};
185 double r = radial_grid.radius[i_rad];
186 gridpoint.grid_pos = atomA_pos + r * s;
187 gridpoint.grid_weight =
188 radial_grid.weight[i_rad] * spherical_grid.weight[i_sph];
189 return gridpoint;
190}
191
193 const QMMolecule& atoms,
194 std::vector<GridContainers::Cartesian_gridpoint>& atomgrid) const {
195 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(atoms.size(), atomgrid.size());
196#pragma omp parallel for
197 for (Index i = 0; i < atoms.size(); ++i) {
198 const Eigen::Vector3d& atom_pos = atoms[i].getPos();
199 for (Index j = 0; j < Index(atomgrid.size()); ++j) {
200 const auto& gridpoint = atomgrid[j];
201 result(i, j) = (atom_pos - gridpoint.grid_pos).norm();
202 }
203 }
204 return result;
205}
206
208 const QMMolecule& atoms,
209 std::vector<GridContainers::Cartesian_gridpoint>& atomgrid, Index i_atom,
210 const Eigen::MatrixXd& Rij) const {
211 Eigen::MatrixXd AtomGridDist = CalcDistanceAtomsGridpoints(atoms, atomgrid);
212
213#pragma omp parallel for schedule(guided)
214 for (Index i_grid = 0; i_grid < Index(atomgrid.size()); i_grid++) {
215 Eigen::VectorXd p = SSWpartition(AtomGridDist.col(i_grid), Rij);
216 // check weight sum
217 double wsum = p.sum();
218 if (wsum != 0.0) {
219 // update the weight of this grid point
220 atomgrid[i_grid].grid_weight *= p[i_atom] / wsum;
221 } else {
222 std::cerr << "\nSum of partition weights of grid point " << i_grid
223 << " of atom " << i_atom << " is zero! ";
224 throw std::runtime_error("\nThis should never happen!");
225 }
226 } // partition weight for each gridpoint
227}
228
229void Vxc_Grid::GridSetup(const std::string& type, const QMMolecule& atoms,
230 const AOBasis& basis) {
231 GridContainers initialgrids;
232 // get radial grid per element
233 EulerMaclaurinGrid radialgridofElement;
234 initialgrids.radial_grids = radialgridofElement.CalculateAtomicRadialGrids(
235 basis, atoms, type); // this checks out 1:1 with NWChem results! AWESOME
236 LebedevGrid sphericalgridofElement;
237 initialgrids.spherical_grids =
238 sphericalgridofElement.CalculateSphericalGrids(atoms, type);
239
240 // for the partitioning, we need all inter-center distances later, stored in
241 // matrix
242 Eigen::MatrixXd Rij = CalcInverseAtomDist(atoms);
243 std::vector<std::vector<GridContainers::Cartesian_gridpoint> > grid;
244
245 for (Index i_atom = 0; i_atom < atoms.size(); ++i_atom) {
246 const QMAtom& atom = atoms[i_atom];
247
248 const Eigen::Vector3d& atomA_pos = atom.getPos();
249 const std::string& name = atom.getElement();
250 GridContainers::radial_grid radial_grid =
251 initialgrids.radial_grids.at(name);
252 GridContainers::spherical_grid spherical_grid =
253 initialgrids.spherical_grids.at(name);
254
255 // maximum order (= number of points) in spherical integration grid
256 Index maxorder = sphericalgridofElement.Type2MaxOrder(name, type);
257 // for pruning of integration grid, get interval boundaries for this element
258 std::vector<double> PruningIntervals =
259 radialgridofElement.CalculatePruningIntervals(name);
260 Index current_order = 0;
261 // for each radial value
262 std::vector<GridContainers::Cartesian_gridpoint> atomgrid;
263 for (Index i_rad = 0; i_rad < radial_grid.radius.size(); i_rad++) {
264 double r = radial_grid.radius[i_rad];
265
266 // which Lebedev order for this point?
267 Index order =
268 UpdateOrder(sphericalgridofElement, maxorder, PruningIntervals, r);
269 // get new spherical grid, if order changed
270 if (order != current_order) {
271 spherical_grid = sphericalgridofElement.CalculateUnitSphereGrid(order);
272 current_order = order;
273 }
274
275 for (Index i_sph = 0; i_sph < spherical_grid.phi.size(); i_sph++) {
277 CreateCartesianGridpoint(atomA_pos, radial_grid, spherical_grid,
278 i_rad, i_sph);
279 atomgrid.push_back(gridpoint);
280 } // spherical gridpoints
281 } // radial gridpoint
282
283 SSWpartitionAtom(atoms, atomgrid, i_atom, Rij);
284 // now remove points from the grid with negligible weights
285 std::vector<GridContainers::Cartesian_gridpoint> atomgrid_cleanedup;
286 for (const auto& point : atomgrid) {
287 if (point.grid_weight > 1e-13) {
288 atomgrid_cleanedup.push_back(point);
289 }
290 }
291 grid.push_back(atomgrid_cleanedup);
292 } // atoms
295 return;
296}
297
298Eigen::VectorXd Vxc_Grid::SSWpartition(const Eigen::VectorXd& rq_i,
299 const Eigen::MatrixXd& Rij) const {
300 const double ass = 0.725;
301 // initialize partition vector to 1.0
302 Eigen::VectorXd p = Eigen::VectorXd::Ones(rq_i.size());
303 const double tol_scr = 1e-10;
304 const double leps = 1e-6;
305 // go through centers
306 for (Index i = 1; i < rq_i.size(); i++) {
307 double rag = rq_i(i);
308 // through all other centers (one-directional)
309 for (Index j = 0; j < i; j++) {
310 if ((std::abs(p[i]) > tol_scr) || (std::abs(p[j]) > tol_scr)) {
311 double mu = (rag - rq_i(j)) * Rij(j, i);
312 if (mu > ass) {
313 p[i] = 0.0;
314 } else if (mu < -ass) {
315 p[j] = 0.0;
316 } else {
317 double sk;
318 if (std::abs(mu) < leps) {
319 sk = -1.88603178008 * mu + 0.5;
320 } else {
321 sk = erf1c(mu);
322 }
323 if (mu > 0.0) {
324 sk = 1.0 - sk;
325 }
326 p[j] = p[j] * sk;
327 p[i] = p[i] * (1.0 - sk);
328 }
329 }
330 }
331 }
332 return p;
333}
334
335double Vxc_Grid::erf1c(double x) const {
336 const static double alpha_erf1 = 1.0 / 0.30;
337 return 0.5 * std::erfc(std::abs(x / (1.0 - x * x)) * alpha_erf1);
338}
339
340} // namespace xtp
341} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
const Eigen::Vector3d & getPos() const
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)
void addGridBox(const GridBox &box)
Definition gridbox.h:57
static bool compareGridboxes(GridBox &box1, GridBox &box2)
Definition gridbox.h:82
Index Shellsize() const
Definition gridbox.h:53
void addGridPoint(const GridContainers::Cartesian_gridpoint &point)
Definition gridbox.h:63
std::map< std::string, radial_grid > radial_grids
std::map< std::string, spherical_grid > spherical_grids
Index getIndexFromOrder(Index order) const
Index getOrderFromIndex(Index index) const
std::map< std::string, GridContainers::spherical_grid > CalculateSphericalGrids(const QMMolecule &atoms, const std::string &type) const
Index Type2MaxOrder(const std::string &element, const std::string &type) const
GridContainers::spherical_grid CalculateUnitSphereGrid(const std::string &element, const std::string &type) const
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
void FindSignificantShells(const AOBasis &basis)
Definition vxc_grid.cc:76
GridContainers::Cartesian_gridpoint CreateCartesianGridpoint(const Eigen::Vector3d &atomA_pos, GridContainers::radial_grid &radial_grid, GridContainers::spherical_grid &spherical_grid, Index i_rad, Index i_sph) const
Definition vxc_grid.cc:176
Eigen::VectorXd SSWpartition(const Eigen::VectorXd &rq_i, const Eigen::MatrixXd &Rij) const
Definition vxc_grid.cc:298
Index getGridSize() const
Definition vxc_grid.h:41
std::vector< GridBox > grid_boxes_
Definition vxc_grid.h:89
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Definition vxc_grid.cc:229
Index getBoxesSize() const
Definition vxc_grid.h:42
Index UpdateOrder(LebedevGrid &sphericalgridofElement, Index maxorder, std::vector< double > &PruningIntervals, double r) const
Definition vxc_grid.cc:138
void SortGridpointsintoBlocks(const std::vector< std::vector< GridContainers::Cartesian_gridpoint > > &grid)
Definition vxc_grid.cc:31
std::vector< const Eigen::Vector3d * > getGridpoints() const
Definition vxc_grid.cc:113
Eigen::MatrixXd CalcDistanceAtomsGridpoints(const QMMolecule &atoms, std::vector< GridContainers::Cartesian_gridpoint > &atomgrid) const
Definition vxc_grid.cc:192
void SSWpartitionAtom(const QMMolecule &atoms, std::vector< GridContainers::Cartesian_gridpoint > &atomgrid, Index i_atom, const Eigen::MatrixXd &Rij) const
Definition vxc_grid.cc:207
Eigen::MatrixXd CalcInverseAtomDist(const QMMolecule &atoms) const
Definition vxc_grid.cc:125
double erf1c(double x) const
Definition vxc_grid.cc:335
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26