1 | /*
|
---|
2 | * Project: MoleCuilder
|
---|
3 | * Description: creates and alters molecular systems
|
---|
4 | * Copyright (C) 2015 Frederik Heber. All rights reserved.
|
---|
5 | *
|
---|
6 | *
|
---|
7 | * This file is part of MoleCuilder.
|
---|
8 | *
|
---|
9 | * MoleCuilder is free software: you can redistribute it and/or modify
|
---|
10 | * it under the terms of the GNU General Public License as published by
|
---|
11 | * the Free Software Foundation, either version 2 of the License, or
|
---|
12 | * (at your option) any later version.
|
---|
13 | *
|
---|
14 | * MoleCuilder is distributed in the hope that it will be useful,
|
---|
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
17 | * GNU General Public License for more details.
|
---|
18 | *
|
---|
19 | * You should have received a copy of the GNU General Public License
|
---|
20 | * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
|
---|
21 | */
|
---|
22 |
|
---|
23 | /*
|
---|
24 | * ChargeSmearer.cpp
|
---|
25 | *
|
---|
26 | * Created on: Sep 2, 2015
|
---|
27 | * Author: heber
|
---|
28 | */
|
---|
29 |
|
---|
30 | // include config.h
|
---|
31 | #ifdef HAVE_CONFIG_H
|
---|
32 | #include <config.h>
|
---|
33 | #endif
|
---|
34 |
|
---|
35 | #include "CodePatterns/MemDebug.hpp"
|
---|
36 |
|
---|
37 | #include "ChargeSmearer.hpp"
|
---|
38 |
|
---|
39 | #include "CodePatterns/Log.hpp"
|
---|
40 | #include "CodePatterns/Singleton_impl.hpp"
|
---|
41 |
|
---|
42 | #include <base/helper.hpp>
|
---|
43 | #include <base/index.hpp>
|
---|
44 | #include <units/particle/bspline.hpp>
|
---|
45 |
|
---|
46 | ChargeSmearer::ChargeSmearer() :
|
---|
47 | nfc(0),
|
---|
48 | meshwidth(0.),
|
---|
49 | vals(NULL),
|
---|
50 | int_val(0.)
|
---|
51 | {}
|
---|
52 |
|
---|
53 | ChargeSmearer::~ChargeSmearer()
|
---|
54 | {
|
---|
55 | delete[] vals;
|
---|
56 | }
|
---|
57 |
|
---|
58 | void ChargeSmearer::initializeSplineArray(
|
---|
59 | const VMG::Particle::BSpline &_spl,
|
---|
60 | const unsigned int _nfc,
|
---|
61 | const double _meshwidth)
|
---|
62 | {
|
---|
63 | // check whether it is changed, if not, do nothing
|
---|
64 | if ((nfc == _nfc) && (meshwidth == _meshwidth))
|
---|
65 | return;
|
---|
66 | nfc = _nfc;
|
---|
67 | meshwidth = _meshwidth;
|
---|
68 |
|
---|
69 | // reallocate memory for spline values
|
---|
70 | delete[] vals;
|
---|
71 | vals = new double[VMG::Helper::intpow(2*nfc+1,3)];
|
---|
72 |
|
---|
73 | // recalculate spline values
|
---|
74 | unsigned int c=0;
|
---|
75 | int_val = 0.;
|
---|
76 | std::pair<int, int> bounds[3];
|
---|
77 | for (int dim=0;dim<3;++dim) {
|
---|
78 | bounds[dim].first = -1*nfc;
|
---|
79 | bounds[dim].second = nfc;
|
---|
80 | }
|
---|
81 | for (int i=bounds[0].first; i<=bounds[0].second; ++i)
|
---|
82 | for (int j=bounds[1].first; j<=bounds[1].second; ++j)
|
---|
83 | for (int k=bounds[2].first; k<=bounds[2].second; ++k) {
|
---|
84 | const double dir_x = (double)i*meshwidth;
|
---|
85 | const double dir_y = (double)j*meshwidth;
|
---|
86 | const double dir_z = (double)k*meshwidth;
|
---|
87 | // Compute distance from grid point to particle
|
---|
88 | const double distance = std::sqrt(dir_x*dir_x+dir_y*dir_y+dir_z*dir_z);
|
---|
89 | const double temp_val = _spl.EvaluateSpline(distance);
|
---|
90 | vals[c++] = temp_val;
|
---|
91 | int_val += temp_val;
|
---|
92 | LOG(4, "DEBUG: Spline evaluated at " << distance << " is " << temp_val);
|
---|
93 | }
|
---|
94 |
|
---|
95 | /// then integrate
|
---|
96 | int_val = 1.0 / int_val;
|
---|
97 |
|
---|
98 | LOG(3, "DEBUG: Spline for smearing electronic charge distribution has norm factor of " << int_val);
|
---|
99 | }
|
---|
100 |
|
---|
101 | void ChargeSmearer::visitBSplineDomain(
|
---|
102 | const VMG::GridIterator &_iter,
|
---|
103 | const visitor_t &_visitor
|
---|
104 | ) const
|
---|
105 | {
|
---|
106 | unsigned int c = 0;
|
---|
107 | VMG::Index index;
|
---|
108 | const VMG::Index end = _iter.GetIndex() + (int)nfc;
|
---|
109 | for (index[0] = _iter.GetIndex()[0] - (int)nfc; index[0]<=end[0]; ++index[0])
|
---|
110 | for (index[1] = _iter.GetIndex()[1] - (int)nfc; index[1]<=end[1]; ++index[1])
|
---|
111 | for (index[2] = _iter.GetIndex()[2] - (int)nfc; index[2]<=end[2]; ++index[2]) {
|
---|
112 | if (index.IsInBounds(_iter.GetBegin(), _iter.GetEnd()))
|
---|
113 | _visitor(index, vals[c++]);
|
---|
114 | else
|
---|
115 | ++c;
|
---|
116 | }
|
---|
117 | assert( c == (unsigned int)VMG::Helper::intpow(2*nfc+1,3) );
|
---|
118 | }
|
---|
119 |
|
---|
120 | static void DomainIntegrator(
|
---|
121 | const VMG::Index & _index,
|
---|
122 | const double _val,
|
---|
123 | double &_int_val)
|
---|
124 | {
|
---|
125 | _int_val += _val;
|
---|
126 | }
|
---|
127 |
|
---|
128 | static void SplineSetter(
|
---|
129 | const VMG::Index & _index,
|
---|
130 | const double _val,
|
---|
131 | const double _factor,
|
---|
132 | VMG::Grid& _grid)
|
---|
133 | {
|
---|
134 | _grid(_index) += _val * _factor;
|
---|
135 | }
|
---|
136 |
|
---|
137 | void ChargeSmearer::operator()(
|
---|
138 | VMG::Grid& _grid,
|
---|
139 | const VMG::GridIterator &_iter,
|
---|
140 | const double _charge) const
|
---|
141 | {
|
---|
142 | // check whether we go over whole bspline support
|
---|
143 | bool renormalize = false;
|
---|
144 | for (int dim=0;dim<3;++dim) {
|
---|
145 | renormalize |= (_iter.GetBegin()[dim] > _iter.GetIndex()[dim] - (int)nfc);
|
---|
146 | renormalize |= (_iter.GetEnd()[dim] < _iter.GetIndex()[dim] + (int)nfc);
|
---|
147 | }
|
---|
148 |
|
---|
149 | /// renormalize bspline if necessary (bounds don't fit in window)
|
---|
150 | double temp_int_val = 0.;
|
---|
151 | if (renormalize) {
|
---|
152 | const visitor_t integrator = boost::bind(DomainIntegrator, _1, _2, boost::ref(temp_int_val));
|
---|
153 | visitBSplineDomain(_iter, integrator);
|
---|
154 | temp_int_val = 1.0 / temp_int_val;
|
---|
155 | } else {
|
---|
156 | temp_int_val = int_val;
|
---|
157 | }
|
---|
158 |
|
---|
159 | /// then transfer to grid in bounded window
|
---|
160 | {
|
---|
161 | const visitor_t setter = boost::bind(SplineSetter, _1, _2, temp_int_val * _charge, boost::ref(_grid));
|
---|
162 | visitBSplineDomain(_iter, setter);
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | CONSTRUCT_SINGLETON(ChargeSmearer)
|
---|