OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
randomBuilder.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 <cmath>
46#include <cstdio>
47#include <cstdlib>
48#include <cstring>
49#include <fstream>
50#include <iostream>
51#include <map>
52#include <random>
53#include <string>
54
55#include "brains/Register.hpp"
56#include "brains/SimCreator.hpp"
57#include "brains/SimInfo.hpp"
58#include "io/DumpWriter.hpp"
59#include "lattice/Lattice.hpp"
62#include "math/Vector3.hpp"
63#include "randomBuilderCmd.hpp"
64#include "utils/MoLocator.hpp"
65#include "utils/StringUtils.hpp"
66
67using namespace std;
68using namespace OpenMD;
69
70void createMdFile(const std::string& oldMdFileName,
71 const std::string& newMdFileName, std::vector<int> nMol);
72
73int main(int argc, char* argv[]) {
75
76 gengetopt_args_info args_info;
77 std::string latticeType;
78 std::string inputFileName;
79 std::string outputFileName;
80 Lattice* simpleLat;
81 RealType latticeConstant;
82 std::vector<RealType> lc;
83 const RealType rhoConvertConst = 1.661;
84 RealType density;
85 int nx, ny, nz;
86 Mat3x3d hmat;
87 MoLocator* locator;
88 std::vector<Vector3d> latticePos;
89 std::vector<Vector3d> latticeOrt;
90 int nMolPerCell;
91 DumpWriter* writer;
92
93 // parse command line arguments
94 if (cmdline_parser(argc, argv, &args_info) != 0) exit(1);
95
96 density = args_info.density_arg;
97
98 // get lattice type
99 latticeType = "FCC";
100 if (args_info.lattice_given) { latticeType = args_info.lattice_arg; }
101
102 simpleLat = LatticeFactory::getInstance().createLattice(latticeType);
103
104 if (simpleLat == NULL) {
105 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
106 "Lattice Factory can not create %s lattice\n",
107 latticeType.c_str());
108 painCave.isFatal = 1;
109 simError();
110 }
111 nMolPerCell = simpleLat->getNumSitesPerCell();
112
113 // get the number of unit cells in each direction:
114
115 nx = args_info.nx_arg;
116
117 if (nx <= 0) {
118 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
119 "The number of unit cells in the x direction "
120 "must be greater than 0.");
121 painCave.isFatal = 1;
122 simError();
123 }
124
125 ny = args_info.ny_arg;
126
127 if (ny <= 0) {
128 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
129 "The number of unit cells in the y direction "
130 "must be greater than 0.");
131 painCave.isFatal = 1;
132 simError();
133 }
134
135 nz = args_info.nz_arg;
136
137 if (nz <= 0) {
138 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
139 "The number of unit cells in the z direction "
140 "must be greater than 0.");
141 painCave.isFatal = 1;
142 simError();
143 }
144
145 int nSites = nMolPerCell * nx * ny * nz;
146
147 // get input file name
148 if (args_info.inputs_num)
149 inputFileName = args_info.inputs[0];
150 else {
151 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
152 "No input .omd file name was specified "
153 "on the command line");
154 painCave.isFatal = 1;
155 simError();
156 }
157
158 // parse md file and set up the system
159
160 SimCreator oldCreator;
161 SimInfo* oldInfo = oldCreator.createSim(inputFileName, false);
162 Globals* simParams = oldInfo->getSimParams();
163
164 // Calculate lattice constant (in Angstroms)
165
166 std::vector<Component*> components = simParams->getComponents();
167 std::vector<RealType> molFractions;
168 std::vector<RealType> molecularMasses;
169 std::vector<int> nMol;
170 std::size_t nComponents = components.size();
171
172 if (nComponents == 1) {
173 molFractions.push_back(1.0);
174 } else {
175 if (args_info.molFraction_given == nComponents) {
176 for (std::size_t i = 0; i < nComponents; i++) {
177 molFractions.push_back(args_info.molFraction_arg[i]);
178 }
179 } else if (args_info.molFraction_given == nComponents - 1) {
180 RealType remainingFraction = 1.0;
181 for (std::size_t i = 0; i < nComponents - 1; i++) {
182 molFractions.push_back(args_info.molFraction_arg[i]);
183 remainingFraction -= molFractions[i];
184 }
185 molFractions.push_back(remainingFraction);
186 } else {
187 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
188 "randomBuilder can't figure out molFractions "
189 "for all of the components in the <MetaData> block.");
190 painCave.isFatal = 1;
191 simError();
192 }
193 }
194
195 // do some sanity checking:
196
197 RealType totalFraction = 0.0;
198
199 for (std::size_t i = 0; i < nComponents; i++) {
200 if (molFractions.at(i) < 0.0) {
201 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
202 "One of the requested molFractions was"
203 " less than zero!");
204 painCave.isFatal = 1;
205 simError();
206 }
207 if (molFractions.at(i) > 1.0) {
208 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
209 "One of the requested molFractions was"
210 " greater than one!");
211 painCave.isFatal = 1;
212 simError();
213 }
214 totalFraction += molFractions.at(i);
215 }
216 if (abs(totalFraction - 1.0) > 1e-6) {
217 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
218 "The sum of molFractions was not close enough to 1.0");
219 painCave.isFatal = 1;
220 simError();
221 }
222
223 int remaining = nSites;
224 for (std::size_t i = 0; i < nComponents - 1; i++) {
225 nMol.push_back(int((RealType)nSites * molFractions.at(i)));
226 remaining -= nMol.at(i);
227 }
228 nMol.push_back(remaining);
229
230 // recompute actual mol fractions and perform final sanity check:
231
232 int totalMolecules = 0;
233 RealType totalMass = 0.0;
234 for (std::size_t i = 0; i < nComponents; i++) {
235 molFractions[i] = (RealType)(nMol.at(i)) / (RealType)nSites;
236 totalMolecules += nMol.at(i);
237 molecularMasses.push_back(MoLocator::getMolMass(
238 oldInfo->getMoleculeStamp(i), oldInfo->getForceField()));
239 totalMass += (RealType)(nMol.at(i)) * molecularMasses.at(i);
240 }
241 RealType avgMass = totalMass / (RealType)totalMolecules;
242
243 if (totalMolecules != nSites) {
244 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
245 "Computed total number of molecules is not equal "
246 "to the number of lattice sites!");
247 painCave.isFatal = 1;
248 simError();
249 }
250
251 latticeConstant = pow(rhoConvertConst * nMolPerCell * avgMass / density,
252 (RealType)(1.0 / 3.0));
253
254 // Set the lattice constant
255
256 lc.push_back(latticeConstant);
257 simpleLat->setLatticeConstant(lc);
258
259 // Calculate the lattice sites and fill the lattice vector.
260
261 // Get the standard orientations of the cell sites
262
263 latticeOrt = simpleLat->getLatticePointsOrt();
264
265 vector<Vector3d> sites;
266 vector<Vector3d> orientations;
267
268 for (int i = 0; i < nx; i++) {
269 for (int j = 0; j < ny; j++) {
270 for (int k = 0; k < nz; k++) {
271 // Get the position of the cell sites
272
273 simpleLat->getLatticePointsPos(latticePos, i, j, k);
274
275 for (int l = 0; l < nMolPerCell; l++) {
276 sites.push_back(latticePos[l]);
277 orientations.push_back(latticeOrt[l]);
278 }
279 }
280 }
281 }
282
283 outputFileName = args_info.output_arg;
284
285 // create a new .omd file on the fly which corrects the number of molecules
286
287 createMdFile(inputFileName, outputFileName, nMol);
288
289 delete oldInfo;
290
291 // We need to read in the new SimInfo object, then Parse the
292 // md file and set up the system
293
294 SimCreator newCreator;
295 SimInfo* newInfo = newCreator.createSim(outputFileName, false);
296
297 // fill Hmat
298
299 hmat(0, 0) = nx * latticeConstant;
300 hmat(0, 1) = 0.0;
301 hmat(0, 2) = 0.0;
302
303 hmat(1, 0) = 0.0;
304 hmat(1, 1) = ny * latticeConstant;
305 hmat(1, 2) = 0.0;
306
307 hmat(2, 0) = 0.0;
308 hmat(2, 1) = 0.0;
309 hmat(2, 2) = nz * latticeConstant;
310
311 // Set Hmat
312
313 newInfo->getSnapshotManager()->getCurrentSnapshot()->setHmat(hmat);
314
315 // place the molecules
316
317 // Randomize a vector of ints:
318
319 vector<int> ids;
320 for (std::size_t i = 0; i < sites.size(); i++)
321 ids.push_back(i);
322
323 /* Set up the random number generator engine */
324 std::random_device rd; // Non-deterministic, uniformly-distributed integer
325 // random number generator
326 std::mt19937 gen(rd()); // 32-bit Mersenne Twister random number engine
327
328 std::shuffle(ids.begin(), ids.end(), gen);
329
330 Molecule* mol;
331 int l = 0;
332 for (std::size_t i = 0; i < nComponents; i++) {
333 locator =
334 new MoLocator(newInfo->getMoleculeStamp(i), newInfo->getForceField());
335 for (int n = 0; n < nMol.at(i); n++) {
336 mol = newInfo->getMoleculeByGlobalIndex(l);
337 locator->placeMol(sites[ids[l]], orientations[ids[l]], mol);
338 l++;
339 }
340 }
341
342 // Create DumpWriter and write out the coordinates
343
344 writer = new DumpWriter(newInfo, outputFileName);
345
346 if (writer == NULL) {
347 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
348 "error in creating DumpWriter");
349 painCave.isFatal = 1;
350 simError();
351 }
352
353 writer->writeDump();
354
355 // deleting the writer will put the closing at the end of the dump file.
356
357 delete writer;
358
359 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
360 "A new OpenMD file called \"%s\" has been "
361 "generated.\n",
362 outputFileName.c_str());
363 painCave.isFatal = 0;
364 painCave.severity = OPENMD_INFO;
365 simError();
366 return 0;
367}
368
369void createMdFile(const std::string& oldMdFileName,
370 const std::string& newMdFileName, std::vector<int> nMol) {
371 ifstream oldMdFile;
372 ofstream newMdFile;
373 const int MAXLEN = 65535;
374 char buffer[MAXLEN];
375
376 // create new .omd file based on old .omd file
377
378 oldMdFile.open(oldMdFileName.c_str());
379 newMdFile.open(newMdFileName.c_str());
380
381 oldMdFile.getline(buffer, MAXLEN);
382
383 std::size_t i = 0;
384 while (!oldMdFile.eof()) {
385 // correct molecule number
386 if (strstr(buffer, "nMol") != NULL) {
387 if (i < nMol.size()) {
388 snprintf(buffer, MAXLEN, "\tnMol = %i;", nMol.at(i));
389 newMdFile << buffer << std::endl;
390 i++;
391 }
392 } else
393 newMdFile << buffer << std::endl;
394
395 oldMdFile.getline(buffer, MAXLEN);
396 }
397
398 oldMdFile.close();
399 newMdFile.close();
400
401 if (i != nMol.size()) {
402 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
403 "Couldn't replace the correct number of nMol\n"
404 "\tstatements in component blocks. Make sure that all\n"
405 "\tcomponents in the template file have nMol=1");
406 painCave.isFatal = 1;
407 simError();
408 }
409}
static LatticeFactory & getInstance()
Returns an instance of Lattice factory.
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
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.