oILAB
Loading...
Searching...
No Matches
Lattice.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_Lattice_cpp_
8#define gbLAB_Lattice_cpp_
9
10#include <Eigen/Eigenvalues>
11
12#include <LatticeModule.h>
13#include <GramMatrix.h>
14#include <iomanip>
15
16namespace gbLAB
17{
18
19
20// /**********************************************************************/
21// template <int dim>
22// typename Lattice<dim>::MatrixDimD Lattice<dim>::getLatticeBasis(const MatrixDimD &A, const MatrixDimD &Q)
23// {
24//
25// // Check that Q is orthogonal
26// const MatrixDimD QQT(Q * Q.transpose());
27// const double QQTerror((QQT - MatrixDimD::Identity()).norm());
28// if (QQTerror > 10.0 * DBL_EPSILON * dim * dim)
29// {
30// throw std::runtime_error("The rotation matrix Q is not orthogonal: norm(Q*Q^T-I)="+std::to_string(QQTerror)+"\n");
31// }
32//
33// const double Qdet(Q.determinant());
34// if (std::fabs(Q.determinant() - 1.0)>FLT_EPSILON)
35// {
36// throw std::runtime_error("The rotation matrix is not proper: det(Q)="+std::to_string(Qdet)+"\n");
37// }
38//
39// return Q * A;
40// }
41
42
43 /**********************************************************************/
44 /**********************************************************************/
45 template <int dim>
47 /* init */ latticeBasis(Fin*A)
48 /* init */,reciprocalBasis(latticeBasis.inverse().transpose())
49 /* init */,F(Fin)
50 {
51
52 }
53
54 /**********************************************************************/
55 template <int dim>
57 {
58 RLLL rlll(latticeBasis,0.75);
59 auto structureMatrix= rlll.reducedBasis();
60 auto U= rlll.unimodularMatrix();
61 Lattice<dim> reducedLattice(structureMatrix);
62 VectorDimD nd;
63 nd= reducedLattice.reciprocalBasis.transpose()*d;
64 LatticeVector<dim> tempReduced(LatticeCore<dim>::rationalApproximation(nd),reducedLattice);
65 VectorDimI tempRecovered= U*tempReduced;
66 LatticeVector<dim> temp(tempRecovered, *this);
67
68 const GramMatrix<double,2> G(std::array<VectorDimD,2>{temp.cartesian().normalized(),d.normalized()});
69 const double crossNorm(sqrt(G.determinant()));
70 if(crossNorm>tol)
71 {
72 std::cout<<"input direction="<<d.normalized().transpose()<<std::endl;
73 std::cout<<"lattice direction="<<temp.cartesian().normalized().transpose()<<std::endl;
74 std::cout<<"cross product norm="<<std::setprecision(15)<<std::scientific<<crossNorm<<std::endl;
75 std::cout<<"tolerance="<<std::setprecision(15)<<std::scientific<<tol<<std::endl;
76 throw std::runtime_error("LATTICE DIRECTION NOT FOUND\n");
77 }
78 return LatticeDirection<dim>(temp);
79 }
80
81 /**********************************************************************/
82 template <int dim>
84 {
85 RLLL rlll(latticeBasis,0.75);
86 auto structureMatrix= rlll.reducedBasis();
88 Lattice<dim> reducedLattice(structureMatrix);
89 VectorDimD nd;
90 nd= reducedLattice.latticeBasis.transpose()*d;
92 VectorDimI tempRecovered(MatrixDimIExt<IntScalarType,dim>::adjoint(U.matrix()).transpose()* tempReduced);
93 ReciprocalLatticeVector<dim> temp(tempRecovered, *this);
94
95 const GramMatrix<double,2> G(std::array<VectorDimD,2>{temp.cartesian().normalized(),d.normalized()});
96 const double crossNorm(sqrt(abs(G.determinant())));
97 if(crossNorm>tol)
98 {
99 std::cout<<"input direction="<<std::setprecision(15)<<std::scientific<<d.normalized().transpose()<<std::endl;
100 std::cout<<"reciprocal lattice direction="<<std::setprecision(15)<<std::scientific<<temp.cartesian().normalized().transpose()<<std::endl;
101 std::cout<<"cross product norm="<<std::setprecision(15)<<std::scientific<<crossNorm<<std::endl;
102 std::cout<<"tolerance="<<std::setprecision(15)<<std::scientific<<tol<<std::endl;
103 throw std::runtime_error("RECIPROCAL LATTICE DIRECTION NOT FOUND\n");
104 }
106 }
107
108 /**********************************************************************/
109 template <int dim>
111 const typename BestRationalApproximation::LongIntType& maxDen,
112 const double& magnitudeTol,
113 const double& directionTol) const
114 {
115 const LatticeDirection<dim> ld(latticeDirection(d,directionTol));
116 const BestRationalApproximation bra(d.norm() / ld.cartesian().norm(), maxDen);
117 const Rational rat(bra.num, bra.den);
118 const RationalLatticeDirection<dim> rld(rat, ld);
119 if ((rld.cartesian() - d).squaredNorm() > magnitudeTol)
120 {
121 std::cout << "input vector=" << d.transpose() << std::endl;
122 std::cout << "lattice direction=" << ld.cartesian().transpose() << std::endl;
123 std::cout << "rational=" << rat << std::endl;
124 std::cout << "d.norm()/ld.cartesian().norm()=" << d.norm() / ld.latticeVector().norm() << std::endl;
125 throw std::runtime_error("Rational Lattice DirectionType NOT FOUND\n");
126 }
127 return rld;
128 }
129
130 /**********************************************************************/
131
132 template <int dim>
134 const typename BestRationalApproximation::LongIntType &maxDen,
135 const double& magnitudeTol,
136 const double& directionTol) const
137 {
138 const ReciprocalLatticeDirection<dim> rld(reciprocalLatticeDirection(d,directionTol));
139 const BestRationalApproximation bra(d.norm() / rld.cartesian().norm(), maxDen);
140 const Rational rat(bra.num, bra.den);
141 const RationalReciprocalLatticeDirection<dim> rrld(rat, rld);
142 if ((rrld.cartesian() - d).squaredNorm() > magnitudeTol)
143 {
144 std::cout << "input reciprocal vector=" << d.transpose() << std::endl;
145 std::cout << "reciprocal lattice direction=" << rld.cartesian().transpose() << std::endl;
146 std::cout << "rational=" << rat << std::endl;
147 std::cout << "d.norm()/rld.cartesian().norm()=" << d.norm() / rld.reciprocalLatticeVector().norm() << std::endl;
148 throw std::runtime_error("Rational Reciprocal Lattice DirectionType NOT FOUND\n");
149 }
150 return rrld;
151 }
152
153 /**********************************************************************/
154 template <int dim>
156 {
157 return LatticeVector<dim>(p, *this);
158 }
159
160 /**********************************************************************/
161 template <int dim>
166
167 /**********************************************************************/
168 template<int dim>
170 const bool& useRLLL) const
171 {
172 assert(this == &l.lattice && "Vectors belong to different Lattices.");
174 auto matrix= IntegerMath<IntScalarType>::ccum(outOfPlaneVector);
175 std::vector<LatticeDirection<dim>> out;
176 int columnIndex= -1;
177 for(const auto& column : matrix.colwise())
178 {
179 columnIndex++;
180 if (columnIndex != 0)
181 out.push_back(LatticeDirection<dim>(column-column.dot(l.reciprocalLatticeVector())*matrix.col(0),*this));
182 else
183 out.push_back(LatticeDirection<dim>(column,*this));
184 }
185
186 if(!useRLLL) return out;
187
188 Eigen::MatrixXd planeParallelLatticeBasisCartesian(dim,dim-1);
189 int index= 0;
190 for(auto it=std::next(out.begin()); it!=out.end(); ++it)
191 {
192 planeParallelLatticeBasisCartesian.col(index)= (*it).cartesian();
193 index++;
194 }
195
196 if constexpr(dim>2){
197 const auto& rlll= RLLL(planeParallelLatticeBasisCartesian, 0.75);
198 planeParallelLatticeBasisCartesian= rlll.reducedBasis();
199 MatrixDimI outIntegerCoords;
200 for (int i=0; i<dim; ++i)
201 outIntegerCoords.col(i)= out[i].latticeVector();
202 Eigen::Matrix<IntScalarType,dim,dim-1> planeParallelLatticeBasisIntegerCoords= outIntegerCoords.block(0,1,dim,dim-1)*rlll.unimodularMatrix();
203 for (int i=1; i<dim; ++i)
204 out[i] = LatticeDirection<dim>(planeParallelLatticeBasisIntegerCoords.col(i-1),*this);
205 }
206 /*
207 if(dim>2) {
208 planeParallelLatticeBasisCartesian = RLLL(planeParallelLatticeBasisCartesian, 0.75).reducedBasis();
209 index = 1;
210 for (const auto &column: planeParallelLatticeBasisCartesian.colwise()) {
211 out[index] = this->latticeDirection(column);
212 index++;
213 }
214 }
215 */
216
217 // (A^T A)^{-1} A^T
218 Eigen::MatrixXd pseudoInverse(dim-1,dim);
219 pseudoInverse= (planeParallelLatticeBasisCartesian.transpose() * planeParallelLatticeBasisCartesian).inverse() *
220 (planeParallelLatticeBasisCartesian.transpose());
221
222 LatticeVector<dim> temp(*this);
223 for(int i=0;i<dim-1;i++)
224 {
225 temp= temp + round(out[0].cartesian().dot(pseudoInverse.row(i)))*out[i+1].latticeVector();
226 }
227 out[0]= LatticeDirection<dim>(out[0].latticeVector()-temp);
228
229
230 return out;
231 }
232
233 /**********************************************************************/
234 template<int dim>
235 std::vector<ReciprocalLatticeDirection<dim>> Lattice<dim>::directionOrthogonalReciprocalLatticeBasis(const LatticeDirection<dim>& l,
236 const bool& useRLLL) const
237 {
238 assert(this == &l.lattice && "Vectors belong to different Lattices.");
239 auto nonOrthogonalReciprocalVector= IntegerMath<IntScalarType>::solveBezout(l.latticeVector());
240 auto matrix= IntegerMath<IntScalarType>::ccum(nonOrthogonalReciprocalVector);
241 std::vector<ReciprocalLatticeDirection<dim>> out;
242 int columnIndex= -1;
243 for(const auto& column : matrix.colwise())
244 {
245 columnIndex++;
246 if (columnIndex != 0) {
247 VectorDimI temp= column - column.dot(l.latticeVector()) * matrix.col(0);
249 }
250 else {
251 VectorDimI temp = column;
253 }
254 }
255 if (!useRLLL) return out;
256
257 Eigen::MatrixXd directionOrthogonalReciprocalLatticeBasisCartesian(dim,dim-1);
258 int index= 0;
259 for(auto it=std::next(out.begin()); it!=out.end(); ++it)
260 {
261 directionOrthogonalReciprocalLatticeBasisCartesian.col(index)= (*it).cartesian();
262 index++;
263 }
264
265 if constexpr(dim>2) {
266 const auto &rlll = RLLL(directionOrthogonalReciprocalLatticeBasisCartesian, 0.75);
267 MatrixDimI outIntegerCoords;
268 for (int i = 0; i < dim; ++i)
269 outIntegerCoords.col(i) = out[i].reciprocalLatticeVector();
270 Eigen::Matrix<IntScalarType, dim, dim - 1> directionOrthogonalReciprocalLatticeBasisIntegerCoords =
271 outIntegerCoords.block(0, 1, dim, dim - 1) * rlll.unimodularMatrix();
272 for (int i = 1; i < dim; ++i)
274 directionOrthogonalReciprocalLatticeBasisIntegerCoords.col(i - 1), *this);
275 }
276
277 Eigen::MatrixXd pseudoInverse(dim-1,dim);
278 pseudoInverse= (directionOrthogonalReciprocalLatticeBasisCartesian.transpose() * directionOrthogonalReciprocalLatticeBasisCartesian).inverse() *
279 (directionOrthogonalReciprocalLatticeBasisCartesian.transpose());
280
282 for(int i=0;i<dim-1;i++)
283 {
284 temp= temp + round(out[0].cartesian().dot(pseudoInverse.row(i)))*out[i+1].reciprocalLatticeVector();
285 }
286 out[0]= ReciprocalLatticeDirection<dim>(out[0].reciprocalLatticeVector()-temp);
287 return out;
288
289 /*
290 directionOrthogonalReciprocalLatticeBasisCartesian= RLLL(directionOrthogonalReciprocalLatticeBasisCartesian,0.75).reducedBasis();
291 index= 1;
292 for(const auto& column : directionOrthogonalReciprocalLatticeBasisCartesian.colwise())
293 {
294 out[index]= this->reciprocalLatticeDirection(column);
295 index++;
296 }
297 return out;
298 */
299 }
300
301 /**********************************************************************/
302 template<int dim>
304 {
305 if(&(r.lattice) != this)
306 throw(std::runtime_error("The input reciprocal lattice vectors does not belong to the current lattice."));
307 return 1.0/r.cartesian().norm();
308 }
309
310 template<int dim> template<int dm>
311 typename std::enable_if<dm==3,std::vector<typename Lattice<dim>::MatrixDimD>>::type
312 Lattice<dim>::generateCoincidentLattices(const ReciprocalLatticeDirection<dim>& rd, const double& maxDen, const int& N) const
313 {
314 std::vector<MatrixDimD> output;
315 std::map<IntScalarType,MatrixDimD> temp;
316 auto basis= planeParallelLatticeBasis(rd);
317 double epsilon=1e-8;
318 IntScalarType keyScale= 1e6;
319
320 auto b1= basis[1].cartesian();
321 auto b2= basis[2].cartesian();
322
323 // Following the notation in Algorithm 3 of
324 // "Interface dislocations and grain boundary disconnections using Smith normal bicrystallography"
325 auto q1= b1;
326 std::vector<std::pair<int,int>> coPrimePairs= farey(N,false);
327 for(const auto& pair : coPrimePairs)
328 {
329 VectorDimI pIndices;
330 auto q2= pair.first*b1+pair.second*b2;
331
332 if (abs(q2.norm())<epsilon ) continue;
333 double ratio= q2.norm()/q1.norm();
334 BestRationalApproximation bra(ratio,maxDen);
335 double error= ratio-static_cast<double>(bra.num)/bra.den;
336 if (abs(error) > epsilon)
337 continue;
338 else
339 {
340 double cosTheta= b1.dot(q2)/(q1.norm()*q2.norm());
341 if (cosTheta-1>-epsilon) cosTheta= 1.0;
342 if (cosTheta+1<epsilon) cosTheta= -1.0;
343 double theta= acos(cosTheta);
344 MatrixDimD rotation;
345 rotation= Eigen::AngleAxis<double>(theta,rd.cartesian().normalized());
346 IntScalarType key= theta*keyScale;
347 temp.insert(std::pair<IntScalarType,MatrixDimD>(key,rotation));
348 }
349 }
350 std::transform(temp.begin(), temp.end(),
351 std::back_inserter(output),
352 [](const std::pair<IntScalarType,MatrixDimD>& p) {
353 return p.second;
354 });
355 return output;
356 }
357
358
359 template<int dim> template<int dm>
360 typename std::enable_if<dm==2,std::vector<typename Lattice<dim>::MatrixDimD>>::type
361 Lattice<dim>::generateCoincidentLattices(const double& maxStrain, const int& maxDen, const int& N) const
362 {
363 std::vector<MatrixDimD> output(generateCoincidentLattices(*this,maxStrain,maxDen,N));
364 return output;
365 }
366
367
368 template<int dim> template<int dm>
369 typename std::enable_if<dm==2,std::vector<typename Lattice<dim>::MatrixDimD>>::type
371 const double& maxStrain,
372 const int& maxDen,
373 const int& N) const
374 {
375 int numberOfConfigurations= 0;
376 const int maxConfigurations= 80;
377 std::vector<MatrixDimD> output;
378 std::map<IntScalarType,MatrixDimD> temp;
379 MatrixDimI mn(MatrixDimI::Zero());
380 MatrixDimI md(MatrixDimI::Ones());
381 std::vector<std::pair<int,int>> coPrimePairs= farey(N,false);
382 double epsilon=1e-8;
383 IntScalarType keyScale= 1e6;
384
385 for(const auto& pair1 : coPrimePairs)
386 {
387 VectorDimI pIndices;
388 pIndices << pair1.first, pair1.second;
389 LatticeVector<dm> q2(pIndices,undeformedLattice);
390 double ratio= q2.cartesian().norm() / latticeBasis.col(0).norm();
391
392
393 if (abs(maxStrain) < epsilon)
394 {
395 BestRationalApproximation alpha(ratio, maxDen);
396 double error = ratio - static_cast<double>(alpha.num) / alpha.den;
397 if (abs(error) > epsilon)
398 continue;
399 else
400 {
401 double cosTheta = latticeBasis.col(0).dot(q2.cartesian()) / (latticeBasis.col(0).norm() * q2.cartesian().norm());
402 if (cosTheta - 1 > -epsilon) cosTheta = 1.0;
403 if (cosTheta + 1 < epsilon) cosTheta = -1.0;
404 double theta = acos(cosTheta);
405 Eigen::Rotation2D<double> rotation(theta);
406 IntScalarType key= theta*keyScale;
407 temp.insert(std::pair<IntScalarType,MatrixDimD>(key,rotation.toRotationMatrix()));
408 }
409 }
410 else
411 {
412 RationalApproximations <IntScalarType> alphaSequence(ratio, maxDen, ratio*maxStrain);
413 for (const auto& alpha: alphaSequence.approximations)
414 {
415 RationalLatticeDirection<dm> q2ByAlpha(Rational<IntScalarType>(alpha.d, alpha.n), q2);
416
417 mn.col(0) = q2 * alpha.d;
418 md.col(0).setConstant(alpha.n);
419
420 double s1 =
421 (q2ByAlpha.cartesian().squaredNorm() - latticeBasis.col(0).squaredNorm()) /
422 latticeBasis.col(0).squaredNorm();
423 if (abs(s1) > maxStrain) continue;
424
425 for (const auto &pair2: coPrimePairs) {
426 VectorDimI qIndices;
427 qIndices << pair2.first, pair2.second;
428 LatticeVector<dm> r2(qIndices, undeformedLattice);
429 double ratio2= r2.cartesian().norm() / latticeBasis.col(1).norm();
430 RationalApproximations<IntScalarType> betaSequence(ratio2, maxDen,maxStrain*ratio2);
431 for(const auto& beta : betaSequence.approximations) {
432 RationalLatticeDirection<dm> r2ByBeta(Rational<IntScalarType>(beta.d, beta.n), r2);
433 double s2 = (r2ByBeta.cartesian().squaredNorm() - latticeBasis.col(1).squaredNorm()) /
434 latticeBasis.col(1).squaredNorm();
435 double s3 = (q2ByAlpha.cartesian().dot(r2ByBeta.cartesian()) -
436 latticeBasis.col(0).dot(latticeBasis.col(1))) /
437 (latticeBasis.col(0).norm() * latticeBasis.col(1).norm());
438 if (abs(s2) > maxStrain || abs(s3) > maxStrain) continue;
439
440 // calculate the deformation gradient
441 MatrixDimD F = q2ByAlpha.cartesian() * reciprocalBasis.col(0).transpose() +
442 r2ByBeta.cartesian() * reciprocalBasis.col(1).transpose();
443 if (F.determinant() < 0) continue;
444
445 output.push_back( F );
446 numberOfConfigurations++;
447 std::cout << numberOfConfigurations << std::endl;
448 if (numberOfConfigurations == maxConfigurations)
449 return output;
450 }
451 }
452 }
453 }
454 }
455 // sort the angles if rotations are being asked
456 if (abs(maxStrain) < epsilon)
457 std::transform(temp.begin(), temp.end(),
458 std::back_inserter(output),
459 [](const std::pair<IntScalarType,MatrixDimD>& p) {
460 return p.second;
461 });
462 return output;
463 }
464
465 template<int dim> template<int dm>
466 typename std::enable_if<dm==3,std::vector<LatticeVector<dim>>>::type
467 Lattice<dim>::box(const std::vector<LatticeVector<dim>>& boxVectors, const std::string& filename) const
468 {
469 for(const LatticeVector<dim>& boxVector : boxVectors)
470 {
471 assert(this == &boxVector.lattice && "Box vectors belong to different lattice.");
472 }
473
474 // Form the box lattice
475 MatrixDimD C;
476 for (int i=0; i<dim; ++i) {
477 C.col(i) = boxVectors[i].cartesian();
478 }
479 assert(C.determinant() != 0);
480 Lattice<dim> boxLattice(C);
481
482 auto planeParallelBasis= planeParallelLatticeBasis(boxVectors[1].cross(boxVectors[2]),true);
483 MatrixDimD A;
484 MatrixDimI mat;
485 for(int i=0; i<dim; ++i) {
486 A.col(i) = planeParallelBasis[i].cartesian();
487 mat.col(i)=planeParallelBasis[i].latticeVector();
488 }
489
490 // l - lattice with plane parallel basis, where the second and third basis vectors
491 // lie on the plane spanned by boxVectors[1] and boxVectors[2]
492 Lattice<dim> l(A);
493
494 // Form plane parallel vectors v1 and v2
495 // v1 is along boxVector[1]
497 assert(v1.latticeVector()(0)==0);
498 IntScalarType x,y;
500 LatticeVector<dim> temp(l);
501 temp << 0,y,x;
502 LatticeDirection<dim> v2(temp);
503
504 int areaRatio= round((boxLattice.latticeBasis.col(1).cross(boxLattice.latticeBasis.col(2))).norm()/
505 (l.latticeBasis.col(1).cross(l.latticeBasis.col(2))).norm());
506 int scale1= abs(IntegerMath<IntScalarType>::gcd(boxVectors[1]));
507 int scale2= round(areaRatio/scale1);
508 int scale0= round(abs(C.determinant()/latticeBasis.determinant()/areaRatio));
509
510 std::vector<LatticeVector<dim>> output;
511
512 // r0, r1, and r2 are reciprocal vectors perpendicular to areas spanned by boxVectors[0],
513 // boxVectors[1], and boxVectors[2]
514 ReciprocalLatticeVector<dim> r0_temp(*this), r1_temp(*this), r2_temp(*this);
515 r0_temp= (boxVectors[1].cross(boxVectors[2])).reciprocalLatticeVector();
516 if (r0_temp.dot(boxVectors[0]) < 0)
517 r0_temp=-1*r0_temp;
518 r1_temp= (boxVectors[2].cross(boxVectors[0])).reciprocalLatticeVector();
519 if (r1_temp.dot(boxVectors[1]) < 0)
520 r1_temp=-1*r1_temp;
521 r2_temp= (boxVectors[0].cross(boxVectors[1])).reciprocalLatticeVector();
522 if (r2_temp.dot(boxVectors[2]) < 0)
523 r2_temp=-1*r2_temp;
524 assert(r0_temp.dot(boxVectors[1])==0 && r0_temp.dot(boxVectors[2])==0);
525 assert(r1_temp.dot(boxVectors[0])==0 && r1_temp.dot(boxVectors[2])==0);
526 assert(r2_temp.dot(boxVectors[0])==0 && r2_temp.dot(boxVectors[1])==0);
527 ReciprocalLatticeDirection<dim> r0(r0_temp), r1(r1_temp), r2(r2_temp);
528
529 for(int i=0; i<scale0; ++i)
530 {
531 for(int j=0; j<scale1; ++j)
532 {
533 for(int k=0; k<scale2; ++k) {
534 LatticeVector<dim> vectorIn_l(l);
535 vectorIn_l << i, 0, 0;
536 vectorIn_l= vectorIn_l + j*v1.latticeVector()+k*v2.latticeVector();
537 //LatticeVector<dim> vector(latticeVector(vectorIn_l.cartesian()));
538 LatticeVector<dim> vector((mat*vectorIn_l).eval(),*this);
539 //LatticeDirection<dim> v1(MatrixDimIExt<IntScalarType,dim>::adjoint(mat)*boxVectors[1],l);
540
541 int c0= IntegerMath<IntScalarType>::positive_modulo(vector.dot(r0),boxVectors[0].dot(r0)) -
542 vector.dot(r0);
543 c0= c0/boxVectors[0].dot(r0);
544 int c1= IntegerMath<IntScalarType>::positive_modulo(vector.dot(r1),boxVectors[1].dot(r1)) -
545 vector.dot(r1);
546 c1= c1/boxVectors[1].dot(r1);
547 int c2= IntegerMath<IntScalarType>::positive_modulo(vector.dot(r2),boxVectors[2].dot(r2)) -
548 vector.dot(r2);
549 c2= c2/boxVectors[2].dot(r2);
550 vector= vector+c0*boxVectors[0]+c1*boxVectors[1]+c2*boxVectors[2];
551 output.push_back(vector);
552 }
553 }
554 }
555
556 if(!filename.empty()) {
557 std::ofstream file;
558 file.open(filename);
559 if (!file) std::cerr << "Unable to open file";
560 file << output.size() << std::endl;
561 file << "Lattice=\"";
562
563 for(const auto& vector:boxVectors) {
564 file << vector.cartesian().transpose() << " ";
565 }
566 file << "\" Properties=atom_types:I:1:pos:R:3" << std::endl;
567
568 for (const auto &vector: output)
569 file << 1 << " " << vector.cartesian().transpose() << std::endl;
570
571 file.close();
572 }
573 return output;
574 }
575
576
577 template<int dim> template<int dm>
578 typename std::enable_if<dm==2,std::vector<LatticeVector<dim>>>::type
579 Lattice<dim>::box(const std::vector<LatticeVector<dim>>& boxVectors, const std::string& filename) const
580 {
581 for(const LatticeVector<dim>& boxVector : boxVectors)
582 {
583 assert(this == &boxVector.lattice && "Box vectors belong to different lattice.");
584 }
585
586 // Form the box lattice
587 MatrixDimD C;
588 for (int i=0; i<dim; ++i) {
589 C.col(i) = boxVectors[i].cartesian();
590 }
591 assert(C.determinant() != 0);
592 Lattice<dim> boxLattice(C);
593
594 // Form plane parallel vectors v0 and v1
595 //LatticeDirection<dim> v0(this->latticeDirection(boxVectors[0].cartesian()));
596 LatticeDirection<dim> v0(
597 (VectorDimI) boxVectors[0]/IntegerMath<IntScalarType>::gcd(boxVectors[0]),
598 *this);
599
600 ReciprocalLatticeVector<dim> temp(*this);
601 temp << v0.latticeVector()(1),-v0.latticeVector()(0);
602 LatticeDirection<dim> v1(planeParallelLatticeBasis(temp,true)[0]);
603
604 /*
605 IntScalarType x,y;
606 IntegerMath<IntScalarType>::extended_gcd(v0.latticeVector()(0),-v0.latticeVector()(1),x,y);
607 LatticeVector<dim> temp(*this);
608 temp << y,x;
609
610 LatticeDirection<dim> v1(temp);
611 */
612
613 int areaRatio= round(abs(boxLattice.latticeBasis.determinant()/
614 (*this).latticeBasis.determinant()));
615
616 int scale1= abs(IntegerMath<IntScalarType>::gcd(boxVectors[0]));
617 int scale2= round(areaRatio/scale1);
618
619 std::vector<LatticeVector<dim>> output;
620
621 // r0 and r1 are reciprocal vectors perpendicular to boxVectors[1] and boxVectors[0], respectively.
622 ReciprocalLatticeVector<dim> r1_temp(*this), r0_temp(*this);
623 r1_temp << boxVectors[0](1),-boxVectors[0](0);
624 if (r1_temp.dot(boxVectors[1]) < 0)
625 r1_temp=-1*r1_temp;
626 r0_temp << boxVectors[1](1),-boxVectors[1](0);
627 if (r0_temp.dot(boxVectors[0]) < 0)
628 r0_temp=-1*r0_temp;
629 assert(r1_temp.dot(boxVectors[0])==0);
630 assert(r0_temp.dot(boxVectors[1])==0);
631 ReciprocalLatticeDirection<dim> r1(r1_temp), r0(r0_temp);
632
633 for(int j=0; j<scale1; ++j)
634 {
635 for(int k=0; k<scale2; ++k) {
636 LatticeVector<dim> vector(j*v0.latticeVector()+k*v1.latticeVector());
637 int c1= IntegerMath<IntScalarType>::positive_modulo(vector.dot(r1),boxVectors[1].dot(r1)) -
638 vector.dot(r1);
639 c1= c1/boxVectors[1].dot(r1);
640 int c2= IntegerMath<IntScalarType>::positive_modulo(vector.dot(r0),boxVectors[0].dot(r0)) -
641 vector.dot(r0);
642 c2= c2/boxVectors[0].dot(r0);
643 vector= vector+c1*boxVectors[1]+c2*boxVectors[0];
644 output.push_back(vector);
645 }
646 }
647
648 if(!filename.empty()) {
649 std::ofstream file;
650 file.open(filename);
651 if (!file) std::cerr << "Unable to open file";
652 file << output.size() << std::endl;
653 file << "Lattice=\"";
654
655 for(const auto& vector:boxVectors) {
656 file << vector.cartesian().transpose() << " 0 ";
657 }
658 file << " 0 0 1 ";
659 file << "\" Properties=atom_types:I:1:pos:R:3" << std::endl;
660
661 for (const auto &vector: output)
662 file << 1 << " " << vector.cartesian().transpose() << " 0 " << std::endl;
663
664 file.close();
665 }
666 return output;
667 }
668
669
670 template class Lattice<1>;
671
672 template class Lattice<2>;
673 template std::vector<typename Lattice<2>::MatrixDimD> Lattice<2>::generateCoincidentLattices<2>(
674 const double &maxStrain, const int &maxDen, const int &N) const;
675 template std::vector<typename Lattice<2>::MatrixDimD> Lattice<2>::generateCoincidentLattices<2>(
676 const Lattice<2> &undeformedLattice, const double &maxStrain, const int &maxDen, const int &N) const;
677 template std::vector<LatticeVector<2>> Lattice<2>::box<2>(const std::vector<LatticeVector<2>> &boxVectors,
678 const std::string &filename) const;
679
680
681 template class Lattice<3>;
682 template std::vector<typename Lattice<3>::MatrixDimD> Lattice<3>::generateCoincidentLattices<3>(
683 const ReciprocalLatticeDirection<3> &rd, const double &maxDen, const int& N) const;
684 template std::vector<LatticeVector<3>> Lattice<3>::box<3>(const std::vector<LatticeVector<3>> &boxVectors,
685 const std::string &filename) const;
686
687 template class Lattice<4>;
688 template class Lattice<5>;
689}
690#endif
Lattice class.
Definition Lattice.h:34
typename LatticeCore< dim >::VectorDimD VectorDimD
Definition Lattice.h:37
RationalReciprocalLatticeDirection< dim > rationalReciprocalLatticeDirection(const VectorDimD &d, const typename BestRationalApproximation::LongIntType &maxDen, const double &magnitudeTol, const double &directionTol=FLT_EPSILON) const
Definition Lattice.cpp:133
double interPlanarSpacing(const ReciprocalLatticeDirection< dim > &r) const
Computes the interplanar spacing.
Definition Lattice.cpp:303
const MatrixDimD latticeBasis
Definition Lattice.h:46
const MatrixDimD reciprocalBasis
Definition Lattice.h:47
std::enable_if< dm==3, std::vector< MatrixDimD > >::type generateCoincidentLattices(const ReciprocalLatticeDirection< dim > &rd, const double &maxDen=100, const int &N=100) const
Definition Lattice.cpp:312
std::vector< ReciprocalLatticeDirection< dim > > directionOrthogonalReciprocalLatticeBasis(const LatticeDirection< dim > &l, const bool &useRLLL=false) const
Given a lattice direction , this function returns a direction-orthogonal reciprocal lattice basis ,...
Definition Lattice.cpp:235
typename LatticeCore< dim >::IntScalarType IntScalarType
Definition Lattice.h:41
typename LatticeCore< dim >::MatrixDimD MatrixDimD
Definition Lattice.h:38
ReciprocalLatticeVector< dim > reciprocalLatticeVector(const VectorDimD &p) const
Returns a reciprocal lattice vector (in the dual of the current lattice) with Cartesian coordinates p...
Definition Lattice.cpp:162
std::enable_if< dm==3, std::vector< LatticeVector< dim > > >::type box(const std::vector< LatticeVector< dim > > &boxVectors, const std::string &filename="") const
Definition Lattice.cpp:467
Lattice(const MatrixDimD &A, const MatrixDimD &Q=MatrixDimD::Identity())
Definition Lattice.cpp: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
typename LatticeCore< dim >::MatrixDimI MatrixDimI
Definition Lattice.h:40
LatticeVector< dim > latticeVector(const VectorDimD &p) const
Returns a lattice vector (in the current lattice) with Cartesian coordinates p.
Definition Lattice.cpp:155
RationalLatticeDirection< dim > rationalLatticeDirection(const VectorDimD &d, const typename BestRationalApproximation::LongIntType &maxDen, const double &magnitudeTol, const double &directionTol=FLT_EPSILON) const
Definition Lattice.cpp:110
typename LatticeCore< dim >::VectorDimI VectorDimI
Definition Lattice.h:39
ReciprocalLatticeDirection< dim > reciprocalLatticeDirection(const VectorDimD &d, const double &tol=FLT_EPSILON) const
Returns the reciprocal lattice direction along a vector.
Definition Lattice.cpp:83
LatticeDirection< dim > latticeDirection(const VectorDimD &d, const double &tol=FLT_EPSILON) const
Returns the lattice direction along a vector.
Definition Lattice.cpp:56
LatticeVector class.
VectorDimD cartesian() const
const Lattice< dim > & lattice
IntScalarType dot(const ReciprocalLatticeVector< dim > &other) const
const MatrixType & reducedBasis() const
Definition RLLL.cpp:192
const Eigen::Matrix< long long int, Eigen::Dynamic, Eigen::Dynamic > & unimodularMatrix() const
Definition RLLL.cpp:198
std::vector< Rational< IntScalarType > > approximations
IntScalarType dot(const LatticeVector< dim > &other) const
std::vector< std::pair< int, int > > farey(int limit, const bool firstQuadrant)
Definition Farey.cpp:6
static Eigen::Matrix< IntScalarType, Eigen::Dynamic, Eigen::Dynamic > ccum(const Eigen::MatrixBase< T > &qin)
static IntScalarType gcd(const IntScalarType &a, const IntScalarType &b)
Definition IntegerMath.h:33
static IntScalarType positive_modulo(IntScalarType i, IntScalarType n)
Definition IntegerMath.h:24
static Eigen::Vector< IntScalarType, Eigen::Dynamic > solveBezout(const Eigen::MatrixBase< T > &a)
static IntScalarType extended_gcd(IntScalarType a, IntScalarType b, IntScalarType &x, IntScalarType &y)
LatticeDirection class.
const LatticeVector< dim > & latticeVector() const
const ReciprocalLatticeVector< dim > & reciprocalLatticeVector() const
Returns a constant reference to the base class (ReciprocalLatticeVector)