//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // UnitCell.C // //////////////////////////////////////////////////////////////////////////////// #include "UnitCell.h" #include #include using namespace std; //////////////////////////////////////////////////////////////////////////////// void UnitCell::set(const D3vector& a0, const D3vector& a1, const D3vector& a2) { a_[0] = a0; a_[1] = a1, a_[2] = a2; amat_[0] = a0.x; amat_[1] = a0.y; amat_[2] = a0.z; amat_[3] = a1.x; amat_[4] = a1.y; amat_[5] = a1.z; amat_[6] = a2.x; amat_[7] = a2.y; amat_[8] = a2.z; // volume = det(A) volume_ = fabs(a0 * ( a1 ^ a2 )); if ( volume_ > 0.0 ) { // Compute rows of A-1 (columns of A^-T) double fac = 1.0 / volume_; D3vector amt0 = fac * a1 ^ a2; D3vector amt1 = fac * a2 ^ a0; D3vector amt2 = fac * a0 ^ a1; amat_inv_[0] = amt0.x; amat_inv_[1] = amt1.x; amat_inv_[2] = amt2.x; amat_inv_[3] = amt0.y; amat_inv_[4] = amt1.y; amat_inv_[5] = amt2.y; amat_inv_[6] = amt0.z; amat_inv_[7] = amt1.z; amat_inv_[8] = amt2.z; amat_inv_t_[0] = amt0.x; amat_inv_t_[1] = amt0.y; amat_inv_t_[2] = amt0.z; amat_inv_t_[3] = amt1.x; amat_inv_t_[4] = amt1.y; amat_inv_t_[5] = amt1.z; amat_inv_t_[6] = amt2.x; amat_inv_t_[7] = amt2.y; amat_inv_t_[8] = amt2.z; // B = 2 pi A^-T b_[0] = 2.0 * M_PI * amt0; b_[1] = 2.0 * M_PI * amt1; b_[2] = 2.0 * M_PI * amt2; bmat_[0] = b_[0].x; bmat_[1] = b_[0].y; bmat_[2] = b_[0].z; bmat_[3] = b_[1].x; bmat_[4] = b_[1].y; bmat_[5] = b_[1].z; bmat_[6] = b_[2].x; bmat_[7] = b_[2].y; bmat_[8] = b_[2].z; } else { b_[0] = b_[1] = b_[2] = D3vector(0.0,0.0,0.0); amat_inv_[0] = amat_inv_[1] = amat_inv_[2] = amat_inv_[3] = amat_inv_[4] = amat_inv_[5] = amat_inv_[6] = amat_inv_[7] = amat_inv_[8] = 0.0; bmat_[0] = bmat_[1] = bmat_[2] = bmat_[3] = bmat_[4] = bmat_[5] = bmat_[6] = bmat_[7] = bmat_[8] = 0.0; } an_[0] = a_[0]; an_[1] = a_[1]; an_[2] = a_[2]; an_[3] = a_[0] + a_[1]; an_[4] = a_[0] - a_[1]; an_[5] = a_[1] + a_[2]; an_[6] = a_[1] - a_[2]; an_[7] = a_[2] + a_[0]; an_[8] = a_[2] - a_[0]; an_[9] = a_[0] + a_[1] + a_[2]; an_[10] = a_[0] - a_[1] - a_[2]; an_[11] = a_[0] + a_[1] - a_[2]; an_[12] = a_[0] - a_[1] + a_[2]; bn_[0] = b_[0]; bn_[1] = b_[1]; bn_[2] = b_[2]; bn_[3] = b_[0] + b_[1]; bn_[4] = b_[0] - b_[1]; bn_[5] = b_[1] + b_[2]; bn_[6] = b_[1] - b_[2]; bn_[7] = b_[2] + b_[0]; bn_[8] = b_[2] - b_[0]; bn_[9] = b_[0] + b_[1] + b_[2]; bn_[10] = b_[0] - b_[1] - b_[2]; bn_[11] = b_[0] + b_[1] - b_[2]; bn_[12] = b_[0] - b_[1] + b_[2]; for ( int i = 0; i < 13; i++ ) { an2h_[i] = 0.5 * norm2(an_[i]); bn2h_[i] = 0.5 * norm2(bn_[i]); } for ( int i = 0; i < 3; i++ ) a_norm_[i] = length(a_[i]); double sp = normalized(a_[1]) * normalized(a_[2]); double c = max(-1.0,min(1.0,sp)); alpha_ = (180.0/M_PI)*acos(c); sp = normalized(a_[0]) * normalized(a_[2]); c = max(-1.0,min(1.0,sp)); beta_ = (180.0/M_PI)*acos(c); sp = normalized(a_[0]) * normalized(a_[1]); c = max(-1.0,min(1.0,sp)); gamma_ = (180.0/M_PI)*acos(c); } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::in_ws(const D3vector& v) const { bool in = true; int i = 0; while ( i < 13 && in ) { in = ( abs(v*an_[i]) <= an2h_[i] ) ; i++; } return in; } //////////////////////////////////////////////////////////////////////////////// void UnitCell::fold_in_ws(D3vector& v) const { const double epsilon = 1.e-10; bool done = false; const int maxiter = 10; int iter = 0; while ( !done && iter < maxiter ) { done = true; for ( int i = 0; (i < 13) && done; i++ ) { const double sp = v*an_[i]; if ( sp > an2h_[i] + epsilon ) { done = false; do v -= an_[i]; while ( v*an_[i] > an2h_[i] + epsilon ); } else if ( sp < -an2h_[i] - epsilon ) { done = false; do v += an_[i]; while ( v*an_[i] < -an2h_[i] - epsilon ); } } iter++; } assert(iter < maxiter); } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::in_bz(const D3vector& k) const { bool in = true; int i = 0; while ( i < 13 && in ) { in = ( abs(k*bn_[i]) <= bn2h_[i] ) ; i++; } return in; } //////////////////////////////////////////////////////////////////////////////// void UnitCell::fold_in_bz(D3vector& k) const { const double epsilon = 1.e-10; bool done = false; const int maxiter = 10; int iter = 0; while ( !done && iter < maxiter ) { done = true; for ( int i = 0; (i < 13) && done; i++ ) { double sp = k*bn_[i]; if ( sp > bn2h_[i] + epsilon ) { done = false; do k -= bn_[i]; while ( k*bn_[i] > bn2h_[i] + epsilon ); } else if ( sp < -bn2h_[i] - epsilon ) { done = false; do k += bn_[i]; while ( k*bn_[i] < -bn2h_[i] - epsilon ); } } iter++; } assert(iter < maxiter); } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::encloses(const UnitCell& c) const { bool in = true; int i = 0; while ( i < 13 && in ) { in = ( contains(c.an_[i]) ); if ( !in ) cout << "UnitCell::encloses: " << c.an_[i] << " not in cell " << c << endl; i++; } return in; } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::contains(D3vector v) const { const double fac = 0.5 / ( 2.0 * M_PI ); const double p0 = fac * v * b_[0]; const double p1 = fac * v * b_[1]; const double p2 = fac * v * b_[2]; return ( (p0 > 0.0) && (p0 <= 1.0) && (p1 > 0.0) && (p1 <= 1.0) && (p2 > 0.0) && (p2 <= 1.0) ); } //////////////////////////////////////////////////////////////////////////////// void UnitCell::print(ostream& os) const { os.setf(ios::fixed,ios::floatfield); os << setprecision(8); os << "" << endl; } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::operator==(const UnitCell& c) const { return ( a_[0]==c.a_[0] && a_[1]==c.a_[1] && a_[2]==c.a_[2] ); } //////////////////////////////////////////////////////////////////////////////// bool UnitCell::operator!=(const UnitCell& c) const { return ! ( *this == c ); } //////////////////////////////////////////////////////////////////////////////// void UnitCell::vecmult3x3(const double* x, const double* y, double *z) const { // | z0 | | x0 x3 x6 | | y0 | // | z1 | = | x1 x4 x7 | * | y1 | // | z2 | | x2 x5 x8 | | y2 | const double z0 = x[0]*y[0]+x[3]*y[1]+x[6]*y[2]; const double z1 = x[1]*y[0]+x[4]*y[1]+x[7]*y[2]; const double z2 = x[2]*y[0]+x[5]*y[1]+x[8]*y[2]; z[0] = z0; z[1] = z1; z[2] = z2; } //////////////////////////////////////////////////////////////////////////////// void UnitCell::vecsmult3x3(const double* xs, const double* y, double *z) const { // multiply a vector by a symmetric 3x3 matrix // | z0 | | xs0 xs3 xs5 | | y0 | // | z1 | = | xs3 xs1 xs4 | * | y1 | // | z2 | | xs5 xs4 xs2 | | y2 | z[0] = xs[0]*y[0]+xs[3]*y[1]+xs[5]*y[2]; z[1] = xs[3]*y[0]+xs[1]*y[1]+xs[4]*y[2]; z[2] = xs[5]*y[0]+xs[4]*y[1]+xs[2]*y[2]; } //////////////////////////////////////////////////////////////////////////////// void UnitCell::matmult3x3(const double* x, const double* y, double *z) const { // | z0 z3 z6 | | x0 x3 x6 | | y0 y3 y6 | // | z1 z4 z7 | = | x1 x4 x7 | * | y1 y4 y7 | // | z2 z5 z8 | | x2 x5 x8 | | y2 y5 y8 | const double z00 = x[0]*y[0]+x[3]*y[1]+x[6]*y[2]; const double z10 = x[1]*y[0]+x[4]*y[1]+x[7]*y[2]; const double z20 = x[2]*y[0]+x[5]*y[1]+x[8]*y[2]; const double z01 = x[0]*y[3]+x[3]*y[4]+x[6]*y[5]; const double z11 = x[1]*y[3]+x[4]*y[4]+x[7]*y[5]; const double z21 = x[2]*y[3]+x[5]*y[4]+x[8]*y[5]; const double z02 = x[0]*y[6]+x[3]*y[7]+x[6]*y[8]; const double z12 = x[1]*y[6]+x[4]*y[7]+x[7]*y[8]; const double z22 = x[2]*y[6]+x[5]*y[7]+x[8]*y[8]; z[0] = z00; z[1] = z10; z[2] = z20; z[3] = z01; z[4] = z11; z[5] = z21; z[6] = z02; z[7] = z12; z[8] = z22; } //////////////////////////////////////////////////////////////////////////////// void UnitCell::smatmult3x3(const double* xs, const double* y, double *z) const { // | z0 z3 z6 | | xs0 xs3 xs5 | | y0 y3 y6 | // | z1 z4 z7 | = | xs3 xs1 xs4 | * | y1 y4 y7 | // | z2 z5 z8 | | xs5 xs4 xs2 | | y2 y5 y8 | const double z00 = xs[0]*y[0]+xs[3]*y[1]+xs[5]*y[2]; const double z10 = xs[3]*y[0]+xs[1]*y[1]+xs[4]*y[2]; const double z20 = xs[5]*y[0]+xs[4]*y[1]+xs[2]*y[2]; const double z01 = xs[0]*y[3]+xs[3]*y[4]+xs[5]*y[5]; const double z11 = xs[3]*y[3]+xs[1]*y[4]+xs[4]*y[5]; const double z21 = xs[5]*y[3]+xs[4]*y[4]+xs[2]*y[5]; const double z02 = xs[0]*y[6]+xs[3]*y[7]+xs[5]*y[8]; const double z12 = xs[3]*y[6]+xs[1]*y[7]+xs[4]*y[8]; const double z22 = xs[5]*y[6]+xs[4]*y[7]+xs[2]*y[8]; z[0] = z00; z[1] = z10; z[2] = z20; z[3] = z01; z[4] = z11; z[5] = z21; z[6] = z02; z[7] = z12; z[8] = z22; } //////////////////////////////////////////////////////////////////////////////// ostream& operator<< ( ostream& os, const UnitCell& cell ) { cell.print(os); return os; }