54#include "brains/ForceModifier.hpp"
55#include "nonbonded/NonBondedInteraction.hpp"
57#include "types/FixedChargeAdapter.hpp"
58#include "types/FluctuatingChargeAdapter.hpp"
59#include "types/MultipoleAdapter.hpp"
60#include "utils/Constants.hpp"
62namespace OpenMD::Perturbations {
63 Light::Light(SimInfo* info) :
64 ForceModifier {info}, initialized {false}, doLight {false},
65 doParticlePot {false}, info_(info) {
66 lightParams = info_->getSimParams()->getLightParameters();
69 void Light::initialize() {
71 bool haveDirection =
false;
72 bool haveFrequency =
false;
73 bool havePolarization =
false;
75 if (lightParams->haveWaveVector()) {
76 std::vector<RealType> k = lightParams->getWaveVector();
82 lambda_ = 2.0 * Constants::PI / kmag_;
83 omega_ = 2.0 * Constants::PI * Constants::c / lambda_;
90 if (lightParams->havePropagationDirection()) {
92 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
93 "light: please specify either waveVector or "
94 "propagationDirection, but not both.\n");
98 std::vector<RealType> pd = lightParams->getPropagationDirection();
103 haveDirection =
true;
106 if (lightParams->haveWavelength()) {
108 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
109 "light: please specify one of: waveVector, wavelength, or"
110 "frequency (but only one of these).\n");
111 painCave.isFatal = 1;
116 lambda_ = lightParams->getWavelength() * 10.0;
117 omega_ = 2.0 * Constants::PI * Constants::c / lambda_;
118 kmag_ = 2.0 * Constants::PI / lambda_;
119 haveFrequency =
true;
122 if (lightParams->haveFrequency()) {
124 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
125 "light: please specify one of: waveVector, wavelength, or"
126 "frequency (but only one of these).\n");
127 painCave.isFatal = 1;
132 omega_ = lightParams->getFrequency() * 1.0e-15;
133 lambda_ = 2.0 * Constants::PI * Constants::c / omega_;
134 kmag_ = 2.0 * Constants::PI / lambda_;
135 haveFrequency =
true;
138 if (haveFrequency && haveDirection) { k_ = khat_ * kmag_; }
140 if (lightParams->haveIntensity()) {
141 RealType intense = lightParams->getIntensity();
143 intense *= 1.439326e-11;
144 E0_ = std::sqrt(2.0 * intense / (Constants::epsilon0 * Constants::c));
152 std::map<std::string, LightPolarization> stringToPolarization;
154 stringToPolarization[
"X"] = lightX;
155 stringToPolarization[
"Y"] = lightY;
156 stringToPolarization[
"+"] = lightPlus;
157 stringToPolarization[
"-"] = lightMinus;
159 if (lightParams->havePolarization()) {
160 std::string lpl = lightParams->getPolarization();
161 LightPolarization lp = stringToPolarization.find(lpl)->second;
164 jones_[0] = {1.0, 0.0};
165 jones_[1] = {0.0, 0.0};
166 havePolarization =
true;
169 jones_[0] = {0.0, 0.0};
170 jones_[1] = {1.0, 0.0};
171 havePolarization =
true;
174 jones_[0] = {1.0, 0.0};
175 jones_[1] = {0.0, 1.0};
176 havePolarization =
true;
179 jones_[0] = {1.0, 0.0};
180 jones_[1] = {0.0, -1.0};
181 havePolarization =
true;
184 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
185 "Light: Unknown polarization type\n");
186 painCave.isFatal = 1;
187 painCave.severity = OPENMD_ERROR;
193 std::string allowedPolarizations;
194 int currentLineLength = 0;
196 for (std::map<std::string, LightPolarization>::iterator polStrIter =
197 stringToPolarization.begin();
198 polStrIter != stringToPolarization.end(); ++polStrIter) {
199 allowedPolarizations += polStrIter->first +
", ";
200 currentLineLength += polStrIter->first.length() + 2;
202 if (currentLineLength >= 50) {
203 allowedPolarizations +=
"\n\t\t";
204 currentLineLength = 0;
208 allowedPolarizations.erase(allowedPolarizations.length() - 2, 2);
211 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
212 "Light: No polarization was set in the omd file. This parameter\n"
213 "\tmust be set to use Light, and can take any of these values:\n"
215 allowedPolarizations.c_str());
216 painCave.isFatal = 1;
217 painCave.severity = OPENMD_ERROR;
221 if (haveE0 && haveDirection && haveFrequency && havePolarization) {
224 if (!haveDirection) {
225 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
226 "Light: could not determine direction of propagation.\n");
227 painCave.isFatal = 1;
231 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
232 "Light: intensity not specified.\n");
233 painCave.isFatal = 1;
236 if (!haveFrequency) {
237 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
238 "Light: could not determine frequency or wavelength.\n");
239 painCave.isFatal = 1;
242 if (!havePolarization) {
243 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
244 "Light: polarization not specifieid.\n");
245 painCave.isFatal = 1;
250 int storageLayout_ = info_->getSnapshotManager()->getAtomStorageLayout();
251 if (storageLayout_ & DataStorage::dslParticlePot) doParticlePot =
true;
257 acos(std::min((RealType)1.0, std::max((RealType)-1.0, khat_[2])));
258 RealType phi = std::atan2(-khat_[1], khat_[0]);
260 if (phi < 0) phi += 2.0 * Constants::PI;
262 A_.setupRotMat(phi, theta, psi);
263 Ainv_ = A_.inverse();
268 void Light::modifyForces() {
269 if (!initialized) initialize();
271 SimInfo::MoleculeIterator i;
272 Molecule::AtomIterator j;
276 potVec longRangePotential(0.0);
278 RealType C {}, U {}, fPot {};
279 Vector3d r {}, rp {}, v {}, f {}, trq {}, D {}, J {}, av {};
280 Vector3d EFk {}, EF {}, BF {};
286 RealType t = info_->getSnapshotManager()->getCurrentSnapshot()->getTime();
290 for (mol = info_->beginMolecule(i); mol != NULL;
291 mol = info_->nextMolecule(i)) {
292 for (atom = mol->beginAtom(j); atom != NULL; atom = mol->nextAtom(j)) {
296 atype = atom->getAtomType();
305 std::complex<RealType> argument(0.0, kmag_ * rp.z() - omega_ * t);
306 std::complex<RealType> Ex = E0_ * jones_[0] * std::exp(argument);
307 std::complex<RealType> Ey = E0_ * jones_[1] * std::exp(argument);
318 BF =
cross(EF, khat_) / Constants::c;
320 atom->addElectricField(EF);
322 FixedChargeAdapter fca = FixedChargeAdapter(atype);
323 if (fca.isFixedCharge()) {
328 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atype);
329 if (fqa.isFluctuatingCharge()) {
331 C += atom->getFlucQPos();
332 atom->addFlucQFrc(
dot(r, EF));
336 f = C * (EF +
cross(v, BF));
339 if (doParticlePot) { atom->addParticlePot(U); }
343 MultipoleAdapter ma = MultipoleAdapter(atype);
345 D = atom->getDipole() * Constants::dipoleConvert;
353 if (atom->isLinear()) {
354 l = atom->linearAxis();
358 av[m] = J[m] / I(m, m);
359 av[n] = J[n] / I(n, n);
361 av = I.inverse() * J;
368 if (doParticlePot) { atom->addParticlePot(U); }
375 MPI_Allreduce(MPI_IN_PLACE, &fPot, 1, MPI_REALTYPE, MPI_SUM,
379 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
380 longRangePotential = snap->getLongRangePotentials();
382 snap->setLongRangePotentials(longRangePotential);
Rotating Electric Field perturbation.
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.