OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
elasticConstants.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 <cmath>
49#include <cstdio>
50#include <cstdlib>
51#include <cstring>
52#include <fstream>
53#include <iostream>
54#include <map>
55#include <memory>
56#include <string>
57
59#include "brains/Register.hpp"
60#include "brains/SimCreator.hpp"
61#include "brains/SimInfo.hpp"
62#include "brains/Thermo.hpp"
63#include "brains/Velocitizer.hpp"
64#include "constraints/Shake.hpp"
66#include "flucq/FluctuatingChargeConstraints.hpp"
67#include "flucq/FluctuatingChargeDamped.hpp"
68#include "io/DumpReader.hpp"
69#include "math/LU.hpp"
70#include "math/QR.hpp"
72#include "optimization/BoxObjectiveFunction.hpp"
75#include "optimization/OptimizationFactory.hpp"
77#include "utils/StringUtils.hpp"
78
79using namespace OpenMD;
80using namespace JAMA;
81#include <algorithm>
82#include <iomanip>
83#include <iostream>
84#include <numeric>
85#include <vector>
86
87template<typename Real>
88class Vector6 : public Vector<Real, 6> {
89public:
90 using ElemType = Real;
91 using ElemPoinerType = Real*;
92
93 Vector6() : Vector<Real, 6>() {}
94
95 /** Constructs and initializes a Vector6d from individual coordinates */
96 inline Vector6(RealType v0, RealType v1, RealType v2, RealType v3,
97 RealType v4, RealType v5) {
98 this->data_[0] = v0;
99 this->data_[1] = v1;
100 this->data_[2] = v2;
101 this->data_[3] = v3;
102 this->data_[4] = v4;
103 this->data_[5] = v5;
104 }
105 /** Constructs and initializes from an array*/
106 inline Vector6(Real* array) : Vector<Real, 6>(array) {}
107
108 inline Vector6(const Vector<Real, 6>& v) : Vector<Real, 6>(v) {}
109
110 inline Vector6<Real>& operator=(const Vector<Real, 6>& v) {
111 if (this == &v) { return *this; }
113 return *this;
114 }
115};
116
117using Vector6d = Vector6<RealType>;
118
119RealType slope(const std::vector<RealType>& x, const std::vector<RealType>& y) {
120 // for (size_t i = 0; i < x.size(); i++) {
121 // std::cerr << x[i] << "\t" << y[i] << "\n";
122 // }
123 // std::cerr << "&\n";
124
125 const size_t n = x.size();
126 const RealType s_x = std::accumulate(x.begin(), x.end(), 0.0);
127 const RealType s_y = std::accumulate(y.begin(), y.end(), 0.0);
128 const RealType s_xx = std::inner_product(x.begin(), x.end(), x.begin(), 0.0);
129 const RealType s_xy = std::inner_product(x.begin(), x.end(), y.begin(), 0.0);
130 const RealType a = (n * s_xy - s_x * s_y) / (n * s_xx - s_x * s_x);
131 return a;
132}
133
134void quadraticFit(const std::vector<RealType>& x,
135 const std::vector<RealType>& y, RealType& a, RealType& b,
136 RealType& c) {
137 RealType s00 = RealType(x.size());
138 RealType s10(0.0), s20(0.0), s30(0.0), s40(0.0);
139 RealType s01(0.0), s11(0.0), s21(0.0);
140
141 for (size_t i = 0; i < x.size(); i++) {
142 // std::cerr << x[i] << "\t" << y[i] << "\n";
143 s10 += x[i];
144 s20 += pow(x[i], 2);
145 s30 += pow(x[i], 3);
146 s40 += pow(x[i], 4);
147 s01 += y[i];
148 s11 += x[i] * y[i];
149 s21 += pow(x[i], 2) * y[i];
150 }
151 // std::cerr << "&\n";
152
153 RealType D = (s40 * (s20 * s00 - s10 * s10) - s30 * (s30 * s00 - s10 * s20) +
154 s20 * (s30 * s10 - s20 * s20));
155
156 a = (s21 * (s20 * s00 - s10 * s10) - s11 * (s30 * s00 - s10 * s20) +
157 s01 * (s30 * s10 - s20 * s20)) /
158 D;
159
160 b = (s40 * (s11 * s00 - s01 * s10) - s30 * (s21 * s00 - s01 * s20) +
161 s20 * (s21 * s10 - s11 * s20)) /
162 D;
163
164 c = (s40 * (s20 * s01 - s10 * s11) - s30 * (s30 * s01 - s10 * s21) +
165 s20 * (s30 * s11 - s20 * s21)) /
166 D;
167
168 return;
169}
170
171void writeMatrix(DynamicRectMatrix<RealType> M, std::string title,
172 std::string units) {
173 std::cout << left << title << " (" << units << "):" << std::endl;
174 std::cout << std::endl;
175
176 std::cout << " ";
177 std::cout << right << setw(12) << M(0, 0) << " ";
178 std::cout << right << setw(12) << M(0, 1) << " ";
179 std::cout << right << setw(12) << M(0, 2) << " ";
180 std::cout << right << setw(12) << M(0, 3) << " ";
181 std::cout << right << setw(12) << M(0, 4) << " ";
182 std::cout << right << setw(12) << M(0, 5);
183 std::cout << std::endl;
184
185 std::cout << " ";
186 std::cout << right << setw(12) << M(1, 0) << " ";
187 std::cout << right << setw(12) << M(1, 1) << " ";
188 std::cout << right << setw(12) << M(1, 2) << " ";
189 std::cout << right << setw(12) << M(1, 3) << " ";
190 std::cout << right << setw(12) << M(1, 4) << " ";
191 std::cout << right << setw(12) << M(1, 5);
192 std::cout << std::endl;
193
194 std::cout << " ";
195 std::cout << right << setw(12) << M(2, 0) << " ";
196 std::cout << right << setw(12) << M(2, 1) << " ";
197 std::cout << right << setw(12) << M(2, 2) << " ";
198 std::cout << right << setw(12) << M(2, 3) << " ";
199 std::cout << right << setw(12) << M(2, 4) << " ";
200 std::cout << right << setw(12) << M(2, 5);
201 std::cout << std::endl;
202
203 std::cout << " ";
204 std::cout << right << setw(12) << M(3, 0) << " ";
205 std::cout << right << setw(12) << M(3, 1) << " ";
206 std::cout << right << setw(12) << M(3, 2) << " ";
207 std::cout << right << setw(12) << M(3, 3) << " ";
208 std::cout << right << setw(12) << M(3, 4) << " ";
209 std::cout << right << setw(12) << M(3, 5);
210 std::cout << std::endl;
211
212 std::cout << " ";
213 std::cout << right << setw(12) << M(4, 0) << " ";
214 std::cout << right << setw(12) << M(4, 1) << " ";
215 std::cout << right << setw(12) << M(4, 2) << " ";
216 std::cout << right << setw(12) << M(4, 3) << " ";
217 std::cout << right << setw(12) << M(4, 4) << " ";
218 std::cout << right << setw(12) << M(4, 5);
219 std::cout << std::endl;
220
221 std::cout << " ";
222 std::cout << right << setw(12) << M(5, 0) << " ";
223 std::cout << right << setw(12) << M(5, 1) << " ";
224 std::cout << right << setw(12) << M(5, 2) << " ";
225 std::cout << right << setw(12) << M(5, 3) << " ";
226 std::cout << right << setw(12) << M(5, 4) << " ";
227 std::cout << right << setw(12) << M(5, 5);
228 std::cout << std::endl;
229 std::cout << std::endl;
230}
231
232void writeBoxGeometries(Mat3x3d org, Mat3x3d opt, std::string title1,
233 std::string title2, std::string units) {
234 std::cout << left << title1 << " (" << units << "):" << std::endl;
235 std::cout << std::endl;
236 std::cout << " ";
237 std::cout << right << setw(12) << org(0, 0) << " ";
238 std::cout << right << setw(12) << org(0, 1) << " ";
239 std::cout << right << setw(12) << org(0, 2) << " ";
240 std::cout << std::endl;
241 std::cout << " ";
242 std::cout << right << setw(12) << org(1, 0) << " ";
243 std::cout << right << setw(12) << org(1, 1) << " ";
244 std::cout << right << setw(12) << org(1, 2) << " ";
245 std::cout << std::endl;
246 std::cout << " ";
247 std::cout << right << setw(12) << org(2, 0) << " ";
248 std::cout << right << setw(12) << org(2, 1) << " ";
249 std::cout << right << setw(12) << org(2, 2) << " ";
250 std::cout << std::endl;
251 std::cout << std::endl;
252 std::cout << left << title2 << " (" << units << "):" << std::endl;
253 std::cout << std::endl;
254 std::cout << " ";
255 std::cout << right << setw(12) << opt(0, 0) << " ";
256 std::cout << right << setw(12) << opt(0, 1) << " ";
257 std::cout << right << setw(12) << opt(0, 2) << " ";
258 std::cout << std::endl;
259 std::cout << " ";
260 std::cout << right << setw(12) << opt(1, 0) << " ";
261 std::cout << right << setw(12) << opt(1, 1) << " ";
262 std::cout << right << setw(12) << opt(1, 2) << " ";
263 std::cout << std::endl;
264 std::cout << " ";
265 std::cout << right << setw(12) << opt(2, 0) << " ";
266 std::cout << right << setw(12) << opt(2, 1) << " ";
267 std::cout << right << setw(12) << opt(2, 2) << " ";
268 std::cout << std::endl;
269 std::cout << std::endl;
270}
271
272void writeMaterialProperties(DynamicRectMatrix<RealType> C,
274 RealType C11 = C(0, 0);
275 RealType C22 = C(1, 1);
276 RealType C33 = C(2, 2);
277 RealType C12 = C(0, 1);
278 RealType C23 = C(1, 2);
279 RealType C31 = C(2, 0);
280 RealType C44 = C(3, 3);
281 RealType C55 = C(4, 4);
282 RealType C66 = C(5, 5);
283
284 RealType S11 = S(0, 0);
285 RealType S22 = S(1, 1);
286 RealType S33 = S(2, 2);
287 RealType S12 = S(0, 1);
288 RealType S23 = S(1, 2);
289 RealType S31 = S(2, 0);
290 RealType S44 = S(3, 3);
291 RealType S55 = S(4, 4);
292 RealType S66 = S(5, 5);
293
294 // Material Properties defined in:
295 //
296 // "Charting the complete elastic properties of inorganic
297 // crystalline compounds," Maarten de Jong, Wei Chen, Thomas
298 // Angsten, Anubhav Jain, Randy Notestine, Anthony Gamst, Marcel
299 // Sluiter, Chaitanya Krishna Ande, Sybrand van der Zwaag, Jose J
300 // Plata, Cormac Toher, Stefano Curtarolo, Gerbrand Ceder, Kristin
301 // A. Persson & Mark Asta,
302 //
303 // Scientific Data volume 2, Article number: 150009 (2015)
304 // doi:10.1038/sdata.2015.9
305 //
306 // And in
307 //
308 // "ELATE: an open-source online application for analysis and
309 // visualization of elastic tensors," Romain Gaillac, Pluton
310 // Pullumbi and François-Xavier Coudert,
311 //
312 // J. Phys.: Condens. Matter 28 275201 (2016)
313 // doi:10.1088/0953-8984/28/27/275201
314
315 // Bulk modulus (Voigt average):
316 RealType Kv = ((C11 + C22 + C33) + 2.0 * (C12 + C23 + C31)) / 9.0;
317 // Bulk modulus (Reuss average):
318 RealType Kr = 1.0 / ((S11 + S22 + S33) + 2.0 * (S12 + S23 + S31));
319 // Shear modulus (Voigt average):
320 RealType Gv =
321 ((C11 + C22 + C33) - (C12 + C23 + C31) + 3.0 * (C44 + C55 + C66)) / 15.0;
322 // Shear modulus (Reuss average):
323 RealType Gr = 15.0 / (4.0 * (S11 + S22 + S33) - 4.0 * (S12 + S23 + S31) +
324 3.0 * (S44 + S55 + S66));
325 // Bulk modulus (Hill average):
326 RealType Kh = (Kv + Kr) / 2.0;
327 // Shear modulus (Hill average):
328 RealType Gh = (Gv + Gr) / 2.0;
329 // Universal elastic anisotropy
330 RealType Au = 5.0 * (Gv / Gr) + (Kv / Kr) - 6.0;
331 // Isotropic Poisson ratio
332 RealType muv = (1.0 - 3.0 * Gv / (3.0 * Kv + Gv)) / 2.0;
333 RealType mur = (1.0 - 3.0 * Gr / (3.0 * Kr + Gr)) / 2.0;
334 RealType muh = (1.0 - 3.0 * Gh / (3.0 * Kh + Gh)) / 2.0;
335 // Isotropic Young's modulus
336 RealType Ev = 1.0 / (1.0 / (3.0 * Gv) + 1.0 / (9.0 * Kv));
337 RealType Er = 1.0 / (1.0 / (3.0 * Gr) + 1.0 / (9.0 * Kr));
338 RealType Eh = 1.0 / (1.0 / (3.0 * Gh) + 1.0 / (9.0 * Kh));
339
340 std::cout << " " << setw(12) << "Voigt"
341 << " " << setw(12) << "Reuss"
342 << " " << setw(12) << "Hill\n";
343 std::cout << "Bulk modulus: " << setw(12) << Kv << " "
344 << setw(12) << Kr << " " << setw(12) << Kh << " (GPa)\n";
345
346 std::cout << "Shear modulus: " << setw(12) << Gv << " "
347 << setw(12) << Gr << " " << setw(12) << Gh << " (GPa)\n";
348
349 std::cout << "Young\'s modulus (isotropic): " << setw(12) << Ev << " "
350 << setw(12) << Er << " " << setw(12) << Eh << " (GPa)\n";
351
352 std::cout << "Poisson\'s Ratio: " << setw(12) << muv << " "
353 << setw(12) << mur << " " << setw(12) << muh << "\n";
354
355 std::cout << "Universal elastic Anisotropy: " << setw(12) << Au << "\n";
356
357 // Assume a cubic crystal, and use symmetries:
358
359 // C11 = (C(0,0) + C(1,1) + C(2,2)) / 3.0;
360 // C12 = (C(0,1) + C(0,2) + C(1,2)) / 3.0;
361 // C44 = (C(3,3) + C(4,4) + C(5,5)) / 3.0;
362 // S11 = (S(0,0) + S(1,1) + S(2,2)) / 3.0;
363 // S12 = (S(0,1) + S(0,2) + S(1,2)) / 3.0;
364 // S44 = (S(3,3) + S(4,4) + S(5,5)) / 3.0;
365
366 // Anisotropy factor
367 // RealType A1 = 2.0*C44 / (C11 - C12);
368 // RealType A2 = 2.0*(S11 - S12) / S44;
369
370 // std::cout << "Anisotropy factor = " << A1 << " " << A2 << "\n";
371
372 // Effective Elastic constants for propagation in Cubic Crystals
373 // RealType kL_100 = C11;
374 // RealType kT_100 = C44;
375 // RealType kL_110 = 0.5 * (C11 + C12 + 2.0*C44);
376 // RealType kT1_110 = C44;
377 // RealType kT2_110 = 0.5*(C11 - C12);
378 // RealType kL_111 = (C11 + 2*C12 + 4*C44) / 3.0;
379 // RealType kT_111 = (C11 - C12 + C44) / 3.0;
380}
381
382int main(int argc, char* argv[]) {
383 std::string method;
384 std::string inputFileName;
385 std::string outputFileName;
386
387 gengetopt_args_info args_info;
388
389 // parse command line arguments
390 if (cmdline_parser(argc, argv, &args_info) != 0) {
392 exit(1);
393 }
394
395 // get input file name
396 if (args_info.input_given) {
397 inputFileName = args_info.input_arg;
398 } else {
399 if (args_info.inputs_num) {
400 inputFileName = args_info.inputs[0];
401 } else {
402 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
403 "No input file name was specified on the command line");
404 painCave.severity = OPENMD_ERROR;
405 painCave.isFatal = 1;
406 simError();
407 }
408 }
409
410 method = "energy";
411 if (args_info.method_given) {
412 method = args_info.method_arg;
413 toLower(method);
414 }
415
416 int nMax = args_info.npoints_arg;
417
418 RealType dmax;
419 if (args_info.delta_given) {
420 dmax = args_info.delta_arg;
421 } else {
422 if (!method.compare("energy")) {
423 dmax = 0.09;
424 } else {
425 dmax = 0.003;
426 }
427 }
428
429 // The strain basis sets are originally from:
430
431 // "Calculations of single-crystal elastic constants made simple,"
432 // R. Yu, J. Zhu, H.Q. Ye,
433 // Computer Physics Communications 181 (2010) 671–675,
434 // DOI: 10.1016/j.cpc.2009.11.017
435 //
436 // and
437 //
438 // "ElaStic: A tool for calculating second-order elastic
439 // constants from first principles," Rostam Golesorkhtabara,
440 // Pasquale Pavonea, Jürgen Spitalera, Peter Puschniga, Claudia Draxl,
441 // Computer Physics Communications 184 (2013) 1861–1873,
442 // DOI: 10.1016/j.cpc.2013.03.010
443 //
444 // Note that this our version assumes the worst about the crystal
445 // system present the box (e.g. a Triclinic box in the N Laue
446 // group).
447
448 std::vector<Vector6d> eStrains;
449 // Only the strains for the "N" Laue group are used (1-21, skipping 0)
450 // eStrains.push_back(Vector6d( 1., 1., 1., 0., 0., 0.));
451 eStrains.push_back(Vector6d(1., 0., 0., 0., 0., 0.));
452 eStrains.push_back(Vector6d(0., 1., 0., 0., 0., 0.));
453 eStrains.push_back(Vector6d(0., 0., 1., 0., 0., 0.));
454 eStrains.push_back(Vector6d(0., 0., 0., 2., 0., 0.));
455 eStrains.push_back(Vector6d(0., 0., 0., 0., 2., 0.));
456 eStrains.push_back(Vector6d(0., 0., 0., 0., 0., 2.));
457 eStrains.push_back(Vector6d(1., 1., 0., 0., 0., 0.));
458 eStrains.push_back(Vector6d(1., 0., 1., 0., 0., 0.));
459 eStrains.push_back(Vector6d(1., 0., 0., 2., 0., 0.));
460 eStrains.push_back(Vector6d(1., 0., 0., 0., 2., 0.));
461 eStrains.push_back(Vector6d(1., 0., 0., 0., 0., 2.));
462 eStrains.push_back(Vector6d(0., 1., 1., 0., 0., 0.));
463 eStrains.push_back(Vector6d(0., 1., 0., 2., 0., 0.));
464 eStrains.push_back(Vector6d(0., 1., 0., 0., 2., 0.));
465 eStrains.push_back(Vector6d(0., 1., 0., 0., 0., 2.));
466 eStrains.push_back(Vector6d(0., 0., 1., 2., 0., 0.));
467 eStrains.push_back(Vector6d(0., 0., 1., 0., 2., 0.));
468 eStrains.push_back(Vector6d(0., 0., 1., 0., 0., 2.));
469 eStrains.push_back(Vector6d(0., 0., 0., 2., 2., 0.));
470 eStrains.push_back(Vector6d(0., 0., 0., 2., 0., 2.));
471 eStrains.push_back(Vector6d(0., 0., 0., 0., 2., 2.));
472
473 // The rest (22-28) are only used for crystals of higher symmetry,
474 // and are not utilized in this code:
475 //
476 // eStrains.push_back(Vector6d( 0., 0., 0., 2., 2., 2.));
477 // eStrains.push_back(Vector6d(-1., .5, .5, 0., 0., 0.));
478 // eStrains.push_back(Vector6d( .5,-1., .5, 0., 0., 0.));
479 // eStrains.push_back(Vector6d( .5, .5,-1., 0., 0., 0.));
480 // eStrains.push_back(Vector6d( 1.,-1., 0., 0., 0., 0.));
481 // eStrains.push_back(Vector6d( 1.,-1., 0., 0., 0., 2.));
482 // eStrains.push_back(Vector6d( 0., 1.,-1., 0., 0., 2.));
483 // eStrains.push_back(Vector6d( .5, .5,-1., 0., 0., 2.));
484 // eStrains.push_back(Vector6d( 1., 0., 0., 2., 2., 0.));
485 // eStrains.push_back(Vector6d( 1., 1.,-1., 0., 0., 0.));
486 // eStrains.push_back(Vector6d( 1., 1., 1.,-2.,-2.,-2.));
487 // eStrains.push_back(Vector6d( .5, .5,-1., 2., 2., 2.));
488 // eStrains.push_back(Vector6d( 0., 0., 0., 2., 2., 4.));
489
490 // The Universal Linear-Independent Coupling Strains (ULICS) are from:
491 //
492 // "Calculations of single-crystal elastic constants made simple,"
493 // R. Yu, J. Zhu, H.Q. Ye,
494 // Computer Physics Communications 181 (2010) 671–675,
495 // DOI: 10.1016/j.cpc.2009.11.017
496
497 std::vector<Vector6d> sStrains;
498 sStrains.push_back(Vector6d(1., 2., 3., 4., 5., 6.));
499 sStrains.push_back(Vector6d(-2., 1., 4., -3., 6., -5.));
500 sStrains.push_back(Vector6d(3., -5., -1., 6., 2., -4.));
501 sStrains.push_back(Vector6d(-4., -6., 5., 1., -3., 2.));
502 sStrains.push_back(Vector6d(5., 4., 6., -2., -1., -3.));
503 sStrains.push_back(Vector6d(-6., 3., -2., 5., -4., 1.));
504
505 std::vector<Vector6d> strainBasis;
506
507 if (!method.compare("energy")) {
508 strainBasis = eStrains;
509 } else {
510 strainBasis = sStrains;
511 }
512
513 // The matrix to perform the linear least squares fits from the
514 // ULICS to find the elastic constants were derived for the ElaStic
515 // code, Golesorkhtabara, et al. (cited above):
516
517 RealType mat[36][21] = {
518 {1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
519 {0, 1, 0, 0, 0, 0, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
520 {0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0},
521 {0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 4, 5, 6, 0, 0, 0},
522 {0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 4, 0, 5, 6, 0},
523 {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 4, 0, 5, 6},
524 {-2, 1, 4, -3, 6, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
525 {0, -2, 0, 0, 0, 0, 1, 4, -3, 6, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
526 {0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 0, 4, -3, 6, -5, 0, 0, 0, 0, 0, 0},
527 {0, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, -3, 6, -5, 0, 0, 0},
528 {0, 0, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, -3, 0, 6, -5, 0},
529 {0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, -3, 0, 6, -5},
530 {3, -5, -1, 6, 2, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
531 {0, 3, 0, 0, 0, 0, -5, -1, 6, 2, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
532 {0, 0, 3, 0, 0, 0, 0, -5, 0, 0, 0, -1, 6, 2, -4, 0, 0, 0, 0, 0, 0},
533 {0, 0, 0, 3, 0, 0, 0, 0, -5, 0, 0, 0, -1, 0, 0, 6, 2, -4, 0, 0, 0},
534 {0, 0, 0, 0, 3, 0, 0, 0, 0, -5, 0, 0, 0, -1, 0, 0, 6, 0, 2, -4, 0},
535 {0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -5, 0, 0, 0, -1, 0, 0, 6, 0, 2, -4},
536 {-4, -6, 5, 1, -3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
537 {0, -4, 0, 0, 0, 0, -6, 5, 1, -3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
538 {0, 0, -4, 0, 0, 0, 0, -6, 0, 0, 0, 5, 1, -3, 2, 0, 0, 0, 0, 0, 0},
539 {0, 0, 0, -4, 0, 0, 0, 0, -6, 0, 0, 0, 5, 0, 0, 1, -3, 2, 0, 0, 0},
540 {0, 0, 0, 0, -4, 0, 0, 0, 0, -6, 0, 0, 0, 5, 0, 0, 1, 0, -3, 2, 0},
541 {0, 0, 0, 0, 0, -4, 0, 0, 0, 0, -6, 0, 0, 0, 5, 0, 0, 1, 0, -3, 2},
542 {5, 4, 6, -2, -1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
543 {0, 5, 0, 0, 0, 0, 4, 6, -2, -1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
544 {0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 6, -2, -1, -3, 0, 0, 0, 0, 0, 0},
545 {0, 0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, -2, -1, -3, 0, 0, 0},
546 {0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, -2, 0, -1, -3, 0},
547 {0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, -2, 0, -1, -3},
548 {-6, 3, -2, 5, -4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
549 {0, -6, 0, 0, 0, 0, 3, -2, 5, -4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
550 {0, 0, -6, 0, 0, 0, 0, 3, 0, 0, 0, -2, 5, -4, 1, 0, 0, 0, 0, 0, 0},
551 {0, 0, 0, -6, 0, 0, 0, 0, 3, 0, 0, 0, -2, 0, 0, 5, -4, 1, 0, 0, 0},
552 {0, 0, 0, 0, -6, 0, 0, 0, 0, 3, 0, 0, 0, -2, 0, 0, 5, 0, -4, 1, 0},
553 {0, 0, 0, 0, 0, -6, 0, 0, 0, 0, 3, 0, 0, 0, -2, 0, 0, 5, 0, -4, 1}};
554
556
557 // register forcefields, integrators and minimizers
558 registerAll();
559
560 // Parse the input file, set up the system, and read the last frame:
561 SimCreator creator;
562 SimInfo* info = creator.createSim(inputFileName, true);
563 Globals* simParams = info->getSimParams();
564 ForceManager* forceMan = new ForceManager(info);
565
566 std::unique_ptr<Velocitizer> veloSet {std::make_unique<Velocitizer>(info)};
567
568 forceMan->initialize();
569
570 Shake* shake = new Shake(info);
571 bool hasFlucQ = false;
573
574 if (info->usesFluctuatingCharges()) {
575 if (info->getNFluctuatingCharges() > 0) {
576 hasFlucQ = true;
577 flucQ->setForceManager(forceMan);
578 flucQ->initialize();
579 }
580 }
581
582 // Important utility classes for computing system properties:
583 Thermo thermo(info);
584
585 // Just in case we were passed a system that is on the move:
586 veloSet->removeComDrift();
587
588 if (args_info.box_flag) {
589 std::cout << "Doing box optimization\n\n";
590 Mat3x3d oldHmat =
592
593 MinimizerParameters* miniPars = simParams->getMinimizerParameters();
594 // OptimizationMethod* minim =
595 // OptimizationFactory::getInstance().createOptimization(toUpperCopy(miniPars->getMethod()),
596 // info);
597 OptimizationMethod* minim =
599
600 if (minim == NULL) {
601 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
602 "Optimization Factory can not create %s OptimizationMethod\n",
603 miniPars->getMethod().c_str());
604 painCave.isFatal = 1;
605 simError();
606 }
607
608 BoxObjectiveFunction boxObjf(info, forceMan);
609 NoConstraint noConstraint {};
610 DumpStatusFunction dsf(info);
611 DynamicVector<RealType> initCoords = boxObjf.setInitialCoords();
612 Problem problem(boxObjf, noConstraint, dsf, initCoords);
613
614 int maxIter = miniPars->getMaxIterations();
615 int mssIter = miniPars->getMaxStationaryStateIterations();
616 RealType rEps = miniPars->getRootEpsilon();
617 RealType fEps = miniPars->getFunctionEpsilon();
618 RealType gnEps = miniPars->getGradientNormEpsilon();
619 RealType initialStepSize = miniPars->getInitialStepSize();
620
621 EndCriteria endCriteria(maxIter, mssIter, rEps, fEps, gnEps);
622
623 minim->minimize(problem, endCriteria, initialStepSize);
624 delete minim;
625
626 Mat3x3d newHmat =
628 writeBoxGeometries(oldHmat, newHmat, "Original Box Geometry",
629 "Optimized Box Geometry", "Angstroms");
630 }
631
633 Mat3x3d refHmat = snap->getHmat();
634
635 forceMan->calcForces();
636 Mat3x3d ptRef = thermo.getPressureTensor();
637 RealType V0 = thermo.getVolume();
638 ptRef.negate();
639 ptRef *= Constants::elasticConvert;
640
641 Vector6d stress(0.0);
642 Vector6d strain(0.0);
643 Vector6d lstress(0.0);
644 Mat3x3d epsilon(0.0);
645
646 std::vector<std::vector<RealType>> stressStrain;
647 std::vector<RealType> strainValues;
648 std::vector<RealType> energyValues;
649 DynamicRectMatrix<RealType> C(6, 6, 0.0);
650 DynamicRectMatrix<RealType> S(6, 6, 0.0);
651 DynamicVector<RealType> ci(21, 0.0);
652 DynamicVector<RealType> sigma(36, 0.0);
653
654 Vector3d pos;
655 SimInfo::MoleculeIterator miter;
656 Molecule* mol;
657 RealType de;
658 Vector3d delta;
659
660 Vector6d L(0.0);
661 Mat3x3d eta(0.0);
662 Mat3x3d eps(0.0);
663 Mat3x3d x(0.0);
664 Mat3x3d test(0.0);
665 Mat3x3d deformation(0.0);
666 std::vector<RealType> A2;
667 RealType norm;
668 RealType a, b, c;
669 RealType energy;
670 Mat3x3d pressureTensor;
671
672 for (std::vector<Vector6d>::iterator it = strainBasis.begin();
673 it != strainBasis.end(); ++it) {
674 strain = *it;
675 int ii = std::distance(strainBasis.begin(), it);
676
677 strainValues.clear();
678 energyValues.clear();
679 stressStrain.clear();
680 stressStrain.resize(6);
681
682 for (int n = 0; n < nMax; n++) {
683 // First, set up the deformation of the box and coodinates:
684 de = -0.5 * dmax + dmax * RealType(n) / RealType(nMax - 1);
685 L = strain * de;
686
687 // η is the Lagrangian strain tensor:
688 eta.setupVoigtTensor(L[0], L[1], L[2], L[3] / 2., L[4] / 2., L[5] / 2.);
689
690 // Make sure the deformation isn't too large:
691 if (eta.frobeniusNorm() > 0.7) {
692 std::cerr << "Deformation is too large!\n";
693 }
694
695 // Find the physical strain tensor, ε, from the Lagrangian strain, η:
696 // η = ε + 0.5 * ε^2
697 norm = 1.0;
698 eps = eta;
699 while (norm > 1.0e-10) {
700 x = eta - eps * eps / 2.0;
701 test = x - eps;
702 norm = test.frobeniusNorm();
703 eps = x;
704 }
705 deformation = SquareMatrix3<RealType>::identity() + eps;
706
707 // Second, do the deformation and compute the energy or stress
708 // tensor for this deformation:
709 info->getSnapshotManager()->advance();
710 for (mol = info->beginMolecule(miter); mol != NULL;
711 mol = info->nextMolecule(miter)) {
712 pos = mol->getCom();
713 delta = deformation * pos;
714 mol->moveCom(delta - pos);
715 }
716 Mat3x3d Hmat = deformation * refHmat;
717 snap->setHmat(Hmat);
718 shake->constraintR();
719 forceMan->calcForces();
720 if (hasFlucQ) flucQ->applyConstraints();
721 shake->constraintF();
722
723 // Third, record the energy or the stress:
724 if (!method.compare("energy")) {
725 energy = thermo.getPotential();
726 energyValues.push_back(energy);
727
728 } else {
729 // Find the Lagragian stress tensor, τ, from the physical
730 // stress tensor, σ, that was computed from the pressureTensor
731 // in this code.
732 // τ = det(1+ε) (1+ε)^−1 · σ · (1+ε)^−1
733 // (Note that 1+ε is the deformation tensor computed above.)
734
735 Mat3x3d idm = deformation.inverse();
736 RealType ddm = deformation.determinant();
737
738 pressureTensor = thermo.getPressureTensor();
739 pressureTensor.negate();
740 pressureTensor *= Constants::elasticConvert;
741
742 Mat3x3d tao = idm * (pressureTensor * idm);
743 tao *= ddm;
744
745 lstress = tao.toVoigtTensor();
746
747 for (int j = 0; j < 6; j++) {
748 stressStrain[j].push_back(lstress[j]);
749 }
750 }
751
752 strainValues.push_back(de);
753 info->getSnapshotManager()->resetToPrevious();
754 }
755
756 // Fit the energy vs. strain (quadratic) or stress vs. strain (linear)
757 if (!method.compare("energy")) {
758 quadraticFit(strainValues, energyValues, a, b, c);
759 A2.push_back(a * Constants::energyElasticConvert / V0);
760 } else {
761 for (int j = 0; j < 6; j++) {
762 quadraticFit(strainValues, stressStrain[j], a, b, c);
763 sigma(6 * ii + j) = b;
764 // sigma(6*ii + j) = slope(strainValues, stressStrain[j]);
765 }
766 }
767 }
768
769 if (!method.compare("energy")) {
770 C(0, 0) = 2. * A2[0];
771 C(0, 1) = 1. * (-A2[0] - A2[1] + A2[6]);
772 C(0, 2) = 1. * (-A2[0] - A2[2] + A2[7]);
773 C(0, 3) = .5 * (-A2[0] - A2[3] + A2[8]);
774 C(0, 4) = .5 * (-A2[0] + A2[9] - A2[4]);
775 C(0, 5) = .5 * (-A2[0] + A2[10] - A2[5]);
776 C(1, 1) = 2. * A2[1];
777 C(1, 2) = 1. * (A2[11] - A2[1] - A2[2]);
778 C(1, 3) = .5 * (A2[12] - A2[1] - A2[3]);
779 C(1, 4) = .5 * (A2[13] - A2[1] - A2[4]);
780 C(1, 5) = .5 * (A2[14] - A2[1] - A2[5]);
781 C(2, 2) = 2. * A2[2];
782 C(2, 3) = .5 * (A2[15] - A2[2] - A2[3]);
783 C(2, 4) = .5 * (A2[16] - A2[2] - A2[4]);
784 C(2, 5) = .5 * (A2[17] - A2[2] - A2[5]);
785 C(3, 3) = .5 * A2[3];
786 C(3, 4) = .25 * (A2[18] - A2[3] - A2[4]);
787 C(3, 5) = .25 * (A2[19] - A2[3] - A2[5]);
788 C(4, 4) = .5 * A2[4];
789 C(4, 5) = .25 * (A2[20] - A2[4] - A2[5]);
790 C(5, 5) = .5 * A2[5];
791 } else {
792 // Least squares to map fits of stress-strain relationships onto
793 // elastic matrix:
794
795 QR<RealType> qr(drMat);
796 ci = qr.solve(sigma);
797
798 C(0, 0) = ci(0);
799 C(0, 1) = ci(1);
800 C(0, 2) = ci(2);
801 C(0, 3) = ci(3);
802 C(0, 4) = ci(4);
803 C(0, 5) = ci(5);
804 C(1, 1) = ci(6);
805 C(1, 2) = ci(7);
806 C(1, 3) = ci(8);
807 C(1, 4) = ci(9);
808 C(1, 5) = ci(10);
809 C(2, 2) = ci(11);
810 C(2, 3) = ci(12);
811 C(2, 4) = ci(13);
812 C(2, 5) = ci(14);
813 C(3, 3) = ci(15);
814 C(3, 4) = ci(16);
815 C(3, 5) = ci(17);
816 C(4, 4) = ci(18);
817 C(4, 5) = ci(19);
818 C(5, 5) = ci(20);
819 }
820
821 // Symmetrize C:
822
823 for (int i = 0; i < 5; i++) {
824 for (int j = i + 1; j < 6; j++) {
825 C(j, i) = C(i, j);
826 }
827 }
828
829 // matrix is destroyed during inversion, so make a working copy:
831 invertMatrix(tmpMat, S);
832
833 writeMatrix(C, "Elastic Tensor", "GPa");
834 writeMatrix(S, "Compliance Tensor", "GPa^-1");
835
836 writeMaterialProperties(C, S);
837
838 delete flucQ;
839 delete shake;
840 delete forceMan;
841 return 0;
842}
Abstract constraint class.
void cmdline_parser_print_help(void)
Print the help.
Abstract optimization method class.
Abstract optimization problem class.
Rectangular matrix class with contiguous flat storage.
Dynamically-sized vector class.
abstract class for propagating fluctuating charge variables
ForceManager is responsible for calculating both the short range (bonded) interactions and long range...
void moveCom(const Vector3d &delta)
Moves the center of this molecule.
Definition Molecule.cpp:358
Vector3d getCom()
Returns the current center of mass position of this molecule.
Definition Molecule.cpp:315
static OptimizationFactory & getInstance()
Returns an instance of Optimization factory.
QuantLib::OptimizationMethod * createOptimization(const std::string &id, SimInfo *info)
Looks up the type identifier in the internal map.
void negate()
Negates the value of this matrix in place.
The only responsibility of SimCreator is to parse the meta-data file and create a SimInfo instance ba...
SimInfo * createSim(const std::string &mdFileName, bool loadInitCoords=true)
Setup Simulation.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:243
int getNFluctuatingCharges()
Returns the total number of fluctuating charges that are present.
Definition SimInfo.hpp:220
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:248
SnapshotManager * getSnapshotManager()
Returns the snapshot manager.
Definition SimInfo.hpp:251
The Snapshot class is a repository storing dynamic data during a Simulation.
Definition Snapshot.hpp:166
Mat3x3d getHmat()
Returns the H-Matrix.
Definition Snapshot.cpp:217
void setHmat(const Mat3x3d &m)
Sets the H-Matrix.
Definition Snapshot.cpp:220
Snapshot * getCurrentSnapshot()
Returns the pointer of current snapshot.
Fix length vector class.
Definition Vector.hpp:81
Vector< Real, Dim > & operator=(const Vector< Real, Dim > &v)
copy assignment operator
Definition Vector.hpp:96
Criteria to end optimization process:
Abstract class for constrained optimization method.
Definition Method.hpp:36
virtual EndCriteria::Type minimize(Problem &P, const EndCriteria &endCriteria, RealType initialStepSize)=0
minimize the optimization problem P
Constrained optimization problem.
Definition Problem.hpp:37
The header file for the command line option parser generated by GNU Gengetopt version 2....
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
void registerAll()
register force fields, integrators and optimizers
Definition Register.cpp:143
bool invertMatrix(MatrixType &A, MatrixType &AI)
Invert input square matrix A into matrix AI.
Definition LU.hpp:101
Where the command line options are stored.
unsigned inputs_num
unamed options number
char ** inputs
unamed options (options without names)
char * input_arg
input dump file.
unsigned int method_given
Whether method was given.
int npoints_arg
number of points for fitting stress-strain relationship (default='25').
unsigned int delta_given
Whether delta was given.
double delta_arg
size of relative volume changes for strains.
int box_flag
Optimize box geometry before performing calculation (default=off).
unsigned int input_given
Whether input was given.
char * method_arg
Calculation Method.