MDStressLab++
Loading...
Searching...
No Matches
BoxConfiguration.cpp
Go to the documentation of this file.
1/*
2 * BoxConfiguration.cpp
3 *
4 * Created on: Nov 4, 2019
5 * Author: Nikhil
6 */
7
8#include <fstream>
9#include "BoxConfiguration.h"
10#include "Configuration.h"
11#include "typedef.h"
12#include "neighbor_list.h"
13#include "helper.hpp"
14
15
16BoxConfiguration::BoxConfiguration(int numberOfParticles, int referenceAndFinal):
17 Configuration(numberOfParticles,referenceAndFinal)
18{
19 MY_HEADING("Initializing a box configuration");
20 if (referenceAndFinal)
21 std::cout << "Creating a configuration of " << numberOfParticles << " particles" <<
22 " along with reference coordinates in a box of size zero" << std::endl;
23 else
24 std::cout << "Creating a configuration of " << numberOfParticles << " particles" <<
25 " in a box of size zero" << std::endl;
26 // Default to zero box sizes and no pbc
27 box.setZero();
28 reference_box.setZero();
29 pbc.setZero();
30}
31
32
33void BoxConfiguration::read(std::string configFileName, int referenceAndFinal)
34{
35 // Read in the atomistic system
36 std::cout << "Reading the box configuration from file " << configFileName << std::endl;
37 std::ifstream file(configFileName);
38 if(!file)
39 {
40 // Print an error and exit
41 std::cerr << "ERROR: " << configFileName << " could not be opened for reading!" << std::endl;
42 exit(1);
43 }
44
45 int numberOfParticlesInFile;
46 file >> numberOfParticlesInFile;
47 if (numberOfParticles != numberOfParticlesInFile)
48 MY_ERROR("Error: Number of particles in file does not equal to that of BoxConfiguration");
49
50 for(int i=0;i<DIM*DIM;++i)
51 if(!(file >> reference_box(i))) MY_ERROR("ERROR: Reference box size.");
52 for(int i=0;i<DIM*DIM;++i)
53 if(!(file >> box(i))) MY_ERROR("ERROR: Box size.");
54 for(int i=0;i<DIM;++i)
55 if(!(file >> pbc(i))) MY_ERROR("ERROR: PBC.");
56
57
58 std::string speciesTemp;
59 for(int i=0;i<numberOfParticles;++i)
60 {
61 if(!(file >> speciesTemp)) MY_ERROR("ERROR: Species code of particle " + std::to_string(i));
62 species.push_back(speciesTemp);
63 for(int j=0;j<DIM;++j)
64 if(!(file >> coordinates[Current](i,j))) MY_ERROR("ERROR: Coordinate of particle " + std::to_string(i));
65 for(int j=0;j<DIM;++j)
66 if(!(file >> velocities(i,j))) MY_ERROR("ERROR: Velocity of particle " + std::to_string(i));
67 if (referenceAndFinal == true)
68 {
69 for(int j=0;j<DIM;++j)
70 if(!(file >> coordinates[Reference](i,j)))
71 MY_ERROR("ERROR: Reference coordinate of particle " + std::to_string(i) + "\n");
72 }
73 else
74 {
75 file.ignore(32767, '\n');
76 }
77 }
78 std::cout << std::endl;
79 std::cout << "Box size = " << std::endl;
80 std::cout << box << std::endl;
81 std::cout << std::endl;
82 std::cout << "Reference box size = " << std::endl;
83 std::cout << reference_box << std::endl;
84 std::cout << std::endl;
85 std::cout << "Periodic boundary conditions = " << pbc << std::endl;
86}
87
88void BoxConfiguration::readLMP(const std::string& configFileName,
89 const ConfigType& configType){
90 // Read in the atomistic system
91 if (configType==Current)
92 std::cout << "Reading the current box configuration from lammps data file " << configFileName << std::endl;
93 else if (configType==Reference)
94 std::cout << "Reading the reference box configuration from lammps data file " << configFileName << std::endl;
95 std::ifstream file(configFileName);
96 if(!file)
97 {
98 std::cerr << "ERROR: " << configFileName << " could not be opened for reading!" << std::endl;
99 exit(1);
100 }
101
102 // Lambda version of hasEnding
103 auto hasEnding = [](const std::string& fullString, const std::string& ending) -> bool {
104 return fullString.size() >= ending.size() &&
105 fullString.compare(fullString.size() - ending.size(), ending.size(), ending) == 0;
106 };
107
108 if (hasEnding(configFileName, ".lmp")) {
109 lmpParser(file,configType);
110 } else {
111 std::cerr << "ERROR: Expecting file with extension .lmp!" << std::endl;
112 exit(1);
113 }
114}
115
116void BoxConfiguration::readLMP(const std::string& currentConfigFileName,
117 const std::string& referenceConfigFileName){
118 readLMP(currentConfigFileName,Current);
119 if(coordinates[Reference].rows()>0)
120 readLMP(referenceConfigFileName,Reference);
121 else
122 MY_ERROR("Error: Memory not assigned to store reference configuration.");
123}
124
125void BoxConfiguration::lmpParser(std::ifstream& file, const ConfigType& configType)
126{
127 std::string line;
128 int numAtoms = 0;
129 int numberOfAtomTypes = 0;
130 std::unordered_map<int, std::string> typeToSpecies;
131
132 while (std::getline(file, line)) {
133 // Normalize to lowercase for keyword checks (optional but helpful)
134 std::string loweredLine = line;
135 std::transform(loweredLine.begin(), loweredLine.end(), loweredLine.begin(), ::tolower);
136
137 // Parse total number of atoms
138 if (loweredLine.find("atoms") != std::string::npos && (std::stringstream(line) >> numAtoms) ) {
139 //std::istringstream ss(line);
140 //ss >> numAtoms;
141 if (numberOfParticles != numAtoms)
142 MY_ERROR("Error: Number of particles in file does not equal to that of BoxConfiguration");
143 }
144 // Parse number of atom types
145 else if (loweredLine.find("atom types") != std::string::npos) {
146 std::istringstream ss(line);
147 ss >> numberOfAtomTypes;
148 }
149 // Parse box dimensions
150 else if (loweredLine.find("xlo xhi") != std::string::npos) {
151 std::istringstream ss(line);
152 double xlo, xhi;
153 ss >> xlo >> xhi;
154 if (configType==Current)
155 box(0, 0) = xhi - xlo;
156 else
157 reference_box(0, 0) = xhi - xlo;
158 } else if (loweredLine.find("ylo yhi") != std::string::npos) {
159 std::istringstream ss(line);
160 double ylo, yhi;
161 ss >> ylo >> yhi;
162 if (configType==Current)
163 box(1, 1) = yhi - ylo;
164 else
165 reference_box(1, 1) = yhi - ylo;
166 } else if (loweredLine.find("zlo zhi") != std::string::npos) {
167 std::istringstream ss(line);
168 double zlo, zhi;
169 ss >> zlo >> zhi;
170 if (configType==Current)
171 box(2, 2) = zhi - zlo;
172 else
173 reference_box(2, 2) = zhi - zlo;
174 }
175
176 // Process Masses section
177 else if (loweredLine.find("masses") != std::string::npos) {
178 int massLinesRead = 0;
179
180 // Read lines until we've read all the atom types
181 while (std::getline(file, line)) {
182 // Skip blank or whitespace-only lines
183 if (line.empty() || line.find_first_not_of(" \t\r\n") == std::string::npos)
184 continue;
185
186 // Skip comment lines
187 if (line[0] == '#')
188 continue;
189
190 // Read: <type> <mass> # optional comment with species name
191 std::istringstream ss(line);
192 int type;
193 double mass;
194 std::string comment;
195
196 ss >> type >> mass;
197 std::getline(ss, comment); // grab remainder of line (comment)
198
199 std::string speciesName = "Unknown";
200
201 // Extract species name from comment if present
202 size_t hashPos = comment.find('#');
203 if (hashPos != std::string::npos) {
204 speciesName = comment.substr(hashPos + 1);
205 // Trim whitespace
206 speciesName.erase(0, speciesName.find_first_not_of(" \t"));
207 speciesName.erase(speciesName.find_last_not_of(" \t\r\n") + 1);
208 }
209
210 typeToSpecies[type] = speciesName;
211
212 if (++massLinesRead >= numberOfAtomTypes)
213 break; // We've read all the expected mass lines
214 }
215 }
216
217 // Process Atoms section
218 else if (loweredLine.find("atoms") != std::string::npos) {
219 // Skip lines until we reach actual atom data
220 while (std::getline(file, line)) {
221 if (line.empty() || line.find_first_not_of(" \t\r\n") == std::string::npos)
222 continue;
223 if (line[0] == '#')
224 continue;
225 break; // first data line found
226 }
227
228 if(configType==Current) species.resize(numberOfParticles);
229 // Read atom lines
230 for (int i = 0; i < numberOfParticles; ++i) {
231 std::istringstream ss(line); // first valid line
232 int id, type;
233 double x, y, z;
234 if (!(ss >> id >> type >> x >> y >> z))
235 MY_ERROR("ERROR: Coordinate of particle " + std::to_string(i));
236
237 int idxFlagx= 0; int idxFlagy= 0; int idxFlagz= 0;
238 int tmpx, tmpy, tmpz;
239 if (ss >> tmpx >> tmpy >> tmpz) {
240 idxFlagx = tmpx;
241 idxFlagy = tmpy;
242 idxFlagz = tmpz;
243 }
244
245 //if(configType==Current) species.push_back(typeToSpecies[type]);
246 if(configType==Current) species[id-1]= typeToSpecies[type];
247 if(configType==Reference) assert(species[id-1] == typeToSpecies[type] &&
248 "Species in the reference configuration do not match with those in the "
249 "current configuration");
250 if (configType==Reference) {
251 coordinates[configType](id - 1, 0) = x + idxFlagx * reference_box(0, 0);
252 coordinates[configType](id - 1, 1) = y + idxFlagy * reference_box(1, 1);;
253 coordinates[configType](id - 1, 2) = z + idxFlagz * reference_box(2, 2);;
254 }
255 else{
256 coordinates[configType](id - 1, 0) = x + idxFlagx * box(0, 0);
257 coordinates[configType](id - 1, 1) = y + idxFlagy * box(1, 1);;
258 coordinates[configType](id - 1, 2) = z + idxFlagz * box(2, 2);;
259 }
260
261 if (i < numberOfParticles - 1) {
262 std::getline(file, line); // read next line
263 }
264 }
265
266 break; // done reading atom data
267 }
268 }
269
270 // Assume no periodicity for now
271 pbc = Eigen::Vector3i::Zero();
272}
273
274
276{
277 // Build padding atoms
278 int numberOfPaddings{0};
279 std::vector<double> reference_coordinatesOfPaddings,coordinatesOfPaddings;
280 std::vector<std::string> speciesOfPaddings;
281 std::vector<int> masterOfPaddings;
282 int referenceAndFinal= (coordinates.at(Reference).rows()>0);
283
285 padding,
286 reference_box.data(),
287 box.data(),
288 pbc.data(),
289 coordinates.at(Reference).data(),
290 coordinates.at(Current).data(),
291 species,
292 numberOfPaddings,
293 reference_coordinatesOfPaddings,
294 coordinatesOfPaddings,
295 speciesOfPaddings,
296 masterOfPaddings,
297 referenceAndFinal);
298
299 int total= numberOfParticles + numberOfPaddings;
300
301 Configuration* config_ptr(new Configuration{total,referenceAndFinal});
302
303 // copy the coordinates, particleContributing and species
304 // of contributing atoms from BoxConfiguration to Configuration
305 if (referenceAndFinal) (config_ptr->coordinates.at(Reference)).topRows(numberOfParticles)= coordinates.at(Reference);
306 (config_ptr->coordinates.at(Current)).topRows(numberOfParticles)= coordinates.at(Current);
307 for (auto it= species.begin();it!= species.end();it++)
308 config_ptr->species.push_back(*it);
309
310 if (numberOfPaddings)
311 {
312 if (referenceAndFinal) config_ptr->coordinates.at(Reference).bottomRows(numberOfPaddings)=
313 *new Eigen::Map<MatrixXd> (reference_coordinatesOfPaddings.data(),numberOfPaddings,DIM);
314 config_ptr->coordinates.at(Current).bottomRows(numberOfPaddings)=
315 *new Eigen::Map<MatrixXd> (coordinatesOfPaddings.data(),numberOfPaddings,DIM);
316 for (auto it= speciesOfPaddings.begin();it!= speciesOfPaddings.end();it++)
317 config_ptr->species.push_back(*it);
318 }
319
320 return config_ptr;
321}
323 // TODO Auto-generated destructor stub
324}
325
void readLMP(const std::string &, const ConfigType &configType)
Reads a configuration from an LAMMPS-style dump file.
BoxConfiguration(int numberOfParticles, int referenceAndFinal)
Constructs a BoxConfiguration with a given number of particles.
Vector3i pbc
Periodic boundary conditions. pbc=(1,0,1) implies periodicity along the and -directions.
void read(std::string configFileName, int referenceAndFinal)
A function to read the properties of atoms from a file in a MDStressLab format.
Configuration * getConfiguration(double padding) const
This function returns a padded configuration by adding padding atoms originating due to pbcs.
void lmpParser(std::ifstream &, const ConfigType &)
Parses a LAMMPS dump file to populate configuration data.
Matrix3d box
The current and reference box vectors stored as columns of respective matrices.
Represents atomic configuration data including coordinates, velocities, and species.
std::vector< std::string > species
Species names for each particle (size equals numberOfParticles).
MatrixXd velocities
Velocities of particles.
int numberOfParticles
Total number of particles in the configuration.
std::map< ConfigType, MatrixXd > coordinates
Map from configuration type (Reference or Current) to coordinate matrices.
#define DIM
int nbl_create_paddings(int const numberOfParticles, double const cutoff, double const *reference_cell, double const *cell, int const *PBC, double const *reference_coordinates, double const *coordinates, const std::vector< std::string > &speciesCode, int &numberOfPaddings, std::vector< double > &reference_coordinatesOfPaddings, std::vector< double > &coordinatesOfPaddings, std::vector< std::string > &speciesCodeOfPaddings, std::vector< int > &masterOfPaddings, int referenceAndFinal)
#define MY_ERROR(message)
Definition typedef.h:17
ConfigType
Definition typedef.h:68
@ Current
Definition typedef.h:70
@ Reference
Definition typedef.h:69
#define MY_HEADING(heading)
Definition typedef.h:36