OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
HydroIO.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 following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#include "hydrodynamics/HydroIO.hpp"
49
50#include <fstream>
51#include <iomanip>
52
53#include "utils/simError.h"
54
55using namespace std;
56
57namespace OpenMD {
58
59 HydroIO::~HydroIO() {}
60
61 void HydroIO::openWriter(std::ostream& os) {
62 std::string h = "OpenMD-Hydro";
63#if defined(NLOHMANN_JSON)
64 j_[h] = ordered_json::array();
65 writerOpen_ = true;
66#elif defined(RAPID_JSON)
67 osw_ = new OStreamWrapper(os);
68 w_.Reset(*osw_);
69 writerOpen_ = true;
70
71 w_.SetMaxDecimalPlaces(7);
72 w_.SetIndent(' ', 2);
73
74 w_.StartObject();
75 w_.Key(h.c_str());
76 w_.StartArray();
77#endif
78 }
79
80 void HydroIO::writeHydroProp(HydroProp* hp, RealType viscosity,
81 RealType temperature, std::ostream& os) {
82 if (!writerOpen_) openWriter(os);
83
84 std::string h = "OpenMD-Hydro";
85 std::string name = hp->getName();
86 Vector3d cor = hp->getCenterOfResistance();
87 Mat6x6d Xi = hp->getResistanceTensor();
88 Vector3d cod = hp->getCenterOfDiffusion(temperature);
89 Mat6x6d Xid = hp->getDiffusionTensorAtPos(cod, temperature);
90 Vector3d cop = hp->getCenterOfPitch();
91 Mat3x3d pitchAxes;
92 Vector3d pitches;
93 RealType pitchScalar;
94
95 hp->pitchAxes(pitchAxes, pitches, pitchScalar);
96
97#if defined(NLOHMANN_JSON)
98
99 ordered_json o;
100 o["name"] = name;
101 o["viscosity"] = viscosity;
102 o["centerOfResistance"] = {cor[0], cor[1], cor[2]};
103 o["resistanceTensor"] = json::array();
104
105 for (unsigned int i = 0; i < 6; i++) {
106 o["resistanceTensor"][i] = {Xi(i, 0), Xi(i, 1), Xi(i, 2),
107 Xi(i, 3), Xi(i, 4), Xi(i, 5)};
108 }
109
110 o["temperature"] = temperature;
111 o["centerOfDiffusion"] = {cod[0], cod[1], cod[2]};
112 o["diffusionTensor"] = json::array();
113
114 for (unsigned int i = 0; i < 6; i++) {
115 o["diffusionTensor"][i] = {Xid(i, 0), Xid(i, 1), Xid(i, 2),
116 Xid(i, 3), Xid(i, 4), Xid(i, 5)};
117 }
118
119 o["pitch"] = pitchScalar;
120 o["centerOfPitch"] = {cop[0], cop[1], cop[2]};
121 o["momentsOfPitch"] = {pitches[0], pitches[1], pitches[2]};
122
123 o["pitchAxes"] = json::array();
124 for (unsigned int i = 0; i < 3; i++) {
125 o["pitchAxes"][i] = {pitchAxes(i, 0), pitchAxes(i, 1), pitchAxes(i, 2)};
126 }
127
128 j_[h].push_back(o);
129
130#elif defined(RAPID_JSON)
131
132 w_.StartObject();
133 w_.Key("name");
134 w_.String(name.c_str());
135
136 w_.Key("viscosity");
137 w_.Double(viscosity);
138 w_.Key("centerOfResistance");
139 w_.StartArray();
140 w_.SetFormatOptions(kFormatSingleLineArray);
141
142 for (unsigned i = 0; i < 3; i++)
143 w_.Double(cor[i]);
144 w_.EndArray();
145 w_.SetFormatOptions(kFormatDefault);
146
147 w_.Key("resistanceTensor");
148 w_.StartArray();
149 for (unsigned i = 0; i < 6; i++) {
150 w_.StartArray();
151 w_.SetFormatOptions(kFormatSingleLineArray);
152
153 for (unsigned j = 0; j < 6; j++) {
154 w_.Double(Xi(i, j));
155 }
156 w_.EndArray();
157 w_.SetFormatOptions(kFormatDefault);
158 }
159 w_.EndArray();
160
161 w_.Key("temperature");
162 w_.Double(temperature);
163 w_.Key("centerOfDiffusion");
164 w_.StartArray();
165 w_.SetFormatOptions(kFormatSingleLineArray);
166
167 for (unsigned i = 0; i < 3; i++)
168 w_.Double(cod[i]);
169 w_.EndArray();
170 w_.SetFormatOptions(kFormatDefault);
171
172 w_.Key("diffusionTensor");
173 w_.StartArray();
174 for (unsigned i = 0; i < 6; i++) {
175 w_.StartArray();
176 w_.SetFormatOptions(kFormatSingleLineArray);
177
178 for (unsigned j = 0; j < 6; j++) {
179 w_.Double(Xid(i, j));
180 }
181 w_.EndArray();
182 w_.SetFormatOptions(kFormatDefault);
183 }
184 w_.EndArray();
185
186 w_.Key("pitch");
187 w_.Double(pitchScalar);
188
189 w_.Key("centerOfPitch");
190 w_.StartArray();
191 w_.SetFormatOptions(kFormatSingleLineArray);
192 for (unsigned i = 0; i < 3; i++)
193 w_.Double(cop[i]);
194 w_.EndArray();
195 w_.SetFormatOptions(kFormatDefault);
196
197 w_.Key("momentsOfPitch");
198 w_.StartArray();
199 w_.SetFormatOptions(kFormatSingleLineArray);
200 for (unsigned i = 0; i < 3; i++)
201 w_.Double(pitches[i]);
202 w_.EndArray();
203 w_.SetFormatOptions(kFormatDefault);
204
205 w_.Key("pitchAxes");
206 w_.StartArray();
207 for (unsigned i = 0; i < 3; i++) {
208 w_.StartArray();
209 w_.SetFormatOptions(kFormatSingleLineArray);
210 for (unsigned j = 0; j < 3; j++) {
211 w_.Double(pitchAxes(i, j));
212 }
213 w_.EndArray();
214 w_.SetFormatOptions(kFormatDefault);
215 }
216 w_.EndArray();
217
218 w_.EndObject();
219#endif
220 }
221
222 void HydroIO::closeWriter(std::ostream& os) {
223#if defined(NLOHMANN_JSON)
224 os << j_.dump(2) << std::endl;
225#elif defined(RAPID_JSON)
226 w_.EndArray();
227 w_.EndObject();
228 delete osw_;
229#endif
230 writerOpen_ = false;
231 }
232
233 map<string, HydroProp*> HydroIO::parseHydroFile(const string& f) {
234 map<string, HydroProp*> props;
235
236 ifstream ifs(f);
237
238 if (!ifs.good()) {
239 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
240 "HydroIO: Cannot open file: %s\n", f.c_str());
241 painCave.isFatal = 1;
242 simError();
243 }
244
245#if defined(NLOHMANN_JSON)
246 json ij = json::parse(ifs);
247
248 auto& entries = ij["OpenMD-Hydro"];
249
250 for (auto& entry : entries) {
251 HydroProp* hp = new HydroProp();
252 std::string name;
253 Vector3d cor;
254 Mat6x6d Xi;
255
256 name = entry["name"].get<std::string>();
257
258 for (unsigned int i = 0; i < 3; i++) {
259 cor[i] = entry["centerOfResistance"].get<vector<RealType>>()[i];
260 }
261
262 for (unsigned int i = 0; i < 6; i++) {
263 for (unsigned int j = 0; j < 6; j++) {
264 Xi(i, j) =
265 entry["resistanceTensor"].get<vector<vector<RealType>>>()[i][j];
266 }
267 }
268
269 hp->setName(name);
270 hp->setCenterOfResistance(cor);
271 hp->setResistanceTensor(Xi);
272 props.insert(map<string, HydroProp*>::value_type(name, hp));
273 }
274#elif defined(RAPID_JSON)
275 // Parse entire file into memory once, then reuse d_ for subsequent
276 // hydroProps.
277
278 if (ifs.peek() != EOF) {
279 rapidjson::IStreamWrapper isw(ifs);
280 d_.ParseStream(isw);
281 if (d_.HasParseError()) {
282 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
283 "HydroIO: JSON parse error in file %s\n"
284 "\tError: %zu : %s\n",
285 f.c_str(), d_.GetErrorOffset(),
286 rapidjson::GetParseError_En(d_.GetParseError()));
287 painCave.isFatal = 1;
288 simError();
289 }
290 if (!d_.IsObject()) {
291 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
292 "HydroIO: OpenMD-Hydro should be a single object.\n");
293 painCave.isFatal = 1;
294 simError();
295 }
296 // OpenMD-Hydro has a single object, but check that it's really
297 // OpenMD-Hydro
298 if (!d_.HasMember("OpenMD-Hydro")) {
299 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
300 "HydroIO: File %s does not have a OpenMD-Hydro object.\n",
301 f.c_str());
302 painCave.isFatal = 1;
303 simError();
304 }
305 }
306 const Value& entries = d_["OpenMD-Hydro"];
307 for (auto& entry : entries.GetArray()) {
308 HydroProp* hp = new HydroProp();
309 std::string name;
310 Vector3d cor;
311 Mat6x6d Xi;
312
313 name = entry["name"].GetString();
314
315 for (unsigned int i = 0; i < 3; i++) {
316 cor[i] = entry["centerOfResistance"][i].GetDouble();
317 }
318
319 for (unsigned int i = 0; i < 6; i++) {
320 for (unsigned int j = 0; j < 6; j++) {
321 Xi(i, j) = entry["resistanceTensor"][i][j].GetDouble();
322 }
323 }
324
325 hp->setName(name);
326 hp->setCenterOfResistance(cor);
327 hp->setResistanceTensor(Xi);
328 props.insert(map<string, HydroProp*>::value_type(name, hp));
329 }
330#endif
331 return props;
332 }
333
334 void HydroIO::interpretHydroProp(HydroProp* hp, RealType viscosity,
335 RealType temperature) {
336 Vector3d ror = hp->getCenterOfResistance();
337
338 Mat6x6d Xi;
339 Xi = hp->getResistanceTensor();
340 Mat3x3d Xirtt;
341 Mat3x3d Xirrt;
342 Mat3x3d Xirtr;
343 Mat3x3d Xirrr;
344
345 Xi.getSubMatrix(0, 0, Xirtt);
346 Xi.getSubMatrix(0, 3, Xirrt);
347 Xi.getSubMatrix(3, 0, Xirtr);
348 Xi.getSubMatrix(3, 3, Xirrr);
349
350 Mat6x6d Dr;
351 Dr = hp->getDiffusionTensor(temperature);
352
353 Mat3x3d Drtt;
354 Mat3x3d Drrt;
355 Mat3x3d Drtr;
356 Mat3x3d Drrr;
357
358 Dr.getSubMatrix(0, 0, Drtt);
359 Dr.getSubMatrix(0, 3, Drrt);
360 Dr.getSubMatrix(3, 0, Drtr);
361 Dr.getSubMatrix(3, 3, Drrr);
362
363 std::cout << "\n";
364 std::cout << "-----------------------------------------\n";
365 std::cout << "viscosity = " << viscosity << " Poise" << std::endl;
366 std::cout << "temperature = " << temperature << " K" << std::endl;
367 std::cout << "-----------------------------------------\n";
368 std::cout << "The centers are based on the elements generated by Hydro "
369 << std::endl;
370 std::cout << "which have been placed in an .xyz or .stl file." << std::endl;
371 std::cout << "They are not based on the geometry in the .omd file.\n"
372 << std::endl;
373 std::cout << "-----------------------------------------\n\n";
374 std::cout << "Center of resistance :" << std::endl;
375 std::cout << ror << "\n" << std::endl;
376 std::cout << "-----------------------------------------\n\n";
377 std::cout << "Resistance tensor at center of resistance\n" << std::endl;
378 std::cout << "translation [kcal.fs/(mol.A^2)]:" << std::endl;
379 std::cout << Xirtt << std::endl;
380 std::cout << "rotation-translation [kcal.fs/(mol.A.radian)]:" << std::endl;
381 std::cout << Xirtr.transpose() << std::endl;
382 std::cout << "translation-rotation [kcal.fs/(mol.A.radian)]:" << std::endl;
383 std::cout << Xirtr << std::endl;
384 std::cout << "rotation [kcal.fs/(mol.radian^2)]:" << std::endl;
385 std::cout << Xirrr << std::endl;
386 std::cout << "-----------------------------------------\n\n";
387 std::cout << "Diffusion tensor at center of resistance\n" << std::endl;
388 std::cout << "translation (A^2 / fs):" << std::endl;
389 std::cout << Drtt << std::endl;
390 std::cout << "rotation-translation (A.radian / fs):" << std::endl;
391 std::cout << Drrt << std::endl;
392 std::cout << "translation-rotation (A.radian / fs):" << std::endl;
393 std::cout << Drtr << std::endl;
394 std::cout << "rotation (radian^2 / fs):" << std::endl;
395 std::cout << Drrr << std::endl;
396 std::cout << "-----------------------------------------\n\n";
397
398 // calculate center of diffusion using the same arbitrary origin as above
399 // (from the generated geometry file .xyz)
400
401 Vector3d cod = hp->getCenterOfDiffusion(temperature);
402 Mat6x6d Xid = hp->getResistanceTensorAtPos(cod);
403
404 Mat3x3d Xidtt;
405 Mat3x3d Xidrt;
406 Mat3x3d Xidtr;
407 Mat3x3d Xidrr;
408
409 Xid.getSubMatrix(0, 0, Xidtt);
410 Xid.getSubMatrix(0, 3, Xidrt);
411 Xid.getSubMatrix(3, 0, Xidtr);
412 Xid.getSubMatrix(3, 3, Xidrr);
413
414 // calculate Diffusion Tensor at center of diffusion
415 Mat6x6d Dd = hp->getDiffusionTensorAtPos(cod, temperature);
416
417 Mat3x3d Ddtt;
418 Mat3x3d Ddtr;
419 Mat3x3d Ddrt;
420 Mat3x3d Ddrr;
421
422 Dd.getSubMatrix(0, 0, Ddtt);
423 Dd.getSubMatrix(0, 3, Ddrt);
424 Dd.getSubMatrix(3, 0, Ddtr);
425 Dd.getSubMatrix(3, 3, Ddrr);
426
427 std::cout << "Center of diffusion: " << std::endl;
428 std::cout << cod << "\n" << std::endl;
429 std::cout << "-----------------------------------------\n\n";
430 std::cout << "Diffusion tensor at center of diffusion \n " << std::endl;
431 std::cout << "translation (A^2 / fs) :" << std::endl;
432 std::cout << Ddtt << std::endl;
433 std::cout << "rotation-translation (A.radian / fs):" << std::endl;
434 std::cout << Ddtr.transpose() << std::endl;
435 std::cout << "translation-rotation (A.radian / fs):" << std::endl;
436 std::cout << Ddtr << std::endl;
437 std::cout << "rotation (radian^2 / fs):" << std::endl;
438 std::cout << Ddrr << std::endl;
439 std::cout << "-----------------------------------------\n\n";
440 std::cout << "Resistance tensor at center of diffusion \n " << std::endl;
441 std::cout << "translation [kcal.fs/(mol.A^2)]:" << std::endl;
442 std::cout << Xidtt << std::endl;
443 std::cout << "rotation-translation [kcal.fs/(mol.A.radian)]:" << std::endl;
444 std::cout << Xidrt << std::endl;
445 std::cout << "translation-rotation [kcal.fs/(mol.A.radian)]:" << std::endl;
446 std::cout << Xidtr << std::endl;
447 std::cout << "rotation [kcal.fs/(mol.radian^2)]:" << std::endl;
448 std::cout << Xidrr << std::endl;
449 std::cout << "-----------------------------------------\n\n";
450 }
451} // namespace OpenMD
Container for information about the hydrodynamic behavior of objects interacting with surroundings.
Definition HydroProp.hpp:77
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.