159 const bool& useRLLL)
try :
160 RationalMatrix<dim>(A_in.reciprocalBasis.transpose()*B_in.latticeBasis)
164 ,M(getM(*this,*this))
165 ,N(getN(*this,*this))
166 ,sigmaA(round(M.template cast<double>().determinant()))
167 ,sigmaB(round(N.template cast<double>().determinant()))
168 ,sigma(std::abs(sigmaA)==std::abs(sigmaB)? std::abs(sigmaA) : 0)
169 , csl(getCSLBasis (A,B,*this,M,N,useRLLL),
MatrixDimD::Identity())
170 ,dscl(getDSCLBasis(A,B,*this,M,N,useRLLL),
MatrixDimD::Identity())
171 ,Ap(A.latticeBasis*this->matrixX().template cast<double>())
172 ,Bp(B.latticeBasis*this->matrixV().template cast<double>())
173 ,LambdaA(getLambdaA(M,N))
174 ,LambdaB(getLambdaB(M,N))
180 const MatrixDimD tempA(
A.reciprocalBasis.transpose()*
csl.latticeBasis);
181 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
184 throw std::runtime_error(
"CSL is not a multiple of lattice A.\n");
187 const MatrixDimD tempB(
B.reciprocalBasis.transpose()*
csl.latticeBasis);
188 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
191 throw std::runtime_error(
"CSL is not a multiple of lattice B\n");
198 const MatrixDimD tempA(
dscl.reciprocalBasis.transpose()*
A.latticeBasis);
199 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
202 throw std::runtime_error(
"Lattice A is not a multiple of the DSCL\n");
205 const MatrixDimD tempB(
dscl.reciprocalBasis.transpose()*
B.latticeBasis);
206 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
209 throw std::runtime_error(
"Lattice B is not a multiple of the DSCL\n");
217 throw std::runtime_error(
"LambdaA + LambdaB != I\n");
223 catch(std::runtime_error& e)
225 std::cout << e.what() << std::endl;
226 throw(std::runtime_error(
"Bicrystal construction failed. "));
501 const double& orthogonality,
502 const int& dsclFactor,
503 std::string filename,
506 assert(orthogonality>=0.0 && orthogonality<=1.0 &&
507 "The \"orthogonality\" parameter should be between 0.0 and 1.0");
508 assert(dsclFactor>=1 &&
509 "The \"dsclFactor\" should be greater than 1.");
510 assert(boxVectors.size()==dim);
511 for(
const auto& boxVector : boxVectors)
513 assert(&csl == &boxVector.lattice &&
514 "Box vectors do not belong to the CSL.");
519 for (
int i=0; i<dim; ++i) {
520 C.col(i) = boxVectors[i].cartesian();
522 assert(abs(C.determinant()) > FLT_EPSILON &&
"Box volume is equal to zero.");
526 auto boxVectorTemp= boxVectors[0];
529 nC= boxVectors[1].
cross();
531 nC= boxVectors[1].
cross(boxVectors[2]);
532 auto basis= csl.planeParallelLatticeBasis(nC,
true);
536 boxLatticeIndices.col(0)= boxVectors[0];
537 for (
int i=1; i<dim; ++i)
539 double minDotProduct= M_PI/2;
542 auto boxVectorUpdated(boxVectors[0]);
544 for(
int i=0;i<planesToExplore;++i)
546 int sign= boxVectors[0].cartesian().dot(basis[0].cartesian())>0? 1 : -1;
547 boxVectorTemp= boxVectors[0]+i*sign*basis[0].latticeVector();
548 boxLatticeIndices.col(0)= boxVectorTemp;
549 Lattice<dim> boxLattice(csl.latticeBasis*boxLatticeIndices.template cast<double>());
555 double dotProduct= abs(acos(boxVectorTemp.cartesian().normalized().dot(rC.
cartesian().normalized())-FLT_EPSILON));
556 if(dotProduct<minDotProduct) {
557 minDotProduct = dotProduct;
558 boxVectorUpdated= boxVectorTemp;
559 if (dotProduct < (1-orthogonality)*M_PI/2)
564 boxVectors[0]=boxVectorUpdated;
565 C.col(0)= boxVectors[0].cartesian();
569 MatrixDimD rotation= Eigen::Matrix<double,dim,dim>::Identity();;
570 Eigen::Matrix<double,dim,dim-1> orthogonalVectors;
573 orthogonalVectors.col(0) = C.col(1).normalized();
574 orthogonalVectors.col(1) = C.col(2).normalized();
577 orthogonalVectors.col(0)= C.col(1).normalized();
579 rotation=Rotation<dim>(orthogonalVectors);
583 assert((rotation*rotation.transpose()).isApprox(Eigen::Matrix<double,dim,dim>::Identity(),1e-6)
584 &&
"Cannot orient the grain boundary. Box vectors are not orthogonal.");
587 std::vector<LatticeVector<dim>> configurationA, configurationB, configurationC, configurationD;
588 std::vector<LatticeVector<dim>> configuration;
590 std::vector<LatticeVector<dim>> boxVectorsInA, boxVectorsInB, boxVectorsInD;
592 for(
const auto& boxVector : boxVectors) {
593 boxVectorsInA.push_back(getLatticeVectorInA(boxVector));
594 boxVectorsInB.push_back(getLatticeVectorInB(boxVector));
595 boxVectorsInD.push_back(getLatticeVectorInD(boxVector));
599 auto dsclVector=getLatticeDirectionInD(boxVectors[0]).latticeVector();
601 if(abs((dsclFactor*dsclVector).dot(nD)) < abs(boxVectorsInD[0].dot(nD)))
602 boxVectorsInD[0]= dsclFactor*dsclVector;
604 std::vector<LatticeVector<dim>> boxVectorsForA(boxVectorsInA),
605 boxVectorsForB(boxVectorsInB),
606 boxVectorsForC(boxVectors),
607 boxVectorsForD(boxVectorsInD);
608 boxVectorsForA[0]=2*boxVectorsInA[0];
609 boxVectorsForB[0]=2*boxVectorsInB[0];
610 boxVectorsForC[0]=2*boxVectors[0];
611 boxVectorsForD[0]=2*boxVectorsInD[0];
613 configurationA= A.box(boxVectorsForA);
614 configurationB= B.box(boxVectorsForB);
615 configurationC= csl.box(boxVectorsForC);
616 configurationD= dscl.box(boxVectorsForD);
619 for(
auto& vector : configurationA)
621 for(
auto& vector : configurationB)
623 for(
auto& vector : configurationC)
624 vector= vector + origin;
625 for(
auto& vector : configurationD)
628 configuration= configurationA;
629 configuration.insert(configuration.end(),configurationB.begin(),configurationB.end());
630 configuration.insert(configuration.end(),configurationC.begin(),configurationC.end());
631 configuration.insert(configuration.end(),configurationD.begin(),configurationD.end());
633 if(!filename.empty()) {
636 if (!file) std::cerr <<
"Unable to open file";
637 file << configuration.size() << std::endl;
638 file <<
"Lattice=\"";
641 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" 0 ";
642 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" 0 ";
644 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\"";
645 file << (rotation*origin.
cartesian()).transpose() <<
" 0.0\"" << std::endl;
646 for (
const auto &vector: configurationA)
647 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
648 for (
const auto &vector: configurationB)
649 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
650 for (
const auto &vector: configurationC)
651 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.2 << std::endl;
652 for (
const auto &vector: configurationD)
653 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.01 << std::endl;
656 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" ";
657 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" ";
658 file << (rotation*boxVectorsForC[2].cartesian()).transpose() <<
" ";
659 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\"";
660 file << (rotation*origin.
cartesian()).transpose() <<
"\"" << std::endl;
662 for (
const auto &vector: configurationA)
663 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
664 for (
const auto &vector: configurationB)
665 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
666 for (
const auto &vector: configurationC)
667 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.2 << std::endl;
668 for (
const auto &vector: configurationD)
669 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.01 << std::endl;
675 return configuration;