def test_remove_absences(inplace, hkl_index): """Test DataSet.remove_absences()""" params = (34., 45., 98., 90., 90., 90.) cell = gemmi.UnitCell(*params) sg_1 = gemmi.SpaceGroup(1) sg_19 = gemmi.SpaceGroup(19) Hall = rs.utils.generate_reciprocal_asu(cell, sg_1, 5., anomalous=False) h, k, l = Hall.T absent = rs.utils.is_absent(Hall, sg_19) ds = rs.DataSet({ 'H': h, 'K': k, 'L': l, 'I': np.ones(len(h)), }, spacegroup=sg_19, cell=cell).infer_mtz_dtypes() if hkl_index: ds.set_index(['H', 'K', 'L'], inplace=True) ds_test = ds.remove_absences(inplace=inplace) ds_true = ds[~ds.label_absences().ABSENT] assert len(ds_test) == len(Hall) - absent.sum() assert np.array_equal(ds_test.get_hkls(), ds_true.get_hkls()) if inplace: assert id(ds_test) == id(ds) else: assert id(ds_test) != id(ds)
def cell_and_spacegroups(): data = [ ((10., 20., 30., 90., 80., 75.), 'P 1'), ((30., 50., 80., 90., 100., 90.), 'P 1 21 1'), ((10., 20., 30., 90., 90., 90.), 'P 21 21 21'), ((89., 89., 105., 90., 90., 120.), 'P 31 2 1'), ((30., 30., 30., 90., 90., 120.), 'R 32'), ] return [(gemmi.UnitCell(*i), gemmi.SpaceGroup(j)) for i, j in data]
def cell(self, val): # GH#18: Type-checking for supported input types if isinstance(val, gemmi.UnitCell) or (val is None): self._cell = val elif isinstance(val, (list, tuple, np.ndarray)) and len(val) == 6: self._cell = gemmi.UnitCell(*val) else: raise ValueError( f"Cannot construct gemmi.UnitCell from value: {val}")
def to_gemmi(self): return gemmi.UnitCell( self.a, self.b, self.c, self.alpha, self.beta, self.gamma, )
def test_reduction(self): cell = gemmi.UnitCell(687.9, 687.9, 1933.3, 90.0, 90.0, 90.0) sg = gemmi.SpaceGroup('I 4 2 2') gv = gemmi.GruberVector(cell, sg) gv.niggli_reduce() self.assertTrue(gv.is_niggli()) self.assertTrue(gv.is_buerger()) self.assertTrue(gv.is_normalized()) p = cell.a q = 1082.134662368783 t = 108.5325886 par = (p * p, p * p, q * q, -p * p, -p * p, 0) assert_almost_equal_seq(self, gv.parameters, par) self.assertTrue(gv.cell_parameters(), (p, p, q, t, t, 0))
def test_change_of_basis(self): uc = gemmi.UnitCell(20, 30, 39, 73, 93, 99) op = gemmi.Op('y-x/2,-2/3*z+2/3*y,3*x') uc2 = uc.changed_basis_backward(op, set_images=False) # compare with result from cctbx: # from cctbx import sgtbx, uctbx # u = uctbx.unit_cell((20,30,39, 73,93,99)) # op = sgtbx.change_of_basis_op('y-x/2,-2/3*z+2/3*y,3*x').inverse() # print(u.change_basis(cb_op=op).parameters()) expected = (117.9468784563987, 25.977921933207348, 20.0, 130.5, 107.65517573180257, 82.63132106791868) assert_almost_equal_seq(self, uc2.parameters, expected) uc3 = uc2.changed_basis_forward(op, set_images=True) assert_almost_equal_seq(self, uc3.parameters, uc.parameters)
def test_write_ccp4_map(realmap): """Test rs.io.write_ccp4_map()""" mapfile = tempfile.NamedTemporaryFile(suffix=".map") sg = gemmi.SpaceGroup(1) cell = gemmi.UnitCell(10., 20., 30., 90., 90., 90.) if not isinstance(realmap, np.ndarray) or not (realmap.ndim == 3): with pytest.raises(ValueError): rs.io.write_ccp4_map(realmap, mapfile.name, cell, sg) mapfile.close() return rs.io.write_ccp4_map(realmap, mapfile.name, cell, sg) assert exists(mapfile.name) mapfile.close()
def test_near_degenerate(self): cell = gemmi.UnitCell(15.53, 91.94, 4.35, 110.326, 7.337, 103.014) gv = gemmi.GruberVector(cell, None) self.assertFalse(gv.is_normalized()) gv.normalize() self.assertTrue(gv.is_normalized()) self.assertFalse(gv.is_buerger()) self.assertFalse(gv.is_niggli()) n = gv.niggli_reduce(iteration_limit=100) self.assertEqual(n, 100) self.assertFalse(gv.is_niggli()) n = gv.niggli_reduce(iteration_limit=100) self.assertTrue(n < 100) self.assertTrue(gv.is_niggli()) expected = (2.814597242, 3.077205425, 7.408935896, 100.42421409, 94.02885284, 95.07179187) assert_almost_equal_seq(self, gv.cell_parameters(), expected)
def __init__(self, s0, cell, R, lam_min, lam_max, dmin, spacegroup='1'): """ Parameters ---------- s0 : array a 3 vector indicating the direction of the incoming beam wavevector. This can be any length, it will be unit normalized in the constructor. cell : iterable or gemmi.UnitCell A tuple or list of unit cell params (a, b, c, alpha, beta, gamma) or a gemmi.UnitCell object R : array A 3x3 rotation matrix corresponding to the crystal orientation for the frame. lam_min : float The lower end of the wavelength range of the beam. lam_max : float The upper end of the wavelength range of the beam. dmin : float The maximum resolution of the model spacegroup : gemmi.SpaceGroup (optional) Anything that the gemmi.SpaceGroup constructor understands. """ if not isinstance(cell, gemmi.UnitCell): cell = gemmi.UnitCell(*cell) self.cell = cell if not isinstance(spacegroup, gemmi.SpaceGroup): spacegroup = gemmi.SpaceGroup(spacegroup) self.spacegroup = spacegroup self.R = R self.lam_min = lam_min self.lam_max = lam_max self.dmin = dmin self.B = np.array(self.cell.fractionalization_matrix).T # self.s{0,1} are dynamically masked by their outlier status self.s0 = s0 / np.linalg.norm(s0) # Initialize the full reciprocal grid hmax, kmax, lmax = self.cell.get_hkl_limits(dmin) Hall = np.mgrid[-hmax:hmax + 1:1., -kmax:kmax + 1:1., -lmax:lmax + 1:1., ].reshape((3, -1)).T Hall = Hall[np.any(Hall != 0, axis=1)] d = cell.calculate_d_array(Hall) Hall = Hall[d >= dmin] self.Hall = Hall
def test_cell(data_fmodel, cell): if cell is None: data_fmodel.cell = cell assert data_fmodel.cell is None elif not isinstance(cell, np.ndarray) and (cell == [] or cell == [10, 20, 30]): with pytest.raises(ValueError): data_fmodel.cell = cell else: data_fmodel.cell = cell if isinstance(cell, gemmi.UnitCell): expected = cell else: expected = gemmi.UnitCell(*cell) assert expected.a == data_fmodel.cell.a assert expected.b == data_fmodel.cell.b assert expected.c == data_fmodel.cell.c assert expected.alpha == data_fmodel.cell.alpha assert expected.beta == data_fmodel.cell.beta assert expected.gamma == data_fmodel.cell.gamma
def __setstate__(self, state): data = state["data"] self.grid = gemmi.FloatGrid( data.shape[0], data.shape[1], data.shape[2], ) spacegroup = state["spacegroup"] self.grid.spacegroup = gemmi.SpaceGroup(spacegroup) unit_cell = state["unit_cell"] self.grid.unit_cell = gemmi.UnitCell( unit_cell[0], unit_cell[1], unit_cell[2], unit_cell[3], unit_cell[4], unit_cell[5], ) for index, val in np.ndenumerate(data): self.grid.set_value(index[0], index[1], index[2], data[index])
import pytest import tempfile import reciprocalspaceship as rs import gemmi from pandas.testing import assert_frame_equal @pytest.mark.parametrize("sep", [",", "\t", ";"]) @pytest.mark.parametrize("spacegroup", [None, gemmi.SpaceGroup("P 1"), 1, "P 1"]) @pytest.mark.parametrize( "cell", [None, gemmi.UnitCell(1, 1, 1, 90, 90, 90), (1, 1, 1, 90, 90, 90)]) @pytest.mark.parametrize("merged", [None, True, False]) @pytest.mark.parametrize("infer_mtz_dtypes", [True, False]) def test_read_csv(IOtest_mtz, sep, spacegroup, cell, merged, infer_mtz_dtypes): """Test rs.read_csv()""" csvfile = tempfile.NamedTemporaryFile(suffix=".csv") expected = rs.read_mtz(IOtest_mtz) expected.to_csv(csvfile.name, sep=sep) result = rs.read_csv(csvfile.name, spacegroup=spacegroup, cell=cell, merged=merged, infer_mtz_dtypes=infer_mtz_dtypes, sep=sep) print(result) result.set_index(["H", "K", "L"], inplace=True) csvfile.close() if spacegroup:
import pytest import numpy as np from reciprocalspaceship.utils import compute_dHKL, generate_reciprocal_cell import gemmi @pytest.mark.parametrize("cell", [ gemmi.UnitCell( 10., 20., 30., 90., 90., 90., ), gemmi.UnitCell(60., 60., 90., 90., 90., 120.), gemmi.UnitCell(291., 423., 315., 90., 100., 90.), gemmi.UnitCell(30., 50., 90., 75., 80., 106.), ]) def test_compute_dHKL(dataset_hkl, cell): """Test rs.utils.compute_dHKL()""" hmax = 10 H = np.mgrid[-hmax:hmax + 1:1, -hmax:hmax + 1:1, -hmax:hmax + 1:1].reshape( (3, -1)).T H = H[~np.all(H == 0, axis=1)] #Remove 0,0,0 result = compute_dHKL(H, cell) # Compare to gemmi result expected = np.zeros(len(result), dtype=np.float32) for i, h in enumerate(H): expected[i] = cell.calculate_d(h)
#centroid distance cutoff in pixels centroid_max_distance = 10. print('parsing precog files') precog_rmsds = pd.read_csv(precog_filename, header=None, delimiter=' ') precog_rmsds = precog_rmsds[precog_rmsds.columns[-2]].to_numpy() print('reading DIALS files') from dxtbx.model.experiment_list import ExperimentListFactory from dials.array_family.flex import reflection_table elist = ExperimentListFactory.from_json_file(expt_file) cryst = elist.crystals()[0] unit_cell = cryst.get_unit_cell() spacegroup = gemmi.SpaceGroup( cryst.get_space_group().type().universal_hermann_mauguin_symbol()) cell = gemmi.UnitCell(*unit_cell.parameters()) refls = reflection_table.from_file(refl_file) refls = refls.select(refls.get_flags(refls.flags.used_in_refinement)) print('generating DIALS dataframe') dials_df = rs.DataSet( { 'X': refls['xyzobs.px.value'].parts()[0].as_numpy_array(), 'Y': refls['xyzobs.px.value'].parts()[1].as_numpy_array(), 'Xcal': refls['xyzcal.px'].parts()[0].as_numpy_array(), 'Ycal': refls['xyzcal.px'].parts()[1].as_numpy_array(), 'BATCH': refls['imageset_id'].as_numpy_array(), }, cell=cell, spacegroup=spacegroup).infer_mtz_dtypes()
#ds = rs.read_precognition(ii_file).reset_index() print('parsing precog files') precog_df = parse_ii_inp_file_pairs( sorted(glob('data/e080_???.mccd.ii')), sorted(glob('data/e080_???.mccd.inp')), ).reset_index() print('reading DIALS files') from dxtbx.model.experiment_list import ExperimentListFactory from dials.array_family.flex import reflection_table elist = ExperimentListFactory.from_json_file(expt_file, False) cryst = elist.crystals()[0] unit_cell = cryst.get_unit_cell() precog_df.spacegroup = gemmi.SpaceGroup( cryst.get_space_group().type().universal_hermann_mauguin_symbol()) precog_df.cell = gemmi.UnitCell(*unit_cell.parameters()) refls = reflection_table.from_file(refl_file) print('generating DIALS dataframe') dials_df = rs.DataSet( { 'X': refls['xyzobs.px.value'].parts()[0].as_numpy_array(), 'Y': refls['xyzobs.px.value'].parts()[1].as_numpy_array(), 'H': refls['miller_index'].as_vec3_double().parts()[0].as_numpy_array(), 'K': refls['miller_index'].as_vec3_double().parts()[1].as_numpy_array(), 'L': refls['miller_index'].as_vec3_double().parts()[2].as_numpy_array(), 'Wavelength': refls['Wavelength'].as_numpy_array(), 'BATCH': refls['imageset_id'].as_numpy_array(),
import gemmi from pandas.testing import assert_frame_equal def test_constructor_empty(): """Test DataSet.__init__()""" result = rs.DataSet() assert len(result) == 0 assert result.spacegroup is None assert result.cell is None @pytest.mark.parametrize("spacegroup", [None, gemmi.SpaceGroup(1), "P 1"]) @pytest.mark.parametrize( "cell", [None, gemmi.UnitCell(1, 1, 1, 90, 90, 90), (1, 1, 1, 90, 90, 90)]) @pytest.mark.parametrize("merged", [None, True, False]) def test_constructor_dataset(data_fmodel, spacegroup, cell, merged): """Test DataSet.__init__() when called with a DataSet""" result = rs.DataSet(data_fmodel, spacegroup=spacegroup, cell=cell, merged=merged) assert_frame_equal(result, data_fmodel) if merged is not None: assert result.merged == merged else: assert result.merged == True # Ensure provided values take precedence
import pytest import tempfile import gemmi import reciprocalspaceship as rs from pandas.testing import assert_frame_equal, assert_series_equal @pytest.mark.parametrize("spacegroup", [None, 1, 4, 19]) @pytest.mark.parametrize("cell", [ None, gemmi.UnitCell(1, 1, 1, 90, 90, 90), gemmi.UnitCell(3, 4, 5, 90, 90, 120) ]) @pytest.mark.parametrize("merged", [True, False]) def test_pickle_roundtrip_dataset(data_fmodel, spacegroup, cell, merged): """Test roundtrip of DataSet.to_pickle() and rs.read_pickle()""" pklfile = tempfile.NamedTemporaryFile(suffix=".pkl") # Setup expected result DataSet expected = data_fmodel expected.spacegroup = spacegroup expected.cell = cell expected.merged = merged # Roundtrip expected.to_pickle(pklfile.name) result = rs.read_pickle(pklfile.name) pklfile.close() assert isinstance(result, rs.DataSet) assert_frame_equal(result, expected)
def __init__(self, s0, s1, cell, R, lam_min, lam_max, dmin, spacegroup='1'): """ Parameters ---------- s0 : array a 3 vector indicating the direction of the incoming beam wavevector. This can be any length, it will be unit normalized in the constructor. s1 : array n x 3 array indicating the direction of the scatterd beam wavevector. This can be any length, it will be unit normalized in the constructor. cell : iterable or gemmi.UnitCell A tuple or list of unit cell params (a, b, c, alpha, beta, gamma) or a gemmi.UnitCell object R : array A 3x3 rotation matrix corresponding to the crystal orientation for the frame. lam_min : float The lower end of the wavelength range of the beam. lam_max : float The upper end of the wavelength range of the beam. dmin : float The maximum resolution of the model spacegroup : gemmi.SpaceGroup (optional) Anything that the gemmi.SpaceGroup constructor understands. """ if not isinstance(cell, gemmi.UnitCell): cell = gemmi.UnitCell(*cell) self.cell = cell if not isinstance(spacegroup, gemmi.SpaceGroup): spacegroup = gemmi.SpaceGroup(spacegroup) self.spacegroup = spacegroup self.R = R self.lam_min = lam_min self.lam_max = lam_max self.dmin = dmin self.B = np.array(self.cell.fractionalization_matrix).T self.ewald_offset = None # self.s{0,1} are dynamically masked by their outlier status self.s0 = s0 / np.linalg.norm(s0) self._s1 = s1 / np.linalg.norm(s1, axis=-1)[:, None] self._qobs = self._s1 - self.s0 self._qpred = np.zeros_like(self._s1) self._H = np.zeros_like(self._s1) self._wav = np.zeros(len(self._H)) self._harmonics = np.zeros(len(self._s1), dtype=bool) self._inliers = np.ones(len(self._s1), dtype=bool) #Initialize the full reciprocal grid hmax, kmax, lmax = self.cell.get_hkl_limits(dmin) Hall = np.mgrid[-hmax:hmax + 1:1., -kmax:kmax + 1:1., -lmax:lmax + 1:1., ].reshape((3, -1)).T Hall = Hall[np.any(Hall != 0, axis=1)] d = cell.calculate_d_array(Hall) Hall = Hall[d >= dmin] #Just remove any systematic absences in the space group Hall = Hall[~rs.utils.is_absent(Hall, self.spacegroup)] self.Hall = Hall
def read_precognition(hklfile,a=None, b=None, c=None, alpha=None, beta=None, gamma=None, sg=None, logfile=None): """ Initialize attributes and populate the DataSet object with data from a HKL file of reflections. This is the output format used by Precognition when processing Laue diffraction data. Parameters ---------- hklfile : str or file name of an hkl file or a file object a : float edge length, a, of the unit cell b : float edge length, b, of the unit cell c : float edge length, c, of the unit cell alpha : float interaxial angle, alpha, of the unit cell beta : float interaxial angle, beta, of the unit cell gamma : float interaxial angle, gamma, of the unit cell sg : str or int If int, this should specify the space group number. If str, this should be a space group symbol logfile : str or file name of a log file to parse to get cell parameters and sg """ # Read data from HKL file if hklfile.endswith(".hkl"): usecols = [0, 1, 2, 3, 4, 5, 6] F = pd.read_csv(hklfile, header=None, delim_whitespace=True, names=["H", "K", "L", "F+", "SigF+", "F-", "SigF-"], usecols=usecols) mtztypes = ["H", "H", "H", "G", "L", "G", "L"] # Check if any anomalous data is actually included if len(F["F-"].unique()) == 1: F = F[["H", "K", "L", "F+", "SigF+"]] F.rename(columns={"F+":"F", "SigF+":"SigF"}, inplace=True) mtztypes = ["H", "H", "H", "F", "Q"] elif hklfile.endswith(".ii"): usecols = range(10) F = pd.read_csv(hklfile, header=None, delim_whitespace=True, names=["H", "K", "L", "Multiplicity", "X", "Y", "Resolution", "Wavelength", "I", "SigI"], usecols=usecols) mtztypes = ["H", "H", "H", "I", "R", "R", "R", "R", "J", "Q"] # If logfile is given, read cell parameters and spacegroup if logfile: from os.path import basename with open(logfile, "r") as log: lines = log.readlines() # Read spacegroup sgline = [ l for l in lines if "space-group" in l ][0] sg = [ s for s in sgline.split() if "#" in s ][0].lstrip("#") # Read cell parameters block = [ i for i, l in enumerate(lines) if basename(hklfile) in l ][0] lengths = lines[block-19].split()[-3:] a, b, c = map(float, lengths) angles = lines[block-18].split()[-3:] alpha, beta, gamma = map(float, angles) # GH#32: Limit use to supported file formats else: raise ValueError("rs.read_precognition() only supports .ii and .hkl files") dataset = DataSet() for (k,v), mtztype in zip(F.items(), mtztypes): dataset[k] = v dataset[k] = dataset[k].astype(mtztype) dataset.set_index(["H", "K", "L"], inplace=True) # Set DataSet attributes if (a and b and c and alpha and beta and gamma): dataset.cell = gemmi.UnitCell(a, b, c, alpha, beta, gamma) if sg: dataset.spacegroup = gemmi.SpaceGroup(sg) return dataset
cryst2 = elist2.crystals()[0] unit_cell2 = cryst2.get_unit_cell() refls2 = reflection_table.from_file(refl_file2) # Remove reflections not used in refinement refls2 = refls2.select(refls2.get_flags(refls2.flags.used_in_refinement)) print('generating DIALS dataframes') dials_df1 = rs.DataSet( { 'X': refls1['xyzobs.px.value'].parts()[0].as_numpy_array(), 'Y': refls1['xyzobs.px.value'].parts()[1].as_numpy_array(), 'Wavelength': refls1['Wavelength'].as_numpy_array(), 'BATCH': refls1['imageset_id'].as_numpy_array(), }, cell=gemmi.UnitCell(*unit_cell1.parameters()), spacegroup=gemmi.SpaceGroup(cryst1.get_space_group().type( ).universal_hermann_mauguin_symbol())).infer_mtz_dtypes() dials_df2 = rs.DataSet( { 'X': refls2['xyzobs.px.value'].parts()[0].as_numpy_array(), 'Y': refls2['xyzobs.px.value'].parts()[1].as_numpy_array(), 'Wavelength': refls2['Wavelength'].as_numpy_array(), 'BATCH': refls2['imageset_id'].as_numpy_array(), }, cell=gemmi.UnitCell(*unit_cell2.parameters()), spacegroup=gemmi.SpaceGroup(cryst2.get_space_group().type( ).universal_hermann_mauguin_symbol())).infer_mtz_dtypes() print('initializing metrics') nspots = np.zeros(len(elist2))
experiment = elist[0] while (True): # Get first expt for this image experiment = elist[i] if (experiment.imageset == img): break i = i + 1 cryst = experiment.crystal spacegroup = gemmi.SpaceGroup( cryst.get_space_group().type().universal_hermann_mauguin_symbol()) # Get beam vector s0 = np.array(experiment.beam.get_s0()) # Get unit cell params cell_params = cryst.get_unit_cell().parameters() cell = gemmi.UnitCell(*cell_params) # Get U matrix U = np.asarray(cryst.get_U()).reshape(3, 3) # Get observed centroids sub_refls = refls.select(refls['imageset_id'] == img_num) xobs = sub_refls['xyzobs.mm.value'].parts()[0].as_numpy_array() yobs = sub_refls['xyzobs.mm.value'].parts()[1].as_numpy_array() # Wavelengths per spot lams = sub_refls['Wavelength'].as_numpy_array() # Hyperparameters for predictor lam_min = 0.95 lam_max = 1.25
import pytest import numpy as np import reciprocalspaceship as rs import gemmi @pytest.mark.parametrize("cell_and_spacegroup", [ (gemmi.UnitCell(10., 20., 30., 90., 90., 90.), gemmi.SpaceGroup('P 21 21 21')), (gemmi.UnitCell(30., 30., 30., 90., 90., 120.), gemmi.SpaceGroup('R 32')), ]) @pytest.mark.parametrize("anomalous", [False, True]) @pytest.mark.parametrize("full_asu", [False, True]) def test_compute_redundancy(cell_and_spacegroup, anomalous, full_asu): """ Test reciprocalspaceship.utils.compute_redundancy. """ dmin = 5. cell,spacegroup = cell_and_spacegroup hkl = rs.utils.generate_reciprocal_asu(cell, spacegroup, dmin, anomalous=anomalous) mult = np.random.choice(10, size=len(hkl)) hobs = np.repeat(hkl, mult, axis=0) hunique, counts = rs.utils.compute_redundancy(hobs, cell, spacegroup, full_asu=full_asu, anomalous=anomalous) assert hunique.dtype == np.int32 assert counts.dtype == np.int32 assert len(hkl) == len(mult) assert len(np.unique(hobs, axis=0)) == np.sum(counts > 0) assert np.all(counts[counts>0] == mult[mult > 0])
assert np.isclose(np.sin(phis), np.sin(ref_phis)).all() assert np.isclose(np.cos(phis), np.cos(ref_phis)).all() def test_hkl_to_observed(sgtbx_by_xhm): xhm = sgtbx_by_xhm[0] reference = sgtbx_by_xhm[1] H = reference[['h', 'k', 'l']].to_numpy() sg = gemmi.SpaceGroup(xhm) Hasu, isym = rs.utils.hkl_to_asu(H, sg) H_observed = rs.utils.hkl_to_observed(Hasu, isym, sg) assert np.array_equal(H, H_observed) @pytest.mark.parametrize("cell_and_spacegroup", [ (gemmi.UnitCell(10., 20., 30., 90., 80., 75.), gemmi.SpaceGroup('P 1')), (gemmi.UnitCell(30., 50., 80., 90., 100., 90.), gemmi.SpaceGroup('P 1 21 1')), (gemmi.UnitCell(10., 20., 30., 90., 90., 90.), gemmi.SpaceGroup('P 21 21 21')), (gemmi.UnitCell(89., 89., 105., 90., 90., 120.), gemmi.SpaceGroup('P 31 2 1')), (gemmi.UnitCell(30., 30., 30., 90., 90., 120.), gemmi.SpaceGroup('R 32')), ]) @pytest.mark.parametrize("dmin", [6., 5., 4.]) @pytest.mark.parametrize("anomalous", [False, True]) def test_generate_reciprocal_asu(cell_and_spacegroup, dmin, anomalous): """ Test generate_reciprocal_asu(). This test confirms that all generated Miller indices are in the ASU and valid given the designated criteria. """