oILAB
Loading...
Searching...
No Matches
Lammps.h
Go to the documentation of this file.
1//
2// Created by Nikhil Chandra Admal on 11/19/24.
3//
4
5#ifndef OILAB_LAMMPS_H
6#define OILAB_LAMMPS_H
7
8#include <iostream>
9#include <fstream>
10#include <vector>
11#include <string>
12#include <cstdlib>
13#include <cmath>
14#include <sstream>
15#ifdef _WIN32
16 #include <io.h>
17 #include <windows.h>
18#else
19 #include <unistd.h>
20 #include <sys/stat.h>
21#endif
22#include <Eigen/Eigen>
23#include <iomanip>
24
25std::tuple<Eigen::MatrixXd,
26 Eigen::Matrix3d,
27 Eigen::Vector3d> read_oILAB_output(const std::string& path)
28{
29 Eigen::MatrixXd atoms;
30 Eigen::Matrix3d box;
31 box.setZero();
32 Eigen::Vector<double,9> boxVectorized;
33 boxVectorized.setZero();
34 Eigen::Vector3d origin;
35 origin.setZero();
36
37 std::ifstream file(path);
38 if (!file.is_open()) {
39 std::cerr << "Error opening file for reading oilab config file: " << path << std::endl;
40 }
41
42 std::string line;
43 int number_atoms = 0;
44
45 int lineCount= 0;
46 int atomCount= 0;
47 int boxCount= -1;
48 int originCount= -1;
49
50 while (std::getline(file, line)) {
51 lineCount++;
52 std::stringstream ss(line);
53 std::string field;
54 std::vector<std::string> fields;
55
56 while (ss >> field) {
57 fields.push_back(field);
58 }
59
60 if (lineCount == 1) {
61 number_atoms = std::stoi(fields[0]);
62 atoms.resize(number_atoms,5);
63 atoms.setZero();
64 }
65 else if (lineCount == 2)
66 {
67 for (size_t i = 0; i < fields.size(); ++i) {
68 if (fields[i].find("Lattice=") != std::string::npos) {
69 boxCount++;
70 continue;
71 }
72 if (boxCount>=0 && boxCount<9) {
73 boxVectorized(boxCount) = std::stod(fields[i]);
74 boxCount++;
75 continue;
76 }
77 if (fields[i].find("origin=") != std::string::npos)
78 {
79 originCount++;
80 continue;
81 }
82 if (originCount>-1 && originCount<3) {
83 origin(originCount) = std::stod(fields[i]);
84 originCount++;
85 continue;
86 }
87 }
88 }
89 else if (lineCount > 2) {
90 // Reading atom data (type, x, y, z, radius)
91 Eigen::VectorXd atom_data(5);
92 int coordCount= 0;
93 for (const auto &field : fields) {
94 atom_data(coordCount)= std::stod(field);
95 coordCount++;
96 }
97 atoms.row(atomCount)= atom_data;
98 atomCount++;
99 }
100 }
101 box= boxVectorized.reshaped(3,3);
102
103 return {atoms, box, origin};
104
105}
106
107/*-----------------------*/
108//std::string write_lammps_datafile(const std::string &filename, const std::vector<std::vector<double>> &box, const std::vector<std::vector<double>> &atom_data, int atom_types) {
109void write_lammps_datafile(const std::string &filename,
110 const std::vector<std::vector<double>> &box,
111 const Eigen::MatrixXd& atom_data,
112 int atom_types)
113{
114 std::ofstream file(filename);
115 if (!file.is_open())
116 std::cerr << "Error opening file for writing lammps configuration file: " << filename << std::endl;
117
118 file << "# LAMMPS data file via write_data\n";
119 file << "\n";
120 file << atom_data.rows() << " atoms\n";
121 file << atom_types << " atom types\n";
122 file << "\n";
123 file << std::setprecision(8) << box[0][0] << " " << std::setprecision(8) << box[0][1] << " xlo xhi\n";
124 file << std::setprecision(8) << box[1][0] << " " << std::setprecision(8) << box[1][1] << " ylo yhi\n";
125 file << std::setprecision(8) << box[2][0] << " " << std::setprecision(8) << box[2][1] << " zlo zhi\n";
126 file << "0 0 0 xy xz yz\n";
127 file << "\n";
128 file << "Atoms # atomic\n";
129 file << "\n";
130 for (size_t i = 0; i < atom_data.rows(); ++i) {
131 //file << atom_data(i,0) << " " << atom_data(i,1) << " " << atom_data(i,2) << " " << atom_data(i,3) << " " << atom_data(i,4) << " 0 0 0\n";
132 file << std::setprecision(8) << atom_data.row(i) << " 0 0 0\n";
133 }
134}
135
136/*-----------------------*/
137void write_lammps_input_script(const std::string &filename,
138 const std::string &infile,
139 const std::string &outfile,
140 double gb_thickness_parameter,
141 const std::string &potential_file_path,
142 const std::string &output_dump_file) {
143 std::ofstream file(filename);
144 if (!file.is_open()) {
145 std::cerr << "Error opening file for writing lammps input script: " << filename << std::endl;
146 return;
147 }
148
149 file << "# Find energy of a config and write in " << outfile << " file\n";
150 file << "\n";
151 file << "variable potential_path string " << potential_file_path << "\n";
152 file << "clear\n";
153 file << "units metal\n";
154 file << "boundary p p p\n";
155 file << "atom_style atomic\n";
156 file << "neighbor 1.0 bin\n";
157 file << "neigh_modify every 1 delay 2 check yes\n";
158 file << "read_data " << infile << "\n";
159 file << "pair_style eam/alloy\n";
160 file << "pair_coeff * * ${potential_path} Cu Cu\n";
161 file << "delete_atoms overlap 1e-2 all all\n";
162 file << "variable area equal ly*lz\n";
163 file << "variable xlogb equal xlo+" << std::setprecision(8) << gb_thickness_parameter << "\n";
164 file << "variable xhigb equal xhi-" << std::setprecision(8) << gb_thickness_parameter << "\n";
165 file << "variable xlobulk equal xlo+" << std::setprecision(8) << gb_thickness_parameter << "\n";
166 file << "variable xhibulk equal xlo+" << std::setprecision(8) << 1.5*gb_thickness_parameter << "\n";
167 file << "region GB block ${xlogb} ${xhigb} INF INF INF INF side in units box\n";
168 file << "region BULK block ${xlobulk} ${xhibulk} INF INF INF INF side in units box\n";
169 file << "group GB region GB\n";
170 file << "group BULK region BULK\n";
171 file << "compute peratom GB pe/atom\n";
172 file << "compute peratombulk BULK pe/atom\n";
173 file << "compute pe GB reduce sum c_peratom\n";
174 file << "compute pebulk GB reduce sum c_peratombulk\n";
175 file << "variable peGB equal c_pe\n";
176 file << "variable peBULK equal c_pebulk\n";
177 file << "variable atomsGB equal count(GB)\n";
178 file << "variable atomsBULK equal count(BULK)\n";
179 file << "thermo 1000\n";
180 file << "compute 1 all ke/atom\n";
181 file << "compute cna all cna/atom 3.08133\n";
182 file << "compute csys all centro/atom fcc\n";
183 file << "compute 3 all pe/atom\n";
184 file << "compute 4 all stress/atom NULL pair\n";
185 file << "timestep 0.001\n";
186 file << "thermo_style custom step temp ke pe etotal press pxx pyy pzz pxy pxz pyz ly lx lz xy xz yz c_pe v_atomsGB v_peBULK v_atomsBULK\n";
187 file << "dump OUT0 all custom 10 " << output_dump_file << " id type x y z fx fy fz c_3 c_1 vx vy vz c_4[1] c_4[2] c_4[3] c_4[4] c_4[5] c_4[6]\n";
188 file << "run 0\n";
189 file << "variable coh equal (${peBULK}/${atomsBULK})\n";
190 file << "variable GBene equal (${peGB}-${coh}*${atomsGB})\n";
191 file << "print \"coh = ${coh} energy = ${peGB} numAtoms = ${atomsGB} GBene = ${GBene} area = ${area}\" file " << outfile << "\n";
192 file << "\n";
193}
194
195/*-----------------------*/
196std::vector<std::vector<double>> read_python_outfile(const std::string &path) {
197 std::vector<std::vector<double>> data;
198 std::ifstream file(path);
199 if (!file.is_open()) {
200 std::cerr << "Error opening file for reading lammps output: " << path << std::endl;
201 return data;
202 }
203
204 std::string line;
205 while (std::getline(file, line)) {
206 std::stringstream ss(line);
207 std::string field;
208 double state_id, area, total_energy, gb_energy, gb_density;
209
210 while (ss >> field)
211 {
212 if (field == "coh") {
213 ss >> field;
214 ss >> state_id;
215 }
216 else if (field == "energy") {
217 ss >> field;
218 ss >> total_energy;
219 }
220 else if (field == "GBene") {
221 ss >> field;
222 ss >> gb_energy;
223 }
224 else if (field == "numAtoms") {
225 ss >> field;
226 ss >> gb_density;
227 }
228 else if (field == "area")
229 {
230 ss >> field;
231 ss >> area;
232 break;
233 }
234 }
235
236 //gb_density = gb_density / area;
237 data.push_back({state_id, area, gb_energy, gb_density});
238 }
239
240 return data;
241}
242
243
244std::pair<double, double> energy(const std::string& lammpsLocation,
245 const std::string& oilabConfigFile,
246 const std::string& potentialFile)
247{
248 // Write data
249 std::string threadNumber= std::to_string(omp_get_thread_num());
250 std::string lammpsInputFile= "in"+ threadNumber +".find_energy";
251 std::string lammpsDataFile= "data" + threadNumber + ".lammps_input";
252 std::string lammpsDumpFile= "dump" + threadNumber + ".lammpsConfigs";
253 std::string outfile = "lmp_mesostate_energies" + threadNumber + ".txt";
254
255 // Read data
256 auto [atoms, box, origin] = read_oILAB_output(oilabConfigFile);
257
258 // Find rotation and new box
259 Eigen::Matrix3d R= box.transpose();
260 for(int i=0; i<3; ++i)
261 R.row(i).normalize();
262 Eigen::Matrix3d new_box= R*box;
263
264 // New atoms
265 Eigen::MatrixXd new_atoms(atoms.rows(),5);
266 for (size_t i = 0; i < atoms.rows(); ++i) {
267 new_atoms(i,Eigen::seq(2,4))= R*(atoms(i,Eigen::seq(1,3)).transpose());
268 /*
269 new_atoms[i][2] = new_atoms[i][2] + R[0][0]*atoms[i][1] + R[0][1]*atoms[i][2] + R[0][2]*atoms[i][3];
270 new_atoms[i][3] = new_atoms[i][3] + R[1][0]*atoms[i][1] + R[1][1]*atoms[i][2] + R[1][2]*atoms[i][3];
271 new_atoms[i][4] = new_atoms[i][4] + R[2][0]*atoms[i][1] + R[2][1]*atoms[i][2] + R[2][2]*atoms[i][3];
272 */
273 new_atoms(i,0)= i + 1;
274 new_atoms(i,1) = atoms(i,0);
275 }
276
277 // Determine nbox values
278 std::vector<std::vector<double>> nbox(3, std::vector<double>(2, 0.0));
279 for (size_t i = 0; i < 3; ++i) {
280 if (i == 0) {
281 nbox[i][0] = -new_box(i,i) / 2;
282 nbox[i][1] = new_box(i,i) / 2;
283 } else if (i == 1) {
284 //nbox[i][0] = origin(i);
285 nbox[i][0] = 0.0;
286 nbox[i][1] = new_box(i,i);
287 } else {
288 nbox[i][0] = 0.0;
289 nbox[i][1] = new_box(i,i);
290 }
291 }
292
293 //double gb_thickness_parameter = 0.75 * (new_box(0,0) * 0.5);
294 double gb_thickness_parameter= 6;
295
296 // Write files
297 write_lammps_datafile(lammpsDataFile, nbox, new_atoms, 2);
298 write_lammps_input_script(lammpsInputFile, lammpsDataFile, outfile, gb_thickness_parameter, potentialFile, lammpsDumpFile);
299
300 // Run the LAMMPS script
301 std::string command = lammpsLocation +" -in " + lammpsInputFile + " > /dev/null 2>&1";
302 std::system(command.c_str());
303
304 // Read energy
305 auto data_energy = read_python_outfile(outfile);
306
307 return {data_energy[0][3], data_energy[0][2]};
308}
309
310#endif //OILAB_LAMMPS_H
std::vector< std::vector< double > > read_python_outfile(const std::string &path)
Definition Lammps.h:196
std::tuple< Eigen::MatrixXd, Eigen::Matrix3d, Eigen::Vector3d > read_oILAB_output(const std::string &path)
Definition Lammps.h:27
std::pair< double, double > energy(const std::string &lammpsLocation, const std::string &oilabConfigFile, const std::string &potentialFile)
Definition Lammps.h:244
void write_lammps_input_script(const std::string &filename, const std::string &infile, const std::string &outfile, double gb_thickness_parameter, const std::string &potential_file_path, const std::string &output_dump_file)
Definition Lammps.h:137
void write_lammps_datafile(const std::string &filename, const std::vector< std::vector< double > > &box, const Eigen::MatrixXd &atom_data, int atom_types)
Definition Lammps.h:109