163 const bool& useRLLL)
try :
164 RationalMatrix<dim>(A_in.reciprocalBasis.transpose()*B_in.latticeBasis)
168 ,M(getM(*this,*this))
169 ,N(getN(*this,*this))
170 ,sigmaA(round(M.template cast<double>().determinant()))
171 ,sigmaB(round(N.template cast<double>().determinant()))
172 ,sigma(std::abs(sigmaA)==std::abs(sigmaB)? std::abs(sigmaA) : 0)
173 ,cslp(getCSLBasis (A,B,*this,M,N),
MatrixDimD::Identity())
174 ,dsclp(getDSCLBasis(A,B,*this,M,N),
MatrixDimD::Identity())
175 ,csl2cslp(useRLLL ?
RLLL(cslp.latticeBasis,0.75).unimodularMatrix() :
MatrixDimI::Identity())
176 ,dscl2dsclp(useRLLL ?
RLLL(dsclp.latticeBasis,0.75).unimodularMatrix() :
MatrixDimI::Identity())
177 ,csl(cslp.latticeBasis*csl2cslp.template cast<double>())
178 ,dscl(dsclp.latticeBasis*dscl2dsclp.template cast<double>())
179 ,Ap(A.latticeBasis*this->matrixX().template cast<double>())
180 ,Bp(B.latticeBasis*this->matrixV().template cast<double>())
181 ,LambdaA(getLambdaA(M,N))
182 ,LambdaB(getLambdaB(M,N))
188 const MatrixDimD tempA(
A.reciprocalBasis.transpose()*
csl.latticeBasis);
189 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
192 throw std::runtime_error(
"CSL is not a multiple of lattice A.\n");
195 const MatrixDimD tempB(
B.reciprocalBasis.transpose()*
csl.latticeBasis);
196 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
199 throw std::runtime_error(
"CSL is not a multiple of lattice B\n");
206 const MatrixDimD tempA(
dscl.reciprocalBasis.transpose()*
A.latticeBasis);
207 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
210 throw std::runtime_error(
"Lattice A is not a multiple of the DSCL\n");
213 const MatrixDimD tempB(
dscl.reciprocalBasis.transpose()*
B.latticeBasis);
214 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
217 throw std::runtime_error(
"Lattice B is not a multiple of the DSCL\n");
225 throw std::runtime_error(
"LambdaA + LambdaB != I\n");
231 catch(std::runtime_error& e)
233 std::cout << e.what() << std::endl;
234 throw(std::runtime_error(
"Bicrystal construction failed. "));
521 const double& orthogonality,
522 const int& dsclFactor,
523 std::string filename,
526 assert(orthogonality>=0.0 && orthogonality<=1.0 &&
527 "The \"orthogonality\" parameter should be between 0.0 and 1.0");
528 assert(dsclFactor>=1 &&
529 "The \"dsclFactor\" should be greater than 1.");
530 assert(boxVectors.size()==dim);
531 for(
const auto& boxVector : boxVectors)
533 assert(&csl == &boxVector.lattice &&
534 "Box vectors do not belong to the CSL.");
539 for (
int i=0; i<dim; ++i) {
540 C.col(i) = boxVectors[i].cartesian();
542 assert(abs(C.determinant()) > FLT_EPSILON &&
"Box volume is equal to zero.");
546 auto boxVectorTemp= boxVectors[0];
549 nC= boxVectors[1].
cross();
551 nC= boxVectors[1].
cross(boxVectors[2]);
552 auto basis= csl.planeParallelLatticeBasis(nC,
true);
556 boxLatticeIndices.col(0)= boxVectors[0];
557 for (
int i=1; i<dim; ++i)
559 double minDotProduct= std::numbers::pi/2;
562 auto boxVectorUpdated(boxVectors[0]);
564 for(
int i=0;i<planesToExplore;++i)
566 int sign= boxVectors[0].cartesian().dot(basis[0].cartesian())>0? 1 : -1;
567 boxVectorTemp= boxVectors[0]+i*sign*basis[0].latticeVector();
568 boxLatticeIndices.col(0)= boxVectorTemp;
569 Lattice<dim> boxLattice(csl.latticeBasis*boxLatticeIndices.template cast<double>());
575 double dotProduct= abs(acos(boxVectorTemp.cartesian().normalized().dot(rC.
cartesian().normalized())-FLT_EPSILON));
576 if(dotProduct<minDotProduct) {
577 minDotProduct = dotProduct;
578 boxVectorUpdated= boxVectorTemp;
579 if (dotProduct < (1-orthogonality)*std::numbers::pi/2)
584 boxVectors[0]=boxVectorUpdated;
585 C.col(0)= boxVectors[0].cartesian();
589 MatrixDimD rotation= Eigen::Matrix<double,dim,dim>::Identity();;
590 Eigen::Matrix<double,dim,dim-1> orthogonalVectors;
593 orthogonalVectors.col(0) = C.col(1).normalized();
594 orthogonalVectors.col(1) = C.col(2).normalized();
597 orthogonalVectors.col(0)= C.col(1).normalized();
599 rotation=Rotation<dim>(orthogonalVectors);
603 assert((rotation*rotation.transpose()).isApprox(Eigen::Matrix<double,dim,dim>::Identity(),1e-6)
604 &&
"Cannot orient the grain boundary. Box vectors are not orthogonal.");
607 std::vector<LatticeVector<dim>> configurationA, configurationB, configurationC, configurationD;
608 std::vector<LatticeVector<dim>> configuration;
610 std::vector<LatticeVector<dim>> boxVectorsInA, boxVectorsInB, boxVectorsInD;
612 for(
const auto& boxVector : boxVectors) {
613 boxVectorsInA.push_back(getLatticeVectorInA(boxVector));
614 boxVectorsInB.push_back(getLatticeVectorInB(boxVector));
615 boxVectorsInD.push_back(getLatticeVectorInD(boxVector));
619 auto dsclVector=getLatticeDirectionInD(boxVectors[0]).latticeVector();
621 if(abs((dsclFactor*dsclVector).dot(nD)) < abs(boxVectorsInD[0].dot(nD)))
622 boxVectorsInD[0]= dsclFactor*dsclVector;
624 std::vector<LatticeVector<dim>> boxVectorsForA(boxVectorsInA),
625 boxVectorsForB(boxVectorsInB),
626 boxVectorsForC(boxVectors),
627 boxVectorsForD(boxVectorsInD);
628 boxVectorsForA[0]=2*boxVectorsInA[0];
629 boxVectorsForB[0]=2*boxVectorsInB[0];
630 boxVectorsForC[0]=2*boxVectors[0];
631 boxVectorsForD[0]=2*boxVectorsInD[0];
633 configurationA= A.box(boxVectorsForA);
634 configurationB= B.box(boxVectorsForB);
635 configurationC= csl.box(boxVectorsForC);
636 configurationD= dscl.box(boxVectorsForD);
639 for(
auto& vector : configurationA)
641 for(
auto& vector : configurationB)
643 for(
auto& vector : configurationC)
644 vector= vector + origin;
645 for(
auto& vector : configurationD)
648 configuration= configurationA;
649 configuration.insert(configuration.end(),configurationB.begin(),configurationB.end());
650 configuration.insert(configuration.end(),configurationC.begin(),configurationC.end());
651 configuration.insert(configuration.end(),configurationD.begin(),configurationD.end());
653 if(!filename.empty()) {
656 if (!file) std::cerr <<
"Unable to open file";
657 file << configuration.size() << std::endl;
658 file <<
"Lattice=\"";
661 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" 0 ";
662 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" 0 ";
664 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"T T F\" origin=\"";
665 file << (rotation*origin.
cartesian()).transpose() <<
" 0.0\"" << std::endl;
666 for (
const auto &vector: configurationA)
667 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
668 for (
const auto &vector: configurationB)
669 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.05 << std::endl;
670 for (
const auto &vector: configurationC)
671 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.2 << std::endl;
672 for (
const auto &vector: configurationD)
673 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.0 <<
" " << 0.01 << std::endl;
676 file << (rotation*boxVectorsForC[0].cartesian()).transpose() <<
" ";
677 file << (rotation*boxVectorsForC[1].cartesian()).transpose() <<
" ";
678 file << (rotation*boxVectorsForC[2].cartesian()).transpose() <<
" ";
679 file <<
"\" Properties=atom_types:I:1:pos:R:3:radius:R:1 PBC=\"F T T\" origin=\"";
680 file << (rotation*origin.
cartesian()).transpose() <<
"\"" << std::endl;
682 for (
const auto &vector: configurationA)
683 file << 1 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
684 for (
const auto &vector: configurationB)
685 file << 2 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.05 << std::endl;
686 for (
const auto &vector: configurationC)
687 file << 3 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.2 << std::endl;
688 for (
const auto &vector: configurationD)
689 file << 4 <<
" " << (rotation*vector.cartesian()).transpose() <<
" " << 0.01 << std::endl;
695 return configuration;