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