1 #ifndef MD_EWALD_POTENTIAL_CPP 2 #define MD_EWALD_POTENTIAL_CPP 11 #include "MdEwaldPotential.h" 12 #include <mcMd/simulation/System.h> 13 #include <mcMd/simulation/Simulation.h> 14 #include <mcMd/chemistry/AtomType.h> 15 #include <simp/boundary/Boundary.h> 16 #include <util/space/Vector.h> 17 #include <util/space/Tensor.h> 18 #include <util/math/Constants.h> 19 #include <util/containers/Array.h> 36 simulationPtr_(&system.simulation()),
38 boundaryPtr_(&system.boundary()),
39 atomTypesPtr_(&system.simulation().atomTypes())
56 bool nextIndent =
false;
60 read<double>(in,
"kSpaceCutoff", kSpaceCutoff_);
68 bool nextIndent =
false;
72 loadParameter<double>(ar,
"kSpaceCutoff", kSpaceCutoff_);
80 ewaldInteraction_.
save(ar);
89 if (name ==
"kSpaceCutoff") {
90 kSpaceCutoff_ = value;
92 ewaldInteraction_.
set(name, value);
103 if (name ==
"kSpaceCutoff") {
104 value = kSpaceCutoff_;
106 value = ewaldInteraction_.
get(name);
115 {
return intWaves_.size(); }
147 if (intWaves_.capacity() == 0) {
149 capacity = ((2*maxK[0] + 1)*(2*maxK[1] + 1)*(2*maxK[2] + 1) - 1)/2;
151 intWaves_.reserve(capacity);
175 double kSpaceCutoffSq = kSpaceCutoff_*kSpaceCutoff_;
178 for (k[0] = 0; k[0] <= maxK[0]; ++k[0]) {
183 mink1 = (k[0] == 0 ? 0 : -maxK[1]);
186 for (k[1] = mink1; k[1] <= maxK[1]; ++k[1]) {
189 mink2 = (k[0] == 0 && k[1] == 0 ? 1 : -maxK[2]);
193 for (k[2] = mink2; k[2] <= maxK[2]; ++k[2]) {
197 if (ksq <= kSpaceCutoffSq) {
199 if (k[0] > upper0_) upper0_ = k[0];
201 if (k[1] < base1_ ) base1_ = k[1];
202 if (k[1] > upper1_) upper1_ = k[1];
204 if (k[2] < base2_ ) base2_ = k[2];
205 if (k[2] > upper2_) upper2_ = k[2];
221 rho_.
resize(intWaves_.size());
222 fexp0_.
resize(upper0_ - base0_ + 1);
223 fexp1_.
resize(upper1_ - base1_ + 1);
224 fexp2_.
resize(upper2_ - base2_ + 1);
233 void MdEwaldPotential::computeKSpaceCharge()
254 for (i = 0; i < rho_.
size(); ++i) {
255 rho_[i] = DCMPLX(0.0, 0.0);
259 int nSpecies = simulationPtr_->
nSpecies();
260 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
261 systemPtr_->
begin(iSpecies, molIter);
262 for ( ; molIter.
notEnd(); ++molIter) {
263 for (molIter->begin(atomIter); atomIter.
notEnd(); ++atomIter) {
265 charge = (*atomTypesPtr_)[atomIter->typeId()].charge();
268 for (i = 0; i < intWaves_.size(); ++i) {
271 qv[j] = double(q[j]);
273 dotqr = rg.
dot(qv)*TwoPi;
274 x = charge*cos(dotqr);
275 y = charge*sin(dotqr);
276 rho_[i] += DCMPLX(x, y);
301 DCMPLX de, expfactor;
303 double volume = boundaryPtr_->
volume();
306 int nSpecies = simulationPtr_->
nSpecies();
311 computeKSpaceCharge();
319 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
320 systemPtr_->
begin(iSpecies, molIter);
321 for ( ; molIter.
notEnd(); ++molIter) {
322 for (molIter->begin(atomIter); atomIter.
notEnd(); ++atomIter) {
323 type = atomIter->typeId();
324 charge = (*atomTypesPtr_)[type].charge();
326 if (fabs(charge) > EPS) {
330 fexp0_[0] = exp(TwoPiIm * rg[0] *
double(base0_));
331 de = exp(TwoPiIm * rg[0]);
332 for (i = 1; i < fexp0_.
size(); ++i) {
333 fexp0_[i] = fexp0_[i-1] * de;
336 fexp1_[0] = exp(TwoPiIm * rg[1] *
double(base1_));
337 de = exp(TwoPiIm * rg[1]);
338 for (i = 1; i < fexp1_.
size(); ++i) {
339 fexp1_[i] = fexp1_[i-1] * de;
342 fexp2_[0] = exp(TwoPiIm * rg[2] *
double(base2_));
343 de = exp(TwoPiIm * rg[2]);
344 for (i = 1; i < fexp2_.
size(); ++i) {
345 fexp2_[i] = fexp2_[i-1] * de;
350 for (i = 0; i < intWaves_.size(); ++i) {
353 df[j] = double(q[j]);
355 expfactor = fexp0_[q[0]-base0_] * fexp1_[q[1]-base1_] * fexp2_[q[2]-base2_];
356 x = expfactor.real();
357 y = expfactor.imag();
358 df *= g_[i]*( x*rho_[i].imag() - y*rho_[i].real() );
361 fg *= -2.0*charge/volume;
366 atomIter->force() += df;
382 computeKSpaceCharge();
387 for (
int i = 0; i < intWaves_.size(); ++i) {
391 energy += rhoSq*g_[i];
393 double volume = boundaryPtr_->
volume();
402 double selfEnergy = 0.0;
403 int nSpecies = simulationPtr_->
nSpecies();
405 for (
int iSpecies = 0; iSpecies < nSpecies; ++iSpecies) {
406 systemPtr_->
begin(iSpecies, molIter);
407 for ( ; molIter.
notEnd(); ++molIter) {
408 for (molIter->begin(atomiter); atomiter.
notEnd(); ++atomiter) {
409 iAtomType = atomiter->typeId();
410 charge = (*atomTypesPtr_)[iAtomType].charge();
411 selfEnergy += charge*charge;
416 double alpha = ewaldInteraction_.
alpha();
417 double epsilon = ewaldInteraction_.
epsilon();
418 selfEnergy *= alpha/(4.0*sqrt(pi)*pi*epsilon);
431 computeKSpaceCharge();
444 double alpha = ewaldInteraction_.
alpha();
445 double ca = 0.25/(alpha*alpha);
446 for (i = 0; i < intWaves_.size(); ++i) {
456 K *= -2.0 * (ca + (1.0/ksq_[i]));
460 K *= g_[i]*(x*x + y*y);
463 double volume = boundaryPtr_->
volume();
464 stressTensor /= volume*volume;
virtual void makeWaves()
Generate wavevectors for the current boundary and kCutoff.
Vector & zero()
Set all elements of a 3D vector to zero.
Coulomb potential for an Md simulation.
const int Dimension
Dimensionality of space.
double kSpacePotential(double kSq) const
Return regularized Fourier-space potential.
Setable< double > kSpaceEnergy_
K-space part of Coulomb energy.
A Vector is a Cartesian vector.
void begin(int speciesId, MoleculeIterator &iterator)
Initialize an iterator for molecules of one species in this System.
void append(const Data &data)
Append an element to the end of the sequence.
void clear()
Reset to empty state.
bool notEnd() const
Is the current pointer not at the end of the array?
double volume() const
Return unit cell volume.
double dot(const Vector &v) const
Return dot product of this vector and vector v.
void set(const T &value)
Set the value and mark as set.
MdEwaldPotential(System &system)
Constructor.
Vector & multiply(const Vector &v, double s)
Multiply a vector v by a scalar s.
const Vector & bravaisBasisVector(int i) const
Return Bravais lattice vector i.
Tensor & zero()
Set all elements of this tensor to zero.
A set of interacting Molecules enclosed by a Boundary.
void reserve(int capacity)
Reserve memory for specified number of elements.
int nWave() const
Current number of wavevectors with |k| < kCutoff.
int size() const
Return logical size of this array (i.e., current number of elements).
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
Classes used by all simpatico molecular simulations.
A Tensor represents a Cartesian tensor.
Tensor & add(const Tensor &t1, const Tensor &t2)
Add tensors t1 and t2.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
Saving / output archive for binary ostream.
Setable< Tensor > kSpaceStress_
K-space part of Coulomb stress.
const Vector & reciprocalBasisVector(int i) const
Return reciprocal lattice basis vector i.
double alpha() const
Get Ewald smearing parameter alpha (inverse length).
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Forward iterator for an Array or a C array.
Forward iterator for a PArray.
void set(std::string name, double value)
Set a parameter value, identified by a string.
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 loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
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.
double abs() const
Return absolute magnitude of this vector.
static const double Pi
Trigonometric constant Pi.
double epsilon() const
Get dielectric permittivity.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
An IntVector is an integer Cartesian vector.
virtual void computeStress()
Compute kspace part of Coulomb pressure.
virtual void addForces()
Add k-space Coulomb forces for all atoms.
static const Tensor Identity
Constant idenity Tensor (diagonal diagonal elements all 1).
virtual void computeEnergy()
Calculate the long range kspace part of Coulomb energy.
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.
void unsetWaves()
Unset all data that depends on the Boundary.
double get(std::string name) const
Get a parameter value, identified by a string.
virtual void readParameters(std::istream &in)
Read parameters and initialize.
double square() const
Return square magnitude of this vector.
void resize(int n)
Resizes array so that it contains n elements.
void readParameters(std::istream &in)
Read epsilon, alpha, and rCutoff.
bool hasWaves()
Are wavevectors and k-space influence function up to date?
virtual ~MdEwaldPotential()
Destructor (does nothing).
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Cartesian Vector to scaled / generalized coordinates.