Ejemplo n.º 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();
}
Ejemplo n.º 2
0
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;
}