예제 #1
0
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();
}
예제 #2
0
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();
}