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 <LatticeModule.h>
11
12namespace gbLAB
13{
14
15 template <int dim>
18 {
20 for(int i=0;i<dim;++i)
21 {
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 const bool& useRLLL)
88 {
89 // The transition matrix is T=P/sigma, where P=rm.integerMatrix is
90 // an integer matrix and sigma=rm.sigma is an integer
91 // The integer matrix P can be decomposed as P=X*D*Y using the Smith decomposition.
92 // X and Y are unimodular, and D is diagonal with D(k,k) dividing D(k+1,k+1)
93 // The decomposition also computes the matices U and V such that D=U*P*V
94 // From T=inv(A)*B=P/sigma=X*D*Y/sigma=X*D*inv(V)/sigma, we have
95 // B1*(sigma*I)=A1*D
96 // where
97 // B1=B*V
98 // A1=A*X
99 // Since V and X are unimodular matrices, B1 and A1 are new bases
100 // of the lattices B and A, respectively. Moreover, since
101 // (sigma*I) and D are diagonal, the columns of B1 and A1 are
102 // proportional, with rational proportionality factors different for each column.
103 // For example, columns "i" read
104 // b1_i*sigma=a1_i*D(i,i)
105 // Therefore, the i-th primitive vectors of the CSL is
106 // c_i=b1_i*sigma/gcd(sigma,D(i,i))=a1_i*D(i,i)/gcd(sigma,D(i,i))
107 // or, in matrix form
108 // C=B1*N=A1*M, that is
109 // C=B*V*N=A*X*M
110 // where M=diag(D(i,i)/gcd(sigma,D(i,i))) and
111 // N=diag(sigma/gcd(sigma,D(i,i))) and
112
113 const auto C1(A.latticeBasis*(sd.matrixX()*M).template cast<double>());
114 const auto C2(B.latticeBasis*(sd.matrixV()*N).template cast<double>());
115 if ((C1-C2).norm()/C1.norm()>FLT_EPSILON || (C1-C2).norm()/C2.norm()>FLT_EPSILON)
116 {
117 throw std::runtime_error("CSL calculation failed.\n");
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
130 template <int dim>
132 const Lattice<dim>& B,
133 const SmithDecomposition<dim>& sd,
134 const typename BiCrystal<dim>::MatrixDimI& M,
135 const typename BiCrystal<dim>::MatrixDimI& N,
136 const bool& useRLLL)
137 {
138
139 const auto D1(A.latticeBasis*sd.matrixX().template cast<double>()*N.template cast<double>().inverse());
140 const auto D2(B.latticeBasis*sd.matrixV().template cast<double>()*M.template cast<double>().inverse());
141 if ((D1-D2).norm()/D1.norm()>FLT_EPSILON || (D1-D2).norm()/D2.norm()>FLT_EPSILON)
142 {
143 throw std::runtime_error("DSCL calculation failed.\n");
144 }
145 if(useRLLL)
146 {
147 return RLLL(0.5*(D1+D2),0.75).reducedBasis();
148 }
149 else
150 {
151 return 0.5*(D1+D2);
152 }
153 }
154
155
156 template <int dim>
158 const Lattice<dim>& B_in,
159 const bool& useRLLL) try :
160 /* init */ RationalMatrix<dim>(A_in.reciprocalBasis.transpose()*B_in.latticeBasis)
161 /* init */,SmithDecomposition<dim>(this->integerMatrix)
162 /* init */,A(A_in)
163 /* init */,B(B_in)
164 /* init */,M(getM(*this,*this))
165 /* init */,N(getN(*this,*this))
166 /* init */,sigmaA(round(M.template cast<double>().determinant()))
167 /* init */,sigmaB(round(N.template cast<double>().determinant()))
168 /* init */,sigma(std::abs(sigmaA)==std::abs(sigmaB)? std::abs(sigmaA) : 0)
169 /* init */, csl(getCSLBasis (A,B,*this,M,N,useRLLL),MatrixDimD::Identity())
170 /* init */,dscl(getDSCLBasis(A,B,*this,M,N,useRLLL),MatrixDimD::Identity())
171 /* init */,Ap(A.latticeBasis*this->matrixX().template cast<double>())
172 /* init */,Bp(B.latticeBasis*this->matrixV().template cast<double>())
173 /* init */,LambdaA(getLambdaA(M,N))
174 /* init */,LambdaB(getLambdaB(M,N))
175 {
176
177 if(true)
178 {//verify that CSL can be obtained as multiple of A and B
179
180 const MatrixDimD tempA(A.reciprocalBasis.transpose()*csl.latticeBasis);
181 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
182 {
183 //std::cout << (tempA-tempA.array().round().matrix()).norm()/tempA.norm() << std::endl;
184 throw std::runtime_error("CSL is not a multiple of lattice A.\n");
185 }
186
187 const MatrixDimD tempB(B.reciprocalBasis.transpose()*csl.latticeBasis);
188 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
189 {
190 //std::cout << (tempB-tempB.array().round().matrix()).norm()/tempB.norm() << std::endl;
191 throw std::runtime_error("CSL is not a multiple of lattice B\n");
192 }
193 }
194
195 if(true)
196 {//verify that A and B are multiples of DSCL
197
198 const MatrixDimD tempA(dscl.reciprocalBasis.transpose()*A.latticeBasis);
199 if ((tempA-tempA.array().round().matrix()).norm()/tempA.norm()>FLT_EPSILON)
200 {
201 //std::cout << (tempA-tempA.array().round().matrix()).norm()/tempA.norm() << std::endl;
202 throw std::runtime_error("Lattice A is not a multiple of the DSCL\n");
203 }
204
205 const MatrixDimD tempB(dscl.reciprocalBasis.transpose()*B.latticeBasis);
206 if ((tempB-tempB.array().round().matrix()).norm()/tempB.norm()>FLT_EPSILON)
207 {
208 //std::cout << (tempB-tempB.array().round().matrix()).norm()/tempB.norm() << std::endl;
209 throw std::runtime_error("Lattice B is not a multiple of the DSCL\n");
210 }
211 }
212
213 if(true)
214 {//verify LambdaA + LambdaB = I
215 if (!(LambdaA+LambdaB).isIdentity())
216 {
217 throw std::runtime_error("LambdaA + LambdaB != I\n");
218 }
219 }
220
221 }
222
223 catch(std::runtime_error& e)
224 {
225 std::cout << e.what() << std::endl;
226 throw(std::runtime_error("Bicrystal construction failed. "));
227 }
228
229 template<int dim>
231 {
232 VectorDimI integerCoordinates;
233
234 if(&(v.lattice) == &(this->A))
235 return v;
236 else if(&(v.lattice) == &(this->csl))
237 // U*M*v
238 integerCoordinates= this->matrixX() * M * v;
239 else
240 throw(std::runtime_error("The input lattice vector should belong "
241 "to lattice A or the CSL"));
242 auto temp= LatticeVector<dim>(integerCoordinates,A);
243 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
244 return temp;
245 }
246
247 template<int dim>
249 {
250 VectorDimI integerCoordinates;
251
252 if(&(v.lattice) == &(this->B))
253 return v;
254 else if(&(v.lattice) == &(this->csl))
255 // V*N*v
256 integerCoordinates= this->matrixV() * N * v;
257 else
258 throw(std::runtime_error("The input lattice vector should belong "
259 "to lattice B or the CSL"));
260 auto temp= LatticeVector<dim>(integerCoordinates,B);
261 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
262 return temp;
263 }
264
265 template<int dim>
267 {
268 VectorDimI integerCoordinates;
269
272
273 if(&(v.lattice) == &(this->A))
274 // N*inv(U)*v
275 integerCoordinates = N * adjX * v;
276 else if(&(v.lattice) == &(this->B))
277 // M*inv(V)*v
278 integerCoordinates = M * adjV * v;
279 else if(&(v.lattice) == &(this->csl))
280 // N*M*v
281 integerCoordinates = N * M * v;
282 else if(&(v.lattice) == &(this->dscl))
283 return LatticeVector<dim>(v);
284 else
285 throw(std::runtime_error("The input lattice vector should belong to one of the four lattices of the bicrystal"));
286
287 auto temp= LatticeVector<dim>(integerCoordinates,dscl);
288 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
289
290 //return LatticeVector<dim>(integerCoordinates,dscl);
291 return temp;
292 }
293
294
295 template<int dim>
297 {
298 VectorDimI integerCoordinates;
299
305
306 if(&(v.lattice) == &(this->A))
307 // inv(M)*inv(U)*v
308 integerCoordinates = adjM * adjX * v;
309 else if(&(v.lattice) == &(this->B))
310 // inv(N)*inv(V)*v
311 integerCoordinates = adjN * adjV * v;
312 else if(&(v.lattice) == &(this->csl))
313 return LatticeDirection<dim>(v);
314 else if(&(v.lattice) == &(this->dscl))
315 integerCoordinates = adjMN* v;
316 else
317 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
318
319 auto temp= LatticeVector<dim>(integerCoordinates,csl);
320 if (temp.cartesian().dot(v.cartesian()) < 0) temp= -1*temp;
321 return LatticeDirection<dim>(temp);
322 }
323 template<int dim>
325 {
326 return LatticeDirection<dim>(getLatticeVectorInD(v));
327 }
328
329 template<int dim>
331 {
332 VectorDimI integerCoordinates;
333
336
337 if(&(rv.lattice) == &(this->A))
339 else if(&(rv.lattice) == &(this->B))
340 // U^-T*inverse(M)*N*V^T
341 integerCoordinates= adjX.transpose() * adjM * N * (this->matrixV()).transpose() * rv;
342 else if(&(rv.lattice) == &(this->csl))
343 // U^-T*inverse(M)
344 integerCoordinates= adjX.transpose() * adjM * rv;
345 else if(&(rv.lattice) == &(this->dscl))
346 // U^-T*N*rv
347 integerCoordinates = adjX.transpose() * N * rv;
348 else
349 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
350
351 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,A);
352 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
354 }
355 template<int dim>
357 {
358 VectorDimI integerCoordinates;
359
364
365 if(&(rv.lattice) == &(this->A))
366 // V^-T*inverse(N)*M*U^T
367 integerCoordinates= adjV.transpose() * adjN * M * (this->matrixX()).transpose() * rv;
368 else if(&(rv.lattice) == &(this->B))
370 else if(&(rv.lattice) == &(this->csl))
371 // V^-T*inverse(N)*rv
372 integerCoordinates= adjV.transpose() * adjN * rv;
373 else if(&(rv.lattice) == &(this->dscl))
374 // V^-T*M*rv
375 integerCoordinates= adjV.transpose() * M * rv;
376 else
377 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
378
379 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,B);
380 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
382 }
383 template<int dim>
385 {
386 VectorDimI integerCoordinates;
387
388 if(&(rv.lattice) == &(this->A))
389 // M*U^T*rv
390 integerCoordinates= M*this->matrixX().transpose()*rv;
391 else if(&(rv.lattice) == &(this->B))
392 // N*V^T*rv
393 integerCoordinates= N*this->matrixV().transpose()*rv;
394 else if(&(rv.lattice) == &(this->csl))
396 else if(&(rv.lattice) == &(this->dscl))
397 // M*N*rv
398 integerCoordinates= M*N*rv;
399 else
400 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
401
402 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,csl);
403 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
405 }
406 template<int dim>
408 {
409 VectorDimI integerCoordinates;
410
413
414 if(&(rv.lattice) == &(this->A))
415 integerCoordinates= adjN * (this->matrixX().transpose()) * rv;
416 else if(&(rv.lattice) == &(this->B))
417 integerCoordinates= adjM * (this->matrixV().transpose()) * rv;
418 else if(&(rv.lattice) == &(this->csl))
419 integerCoordinates= adjN * adjM * rv;
420 else
421 throw(std::runtime_error("The input reciprocal lattice vector should belong to one of the four reciprocal lattices of the bicrystal"));
422
423 auto temp= ReciprocalLatticeVector<dim>(integerCoordinates,dscl);
424 if (temp.cartesian().dot(rv.cartesian()) < 0) temp= -1*temp;
426 }
427
428 template<int dim>
430 {
431 if(&d.lattice != &this->dscl)
432 throw(std::runtime_error("Input vector is not a DSCL vectors"));
433 return LatticeVector<dim>((LambdaA*d).eval(),d.lattice);
434 }
435
436 template<int dim>
438 {
439 if(&d.lattice != &this->dscl)
440 throw(std::runtime_error("Input vector is not a DSCL vectors"));
441 return LatticeVector<dim>((LambdaB*d).eval(),d.lattice);
442 }
443
444 template<int dim> template<int dm>
445 typename std::enable_if<dm==2 || dm==3,std::map<typename BiCrystal<dim>::IntScalarType,Gb<dm>>>::type
447 {
448 if (&d.lattice != &A && &d.lattice != &B)
449 throw std::runtime_error("The tilt axis does not belong to lattices A and B \n");
450 std::vector<Gb<dm>> gbVec;
451 double epsilon=1e-8;
452 int count= -1;
453 IntScalarType keyScale= 1e6;
454 auto basis= d.lattice.directionOrthogonalReciprocalLatticeBasis(d,true);
455 if (dm==3)
456 {
457 for (int i = -div; i <= div; ++i)
458 {
459 for (int j = -div; j <= div; ++j)
460 {
461 if (i==0 && j==0) continue;
462 count++;
463 ReciprocalLatticeVector<dm> rv = i * basis[1].reciprocalLatticeVector() + j * basis[2].reciprocalLatticeVector();
464 try
465 {
466 Gb<dm> gb(*this, rv);
467 gbVec.push_back(gb);
468 }
469 catch(std::runtime_error& e)
470 {
471 std::cout << e.what() << std::endl;
472 std::cout << "Unable to form GB with normal = " << rv << std::endl;
473 std::cout << "moving on to next inclination" << std::endl;
474 }
475 }
476 }
477 }
478 else if(dm==2)
479 {
480 auto rv= basis[0].reciprocalLatticeVector();
481 gbVec.push_back(Gb<dm>(*this, rv));
482 }
483 std::map<IntScalarType,Gb<dm>> gbSet;
484 for(const Gb<dim>& gb:gbVec)
485 {
486 double cosAngle;
487 cosAngle= gb.nA.cartesian().normalized().dot(gbVec[0].nA.cartesian().normalized());
488 if (cosAngle-1>-epsilon) cosAngle= 1.0;
489 if (cosAngle+1<epsilon) cosAngle= -1.0;
490
491 double angle= acos(cosAngle);
492 IntScalarType key= angle*keyScale;
493 gbSet.insert(std::pair<IntScalarType,Gb<dm>>(key,gb));
494 }
495 return gbSet;
496 }
497
498 template<int dim> template<int dm>
499 typename std::enable_if<dm==2 || dm==3,std::vector<LatticeVector<dim>>>::type
500 BiCrystal<dim>::box(std::vector<LatticeVector<dim>>& boxVectors,
501 const double& orthogonality,
502 const int& dsclFactor,
503 std::string filename,
504 bool orient) const
505 {
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)
512 {
513 assert(&csl == &boxVector.lattice &&
514 "Box vectors do not belong to the CSL.");
515 }
516
517 // Form the box lattice
518 MatrixDimD C;
519 for (int i=0; i<dim; ++i) {
520 C.col(i) = boxVectors[i].cartesian();
521 }
522 assert(abs(C.determinant()) > FLT_EPSILON && "Box volume is equal to zero.");
523
524
525 // Adjust boxVector[0] such that it is as orthogonal as possible to boxVector[1]
526 auto boxVectorTemp= boxVectors[0];
528 if (dim==2)
529 nC= boxVectors[1].cross();
530 if (dim==3)
531 nC= boxVectors[1].cross(boxVectors[2]);
532 auto basis= csl.planeParallelLatticeBasis(nC,true);
533
534 int planesToExplore= nC.stacking();
535 MatrixDimI boxLatticeIndices;
536 boxLatticeIndices.col(0)= boxVectors[0];
537 for (int i=1; i<dim; ++i)
538 boxLatticeIndices.col(i)= boxVectors[i]/IntegerMath<long long int>::gcd(boxVectors[i]);
539 double minDotProduct= M_PI/2;
540 int minStep;
541
542 auto boxVectorUpdated(boxVectors[0]);
543
544 for(int i=0;i<planesToExplore;++i)
545 {
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>());
550 ReciprocalLatticeVector<dim> rC(boxLattice);
551 rC(0)=1;
552 VectorDimI temp=
553 boxLatticeIndices*boxLattice.planeParallelLatticeBasis(ReciprocalLatticeDirection<dim>(rC),true)[0].latticeVector();
554 boxVectorTemp= LatticeVector<dim>(temp,csl);
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)
560 break;
561 }
562
563 }
564 boxVectors[0]=boxVectorUpdated;
565 C.col(0)= boxVectors[0].cartesian();
566
567
568 // form the rotation matrix used to orient the system
569 MatrixDimD rotation= Eigen::Matrix<double,dim,dim>::Identity();;
570 Eigen::Matrix<double,dim,dim-1> orthogonalVectors;
571 if (orient) {
572 if (dim==3) {
573 orthogonalVectors.col(0) = C.col(1).normalized();
574 orthogonalVectors.col(1) = C.col(2).normalized();
575 }
576 else if (dim==2)
577 orthogonalVectors.col(0)= C.col(1).normalized();
578
579 rotation=Rotation<dim>(orthogonalVectors);
580 }
581 //assert((rotation*rotation.transpose()).template isApprox(Eigen::Matrix<double,dim,dim>::Identity())
582 //assert((rotation*rotation.transpose()).isApprox(Eigen::Matrix<double,dim,dim>::Identity())
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.");
585
586
587 std::vector<LatticeVector<dim>> configurationA, configurationB, configurationC, configurationD;
588 std::vector<LatticeVector<dim>> configuration;
589
590 std::vector<LatticeVector<dim>> boxVectorsInA, boxVectorsInB, boxVectorsInD;
591 // calculate boxVectors in A, B, and D
592 for(const auto& boxVector : boxVectors) {
593 boxVectorsInA.push_back(getLatticeVectorInA(boxVector));
594 boxVectorsInB.push_back(getLatticeVectorInB(boxVector));
595 boxVectorsInD.push_back(getLatticeVectorInD(boxVector));
596 }
597
598 // prepare boxVectors for D
599 auto dsclVector=getLatticeDirectionInD(boxVectors[0]).latticeVector();
600 auto nD= getReciprocalLatticeDirectionInD(nC.reciprocalLatticeVector());
601 if(abs((dsclFactor*dsclVector).dot(nD)) < abs(boxVectorsInD[0].dot(nD)))
602 boxVectorsInD[0]= dsclFactor*dsclVector;
603
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];
612
613 configurationA= A.box(boxVectorsForA);
614 configurationB= B.box(boxVectorsForB);
615 configurationC= csl.box(boxVectorsForC);
616 configurationD= dscl.box(boxVectorsForD);
617
618 LatticeVector<dim> origin(-1*boxVectors[0]);
619 for(auto& vector : configurationA)
620 vector= vector + LatticeVector<dim>(-1*boxVectorsInA[0]);
621 for(auto& vector : configurationB)
622 vector= vector + LatticeVector<dim>(-1*boxVectorsInB[0]);
623 for(auto& vector : configurationC)
624 vector= vector + origin;
625 for(auto& vector : configurationD)
626 vector= vector + LatticeVector<dim>(-1*boxVectorsInD[0]);
627
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());
632
633 if(!filename.empty()) {
634 std::ofstream file;
635 file.open(filename);
636 if (!file) std::cerr << "Unable to open file";
637 file << configuration.size() << std::endl;
638 file << "Lattice=\"";
639
640 if (dim==2) {
641 file << (rotation*boxVectorsForC[0].cartesian()).transpose() << " 0 ";
642 file << (rotation*boxVectorsForC[1].cartesian()).transpose() << " 0 ";
643 file << " 0 0 1 ";
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;
654 }
655 else if (dim==3){
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;
661
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;
670 }
671
672
673 file.close();
674 }
675 return configuration;
676 }
677
678// template class BiCrystal<1>;
679 template class BiCrystal<2>;
680 template std::map<BiCrystal<2>::IntScalarType, Gb<2>>
682 template std::vector<LatticeVector<2>>
683 BiCrystal<2>::box<2>(std::vector<LatticeVector<2>> &boxVectors,
684 const double &orthogonality, const int &dsclFactor,
685 std::string filename, bool orient) const;
686
687 template class BiCrystal<3>;
688 template std::map<BiCrystal<3>::IntScalarType, Gb<3>>
690 template std::vector<LatticeVector<3>>
691 BiCrystal<3>::box<3>(std::vector<LatticeVector<3>> &boxVectors,
692 const double &orthogonality, const int &dsclFactor,
693 std::string filename, bool orient) const;
694
695 template class BiCrystal<4>;
696 template class BiCrystal<5>;
697
698} // end namespace
699#endif
700
const Lattice< dim > & A
Definition BiCrystal.h:56
LatticeVector< dim > shiftTensorB(const LatticeVector< dim > &d) const
LatticeVector< dim > getLatticeVectorInB(const LatticeVector< dim > &v) const
static MatrixDimI getLambdaA(const MatrixDimI &M, const MatrixDimI &N)
Definition BiCrystal.cpp:42
LatticeVector< dim > getLatticeVectorInD(const LatticeVector< dim > &v) const
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInD(const ReciprocalLatticeVector< dim > &v) const
LatticeVector< dim > shiftTensorA(const LatticeVector< dim > &d) const
const Lattice< dim > dscl
DCSL lattice .
Definition BiCrystal.h:90
const MatrixDimI LambdaB
Shift tensor describes the shift in the CSL when lattice is shifted by a DSCL vector.
Definition BiCrystal.h:108
const Lattice< dim > & B
Definition BiCrystal.h:57
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInA(const ReciprocalLatticeVector< dim > &v) const
LatticeCore< dim >::IntScalarType IntScalarType
Definition BiCrystal.h:30
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInC(const ReciprocalLatticeVector< dim > &v) const
LatticeCore< dim >::VectorDimI VectorDimI
Definition BiCrystal.h:33
LatticeVector< dim > getLatticeVectorInA(const LatticeVector< dim > &v) const
ReciprocalLatticeDirection< dim > getReciprocalLatticeDirectionInB(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, const bool &useRLLL)
LatticeDirection< dim > getLatticeDirectionInC(const LatticeVector< dim > &v) const
const Lattice< dim > csl
CSL lattice .
Definition BiCrystal.h:86
static MatrixDimI getN(const RationalMatrix< dim > &rm, const SmithDecomposition< dim > &sd)
Definition BiCrystal.cpp:29
LatticeDirection< dim > getLatticeDirectionInD(const LatticeVector< dim > &v) const
LatticeCore< dim >::MatrixDimI MatrixDimI
Definition BiCrystal.h:34
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....
static MatrixDimD getCSLBasis(const Lattice< dim > &A, const Lattice< dim > &B, const SmithDecomposition< dim > &sd, const MatrixDimI &M, const MatrixDimI &N, const bool &useRLLL)
Definition BiCrystal.cpp:82
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
LatticeCore< dim >::MatrixDimD MatrixDimD
Definition BiCrystal.h:32
static MatrixDimI getLambdaB(const MatrixDimI &M, const MatrixDimI &N)
Definition BiCrystal.cpp:62
static MatrixDimI getM(const RationalMatrix< dim > &rm, const SmithDecomposition< dim > &sd)
Definition BiCrystal.cpp:16
const MatrixDimI LambdaA
Shift tensor describes the shift in the CSL when lattice is shifted by a DSCL vector.
Definition BiCrystal.h:103
Definition Gb.h:16
Lattice class.
Definition Lattice.h:34
const MatrixDimD latticeBasis
Definition Lattice.h:46
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:169
LatticeVector class.
VectorDimD cartesian() const
const Lattice< dim > & lattice
static Eigen::Matrix< IntScalarType, dim, dim > adjoint(const Eigen::Matrix< IntScalarType, dim, dim > &input)
const MatrixType & reducedBasis() const
Definition RLLL.cpp:192
const IntScalarType & mu
std::enable_if< dm==2, LatticeDirection< dim > >::type cross(const ReciprocalLatticeVector< dim > &other) const
const MatrixNi & matrixD() const
const MatrixNi & matrixV() const
const MatrixNi & matrixX() const
static IntScalarType gcd(const IntScalarType &a, const IntScalarType &b)
Definition IntegerMath.h:33
static void solveDiophantine2vars(IntScalarType a, IntScalarType b, IntScalarType c, IntScalarType &x, IntScalarType &y)
LatticeDirection class.
int stacking() const
Returns the number of planes in the stacking sequence.
const ReciprocalLatticeVector< dim > & reciprocalLatticeVector() const
Returns a constant reference to the base class (ReciprocalLatticeVector)