OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
MultipoleAtomTypesSectionParser.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the appropriate papers when you publish your
33 * work. Good starting points are:
34 *
35 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
36 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
37 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
38 * [4] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
39 * [5] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
40 * [6] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
41 * [7] Lamichhane, Newman & Gezelter, J. Chem. Phys. 141, 134110 (2014).
42 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
43 */
44
45#include "io/MultipoleAtomTypesSectionParser.hpp"
46
47#include "brains/ForceField.hpp"
48#include "utils/Constants.hpp"
49#include "utils/simError.h"
50
51namespace OpenMD {
52
53 MultipoleAtomTypesSectionParser::MultipoleAtomTypesSectionParser(
54 ForceFieldOptions&) {
55 setSectionName("MultipoleAtomTypes");
56 }
57
58 void MultipoleAtomTypesSectionParser::parseLine(ForceField& ff,
59 const std::string& line,
60 int lineNo) {
61 StringTokenizer tokenizer(line);
62 int nTokens = tokenizer.countTokens();
63
64 // name multipole_type theta phi psi
65 // "name" must match the name in the AtomTypes section
66 //
67 // avaliable multipole types are:
68 // d (dipole)
69 // q (quadrupole)
70 // dq (dipole plus quadrupole)
71 //
72 // Directionality for dipoles and quadrupoles is given by three
73 // euler angles (phi, theta, psi), because the body-fixed
74 // reference frame for directional atoms is determined by the
75 // *mass* distribution and not by the charge distribution.
76 //
77 // Dipoles are given in units of Debye
78 // Quadrupoles are given in units of esu centibarn
79 //
80 // Examples:
81 //
82 // name d phi theta psi dipole_moment
83 // name q phi theta psi Qxx Qyy Qzz
84 // name dq phi theta psi dipole_moment Qxx Qyy Qzz
85
86 if (nTokens < 5) {
87 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
88 "MultipoleAtomTypesSectionParser Error: Not enough tokens at "
89 "line %d\n",
90 lineNo);
91 painCave.isFatal = 1;
92 simError();
93 } else {
94 std::string atomTypeName = tokenizer.nextToken();
95 std::string multipoleType = tokenizer.nextToken();
96 RealType phi = tokenizer.nextTokenAsDouble() * Constants::PI / 180.0;
97 RealType theta = tokenizer.nextTokenAsDouble() * Constants::PI / 180.0;
98 RealType psi = tokenizer.nextTokenAsDouble() * Constants::PI / 180.0;
99
100 AtomType* atomType = ff.getAtomType(atomTypeName);
101 if (atomType == NULL) {
102 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
103 "MultipoleAtomTypesSectionParser Error: Can not find matched "
104 "AtomType[%s] "
105 "at line %d\n",
106 atomTypeName.c_str(), lineNo);
107 painCave.isFatal = 1;
108 simError();
109 }
110
111 MultipoleAdapter ma = MultipoleAdapter(atomType);
112
113 RotMat3x3d eFrame(0.0);
114
115 eFrame.setupRotMat(phi, theta, psi);
116
117 RealType dipoleMoment(0);
118 Vector3d dipole(V3Zero);
119 Vector3d quadrupoleMoments(V3Zero);
120 Mat3x3d quadrupole(0.0);
121
122 bool isDipole(false);
123 bool isQuadrupole(false);
124
125 if (multipoleType == "d") {
126 parseDipole(tokenizer, dipoleMoment, lineNo);
127 isDipole = true;
128 } else if (multipoleType == "s") {
129 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
130 "MultipoleAtomTypesSectionParser Error: \n"
131 "\tsplit dipoles (type s) have been deprecated (line: %d)\n",
132 lineNo);
133 painCave.isFatal = 1;
134 simError();
135 } else if (multipoleType == "q") {
136 parseQuadrupole(tokenizer, quadrupoleMoments, lineNo);
137 isQuadrupole = true;
138 } else if (multipoleType == "dq") {
139 parseDipole(tokenizer, dipoleMoment, lineNo);
140 isDipole = true;
141 parseQuadrupole(tokenizer, quadrupoleMoments, lineNo);
142 isQuadrupole = true;
143 } else if (multipoleType == "sq") {
144 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
145 "MultipoleAtomTypesSectionParser Error: \n"
146 "\tsplit dipole quadrupoles (type sq) have been deprecated "
147 "(line: %d)\n",
148 lineNo);
149 painCave.isFatal = 1;
150 simError();
151 } else {
152 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
153 "MultipoleAtomTypesSectionParser Error: unrecognized multiple "
154 "type at line "
155 "%d\n",
156 lineNo);
157 painCave.isFatal = 1;
158 simError();
159 }
160 if (isDipole) dipole = dipoleMoment * eFrame.transpose() * V3Z;
161 if (isQuadrupole) {
162 quadrupole(0, 0) = quadrupoleMoments(0);
163 quadrupole(1, 1) = quadrupoleMoments(1);
164 quadrupole(2, 2) = quadrupoleMoments(2);
165 quadrupole = eFrame.transpose() * quadrupole * eFrame;
166 }
167
168 ma.makeMultipole(dipole, quadrupole, isDipole, isQuadrupole);
169 }
170 }
171
172 void MultipoleAtomTypesSectionParser::parseDipole(StringTokenizer& tokenizer,
173 RealType& dipoleMoment,
174 int lineNo) {
175 if (tokenizer.hasMoreTokens()) {
176 dipoleMoment = tokenizer.nextTokenAsDouble();
177 } else {
178 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
179 "MultipoleAtomTypesSectionParser Error: Not enough tokens at "
180 "line %d\n",
181 lineNo);
182 painCave.isFatal = 1;
183 simError();
184 }
185 }
186
187 void MultipoleAtomTypesSectionParser::parseQuadrupole(
188 StringTokenizer& tokenizer, Vector3d& quadrupoleMoments, int lineNo) {
189 int nTokens = tokenizer.countTokens();
190 if (nTokens >= 3) {
191 quadrupoleMoments[0] = tokenizer.nextTokenAsDouble();
192 quadrupoleMoments[1] = tokenizer.nextTokenAsDouble();
193 quadrupoleMoments[2] = tokenizer.nextTokenAsDouble();
194
195 // RealType trace = quadrupoleMoments.sum();
196 //
197 // if (fabs(trace) > OpenMD::epsilon) {
198 // snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
199 // "MultipoleAtomTypesSectionParser Error: the trace of quadrupole
200 // moments is not zero at line %d\n", lineNo); painCave.isFatal = 1;
201 // simError();
202 // }
203
204 } else {
205 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
206 "MultipoleAtomTypesSectionParser Error: Not enough tokens at "
207 "line %d\n",
208 lineNo);
209 painCave.isFatal = 1;
210 simError();
211 }
212 }
213} // namespace OpenMD
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.