File: definition.md

package info (click to toggle)
spglib 2.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 14,180 kB
  • sloc: ansic: 125,066; python: 7,717; cpp: 2,197; f90: 2,143; ruby: 792; makefile: 22; sh: 18
file content (866 lines) | stat: -rw-r--r-- 26,731 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
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
# Definitions and conventions

Information in this page is valid for spglib 1.8.1 or later. The
definitions of transformation matrix and origin shift were different
in the previous versions.

## Space group operation and change of basis

(def_basis_vectors)=

### Basis vectors $(\mathbf{a}, \mathbf{b}, \mathbf{c})$ or $(\mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3)$

In spglib, basis vectors are represented by three column vectors:

$$
\mathbf{a}= \begin{pmatrix}
a_x \\
a_y \\
a_z \\
\end{pmatrix},
\mathbf{b}= \begin{pmatrix}
b_x \\
b_y \\
b_z \\
\end{pmatrix},
\mathbf{c}= \begin{pmatrix}
c_x \\
c_y \\
c_z \\
\end{pmatrix},
$$ (basis_vectors)

in Cartesian coordinates. Depending on the situation,
$(\mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3)$ is used instead of
$(\mathbf{a}, \mathbf{b}, \mathbf{c})$.

(def_point_coordinates)=

### Atomic point coordinates $\boldsymbol{x}$

Coordinates of an atomic point $\boldsymbol{x}$ are represented
as three fractional values relative to basis vectors as follows,

$$
\boldsymbol{x}= \begin{pmatrix}
x_1 \\
x_2 \\
x_3 \\
\end{pmatrix},
$$ (coordinate_triplet)

where $0 \le x_i < 1$. A position vector $\mathbf{x}$ in
Cartesian coordinates is obtained by

