[cceb8c] | 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 |
|
---|
[62d092] | 39 | #include "CodePatterns/Log.hpp"
|
---|
[cceb8c] | 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;
|
---|
[62d092] | 71 | vals = new double[VMG::Helper::intpow(2*nfc+1,3)];
|
---|
[cceb8c] | 72 |
|
---|
| 73 | // recalculate spline values
|
---|
| 74 | unsigned int c=0;
|
---|
| 75 | int_val = 0.;
|
---|
[62d092] | 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;
|
---|
[cceb8c] | 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;
|
---|
[62d092] | 92 | LOG(4, "DEBUG: Spline evaluated at " << distance << " is " << temp_val);
|
---|
[cceb8c] | 93 | }
|
---|
| 94 |
|
---|
| 95 | /// then integrate
|
---|
[62d092] | 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;
|
---|
[cceb8c] | 135 | }
|
---|
| 136 |
|
---|
| 137 | void ChargeSmearer::operator()(
|
---|
| 138 | VMG::Grid& _grid,
|
---|
| 139 | const VMG::GridIterator &_iter,
|
---|
| 140 | const double _charge) const
|
---|
| 141 | {
|
---|
[62d092] | 142 | // check whether we go over whole bspline support
|
---|
| 143 | bool renormalize = false;
|
---|
[cceb8c] | 144 | for (int dim=0;dim<3;++dim) {
|
---|
[62d092] | 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;
|
---|
[cceb8c] | 157 | }
|
---|
| 158 |
|
---|
| 159 | /// then transfer to grid in bounded window
|
---|
[62d092] | 160 | {
|
---|
| 161 | const visitor_t setter = boost::bind(SplineSetter, _1, _2, temp_int_val * _charge, boost::ref(_grid));
|
---|
| 162 | visitBSplineDomain(_iter, setter);
|
---|
| 163 | }
|
---|
[cceb8c] | 164 | }
|
---|
| 165 |
|
---|
| 166 | CONSTRUCT_SINGLETON(ChargeSmearer)
|
---|