35Structure::Structure() :
38 hasNeighborList (false ),
39 NeighborListIsSorted (false ),
40 hasSymmetryFunctions (false ),
41 hasSymmetryFunctionDerivatives(false ),
45 numElementsPresent (0 ),
54 maxCutoffRadiusOverall (0.0 ),
55 sampleType (ST_UNKNOWN),
59 for (
size_t i = 0; i < 3; i++)
86 atoms.back().clearNeighborList();
90 atoms.back().numSymmetryFunctions = 0;
101 file.open(fileName.c_str());
104 throw runtime_error(
"ERROR: Could not open file: \"" + fileName
116 vector<string> lines;
117 vector<string> splitLine;
121 lines.push_back(line);
123 if (splitLine.at(0) !=
"begin")
125 throw runtime_error(
"ERROR: Unexpected file content, expected"
126 " \"begin\" keyword.\n");
129 while (getline(file, line))
131 lines.push_back(line);
133 if (splitLine.at(0) ==
"end")
break;
144 size_t iBoxVector = 0;
145 vector<string> splitLine;
149 if (splitLine.at(0) !=
"begin")
151 throw runtime_error(
"ERROR: Unexpected line content, expected"
152 " \"begin\" keyword.\n");
155 for (vector<string>::const_iterator line = lines.begin();
156 line != lines.end(); ++line)
159 if (splitLine.at(0) ==
"begin")
161 if (splitLine.size() > 1)
163 for (vector<string>::const_iterator word =
164 splitLine.begin() + 1; word != splitLine.end(); ++word)
170 throw runtime_error(
"ERROR: Unknown keyword in "
171 "structure specification, check "
172 "\"begin\" arguments.\n");
177 else if (splitLine.at(0) ==
"comment")
179 size_t position = line->find(
"comment");
180 string tmpLine = *line;
181 comment = tmpLine.erase(position, splitLine.at(0).length() + 1);
183 else if (splitLine.at(0) ==
"lattice")
187 throw runtime_error(
"ERROR: Too many box vectors.\n");
189 box[iBoxVector][0] = atof(splitLine.at(1).c_str());
190 box[iBoxVector][1] = atof(splitLine.at(2).c_str());
191 box[iBoxVector][2] = atof(splitLine.at(3).c_str());
196 if (
box[0][1] > numeric_limits<double>::min() ||
197 box[0][2] > numeric_limits<double>::min() ||
198 box[1][0] > numeric_limits<double>::min() ||
199 box[1][2] > numeric_limits<double>::min() ||
200 box[2][0] > numeric_limits<double>::min() ||
201 box[2][1] > numeric_limits<double>::min())
209 else if (splitLine.at(0) ==
"atom")
215 atoms.back().r[0] = atof(splitLine.at(1).c_str());
216 atoms.back().r[1] = atof(splitLine.at(2).c_str());
217 atoms.back().r[2] = atof(splitLine.at(3).c_str());
219 atoms.back().chargeRef = atof(splitLine.at(5).c_str());
220 atoms.back().fRef[0] = atof(splitLine.at(7).c_str());
221 atoms.back().fRef[1] = atof(splitLine.at(8).c_str());
222 atoms.back().fRef[2] = atof(splitLine.at(9).c_str());
227 else if (splitLine.at(0) ==
"energy")
231 else if (splitLine.at(0) ==
"charge")
235 else if (splitLine.at(0) ==
"end")
237 if (!(iBoxVector == 0 || iBoxVector == 3))
239 throw runtime_error(
"ERROR: Strange number of box vectors.\n");
242 abs(
chargeRef) > 10*std::numeric_limits<double>::epsilon())
244 throw runtime_error(
"ERROR: In structure with index "
246 +
"; if PBCs are applied, the\n"
247 "simulation cell has to be neutrally "
254 throw runtime_error(
"ERROR: Unexpected file content, "
255 "unknown keyword \"" + splitLine.at(0) +
276 double maxCutoffRadius)
299 cutoffRadius *= cutoffRadius;
302 #pragma omp parallel for
304 for (
size_t i = 0; i <
numAtoms; i++)
307 atoms[i].neighborsUnique.push_back(i);
308 atoms[i].numNeighborsUnique++;
309 for (
size_t j = 0; j <
numAtoms; j++)
311 for (
int bc0 = -
pbc[0]; bc0 <=
pbc[0]; bc0++)
313 for (
int bc1 = -
pbc[1]; bc1 <=
pbc[1]; bc1++)
315 for (
int bc2 = -
pbc[2]; bc2 <=
pbc[2]; bc2++)
317 if (!(i == j && bc0 == 0 && bc1 == 0 && bc2 == 0))
323 if (dr.
norm2() <= cutoffRadius)
332 back().element =
atoms[j].element;
334 back().d = dr.
norm();
337 atoms[i].numNeighborsPerElement[
339 atoms[i].numNeighbors++;
342 if (
atoms[i].neighborsUnique.back() != j &&
345 atoms[i].neighborsUnique.push_back(j);
346 atoms[i].numNeighborsUnique++;
354 atoms[i].hasNeighborList =
true;
360 cutoffRadius *= cutoffRadius;
363 #pragma omp parallel for
365 for (
size_t i = 0; i <
numAtoms; i++)
368 atoms[i].neighborsUnique.push_back(i);
369 atoms[i].numNeighborsUnique++;
370 for (
size_t j = 0; j <
numAtoms; j++)
375 if (dr.
norm2() <= cutoffRadius)
378 atoms[i].neighbors.back().index = j;
379 atoms[i].neighbors.back().tag = j;
380 atoms[i].neighbors.back().element =
atoms[j].element;
382 atoms[i].neighbors.back().dr = dr;
383 atoms[i].numNeighborsPerElement[
atoms[j].element]++;
384 atoms[i].numNeighbors++;
385 atoms[i].neighborsUnique.push_back(j);
386 atoms[i].numNeighborsUnique++;
390 atoms[i].hasNeighborList =
true;
403 std::vector<double>>& cutoffs)
412 #pragma omp parallel for
414 for (
size_t i = 0; i <
numAtoms; ++i)
416 sort(
atoms[i].neighbors.begin(),
atoms[i].neighbors.end());
418 atoms[i].NeighborListIsSorted =
true;
424 vector<double>> cutoffs)
427 throw runtime_error(
"NeighborCutoffs map needs a sorted neighbor list");
429 for (
auto& elementCutoffs : cutoffs )
437 if ( !is_sorted(elementCutoffs.begin(), elementCutoffs.end()) )
439 sort(elementCutoffs.begin(), elementCutoffs.end());
444 for(
auto& a :
atoms )
446 size_t const eIndex = a.element;
447 vector<double>
const& elementCutoffs = cutoffs.at(eIndex);
451 while( in < a.numNeighbors && ic < elementCutoffs.size() )
458 if( n.
d > elementCutoffs[ic] )
460 a.neighborCutoffs.emplace( elementCutoffs.at(ic), in );
463 else if ( in == a.numNeighbors - 1 )
465 a.neighborCutoffs.emplace( elementCutoffs.at(ic), a.numNeighbors );
475 size_t maxNumNeighbors = 0;
477 for(vector<Atom>::const_iterator it =
atoms.begin();
478 it !=
atoms.end(); ++it)
480 maxNumNeighbors = max(maxNumNeighbors, it->numNeighbors);
483 return maxNumNeighbors;
496 double proja = fabs(
box[0] * bxc);
497 double projb = fabs(
box[1] * axc);
498 double projc = fabs(
box[2] * axb);
503 while (
pbc[0] * proja <= cutoffRadius)
507 while (
pbc[1] * projb <= cutoffRadius)
511 while (
pbc[2] * projc <= cutoffRadius)
521 double invdet =
box[0][0] *
box[1][1] *
box[2][2]
527 invdet = 1.0 / invdet;
559 proj[0] = fabs(
box[0] * bxc);
560 proj[1] = fabs(
box[1] * axc);
561 proj[2] = fabs(
box[2] * axb);
563 double minProj = *min_element(proj, proj+3);
564 return (cutoffRadius < minProj / 2.0);
572 for (
size_t i=0; i<3; ++i)
574 dsNINT[i] = round(ds[i]);
592 VectorXd sigmaSqrtPi,
594 double const fourPiEps,
616 throw runtime_error(
"ERROR: Neighbor list needs to "
617 "be sorted for Ewald summation!\n");
627 double const rcutReal = ewaldSetup.
params.
rCut;
628 double const sqrt2eta = sqrt(2.0) * ewaldSetup.
params.
eta;
631 #pragma omp for schedule(dynamic)
633 for (
size_t i = 0; i <
numAtoms; ++i)
639 A(i, i) += hardness(ei)
640 + (1.0 / sigmaSqrtPi(ei) - 2 / (sqrt2eta * sqrt(M_PI)))
643 hardnessJ(i) = hardness(ei);
648 for (
size_t k = 0; k < numNeighbors; ++k)
654 double const rij = n.d;
655 size_t const ej = n.element;
657 double erfcSqrt2Eta = erfcBuf.
getf(i, k, 0, rij / sqrt2eta);
658 double erfcGammaSqrt2 =
659 erfcBuf.
getf(i, k, 1, rij / gammaSqrt2(ei, ej));
661 A(i, j) += (erfcSqrt2Eta - erfcGammaSqrt2) / (rij * fourPiEps);
666 for (
size_t j = i; j <
numAtoms; ++j)
674 A(i, j) += 2 * gv.coeff * cos(gv.k * dr) / fourPiEps;
684#pragma omp for schedule(dynamic)
686 for (
size_t i = 0; i <
numAtoms; ++i)
691 A(i, i) = hardness(ei)
692 + 1.0 / (sigmaSqrtPi(ei) * fourPiEps);
693 hardnessJ(i) = hardness(ei);
695 for (
size_t j = i + 1; j <
numAtoms; ++j)
699 double const rij = (ai.
r - aj.
r).norm();
701 A(i, j) = erf(rij / gammaSqrt2(ei, ej)) / (rij * fourPiEps);
721 Q =
A.colPivHouseholderQr().solve(b);
723 #pragma omp for nowait
725 for (
size_t i = 0; i <
numAtoms; ++i)
727 atoms.at(i).charge = Q(i);
735 double error = (
A * Q - b).norm() / b.norm();
740 MatrixXd(hardnessJ.asDiagonal())) * Q.head(
numAtoms);
748 VectorXd sigmaSqrtPi,
750 double const fourPiEps)
753 double energyScreen = 0;
754 double const rcutScreen = fs.
getOuter();
759 double localEnergyScreen = 0;
764 #pragma omp for schedule(dynamic)
766 for (
size_t i = 0; i <
numAtoms; ++i)
770 double const Qi = ai.
charge;
772 localEnergyScreen += -Qi * Qi
773 / (2 * sigmaSqrtPi(ei) * fourPiEps);
775 energyScreen += -Qi * Qi
776 / (2 * sigmaSqrtPi(ei) * fourPiEps);
780 for (
size_t k = 0; k < numNeighbors; ++k)
783 size_t const j = n.tag;
785 double const rij = n.d;
786 size_t const ej = n.element;
788 double const Qj =
atoms.at(j).charge;
790 localEnergyScreen += Qi * Qj * erf(rij / gammaSqrt2(ei, ej))
791 * (fs.
f(rij) - 1) / (rij * fourPiEps);
793 energyScreen += Qi * Qj * erf(rij / gammaSqrt2(ei, ej))
794 * (fs.
f(rij) - 1) / (rij * fourPiEps);
803 #pragma omp for schedule(dynamic)
805 for (
size_t i = 0; i <
numAtoms; ++i)
809 double const Qi = ai.
charge;
811 localEnergyScreen += -Qi * Qi
812 / (2 * sigmaSqrtPi(ei) * fourPiEps);
814 energyScreen += -Qi * Qi
815 / (2 * sigmaSqrtPi(ei) * fourPiEps);
818 for (
size_t j = i + 1; j <
numAtoms; ++j)
821 double const Qj = aj.
charge;
822 double const rij = (ai.
r - aj.
r).norm();
823 if ( rij < rcutScreen )
826 localEnergyScreen += Qi * Qj *
A(i, j) * (fs.
f(rij) - 1);
828 energyScreen += Qi * Qj *
A(i, j) * (fs.
f(rij) - 1);
836 energyScreen += localEnergyScreen;
847 double const fourPiEps,
856 #pragma omp declare reduction(vec_Vec3D_plus : std::vector<Vec3D> : \
857 std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<Vec3D>())) \
858 initializer(omp_priv = decltype(omp_orig)(omp_orig.size()))
863 for (
size_t i = 0; i <
numAtoms; ++i)
880 double const sqrt2eta = sqrt(2.0) * ewaldSetup.
params.
eta;
885 #pragma omp for reduction(vec_Vec3D_plus : dAdrQDiag) schedule(dynamic)
887 for (
size_t i = 0; i <
numAtoms; ++i)
891 double const Qi = ai.
charge;
895 for (
size_t k = 0; k < numNeighbors; ++k)
900 if (j <= i)
continue;
902 double const rij = n.d;
905 double const Qj = aj.
charge;
907 double erfcSqrt2Eta = erfcBuf.
getf(i, k, 0, rij / sqrt2eta);
908 double erfcGammaSqrt2 =
909 erfcBuf.
getf(i, k, 1, rij / gammaSqrt2(ei, ej));
912 dAijdri = n.dr / pow(rij, 2)
913 * (2 / sqrt(M_PI) * (-exp(-pow(rij / sqrt2eta, 2))
914 / sqrt2eta + exp(-pow(rij / gammaSqrt2(ei, ej), 2))
915 / gammaSqrt2(ei, ej)) - 1 / rij
916 * (erfcSqrt2Eta - erfcGammaSqrt2));
917 dAijdri /= fourPiEps;
920 ai.
dAdrQ[i] += dAijdri * Qj;
921 ai.
dAdrQ[j] += dAijdri * Qi;
922 aj.
dAdrQ[i] -= dAijdri * Qj;
924 dAdrQDiag[j] -= dAijdri * Qi;
926 aj.
dAdrQ[j] -= dAijdri * Qi;
931 for (
size_t j = i + 1; j <
numAtoms; ++j)
934 double const Qj = aj.
charge;
941 dAijdri -= 2 * gv.coeff * sin(gv.k * dr) * gv.k;
943 dAijdri /= fourPiEps;
945 ai.
dAdrQ[i] += dAijdri * Qj;
946 ai.
dAdrQ[j] += dAijdri * Qi;
947 aj.
dAdrQ[i] -= dAijdri * Qj;
949 dAdrQDiag[j] -= dAijdri * Qi;
951 aj.
dAdrQ[j] -= dAijdri * Qi;
959 #pragma omp for reduction(vec_Vec3D_plus : dAdrQDiag) schedule(dynamic)
961 for (
size_t i = 0; i <
numAtoms; ++i)
965 double const Qi = ai.
charge;
967 for (
size_t j = i + 1; j <
numAtoms; ++j)
971 double const Qj = aj.
charge;
973 double rij = (ai.
r - aj.
r).norm();
975 dAijdri = (ai.
r - aj.
r) / pow(rij, 2)
976 * (2 / (sqrt(M_PI) * gammaSqrt2(ei, ej))
977 * exp(-pow(rij / gammaSqrt2(ei, ej), 2))
978 - erf(rij / gammaSqrt2(ei, ej)) / rij);
979 dAijdri /= fourPiEps;
982 ai.
dAdrQ[i] += dAijdri * Qj;
983 ai.
dAdrQ[j] = dAijdri * Qi;
984 aj.
dAdrQ[i] = -dAijdri * Qj;
986 dAdrQDiag[j] -= dAijdri * Qi;
988 aj.
dAdrQ[j] -= dAijdri * Qi;
995 for (
size_t i = 0; i <
numAtoms; ++i)
998 ai.
dAdrQ[i] += dAdrQDiag[i];
1009 for (
size_t i = 0; i <
numAtoms; ++i)
1015 dQdChi.push_back(
A.colPivHouseholderQr().solve(b).head(
numAtoms));
1029 for (
size_t j = 0; j <
numAtoms; ++j)
1034 dQdJ.push_back(
A.colPivHouseholderQr().solve(b).head(
numAtoms));
1040 vector<size_t>
const& compIndices,
1041 double const maxCutoffRadius,
1042 vector<Element>
const& elements)
1044 if (atomIndices.size() != compIndices.size())
1045 throw runtime_error(
"ERROR: In calculation of dQ/dr both atom index and"
1046 " component index must be specified.");
1047 for (
size_t i = 0; i < atomIndices.size(); ++i)
1050 if ( a.
dAdrQ.size() == 0 )
1051 throw runtime_error(
"ERROR: dAdrQ needs to be calculated before "
1052 "calculating dQdr");
1058 for (
size_t j = 0; j <
numAtoms; ++j)
1062#ifndef N2P2_FULL_SFD_MEMORY
1063 vector<vector<size_t> >
const *
const tableFull
1064 = &(elements.at(aj.
element).getSymmetryFunctionTable());
1066 vector<vector<size_t> >
const *
const tableFull =
nullptr;
1070 tableFull)[compIndices[i]];
1071 b(j) -= a.
dAdrQ.at(j)[compIndices[i]];
1073 VectorXd dQdr =
A.colPivHouseholderQr().solve(b).head(
numAtoms);
1074 for (
size_t j = 0; j <
numAtoms; ++j)
1076 a.
dQdr.at(j)[compIndices[i]] = dQdr(j);
1084 Eigen::VectorXd hardness,
1085 Eigen::MatrixXd gammaSqrt2,
1086 VectorXd sigmaSqrtPi,
1088 double const fourPiEps)
1093 ai.pEelecpr =
Vec3D{};
1098 for (
size_t i = 0; i <
numAtoms; ++i)
1102 double const Qi = ai.
charge;
1106 for (
size_t j = 0; j <
numAtoms; ++j)
1109 double const Qj = aj.
charge;
1117 ai.
dEelecdQ += Qi * (
A(i,i) - hardness(ei)
1118 - 1 / (sigmaSqrtPi(ei) * fourPiEps));
1128 if (j < i)
continue;
1129 double const rij = ajN.d;
1130 if (rij >= rcutScreen)
break;
1133 double const Qj =
atoms.at(j).charge;
1135 double erfRij = erf(rij / gammaSqrt2(ei,ej));
1136 double fsRij = fs.
f(rij);
1139 Vec3D Tij = Qi * Qj * ajN.dr / pow(rij,2)
1140 * (2 / (sqrt(M_PI) * gammaSqrt2(ei,ej))
1141 * exp(- pow(rij / gammaSqrt2(ei,ej),2))
1142 * (fsRij - 1) + erfRij * fs.
df(rij) - erfRij
1143 * (fsRij - 1) / rij);
1148 double Sij = erfRij * (fsRij - 1) / rij;
1156 for (
size_t j = i + 1; j <
numAtoms; ++j)
1159 double const rij = (ai.
r - aj.
r).norm();
1160 if (rij >= rcutScreen)
continue;
1163 double const Qj =
atoms.at(j).charge;
1165 double erfRij = erf(rij / gammaSqrt2(ei,ej));
1166 double fsRij = fs.
f(rij);
1169 Vec3D Tij = Qi * Qj * (ai.
r - aj.
r) / pow(rij,2)
1170 * (2 / (sqrt(M_PI) * gammaSqrt2(ei,ej))
1171 * exp(- pow(rij / gammaSqrt2(ei,ej),2))
1172 * (fsRij - 1) + erfRij * fs.
df(rij) - erfRij
1173 * (fsRij - 1) / rij);
1178 double Sij = erfRij * (fsRij - 1) / rij;
1191 for (
size_t i = 0; i <
numAtoms; ++i)
1197 VectorXd
const lambdaTotal =
A.colPivHouseholderQr().solve(-dEdQ);
1204 for (
size_t i = 0; i <
numAtoms; ++i)
1210 VectorXd
const lambdaElec =
A.colPivHouseholderQr().solve(-dEelecdQ);
1216 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
1230 if (f[0] > 1.0) f[0] -= (int)f[0];
1231 if (f[1] > 1.0) f[1] -= (int)f[1];
1232 if (f[2] > 1.0) f[2] -= (int)f[2];
1234 if (f[0] < 0.0) f[0] += 1.0 - (int)f[0];
1235 if (f[1] < 0.0) f[1] += 1.0 - (int)f[1];
1236 if (f[2] < 0.0) f[2] += 1.0 - (int)f[2];
1238 if (f[0] == 1.0) f[0] = 0.0;
1239 if (f[1] == 1.0) f[1] = 0.0;
1240 if (f[2] == 1.0) f[2] = 0.0;
1242 atom.
r = f[0] *
box[0]
1256 box[0] *= convLength;
1257 box[1] *= convLength;
1258 box[2] *= convLength;
1268 volume *= convLength * convLength * convLength;
1270 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
1272 it->toNormalizedUnits(convEnergy, convLength, convCharge);
1285 box[0] /= convLength;
1286 box[1] /= convLength;
1287 box[2] /= convLength;
1297 volume /= convLength * convLength * convLength;
1299 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
1301 it->toPhysicalUnits(convEnergy, convLength, convCharge);
1309 for (vector<Atom>::iterator it =
atoms.begin(); it !=
atoms.end(); ++it)
1311 it->free(all, maxCutoffRadius);
1337 for (
size_t i = 0; i < 3; ++i)
1340 for (
size_t j = 0; j < 3; ++j)
1358 for (
size_t i = 0; i <
numAtoms; i++)
1376 for (
auto& a :
atoms)
1378 vector<Vec3D>().swap(a.dAdrQ);
1381 vector<Vec3D>().swap(a.dQdr);
1387 map<string, double>& error,
1388 size_t& count)
const
1390 if (property ==
"energy")
1395 error.at(
"RMSE") += diff * diff;
1397 error.at(
"MAEpa") += diff /
numAtoms;
1398 error.at(
"MAE") += diff;
1400 else if (property ==
"force" || property ==
"charge")
1402 for (vector<Atom>::const_iterator it =
atoms.begin();
1403 it !=
atoms.end(); ++it)
1405 it->updateError(property, error, count);
1410 throw runtime_error(
"ERROR: Unknown property for error update.\n");
1418 return strpr(
"%10zu %16.8E %16.8E\n",
1427 for (vector<Atom>::const_iterator it =
atoms.begin();
1428 it !=
atoms.end(); ++it)
1430 vector<string> va = it->getForcesLines();
1431 v.insert(v.end(), va.begin(), va.end());
1440 for (vector<Atom>::const_iterator it =
atoms.begin();
1441 it !=
atoms.end(); ++it)
1443 v.push_back(it->getChargeLine());
1451 bool const append)
const
1457 file.open(fileName.c_str(), ofstream::app);
1461 file.open(fileName.c_str());
1463 if (!file.is_open())
1465 throw runtime_error(
"ERROR: Could not open file: \"" + fileName
1476 if (!file->is_open())
1478 runtime_error(
"ERROR: Cannot write to file, file is not open.\n");
1481 (*file) <<
"begin\n";
1485 for (
size_t i = 0; i < 3; ++i)
1487 (*file) <<
strpr(
"lattice %24.16E %24.16E %24.16E\n",
1491 for (vector<Atom>::const_iterator it =
atoms.begin();
1492 it !=
atoms.end(); ++it)
1496 (*file) <<
strpr(
"atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
1497 " %24.16E %24.16E %24.16E\n",
1510 (*file) <<
strpr(
"atom %24.16E %24.16E %24.16E %2s %24.16E %24.16E"
1511 " %24.16E %24.16E %24.16E\n",
1525 else (*file) <<
strpr(
"energy %24.16E\n",
energy);
1527 else (*file) <<
strpr(
"charge %24.16E\n",
charge);
1528 (*file) <<
strpr(
"end\n");
1535 if (!file->is_open())
1537 runtime_error(
"ERROR: Could not write to file.\n");
1543 (*file) <<
"Lattice=\"";
1544 (*file) <<
strpr(
"%24.16E %24.16E %24.16E " ,
1546 (*file) <<
strpr(
"%24.16E %24.16E %24.16E " ,
1548 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\"\n",
1555 for (vector<Atom>::const_iterator it =
atoms.begin();
1556 it !=
atoms.end(); ++it)
1558 (*file) <<
strpr(
"%-2s %24.16E %24.16E %24.16E\n",
1576 string const elements)
const
1578 if (!file->is_open())
1580 runtime_error(
"ERROR: Could not write to file.\n");
1583 vector<string> ve =
split(elements);
1584 vector<size_t> elementOrder;
1585 for (
size_t i = 0; i < ve.size(); ++i)
1587 elementOrder.push_back(
elementMap[ve.at(i)]);
1591 runtime_error(
"ERROR: Inconsistent element declaration.\n");
1596 for (
size_t i = 1; i < elementOrder.size(); ++i)
1604 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
1606 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
1608 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
1613 runtime_error(
"ERROR: Writing non-periodic structure to POSCAR file "
1614 "is not implemented.\n");
1622 (*file) <<
"Cartesian\n";
1623 for (
size_t i = 0; i < elementOrder.size(); ++i)
1625 for (vector<Atom>::const_iterator it =
atoms.begin();
1626 it !=
atoms.end(); ++it)
1628 if (it->element == elementOrder.at(i))
1630 (*file) <<
strpr(
"%24.16E %24.16E %24.16E\n",
1645 v.push_back(
strpr(
"********************************\n"));
1646 v.push_back(
strpr(
"STRUCTURE \n"));
1647 v.push_back(
strpr(
"********************************\n"));
1649 v.insert(v.end(), vm.begin(), vm.end());
1666 v.push_back(
strpr(
"comment : %s\n",
comment.c_str() ));
1667 v.push_back(
strpr(
"box[0] : %16.8E %16.8E %16.8E\n",
box[0][0],
box[0][1],
box[0][2]));
1668 v.push_back(
strpr(
"box[1] : %16.8E %16.8E %16.8E\n",
box[1][0],
box[1][1],
box[1][2]));
1669 v.push_back(
strpr(
"box[2] : %16.8E %16.8E %16.8E\n",
box[2][0],
box[2][1],
box[2][2]));
1673 v.push_back(
strpr(
"--------------------------------\n"));
1675 v.push_back(
strpr(
"--------------------------------\n"));
1680 v.push_back(
strpr(
"--------------------------------\n"));
1681 v.push_back(
strpr(
"--------------------------------\n"));
1682 v.push_back(
strpr(
"atoms [*] : %d\n",
atoms.size()));
1683 v.push_back(
strpr(
"--------------------------------\n"));
1684 for (
size_t i = 0; i <
atoms.size(); ++i)
1686 v.push_back(
strpr(
"%29d :\n", i));
1687 vector<string> va =
atoms[i].info();
1688 v.insert(v.end(), va.begin(), va.end());
1690 v.push_back(
strpr(
"--------------------------------\n"));
1691 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).
Setup data for Ewald summation.
void calculateParameters(double const newVolume, size_t const newNumAtoms)
Compute eta, rCut and kCut.
std::vector< Kvector > kvectors
Vector containing all k-vectors.
void setup(Vec3D box[3], EwaldSetup &ewaldSetup)
Set up reciprocal box vectors and eta.
A screening functions for use with electrostatics.
double getOuter() const
Getter for outer.
double df(double r) const
Derivative of screening function .
double f(double r) const
Screening function .
string strpr(const char *format,...)
String version of printf function.
bool vectorContains(std::vector< T > const &stdVec, T value)
Test if vector contains specified value.
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.
double d
Distance to neighbor atom.
Storage for a single atom.
std::vector< Neighbor > neighbors
Neighbor array (maximum number defined in macros.h.
Vec3D r
Cartesian coordinates.
std::vector< double > dEdG
Derivative of atomic energy with respect to symmetry functions.
Vec3D calculateDChidr(size_t const atomIndexOfR, double const maxCutoffRadius, std::vector< std::vector< size_t > > const *const tableFull=nullptr) const
Calculate dChi/dr of this atom's Chi with respect to the coordinates of the given atom.
double charge
Atomic charge determined by neural network.
std::size_t getStoredMinNumNeighbors(double const cutoffRadius) const
Return needed number of neighbors for a given cutoff radius from neighborCutoffs map.
double chi
Atomic electronegativity determined by neural network.
void clearNeighborList()
Clear neighbor list.
Vec3D pEelecpr
Partial derivative of electrostatic energy with respect to this atom's coordinates.
std::vector< Vec3D > dAdrQ
If dQdr has been calculated for respective components.
std::size_t element
Element index of this atom.
std::vector< Vec3D > dQdr
Derivative of charges with respect to this atom's coordinates.
double dEelecdQ
Derivative of electrostatic energy with respect to this atom's charge.
std::vector< std::size_t > numNeighborsPerElement
Number of neighbors per element.
Helper class to store previously calculated values of erfc() that are needed during the charge equili...
double getf(size_t const atomIndex, size_t const neighIndex, size_t const valIndex, double const x)
Either returns already stored value erfc(x) or calculates it if not yet stored.
void reset(std::vector< Atom > const &atoms, size_t const valuesPerPair)
Resizes and resets the storage array to fit the current structure.
double rCut
Cutoff in real space.
double eta
Width of the gaussian screening charges.
void freeAtoms(bool all, double const maxCutoffRadius=0.0)
Free symmetry function memory for all atoms, see free() in Atom class.
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.
void toPhysicalUnits(double meanEnergy, double convEnergy, double convLength, double convCharge)
Switch to physical units, shift energy and change energy, length and charge unit.
Vec3D box[3]
Simulation box vectors.
bool isTriclinic
If the simulation box is triclinic.
std::size_t getMaxNumNeighbors() const
Find maximum number of neighbors.
void setupNeighborCutoffMap(std::vector< std::vector< double > > cutoffs)
Set up a neighbor cut-off map which gives the index (value) of the last needed neighbor corresponding...
void sortNeighborList()
Sort all neighbor lists of this structure with respect to the distance.
Eigen::VectorXd const calculateForceLambdaElec() const
Calculate lambda_elec vector which is needed for the electrostatic force calculation in 4G NN.
std::vector< std::size_t > numAtomsPerElement
Number of atoms of each element in this structure.
double lambda
Lagrange multiplier used for charge equilibration.
void calculateMaxCutoffRadiusOverall(EwaldSetup &ewaldSetup, double rcutScreen, double maxCutoffRadius)
Calculate maximal cut-off if cut-off of screening and real part Ewald summation are also considered.
bool canMinimumImageConventionBeApplied(double cutoffRadius)
Check if cut-off radius is small enough to apply minimum image convention.
void writeToFile(std::string const fileName="output.data", bool const ref=true, bool const append=false) const
Write configuration to file.
void calculateDQdChi(std::vector< Eigen::VectorXd > &dQdChi)
Calculates derivative of the charges with respect to electronegativities.
std::string comment
Structure comment.
bool isPeriodic
If periodic boundary conditions apply.
double maxCutoffRadiusOverall
Maximum cut-off radius with respect to symmetry functions, screening function and Ewald summation.
double charge
Charge determined by neural network potential.
double calculateElectrostaticEnergy(EwaldSetup &ewaldSetup, Eigen::VectorXd hardness, Eigen::MatrixXd gammaSqrt2, Eigen::VectorXd sigmaSqrtPi, ScreeningFunction const &fs, double const fourPiEps, ErfcBuf &erfcBuf)
Compute electrostatic energy with global charge equilibration.
bool NeighborListIsSorted
If the neighbor list has been sorted by distance.
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 calculateDQdJ(std::vector< Eigen::VectorXd > &dQdJ)
Calculates derivative of the charges with respect to atomic hardness.
bool hasAMatrix
If A matrix of this structure is currently stored.
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 calculateDQdr(std::vector< size_t > const &atomsIndices, std::vector< size_t > const &compIndices, double const maxCutoffRadius, std::vector< Element > const &elements)
Calculates derivative of the charges with respect to the atom's position.
Eigen::MatrixXd A
Global charge equilibration matrix A'.
void calculatePbcCopies(double cutoffRadius, int(&pbc)[3])
Calculate required PBC copies.
Eigen::VectorXd const calculateForceLambdaTotal() const
Calculate lambda_total vector which is needed for the total force calculation in 4G NN.
std::string getEnergyLine() const
Get reference and NN energy.
void clearElectrostatics(bool clearDQdr=false)
Clear A-matrix, dAdrQ and optionally dQdr.
double energyElec
Electrostatics part of the potential energy predicted by NNP.
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 for max cut-off.
void toNormalizedUnits(double meanEnergy, double convEnergy, double convLength, double convCharge)
Normalize structure, shift energy and change energy, length and charge unit.
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 calculateElectrostaticEnergyDerivatives(Eigen::VectorXd hardness, Eigen::MatrixXd gammaSqrt2, Eigen::VectorXd sigmaSqrtPi, ScreeningFunction const &fs, double const fourPiEps)
Calculates partial derivatives of electrostatic Energy with respect to atom's coordinates and charges...
Vec3D applyMinimumImageConvention(Vec3D const &dr)
Calculate distance between two atoms in the minimum image convention.
void calculateNeighborList(double cutoffRadius, bool sortByDistance=false)
Calculate neighbor list for all atoms.
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 calculateDAdrQ(EwaldSetup &ewaldSetup, Eigen::MatrixXd gammaSqrt2, double const fourPiEps, ErfcBuf &erfcBuf)
Calculates derivative of A-matrix with respect to the atoms positions and contract it with Q.
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.
double calculateScreeningEnergy(Eigen::MatrixXd gammaSqrt2, Eigen::VectorXd sigmaSqrtPi, ScreeningFunction const &fs, double const fourPiEps)
Calculate screening energy which needs to be added (!) to the electrostatic energy in order to remove...
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 hasCharges
If all charges of this structure have been calculated (and stay the same, e.g.
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.