160 const bool& useRLLL)
try :
161 RationalMatrix<dim>(A_in.reciprocalBasis.transpose()*B_in.latticeBasis)
165 ,M(getM(*this,*this))
166 ,N(getN(*this,*this))
167 ,sigmaA(round(M.template cast<double>().determinant()))
168 ,sigmaB(round(N.template cast<double>().determinant()))
169 ,sigma(std::abs(sigmaA)==std::abs(sigmaB)? std::abs(sigmaA) : 0)
170 , csl(getCSLBasis (A,B,*this,M,N,useRLLL),
MatrixDimD::Identity())
171 ,dscl(getDSCLBasis(A,B,*this,M,N,useRLLL),
MatrixDimD::Identity())
172 ,Ap(A.latticeBasis*this->matrixX().template cast<double>())
173 ,Bp(B.latticeBasis*this->matrixV().template cast<double>())
174 ,LambdaA(getLambdaA(M,N))
175 ,LambdaB(getLambdaB(M,N))
181 const MatrixDimD tempA(
A.reciprocalBasis.transpose()*
csl.latticeBasis);
182 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
185 throw std::runtime_error(
"CSL is not a multiple of lattice A.\n");
188 const MatrixDimD tempB(
B.reciprocalBasis.transpose()*
csl.latticeBasis);
189 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
192 throw std::runtime_error(
"CSL is not a multiple of lattice B\n");
199 const MatrixDimD tempA(
dscl.reciprocalBasis.transpose()*
A.latticeBasis);
200 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
203 throw std::runtime_error(
"Lattice A is not a multiple of the DSCL\n");
206 const MatrixDimD tempB(
dscl.reciprocalBasis.transpose()*
B.latticeBasis);
207 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
210 throw std::runtime_error(
"Lattice B is not a multiple of the DSCL\n");
218 throw std::runtime_error(
"LambdaA + LambdaB != I\n");
224 catch(std::runtime_error& e)
226 std::cout << e.what() << std::endl;
227 throw(std::runtime_error(
"Bicrystal construction failed. "));
502 const double& orthogonality,
503 const int& dsclFactor,
504 std::string filename,
507 assert(orthogonality>=0.0 && orthogonality<=1.0 &&
508 "The \"orthogonality\" parameter should be between 0.0 and 1.0");
509 assert(dsclFactor>=1 &&
510 "The \"dsclFactor\" should be greater than 1.");
511 assert(boxVectors.size()==dim);
512 for(
const auto& boxVector : boxVectors)
514 assert(&csl == &boxVector.lattice &&
515 "Box vectors do not belong to the CSL.");
520 for (
int i=0; i<dim; ++i) {
521 C.col(i) = boxVectors[i].cartesian();
523 assert(abs(C.determinant()) > FLT_EPSILON &&
"Box volume is equal to zero.");
527 auto boxVectorTemp= boxVectors[0];
530 nC= boxVectors[1].
cross();
532 nC= boxVectors[1].
cross(boxVectors[2]);
533 auto basis= csl.planeParallelLatticeBasis(nC,
true);
537 boxLatticeIndices.col(0)= boxVectors[0];
538 for (
int i=1; i<dim; ++i)
540 double minDotProduct= std::numbers::pi/2;
543 auto boxVectorUpdated(boxVectors[0]);
545 for(
int i=0;i<planesToExplore;++i)
547 int sign= boxVectors[0].cartesian().dot(basis[0].cartesian())>0? 1 : -1;
548 boxVectorTemp= boxVectors[0]+i*sign*basis[0].latticeVector();
549 boxLatticeIndices.col(0)= boxVectorTemp;
550 Lattice<dim> boxLattice(csl.latticeBasis*boxLatticeIndices.template cast<double>());
556 double dotProduct= abs(acos(boxVectorTemp.cartesian().normalized().dot(rC.
cartesian().normalized())-FLT_EPSILON));
557 if(dotProduct<minDotProduct) {
558 minDotProduct = dotProduct;
559 boxVectorUpdated= boxVectorTemp;
560 if (dotProduct < (1-orthogonality)*std::numbers::pi/2)
565 boxVectors[0]=boxVectorUpdated;
566 C.col(0)= boxVectors[0].cartesian();
570 MatrixDimD rotation= Eigen::Matrix<double,dim,dim>::Identity();;
571 Eigen::Matrix<double,dim,dim-1> orthogonalVectors;
574 orthogonalVectors.col(0) = C.col(1).normalized();
575 orthogonalVectors.col(1) = C.col(2).normalized();
578 orthogonalVectors.col(0)= C.col(1).normalized();
584 assert((rotation*rotation.transpose()).isApprox(Eigen::Matrix<double,dim,dim>::Identity(),1e-6)
585 &&
"Cannot orient the grain boundary. Box vectors are not orthogonal.");
588 std::vector<LatticeVector<dim>> configurationA, configurationB, configurationC, configurationD;
589 std::vector<LatticeVector<dim>> configuration;
591 std::vector<LatticeVector<dim>> boxVectorsInA, boxVectorsInB, boxVectorsInD;
593 for(
const auto& boxVector : boxVectors) {
594 boxVectorsInA.push_back(getLatticeVectorInA(boxVector));
595 boxVectorsInB.push_back(getLatticeVectorInB(boxVector));
596 boxVectorsInD.push_back(getLatticeVectorInD(boxVector));
600 auto dsclVector=getLatticeDirectionInD(boxVectors[0]).latticeVector();
602 if(abs((dsclFactor*dsclVector).dot(nD)) < abs(boxVectorsInD[0].dot(nD)))
603 boxVectorsInD[0]= dsclFactor*dsclVector;
605 std::vector<LatticeVector<dim>> boxVectorsForA(boxVectorsInA),
606 boxVectorsForB(boxVectorsInB),
607 boxVectorsForC(boxVectors),
608 boxVectorsForD(boxVectorsInD);
609 boxVectorsForA[0]=2*boxVectorsInA[0];
610 boxVectorsForB[0]=2*boxVectorsInB[0];
611 boxVectorsForC[0]=2*boxVectors[0];
612 boxVectorsForD[0]=2*boxVectorsInD[0];
614 configurationA= A.box(boxVectorsForA);
615 configurationB= B.box(boxVectorsForB);
616 configurationC= csl.box(boxVectorsForC);
617 configurationD= dscl.box(boxVectorsForD);
620 for(
auto& vector : configurationA)
622 for(
auto& vector : configurationB)
624 for(
auto& vector : configurationC)
625 vector= vector + origin;
626 for(
auto& vector : configurationD)
629 configuration= configurationA;
630 configuration.insert(configuration.end(),configurationB.begin(),configurationB.end());
631 configuration.insert(configuration.end(),configurationC.begin(),configurationC.end());
632 configuration.insert(configuration.end(),configurationD.begin(),configurationD.end());
634 if(!filename.empty()) {
637 if (!file) std::cerr <<
"Unable to open file";
638 file << configuration.size() << std::endl;
639 file <<
"Lattice=\"";
642 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" 0 ";
643 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" 0 ";
645 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\"";
646 file << (rotation*origin.
cartesian()).transpose() <<
" 0.0\"" << std::endl;
647 for (
const auto &vector: configurationA)
648 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
649 for (
const auto &vector: configurationB)
650 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
651 for (
const auto &vector: configurationC)
652 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.2 << std::endl;
653 for (
const auto &vector: configurationD)
654 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.01 << std::endl;
657 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" ";
658 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" ";
659 file << (rotation*boxVectorsForC[2].cartesian()).transpose() <<
" ";
660 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\"";
661 file << (rotation*origin.
cartesian()).transpose() <<
"\"" << std::endl;
663 for (
const auto &vector: configurationA)
664 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
665 for (
const auto &vector: configurationB)
666 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
667 for (
const auto &vector: configurationC)
668 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.2 << std::endl;
669 for (
const auto &vector: configurationD)
670 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.01 << std::endl;
676 return configuration;