$$
\mathbf{x} = (\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{x}.
$$ (position_vector_1)

or

$$
\mathbf{x} = \sum_i x_i \mathbf{a}_i.
$$ (position_vector_2)

(def_symmetry_operation)=

### Symmetry operation $(\boldsymbol{W}, \boldsymbol{w})$

A symmetry operation consists of a pair of the rotation part
$\boldsymbol{W}$ and translation part $\boldsymbol{w}$,
and is represented as $(\boldsymbol{W}, \boldsymbol{w})$ in the
spglib document. The symmetry operation transfers $\boldsymbol{x}$ to
$\tilde{\boldsymbol{x}}$ as follows:

$$
\tilde{\boldsymbol{x}} = \boldsymbol{W}\boldsymbol{x} + \boldsymbol{w}.
$$ (space_group_operation)

(def_transformation_and_origin_shift)=

### Transformation matrix $\boldsymbol{P}$ and origin shift $\boldsymbol{p}$

The transformation matrix $\boldsymbol{P}$ changes choice of
basis vectors as follows

$$
( \mathbf{a} \; \mathbf{b} \; \mathbf{c} )
= ( \mathbf{a}_\mathrm{s} \; \mathbf{b}_\mathrm{s} \;
\mathbf{c}_\mathrm{s} )  \boldsymbol{P},
$$ (transformation_matrix)

where $( \mathbf{a} \; \mathbf{b} \; \mathbf{c} )$ and $(
\mathbf{a}_\mathrm{s} \; \mathbf{b}_\mathrm{s} \;
\mathbf{c}_\mathrm{s} )$ are the basis vectors of an arbitrary system
and of a standardized system, respectively. In general, the
transformation matrix is not limited for the transformation from the
standardized system, but can be used in between any systems possibly
transformed. It has to be emphasized that the transformation matrix
**doesn't** rotate a crystal in Cartesian coordinates, but just
changes the choices of basis vectors.

The origin shift $\boldsymbol{p}$ gives the vector from the
origin of the standardized system $\boldsymbol{O}_\mathrm{s}$ to
the origin of the arbitrary system $\boldsymbol{O}$,

$$
\boldsymbol{p} = \boldsymbol{O} - \boldsymbol{O}_\mathrm{s}.
$$ (origin_shift)

Origin shift **doesn't** move a crystal in Cartesian coordinates, but
just changes the origin to measure the coordinates of atomic points.

A change of basis is described by the combination of the
transformation matrix and the origin shift denoted by
$(\boldsymbol{P}, \boldsymbol{p})$ where first the
transformation matrix is applied and then origin shift. The points in
the standardized system $\boldsymbol{x}_\mathrm{s}$ and
arbitrary system $\boldsymbol{x}$ are related by

$$
\boldsymbol{x}_\mathrm{s} = \boldsymbol{P}\boldsymbol{x} +
\boldsymbol{p},
$$ (change_of_basis_1)

or equivalently,

$$
\boldsymbol{x} = \boldsymbol{P}^{-1}\boldsymbol{x}_\mathrm{s} -
\boldsymbol{P}^{-1}\boldsymbol{p}.
$$ (change_of_basis_2)

A graphical example is shown below.

```{image} _static/change-of-basis.png
---
width: 50%
align: center
---
```

In this example,

$$
\boldsymbol{P} = \begin{pmatrix}
\frac{1}{2} & \frac{\bar{1}}{2} & 0 \\
\frac{1}{2} & \frac{1}{2} & 0 \\
0 & 0 & 1
\end{pmatrix}.
$$

### Difference between rotation and transformation matrices

A rotation matrix rotates (or mirrors, inverts) the crystal body with
respect to origin. A transformation matrix changes the choice of the
basis vectors, but does not rotate the crystal body.

A space group operation having no translation part sends an atom to
another point by

$$
\tilde{\boldsymbol{x}} = \boldsymbol{W}\boldsymbol{x},
$$

where $\tilde{\boldsymbol{x}}$ and $\boldsymbol{x}$ are
represented with respect to the same basis vectors $(\mathbf{a},
\mathbf{b}, \mathbf{c})$. Equivalently the rotation is achieved by
rotating the basis vectors:

$$
(\tilde{\mathbf{a}}, \tilde{\mathbf{b}}, \tilde{\mathbf{c}}) =
(\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{W}
$$ (rotation_matrix)

with keeping the representation of the atomic point coordinates
$\boldsymbol{x}$ because

$$
\tilde{\mathbf{x}} = (\mathbf{a}, \mathbf{b}, \mathbf{c}) \tilde{\boldsymbol{x}}
= (\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{W}
\boldsymbol{x}
= (\tilde{\mathbf{a}}, \tilde{\mathbf{b}}, \tilde{\mathbf{c}})
\boldsymbol{x}.
$$

The transformation matrix changes the choice of the basis vectors as:

$$
(\mathbf{a}', \mathbf{b}', \mathbf{c}') = (\mathbf{a}, \mathbf{b},
\mathbf{c}) \boldsymbol{P}.
$$

The atomic position vector is not altered by this transformation, i.e.,

$$
(\mathbf{a}', \mathbf{b}', \mathbf{c}') \boldsymbol{x}' =
(\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{x}.
$$

However the representation of the atomic point coordinates changes as follows:

$$
\boldsymbol{P} \boldsymbol{x}' = \boldsymbol{x}.
$$

because

$$
(\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{P} \boldsymbol{x}'
= (\mathbf{a}', \mathbf{b}', \mathbf{c}') \boldsymbol{x}' =
(\mathbf{a}, \mathbf{b}, \mathbf{c}) \boldsymbol{x}.
$$

(def_standardized_unit_cell)=

## Spglib conventions of standardized unit cell

The standardization in spglib is achieved by [a change of basis
transformation](#def_transformation_and_origin_shift). If
[idealization](#def_idealize_cell) as shown below is further
applied, the crystal can be rigidly rotated in Cartesian
coordinates.

### Choice of basis vectors

Using the APIs `spg_get_dataset`,
`spg_get_dataset_with_hall_number`, or `spg_standardize_cell`, the
standardized unit cell is obtained. The "standardized unit cell" in
this document means that the (conventional) unit cell structure is
standardized by the crystal symmetry and lengths of basis
vectors. This standardization in spglib is not unique, but upto space
group operations and generators of Euclidean normalizer. Crystals are
categorized by Hall symbols in 530 different types in terms of 230
space group types, unique axes, settings, and cell choices. Moreover
in spglib, lengths of basis vectors are used to choose the order of
$(\mathbf{a}, \mathbf{b}, \mathbf{c})$ if the order can not be
determined only by the symmetrical conventions.

(def_standardized_primitive_cell)=

### Transformation to the primitive cell

In the standardized unit cells, there are five different centring
types available, base centrings of A and C, rhombohedral (R), body centred
(I), and face centred (F). The transformation is applied to the
standardized unit cell by

$$
( \mathbf{a}_\mathrm{p} \; \mathbf{b}_\mathrm{p} \; \mathbf{c}_\mathrm{p} )
= ( \mathbf{a}_\mathrm{s} \; \mathbf{b}_\mathrm{s} \;
\mathbf{c}_\mathrm{s} )  \boldsymbol{P}_\mathrm{c},
$$ (transformation_to_primitive)

where $\mathbf{a}_\mathrm{p}$, $\mathbf{b}_\mathrm{p}$,
and $\mathbf{c}_\mathrm{p}$ are the basis vectors of the
primitive cell and $\boldsymbol{P}_\mathrm{c}$ is the
transformation matrix from the standardized unit cell to the primitive
cell. $\boldsymbol{P}_\mathrm{c}$ for centring types are given
as follows:

$$
\boldsymbol{P}_\mathrm{A} =
\begin{pmatrix}
1 & 0 & 0 \\
0 & \frac{1}{2} & \frac{\bar{1}}{2} \\
0 & \frac{1}{2} & \frac{{1}}{2}
\end{pmatrix},
\boldsymbol{P}_\mathrm{C} =
\begin{pmatrix}
\frac{1}{2} & \frac{{1}}{2} & 0 \\
\frac{\bar{1}}{2} & \frac{1}{2} & 0\\
0 & 0 & 1
\end{pmatrix},
\boldsymbol{P}_\mathrm{R} =
\begin{pmatrix}
\frac{2}{3} & \frac{\bar{1}}{3} & \frac{\bar{1}}{3} \\
\frac{1}{3} & \frac{{1}}{3} & \frac{\bar{2}}{3} \\
\frac{1}{3} & \frac{{1}}{3} & \frac{{1}}{3}
\end{pmatrix},
\boldsymbol{P}_\mathrm{I} =
\begin{pmatrix}
\frac{\bar{1}}{2} & \frac{{1}}{2} & \frac{{1}}{2} \\
\frac{{1}}{2} & \frac{\bar{1}}{2} & \frac{{1}}{2} \\
\frac{{1}}{2} & \frac{{1}}{2} & \frac{\bar{1}}{2}
\end{pmatrix},
\boldsymbol{P}_\mathrm{F} =
\begin{pmatrix}
0 & \frac{{1}}{2} & \frac{{1}}{2} \\
\frac{{1}}{2} & 0 & \frac{{1}}{2} \\
\frac{{1}}{2} & \frac{{1}}{2} & 0
\end{pmatrix}.
$$

The choice of transformation matrix depends on purposes. These
transformation matrices above are just the spglib choices and may not
be the best.

For rhombohedral lattice systems with the H setting (hexagonal
lattice), $\boldsymbol{P}_\mathrm{R}$ is applied to obtain
primitive basis vectors, but for that with the R setting (rhombohedral
lattice), no transformation matrix is applied because it is already
the primitive cell.

(def_idealize_cell)=

### Idealization of unit cell structure

Spglib allows tolerance parameters to match a slightly distorted unit
cell structure to a space group type with some higher symmetry. Using
obtained symmetry operations, the distortion is removed to idealize
the unit cell structure. The coordinates of atomic points are
idealized using respective site-symmetries (Grosse-Kunstleve *et
al*. (2002)). The basis vectors are idealized by forcing them into
respective lattice shapes as follows. In this treatment, except for
triclinic crystals, crystals can be rotated in Cartesian coordinates,
which is the different type of transformation from that of the
change-of-basis transformation explained above.

#### Triclinic lattice

- Niggli reduced cell is used for choosing $\mathbf{a}, \mathbf{b}, \mathbf{c}$.
- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.
- $\mathbf{b}$ is set in $x\text{-}y$ plane of Cartesian
  coordinates so that $\mathbf{a}\times\mathbf{b}$ is along
  $+z$ direction of Cartesian coordinates.

#### Monoclinic lattice

- $b$ axis is taken as the unique axis.

- $\alpha = 90^\circ$ and $\gamma = 90^\circ$

- $90^\circ < \beta < 120^\circ$.

- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.

- $\mathbf{b}$ is set along $+y$ direction of Cartesian coordinates.

- $\mathbf{c}$ is set in $x\text{-}z$ plane of Cartesian coordinates.

#### Orthorhombic lattice

- $\alpha = \beta = \gamma = 90^\circ$.

- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.

- $\mathbf{b}$ is set along $+y$ direction of Cartesian coordinates.

- $\mathbf{c}$ is set along $+z$ direction of Cartesian coordinates.

#### Tetragonal lattice

- $\alpha = \beta = \gamma = 90^\circ$.

- $a=b$.

- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.

- $\mathbf{b}$ is set along $+y$ direction of Cartesian coordinates.

- $\mathbf{c}$ is set along $+z$ direction of Cartesian coordinates.

#### Rhombohedral lattice

- $\alpha = \beta = \gamma$.

- $a=b=c$.

- Let $\mathbf{a}$, $\mathbf{b}$, and $\mathbf{c}$
  projected on $x\text{-}y$ plane in Cartesian coordinates be
  $\mathbf{a}_{xy}$, $\mathbf{b}_{xy}$, and
  $\mathbf{c}_{xy}$, respectively, and their angles be
  $\alpha_{xy}$, $\beta_{xy}$,
  $\gamma_{xy}$, respectively.

- Let $\mathbf{a}$, $\mathbf{b}$, and $\mathbf{c}$
  projected along $z$-axis in Cartesian coordinates be
  $\mathbf{a}_{z}$, $\mathbf{b}_{z}$, and
  $\mathbf{c}_{z}$, respectively.

- $\mathbf{a}_{xy}$ is set along the ray $30^\circ$
  rotated counter-clockwise from the $+x$
  direction of Cartesian coordinates, and $\mathbf{b}_{xy}$ and
  $\mathbf{c}_{xy}$ are placed by angles $120^\circ$ and
  $240^\circ$ from $\mathbf{a}_{xy}$ counter-clockwise,
  respectively.

- $\alpha_{xy} = \beta_{xy} = \gamma_{xy} = 120^\circ$.

- $a_{xy} = b_{xy} = c_{xy}$.

- $a_{z} = b_{z} = c_{z}$.

#### Hexagonal lattice

- $\alpha = \beta = 90^\circ$.

- $\gamma = 120^\circ$.

- $a=b$.

- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.

- $\mathbf{b}$ is set in $x\text{-}y$ plane of Cartesian coordinates.

- $\mathbf{c}$ is set along $+z$ direction of Cartesian coordinates.

#### Cubic lattice

- $\alpha = \beta = \gamma = 90^\circ$.

- $a=b=c$.

- $\mathbf{a}$ is set along $+x$ direction of Cartesian coordinates.

- $\mathbf{b}$ is set along $+y$ direction of Cartesian coordinates.

- $\mathbf{c}$ is set along $+z$ direction of Cartesian coordinates.

### Rotation introduced by idealization

In the idealization step presented above, the input unit cell crystal
structure can be rotated in the Cartesian coordinates. The rotation
matrix $\boldsymbol{R}$ of this rotation is defined by

$$
( \bar{\mathbf{a}}_\mathrm{s} \;
\bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )
= ( \boldsymbol{R} \mathbf{a}_\mathrm{s} \;
\boldsymbol{R} \mathbf{b}_\mathrm{s} \; \boldsymbol{R}
\mathbf{c}_\mathrm{s} ).
$$ (rigid_rotation_matrix)

This rotation matrix rotates the standardized
crystal structure before idealization $( \mathbf{a}_\mathrm{s}
\; \mathbf{b}_\mathrm{s} \; \mathbf{c}_\mathrm{s} )$ to that after
idealization $( \bar{\mathbf{a}}_\mathrm{s} \;
\bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )$ in
Cartesian coordinates of the given input unit cell.

## Examples

Throughout this section we are assuming that we are using a setup like:

```{testsetup}
import spglib
import numpy as np
```

### Crystallographic choice and rigid rotation

The following example of a python script gives a crystal structure of
Br whose space group type is *Cmce*. The basis vectors
$(\mathbf{a}, \mathbf{b}, \mathbf{c})$ are fixed by the symmetry
crystal in the standardization. The C-centring determines the c-axis,
and *m* and *c* operations in *Cmce* fix which directions a- and
b-axes should be with respect to each other axis. This is the first
one choice appearing in the list of Hall symbols among 6 different
choices for this space group type.

```{testcode}
# Mind that the a, b, c axes are given in row vectors here,
# but the formulation above is given for the column vectors.
lattice = [[7.17851431, 0, 0],  # a
            [0, 3.99943947, 0],  # b
            [0, 0, 8.57154746]]  # c
points = [[0.0, 0.84688439, 0.1203133],
            [0.0, 0.65311561, 0.6203133],
            [0.0, 0.34688439, 0.3796867],
            [0.0, 0.15311561, 0.8796867],
            [0.5, 0.34688439, 0.1203133],
            [0.5, 0.15311561, 0.6203133],
            [0.5, 0.84688439, 0.3796867],
            [0.5, 0.65311561, 0.8796867]]
numbers = [35,] * len(points)
cell = (lattice, points, numbers)
dataset = spglib.get_symmetry_dataset(cell)
print("Space group type: %s (%d)"
        % (dataset['international'], dataset['number']))
print("Transformation matrix:")
for x in dataset['transformation_matrix']:
    print("  %2d %2d %2d" % tuple(x))
print("Origin shift: %f %f %f" % tuple(dataset['origin_shift']))
```

This python script is saved in the file `example.py`. Then we get

```{testoutput}
Space group type: Cmce (64)
Transformation matrix:
   1  0  0
   0  1  0
   0  0  1
Origin shift: 0.000000 0.000000 0.000000
```

No rotation was introduced in the idealization. Next, we swap a- and c-axes.

```{testcode}
# Mind that the a, b, c axes are given in row vectors here,
# but the formulation above is given for the column vectors.
lattice = [[8.57154746, 0, 0],  # a
            [0, 3.99943947, 0],  # b
            [0, 0, 7.17851431]]  # c
points = [[0.1203133, 0.84688439, 0.0],
            [0.6203133, 0.65311561, 0.0],
            [0.3796867, 0.34688439, 0.0],
            [0.8796867, 0.15311561, 0.0],
            [0.1203133, 0.34688439, 0.5],
            [0.6203133, 0.15311561, 0.5],
            [0.3796867, 0.84688439, 0.5],
            [0.8796867, 0.65311561, 0.5]]
numbers = [35,] * len(points)
cell = (lattice, points, numbers)
dataset = spglib.get_symmetry_dataset(cell)
print("Space group type: %s (%d)"
        % (dataset['international'], dataset['number']))
print("Transformation matrix:")
for x in dataset['transformation_matrix']:
    print("  %2d %2d %2d" % tuple(x))
print("Origin shift: %f %f %f" % tuple(dataset['origin_shift']))
```

By this,

```{testoutput}
Space group type: Cmce (64)
Transformation matrix:
   0  0  1
   0  1  0
  -1  0  0
Origin shift: 0.000000 0.000000 0.000000
```

We get a non-identity transformation matrix, which wants to transform
back to the original (above) crystal structure by swapping a- and
c-axes. The transformation back of the basis vectors is achieved by
Eq. {eq}`transformation_matrix`. Next, we try to rotate rigidly the
crystal structure by $45^\circ$ around c-axis in Cartesian
coordinates from the first one:

```{testcode}
# Mind that the a, b, c axes are given in row vectors here,
# but the formulation above is given for the column vectors.
lattice = [[5.0759761474456697, 5.0759761474456697, 0],  # a
            [-2.8280307701821314, 2.8280307701821314, 0],  # b
            [0, 0, 8.57154746]]  # c
points = [[0.0, 0.84688439, 0.1203133],
            [0.0, 0.65311561, 0.6203133],
            [0.0, 0.34688439, 0.3796867],
            [0.0, 0.15311561, 0.8796867],
            [0.5, 0.34688439, 0.1203133],
            [0.5, 0.15311561, 0.6203133],
            [0.5, 0.84688439, 0.3796867],
            [0.5, 0.65311561, 0.8796867]]
numbers = [35,] * len(points)
cell = (lattice, points, numbers)
dataset = spglib.get_symmetry_dataset(cell)
print("Space group type: %s (%d)"
        % (dataset['international'], dataset['number']))
print("Transformation matrix:")
for x in dataset['transformation_matrix']:
    print("  %2d %2d %2d" % tuple(x))
print("Origin shift: %f %f %f" % tuple(dataset['origin_shift']))
```

and

```{testoutput}
Space group type: Cmce (64)
Transformation matrix:
   1  0  0
   0  1  0
   0  0  1
Origin shift: 0.000000 0.000000 0.000000
```

The transformation matrix is kept unchanged even though the crystal
structure is rotated in Cartesian coordinates. The origin shift is
different but it changes only the order of atoms, so effectively it
does nothing.

### Transformation to a primitive cell

There are infinite number of choices of primitive cell. The
transformation from a primitive cell basis vectors to the other
primitive cell basis vectors is always done by an integer matrix
because any lattice points can be generated by the linear combination
of the three primitive basis vectors.

When we have a non-primitive cell basis vectors as given in the above
example:

```
lattice = [[7.17851431, 0, 0],  # a
           [0, 3.99943947, 0],  # b
           [0, 0, 8.57154746]]  # c
```

This has the C-centring, so it must be transformed to a primitive
cell. A possible transformation is shown at
[](#def_standardized_primitive_cell), which is
$\boldsymbol{P}_\mathrm{C}$. With the following script:

```{testcode}
lattice = [[7.17851431, 0, 0],  # a
           [0, 3.99943947, 0],  # b
           [0, 0, 8.57154746]]  # c
Pc = [[0.5, 0.5, 0],
      [-0.5, 0.5, 0],
      [0, 0, 1]]
print(np.dot(np.transpose(lattice), Pc).T)  # given in row vectors
```

we get the primitive cell basis vectors (shown in row vectors):

```{testoutput}
[[ 3.58925715 -1.99971973  0.        ]
 [ 3.58925715  1.99971973  0.        ]
 [ 0.          0.          8.57154746]]
```

`find_primitive` gives a primitive cell that is obtained by
transforming standardized and idealized crystal structure to the
primitive cell using the transformation matrix. Therefore by this
script:

```{testcode}
lattice = [[7.17851431, 0, 0],
            [0, 3.99943947, 0],
            [0, 0, 8.57154746]]
points = [[0.0, 0.84688439, 0.1203133],
            [0.0, 0.65311561, 0.6203133],
            [0.0, 0.34688439, 0.3796867],
            [0.0, 0.15311561, 0.8796867],
            [0.5, 0.34688439, 0.1203133],
            [0.5, 0.15311561, 0.6203133],
            [0.5, 0.84688439, 0.3796867],
            [0.5, 0.65311561, 0.8796867]]
numbers = [8,] * len(points)
cell = (lattice, points, numbers)

primitive_cell = spglib.find_primitive(cell)
print(primitive_cell[0])
```

we get:

```{testoutput}
[[ 3.58925715 -1.99971973  0.        ]
 [ 3.58925715  1.99971973  0.        ]
 [ 0.          0.          8.57154746]]
```

This is same as what we manually obtained above.
Even when the basis vectors are rigidly rotated as:

```
lattice = [[5.0759761474456697, 5.0759761474456697, 0],
           [-2.8280307701821314, 2.8280307701821314, 0],
           [0, 0, 8.57154746]]
```

the relationship of a, b, c axes is unchanged. Therefore the same
transformation matrix to the primitive cell can be used. Then we get:

```
   [[3.95200346 1.12397269 0.        ]
    [1.12397269 3.95200346 0.        ]
    [0.         0.         8.57154746]]
```

However applying `find_primitive` rigidly rotates automatically and
so the following script doesn't give this basis vectors:

```{testcode}
lattice = [[5.0759761474456697, 5.0759761474456697, 0],
            [-2.8280307701821314, 2.8280307701821314, 0],
            [0, 0, 8.57154746]]
points = [[0.0, 0.84688439, 0.1203133],
            [0.0, 0.65311561, 0.6203133],
            [0.0, 0.34688439, 0.3796867],
            [0.0, 0.15311561, 0.8796867],
            [0.5, 0.34688439, 0.1203133],
            [0.5, 0.15311561, 0.6203133],
            [0.5, 0.84688439, 0.3796867],
            [0.5, 0.65311561, 0.8796867]]
numbers = [8,] * len(points)
cell = (lattice, points, numbers)

primitive_cell = spglib.find_primitive(cell)
print(primitive_cell[0])
```

but gives those with respect to the idealized ones:

```{testoutput}
[[ 3.58925715 -1.99971973  0.        ]
 [ 3.58925715  1.99971973  0.        ]
 [ 0.          0.          8.57154746]]
```

To obtain the rotated primitive cell basis vectors, we can use
`standardize_cell` as shown below::

```{testcode}
lattice = [[5.0759761474456697, 5.0759761474456697, 0],
           [-2.8280307701821314, 2.8280307701821314, 0],
           [0, 0, 8.57154746]]
points = [[0.0, 0.84688439, 0.1203133],
          [0.0, 0.65311561, 0.6203133],
          [0.0, 0.34688439, 0.3796867],
          [0.0, 0.15311561, 0.8796867],
          [0.5, 0.34688439, 0.1203133],
          [0.5, 0.15311561, 0.6203133],
          [0.5, 0.84688439, 0.3796867],
          [0.5, 0.65311561, 0.8796867]]
numbers = [8,] * len(points)
cell = (lattice, points, numbers)
primitive_cell = spglib.standardize_cell(cell, to_primitive=1, no_idealize=1)
print(primitive_cell[0])
```

then we get:

```{testoutput}
[[3.95200346 1.12397269 0.        ]
 [1.12397269 3.95200346 0.        ]
 [0.         0.         8.57154746]]
```

which is equivalent to that we get manually. However using
`standardize_cell`, distortion is not removed for the distorted
crystal structure.

### Computing rigid rotation introduced by idealization

In spglib, rigid rotation is purposely introduced in the idealization
step though this is unlikely as a crystallographic operation.

The crystal structure in the following script is the same as shown
above, which is the one $45^\circ$ rotated around c-axis:

```{testcode}
# Mind that the a, b, c axes are given in row vectors here,
# but the formulation above is given for the column vectors.
lattice = [[5.0759761474456697, 5.0759761474456697, 0],  # a
            [-2.8280307701821314, 2.8280307701821314, 0],  # b
            [0, 0, 8.57154746]]  # c
points = [[0.0, 0.84688439, 0.1203133],
            [0.0, 0.65311561, 0.6203133],
            [0.0, 0.34688439, 0.3796867],
            [0.0, 0.15311561, 0.8796867],
            [0.5, 0.34688439, 0.1203133],
            [0.5, 0.15311561, 0.6203133],
            [0.5, 0.84688439, 0.3796867],
            [0.5, 0.65311561, 0.8796867]]
numbers = [35,] * len(points)
cell = (lattice, points, numbers)
dataset = spglib.get_symmetry_dataset(cell)
print("Space group type: %s (%d)"
        % (dataset['international'], dataset['number']))
print("Transformation matrix:")
for x in dataset['transformation_matrix']:
    print("  %2d %2d %2d" % tuple(x))
print("std_lattice_after_idealization:")
print(dataset['std_lattice'])
```

we get

```{testoutput}
Space group type: Cmce (64)
Transformation matrix:
   1  0  0
   0  1  0
   0  0  1
std_lattice_after_idealization:
[[7.17851431 0.         0.        ]
 [0.         3.99943947 0.        ]
 [0.         0.         8.57154746]]
```

From Eq. {eq}`transformation_matrix`, the standardized basis vectors
**before** idealization $( \mathbf{a}_\mathrm{s} \; \mathbf{b}_\mathrm{s}
\; \mathbf{c}_\mathrm{s} )$ is obtained by (after `import numpy as np`)

```{testcode}
std_lattice_before_idealization = np.dot(
    np.transpose(lattice),
    np.linalg.inv(dataset['transformation_matrix'])).T
print(std_lattice_before_idealization)
```

which is (in row vectors)

```{testoutput}
[[ 5.07597615  5.07597615  0.        ]
 [-2.82803077  2.82803077  0.        ]
 [ 0.          0.          8.57154746]]
```

This is different from the standardized basis vectors **after**
idealization $( \bar{\mathbf{a}}_\mathrm{s} \;
\bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )$. Unless
this crystal structure is distorted from the crystal structure that
has the ideal symmetry, this means that the crystal was rotated
rigidly in the idealization step by

$$
( \bar{\mathbf{a}}_\mathrm{s} \;
\bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )
= ( \boldsymbol{R} \mathbf{a}_\mathrm{s} \;
\boldsymbol{R} \mathbf{b}_\mathrm{s} \; \boldsymbol{R}
\mathbf{c}_\mathrm{s} ).
$$

where $\boldsymbol{R}$ is the rotation
matrix. This is computed by

```{testcode}
R = np.dot(dataset['std_lattice'].T,
            np.linalg.inv(std_lattice_before_idealization.T))
print(R)
```

and we get

```{testoutput}
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
```

This equals to

$$
\begin{pmatrix}
\cos\theta & -\sin\theta & 0 \\
\sin\theta & \cos\theta & 0 \\
0 & 0 & 1
\end{pmatrix},
$$

with $\theta = -\pi/4$ and $\det(\boldsymbol{R})=1$ when
no distortion. `dataset['std_rotation_matrix']` gives
approximately the same result:

```
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
```

In summary,

$$
( \bar{\mathbf{a}}_\mathrm{s} \;
\bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )  \boldsymbol{P}
= ( \boldsymbol{R} \mathbf{a} \; \boldsymbol{R} \mathbf{b} \;
\boldsymbol{R} \mathbf{c} ).
$$

The atomic point coordinates in $( \bar{\mathbf{a}}_\mathrm{s}
\; \bar{\mathbf{b}}_\mathrm{s} \; \bar{\mathbf{c}}_\mathrm{s} )$
are simply obtained by Eq. {eq}`change_of_basis_1` since the
rotation doesn't affect them.