Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidGeometry/Crystal/UnitCell.h"
#include "MantidKernel/Matrix.h"
#include "MantidKernel/StringTokenizer.h"
#include "MantidKernel/System.h"
#include "MantidKernel/V3D.h"
#include <cfloat>
#include <iomanip>
#include <ios>
#include <boost/lexical_cast.hpp>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
namespace Mantid {
namespace Geometry {
using Mantid::Kernel::DblMatrix;
using Mantid::Kernel::V3D;
/** Default constructor.
\f$ a = b = c = 1 \mbox{\AA, } \alpha = \beta = \gamma = 90^\circ \f$ */
UnitCell::UnitCell()
: da(6), ra(6), errorda(6), G(3, 3), Gstar(3, 3), B(3, 3), ModHKL(3, 3),
errorModHKL(3, 3) {
da[0] = da[1] = da[2] = 1.;
da[3] = da[4] = da[5] = deg2rad * 90.0;
errorda[0] = errorda[1] = errorda[2] = errorda[3] = errorda[4] = errorda[5] =
0.0;
MaxOrder = 0;
CrossTerm = false;
recalculate();
}
/** Constructor
@param _a, _b, _c :: lattice parameters \f$ a, b, c \f$ \n
with \f$\alpha = \beta = \gamma = 90^\circ \f$*/
UnitCell::UnitCell(double _a, double _b, double _c)
: da(6), ra(6), errorda(6), G(3, 3), Gstar(3, 3), B(3, 3), ModHKL(3, 3),
errorModHKL(3, 3) {
da[0] = _a;
da[1] = _b;
da[2] = _c;
// Angles are 90 degrees in radians ->Pi/2
da[3] = da[4] = da[5] = 0.5 * M_PI;
errorda[0] = errorda[1] = errorda[2] = errorda[3] = errorda[4] = errorda[5] =
0.0;
MaxOrder = 0;
CrossTerm = false;
recalculate();
}
/** Constructor
@param _a, _b, _c, _alpha, _beta, _gamma :: lattice parameters\n
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
UnitCell::UnitCell(double _a, double _b, double _c, double _alpha, double _beta,
double _gamma, const int angleunit)
: da(6), ra(6), errorda(6), G(3, 3), Gstar(3, 3), B(3, 3), ModHKL(3, 3),
errorModHKL(3, 3) {
da[0] = _a;
da[1] = _b;
da[2] = _c;
// Angle transformed in radians
if (angleunit == angDegrees) {
da[3] = deg2rad * _alpha;
da[4] = deg2rad * _beta;
da[5] = deg2rad * _gamma;
} else {
da[3] = _alpha;
da[4] = _beta;
da[5] = _gamma;
}
errorda[0] = errorda[1] = errorda[2] = errorda[3] = errorda[4] = errorda[5] =
0.0;
MaxOrder = 0;
CrossTerm = false;
recalculate();
}
/** Get lattice parameter
@return a1 :: lattice parameter \f$ a \f$ (in \f$ \mbox{\AA} \f$ )
@see a()*/
double UnitCell::a1() const { return da[0]; }
/** Get lattice parameter
@return a2 :: lattice parameter \f$ b \f$ (in \f$ \mbox{\AA} \f$ )
@see b()*/
double UnitCell::a2() const { return da[1]; }
/** Get lattice parameter
@return a3 :: lattice parameter \f$ c \f$ (in \f$ \mbox{\AA} \f$ )
@see c()*/
double UnitCell::a3() const { return da[2]; }
/** Get lattice parameter a1-a3 as function of index (0-2)
@return a_n :: lattice parameter \f$ a,b or c \f$ (in \f$ \mbox{\AA} \f$ )
*/
double UnitCell::a(int nd) const {
if (nd < 0 || nd > 2)
throw(std::invalid_argument(
"lattice parameter index can change from 0 to 2 "));
return da[nd];
}
/** Get lattice parameter
@return alpha1 :: lattice parameter \f$ \alpha \f$ (in radians)
@see alpha()*/
double UnitCell::alpha1() const { return da[3]; }
/** Get lattice parameter
@return alpha2 :: lattice parameter \f$ \beta \f$ (in radians)
@see beta()*/
double UnitCell::alpha2() const { return da[4]; }
/** Get lattice parameter
@return alpha3 :: lattice parameter \f$ \gamma \f$ (in radians)
@see gamma()*/
double UnitCell::alpha3() const { return da[5]; }
/** Get lattice parameter
@return a :: lattice parameter \f$ a \f$ (in \f$ \mbox{\AA} \f$ )
@see a1()*/
double UnitCell::a() const { return da[0]; }
/** Get lattice parameter
@return b :: lattice parameter \f$ b \f$ (in \f$ \mbox{\AA} \f$ )
@see a2()*/
double UnitCell::b() const { return da[1]; }
/** Get lattice parameter
@return c :: lattice parameter \f$ c \f$ (in \f$ \mbox{\AA} \f$ )
@see a3()*/
double UnitCell::c() const { return da[2]; }
/** Get lattice parameter
@return alpha :: lattice parameter \f$ \alpha \f$ (in degrees)
@see alpha1()*/
double UnitCell::alpha() const { return da[3] * rad2deg; }
/** Get lattice parameter
@return beta :: lattice parameter \f$ \beta \f$ (in degrees)
@see alpha2()*/
double UnitCell::beta() const { return da[4] * rad2deg; }
/** Get lattice parameter
@return gamma :: lattice parameter \f$ \gamma \f$ (in degrees)
@see alpha3()*/
double UnitCell::gamma() const { return da[5] * rad2deg; }
/** Get reciprocal lattice parameter
@return b1 :: lattice parameter \f$ a^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see astar()*/
double UnitCell::b1() const { return ra[0]; }
/** Get reciprocal lattice parameter
@return b2 :: lattice parameter \f$ b^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see bstar()*/
double UnitCell::b2() const { return ra[1]; }
/** Get reciprocal lattice parameter
@return b3 :: lattice parameter \f$ c^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see cstar()*/
double UnitCell::b3() const { return ra[2]; }
/** Get reciprocal lattice parameter
@return beta1 :: lattice parameter \f$ \alpha^{*} \f$ (in radians)
@see alphastar()*/
double UnitCell::beta1() const { return ra[3]; }
/** Get reciprocal lattice parameter
@return beta2 :: lattice parameter \f$ \beta^{*} \f$ (in radians)
@see betastar()*/
double UnitCell::beta2() const { return ra[4]; }
/** Get reciprocal lattice parameter
@return beta3 :: lattice parameter \f$ \gamma^{*} \f$ (in radians)
@see gammastar()*/
double UnitCell::beta3() const { return ra[5]; }
/** Get reciprocal lattice parameter
@return astar :: lattice parameter \f$ a^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see b1()*/
double UnitCell::astar() const { return ra[0]; }
/** Get reciprocal lattice parameter
@return bstar :: lattice parameter \f$ b^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see b2()*/
double UnitCell::bstar() const { return ra[1]; }
/** Get reciprocal lattice parameter
@return cstar :: lattice parameter \f$ c^{*} \f$ (in \f$ \mbox{\AA}^{-1} \f$ )
@see b3()*/
double UnitCell::cstar() const { return ra[2]; }
/** Get reciprocal lattice parameter
@return alphastar :: lattice parameter \f$ \alpha^{*} \f$ (in degrees)
@see beta1()*/
double UnitCell::alphastar() const { return ra[3] * rad2deg; }
/** Get reciprocal lattice parameter
@return betastar:: lattice parameter \f$ \beta^{*} \f$ (in degrees)
@see beta2()*/
double UnitCell::betastar() const { return ra[4] * rad2deg; }
/** Get reciprocal lattice parameter
@return gammastar:: lattice parameter \f$ \gamma^{*} \f$ (in degrees)
@see beta3()*/
double UnitCell::gammastar() const { return ra[5] * rad2deg; }
/** Get lattice parameter error
@return errora :: errorlattice parameter \f$ a \f$ (in \f$ \mbox{\AA} \f$ )
*/
double UnitCell::errora() const { return errorda[0]; }
/** Get lattice parameter error
@return errorb :: errorlattice parameter \f$ b \f$ (in \f$ \mbox{\AA} \f$ )
*/
double UnitCell::errorb() const { return errorda[1]; }
/** Get lattice parameter error
@return errorc :: errorlattice parameter \f$ c \f$ (in \f$ \mbox{\AA} \f$ )
*/
double UnitCell::errorc() const { return errorda[2]; }
/** Get lattice parameter error
@param angleunit :: units for angle, of type #AngleUnits . Default is degrees.
@return erroralpha :: errorlattice parameter \f$ alpha \f$ (in degrees or
radians )
*/
double UnitCell::erroralpha(const int angleunit) const {
if (angleunit == angDegrees) {
return errorda[3] * rad2deg;
} else {
return errorda[3];
}
}
/** Get lattice parameter error
@param angleunit :: units for angle, of type #AngleUnits . Default is degrees.
@return erroralpha :: errorlattice parameter \f$ beta \f$ (in degrees or
radians
)
*/
double UnitCell::errorbeta(const int angleunit) const {
if (angleunit == angDegrees) {
return errorda[4] * rad2deg;
} else {
return errorda[4];
}
}
/** Get lattice parameter error
@param angleunit :: units for angle, of type #AngleUnits . Default is degrees.
@return erroralpha :: errorlattice parameter \f$ gamma \f$ (in degrees or
radians )
*/
double UnitCell::errorgamma(const int angleunit) const {
if (angleunit == angDegrees) {
return errorda[5] * rad2deg;
} else {
return errorda[5];
}
}
/** Get lattice parameter error
@return errorc :: errorlattice parameter \f$ volume \f$ (in \f$ \mbox{\AA} \f$
)
*/
double UnitCell::errorvolume() const {
// From latcon.py by Art Schultz
double V = volume();
double delta_V_alphaV = 0.0;
if (erroralpha() > 0.0) {
double alpha1 = alpha() - 0.5 * erroralpha();
double Va1 = UnitCell(a(), b(), c(), alpha1, beta(), gamma()).volume();
double alpha2 = alpha() + 0.5 * erroralpha();
double Va2 = UnitCell(a(), b(), c(), alpha2, beta(), gamma()).volume();
delta_V_alphaV = (Va2 - Va1) / V;
}
double delta_V_betaV = 0.0;
if (errorbeta() > 0.0) {
double beta1 = beta() - 0.5 * errorbeta();
double Va1 = UnitCell(a(), b(), c(), alpha(), beta1, gamma()).volume();
double beta2 = beta() + 0.5 * errorbeta();
double Va2 = UnitCell(a(), b(), c(), alpha(), beta2, gamma()).volume();
delta_V_betaV = (Va2 - Va1) / V;
}
double delta_V_gammaV = 0.0;
if (errorgamma() > 0.0) {
double gamma1 = gamma() - 0.5 * errorgamma();
double Va1 = UnitCell(a(), b(), c(), alpha(), beta(), gamma1).volume();
double gamma2 = gamma() + 0.5 * errorgamma();
double Va2 = UnitCell(a(), b(), c(), alpha(), beta(), gamma2).volume();
delta_V_gammaV = (Va2 - Va1) / V;
}
return V * sqrt(std::pow(errora() / a(), 2) + std::pow(errorb() / b(), 2) +
std::pow(errorc() / c(), 2) + std::pow(delta_V_alphaV, 2) +
std::pow(delta_V_betaV, 2) + std::pow(delta_V_gammaV, 2));
}
/** Set lattice parameters
@param _a, _b, _c, _alpha, _beta, _gamma :: lattice parameters\n
@param angleunit :: units for angle, of type #AngleUnits . Default is degrees.
*/
void UnitCell::set(double _a, double _b, double _c, double _alpha, double _beta,
double _gamma, const int angleunit) {
da[0] = _a;
da[1] = _b;
da[2] = _c;
if (angleunit == angDegrees) {
da[3] = deg2rad * _alpha;
da[4] = deg2rad * _beta;
da[5] = deg2rad * _gamma;
} else {
da[3] = _alpha;
da[4] = _beta;
da[5] = _gamma;
}
recalculate();
}
/** Set lattice parameter errors
@param _aerr, _berr, _cerr, _alphaerr, _betaerr, _gammaerr :: lattice
parameter errors\n
@param angleunit :: units for angle, of type #AngleUnits . Default is degrees.
*/
void UnitCell::setError(double _aerr, double _berr, double _cerr,
double _alphaerr, double _betaerr, double _gammaerr,
const int angleunit) {
errorda[0] = _aerr;
errorda[1] = _berr;
errorda[2] = _cerr;
if (angleunit == angDegrees) {
errorda[3] = deg2rad * _alphaerr;
errorda[4] = deg2rad * _betaerr;
errorda[5] = deg2rad * _gammaerr;
} else {
errorda[3] = _alphaerr;
errorda[4] = _betaerr;
errorda[5] = _gammaerr;
}
}
/** Set modulation vectors for satellites
@param _dh1 offset for H for first vector
@param _dk1 offset for K for first vector
@param _dl1 offset for l for first vector
@param _dh2 offset for H for second vector
@param _dk2 offset for K for second vector
@param _dl2 offset for l for second vector
@param _dh3 offset for H for third vector
@param _dk3 offset for K for third vector
@param _dl3 offset for l for third vector
*/
void UnitCell::setModHKL(double _dh1, double _dk1, double _dl1, double _dh2,
double _dk2, double _dl2, double _dh3, double _dk3,
double _dl3) {
ModHKL[0][0] = _dh1;
ModHKL[1][0] = _dk1;
ModHKL[2][0] = _dl1;
ModHKL[0][1] = _dh2;
ModHKL[1][1] = _dk2;
ModHKL[2][1] = _dl2;
ModHKL[0][2] = _dh3;
ModHKL[1][2] = _dk3;
ModHKL[2][2] = _dl3;
}
/** Set modulation vectors for satellites
@param newModHKL modulation vectors for HKL for three vectors
*/
void UnitCell::setModHKL(const DblMatrix &newModHKL) { ModHKL = newModHKL; }
/** Set modulation vectors for satellites
@param newErrorModHKL errors for modulation vectors for HKL for three vectors
*/
void UnitCell::setErrorModHKL(const DblMatrix &newErrorModHKL) {
errorModHKL = newErrorModHKL;
}
/** Set modulation vectors for satellites
@param _dh1err error for offset for H for first vector
@param _dk1err error for offset for K for first vector
@param _dl1err error for offset for l for first vector
@param _dh2err error for offset for H for second vector
@param _dk2err error for offset for K for second vector
@param _dl2err error for offset for l for second vector
@param _dh3err error for offset for H for third vector
@param _dk3err error for offset for K for third vector
@param _dl3err error for offset for l for third vector
*/
void UnitCell::setErrorModHKL(double _dh1err, double _dk1err, double _dl1err,
double _dh2err, double _dk2err, double _dl2err,
double _dh3err, double _dk3err, double _dl3err) {
errorModHKL[0][0] = _dh1err;
errorModHKL[1][0] = _dk1err;
errorModHKL[2][0] = _dl1err;
errorModHKL[0][1] = _dh2err;
errorModHKL[1][1] = _dk2err;
errorModHKL[2][1] = _dl2err;
errorModHKL[0][2] = _dh3err;
errorModHKL[1][2] = _dk3err;
errorModHKL[2][2] = _dl3err;
}
/** Set modulation vectors for satellites
@param _dh1 offset for H for first vector
@param _dk1 offset for K for first vector
@param _dl1 offset for l for first vector
*/
void UnitCell::setModVec1(double _dh1, double _dk1, double _dl1) {
ModHKL[0][0] = _dh1;
ModHKL[1][0] = _dk1;
ModHKL[2][0] = _dl1;
}
/** Set modulation vectors for satellites
@param _dh2 offset for H for second vector
@param _dk2 offset for K for second vector
@param _dl2 offset for l for second vector
*/
void UnitCell::setModVec2(double _dh2, double _dk2, double _dl2) {
ModHKL[0][1] = _dh2;
ModHKL[1][1] = _dk2;
ModHKL[2][1] = _dl2;
}
/** Set modulation vectors for satellites
@param _dh3 offset for H for third vector
@param _dk3 offset for K for third vector
@param _dl3 offset for l for third vector
*/
void UnitCell::setModVec3(double _dh3, double _dk3, double _dl3) {
ModHKL[0][2] = _dh3;
ModHKL[1][2] = _dk3;
ModHKL[2][2] = _dl3;
}
/** Set modulation vectors for satellites
@param newModVec modulation vectors for HKL for first vector
*/
void UnitCell::setModVec1(const V3D &newModVec) {
ModHKL[0][0] = newModVec[0];
ModHKL[1][0] = newModVec[1];
ModHKL[2][0] = newModVec[2];
}
/** Set modulation vectors for satellites
@param newModVec modulation vectors for HKL for second vector
*/
void UnitCell::setModVec2(const V3D &newModVec) {
ModHKL[0][1] = newModVec[0];
ModHKL[1][1] = newModVec[1];
ModHKL[2][1] = newModVec[2];
}
/** Set modulation vectors for satellites
@param newModVec modulation vectors for HKL for third vector
*/
void UnitCell::setModVec3(const V3D &newModVec) {
ModHKL[0][2] = newModVec[0];
ModHKL[1][2] = newModVec[1];
ModHKL[2][2] = newModVec[2];
}
/** Set modulation vectors for satellites
@param i index of vector to set
@param _dherr error for offset for H for ith vector
@param _dkerr error for offset for K for ith vector
@param _dlerr error for offset for l for ith vector
*/
void UnitCell::setModerr(int i, double _dherr, double _dkerr, double _dlerr) {
errorModHKL[0][i] = _dherr;
errorModHKL[1][i] = _dkerr;
errorModHKL[2][i] = _dlerr;
}
/** Set modulation vectors for satellites
@param _dh1err error for offset for H for first vector
@param _dk1err error for offset for K for first vector
@param _dl1err error for offset for l for first vector
void UnitCell::setModerr1(double _dh1err, double _dk1err, double _dl1err) {
errorModHKL[0][0] = _dh1err;
errorModHKL[1][0] = _dk1err;
errorModHKL[2][0] = _dl1err;
}
/** Set modulation vectors for satellites
@param _dh2err error for offset for H for second vector
@param _dk2err error for offset for K for second vector
@param _dl2err error for offset for l for second vector
void UnitCell::setModerr2(double _dh2err, double _dk2err, double _dl2err) {
errorModHKL[0][1] = _dh2err;
errorModHKL[1][1] = _dk2err;
errorModHKL[2][1] = _dl2err;
}
/** Set modulation vectors for satellites
@param _dh3err error for offset for H for third vector
@param _dk3err error for offset for K for third vector
@param _dl3err error for offset for l for third vector
void UnitCell::setModerr3(double _dh3err, double _dk3err, double _dl3err) {
errorModHKL[0][2] = _dh3err;
errorModHKL[1][2] = _dk3err;
errorModHKL[2][2] = _dl3err;
}
/** Set modulation vectors for satellites
@param MaxO maximum order of modulation vectors
*/
void UnitCell::setMaxOrder(int MaxO) { MaxOrder = MaxO; }
/** Set modulation vectors for satellites
@param CT if true, use cross terms
*/
void UnitCell::setCrossTerm(bool CT) { CrossTerm = CT; }
/** Get modulation vectors for satellites
@param j index of vector to get
@return ModVec :: modulation vector
*/
const Kernel::V3D UnitCell::getModVec(int j) const {
return V3D(getdh(j), getdk(j), getdl(j));
}
/** Get errors for modulation vectors for satellites
@param j index of vector to get
@return VecErr :: error of modulation vector
*/
const Kernel::V3D UnitCell::getVecErr(int j) const {
return V3D(getdherr(j), getdkerr(j), getdlerr(j));
}
/** Get modulation vectors for satellites
@return ModHKL :: modulation vectors
*/
const Kernel::DblMatrix &UnitCell::getModHKL() const { return ModHKL; }
/** Get modulation vectors for satellites
@param j index of vector to get
@return dh :: dh of modulation vector
*/
double UnitCell::getdh(int j) const { return ModHKL[0][j]; }
/** Get modulation vectors for satellites
@param j index of vector to get
@return ModVec :: modulation vector
*/
double UnitCell::getdk(int j) const { return ModHKL[1][j]; }
/** Get modulation vectors for satellites
@param j index of vector to get
@return ModVec :: modulation vector
*/
double UnitCell::getdl(int j) const { return ModHKL[2][j]; }
/** Get error of modulation vectors for satellites
@param j index of vector to get
@return ModVecErr :: error of modulation vector
*/
double UnitCell::getdherr(int j) const { return errorModHKL[0][j]; }
/** Get error of modulation vectors for satellites
@param j index of vector to get
@return ModVecErr :: error of modulation vector
*/
double UnitCell::getdkerr(int j) const { return errorModHKL[1][j]; }
/** Get error of modulation vectors for satellites
@param j index of vector to get
@return ModVecErr :: error of modulation vector
*/
double UnitCell::getdlerr(int j) const { return errorModHKL[2][j]; }
/** Get max order
@return MaxOrder :: maximum order
*/
int UnitCell::getMaxOrder() const { return MaxOrder; }
/** Get cross term boolean
@return CrossTerm :: if true, use cross terms
*/
bool UnitCell::getCrossTerm() const { return CrossTerm; }
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
/** Set lattice parameter
@param _a :: lattice parameter \f$ a \f$ (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::seta(double _a) {
da[0] = _a;
recalculate();
}
/** Set lattice parameter error
@param _aerr :: lattice parameter \f$ a \f$ error (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::setErrora(double _aerr) { errorda[0] = _aerr; }
/** Set lattice parameter
@param _b :: lattice parameter \f$ b \f$ (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::setb(double _b) {
da[1] = _b;
recalculate();
}
/** Set lattice parameter error
@param _berr :: lattice parameter \f$ b \f$ error (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::setErrorb(double _berr) { errorda[1] = _berr; }
/** Set lattice parameter
@param _c :: lattice parameter \f$ c \f$ (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::setc(double _c) {
da[2] = _c;
recalculate();
}
/** Set lattice parameter error
@param _cerr :: lattice parameter \f$ c \f$ error (in \f$ \mbox{\AA} \f$ )*/
void UnitCell::setErrorc(double _cerr) { errorda[2] = _cerr; }
/** Set lattice parameter
@param _alpha :: lattice parameter \f$ \alpha \f$
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setalpha(double _alpha, const int angleunit) {
if (angleunit == angDegrees)
da[3] = deg2rad * _alpha;
else
da[3] = _alpha;
recalculate();
}
/** Set lattice parameter error
@param _alphaerr :: lattice parameter \f$ \alpha \f$ error
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setErroralpha(double _alphaerr, const int angleunit) {
if (angleunit == angDegrees)
errorda[3] = deg2rad * _alphaerr;
else
errorda[3] = _alphaerr;
}
/** Set lattice parameter
@param _beta :: lattice parameter \f$ \beta \f$
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setbeta(double _beta, const int angleunit) {
if (angleunit == angDegrees)
da[4] = deg2rad * _beta;
else
da[4] = _beta;
recalculate();
}
/** Set lattice parameter error
@param _betaerr :: lattice parameter \f$ \beta \f$ error
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setErrorbeta(double _betaerr, const int angleunit) {
if (angleunit == angDegrees)
errorda[4] = deg2rad * _betaerr;
else
errorda[4] = _betaerr;
}
/** Set lattice parameter
@param _gamma :: lattice parameter \f$ \gamma \f$
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setgamma(double _gamma, const int angleunit) {
if (angleunit == angDegrees)
da[5] = deg2rad * _gamma;
else
da[5] = _gamma;
recalculate();
}
/** Set lattice parameter error
@param _gammaerr :: lattice parameter \f$ \gamma \f$ error
@param angleunit :: units for angle, of type #AngleUnits. Default is degrees.
*/
void UnitCell::setErrorgamma(double _gammaerr, const int angleunit) {
if (angleunit == angDegrees)
errorda[5] = deg2rad * _gammaerr;
else
errorda[5] = _gammaerr;
}
/// Return d-spacing (\f$ \mbox{ \AA } \f$) for a given h,k,l coordinate
double UnitCell::d(double h, double k, double l) const {
return 1.0 / dstar(V3D(h, k, l));
}
/// Return d-spacing (\f$ \mbox{ \AA } \f$) for a given h,k,l coordinate
double UnitCell::d(const V3D &hkl) const { return 1.0 / dstar(hkl); }
/// Return d*=1/d (\f$ \mbox{ \AA }^{-1} \f$) for a given h,k,l coordinate
double UnitCell::dstar(double h, double k, double l) const {
return dstar(V3D(h, k, l)); // create a V3D vector h,k,l
}
/// Return d*=1/d (\f$ \mbox{ \AA }^{-1} \f$) for a given h,k,l coordinate
double UnitCell::dstar(const V3D &hkl) const {
V3D Q = B * hkl; // transform into $AA^-1$
return Q.norm();
}
/// Calculate the angle in degrees or radians between two reciprocal vectors
/// (h1,k1,l1) and (h2,k2,l2)
double UnitCell::recAngle(double h1, double k1, double l1, double h2, double k2,
double l2, const int angleunit) const {
V3D Q1(h1, k1, l1), Q2(h2, k2, l2);
double E, ang;
Q1 = Gstar * Q1;
E = Q1.scalar_prod(Q2);
double temp = E / dstar(h1, k1, l1) / dstar(h2, k2, l2);
if (temp > 1)
ang = 0.;
else if (temp < -1)
ang = M_PI;
else
ang = acos(temp);
if (angleunit == angDegrees)
return rad2deg * ang;
else
return ang;
}
/// Volume of the direct unit-cell
double UnitCell::volume() const {
double volume = G.determinant();
return sqrt(volume);
}
/// Volume of the reciprocal lattice
double UnitCell::recVolume() const {
double recvolume = Gstar.determinant();
return sqrt(recvolume);
}
/// Get the metric tensor
/// @return G :: metric tensor
const Kernel::DblMatrix &UnitCell::getG() const { return G; }
/// Get the reciprocal metric tensor
/// @return Gstar :: metric tensor of the reciprocal lattice
const Kernel::DblMatrix &UnitCell::getGstar() const { return Gstar; }
/// Get the B-matrix
/// @return B :: B matrix in Busing-Levy convention
const Kernel::DblMatrix &UnitCell::getB() const { return B; }
/// Get the inverse of the B-matrix
/// @return Binv :: inverse of the B matrix in Busing-Levy convention
const Kernel::DblMatrix &UnitCell::getBinv() const { return Binv; }
/// Private function, called at initialization or whenever lattice parameters
/// are changed
void UnitCell::recalculate() {
if ((da[3] > da[4] + da[5]) || (da[4] > da[3] + da[5]) ||
(da[5] > da[4] + da[3])) {
throw std::invalid_argument("Invalid angles");
}
calculateG();
calculateGstar();
calculateReciprocalLattice();
calculateB();
}
void UnitCell::calculateG() {
G[0][0] = da[0] * da[0];
G[1][1] = da[1] * da[1];
G[2][2] = da[2] * da[2];
G[0][1] = da[0] * da[1] * cos(da[5]);
G[0][2] = da[0] * da[2] * cos(da[4]);
G[1][2] = da[1] * da[2] * cos(da[3]);
G[1][0] = G[0][1];
G[2][0] = G[0][2];
G[2][1] = G[1][2];
}
/// Private function to calculate #Gstar matrix
void UnitCell::calculateGstar() {
// Reciprocal metrix tensor is simply the inverse of the direct one
double det = G.determinant();
if (det == 0) {
throw std::range_error("UnitCell not properly initialized");
}
Gstar = G;
if (Gstar.Invert() == 0) {
throw std::range_error("UnitCell not properly initialized");
}
}
/// Private function to calculate reciprocal lattice parameters
void UnitCell::calculateReciprocalLattice() {
ra[0] = sqrt(Gstar[0][0]); // a*
ra[1] = sqrt(Gstar[1][1]); // b*
ra[2] = sqrt(Gstar[2][2]); // c*
ra[3] = acos(Gstar[1][2] / ra[1] / ra[2]); // alpha*
ra[4] = acos(Gstar[0][2] / ra[0] / ra[2]); // beta*
ra[5] = acos(Gstar[0][1] / ra[0] / ra[1]); // gamma*
}
/// Private function to calculate #B matrix
void UnitCell::calculateB() {
// B matrix using a right handed coordinate system with b1 along x and y in
// the (b1,b2) plane.
// This is the convention in Busing and Levy.
// | b1 b2cos(beta3) b3cos(beta2) |
// | 0 b2sin(beta3) -b3sin(beta2)cos(alpha1) |
// | 0 0 1/a3 |
B[0][0] = ra[0];
B[0][1] = ra[1] * cos(ra[5]);
B[0][2] = ra[2] * cos(ra[4]);
B[1][0] = 0.;
B[1][1] = ra[1] * sin(ra[5]);
B[1][2] = -ra[2] * sin(ra[4]) * cos(da[3]);
B[2][0] = 0.;
B[2][1] = 0.;
B[2][2] = 1. / da[2];
/// Now let's cache the inverse B
Binv = B;
Binv.Invert();
}
/// Recalculate lattice from reciprocal metric tensor (Gstar=transpose(UB)*UB)
void UnitCell::recalculateFromGstar(const DblMatrix &NewGstar) {
if (NewGstar.numRows() != 3 || NewGstar.numCols() != 3) {
std::ostringstream msg;
msg << "UnitCell::recalculateFromGstar - Expected a 3x3 matrix but was "
"given a "
<< NewGstar.numRows() << "x" << NewGstar.numCols();
throw std::invalid_argument(msg.str());
}
if (NewGstar[0][0] * NewGstar[1][1] * NewGstar[2][2] <= 0.)
throw std::invalid_argument("NewGstar");
Gstar = NewGstar;
calculateReciprocalLattice();
G = Gstar;
G.Invert();
da[0] = sqrt(G[0][0]); // a
da[1] = sqrt(G[1][1]); // b
da[2] = sqrt(G[2][2]); // c
da[3] = acos(G[1][2] / da[1] / da[2]); // alpha
da[4] = acos(G[0][2] / da[0] / da[2]); // beta
da[5] = acos(G[0][1] / da[0] / da[1]); // gamma
calculateB();
}
bool UnitCell::operator==(const UnitCell &other) const {
return da == other.da; // da error not used in comparison
}
bool UnitCell::operator!=(const UnitCell &other) const {
return !this->operator==(other);
}
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
std::ostream &operator<<(std::ostream &out, const UnitCell &unitCell) {
// always show the lattice constants
out << "Lattice Parameters:" << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.a() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.b() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.c() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.alpha() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.beta() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.gamma() << std::fixed << std::setprecision(6)
<< " " << std::setw(12) << unitCell.volume();
// write out the uncertainty if there is a positive one somewhere
if ((unitCell.errora() > 0) || (unitCell.errorb() > 0) ||
(unitCell.errorc() > 0) || (unitCell.erroralpha() > 0) ||
(unitCell.errorbeta() > 0) || (unitCell.errorgamma() > 0))
out << "\nParameter Errors :" << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.errora() << std::fixed
<< std::setprecision(6) << std::setw(12) << unitCell.errorb()
<< std::fixed << std::setprecision(6) << std::setw(12)
<< unitCell.errorc() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.erroralpha() << std::fixed
<< std::setprecision(6) << std::setw(12) << unitCell.errorbeta()
<< std::fixed << std::setprecision(6) << std::setw(12)
<< unitCell.errorgamma() << std::fixed << std::setprecision(6)
<< std::setw(12) << unitCell.errorvolume();
return out;
}
std::string unitCellToStr(const UnitCell &unitCell) {
std::ostringstream stream;
stream << std::setprecision(9);
stream << unitCell.a() << " " << unitCell.b() << " " << unitCell.c() << " "
<< unitCell.alpha() << " " << unitCell.beta() << " "
<< unitCell.gamma();
return stream.str();
}
UnitCell strToUnitCell(const std::string &unitCellString) {
Mantid::Kernel::StringTokenizer cellTokens(
unitCellString, " ", Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
std::vector<double> components;
components.reserve(cellTokens.size());
components.emplace_back(boost::lexical_cast<double>(token));
}
switch (components.size()) {
case 3:
return UnitCell(components[0], components[1], components[2]);
case 6:
return UnitCell(components[0], components[1], components[2], components[3],
components[4], components[5]);
default:
throw std::runtime_error("Failed to parse unit cell input string: " +
unitCellString);
}
}
} // namespace Geometry
} // namespace Mantid