void Interstitial::voronoi(const ISO& iso, const Symmetry& symmetry, double tol) { // Clear space clear(); // Output Output::newline(); Output::print("Searching for interstitial sites using Voronoi method"); Output::increase(); // Set up image iterator ImageIterator images; images.setCell(iso.basis(), 12); // Loop over unique atoms in the structure int i, j, k; List<double> weights; OList<Vector3D> points; OList<Vector3D> vertices; Linked<Vector3D> intPoints; for (i = 0; i < symmetry.orbits().length(); ++i) { // Reset variables weights.length(0); points.length(0); vertices.length(0); // Loop over atoms in the structure for (j = 0; j < iso.atoms().length(); ++j) { for (k = 0; k < iso.atoms()[j].length(); ++k) { // Loop over images images.reset(symmetry.orbits()[i].atoms()[0]->fractional(), iso.atoms()[j][k].fractional()); while (!images.finished()) { // Skip if atoms are the same if (++images < 1e-8) continue; // Save current point points += symmetry.orbits()[i].atoms()[0]->cartesian() + images.cartVector(); weights += 0.5; } } } // Calculate Voronoi volume symmetry.orbits()[i].atoms()[0]->cartesian().voronoi(points, weights, tol, &vertices); // Save points for (j = 0; j < vertices.length(); ++j) { intPoints += iso.basis().getFractional(vertices[j]); ISO::moveIntoCell(*intPoints.last()); } } // Reduce points to unique ones bool found; double curDistance; Vector3D rotPoint; Vector3D equivPoint; Vector3D origin(0.0); Linked<double> distances; Linked<double>::iterator itDist; Linked<Vector3D>::iterator it; Linked<Vector3D> uniquePoints; Linked<Vector3D>::iterator itUnique; for (it = intPoints.begin(); it != intPoints.end(); ++it) { // Get current distance to origin curDistance = iso.basis().distance(*it, FRACTIONAL, origin, FRACTIONAL); // Loop over points that were already saved found = false; itDist = distances.begin(); itUnique = uniquePoints.begin(); for (; itDist != distances.end(); ++itDist, ++itUnique) { // Current points are not the same if (Num<double>::abs(curDistance - *itDist) <= tol) { if (iso.basis().distance(*it, FRACTIONAL, *itUnique, FRACTIONAL) <= tol) { found = true; break; } } // Loop over symmetry operations for (i = 0; i < symmetry.operations().length(); ++i) { // Loop over translations rotPoint = symmetry.operations()[i].rotation() * *it; for (j = 0; j < symmetry.operations()[i].translations().length(); ++j) { // Check if points are the same equivPoint = rotPoint; equivPoint += symmetry.operations()[i].translations()[j]; if (iso.basis().distance(equivPoint, FRACTIONAL, *itUnique, FRACTIONAL) <= tol) { found = true; break; } } if (found) break; } if (found) break; } // Found a new point if (!found) { distances += curDistance; uniquePoints += *it; } } // Save unique points _sites.length(uniquePoints.length()); for (i = 0, it = uniquePoints.begin(); it != uniquePoints.end(); ++i, ++it) _sites[i] = *it; // Output Output::newline(); Output::print("Found "); Output::print(_sites.length()); Output::print(" possible interstitial site"); if (_sites.length() != 1) Output::print("s"); Output::increase(); for (i = 0; i < _sites.length(); ++i) { Output::newline(); Output::print("Site "); Output::print(i+1); Output::print(":"); for (j = 0; j < 3; ++j) { Output::print(" "); Output::print(_sites[i][j], 8); } } Output::decrease(); // Output Output::decrease(); }
Vector3D Interstitial::getStep(const ISO& iso, const Vector3D& point, Vector3D& deriv, Matrix3D& H, double scale) { // Clear data deriv = 0.0; H = 0.0; // Get fractional coordinates of current point Vector3D fracPoint = iso.basis().getFractional(point); ISO::moveIntoCell(fracPoint); // Loop over atoms int i, j, k; double dis; double norm; double denom; double cutoff; double exponent; Vector3D dif; ImageIterator images; for (i = 0; i < iso.atoms().length(); ++i) { // Set cutoff for current element norm = scale * iso.atoms()[i][0].element().radius(); cutoff = -log(1e-8) * norm; // Set image iterator images.setCell(iso.basis(), cutoff); // Loop over atoms of current element for (j = 0; j < iso.atoms()[i].length(); ++j) { // Reset image iterator for current atom images.reset(fracPoint, iso.atoms()[i][j].fractional()); // Loop over images while (!images.finished()) { // Get current value dis = ++images; if (dis < 1e-8) continue; exponent = exp(-dis / norm); // Get derivative vector dif = images.cartVector(); dif *= -1; for (k = 0; k < 3; ++k) deriv[k] += -exponent * dif[k] / (norm * dis); // Get second derivative vector denom = norm * norm * pow(dis, 3); H(0, 0) += exponent * (dif[0]*dif[0]*dis - norm * (dif[1]*dif[1] + dif[2]*dif[2])) / denom; H(1, 1) += exponent * (dif[1]*dif[1]*dis - norm * (dif[0]*dif[0] + dif[2]*dif[2])) / denom; H(2, 2) += exponent * (dif[2]*dif[2]*dis - norm * (dif[0]*dif[0] + dif[1]*dif[1])) / denom; // Add to Hessian H(0, 1) += exponent * dif[0]*dif[1] * (norm + dis) / denom; H(0, 2) += exponent * dif[0]*dif[2] * (norm + dis) / denom; H(1, 2) += exponent * dif[1]*dif[2] * (norm + dis) / denom; } } } // Finish building Hessian H(1, 0) = H(0, 1); H(2, 0) = H(0, 2); H(2, 1) = H(1, 2); // Return Newton step return H.inverse() * deriv; }