51#include "brains/ForceModifier.hpp"
52#include "nonbonded/NonBondedInteraction.hpp"
54#include "types/FixedChargeAdapter.hpp"
55#include "types/FluctuatingChargeAdapter.hpp"
56#include "types/MultipoleAdapter.hpp"
57#include "utils/Constants.hpp"
59namespace OpenMD::Perturbations {
62 doParticlePot {false}, info_(info) {
63 lightParams = info_->getSimParams()->getLightParameters();
66 void Light::initialize() {
68 bool haveDirection =
false;
69 bool haveFrequency =
false;
70 bool havePolarization =
false;
72 if (lightParams->haveWaveVector()) {
73 std::vector<RealType> k = lightParams->getWaveVector();
79 lambda_ = 2.0 * Constants::PI / kmag_;
80 omega_ = 2.0 * Constants::PI * Constants::c / lambda_;
87 if (lightParams->havePropagationDirection()) {
89 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
90 "light: please specify either waveVector or "
91 "propagationDirection, but not both.\n");
95 std::vector<RealType> pd = lightParams->getPropagationDirection();
100 haveDirection =
true;
103 if (lightParams->haveWavelength()) {
105 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
106 "light: please specify one of: waveVector, wavelength, or"
107 "frequency (but only one of these).\n");
108 painCave.isFatal = 1;
113 lambda_ = lightParams->getWavelength() * 10.0;
114 omega_ = 2.0 * Constants::PI * Constants::c / lambda_;
115 kmag_ = 2.0 * Constants::PI / lambda_;
116 haveFrequency =
true;
119 if (lightParams->haveFrequency()) {
121 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
122 "light: please specify one of: waveVector, wavelength, or"
123 "frequency (but only one of these).\n");
124 painCave.isFatal = 1;
129 omega_ = lightParams->getFrequency() * 1.0e-15;
130 lambda_ = 2.0 * Constants::PI * Constants::c / omega_;
131 kmag_ = 2.0 * Constants::PI / lambda_;
132 haveFrequency =
true;
135 if (haveFrequency && haveDirection) { k_ = khat_ * kmag_; }
137 if (lightParams->haveIntensity()) {
138 RealType intense = lightParams->getIntensity();
140 intense *= 1.439326e-11;
141 E0_ = std::sqrt(2.0 * intense / (Constants::epsilon0 * Constants::c));
149 std::map<std::string, LightPolarization> stringToPolarization;
151 stringToPolarization[
"X"] = lightX;
152 stringToPolarization[
"Y"] = lightY;
153 stringToPolarization[
"+"] = lightPlus;
154 stringToPolarization[
"-"] = lightMinus;
156 if (lightParams->havePolarization()) {
157 std::string lpl = lightParams->getPolarization();
158 LightPolarization lp = stringToPolarization.find(lpl)->second;
161 jones_[0] = {1.0, 0.0};
162 jones_[1] = {0.0, 0.0};
163 havePolarization =
true;
166 jones_[0] = {0.0, 0.0};
167 jones_[1] = {1.0, 0.0};
168 havePolarization =
true;
171 jones_[0] = {1.0, 0.0};
172 jones_[1] = {0.0, 1.0};
173 havePolarization =
true;
176 jones_[0] = {1.0, 0.0};
177 jones_[1] = {0.0, -1.0};
178 havePolarization =
true;
181 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
182 "Light: Unknown polarization type\n");
183 painCave.isFatal = 1;
184 painCave.severity = OPENMD_ERROR;
190 std::string allowedPolarizations;
191 int currentLineLength = 0;
193 for (std::map<std::string, LightPolarization>::iterator polStrIter =
194 stringToPolarization.begin();
195 polStrIter != stringToPolarization.end(); ++polStrIter) {
196 allowedPolarizations += polStrIter->first +
", ";
197 currentLineLength += polStrIter->first.length() + 2;
199 if (currentLineLength >= 50) {
200 allowedPolarizations +=
"\n\t\t";
201 currentLineLength = 0;
205 allowedPolarizations.erase(allowedPolarizations.length() - 2, 2);
208 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
209 "Light: No polarization was set in the omd file. This parameter\n"
210 "\tmust be set to use Light, and can take any of these values:\n"
212 allowedPolarizations.c_str());
213 painCave.isFatal = 1;
214 painCave.severity = OPENMD_ERROR;
218 if (haveE0 && haveDirection && haveFrequency && havePolarization) {
221 if (!haveDirection) {
222 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
223 "Light: could not determine direction of propagation.\n");
224 painCave.isFatal = 1;
228 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
229 "Light: intensity not specified.\n");
230 painCave.isFatal = 1;
233 if (!haveFrequency) {
234 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
235 "Light: could not determine frequency or wavelength.\n");
236 painCave.isFatal = 1;
239 if (!havePolarization) {
240 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
241 "Light: polarization not specifieid.\n");
242 painCave.isFatal = 1;
247 int storageLayout_ = info_->getSnapshotManager()->getAtomStorageLayout();
248 if (storageLayout_ & DataStorage::dslParticlePot) doParticlePot =
true;
254 acos(std::min((RealType)1.0, std::max((RealType)-1.0, khat_[2])));
255 RealType phi = std::atan2(-khat_[1], khat_[0]);
257 if (phi < 0) phi += 2.0 * Constants::PI;
259 A_.setupRotMat(phi, theta, psi);
260 Ainv_ = A_.inverse();
265 void Light::modifyForces() {
266 if (!initialized) initialize();
268 SimInfo::MoleculeIterator i;
269 Molecule::AtomIterator j;
273 potVec longRangePotential(0.0);
275 RealType C {}, U {}, fPot {};
276 Vector3d r {}, rp {}, v {}, f {}, trq {}, D {}, J {}, av {};
283 RealType t = info_->getSnapshotManager()->getCurrentSnapshot()->getTime();
287 for (mol = info_->beginMolecule(i); mol != NULL;
288 mol = info_->nextMolecule(i)) {
289 for (atom = mol->beginAtom(j); atom != NULL; atom = mol->nextAtom(j)) {
302 std::complex<RealType> argument(0.0, kmag_ * rp.z() - omega_ * t);
303 std::complex<RealType> Ex = E0_ * jones_[0] * std::exp(argument);
304 std::complex<RealType> Ey = E0_ * jones_[1] * std::exp(argument);
315 BF =
cross(EF, khat_) / Constants::c;
320 if (fca.isFixedCharge()) {
326 if (fqa.isFluctuatingCharge()) {
333 f = C * (EF +
cross(v, BF));
342 D = atom->
getDipole() * Constants::dipoleConvert;
355 av[m] = J[m] / I(m, m);
356 av[n] = J[n] / I(n, n);
358 av = I.inverse() * J;
372 MPI_Allreduce(MPI_IN_PLACE, &fPot, 1, MPI_REALTYPE, MPI_SUM,
376 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
377 longRangePotential = snap->getLongRangePotentials();
379 snap->setLongRangePotentials(longRangePotential);
Rotating Electric Field perturbation.
virtual Mat3x3d getI()
Returns the inertia tensor of this stuntdouble.
AtomType * getAtomType()
Returns the AtomType of this Atom.
AtomType is what OpenMD looks to for unchanging data about an atom.
Abstract class for external ForceModifier classes.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
The Snapshot class is a repository storing dynamic data during a Simulation.
void addFlucQFrc(RealType cfrc)
Adds charge force into the current charge force of this stuntDouble.
Vector3d getVel()
Returns the current velocity of this stuntDouble.
void addElectricField(const Vector3d &eField)
Adds electric field into the current electric field of this stuntDouble.
int linearAxis()
Returns the linear axis of the rigidbody, atom and directional atom will always return -1.
bool isLinear()
Tests the if this stuntDouble is a linear rigidbody.
Vector3d getPos()
Returns the current position of this stuntDouble.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
Vector3d getDipole()
Returns the current dipole vector of this stuntDouble.
void addTrq(const Vector3d &trq)
Adds torque into the current torque of this stuntDouble.
void addParticlePot(const RealType &particlePot)
Adds particlePot into the current particlePot of this stuntDouble.
Vector3d getJ()
Returns the current angular momentum of this stuntDouble (body -fixed).
void addFrc(const Vector3d &frc)
Adds force into the current force of this stuntDouble.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
@ ELECTROSTATIC_FAMILY
Coulombic and point-multipole interactions.