OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
nanorod_pentBuilder.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 <config.h>
46
47#include <algorithm>
48#include <cmath>
49#include <cstdio>
50#include <cstdlib>
51#include <cstring>
52#include <fstream>
53#include <iostream>
54#include <map>
55#include <random>
56#include <string>
57
58#include "brains/Register.hpp"
59#include "brains/SimCreator.hpp"
60#include "brains/SimInfo.hpp"
61#include "io/DumpWriter.hpp"
62#include "lattice/Lattice.hpp"
66#include "shapedLatticePentRod.hpp"
67#include "shapedLatticeRod.hpp"
68#include "utils/Constants.hpp"
69#include "utils/MoLocator.hpp"
70#include "utils/StringUtils.hpp"
71
72using namespace std;
73using namespace OpenMD;
74void createMdFile(const std::string& oldMdFileName,
75 const std::string& newMdFileName, std::vector<int> numMol);
76
77int main(int argc, char* argv[]) {
79
80 gengetopt_args_info args_info;
81 std::string latticeType;
82 std::string inputFileName;
83 std::string outputFileName;
84 MoLocator* locator;
85 int nComponents;
86 double latticeConstant;
87 RealType rodRadius;
88 RealType rodLength;
89 Mat3x3d hmat;
90 DumpWriter* writer;
91
92 // Parse Command Line Arguments
93 if (cmdline_parser(argc, argv, &args_info) != 0) exit(1);
94
95 /* get lattice type */
96 latticeType = "FCC";
97
98 /* get input file name */
99 if (args_info.inputs_num)
100 inputFileName = args_info.inputs[0];
101 else {
102 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
103 "No input .omd file name was specified "
104 "on the command line");
105 painCave.isFatal = 1;
106 cmdline_parser_print_help();
107 simError();
108 }
109
110 /* parse md file and set up the system */
111 SimCreator oldCreator;
112 SimInfo* oldInfo = oldCreator.createSim(inputFileName, false);
113
114 latticeConstant = args_info.latticeConstant_arg;
115 rodRadius = args_info.radius_arg;
116 rodLength = args_info.length_arg;
117 Globals* simParams = oldInfo->getSimParams();
118
119 /* Create nanorod */
120 shapedLatticePentRod nanoRod(latticeConstant, latticeType, rodRadius,
121 rodLength);
122
123 /* Set up the random number generator engine */
124 std::random_device rd; // Non-deterministic, uniformly-distributed integer
125 // random number generator
126 std::mt19937 gen(rd()); // 32-bit Mersenne Twister random number engine
127
128 /* Build a lattice and get lattice points for this lattice constant */
129
130 // Rotation angles for lattice
131 RealType phi, theta, psi;
132
133 /*
134 RealType cphi, sphi, ctheta, stheta, cpsi, spsi;
135
136 cphi = cos(phi);
137 sphi = sin(phi);
138 ctheta = cos(theta);
139 stheta = sin(theta);
140 cpsi = cos(psi);
141 spsi = sin(psi);
142 */
143
144 // Rotates 45 degrees about z-axis
145 RotMat3x3d rotation45(45.0 * Constants::PI / 180.0, 0.0, 0.0);
146
147 /*rotation45[0][0] = sqrt(2)/2;
148 rotation45[0][1] = -sqrt(2)/2;
149 rotation45[0][2] = 0;
150 rotation45[1][0] = sqrt(2)/2;
151 rotation45[1][1] = sqrt(2)/2;
152 rotation45[1][2] = 0;
153 rotation45[2][0] = 0;
154 rotation45[2][1] = 0;
155 rotation45[2][2] = 1;*/
156
157 phi = 0.0;
158 theta = 72.0 * Constants::PI / 180.0;
159 psi = 0.0;
160
161 // Rotates 72 degrees about y-axis
162 RotMat3x3d rotation72(phi, theta, psi);
163
164 /*rotation72[0][0] = sqrt(5)/4 - 0.25;
165 rotation72[0][1] = 0;
166 rotation72[0][2] = sqrt(2*(sqrt(5) + 5))/4;
167 rotation72[1][0] = 0;
168 rotation72[1][1] = 1;
169 rotation72[1][2] = 0;
170 rotation72[2][0] = -sqrt(2*(sqrt(5) + 5))/4;
171 rotation72[2][1] = 0;
172 rotation72[2][2] = sqrt(5)/4 - 0.25;*/
173
174 vector<Vector3d> getsites = nanoRod.getSites();
175 vector<Vector3d> getorientations = nanoRod.getOrientations();
176 vector<Vector3d> sites;
177 vector<Vector3d> orientations;
178
179 for (unsigned int index = 0; index < getsites.size(); index++) {
180 Vector3d mySite = getsites[index];
181 Vector3d myOrient = getorientations[index];
182 Vector3d mySite2 = rotation45 * mySite;
183 Vector3d o2 = rotation45 * myOrient;
184 sites.push_back(mySite2);
185 orientations.push_back(o2);
186
187 mySite2 = rotation72 * mySite2;
188 o2 = rotation72 * o2;
189 sites.push_back(mySite2);
190 orientations.push_back(o2);
191
192 mySite2 = rotation72 * mySite2;
193 o2 = rotation72 * o2;
194 sites.push_back(mySite2);
195 orientations.push_back(o2);
196
197 mySite2 = rotation72 * mySite2;
198 o2 = rotation72 * o2;
199 sites.push_back(mySite2);
200 orientations.push_back(o2);
201
202 mySite2 = rotation72 * mySite2;
203 o2 = rotation72 * o2;
204 sites.push_back(mySite2);
205 orientations.push_back(o2);
206 }
207
208 int nCenter = int((rodLength + 1.154700538 * rodRadius) / 2.88);
209
210 for (unsigned int index = 0; index <= 0.5 * nCenter; index++) {
211 Vector3d myLoc_top(2.88 * index, 0.0, 0.0);
212 sites.push_back(myLoc_top);
213 orientations.push_back(Vector3d(0.0));
214 }
215
216 for (unsigned int index = 1; index <= 0.5 * nCenter; index++) {
217 Vector3d myLoc_bottom(-2.88 * index, 0.0, 0.0);
218 sites.push_back(myLoc_bottom);
219 orientations.push_back(Vector3d(0.0));
220 }
221
222 std::vector<std::size_t> vacancyTargets;
223 vector<bool> isVacancy;
224
225 Vector3d myLoc;
226 RealType myR;
227
228 for (unsigned int i = 0; i < sites.size(); i++)
229 isVacancy.push_back(false);
230
231 // cerr << "checking vacancyPercent" << "\n";
232 if (args_info.vacancyPercent_given) {
233 // cerr << "vacancyPercent given" << "\n";
234 if (args_info.vacancyPercent_arg < 0.0 ||
235 args_info.vacancyPercent_arg > 100.0) {
236 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
237 "vacancyPercent was set to a non-sensical value.");
238 painCave.isFatal = 1;
239 simError();
240 } else {
241 RealType vF = args_info.vacancyPercent_arg / 100.0;
242 // cerr << "vacancyPercent = " << vF << "\n";
243 RealType vIR;
244 RealType vOR;
245 if (args_info.vacancyInnerRadius_given) {
246 vIR = args_info.vacancyInnerRadius_arg;
247 } else {
248 vIR = 0.0;
249 }
250 if (args_info.vacancyOuterRadius_given) {
251 vOR = args_info.vacancyOuterRadius_arg;
252 } else {
253 vOR = rodRadius;
254 }
255 if (vIR >= 0.0 && vOR <= rodRadius && vOR >= vIR) {
256 for (unsigned int i = 0; i < sites.size(); i++) {
257 myLoc = sites[i];
258 myR = myLoc.length();
259 if (myR >= vIR && myR <= vOR) { vacancyTargets.push_back(i); }
260 }
261 std::shuffle(vacancyTargets.begin(), vacancyTargets.end(), gen);
262
263 int nTargets = vacancyTargets.size();
264 vacancyTargets.resize((int)(vF * nTargets));
265
266 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
267 "Removing %d atoms from randomly-selected\n"
268 "\tsites between %lf and %lf.",
269 (int)vacancyTargets.size(), vIR, vOR);
270 painCave.severity = OPENMD_INFO;
271 painCave.isFatal = 0;
272 simError();
273
274 isVacancy.clear();
275 for (std::size_t i = 0; i < sites.size(); i++) {
276 bool vac = false;
277 for (std::size_t j = 0; j < vacancyTargets.size(); j++) {
278 if (i == vacancyTargets[j]) vac = true;
279 }
280 isVacancy.push_back(vac);
281 }
282
283 } else {
284 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
285 "Something is strange about the vacancy\n"
286 "\tinner or outer radii. Check their values.");
287 painCave.isFatal = 1;
288 simError();
289 }
290 }
291 }
292
293 /* Get number of lattice sites */
294 int nSites = sites.size() - vacancyTargets.size();
295
296 // cerr << "sites.size() = " << sites.size() << "\n";
297 // cerr << "nSites = " << nSites << "\n";
298 // cerr << "vacancyTargets = " << vacancyTargets.size() << "\n";
299
300 std::vector<Component*> components = simParams->getComponents();
301 std::vector<RealType> molFractions;
302 std::vector<RealType> shellRadii;
303 std::vector<int> nMol;
304 std::map<int, int> componentFromSite;
305 nComponents = components.size();
306 // cerr << "nComponents = " << nComponents << "\n";
307
308 if (args_info.molFraction_given && args_info.shellRadius_given) {
309 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
310 "Specify either molFraction or shellRadius "
311 "arguments, but not both!");
312 painCave.isFatal = 1;
313 simError();
314 }
315
316 if (nComponents == 1) {
317 molFractions.push_back(1.0);
318 shellRadii.push_back(rodRadius);
319 } else if (args_info.molFraction_given) {
320 if ((int)args_info.molFraction_given == nComponents) {
321 for (int i = 0; i < nComponents; i++) {
322 molFractions.push_back(args_info.molFraction_arg[i]);
323 }
324 } else if ((int)args_info.molFraction_given == nComponents - 1) {
325 RealType remainingFraction = 1.0;
326 for (int i = 0; i < nComponents - 1; i++) {
327 molFractions.push_back(args_info.molFraction_arg[i]);
328 remainingFraction -= molFractions[i];
329 }
330 molFractions.push_back(remainingFraction);
331 } else {
332 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
333 "nanorodBuilder can't figure out molFractions "
334 "for all of the components in the <MetaData> block.");
335 painCave.isFatal = 1;
336 simError();
337 }
338 } else if ((int)args_info.shellRadius_given) {
339 if ((int)args_info.shellRadius_given == nComponents) {
340 for (int i = 0; i < nComponents; i++) {
341 shellRadii.push_back(args_info.shellRadius_arg[i]);
342 }
343 } else if ((int)args_info.shellRadius_given == nComponents - 1) {
344 for (int i = 0; i < nComponents - 1; i++) {
345 shellRadii.push_back(args_info.shellRadius_arg[i]);
346 }
347 shellRadii.push_back(rodRadius);
348 } else {
349 snprintf(
350 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
351 "nanorodBuilder can't figure out the\n"
352 "\tshell radii for all of the components in the <MetaData> block.");
353 painCave.isFatal = 1;
354 simError();
355 }
356 } else {
357 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
358 "You have a multi-component <MetaData> block,\n"
359 "\tbut have not specified either molFraction or shellRadius "
360 "arguments.");
361 painCave.isFatal = 1;
362 simError();
363 }
364
365 if (args_info.molFraction_given) {
366 RealType totalFraction = 0.0;
367
368 /* Do some simple sanity checking*/
369
370 for (int i = 0; i < nComponents; i++) {
371 if (molFractions.at(i) < 0.0) {
372 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
373 "One of the requested molFractions was"
374 " less than zero!");
375 painCave.isFatal = 1;
376 simError();
377 }
378 if (molFractions.at(i) > 1.0) {
379 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
380 "One of the requested molFractions was"
381 " greater than one!");
382 painCave.isFatal = 1;
383 simError();
384 }
385 totalFraction += molFractions.at(i);
386 }
387 if (abs(totalFraction - 1.0) > 1e-6) {
388 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
389 "The sum of molFractions was not close enough to 1.0");
390 painCave.isFatal = 1;
391 simError();
392 }
393
394 int remaining = nSites;
395 for (int i = 0; i < nComponents - 1; i++) {
396 nMol.push_back(int((RealType)nSites * molFractions.at(i)));
397 remaining -= nMol.at(i);
398 }
399 nMol.push_back(remaining);
400
401 // recompute actual mol fractions and perform final sanity check:
402
403 int totalMolecules = 0;
404 for (int i = 0; i < nComponents; i++) {
405 molFractions[i] = (RealType)(nMol.at(i)) / (RealType)nSites;
406 totalMolecules += nMol.at(i);
407 }
408 if (totalMolecules != nSites) {
409 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
410 "Computed total number of molecules is not equal "
411 "to the number of lattice sites!");
412 painCave.isFatal = 1;
413 simError();
414 }
415 } else {
416 for (unsigned int i = 0; i < shellRadii.size(); i++) {
417 if (shellRadii.at(i) > rodRadius + 1e-6) {
418 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
419 "One of the shellRadius values exceeds the rod Radius.");
420 painCave.isFatal = 1;
421 simError();
422 }
423 if (shellRadii.at(i) <= 0.0) {
424 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
425 "One of the shellRadius values is smaller than zero!");
426 painCave.isFatal = 1;
427 simError();
428 }
429 }
430 }
431
432 vector<int> ids;
433 if ((int)args_info.molFraction_given) {
434 // cerr << "molFraction given 2" << "\n";
435 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
436 "Creating a randomized spherically-capped nanorod.");
437 painCave.isFatal = 0;
438 painCave.severity = OPENMD_INFO;
439 simError();
440 /* Random rod is the default case*/
441
442 for (unsigned int i = 0; i < sites.size(); i++)
443 if (!isVacancy[i]) ids.push_back(i);
444
445 std::shuffle(ids.begin(), ids.end(), gen);
446
447 } else {
448 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
449 "Creating an fcc nanorod.");
450 painCave.isFatal = 0;
451 painCave.severity = OPENMD_INFO;
452 simError();
453
454 // RealType smallestSoFar;
455 int myComponent = -1;
456 nMol.clear();
457 nMol.resize(nComponents);
458
459 // cerr << "shellRadii[0] " << shellRadii[0] << "\n";
460 // cerr << "rodRadius " << rodRadius << "\n";
461
462 for (unsigned int i = 0; i < sites.size(); i++) {
463 myLoc = sites[i];
464 myR = myLoc.length();
465 // smallestSoFar = rodRadius;
466 // cerr << "vac = " << isVacancy[i]<< "\n";
467
468 if (!isVacancy[i]) {
469 // for (int j = 0; j < nComponents; j++) {
470 // if (myR <= shellRadii[j]) {
471 // if (shellRadii[j] <= smallestSoFar) {
472 // smallestSoFar = shellRadii[j];
473 // myComponent = j;
474 // }
475 // }
476 // }
477 myComponent = 0;
478 componentFromSite[i] = myComponent;
479 nMol[myComponent]++;
480 // cerr << "nMol for myComp(" << myComponent<<") = " <<
481 // nMol[myComponent] <<
482 //"\n";
483 }
484 }
485 }
486 // cerr << "nMol = " << nMol.at(0) << "\n";
487
488 outputFileName = args_info.output_arg;
489
490 // creat new .omd file on fly which corrects the number of molecule
491
492 createMdFile(inputFileName, outputFileName, nMol);
493
494 delete oldInfo;
495
496 SimCreator newCreator;
497 SimInfo* NewInfo = newCreator.createSim(outputFileName, false);
498
499 // Place molecules
500 Molecule* mol;
501 SimInfo::MoleculeIterator mi;
502 mol = NewInfo->beginMolecule(mi);
503
504 int l = 0;
505
506 for (int i = 0; i < nComponents; i++) {
507 locator =
508 new MoLocator(NewInfo->getMoleculeStamp(i), NewInfo->getForceField());
509
510 // cerr << "nMol = " << nMol.at(i) << "\n";
511 if (!args_info.molFraction_given) {
512 for (unsigned int n = 0; n < sites.size(); n++) {
513 if (!isVacancy[n]) {
514 if (componentFromSite[n] == i) {
515 mol = NewInfo->getMoleculeByGlobalIndex(l);
516 locator->placeMol(sites[n], orientations[n], mol);
517 l++;
518 }
519 }
520 }
521 } else {
522 for (int n = 0; n < nMol.at(i); n++) {
523 mol = NewInfo->getMoleculeByGlobalIndex(l);
524 locator->placeMol(sites[ids[l]], orientations[ids[l]], mol);
525 l++;
526 }
527 }
528 }
529
530 // fill Hmat
531 hmat(0, 0) = 10.0 * rodRadius;
532 hmat(0, 1) = 0.0;
533 hmat(0, 2) = 0.0;
534
535 hmat(1, 0) = 0.0;
536 hmat(1, 1) = 10.0 * rodRadius;
537 hmat(1, 2) = 0.0;
538
539 hmat(2, 0) = 0.0;
540 hmat(2, 1) = 0.0;
541 hmat(2, 2) = 5.0 * rodLength + 2.0 * rodRadius;
542
543 // set Hmat
544 NewInfo->getSnapshotManager()->getCurrentSnapshot()->setHmat(hmat);
545
546 // create dumpwriter and write out the coordinates
547 writer = new DumpWriter(NewInfo, outputFileName);
548
549 if (writer == NULL) {
550 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
551 "Error in creating dumpwriter object ");
552 painCave.isFatal = 1;
553 simError();
554 }
555
556 writer->writeDump();
557
558 // deleting the writer will put the closing at the end of the dump file
559
560 delete writer;
561
562 // cleanup a by calling sim error.....
563 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
564 "A new OpenMD file called \"%s\" has been "
565 "generated.\n",
566 outputFileName.c_str());
567 painCave.isFatal = 0;
568 painCave.severity = OPENMD_INFO;
569 simError();
570 return 0;
571}
572
573void createMdFile(const std::string& oldMdFileName,
574 const std::string& newMdFileName, std::vector<int> nMol) {
575 ifstream oldMdFile;
576 ofstream newMdFile;
577 const int MAXLEN = 65535;
578 char buffer[MAXLEN];
579
580 // create new .omd file based on old .omd file
581 oldMdFile.open(oldMdFileName.c_str());
582 newMdFile.open(newMdFileName.c_str());
583 oldMdFile.getline(buffer, MAXLEN);
584
585 unsigned int i = 0;
586 while (!oldMdFile.eof()) {
587 // correct molecule number
588 if (strstr(buffer, "nMol") != NULL) {
589 if (i < nMol.size()) {
590 snprintf(buffer, MAXLEN, "\tnMol = %i;", nMol.at(i));
591 newMdFile << buffer << std::endl;
592 i++;
593 }
594 } else
595 newMdFile << buffer << std::endl;
596
597 oldMdFile.getline(buffer, MAXLEN);
598 }
599
600 oldMdFile.close();
601 newMdFile.close();
602
603 if (i != nMol.size()) {
604 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
605 "Couldn't replace the correct number of nMol\n"
606 "\tstatements in component blocks. Make sure that all\n"
607 "\tcomponents in the template file have nMol=1");
608 painCave.isFatal = 1;
609 simError();
610 }
611}
The only responsibility of SimCreator is to parse the meta-data file and create a SimInfo instance ba...
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:93
Implements a spherically-capped rod-shaped lattice.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
void registerLattice()
Register all lattice.
Definition Register.cpp:131
The header file for the command line option parser generated by GNU Gengetopt version 2....
Where the command line options are stored.