n2p2 - A neural network potential package
Structure.cpp
Go to the documentation of this file.
1// n2p2 - A neural network potential package
2// Copyright (C) 2018 Andreas Singraber (University of Vienna)
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17#include "Structure.h"
18#include "utility.h"
19#include <algorithm> // std::max
20#include <cmath> // fabs
21#include <cstdlib> // atof
22#include <limits> // std::numeric_limits
23#include <stdexcept> // std::runtime_error
24#include <string> // std::getline
25#include <iostream>
26
27using namespace std;
28using namespace nnp;
29
30Structure::Structure() :
31 isPeriodic (false ),
32 isTriclinic (false ),
33 hasNeighborList (false ),
34 hasSymmetryFunctions (false ),
35 hasSymmetryFunctionDerivatives(false ),
36 index (0 ),
37 numAtoms (0 ),
38 numElements (0 ),
39 numElementsPresent (0 ),
40 energy (0.0 ),
41 energyRef (0.0 ),
42 charge (0.0 ),
43 chargeRef (0.0 ),
44 volume (0.0 ),
45 sampleType (ST_UNKNOWN),
46 comment ("" )
47{
48 for (size_t i = 0; i < 3; i++)
49 {
50 pbc[i] = 0;
51 box[i][0] = 0.0;
52 box[i][1] = 0.0;
53 box[i][2] = 0.0;
54 invbox[i][0] = 0.0;
55 invbox[i][1] = 0.0;
56 invbox[i][2] = 0.0;
57 }
58}
59
60void Structure::setElementMap(ElementMap const& elementMap)
61{
62 this->elementMap = elementMap;
65
66 return;
67}
68
69void Structure::addAtom(Atom const& atom, string const& element)
70{
71 atoms.push_back(Atom());
72 atoms.back() = atom;
73 // The number of elements may have changed.
74 atoms.back().numNeighborsPerElement.resize(elementMap.size(), 0);
75 atoms.back().clearNeighborList();
76 atoms.back().index = numAtoms;
77 atoms.back().indexStructure = index;
78 atoms.back().element = elementMap[element];
79 atoms.back().numSymmetryFunctions = 0;
80 numAtoms++;
82
83 return;
84}
85
86void Structure::readFromFile(string const fileName)
87{
88 ifstream file;
89
90 file.open(fileName.c_str());
91 if (!file.is_open())
92 {
93 throw runtime_error("ERROR: Could not open file: \"" + fileName
94 + "\".\n");
95 }
96 readFromFile(file);
97 file.close();
98
99 return;
100}
101
102void Structure::readFromFile(ifstream& file)
103{
104 string line;
105 vector<string> lines;
106 vector<string> splitLine;
107
108 // read first line, should be keyword "begin".
109 getline(file, line);
110 lines.push_back(line);
111 splitLine = split(reduce(line));
112 if (splitLine.at(0) != "begin")
113 {
114 throw runtime_error("ERROR: Unexpected file content, expected"
115 " \"begin\" keyword.\n");
116 }
117
118 while (getline(file, line))
119 {
120 lines.push_back(line);
121 splitLine = split(reduce(line));
122 if (splitLine.at(0) == "end") break;
123 }
124
125 readFromLines(lines);
126
127 return;
128}
129
130
131void Structure::readFromLines(vector<string> const& lines)
132{
133 size_t iBoxVector = 0;
134 vector<string> splitLine;
135
136 // read first line, should be keyword "begin".
137 splitLine = split(reduce(lines.at(0)));
138 if (splitLine.at(0) != "begin")
139 {
140 throw runtime_error("ERROR: Unexpected line content, expected"
141 " \"begin\" keyword.\n");
142 }
143
144 for (vector<string>::const_iterator line = lines.begin();
145 line != lines.end(); ++line)
146 {
147 splitLine = split(reduce(*line));
148 if (splitLine.at(0) == "begin")
149 {
150 if (splitLine.size() > 1)
151 {
152 for (vector<string>::const_iterator word =
153 splitLine.begin() + 1; word != splitLine.end(); ++word)
154 {
155 if (*word == "set=train") sampleType = ST_TRAINING;
156 else if (*word == "set=test") sampleType = ST_TEST;
157 else
158 {
159 throw runtime_error("ERROR: Unknown keyword in "
160 "structure specification, check "
161 "\"begin\" arguments.\n");
162 }
163 }
164 }
165 }
166 else if (splitLine.at(0) == "comment")
167 {
168 size_t position = line->find("comment");
169 string tmpLine = *line;
170 comment = tmpLine.erase(position, splitLine.at(0).length() + 1);
171 }
172 else if (splitLine.at(0) == "lattice")
173 {
174 if (iBoxVector > 2)
175 {
176 throw runtime_error("ERROR: Too many box vectors.\n");
177 }
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());
181 iBoxVector++;
182 if (iBoxVector == 3)
183 {
184 isPeriodic = true;
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())
191 {
192 isTriclinic = true;
193 }
196 }
197 }
198 else if (splitLine.at(0) == "atom")
199 {
200 atoms.push_back(Atom());
201 atoms.back().index = numAtoms;
202 atoms.back().indexStructure = index;
203 atoms.back().tag = numAtoms; // Implicit conversion!
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());
207 atoms.back().element = elementMap[splitLine.at(4)];
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());
212 atoms.back().numNeighborsPerElement.resize(numElements, 0);
213 numAtoms++;
214 numAtomsPerElement[elementMap[splitLine.at(4)]]++;
215 }
216 else if (splitLine.at(0) == "energy")
217 {
218 energyRef = atof(splitLine[1].c_str());
219 }
220 else if (splitLine.at(0) == "charge")
221 {
222 chargeRef = atof(splitLine[1].c_str());
223 }
224 else if (splitLine.at(0) == "end")
225 {
226 if (!(iBoxVector == 0 || iBoxVector == 3))
227 {
228 throw runtime_error("ERROR: Strange number of box vectors.\n");
229 }
230 break;
231 }
232 else
233 {
234 throw runtime_error("ERROR: Unexpected file content, "
235 "unknown keyword \"" + splitLine.at(0) +
236 "\".\n");
237 }
238 }
239
240 for (size_t i = 0; i < numElements; i++)
241 {
242 if (numAtomsPerElement[i] > 0)
243 {
245 }
246 }
247
248 if (isPeriodic) remap();
249
250 return;
251}
252
253void Structure::calculateNeighborList(double cutoffRadius)
254{
255 if (isPeriodic)
256 {
257 calculatePbcCopies(cutoffRadius);
258
259 // Use square of cutoffRadius (faster).
260 cutoffRadius *= cutoffRadius;
261
262 size_t i = 0;
263#ifdef _OPENMP
264 #pragma omp parallel for private(i)
265#endif
266 for (i = 0; i < numAtoms; i++)
267 {
268 // Count atom i as unique neighbor.
269 atoms[i].neighborsUnique.push_back(i);
270 atoms[i].numNeighborsUnique++;
271 for (size_t j = 0; j < numAtoms; j++)
272 {
273 for (int bc0 = -pbc[0]; bc0 <= pbc[0]; bc0++)
274 {
275 for (int bc1 = -pbc[1]; bc1 <= pbc[1]; bc1++)
276 {
277 for (int bc2 = -pbc[2]; bc2 <= pbc[2]; bc2++)
278 {
279 if (!(i == j && bc0 == 0 && bc1 == 0 && bc2 == 0))
280 {
281 Vec3D dr = atoms[i].r - atoms[j].r
282 + bc0 * box[0]
283 + bc1 * box[1]
284 + bc2 * box[2];
285 if (dr.norm2() <= cutoffRadius)
286 {
287 atoms[i].neighbors.
288 push_back(Atom::Neighbor());
289 atoms[i].neighbors.
290 back().index = j;
291 atoms[i].neighbors.
292 back().tag = j; // Implicit conversion!
293 atoms[i].neighbors.
294 back().element = atoms[j].element;
295 atoms[i].neighbors.
296 back().d = dr.norm();
297 atoms[i].neighbors.
298 back().dr = dr;
299 atoms[i].numNeighborsPerElement[
300 atoms[j].element]++;
301 atoms[i].numNeighbors++;
302 // Count atom j only once as unique
303 // neighbor.
304 if (atoms[i].neighborsUnique.back() != j &&
305 i != j)
306 {
307 atoms[i].neighborsUnique.push_back(j);
308 atoms[i].numNeighborsUnique++;
309 }
310 }
311 }
312 }
313 }
314 }
315 }
316 atoms[i].hasNeighborList = true;
317 }
318 }
319 else
320 {
321 // Use square of cutoffRadius (faster).
322 cutoffRadius *= cutoffRadius;
323
324 size_t i = 0;
325#ifdef _OPENMP
326 #pragma omp parallel for private(i)
327#endif
328 for (i = 0; i < numAtoms; i++)
329 {
330 // Count atom i as unique neighbor.
331 atoms[i].neighborsUnique.push_back(i);
332 atoms[i].numNeighborsUnique++;
333 for (size_t j = 0; j < numAtoms; j++)
334 {
335 if (i != j)
336 {
337 Vec3D dr = atoms[i].r - atoms[j].r;
338 if (dr.norm2() <= cutoffRadius)
339 {
340 atoms[i].neighbors.push_back(Atom::Neighbor());
341 atoms[i].neighbors.back().index = j;
342 atoms[i].neighbors.back().tag = j; // Impl. conv.!
343 atoms[i].neighbors.back().element = atoms[j].element;
344 atoms[i].neighbors.back().d = dr.norm();
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++;
350 }
351 }
352 }
353 atoms[i].hasNeighborList = true;
354 }
355 }
356
357 hasNeighborList = true;
358
359 return;
360}
361
363{
364 size_t maxNumNeighbors = 0;
365
366 for(vector<Atom>::const_iterator it = atoms.begin();
367 it != atoms.end(); ++it)
368 {
369 maxNumNeighbors = max(maxNumNeighbors, it->numNeighbors);
370 }
371
372 return maxNumNeighbors;
373}
374
375void Structure::calculatePbcCopies(double cutoffRadius)
376{
377 Vec3D axb;
378 Vec3D axc;
379 Vec3D bxc;
380
381 axb = box[0].cross(box[1]).normalize();
382 axc = box[0].cross(box[2]).normalize();
383 bxc = box[1].cross(box[2]).normalize();
384
385 double proja = fabs(box[0] * bxc);
386 double projb = fabs(box[1] * axc);
387 double projc = fabs(box[2] * axb);
388
389 pbc[0] = 0;
390 pbc[1] = 0;
391 pbc[2] = 0;
392 while (pbc[0] * proja <= cutoffRadius)
393 {
394 pbc[0]++;
395 }
396 while (pbc[1] * projb <= cutoffRadius)
397 {
398 pbc[1]++;
399 }
400 while (pbc[2] * projc <= cutoffRadius)
401 {
402 pbc[2]++;
403 }
404
405 return;
406}
407
409{
410 double invdet = box[0][0] * box[1][1] * box[2][2]
411 + box[1][0] * box[2][1] * box[0][2]
412 + box[2][0] * box[0][1] * box[1][2]
413 - box[2][0] * box[1][1] * box[0][2]
414 - box[0][0] * box[2][1] * box[1][2]
415 - box[1][0] * box[0][1] * box[2][2];
416 invdet = 1.0 / invdet;
417
418 invbox[0][0] = box[1][1] * box[2][2] - box[2][1] * box[1][2];
419 invbox[0][1] = box[2][1] * box[0][2] - box[0][1] * box[2][2];
420 invbox[0][2] = box[0][1] * box[1][2] - box[1][1] * box[0][2];
421 invbox[0] *= invdet;
422
423 invbox[1][0] = box[2][0] * box[1][2] - box[1][0] * box[2][2];
424 invbox[1][1] = box[0][0] * box[2][2] - box[2][0] * box[0][2];
425 invbox[1][2] = box[1][0] * box[0][2] - box[0][0] * box[1][2];
426 invbox[1] *= invdet;
427
428 invbox[2][0] = box[1][0] * box[2][1] - box[2][0] * box[1][1];
429 invbox[2][1] = box[2][0] * box[0][1] - box[0][0] * box[2][1];
430 invbox[2][2] = box[0][0] * box[1][1] - box[1][0] * box[0][1];
431 invbox[2] *= invdet;
432
433 return;
434}
435
437{
438 volume = fabs(box[0] * (box[1].cross(box[2])));
439
440 return;
441}
442
444{
445 for (vector<Atom>::iterator it = atoms.begin(); it != atoms.end(); ++it)
446 {
447 remap((*it));
448 }
449
450 return;
451}
452
454{
455 Vec3D f = atom.r[0] * invbox[0]
456 + atom.r[1] * invbox[1]
457 + atom.r[2] * invbox[2];
458
459 // Quick and dirty... there may be a more elegant way!
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];
463
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];
467
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;
471
472 atom.r = f[0] * box[0]
473 + f[1] * box[1]
474 + f[2] * box[2];
475
476 return;
477}
478
479void Structure::toNormalizedUnits(double meanEnergy,
480 double convEnergy,
481 double convLength)
482{
483 if (isPeriodic)
484 {
485 box[0] *= convLength;
486 box[1] *= convLength;
487 box[2] *= convLength;
488 invbox[0] /= convLength;
489 invbox[1] /= convLength;
490 invbox[2] /= convLength;
491 }
492
493 energyRef = (energyRef - numAtoms * meanEnergy) * convEnergy;
494 energy = (energy - numAtoms * meanEnergy) * convEnergy;
495 volume *= convLength * convLength * convLength;
496
497 for (vector<Atom>::iterator it = atoms.begin(); it != atoms.end(); ++it)
498 {
499 it->toNormalizedUnits(convEnergy, convLength);
500 }
501
502 return;
503}
504
505void Structure::toPhysicalUnits(double meanEnergy,
506 double convEnergy,
507 double convLength)
508{
509 if (isPeriodic)
510 {
511 box[0] /= convLength;
512 box[1] /= convLength;
513 box[2] /= convLength;
514 invbox[0] *= convLength;
515 invbox[1] *= convLength;
516 invbox[2] *= convLength;
517 }
518
519 energyRef = energyRef / convEnergy + numAtoms * meanEnergy;
520 energy = energy / convEnergy + numAtoms * meanEnergy;
521 volume /= convLength * convLength * convLength;
522
523 for (vector<Atom>::iterator it = atoms.begin(); it != atoms.end(); ++it)
524 {
525 it->toPhysicalUnits(convEnergy, convLength);
526 }
527
528 return;
529}
530
532{
533 for (vector<Atom>::iterator it = atoms.begin(); it != atoms.end(); ++it)
534 {
535 it->free(all);
536 }
537 if (all) hasSymmetryFunctions = false;
539
540 return;
541}
542
544{
545 isPeriodic = false ;
546 isTriclinic = false ;
547 hasNeighborList = false ;
548 hasSymmetryFunctions = false ;
550 index = 0 ;
551 numAtoms = 0 ;
553 energy = 0.0 ;
554 energyRef = 0.0 ;
555 charge = 0.0 ;
556 chargeRef = 0.0 ;
557 volume = 0.0 ;
559 comment = "" ;
560
561 for (size_t i = 0; i < 3; ++i)
562 {
563 pbc[i] = 0;
564 for (size_t j = 0; j < 3; ++j)
565 {
566 box[i][j] = 0.0;
567 invbox[i][j] = 0.0;
568 }
569 }
570
572 numAtomsPerElement.clear();
574 atoms.clear();
575 vector<Atom>(atoms).swap(atoms);
576
577 return;
578}
579
581{
582 for (size_t i = 0; i < numAtoms; i++)
583 {
584 Atom& a = atoms.at(i);
585 // This may have changed if atoms are added via addAtoms().
588 }
589 hasNeighborList = false;
590 hasSymmetryFunctions = false;
592
593 return;
594}
595
596void Structure::updateError(string const& property,
597 map<string, double>& error,
598 size_t& count) const
599{
600 if (property == "energy")
601 {
602 count++;
603 double diff = energyRef - energy;
604 error.at("RMSEpa") += diff * diff / (numAtoms * numAtoms);
605 error.at("RMSE") += diff * diff;
606 diff = fabs(diff);
607 error.at("MAEpa") += diff / numAtoms;
608 error.at("MAE") += diff;
609 }
610 else if (property == "force" || property == "charge")
611 {
612 for (vector<Atom>::const_iterator it = atoms.begin();
613 it != atoms.end(); ++it)
614 {
615 it->updateError(property, error, count);
616 }
617 }
618 else
619 {
620 throw runtime_error("ERROR: Unknown property for error update.\n");
621 }
622
623 return;
624}
625
627{
628 return strpr("%10zu %16.8E %16.8E\n",
629 index,
631 energy / numAtoms);
632}
633
634vector<string> Structure::getForcesLines() const
635{
636 vector<string> v;
637 for (vector<Atom>::const_iterator it = atoms.begin();
638 it != atoms.end(); ++it)
639 {
640 vector<string> va = it->getForcesLines();
641 v.insert(v.end(), va.begin(), va.end());
642 }
643
644 return v;
645}
646
647vector<string> Structure::getChargesLines() const
648{
649 vector<string> v;
650 for (vector<Atom>::const_iterator it = atoms.begin();
651 it != atoms.end(); ++it)
652 {
653 v.push_back(it->getChargeLine());
654 }
655
656 return v;
657}
658
659void Structure::writeToFile(string const fileName,
660 bool const ref,
661 bool const append) const
662{
663 ofstream file;
664
665 if (append)
666 {
667 file.open(fileName.c_str(), ofstream::app);
668 }
669 else
670 {
671 file.open(fileName.c_str());
672 }
673 if (!file.is_open())
674 {
675 throw runtime_error("ERROR: Could not open file: \"" + fileName
676 + "\".\n");
677 }
678 writeToFile(&file, ref );
679 file.close();
680
681 return;
682}
683
684void Structure::writeToFile(ofstream* const& file, bool const ref) const
685{
686 if (!file->is_open())
687 {
688 runtime_error("ERROR: Cannot write to file, file is not open.\n");
689 }
690
691 (*file) << "begin\n";
692 (*file) << strpr("comment %s\n", comment.c_str());
693 if (isPeriodic)
694 {
695 for (size_t i = 0; i < 3; ++i)
696 {
697 (*file) << strpr("lattice %24.16E %24.16E %24.16E\n",
698 box[i][0], box[i][1], box[i][2]);
699 }
700 }
701 for (vector<Atom>::const_iterator it = atoms.begin();
702 it != atoms.end(); ++it)
703 {
704 if (ref)
705 {
706 (*file) << strpr("atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
707 " %24.16E %24.16E %24.16E\n",
708 it->r[0],
709 it->r[1],
710 it->r[2],
711 elementMap[it->element].c_str(),
712 it->chargeRef,
713 0.0,
714 it->fRef[0],
715 it->fRef[1],
716 it->fRef[2]);
717 }
718 else
719 {
720 (*file) << strpr("atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
721 " %24.16E %24.16E %24.16E\n",
722 it->r[0],
723 it->r[1],
724 it->r[2],
725 elementMap[it->element].c_str(),
726 it->charge,
727 0.0,
728 it->f[0],
729 it->f[1],
730 it->f[2]);
731
732 }
733 }
734 if (ref) (*file) << strpr("energy %24.16E\n", energyRef);
735 else (*file) << strpr("energy %24.16E\n", energy);
736 if (ref) (*file) << strpr("charge %24.16E\n", chargeRef);
737 else (*file) << strpr("charge %24.16E\n", charge);
738 (*file) << strpr("end\n");
739
740 return;
741}
742
743void Structure::writeToFileXyz(ofstream* const& file) const
744{
745 if (!file->is_open())
746 {
747 runtime_error("ERROR: Could not write to file.\n");
748 }
749
750 (*file) << strpr("%d\n", numAtoms);
751 if (isPeriodic)
752 {
753 (*file) << "Lattice=\"";
754 (*file) << strpr("%24.16E %24.16E %24.16E " ,
755 box[0][0], box[0][1], box[0][2]);
756 (*file) << strpr("%24.16E %24.16E %24.16E " ,
757 box[1][0], box[1][1], box[1][2]);
758 (*file) << strpr("%24.16E %24.16E %24.16E\"\n",
759 box[2][0], box[2][1], box[2][2]);
760 }
761 else
762 {
763 (*file) << "\n";
764 }
765 for (vector<Atom>::const_iterator it = atoms.begin();
766 it != atoms.end(); ++it)
767 {
768 (*file) << strpr("%-2s %24.16E %24.16E %24.16E\n",
769 elementMap[it->element].c_str(),
770 it->r[0],
771 it->r[1],
772 it->r[2]);
773 }
774
775 return;
776}
777
778void Structure::writeToFilePoscar(ofstream* const& file) const
779{
781
782 return;
783}
784
785void Structure::writeToFilePoscar(ofstream* const& file,
786 string const elements) const
787{
788 if (!file->is_open())
789 {
790 runtime_error("ERROR: Could not write to file.\n");
791 }
792
793 vector<string> ve = split(elements);
794 vector<size_t> elementOrder;
795 for (size_t i = 0; i < ve.size(); ++i)
796 {
797 elementOrder.push_back(elementMap[ve.at(i)]);
798 }
799 if (elementOrder.size() != elementMap.size())
800 {
801 runtime_error("ERROR: Inconsistent element declaration.\n");
802 }
803
804 (*file) << strpr("%s, ", comment.c_str());
805 (*file) << strpr("ATOM=%s", elementMap[elementOrder.at(0)].c_str());
806 for (size_t i = 1; i < elementOrder.size(); ++i)
807 {
808 (*file) << strpr(" %s", elementMap[elementOrder.at(i)].c_str());
809 }
810 (*file) << "\n";
811 (*file) << "1.0\n";
812 if (isPeriodic)
813 {
814 (*file) << strpr("%24.16E %24.16E %24.16E\n",
815 box[0][0], box[0][1], box[0][2]);
816 (*file) << strpr("%24.16E %24.16E %24.16E\n",
817 box[1][0], box[1][1], box[1][2]);
818 (*file) << strpr("%24.16E %24.16E %24.16E\n",
819 box[2][0], box[2][1], box[2][2]);
820 }
821 else
822 {
823 runtime_error("ERROR: Writing non-periodic structure to POSCAR file "
824 "is not implemented.\n");
825 }
826 (*file) << strpr("%d", numAtomsPerElement.at(elementOrder.at(0)));
827 for (size_t i = 1; i < numAtomsPerElement.size(); ++i)
828 {
829 (*file) << strpr(" %d", numAtomsPerElement.at(elementOrder.at(i)));
830 }
831 (*file) << "\n";
832 (*file) << "Cartesian\n";
833 for (size_t i = 0; i < elementOrder.size(); ++i)
834 {
835 for (vector<Atom>::const_iterator it = atoms.begin();
836 it != atoms.end(); ++it)
837 {
838 if (it->element == elementOrder.at(i))
839 {
840 (*file) << strpr("%24.16E %24.16E %24.16E\n",
841 it->r[0],
842 it->r[1],
843 it->r[2]);
844 }
845 }
846 }
847
848 return;
849}
850
851vector<string> Structure::info() const
852{
853 vector<string> v;
854
855 v.push_back(strpr("********************************\n"));
856 v.push_back(strpr("STRUCTURE \n"));
857 v.push_back(strpr("********************************\n"));
858 vector<string> vm = elementMap.info();
859 v.insert(v.end(), vm.begin(), vm.end());
860 v.push_back(strpr("index : %d\n", index));
861 v.push_back(strpr("isPeriodic : %d\n", isPeriodic ));
862 v.push_back(strpr("isTriclinic : %d\n", isTriclinic ));
863 v.push_back(strpr("hasNeighborList : %d\n", hasNeighborList ));
864 v.push_back(strpr("hasSymmetryFunctions : %d\n", hasSymmetryFunctions));
865 v.push_back(strpr("hasSymmetryFunctionDerivatives : %d\n", hasSymmetryFunctionDerivatives));
866 v.push_back(strpr("numAtoms : %d\n", numAtoms ));
867 v.push_back(strpr("numElements : %d\n", numElements ));
868 v.push_back(strpr("numElementsPresent : %d\n", numElementsPresent));
869 v.push_back(strpr("pbc : %d %d %d\n", pbc[0], pbc[1], pbc[2]));
870 v.push_back(strpr("energy : %16.8E\n", energy ));
871 v.push_back(strpr("energyRef : %16.8E\n", energyRef ));
872 v.push_back(strpr("charge : %16.8E\n", charge ));
873 v.push_back(strpr("chargeRef : %16.8E\n", chargeRef ));
874 v.push_back(strpr("volume : %16.8E\n", volume ));
875 v.push_back(strpr("sampleType : %d\n", (int)sampleType));
876 v.push_back(strpr("comment : %s\n", comment.c_str() ));
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]));
880 v.push_back(strpr("invbox[0] : %16.8E %16.8E %16.8E\n", invbox[0][0], invbox[0][1], invbox[0][2]));
881 v.push_back(strpr("invbox[1] : %16.8E %16.8E %16.8E\n", invbox[1][0], invbox[1][1], invbox[1][2]));
882 v.push_back(strpr("invbox[2] : %16.8E %16.8E %16.8E\n", invbox[2][0], invbox[2][1], invbox[2][2]));
883 v.push_back(strpr("--------------------------------\n"));
884 v.push_back(strpr("numAtomsPerElement [*] : %d\n", numAtomsPerElement.size()));
885 v.push_back(strpr("--------------------------------\n"));
886 for (size_t i = 0; i < numAtomsPerElement.size(); ++i)
887 {
888 v.push_back(strpr("%29d : %d\n", i, numAtomsPerElement.at(i)));
889 }
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)
895 {
896 v.push_back(strpr("%29d :\n", i));
897 vector<string> va = atoms[i].info();
898 v.insert(v.end(), va.begin(), va.end());
899 }
900 v.push_back(strpr("--------------------------------\n"));
901 v.push_back(strpr("********************************\n"));
902
903 return v;
904}
Contains element map.
Definition: ElementMap.h:30
std::vector< std::string > info() const
Get map information as a vector of strings.
Definition: ElementMap.cpp:125
std::size_t size() const
Get element map size.
Definition: ElementMap.h:140
std::string getElementsString() const
Get sorted list of elements in one string (space separated).
Definition: ElementMap.cpp:56
Definition: Atom.h:28
string strpr(const char *format,...)
String version of printf function.
Definition: utility.cpp:90
vector< string > split(string const &input, char delimiter)
Split string at each delimiter.
Definition: utility.cpp:33
string reduce(string const &line, string const &whitespace, string const &fill)
Replace multiple whitespaces with fill.
Definition: utility.cpp:60
Struct to store information on neighbor atoms.
Definition: Atom.h:35
Storage for a single atom.
Definition: Atom.h:32
Vec3D r
Cartesian coordinates.
Definition: Atom.h:118
void clearNeighborList()
Clear neighbor list.
Definition: Atom.cpp:259
std::vector< std::size_t > numNeighborsPerElement
Number of neighbors per element.
Definition: Atom.h:126
void toPhysicalUnits(double meanEnergy, double convEnergy, double convLength)
Switch to physical units, shift energy and change energy and length unit.
Definition: Structure.cpp:505
void calculateVolume()
Calculate volume from box vectors.
Definition: Structure.cpp:436
@ ST_TRAINING
Structure is part of the training set.
Definition: Structure.h:44
@ ST_UNKNOWN
Sample type not assigned yet.
Definition: Structure.h:41
@ ST_TEST
Structure is part of the test set.
Definition: Structure.h:50
Vec3D invbox[3]
Inverse simulation box vectors.
Definition: Structure.h:92
Vec3D box[3]
Simulation box vectors.
Definition: Structure.h:90
bool isTriclinic
If the simulation box is triclinic.
Definition: Structure.h:58
std::size_t getMaxNumNeighbors() const
Find maximum number of neighbors.
Definition: Structure.cpp:362
std::vector< std::size_t > numAtomsPerElement
Number of atoms of each element in this structure.
Definition: Structure.h:94
void writeToFile(std::string const fileName="output.data", bool const ref=true, bool const append=false) const
Write configuration to file.
Definition: Structure.cpp:659
std::string comment
Structure comment.
Definition: Structure.h:88
bool isPeriodic
If periodic boundary conditions apply.
Definition: Structure.h:56
double charge
Charge determined by neural network potential.
Definition: Structure.h:80
ElementMap elementMap
Copy of element map provided as constructor argument.
Definition: Structure.h:54
void setElementMap(ElementMap const &elementMap)
Set element map of structure.
Definition: Structure.cpp:60
std::size_t index
Index number of this structure.
Definition: Structure.h:66
void remap()
Translate all atoms back into box if outside.
Definition: Structure.cpp:443
std::vector< std::string > getChargesLines() const
Get reference and NN charges for all atoms.
Definition: Structure.cpp:647
double chargeRef
Reference charge.
Definition: Structure.h:82
SampleType sampleType
Sample type (training or test set).
Definition: Structure.h:86
void addAtom(Atom const &atom, std::string const &element)
Add a single atom to structure.
Definition: Structure.cpp:69
void calculateInverseBox()
Calculate inverse box.
Definition: Structure.cpp:408
void writeToFilePoscar(std::ofstream *const &file) const
Write configuration to POSCAR file.
Definition: Structure.cpp:778
void writeToFileXyz(std::ofstream *const &file) const
Write configuration to xyz file.
Definition: Structure.cpp:743
bool hasSymmetryFunctionDerivatives
If symmetry function derivatives are saved for each atom.
Definition: Structure.h:64
void calculatePbcCopies(double cutoffRadius)
Calculate required PBC copies.
Definition: Structure.cpp:375
std::string getEnergyLine() const
Get reference and NN energy.
Definition: Structure.cpp:626
void freeAtoms(bool all)
Free symmetry function memory for all atoms, see free() in Atom class.
Definition: Structure.cpp:531
double energy
Potential energy determined by neural network.
Definition: Structure.h:76
void readFromFile(std::string const fileName="input.data")
Read configuration from file.
Definition: Structure.cpp:86
double energyRef
Reference potential energy.
Definition: Structure.h:78
int pbc[3]
Number of PBC images necessary in each direction.
Definition: Structure.h:74
void reset()
Reset everything but elementMap.
Definition: Structure.cpp:543
std::vector< std::string > getForcesLines() const
Get reference and NN forces for all atoms.
Definition: Structure.cpp:634
double volume
Simulation box volume.
Definition: Structure.h:84
void toNormalizedUnits(double meanEnergy, double convEnergy, double convLength)
Normalize structure, shift energy and change energy and length unit.
Definition: Structure.cpp:479
std::size_t numAtoms
Total number of atoms present in this structure.
Definition: Structure.h:68
std::size_t numElements
Global number of elements (all structures).
Definition: Structure.h:70
void updateError(std::string const &property, std::map< std::string, double > &error, std::size_t &count) const
Update property error metrics with this structure.
Definition: Structure.cpp:596
void calculateNeighborList(double cutoffRadius)
Calculate neighbor list for all atoms.
Definition: Structure.cpp:253
std::vector< Atom > atoms
Vector of all atoms in this structure.
Definition: Structure.h:96
std::size_t numElementsPresent
Number of elements present in this structure.
Definition: Structure.h:72
void readFromLines(std::vector< std::string > const &lines)
Read configuration from lines.
Definition: Structure.cpp:131
bool hasNeighborList
If the neighbor list has been calculated.
Definition: Structure.h:60
void clearNeighborList()
Clear neighbor list of all atoms.
Definition: Structure.cpp:580
std::vector< std::string > info() const
Get structure information as a vector of strings.
Definition: Structure.cpp:851
bool hasSymmetryFunctions
If symmetry function values are saved for each atom.
Definition: Structure.h:62
Vector in 3 dimensional real space.
Definition: Vec3D.h:29
double norm2() const
Calculate square of norm of vector.
Definition: Vec3D.h:261
Vec3D & normalize()
Normalize vector, norm equals 1.0 afterwards.
Definition: Vec3D.h:271
Vec3D cross(Vec3D const &v) const
Cross product, argument vector is second in product.
Definition: Vec3D.h:281
double norm() const
Calculate norm of vector.
Definition: Vec3D.h:256