8 #include "MdSpmePotential.h" 9 #include <mcMd/simulation/System.h> 10 #include <mcMd/simulation/Simulation.h> 11 #include <mcMd/chemistry/AtomType.h> 13 #include <simp/boundary/Boundary.h> 15 #include <util/space/Vector.h> 16 #include <util/space/Tensor.h> 17 #include <util/math/Constants.h> 18 #include <util/containers/Array.h> 35 simulationPtr_(&system.simulation()),
37 boundaryPtr_(&system.boundary()),
38 atomTypesPtr_(&system.simulation().atomTypes()),
58 fftw_destroy_plan(forward_plan);
59 fftw_destroy_plan(xfield_backward_plan);
60 fftw_destroy_plan(yfield_backward_plan);
61 fftw_destroy_plan(zfield_backward_plan);
70 bool nextIndent =
false;
73 read<IntVector>(in,
"gridDimensions", gridDimensions_);
82 bool nextIndent =
false;
85 loadParameter<IntVector>(ar,
"gridDimensions", gridDimensions_);
94 ewaldInteraction_.
save(ar);
95 ar << gridDimensions_;
103 ewaldInteraction_.
set(name, value);
113 value = ewaldInteraction_.
get(name);
122 {
return gridDimensions_[0]*gridDimensions_[1]*gridDimensions_[2]; }
130 if (g_.
size() == 0) {
141 void MdSpmePotential::setGridDimensions()
148 vecWaves_.allocate(gridDimensions_);
156 inf =
reinterpret_cast<fftw_complex*
>(rhoR_.data());
157 outf =
reinterpret_cast<fftw_complex*
>(rhoK_.data());
158 forward_plan = fftw_plan_dft_3d(gridDimensions_[0],
162 FFTW_FORWARD,FFTW_MEASURE);
167 inxf =
reinterpret_cast<fftw_complex*
>(xfield_.data());
168 outxf =
reinterpret_cast<fftw_complex*
>(xfield_.data());
169 xfield_backward_plan =
170 fftw_plan_dft_3d(gridDimensions_[0],
173 inxf, outxf,FFTW_BACKWARD, FFTW_MEASURE);
176 inyf =
reinterpret_cast<fftw_complex*
>(yfield_.data());
177 outyf =
reinterpret_cast<fftw_complex*
>(yfield_.data());
178 yfield_backward_plan =
179 fftw_plan_dft_3d(gridDimensions_[0],
182 inyf, outyf,FFTW_BACKWARD, FFTW_MEASURE);
185 inzf =
reinterpret_cast<fftw_complex*
>(zfield_.data());
186 outzf =
reinterpret_cast<fftw_complex*
>(zfield_.data());
187 zfield_backward_plan =
188 fftw_plan_dft_3d(gridDimensions_[0],
191 inzf, outzf,FFTW_BACKWARD, FFTW_MEASURE);
203 for (
int i = 0; i < grid.
dimension(0); ++i) {
205 for (
int j = 0; j < grid.
dimension(1); ++j) {
207 for (
int k = 0; k < grid.
dimension(2); ++k) {
218 void MdSpmePotential::computeWaves()
234 for (i = 0; i < gridDimensions_[0]; ++i) {
236 m0 = (i <= gridDimensions_[0]/2) ? i : i - gridDimensions_[0];
239 for (j = 0; j < gridDimensions_[1]; ++j) {
241 m1 = (j <= gridDimensions_[1]/2) ? j : j - gridDimensions_[1];
245 for (k = 0; k < gridDimensions_[2]; ++k) {
247 m2 = (k <= gridDimensions_[2]/2) ? k : k - gridDimensions_[2];
255 b = bfactor(i, 0) * bfactor(j, 1) *bfactor(k, 2);
270 double MdSpmePotential::bfactor(
double m,
int dim)
274 if (order_%2 == 1 && m == gridDimensions_[dim]/2) {
279 double gridDimensions(gridDimensions_[dim]);
281 DCMPLX denom(0.0, 0.0);
282 for (
double k = 0.0; k <= order_ - 2.0; k++) {
283 denom += basisSpline(k + 1.0)*exp(2.0 * pi * I * m * k / gridDimensions) ;
285 return std::norm(exp(2.0 * pi * I * (order_ -1.0) * m/gridDimensions) / denom);
291 void MdSpmePotential::assignCharges()
300 double xdistance, ydistance, zdistance;
304 int ximg, yimg, zimg;
305 int xknot, yknot, zknot;
307 setGridToZero(rhoR_);
310 int nSpecies = simulationPtr_->
nSpecies();
311 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
312 systemPtr_->
begin(iSpecies, molIter);
313 for ( ; molIter.
notEnd(); ++molIter) {
314 for (molIter->begin(atomIter); atomIter.
notEnd(); ++atomIter) {
315 charge = (*atomTypesPtr_)[atomIter->typeId()].charge();
322 floorGridIdx[0]=floor(gpos[0]*gridDimensions_[0]);
323 floorGridIdx[1]=floor(gpos[1]*gridDimensions_[1]);
324 floorGridIdx[2]=floor(gpos[2]*gridDimensions_[2]);
329 for (
int x = 0 ; x < order_ ; ++x) {
330 ximg = floorGridIdx[0] + x - (order_ - 1);
331 xdistance = (gpos[0]*gridDimensions_[0]-ximg);
332 xknot = ximg < 0 ? ximg + gridDimensions_[0] : ximg;
335 for (
int y = 0 ; y < order_ ; ++y) {
336 yimg = floorGridIdx[1] + y - (order_ - 1);
337 ydistance = (gpos[1]*gridDimensions_[1]-yimg) ;
338 yknot = yimg < 0 ? yimg + gridDimensions_[1] : yimg;
341 for (
int z = 0; z < order_; ++z) {
342 zimg = floorGridIdx[2] + z - (order_ - 1);
343 zdistance = (gpos[2]*gridDimensions_[2]-zimg) ;
344 zknot = zimg < 0 ? zimg + gridDimensions_[2] : zimg;
347 rhoR_(knot) += charge
348 * basisSpline(xdistance)
349 * basisSpline(ydistance)
350 * basisSpline(zdistance);
362 double MdSpmePotential::basisSpline(
double x)
364 if (0.0 < x && x < 1.0)
365 return 1.0 / 24.0 * x * x * x *x;
366 else if (1.0 <= x && x < 2.0)
367 return -5.0/24.0 + (5.0/6.0 + (-5.0/4.0 + (5.0 / 6.0 -1.0/6.0*x) *x) *x) *x;
368 else if (2.0 <= x && x < 3.0)
369 return 155.0/24.0 + (-25.0/2.0 + (35.0/4.0 + (-5.0/2.0 +1.0/4.0*x)*x)*x)*x;
370 else if (3.0 <= x && x < 4.0)
371 return -655.0/24.0 + (65.0/2.0 + ( -55.0/4.0 + (5.0/2.0 - 1.0/6.0*x)*x)*x)*x;
372 else if (4.0 <= x && x < 5.0)
373 return 625.0/24.0 + (-125.0/6.0 + (25.0/4.0 + (-5.0/6.0 + 1/24.0 *x)*x)*x)*x;
384 setGridToZero(rhoK_);
385 fftw_execute(forward_plan);
390 for (
int rank = 0 ; rank < g_.
size() ; ++rank) {
391 qv = vecWaves_[rank];
392 xfield_[rank] = ci*qv[0]*rhoK_[rank]*g_[rank];
393 yfield_[rank] = ci*qv[1]*rhoK_[rank]*g_[rank];
394 zfield_[rank] = ci*qv[2]*rhoK_[rank]*g_[rank];
398 fftw_execute(xfield_backward_plan);
399 fftw_execute(yfield_backward_plan);
400 fftw_execute(zfield_backward_plan);
405 Vector floorGridIdx, gpos;
408 double xdistance, ydistance, zdistance;
409 double EPS = 1.0E-10;
412 int ximg, yimg, zimg;
413 int xknot, yknot, zknot;
416 int nSpecies(simulationPtr_->
nSpecies());
417 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
418 systemPtr_->
begin(iSpecies, molIter);
419 for ( ; molIter.
notEnd(); ++molIter) {
420 for (molIter->begin(atomIter); atomIter.
notEnd(); ++atomIter) {
421 type = atomIter->typeId();
422 charge = (*atomTypesPtr_)[type].charge();
425 if( fabs(charge) > EPS) {
432 floorGridIdx[0]=floor(gpos[0]*gridDimensions_[0]);
433 floorGridIdx[1]=floor(gpos[1]*gridDimensions_[1]);
434 floorGridIdx[2]=floor(gpos[2]*gridDimensions_[2]);
438 for (
int x = 0 ; x < order_ ; ++x) {
439 ximg = floorGridIdx[0] + x - (order_ - 1);
440 xdistance = (gpos[0]*gridDimensions_[0]-ximg) ;
441 xknot = ximg < 0 ? ximg + gridDimensions_[0] : ximg;
444 for (
int y = 0 ; y < order_ ; ++y) {
445 yimg = floorGridIdx[1] + y - (order_ - 1);
446 ydistance = (gpos[1]*gridDimensions_[1]-yimg) ;
447 yknot = yimg < 0 ? yimg + gridDimensions_[1] : yimg;
450 for (
int z = 0; z < order_; ++z) {
451 zimg = floorGridIdx[2] + z - (order_ - 1);
452 zdistance = (gpos[2]*gridDimensions_[2]-zimg) ;
453 zknot = zimg < 0 ? zimg + gridDimensions_[2] : zimg;
456 fatom[0] +=basisSpline(xdistance)
457 *basisSpline(ydistance)
458 *basisSpline(zdistance)
459 *std::real(xfield_(knot));
460 fatom[1] +=basisSpline(xdistance)
461 *basisSpline(ydistance)
462 *basisSpline(zdistance)
463 *std::real(yfield_(knot));
464 fatom[2] +=basisSpline(xdistance)
465 *basisSpline(ydistance)
466 *basisSpline(zdistance)
467 *std::real(zfield_(knot));
471 fatom *= -1.0*charge;
472 atomIter->force() += fatom;
485 setGridToZero(rhoK_);
486 fftw_execute(forward_plan);
490 for (
int i = 0; i < g_.
size(); ++i) {
491 energy += g_[i] * std::norm(rhoK_[i]);
493 double volume = boundaryPtr_->
volume();
494 energy /= 2.0*volume;
500 double selfEnergy = 0.0;
501 int nSpecies = simulationPtr_->
nSpecies();
502 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
503 systemPtr_->
begin(iSpecies, molIter);
504 for ( ; molIter.
notEnd(); ++molIter) {
505 molIter->begin(atomIter);
506 for ( ; atomIter.
notEnd(); ++atomIter) {
507 charge = (*atomTypesPtr_)[atomIter->typeId()].charge();
508 selfEnergy += charge*charge;
513 double alpha = ewaldInteraction_.
alpha();
514 double epsilon = ewaldInteraction_.
epsilon();
515 selfEnergy *= alpha/(4.0*sqrt(pi)*pi*epsilon);
516 energy -= selfEnergy;
527 setGridToZero(rhoK_);
528 fftw_execute(forward_plan);
532 double alpha = ewaldInteraction_.
alpha();
533 double ca = 0.25/(alpha*alpha);
538 for (
int i = 0; i < g_.
size(); ++i) {
543 K *= -2.0 * (ca + (1.0/qSq));
545 K *= g_[i]*std::norm(rhoK_[i]);
549 double volume = boundaryPtr_->
volume();
550 stress /= 2.0*volume*volume;
Vector & zero()
Set all elements of a 3D vector to zero.
Coulomb potential for an Md simulation.
virtual ~MdSpmePotential()
Destructor (destroy fftw plan).
int size() const
Get total number of grid points.
double kSpacePotential(double kSq) const
Return regularized Fourier-space potential.
void shiftGen(Vector &r) const
Shift generalized Vector r to its primary image.
Setable< double > kSpaceEnergy_
K-space part of Coulomb energy.
A Vector is a Cartesian vector.
int dimension(int i) const
Get number of grid points along direction i.
void begin(int speciesId, MoleculeIterator &iterator)
Initialize an iterator for molecules of one species in this System.
bool notEnd() const
Is the current pointer not at the end of the array?
double volume() const
Return unit cell volume.
void set(const T &value)
Set the value and mark as set.
Vector & multiply(const Vector &v, double s)
Multiply a vector v by a scalar s.
Tensor & zero()
Set all elements of this tensor to zero.
A set of interacting Molecules enclosed by a Boundary.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
virtual int nWave() const
Total number of waves or grid points.
Classes used by all simpatico molecular simulations.
MdSpmePotential(System &system)
Constructor.
A Tensor represents a Cartesian tensor.
Tensor & add(const Tensor &t1, const Tensor &t2)
Add tensors t1 and t2.
Tensor stress()
Get total Coulomb stress.
Saving / output archive for binary ostream.
Setable< Tensor > kSpaceStress_
K-space part of Coulomb stress.
virtual void makeWaves()
Precompute waves and influence function.
void set(std::string name, double value)
Set a parameter value, identified by a string.
const Vector & reciprocalBasisVector(int i) const
Return reciprocal lattice basis vector i.
virtual void computeStress()
place holder.
double alpha() const
Get Ewald smearing parameter alpha (inverse length).
virtual void computeEnergy()
Calculate the long range kspace part of Coulomb energy.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
void allocate(const IntVector &dimensions)
Allocate memory for a matrix.
Forward iterator for an Array or a C array.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
Forward iterator for a PArray.
void set(std::string name, double value)
Modify a parameter, identified by a string.
double get(std::string name) const
Get a parameter value, identified by a string.
Saving archive for binary istream.
virtual void readParameters(std::istream &in)
Read parameters and initialize.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
double get(std::string name) const
Get a parameter value, identified by a string.
int nSpecies() const
Get the number of Species in this Simulation.
bool hasWaves_
Are waves and k-space potential up to date? Unset if boundary or parameters change.
void addParamComposite(ParamComposite &child, bool next=true)
Add a child ParamComposite object to the format array.
Multi-dimensional array with the dimensionality of space.
static const double Pi
Trigonometric constant Pi.
double epsilon() const
Get dielectric permittivity.
An IntVector is an integer Cartesian vector.
static const Tensor Identity
Constant idenity Tensor (diagonal diagonal elements all 1).
Tensor & dyad(const Vector &v1, const Vector &v2)
Create dyad of two vectors.
double energy()
Get total Coulomb energy.
static const std::complex< double > Im
Square root of -1.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
void unsetWaves()
Unset all data that depends on the Boundary.
double square() const
Return square magnitude of this vector.
void readParameters(std::istream &in)
Read epsilon, alpha, and rCutoff.
bool hasWaves()
Are wavevectors and k-space influence function up to date?
virtual void addForces()
Add k-space Coulomb forces for all atoms.
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Cartesian Vector to scaled / generalized coordinates.