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(); }
void Interstitial::evaluate(const ISO& iso, const Symmetry& symmetry, int numPointsPerAtom, double tol, double scale) { // Clear space clear(); // Output Output::newline(); Output::print("Searching for interstitial sites using "); Output::print(numPointsPerAtom); Output::print(" starting point"); if (numPointsPerAtom != 1) Output::print("s"); Output::print(" per atom and a scale of "); Output::print(scale); Output::increase(); // Constants used in generating points on sphere around each atom double phiScale = Constants::pi * (3 - sqrt(5)); double yScale = 2.0 / numPointsPerAtom; // Loop over unique atoms in the structure int i, j, k; int count = 0; double y; double r; double phi; double curDistance; double nearDistance; double startDistance; Vector3D curPoint; Linked<Vector3D > points; for (i = 0; i < symmetry.orbits().length(); ++i) { // Get the distance to nearest atom in the structure nearDistance = -1; for (j = 0; j < iso.atoms().length(); ++j) { for (k = 0; k < iso.atoms()[j].length(); ++k) { curDistance = iso.basis().distance(symmetry.orbits()[i].atoms()[0]->fractional(), FRACTIONAL, \ iso.atoms()[j][k].fractional(), FRACTIONAL); if (curDistance > 0) { if ((nearDistance == -1) || (curDistance < nearDistance)) nearDistance = curDistance; } } } // Set the starting distance away from atom startDistance = nearDistance / 2; // Loop over starting points for (j = 0; j < numPointsPerAtom; ++j) { // Check if running current point on current processor if ((++count + Multi::rank()) % Multi::worldSize() == 0) { // Get current starting point y = j * yScale - 1 + (yScale / 2); r = sqrt(1 - y*y); phi = j * phiScale; curPoint.set(symmetry.orbits()[i].atoms()[0]->cartesian()[0] + startDistance*r*cos(phi), \ symmetry.orbits()[i].atoms()[0]->cartesian()[1] + startDistance*y, \ symmetry.orbits()[i].atoms()[0]->cartesian()[2] + startDistance*r*sin(phi)); // Minimize the current point if (!minimizePoint(curPoint, iso, scale)) continue; // Save current point in fractional coordinates points += iso.basis().getFractional(curPoint); ISO::moveIntoCell(*points.last()); } } } // Reduce list of points to unique ones int m; bool found; int numLoops; Vector3D rotPoint; Vector3D equivPoint; Vector3D origin(0.0); Linked<double> distances; Linked<double>::iterator itDist; Linked<Vector3D> uniquePoints; Linked<Vector3D>::iterator it; Linked<Vector3D>::iterator itUnique; for (i = 0; i < Multi::worldSize(); ++i) { // Send number of points in list on current processor numLoops = points.length(); Multi::broadcast(numLoops, i); // Loop over points if (i == Multi::rank()) it = points.begin(); for (j = 0; j < numLoops; ++j) { // Send out current point if (i == Multi::rank()) { curPoint = *it; ++it; } Multi::broadcast(curPoint, i); // Get current distance to origin curDistance = iso.basis().distance(curPoint, 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(curPoint, FRACTIONAL, *itUnique, FRACTIONAL) <= tol) { found = true; break; } } // Loop over symmetry operations for (k = 0; k < symmetry.operations().length(); ++k) { // Loop over translations rotPoint = symmetry.operations()[k].rotation() * curPoint; for (m = 0; m < symmetry.operations()[k].translations().length(); ++m) { // Check if points are the same equivPoint = rotPoint; equivPoint += symmetry.operations()[k].translations()[m]; 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 += curPoint; } } } // 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(); }