Repository: pyxem/diffsims (language: python)

Issue:
get_beam_directions_grid() does not sample fundamental region of hexagonal systems
**Describe the bug**
When using get_beam_directions_grid with diffsims-0.5.dev the entire fundamental region of hexagonal systems is not sampled. With 5 degree sampling resolution, only 162 orientations are sampled, while 386 orientations was sampled with diffsims-0.4.2. It seems that this only happens for hexagonal systems (6/mmm). The missing orientations are quite clear from these plots:

Result from diffsims-0.5.dev:
![diffsims-0-5-dev](https://user-images.githubusercontent.com/16645501/169124950-3f971fa2-b728-43ec-8120-84efeeae8c89.png)

Result from diffsims-0.4.2:
![diffsims-0-4-2](https://user-images.githubusercontent.com/16645501/169125469-f691fa0a-394a-4241-9404-4f3d530a74a9.png)

Also, the sampling grid appears different as well, which is not so clear in the figures above. I am not certain which sampling "pattern" is correct, but the sampling in diffsims 0.5.dev appears more "aesthetic".

**To Reproduce**
```python
from orix import plot
from orix.quaternion import Orientation, Rotation, symmetry
from orix.vector import Vector3d
from diffsims.generators.rotation_list_generators import get_beam_directions_grid
import matplotlib.pyplot as plt
import numpy as np

resolution = 5.0

systems = {
    'cubic': symmetry.Oh,
    'hexagonal': symmetry.D6h,
    'trigonal': symmetry.D3d,
    'tetragonal': symmetry.D4h,
    'orthorhombic': symmetry.D2h,
    'monoclinic': symmetry.C2h, 
    'triclinic': symmetry.Ci
}

fig = plt.figure(figsize=[4*len(systems), 3])

for i, system in enumerate(systems):
    euler_angles = get_beam_directions_grid(system, resolution, mesh='spherified_cube_edge') #Get a uniform sampling of euler angles
    print(f'Simulated {len(euler_angles)} orientations for {systems[system].name}')

    orientations = Orientation(Rotation.from_euler(np.deg2rad(euler_angles)), symmetry=systems[system])
    ax = fig.add_subplot(1, len(systems), i+1, 
                         projection='ipf',
                         symmetry=systems[system],
                         direction=Vector3d.zvector(),
                         hemisphere='upper')
    ax.set_title(systems[system].name, fontweight='bold')
    ax.scatter(orientations)
plt.tight_layout()
```


Discussion / hints:
The "gridding" methods available don't work very well in the case of hexagonal crystals. My suspicion is that this is related to rounding issues. I think sampling should be a functionality in orix, not diffsims, so I'm moving it in this PR: https://github.com/pyxem/orix/pull/334 where I also added a gridding method with 6-fold symmetry to avoid these issues. 
The deleted comment was a duplicate.

Thanks for raising this @emichr, I’ll have a look at this before releasing diffsims.
That sounds great @din14970! I assume it will be a few weeks until that will be ready and available?

By the way @hakonanes, the result is the same with Orix 0.8.2, 0.9.0, and 0.9.0.post0.
> By the way @hakonanes, the result is the same with Orix 0.8.2, 0.9.0, and 0.9.0.post0.

Thanks for pointing this out @emichr. I initially thought that the cause of the different hexagonal sampling was the change of the meaning of `Rotation.from_euler(..., direction=crystal2lab)` in orix from 0.8.2 to 0.9.0, but according to your comment, and also my own verification of this, this is not the case.

With diffsims 0.4.2 and orix 0.8.2 or 0.9.0

```python
>>> from diffsims.generators.rotation_list_generators import get_beam_directions_grid
>>> rot = get_beam_directions_grid("hexagonal", 2)
>>> rot.shape
(2255, 3)
```

With diffsims 0.5.0 and orix 0.8.2 or 0.9.0

```python
>>> from diffsims.generators.rotation_list_generators import get_beam_directions_grid
>>> rot = get_beam_directions_grid("hexagonal", 2)
>>> rot.shape
(915, 3)
```

I checked the rotations returned from the other crystal systems with the four combinations of versions: taking diffsims 0.4.2 and orix 0.8.2 as the ground truth, the rotations are the same except for the hexagonal system. We should get to the bottom of this before releasing diffsims 0.5.0.

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 91514ef0..a19232d1 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -21,6 +21,8 @@ Added
 Changed
 -------
 - Minimal version of dependencies numpy >= 1.17 and tqdm >= 4.9
+- The Laue group representing the rotation list sampling of "hexagonal" from 6/m to
+  6/mmm.
 
 2021-04-16 - version 0.4.2
 ==========================
diff --git a/diffsims/generators/rotation_list_generators.py b/diffsims/generators/rotation_list_generators.py
index 4577106d..1239f6eb 100644
--- a/diffsims/generators/rotation_list_generators.py
+++ b/diffsims/generators/rotation_list_generators.py
@@ -43,7 +43,7 @@
 # https://github.com/pyxem/orix/issues/125#issuecomment-698956290.
 crystal_system_dictionary = {
     "cubic": [(0, 0, 1), (1, 1, 1), (1, 0, 1)],
-    "hexagonal": [(0, 0, 0, 1), (1, 0, -1, 0), (2, -1, -1, 0)],
+    "hexagonal": [(0, 0, 0, 1), (9, 1, -10, 0), (2, -1, -1, 0)],
     "trigonal": [(0, 0, 0, 1), (-2, 1, 1, 0), (-1, 2, -1, 0)],
     "tetragonal": [(0, 0, 1), (1, 0, 0), (1, 1, 0)],
     "orthorhombic": [(0, 0, 1), (-1, 0, 0), (0, 1, 0)],


Test patch:
diff --git a/diffsims/tests/generators/test_rotation_list_generator.py b/diffsims/tests/generators/test_rotation_list_generator.py
index cd8160eb..b81826e7 100644
--- a/diffsims/tests/generators/test_rotation_list_generator.py
+++ b/diffsims/tests/generators/test_rotation_list_generator.py
@@ -76,6 +76,23 @@ def test_get_beam_directions_grid(crystal_system, mesh):
     grid = get_beam_directions_grid(crystal_system, 5, mesh=mesh)
 
 
+@pytest.mark.parametrize(
+    "crystal_system, desired_size",
+    [
+        ("cubic", 300),
+        ("hexagonal", 1050),
+        ("trigonal", 1657),
+        ("tetragonal", 852),
+        ("orthorhombic", 1657),
+        ("monoclinic", 6441),
+        ("triclinic", 12698),
+    ]
+)
+def test_get_beam_directions_grid_size(crystal_system, desired_size):
+    grid = get_beam_directions_grid(crystal_system, 2)
+    assert grid.shape[0] == desired_size
+
+
 @pytest.mark.xfail()
 def test_invalid_mesh_beam_directions():
     _ = get_beam_directions_grid("cubic", 10, mesh="invalid")
diff --git a/diffsims/tests/sims/test_diffraction_simulation.py b/diffsims/tests/sims/test_diffraction_simulation.py
index 01eae28f..90e3b951 100644
--- a/diffsims/tests/sims/test_diffraction_simulation.py
+++ b/diffsims/tests/sims/test_diffraction_simulation.py
@@ -88,18 +88,21 @@ def test_plot_profile_simulation(profile_simulation):
 class TestDiffractionSimulation:
     @pytest.fixture
     def diffraction_simulation(self):
-        return DiffractionSimulation(np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]]))
+        return DiffractionSimulation(
+            np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]], dtype=float)
+        )
 
     @pytest.fixture
     def diffraction_simulation_calibrated(self):
         return DiffractionSimulation(
-            np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]]), calibration=0.5
+            np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]], dtype=float), calibration=0.5
         )
 
     def test_failed_initialization(self):
         with pytest.raises(ValueError, match="Coordinate"):
             DiffractionSimulation(
-                np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]]), indices=np.array([1, 2, 3])
+                np.array([[0, 0, 0], [1, 2, 3], [3, 4, 5]], dtype=float),
+                indices=np.array([1, 2, 3])
             )
 
     def test_init(self, diffraction_simulation):