oILAB
Loading...
Searching...
No Matches
BiCrystal.cpp
Go to the documentation of this file.
1/* This file is part of gbLAB.
2 *
3 * gbLAB is distributed without any warranty under the MIT License.
4 */
5
6
7#ifndef gbLAB_BiCrystal_cpp_
8#define gbLAB_BiCrystal_cpp_
9
10#include "../../include/Lattices/LatticeModule.h"
11#include <numbers>
12
13namespace oILAB {
14
15template <int dim>
18 const SmithDecomposition<dim> &sd) {
21 for (int i = 0; i < dim; ++i) {
22 const auto &dii(sd.matrixD()(i, i));
23 M(i, i) = dii / IntegerMath<IntScalarType>::gcd(rm.mu, dii);
24 }
25 return M;
26 }
27
28 template <int dim>
31 {
33 for(int i=0;i<dim;++i)
34 {
35 const auto& dii=sd.matrixD()(i,i);
36 N(i,i)=rm.mu/IntegerMath<IntScalarType>::gcd(rm.mu,dii);
37 }
38 return N;
39 }
40
41 template <int dim>
43 const typename BiCrystal<dim>::MatrixDimI& N)
44 {
46 for(int col=0; col<dim; ++col)
47 {
49 for (int i = 0; i < dim; ++i)
50 {
51 IntScalarType a = N(i, i);
52 IntScalarType b = -M(i, i);
53 IntScalarType c = -(i==col);
55 }
56 LambdaA.col(col)= M*y;
57 }
58 return LambdaA;
59 }
60
61 template <int dim>
63 const typename BiCrystal<dim>::MatrixDimI& N)
64 {
65 typename BiCrystal<dim>::MatrixDimI LambdaB;
66 for(int col=0; col<dim; ++col)
67 {
69 for (int i = 0; i < dim; ++i)
70 {
71 IntScalarType a = N(i, i);
72 IntScalarType b = -M(i, i);
73 IntScalarType c = (i==col);
75 }
76 LambdaB.col(col)= N*x;
77 }
78 return LambdaB;
79 }
80
81 template <int dim>
83 const Lattice<dim>& B,
85 const typename BiCrystal<dim>::MatrixDimI& M,
86 const typename BiCrystal<dim>::MatrixDimI& N)
87 {
88 // The transition matrix is T=P/sigma, where P=rm.integerMatrix is
89 // an integer matrix and sigma=rm.sigma is an integer
90 // The integer matrix P can be decomposed as P=X*D*Y using the Smith decomposition.
91 // X and Y are unimodular, and D is diagonal with D(k,k) dividing D(k+1,k+1)
92 // The decomposition also computes the matices U and V such that D=U*P*V
93 // From T=inv(A)*B=P/sigma=X*D*Y/sigma=X*D*inv(V)/sigma, we have
94 // B1*(sigma*I)=A1*D
95 // where
96 // B1=B*V
97 // A1=A*X
98 // Since V and X are unimodular matrices, B1 and A1 are new bases
99 // of the lattices B and A, respectively. Moreover, since
100 // (sigma*I) and D are diagonal, the columns of B1 and A1 are
101 // proportional, with rational proportionality factors different for each column.
102 // For example, columns "i" read
103 // b1_i*sigma=a1_i*D(i,i)
104 // Therefore, the i-th primitive vectors of the CSL is
105 // c_i=b1_i*sigma/gcd(sigma,D(i,i))=a1_i*D(i,i)/gcd(sigma,D(i,i))
106 // or, in matrix form
107 // C=B1*N=A1*M, that is
108 // C=B*V*N=A*X*M
109 // where M=diag(D(i,i)/gcd(sigma,D(i,i))) and
110 // N=diag(sigma/gcd(sigma,D(i,i))) and
111
112 const auto C1(A.latticeBasis*(sd.matrixX()*M).template cast<double>());
113 const auto C2(B.latticeBasis*(sd.matrixV()*N).template cast<double>());
114 if ((C1-C2).norm()/C1.norm()>FLT_EPSILON || (C1-C2).norm()/C2.norm()>FLT_EPSILON)
115 {
116 throw std::runtime_error("CSL calculation failed.\n");
117 }
118
119 /*
120 if(useRLLL)
121 {
122 return RLLL(0.5*(C1+C2),0.75).reducedBasis();
123 }
124 else
125 {
126 return 0.5*(C1+C2);
127 }
128 */
129 return 0.5*(C1+C2);
130 }
131
132 template <int dim>
134 const Lattice<dim>& B,
135 const SmithDecomposition<dim>& sd,
136 const typename BiCrystal<dim>::MatrixDimI& M,
137 const typename BiCrystal<dim>::MatrixDimI& N)
138 {
139
140 const auto D1(A.latticeBasis*sd.matrixX().template cast<double>()*N.template cast<double>().inverse());
141 const auto D2(B.latticeBasis*sd.matrixV().template cast<double>()*M.template cast<double>().inverse());
142 if ((D1-D2).norm()/D1.norm()>FLT_EPSILON || (D1-D2).norm()/D2.norm()>FLT_EPSILON)
143 {
144 throw std::runtime_error("DSCL calculation failed.\n");
145 }
146 /*
147 if(useRLLL)
148 {
149 return RLLL(0.5*(D1+D2),0.75).reducedBasis();
150 }
151 else
152 {
153 return 0.5*(D1+D2);
154 }
155 */
156 return 0.5*(D1+D2);
157 }
158
159
160 template <int dim>
162 const Lattice<dim>& B_in,
163 const bool& useRLLL) try :
164 /* init */ RationalMatrix<dim>(A_in.reciprocalBasis.transpose()*B_in.latticeBasis)
165 /* init */,SmithDecomposition<dim>(this->integerMatrix)
166 /* init */,A(A_in)
167 /* init */,B(B_in)
168 /* init */,M(getM(*this,*this))
169 /* init */,N(getN(*this,*this))
170 /* init */,sigmaA(round(M.template cast<double>().determinant()))
171 /* init */,sigmaB(round(N.template cast<double>().determinant()))
172 /* init */,sigma(std::abs(sigmaA)==std::abs(sigmaB)? std::abs(sigmaA) : 0)
173 /* init */,cslp(getCSLBasis (A,B,*this,M,N),MatrixDimD::Identity())
174 /* init */,dsclp(getDSCLBasis(A,B,*this,M,N),MatrixDimD::Identity())
175 /* init */,csl2cslp(useRLLL ? RLLL(cslp.latticeBasis,0.75).unimodularMatrix() : MatrixDimI::Identity())
176 /* init */,dscl2dsclp(useRLLL ? RLLL(dsclp.latticeBasis,0.75).unimodularMatrix() : MatrixDimI::Identity())
177 /* init */,csl(cslp.latticeBasis*csl2cslp.template cast<double>())
178 /* init */,dscl(dsclp.latticeBasis*dscl2dsclp.template cast<double>())
179 /* init */,Ap(A.latticeBasis*this->matrixX().template cast<double>())
180 /* init */,Bp(B.latticeBasis*this->matrixV().template cast<double>())
181 /* init */,LambdaA(getLambdaA(M,N))
182 /* init */,LambdaB(getLambdaB(M,N))
183 {
184
185 if(true)
186 {//verify that CSL can be obtained as multiple of A and B
187
188 const MatrixDimD tempA(A.reciprocalBasis.transpose()*csl.latticeBasis);
189 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
190 {
191 //std::cout << (tempA-tempA.array().round().matrix()).norm()/tempA.norm() << std::endl;
192 throw std::runtime_error("CSL is not a multiple of lattice A.\n");
193 }
194
195 const MatrixDimD tempB(B.reciprocalBasis.transpose()*csl.latticeBasis);
196 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
197 {
198 //std::cout << (tempB-tempB.array().round().matrix()).norm()/tempB.norm() << std::endl;
199 throw std::runtime_error("CSL is not a multiple of lattice B\n");
200 }
201 }
202
203 if(true)
204 {//verify that A and B are multiples of DSCL
205
206 const MatrixDimD tempA(dscl.reciprocalBasis.transpose()*A.latticeBasis);
207 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
208 {
209 //std::cout << (tempA-tempA.array().round().matrix()).norm()/tempA.norm() << std::endl;
210 throw std::runtime_error("Lattice A is not a multiple of the DSCL\n");
211 }
212
213 const MatrixDimD tempB(dscl.reciprocalBasis.transpose()*B.latticeBasis);
214 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
215 {
216 //std::cout << (tempB-tempB.array().round().matrix()).norm()/tempB.norm() << std::endl;
217 throw std::runtime_error("Lattice B is not a multiple of the DSCL\n");
218 }
219 }
220
221 if(true)
222 {//verify LambdaA + LambdaB = I
223 if (!(LambdaA+LambdaB).isIdentity())
224 {
225 throw std::runtime_error("LambdaA + LambdaB != I\n");
226 }
227 }
228
229 }
230
231 catch(std::runtime_error& e)
232 {
233 std::cout << e.what() << std::endl;
234 throw(std::runtime_error("Bicrystal construction failed. "));
235 }
236
237 template<int dim>
239 {
240 VectorDimI integerCoordinates;
241
242 if(&(v.lattice) == &(this->A))
243 return v;
244 else if(&(v.lattice) == &(this->csl))
245 // U*M*csl2cslp*v
246 integerCoordinates= this->matrixX() * M * csl2cslp * v;
247 else
248 throw(std::runtime_error("The input lattice vector should belong "
249 "to lattice A or the CSL"));
250 auto temp= LatticeVector<dim>(integerCoordinates,A);
251 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
252 return temp;
253 }
254
255 template<int dim>
257 {
258 VectorDimI integerCoordinates;
259
260 if(&(v.lattice) == &(this->B))
261 return v;
262 else if(&(v.lattice) == &(this->csl))
263 // V*N*csl2cslp*v
264 integerCoordinates= this->matrixV() * N * csl2cslp * v;
265 else
266 throw(std::runtime_error("The input lattice vector should belong "
267 "to lattice B or the CSL"));
268 auto temp= LatticeVector<dim>(integerCoordinates,B);
269 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
270 return temp;
271 }
272
273 template<int dim>
275 {
276 VectorDimI integerCoordinates;
277
280
281 if(&(v.lattice) == &(this->A))
282 // N*inv(U)*v
283 integerCoordinates = N * adjX * v;
284 else if(&(v.lattice) == &(this->B))
285 // M*inv(V)*v
286 integerCoordinates = M * adjV * v;
287 else if(&(v.lattice) == &(this->csl))
288 // N*M*csl2cslp*v
289 integerCoordinates = N * M * csl2cslp * v;
290 else if(&(v.lattice) == &(this->dscl))
291 return LatticeVector<dim>(v);
292 else
293 throw(std::runtime_error("The input lattice vector should belong to one of the four lattices of the bicrystal"));
294
295 MatrixDimI adj_dscl2dsclp = MatrixDimIExt<IntScalarType,dim>::adjoint(dscl2dsclp);
296 integerCoordinates= adj_dscl2dsclp*integerCoordinates;
297 auto temp= LatticeVector<dim>(integerCoordinates,dscl);
298 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
299
300 //return LatticeVector<dim>(integerCoordinates,dscl);
301 return temp;
302 }
303
304
305 template<int dim>
307 {
308 VectorDimI integerCoordinates;
309
316
317 if(&(v.lattice) == &(this->A))
318 // inv(M)*inv(U)*v
319 integerCoordinates = adjM * adjX * v;
320 else if(&(v.lattice) == &(this->B))
321 // inv(N)*inv(V)*v
322 integerCoordinates = adjN * adjV * v;
323 else if(&(v.lattice) == &(this->csl))
324 return LatticeDirection<dim>(v);
325 else if(&(v.lattice) == &(this->dscl))
326 integerCoordinates = adjMN* dscl2dsclp * v;
327 else
328 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
329
330 integerCoordinates= adj_csl2cslp*integerCoordinates;
331 auto temp= LatticeVector<dim>(integerCoordinates,csl);
332 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
333 return LatticeDirection<dim>(temp);
334 }
335 template<int dim>
337 {
338 return LatticeDirection<dim>(getLatticeVectorInD(v));
339 }
340
341 template<int dim>
343 {
344 VectorDimI integerCoordinates;
345
349 MatrixDimI adj_dscl2dsclp = MatrixDimIExt<IntScalarType,dim>::adjoint(dscl2dsclp);
350
351 if(&(rv.lattice) == &(this->A))
353 else if(&(rv.lattice) == &(this->B))
354 // U^-T*inverse(M)*N*V^T
355 integerCoordinates= adjX.transpose() * adjM * N * (this->matrixV()).transpose() * rv;
356 else if(&(rv.lattice) == &(this->csl))
357 // U^-T*inverse(M) * csl2cslp^{-T}
358 integerCoordinates= adjX.transpose() * adjM * adj_csl2cslp.transpose() * rv;
359 else if(&(rv.lattice) == &(this->dscl))
360 // U^-T*N*rv * dscl2dsclp^{-T}
361 integerCoordinates = adjX.transpose() * N * adj_dscl2dsclp.transpose() * rv;
362 else
363 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
364
365 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,A);
366 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
368 }
369 template<int dim>
371 {
372 VectorDimI integerCoordinates;
373
379 MatrixDimI adj_dscl2dsclp = MatrixDimIExt<IntScalarType,dim>::adjoint(dscl2dsclp);
380
381 if(&(rv.lattice) == &(this->A))
382 // V^-T*inverse(N)*M*U^T
383 integerCoordinates= adjV.transpose() * adjN * M * (this->matrixX()).transpose() * rv;
384 else if(&(rv.lattice) == &(this->B))
386 else if(&(rv.lattice) == &(this->csl))
387 // V^-T*inverse(N)*rv*cslp2csl^T
388 integerCoordinates= adjV.transpose() * adjN * adj_csl2cslp.transpose() * rv;
389 else if(&(rv.lattice) == &(this->dscl))
390 // V^-T*M*rv*dsclp2dscl^T
391 integerCoordinates= adjV.transpose() * M * adj_dscl2dsclp.transpose() * rv;
392 else
393 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
394
395 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,B);
396 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
398 }
399 template<int dim>
401 {
402 VectorDimI integerCoordinates;
403 MatrixDimI adj_dscl2dsclp = MatrixDimIExt<IntScalarType,dim>::adjoint(dscl2dsclp);
404
405 if(&(rv.lattice) == &(this->A))
406 // M*U^T*rv
407 integerCoordinates= M*this->matrixX().transpose()*rv;
408 else if(&(rv.lattice) == &(this->B))
409 // N*V^T*rv
410 integerCoordinates= N*this->matrixV().transpose()*rv;
411 else if(&(rv.lattice) == &(this->csl))
413 else if(&(rv.lattice) == &(this->dscl))
414 // M*N*rv
415 integerCoordinates= M*N*adj_dscl2dsclp.transpose()*rv;
416 else
417 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
418
419 integerCoordinates= csl2cslp.transpose()*integerCoordinates;
420 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,csl);
421 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
423 }
424 template<int dim>
426 {
427 VectorDimI integerCoordinates;
429
432
433 if(&(rv.lattice) == &(this->A))
434 integerCoordinates= adjN * (this->matrixX().transpose()) * rv;
435 else if(&(rv.lattice) == &(this->B))
436 integerCoordinates= adjM * (this->matrixV().transpose()) * rv;
437 else if(&(rv.lattice) == &(this->csl))
438 integerCoordinates= adjN * adjM * adj_csl2cslp.transpose() * rv;
439 else
440 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
441
442 integerCoordinates= dscl2dsclp.transpose()*integerCoordinates;
443 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,dscl);
444 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
446 }
447
448 template<int dim>
450 {
451 if(&d.lattice != &this->dscl)
452 throw(std::runtime_error("Input vector is not a DSCL vectors"));
453 return LatticeVector<dim>((LambdaA*d).eval(),d.lattice);
454 }
455
456 template<int dim>
458 {
459 if(&d.lattice != &this->dscl)
460 throw(std::runtime_error("Input vector is not a DSCL vectors"));
461 return LatticeVector<dim>((LambdaB*d).eval(),d.lattice);
462 }
463
464 template<int dim> template<int dm>
465 typename std::enable_if<dm==2 || dm==3,std::map<typename BiCrystal<dim>::IntScalarType,Gb<dm>>>::type
467 {
468 if (&d.lattice != &A && &d.lattice != &B)
469 throw std::runtime_error("The tilt axis does not belong to lattices A and B \n");
470 std::vector<Gb<dm>> gbVec;
471 double epsilon=1e-8;
472 int count= -1;
473 IntScalarType keyScale= 1e6;
474 auto basis= d.lattice.directionOrthogonalReciprocalLatticeBasis(d,true);
475 if (dm==3)
476 {
477 for (int i = -div; i <= div; ++i)
478 {
479 for (int j = -div; j <= div; ++j)
480 {
481 if (i==0 && j==0) continue;
482 count++;
483 ReciprocalLatticeVector<dm> rv = i * basis[1].reciprocalLatticeVector() + j * basis[2].reciprocalLatticeVector();
484 try
485 {
486 Gb<dm> gb(*this, rv);
487 gbVec.push_back(gb);
488 }
489 catch(std::runtime_error& e)
490 {
491 std::cout << e.what() << std::endl;
492 std::cout << "Unable to form GB with normal = " << rv << std::endl;
493 std::cout << "moving on to next inclination" << std::endl;
494 }
495 }
496 }
497 }
498 else if(dm==2)
499 {
500 auto rv= basis[0].reciprocalLatticeVector();
501 gbVec.push_back(Gb<dm>(*this, rv));
502 }
503 std::map<IntScalarType,Gb<dm>> gbSet;
504 for(const Gb<dim>& gb:gbVec)
505 {
506 double cosAngle;
507 cosAngle= gb.nA.cartesian().normalized().dot(gbVec[0].nA.cartesian().normalized());
508 if (cosAngle-1>-epsilon) cosAngle= 1.0;
509 if (cosAngle+1<epsilon) cosAngle= -1.0;
510
511 double angle= acos(cosAngle);
512 IntScalarType key= angle*keyScale;
513 gbSet.insert(std::pair<IntScalarType,Gb<dm>>(key,gb));
514 }
515 return gbSet;
516 }
517
518 template<int dim> template<int dm>
519 typename std::enable_if<dm==2 || dm==3,std::vector<LatticeVector<dim>>>::type
520 BiCrystal<dim>::box(std::vector<LatticeVector<dim>>& boxVectors,
521 const double& orthogonality,
522 const int& dsclFactor,
523 std::string filename,
524 bool orient) const
525 {
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)
532 {
533 assert(&csl == &boxVector.lattice &&
534 "Box vectors do not belong to the CSL.");
535 }
536
537 // Form the box lattice
538 MatrixDimD C;
539 for (int i=0; i<dim; ++i) {
540 C.col(i) = boxVectors[i].cartesian();
541 }
542 assert(abs(C.determinant()) > FLT_EPSILON && "Box volume is equal to zero.");
543
544
545 // Adjust boxVector[0] such that it is as orthogonal as possible to boxVector[1]
546 auto boxVectorTemp= boxVectors[0];
548 if (dim==2)
549 nC= boxVectors[1].cross();
550 if (dim==3)
551 nC= boxVectors[1].cross(boxVectors[2]);
552 auto basis= csl.planeParallelLatticeBasis(nC,true);
553
554 int planesToExplore= nC.stacking();
555 MatrixDimI boxLatticeIndices;
556 boxLatticeIndices.col(0)= boxVectors[0];
557 for (int i=1; i<dim; ++i)
558 boxLatticeIndices.col(i)= boxVectors[i]/IntegerMath<long long int>::gcd(boxVectors[i]);
559 double minDotProduct= std::numbers::pi/2;
560 int minStep;
561
562 auto boxVectorUpdated(boxVectors[0]);
563
564 for(int i=0;i<planesToExplore;++i)
565 {
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>());
570 ReciprocalLatticeVector<dim> rC(boxLattice);
571 rC(0)=1;
572 VectorDimI temp=
573 boxLatticeIndices*boxLattice.planeParallelLatticeBasis(ReciprocalLatticeDirection<dim>(rC),true)[0].latticeVector();
574 boxVectorTemp= LatticeVector<dim>(temp,csl);
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)
580 break;
581 }
582
583 }
584 boxVectors[0]=boxVectorUpdated;
585 C.col(0)= boxVectors[0].cartesian();
586
587
588 // form the rotation matrix used to orient the system
589 MatrixDimD rotation= Eigen::Matrix<double,dim,dim>::Identity();;
590 Eigen::Matrix<double,dim,dim-1> orthogonalVectors;
591 if (orient) {
592 if (dim==3) {
593 orthogonalVectors.col(0) = C.col(1).normalized();
594 orthogonalVectors.col(1) = C.col(2).normalized();
595 }
596 else if (dim==2)
597 orthogonalVectors.col(0)= C.col(1).normalized();
598
599 rotation=Rotation<dim>(orthogonalVectors);
600 }
601 //assert((rotation*rotation.transpose()).template isApprox(Eigen::Matrix<double,dim,dim>::Identity())
602 //assert((rotation*rotation.transpose()).isApprox(Eigen::Matrix<double,dim,dim>::Identity())
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.");
605
606
607 std::vector<LatticeVector<dim>> configurationA, configurationB, configurationC, configurationD;
608 std::vector<LatticeVector<dim>> configuration;
609
610 std::vector<LatticeVector<dim>> boxVectorsInA, boxVectorsInB, boxVectorsInD;
611 // calculate boxVectors in A, B, and D
612 for(const auto& boxVector : boxVectors) {
613 boxVectorsInA.push_back(getLatticeVectorInA(boxVector));
614 boxVectorsInB.push_back(getLatticeVectorInB(boxVector));
615 boxVectorsInD.push_back(getLatticeVectorInD(boxVector));
616 }
617
618 // prepare boxVectors for D
619 auto dsclVector=getLatticeDirectionInD(boxVectors[0]).latticeVector();
620 auto nD= getReciprocalLatticeDirectionInD(nC.reciprocalLatticeVector());
621 if(abs((dsclFactor*dsclVector).dot(nD)) < abs(boxVectorsInD[0].dot(nD)))
622 boxVectorsInD[0]= dsclFactor*dsclVector;
623
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];
632
633 configurationA= A.box(boxVectorsForA);
634 configurationB= B.box(boxVectorsForB);
635 configurationC= csl.box(boxVectorsForC);
636 configurationD= dscl.box(boxVectorsForD);
637
638 LatticeVector<dim> origin(-1*boxVectors[0]);
639 for(auto& vector : configurationA)
640 vector= vector + LatticeVector<dim>(-1*boxVectorsInA[0]);
641 for(auto& vector : configurationB)
642 vector= vector + LatticeVector<dim>(-1*boxVectorsInB[0]);
643 for(auto& vector : configurationC)
644 vector= vector + origin;
645 for(auto& vector : configurationD)
646 vector= vector + LatticeVector<dim>(-1*boxVectorsInD[0]);
647
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());
652
653 if(!filename.empty()) {
654 std::ofstream file;
655 file.open(filename);
656 if (!file) std::cerr << "Unable to open file";
657 file << configuration.size() << std::endl;
658 file << "Lattice=\"";
659
660 if (dim==2) {
661 file << (rotation*boxVectorsForC[0].cartesian()).transpose() << " 0 ";
662 file << (rotation*boxVectorsForC[1].cartesian()).transpose() << " 0 ";
663 file << " 0 0 1 ";
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;
674 }
675 else if (dim==3){
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;
681
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;
690 }
691
692
693 file.close();
694 }
695 return configuration;
696 }
697
698// template class BiCrystal<1>;
699 template class BiCrystal<2>;
700 template std::map<BiCrystal<2>::IntScalarType, Gb<2>>
702 template std::vector<LatticeVector<2>>
703 BiCrystal<2>::box<2>(std::vector<LatticeVector<2>> &boxVectors,
704 const double &orthogonality, const int &dsclFactor,
705 std::string filename, bool orient) const;
706
707 template class BiCrystal<3>;
708 template std::map<BiCrystal<3>::IntScalarType, Gb<3>>
710 template std::vector<LatticeVector<3>>
711 BiCrystal<3>::box<3>(std::vector<LatticeVector<3>> &boxVectors,
712 const double &orthogonality, const int &dsclFactor,
713 std::string filename, bool orient) const;
714
715 template class BiCrystal<4>;
716 template class BiCrystal<5>;
717
718 } // namespace oILAB
719#endif
720
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInD(const ReciprocalLatticeVector< dim > &v) const
const MatrixDimI LambdaB
Shift tensor describes the shift in the CSL when lattice is shifted by a DSCL vector.
Definition BiCrystal.h:124
static MatrixDimI getN(const RationalMatrix< dim > &rm, const SmithDecomposition< dim > &sd)
Definition BiCrystal.cpp:29
LatticeCore< dim >::MatrixDimD MatrixDimD
Definition BiCrystal.h:30
static MatrixDimI getM(const RationalMatrix< dim > &rm, const SmithDecomposition< dim > &sd)
Definition BiCrystal.cpp:17
static MatrixDimD getCSLBasis(const Lattice< dim > &A, const Lattice< dim > &B, const SmithDecomposition< dim > &sd, const MatrixDimI &M, const MatrixDimI &N)
Definition BiCrystal.cpp:82
std::enable_if< dm==2||dm==3, std::map< IntScalarType, Gb< dm > > >::type generateGrainBoundaries(const LatticeDirection< dim > &d, int div=30) const
Given a tilt axis , that belongs to lattices or , this function generate a set of tilt GBs....
LatticeCore< dim >::MatrixDimI MatrixDimI
Definition BiCrystal.h:32
const MatrixDimI LambdaA
Shift tensor describes the shift in the CSL when lattice is shifted by a DSCL vector.
Definition BiCrystal.h:119
LatticeVector< dim > getLatticeVectorInA(const LatticeVector< dim > &v) const
LatticeVector< dim > getLatticeVectorInD(const LatticeVector< dim > &v) const
LatticeVector< dim > shiftTensorB(const LatticeVector< dim > &d) const
static MatrixDimI getLambdaA(const MatrixDimI &M, const MatrixDimI &N)
Definition BiCrystal.cpp:42
LatticeDirection< dim > getLatticeDirectionInD(const LatticeVector< dim > &v) const
LatticeVector< dim > getLatticeVectorInB(const LatticeVector< dim > &v) const
std::enable_if< dm==2||dm==3, std::vector< LatticeVector< dim > > >::type box(std::vector< LatticeVector< dim > > &boxVectors, const double &orthogonality, const int &dsclFactor, std::string filename="", bool orient=false) const
LatticeDirection< dim > getLatticeDirectionInC(const LatticeVector< dim > &v) const
LatticeCore< dim >::IntScalarType IntScalarType
Definition BiCrystal.h:28
const Lattice< dim > & B
Definition BiCrystal.h:53
const Lattice< dim > & A
Definition BiCrystal.h:52
static MatrixDimI getLambdaB(const MatrixDimI &M, const MatrixDimI &N)
Definition BiCrystal.cpp:62
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInB(const ReciprocalLatticeVector< dim > &v) const
const Lattice< dim > csl
CSL lattice .
Definition BiCrystal.h:102
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInC(const ReciprocalLatticeVector< dim > &v) const
LatticeVector< dim > shiftTensorA(const LatticeVector< dim > &d) const
const Lattice< dim > dscl
DCSL lattice .
Definition BiCrystal.h:106
LatticeCore< dim >::VectorDimI VectorDimI
Definition BiCrystal.h:31
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInA(const ReciprocalLatticeVector< dim > &v) const
BiCrystal(const Lattice< dim > &A, const Lattice< dim > &B, const bool &useRLLL=false)
Constructs a bicrystal from two lattices and by computing the parallel bases for lattices ,...
static MatrixDimD getDSCLBasis(const Lattice< dim > &A, const Lattice< dim > &B, const SmithDecomposition< dim > &sd, const MatrixDimI &M, const MatrixDimI &N)
Definition Gb.h:13
Lattice class.
Definition Lattice.h:31
std::vector< LatticeDirection< dim > > planeParallelLatticeBasis(const ReciprocalLatticeDirection< dim > &l, const bool &useRLLL=false) const
Given a reciprocal lattice direction , this function returns a plane-parallel lattice basis ,...
Definition Lattice.cpp:167
const MatrixDimD latticeBasis
Definition Lattice.h:41
LatticeVector class.
const Lattice< dim > & lattice
VectorDimD cartesian() const
static Eigen::Matrix< IntScalarType, dim, dim > adjoint(const Eigen::Matrix< IntScalarType, dim, dim > &input)
const IntScalarType & mu
std::enable_if< dm==2, LatticeDirection< dim > >::type cross(const ReciprocalLatticeVector< dim > &other) const
const MatrixNi & matrixD() const
const MatrixNi & matrixX() const
const MatrixNi & matrixV() const
static IntScalarType gcd(const IntScalarType &a, const IntScalarType &b)
Definition IntegerMath.h:26
static void solveDiophantine2vars(IntScalarType a, IntScalarType b, IntScalarType c, IntScalarType &x, IntScalarType &y)
LatticeDirection class.
const ReciprocalLatticeVector< dim > & reciprocalLatticeVector() const
Returns a constant reference to the base class (ReciprocalLatticeVector)
int stacking() const
Returns the number of planes in the stacking sequence.