30Structure::Structure() :
33 hasNeighborList (false ),
34 hasSymmetryFunctions (false ),
35 hasSymmetryFunctionDerivatives(false ),
39 numElementsPresent (0 ),
45 sampleType (ST_UNKNOWN),
48 for (
size_t i = 0; i < 3; i++)
75 atoms.back().clearNeighborList();
79 atoms.back().numSymmetryFunctions = 0;
90 file.open(fileName.c_str());
93 throw runtime_error(
"ERROR: Could not open file: \"" + fileName
105 vector<string> lines;
106 vector<string> splitLine;
110 lines.push_back(line);
112 if (splitLine.at(0) !=
"begin")
114 throw runtime_error(
"ERROR: Unexpected file content, expected"
115 " \"begin\" keyword.\n");
118 while (getline(file, line))
120 lines.push_back(line);
122 if (splitLine.at(0) ==
"end")
break;
133 size_t iBoxVector = 0;
134 vector<string> splitLine;
138 if (splitLine.at(0) !=
"begin")
140 throw runtime_error(
"ERROR: Unexpected line content, expected"
141 " \"begin\" keyword.\n");
144 for (vector<string>::const_iterator line = lines.begin();
145 line != lines.end(); ++line)
148 if (splitLine.at(0) ==
"begin")
150 if (splitLine.size() > 1)
152 for (vector<string>::const_iterator word =
153 splitLine.begin() + 1; word != splitLine.end(); ++word)
159 throw runtime_error(
"ERROR: Unknown keyword in "
160 "structure specification, check "
161 "\"begin\" arguments.\n");
166 else if (splitLine.at(0) ==
"comment")
168 size_t position = line->find(
"comment");
169 string tmpLine = *line;
170 comment = tmpLine.erase(position, splitLine.at(0).length() + 1);
172 else if (splitLine.at(0) ==
"lattice")
176 throw runtime_error(
"ERROR: Too many box vectors.\n");
178 box[iBoxVector][0] = atof(splitLine.at(1).c_str());
179 box[iBoxVector][1] = atof(splitLine.at(2).c_str());
180 box[iBoxVector][2] = atof(splitLine.at(3).c_str());
185 if (
box[0][1] > numeric_limits<double>::min() ||
186 box[0][2] > numeric_limits<double>::min() ||
187 box[1][0] > numeric_limits<double>::min() ||
188 box[1][2] > numeric_limits<double>::min() ||
189 box[2][0] > numeric_limits<double>::min() ||
190 box[2][1] > numeric_limits<double>::min())
198 else if (splitLine.at(0) ==
"atom")
204 atoms.back().r[0] = atof(splitLine.at(1).c_str());
205 atoms.back().r[1] = atof(splitLine.at(2).c_str());
206 atoms.back().r[2] = atof(splitLine.at(3).c_str());
208 atoms.back().chargeRef = atof(splitLine.at(5).c_str());
209 atoms.back().fRef[0] = atof(splitLine.at(7).c_str());
210 atoms.back().fRef[1] = atof(splitLine.at(8).c_str());
211 atoms.back().fRef[2] = atof(splitLine.at(9).c_str());
216 else if (splitLine.at(0) ==
"energy")
220 else if (splitLine.at(0) ==
"charge")
224 else if (splitLine.at(0) ==
"end")
226 if (!(iBoxVector == 0 || iBoxVector == 3))
228 throw runtime_error(
"ERROR: Strange number of box vectors.\n");
234 throw runtime_error(
"ERROR: Unexpected file content, "
235 "unknown keyword \"" + splitLine.at(0) +
260 cutoffRadius *= cutoffRadius;
264 #pragma omp parallel for private(i)
269 atoms[i].neighborsUnique.push_back(i);
270 atoms[i].numNeighborsUnique++;
271 for (
size_t j = 0; j <
numAtoms; j++)
273 for (
int bc0 = -
pbc[0]; bc0 <=
pbc[0]; bc0++)
275 for (
int bc1 = -
pbc[1]; bc1 <=
pbc[1]; bc1++)
277 for (
int bc2 = -
pbc[2]; bc2 <=
pbc[2]; bc2++)
279 if (!(i == j && bc0 == 0 && bc1 == 0 && bc2 == 0))
285 if (dr.
norm2() <= cutoffRadius)
294 back().element =
atoms[j].element;
296 back().d = dr.
norm();
299 atoms[i].numNeighborsPerElement[
301 atoms[i].numNeighbors++;
304 if (
atoms[i].neighborsUnique.back() != j &&
307 atoms[i].neighborsUnique.push_back(j);
308 atoms[i].numNeighborsUnique++;
316 atoms[i].hasNeighborList =
true;
322 cutoffRadius *= cutoffRadius;
326 #pragma omp parallel for private(i)
331 atoms[i].neighborsUnique.push_back(i);
332 atoms[i].numNeighborsUnique++;
333 for (
size_t j = 0; j <
numAtoms; j++)
338 if (dr.
norm2() <= cutoffRadius)
341 atoms[i].neighbors.back().index = j;
342 atoms[i].neighbors.back().tag = j;
343 atoms[i].neighbors.back().element =
atoms[j].element;
345 atoms[i].neighbors.back().dr = dr;
346 atoms[i].numNeighborsPerElement[
atoms[j].element]++;
347 atoms[i].numNeighbors++;
348 atoms[i].neighborsUnique.push_back(j);
349 atoms[i].numNeighborsUnique++;
353 atoms[i].hasNeighborList =
true;
364 size_t maxNumNeighbors = 0;
366 for(vector<Atom>::const_iterator it =
atoms.begin();
367 it !=
atoms.end(); ++it)
369 maxNumNeighbors = max(maxNumNeighbors, it->numNeighbors);
372 return maxNumNeighbors;
385 double proja = fabs(
box[0] * bxc);
386 double projb = fabs(
box[1] * axc);
387 double projc = fabs(
box[2] * axb);
392 while (
pbc[0] * proja <= cutoffRadius)
396 while (
pbc[1] * projb <= cutoffRadius)
400 while (
pbc[2] * projc <= cutoffRadius)
410 double invdet =
box[0][0] *
box[1][1] *
box[2][2]
416 invdet = 1.0 / invdet;
445 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
460 if (f[0] > 1.0) f[0] -= (int)f[0];
461 if (f[1] > 1.0) f[1] -= (int)f[1];
462 if (f[2] > 1.0) f[2] -= (int)f[2];
464 if (f[0] < 0.0) f[0] += 1.0 - (int)f[0];
465 if (f[1] < 0.0) f[1] += 1.0 - (int)f[1];
466 if (f[2] < 0.0) f[2] += 1.0 - (int)f[2];
468 if (f[0] == 1.0) f[0] = 0.0;
469 if (f[1] == 1.0) f[1] = 0.0;
470 if (f[2] == 1.0) f[2] = 0.0;
472 atom.
r = f[0] *
box[0]
485 box[0] *= convLength;
486 box[1] *= convLength;
487 box[2] *= convLength;
495 volume *= convLength * convLength * convLength;
497 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
499 it->toNormalizedUnits(convEnergy, convLength);
511 box[0] /= convLength;
512 box[1] /= convLength;
513 box[2] /= convLength;
521 volume /= convLength * convLength * convLength;
523 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
525 it->toPhysicalUnits(convEnergy, convLength);
533 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
561 for (
size_t i = 0; i < 3; ++i)
564 for (
size_t j = 0; j < 3; ++j)
582 for (
size_t i = 0; i <
numAtoms; i++)
597 map<string, double>& error,
600 if (property ==
"energy")
605 error.at(
"RMSE") += diff * diff;
607 error.at(
"MAEpa") += diff /
numAtoms;
608 error.at(
"MAE") += diff;
610 else if (property ==
"force" || property ==
"charge")
612 for (vector<Atom>::const_iterator it =
atoms.begin();
613 it !=
atoms.end(); ++it)
615 it->updateError(property, error, count);
620 throw runtime_error(
"ERROR: Unknown property for error update.\n");
628 return strpr(
"%10zu %16.8E %16.8E\n",
637 for (vector<Atom>::const_iterator it =
atoms.begin();
638 it !=
atoms.end(); ++it)
640 vector<string> va = it->getForcesLines();
641 v.insert(v.end(), va.begin(), va.end());
650 for (vector<Atom>::const_iterator it =
atoms.begin();
651 it !=
atoms.end(); ++it)
653 v.push_back(it->getChargeLine());
661 bool const append)
const
667 file.open(fileName.c_str(), ofstream::app);
671 file.open(fileName.c_str());
675 throw runtime_error(
"ERROR: Could not open file: \"" + fileName
686 if (!file->is_open())
688 runtime_error(
"ERROR: Cannot write to file, file is not open.\n");
691 (*file) <<
"begin\n";
695 for (
size_t i = 0; i < 3; ++i)
697 (*file) <<
strpr(
"lattice %24.16E %24.16E %24.16E\n",
701 for (vector<Atom>::const_iterator it =
atoms.begin();
702 it !=
atoms.end(); ++it)
706 (*file) <<
strpr(
"atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
707 " %24.16E %24.16E %24.16E\n",
720 (*file) <<
strpr(
"atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
721 " %24.16E %24.16E %24.16E\n",
738 (*file) <<
strpr(
"end\n");
745 if (!file->is_open())
747 runtime_error(
"ERROR: Could not write to file.\n");
753 (*file) <<
"Lattice=\"";
754 (*file) <<
strpr(
"%24.16E %24.16E %24.16E " ,
756 (*file) <<
strpr(
"%24.16E %24.16E %24.16E " ,
758 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\"\n",
765 for (vector<Atom>::const_iterator it =
atoms.begin();
766 it !=
atoms.end(); ++it)
768 (*file) <<
strpr(
"%-2s %24.16E %24.16E %24.16E\n",
786 string const elements)
const
788 if (!file->is_open())
790 runtime_error(
"ERROR: Could not write to file.\n");
793 vector<string> ve =
split(elements);
794 vector<size_t> elementOrder;
795 for (
size_t i = 0; i < ve.size(); ++i)
801 runtime_error(
"ERROR: Inconsistent element declaration.\n");
806 for (
size_t i = 1; i < elementOrder.size(); ++i)
814 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
816 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
818 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
823 runtime_error(
"ERROR: Writing non-periodic structure to POSCAR file "
824 "is not implemented.\n");
832 (*file) <<
"Cartesian\n";
833 for (
size_t i = 0; i < elementOrder.size(); ++i)
835 for (vector<Atom>::const_iterator it =
atoms.begin();
836 it !=
atoms.end(); ++it)
838 if (it->element == elementOrder.at(i))
840 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
855 v.push_back(
strpr(
"********************************\n"));
856 v.push_back(
strpr(
"STRUCTURE \n"));
857 v.push_back(
strpr(
"********************************\n"));
859 v.insert(v.end(), vm.begin(), vm.end());
877 v.push_back(
strpr(
"box[0] : %16.8E %16.8E %16.8E\n",
box[0][0],
box[0][1],
box[0][2]));
878 v.push_back(
strpr(
"box[1] : %16.8E %16.8E %16.8E\n",
box[1][0],
box[1][1],
box[1][2]));
879 v.push_back(
strpr(
"box[2] : %16.8E %16.8E %16.8E\n",
box[2][0],
box[2][1],
box[2][2]));
883 v.push_back(
strpr(
"--------------------------------\n"));
885 v.push_back(
strpr(
"--------------------------------\n"));
890 v.push_back(
strpr(
"--------------------------------\n"));
891 v.push_back(
strpr(
"--------------------------------\n"));
892 v.push_back(
strpr(
"atoms [*] : %d\n",
atoms.size()));
893 v.push_back(
strpr(
"--------------------------------\n"));
894 for (
size_t i = 0; i <
atoms.size(); ++i)
896 v.push_back(
strpr(
"%29d :\n", i));
897 vector<string> va =
atoms[i].info();
898 v.insert(v.end(), va.begin(), va.end());
900 v.push_back(
strpr(
"--------------------------------\n"));
901 v.push_back(
strpr(
"********************************\n"));
std::vector< std::string > info() const
Get map information as a vector of strings.
std::size_t size() const
Get element map size.
std::string getElementsString() const
Get sorted list of elements in one string (space separated).
string strpr(const char *format,...)
String version of printf function.
vector< string > split(string const &input, char delimiter)
Split string at each delimiter.
string reduce(string const &line, string const &whitespace, string const &fill)
Replace multiple whitespaces with fill.
Struct to store information on neighbor atoms.
Storage for a single atom.
Vec3D r
Cartesian coordinates.
void clearNeighborList()
Clear neighbor list.
std::vector< std::size_t > numNeighborsPerElement
Number of neighbors per element.
void toPhysicalUnits(double meanEnergy, double convEnergy, double convLength)
Switch to physical units, shift energy and change energy and length unit.
void calculateVolume()
Calculate volume from box vectors.
@ ST_TRAINING
Structure is part of the training set.
@ ST_UNKNOWN
Sample type not assigned yet.
@ ST_TEST
Structure is part of the test set.
Vec3D invbox[3]
Inverse simulation box vectors.
Vec3D box[3]
Simulation box vectors.
bool isTriclinic
If the simulation box is triclinic.
std::size_t getMaxNumNeighbors() const
Find maximum number of neighbors.
std::vector< std::size_t > numAtomsPerElement
Number of atoms of each element in this structure.
void writeToFile(std::string const fileName="output.data", bool const ref=true, bool const append=false) const
Write configuration to file.
std::string comment
Structure comment.
bool isPeriodic
If periodic boundary conditions apply.
double charge
Charge determined by neural network potential.
ElementMap elementMap
Copy of element map provided as constructor argument.
void setElementMap(ElementMap const &elementMap)
Set element map of structure.
std::size_t index
Index number of this structure.
void remap()
Translate all atoms back into box if outside.
std::vector< std::string > getChargesLines() const
Get reference and NN charges for all atoms.
double chargeRef
Reference charge.
SampleType sampleType
Sample type (training or test set).
void addAtom(Atom const &atom, std::string const &element)
Add a single atom to structure.
void calculateInverseBox()
Calculate inverse box.
void writeToFilePoscar(std::ofstream *const &file) const
Write configuration to POSCAR file.
void writeToFileXyz(std::ofstream *const &file) const
Write configuration to xyz file.
bool hasSymmetryFunctionDerivatives
If symmetry function derivatives are saved for each atom.
void calculatePbcCopies(double cutoffRadius)
Calculate required PBC copies.
std::string getEnergyLine() const
Get reference and NN energy.
void freeAtoms(bool all)
Free symmetry function memory for all atoms, see free() in Atom class.
double energy
Potential energy determined by neural network.
void readFromFile(std::string const fileName="input.data")
Read configuration from file.
double energyRef
Reference potential energy.
int pbc[3]
Number of PBC images necessary in each direction.
void reset()
Reset everything but elementMap.
std::vector< std::string > getForcesLines() const
Get reference and NN forces for all atoms.
double volume
Simulation box volume.
void toNormalizedUnits(double meanEnergy, double convEnergy, double convLength)
Normalize structure, shift energy and change energy and length unit.
std::size_t numAtoms
Total number of atoms present in this structure.
std::size_t numElements
Global number of elements (all structures).
void updateError(std::string const &property, std::map< std::string, double > &error, std::size_t &count) const
Update property error metrics with this structure.
void calculateNeighborList(double cutoffRadius)
Calculate neighbor list for all atoms.
std::vector< Atom > atoms
Vector of all atoms in this structure.
std::size_t numElementsPresent
Number of elements present in this structure.
void readFromLines(std::vector< std::string > const &lines)
Read configuration from lines.
bool hasNeighborList
If the neighbor list has been calculated.
void clearNeighborList()
Clear neighbor list of all atoms.
std::vector< std::string > info() const
Get structure information as a vector of strings.
bool hasSymmetryFunctions
If symmetry function values are saved for each atom.
Vector in 3 dimensional real space.
double norm2() const
Calculate square of norm of vector.
Vec3D & normalize()
Normalize vector, norm equals 1.0 afterwards.
Vec3D cross(Vec3D const &v) const
Cross product, argument vector is second in product.
double norm() const
Calculate norm of vector.