reciprocalspaceship 1.0.2__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reciprocalspaceship might be problematic. Click here for more details.

Files changed (70) hide show
  1. {reciprocalspaceship-1.0.2/reciprocalspaceship.egg-info → reciprocalspaceship-1.0.4}/PKG-INFO +43 -3
  2. reciprocalspaceship-1.0.4/reciprocalspaceship/VERSION +1 -0
  3. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/__init__.py +9 -2
  4. reciprocalspaceship-1.0.4/reciprocalspaceship/commandline/cifdump.py +115 -0
  5. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/commandline/mtzdump.py +7 -3
  6. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dataset.py +75 -24
  7. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/decorators.py +6 -2
  8. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/internals.py +1 -1
  9. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/__init__.py +1 -0
  10. reciprocalspaceship-1.0.4/reciprocalspaceship/io/common.py +48 -0
  11. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/crystfel.py +17 -26
  12. reciprocalspaceship-1.0.4/reciprocalspaceship/io/dials.py +330 -0
  13. reciprocalspaceship-1.0.4/reciprocalspaceship/io/dials_mpi.py +44 -0
  14. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/mtz.py +4 -5
  15. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/precognition.py +2 -2
  16. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/cell.py +1 -1
  17. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/grid.py +2 -1
  18. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/structurefactors.py +1 -1
  19. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4/reciprocalspaceship.egg-info}/PKG-INFO +43 -3
  20. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship.egg-info/SOURCES.txt +5 -0
  21. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship.egg-info/entry_points.txt +1 -0
  22. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship.egg-info/requires.txt +3 -2
  23. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/setup.py +4 -2
  24. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset.py +89 -0
  25. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_grid.py +2 -2
  26. reciprocalspaceship-1.0.4/tests/test_dataset_signatures.py +53 -0
  27. reciprocalspaceship-1.0.2/reciprocalspaceship/VERSION +0 -1
  28. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/LICENSE +0 -0
  29. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/MANIFEST.in +0 -0
  30. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/README.md +0 -0
  31. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/algorithms/__init__.py +0 -0
  32. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/algorithms/intensity.py +0 -0
  33. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/algorithms/merge.py +0 -0
  34. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/algorithms/scale_merged_intensities.py +0 -0
  35. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/commandline/__init__.py +0 -0
  36. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/concat.py +0 -0
  37. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dataseries.py +0 -0
  38. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/__init__.py +0 -0
  39. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/base.py +0 -0
  40. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/floating.py +0 -0
  41. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/inference.py +0 -0
  42. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/integer.py +0 -0
  43. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/dtypes/summarize.py +0 -0
  44. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/ccp4map.py +0 -0
  45. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/csv.py +0 -0
  46. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/io/pickle.py +0 -0
  47. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/stats/__init__.py +0 -0
  48. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/stats/completeness.py +0 -0
  49. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/__init__.py +0 -0
  50. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/asu.py +0 -0
  51. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/binning.py +0 -0
  52. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/math.py +0 -0
  53. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/phases.py +0 -0
  54. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/rfree.py +0 -0
  55. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/stats.py +0 -0
  56. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/symmetry.py +0 -0
  57. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship/utils/units.py +0 -0
  58. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship.egg-info/dependency_links.txt +0 -0
  59. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/reciprocalspaceship.egg-info/top_level.txt +0 -0
  60. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/setup.cfg +0 -0
  61. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/__init__.py +0 -0
  62. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/conftest.py +0 -0
  63. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataseries.py +0 -0
  64. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_anomalous.py +0 -0
  65. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_binning.py +0 -0
  66. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_index.py +0 -0
  67. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_preserve_attributes.py +0 -0
  68. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_dataset_symops.py +0 -0
  69. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_decorators.py +0 -0
  70. {reciprocalspaceship-1.0.2 → reciprocalspaceship-1.0.4}/tests/test_summarize_mtz_dtypes.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: reciprocalspaceship
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Tools for exploring reciprocal space
5
5
  Home-page: https://rs-station.github.io/reciprocalspaceship/
6
6
  Author: Kevin M. Dalton, Jack B. Greisman
@@ -18,9 +18,49 @@ Classifier: Topic :: Scientific/Engineering :: Physics
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Classifier: Programming Language :: Python
20
20
  Requires-Python: >=3.9
21
+ License-File: LICENSE
22
+ Requires-Dist: gemmi<=0.7.1,>=0.7.0
23
+ Requires-Dist: pandas<=2.2.3,>=2.2.2
24
+ Requires-Dist: numpy
25
+ Requires-Dist: scipy
26
+ Requires-Dist: ipython
27
+ Requires-Dist: msgpack
21
28
  Provides-Extra: dev
29
+ Requires-Dist: pytest; extra == "dev"
30
+ Requires-Dist: pytest-cov; extra == "dev"
31
+ Requires-Dist: pytest-xdist; extra == "dev"
32
+ Requires-Dist: ray; extra == "dev"
33
+ Requires-Dist: sphinx; extra == "dev"
34
+ Requires-Dist: sphinx_rtd_theme; extra == "dev"
35
+ Requires-Dist: nbsphinx; extra == "dev"
36
+ Requires-Dist: sphinx-design; extra == "dev"
37
+ Requires-Dist: sphinxcontrib-autoprogram; extra == "dev"
38
+ Requires-Dist: autodocsumm; extra == "dev"
39
+ Requires-Dist: jupyter; extra == "dev"
40
+ Requires-Dist: tqdm; extra == "dev"
41
+ Requires-Dist: matplotlib; extra == "dev"
42
+ Requires-Dist: seaborn; extra == "dev"
43
+ Requires-Dist: celluloid; extra == "dev"
44
+ Requires-Dist: scikit-image; extra == "dev"
22
45
  Provides-Extra: examples
23
- License-File: LICENSE
46
+ Requires-Dist: jupyter; extra == "examples"
47
+ Requires-Dist: tqdm; extra == "examples"
48
+ Requires-Dist: matplotlib; extra == "examples"
49
+ Requires-Dist: seaborn; extra == "examples"
50
+ Requires-Dist: celluloid; extra == "examples"
51
+ Requires-Dist: scikit-image; extra == "examples"
52
+ Dynamic: author
53
+ Dynamic: author-email
54
+ Dynamic: classifier
55
+ Dynamic: description
56
+ Dynamic: home-page
57
+ Dynamic: license
58
+ Dynamic: license-file
59
+ Dynamic: project-url
60
+ Dynamic: provides-extra
61
+ Dynamic: requires-dist
62
+ Dynamic: requires-python
63
+ Dynamic: summary
24
64
 
25
65
 
26
66
  ``reciprocalspaceship`` provides a ``pandas``-style interface for
@@ -1,8 +1,15 @@
1
1
  # Version number for reciprocalspaceship
2
2
  def getVersionNumber():
3
- import pkg_resources
3
+ version = None
4
+ try:
5
+ from setuptools.version import metadata
6
+
7
+ version = metadata.version("reciprocalspaceship")
8
+ except ImportError:
9
+ from setuptools.version import pkg_resources
10
+
11
+ version = pkg_resources.require("reciprocalspaceship")[0].version
4
12
 
5
- version = pkg_resources.require("reciprocalspaceship")[0].version
6
13
  return version
7
14
 
8
15
 
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Summarize the contents of a CIF file.
4
+
5
+ Examples
6
+ --------
7
+ In order to summarize contents of file.cif::
8
+
9
+ > rs.cifdump file.cif
10
+
11
+ If you would like to interactively inspect file.cif in an IPython
12
+ shell, use the "--embed" argument::
13
+
14
+ > rs.cifdump file.cif --embed
15
+
16
+ If multiple CIF files are listed, they will be summarized sequentially,
17
+ and can be accessed in an IPython shell as a dictionary called `cifs`::
18
+
19
+ > rs.cifdump file1.cif file2.cif file3.cif --embed
20
+
21
+ Usage Details
22
+ -------------
23
+ """
24
+ import argparse
25
+
26
+ import pandas as pd
27
+
28
+ import reciprocalspaceship as rs
29
+
30
+ # If matplotlib is available, use pylab to setup IPython environment
31
+ try:
32
+ from pylab import *
33
+ except:
34
+ pass
35
+
36
+
37
+ def parse_arguments():
38
+ """Parse commandline arguments"""
39
+
40
+ parser = argparse.ArgumentParser(
41
+ formatter_class=argparse.RawTextHelpFormatter, description=__doc__
42
+ )
43
+
44
+ # Required arguments
45
+ parser.add_argument("cif", nargs="+", help="CIF file(s) to summarize")
46
+
47
+ # Optional arguments
48
+ parser.add_argument(
49
+ "--embed",
50
+ action="store_true",
51
+ help=(
52
+ "CIF file(s) will be summarized, and an IPython " "shell will be started"
53
+ ),
54
+ )
55
+ parser.add_argument(
56
+ "-p",
57
+ "--precision",
58
+ type=int,
59
+ default=3,
60
+ help="Number of significant digits to output for floats",
61
+ )
62
+
63
+ return parser
64
+
65
+
66
+ def summarize(cif, precision):
67
+ """Summarize contents of CIF file"""
68
+ with pd.option_context("display.precision", precision):
69
+ print(f"Spacegroup: {cif.spacegroup.short_name()}")
70
+ print(f"Extended Hermann-Mauguin name: {cif.spacegroup.xhm()}")
71
+ print(
72
+ (
73
+ f"Unit cell dimensions: {cif.cell.a:.3f} {cif.cell.b:.3f} {cif.cell.c:.3f} "
74
+ f"{cif.cell.alpha:.3f} {cif.cell.beta:.3f} {cif.cell.gamma:.3f}"
75
+ )
76
+ )
77
+ print(f"\ncif.head():\n\n{cif.head()}")
78
+ print(f"\ncif.describe():\n\n{cif.describe()}")
79
+ print(f"\ncif.dtypes:\n\n{cif.dtypes}")
80
+ return
81
+
82
+
83
+ def main():
84
+ # Parse commandline arguments
85
+ parser = parse_arguments()
86
+ args = parser.parse_args()
87
+
88
+ if len(args.cif) == 1:
89
+ cif = rs.read_cif(args.cif[0])
90
+ summarize(cif, args.precision)
91
+ else:
92
+ cifs = dict(zip(args.cif, map(rs.read_cif, args.cif)))
93
+ for key, value in cifs.items():
94
+ print(f"CIF file: {key}\n")
95
+ summarize(value, args.precision)
96
+ print(f"{'-'*50}")
97
+
98
+ # Begin IPython shell
99
+ if args.embed:
100
+ from IPython import embed
101
+
102
+ bold = "\033[1m"
103
+ end = "\033[0m"
104
+ if "cifs" in locals():
105
+ header = f"rs.DataSets stored in {bold}cifs{end} dictionary"
106
+ else:
107
+ header = f"rs.DataSet stored as {bold}cif{end}"
108
+ print()
109
+ embed(colors="neutral", header=header)
110
+
111
+ return
112
+
113
+
114
+ if __name__ == "__main__":
115
+ parser = main()
@@ -74,9 +74,13 @@ def summarize(mtz, precision):
74
74
  f"{mtz.cell.alpha:.3f} {mtz.cell.beta:.3f} {mtz.cell.gamma:.3f}"
75
75
  )
76
76
  )
77
- print(f"\nmtz.head():\n\n{mtz.head()}")
78
- print(f"\nmtz.describe():\n\n{mtz.describe()}")
79
- print(f"\nmtz.dtypes:\n\n{mtz.dtypes}")
77
+ if mtz.cell is not None:
78
+ dHKL = mtz.compute_dHKL().dHKL
79
+ print(f"Resolution range: {dHKL.max():.3f} - {dHKL.min():.3f} Å")
80
+ with pd.option_context("display.max_rows", None):
81
+ print(f"\nmtz.head():\n\n{mtz.head()}")
82
+ print(f"\nmtz.describe().T:\n\n{mtz.describe().T}")
83
+ print(f"\nmtz.dtypes:\n\n{mtz.dtypes}")
80
84
  return
81
85
 
82
86
 
@@ -43,6 +43,23 @@ class DataSet(pd.DataFrame):
43
43
  and attributes, please see the `Pandas.DataFrame documentation`_.
44
44
 
45
45
  .. _Pandas.DataFrame documentation: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html
46
+
47
+ Attributes
48
+ ----------
49
+ acentrics : rs.DataSet
50
+ Access only the acentric reflections in this dataset
51
+ cell : gemmi.UnitCell
52
+ The unit cell
53
+ centrics : rs.DataSet
54
+ Access only the centric reflections in this dataset
55
+ hkls : ndarray, shape=(n_reflections, 3)
56
+ Miller indices in DataSet.
57
+ merged : bool
58
+ Whether this is a merged dataset or unmerged
59
+ spacegroup : gemmi.SpaceGroup
60
+ The space group
61
+ reindexing_ops : list
62
+ Possible reindexing ops consistent with the cell and spacegroup
46
63
  """
47
64
 
48
65
  _metadata = ["_spacegroup", "_cell", "_index_dtypes", "_merged"]
@@ -131,6 +148,38 @@ class DataSet(pd.DataFrame):
131
148
  def merged(self, val):
132
149
  self._merged = val
133
150
 
151
+ @property
152
+ @range_indexed
153
+ def hkls(self):
154
+ """Miller indices"""
155
+ hkl = self[["H", "K", "L"]].to_numpy(dtype=np.int32)
156
+ return hkl
157
+
158
+ def get_hkls(self):
159
+ """Get the Miller indices of the dataset."""
160
+ return self.hkls
161
+
162
+ @hkls.setter
163
+ @range_indexed
164
+ def hkls(self, hkls):
165
+ if isinstance(hkls, DataSet):
166
+ """Convert to numpy if hkls is a dataset"""
167
+ hkls = hkls.hkls
168
+ if isinstance(hkls, np.ndarray):
169
+ h, k, l = hkls[..., 0], hkls[..., 1], hkls[..., 2]
170
+ else:
171
+ """Try coercing to numpy"""
172
+ try:
173
+ hkls = np.array(hkls)
174
+ h, k, l = hkls[..., 0], hkls[..., 1], hkls[..., 2]
175
+ except:
176
+ raise ValueError(
177
+ "Unable to convert hkls to a suitable type. Please ensure hkls is a numpy array or rs.DataSet"
178
+ )
179
+ self["H"] = DataSeries(h, index=self.index, dtype="H")
180
+ self["K"] = DataSeries(k, index=self.index, dtype="H")
181
+ self["L"] = DataSeries(l, index=self.index, dtype="H")
182
+
134
183
  @property
135
184
  def centrics(self):
136
185
  """Access centric reflections in DataSet"""
@@ -258,7 +307,14 @@ class DataSet(pd.DataFrame):
258
307
  )
259
308
 
260
309
  def reset_index(
261
- self, level=None, drop=False, inplace=False, col_level=0, col_fill=""
310
+ self,
311
+ level=None,
312
+ drop=False,
313
+ inplace=False,
314
+ col_level=0,
315
+ col_fill="",
316
+ allow_duplicates=lib.no_default,
317
+ names=None,
262
318
  ):
263
319
  """
264
320
  Reset the index or a specific level of a MultiIndex.
@@ -281,6 +337,12 @@ class DataSet(pd.DataFrame):
281
337
  col_fill : object
282
338
  If the columns have multiple levels, determines how the other
283
339
  levels are named. If None then the index name is repeated.
340
+ allow_duplicates : bool
341
+ Allow duplicate column labels to be created.
342
+ names : int, str, tuple, list
343
+ Using the given string, rename the DataSet column which contains the
344
+ index data. If the DataSet has a MultiIndex, this has to be a list or
345
+ tuple with length equal to the number of levels.
284
346
 
285
347
  Returns
286
348
  -------
@@ -317,6 +379,8 @@ class DataSet(pd.DataFrame):
317
379
  inplace=inplace,
318
380
  col_level=col_level,
319
381
  col_fill=col_fill,
382
+ allow_duplicates=allow_duplicates,
383
+ names=names,
320
384
  )
321
385
  _handle_cached_dtypes(self, columns, drop)
322
386
  return
@@ -327,6 +391,8 @@ class DataSet(pd.DataFrame):
327
391
  inplace=inplace,
328
392
  col_level=col_level,
329
393
  col_fill=col_fill,
394
+ allow_duplicates=allow_duplicates,
395
+ names=names,
330
396
  )
331
397
  dataset._index_dtypes = dataset._index_dtypes.copy()
332
398
  dataset = _handle_cached_dtypes(dataset, columns, drop)
@@ -406,6 +472,7 @@ class DataSet(pd.DataFrame):
406
472
  """
407
473
  return cls(gemmiMtz)
408
474
 
475
+ @range_indexed
409
476
  def to_gemmi(
410
477
  self,
411
478
  skip_problem_mtztypes=False,
@@ -575,6 +642,7 @@ class DataSet(pd.DataFrame):
575
642
  result = super().join(*args, **kwargs)
576
643
  return result.__finalize__(self)
577
644
 
645
+ @range_indexed
578
646
  def write_mtz(
579
647
  self,
580
648
  mtzfile,
@@ -1158,7 +1226,7 @@ class DataSet(pd.DataFrame):
1158
1226
 
1159
1227
  return result
1160
1228
 
1161
- def is_isomorphous(self, other, cell_threshold=0.05):
1229
+ def is_isomorphous(self, other, cell_threshold=0.5):
1162
1230
  """
1163
1231
  Determine whether DataSet is isomorphous to another DataSet. This
1164
1232
  method confirms isomorphism by ensuring the spacegroups are equivalent,
@@ -1195,7 +1263,8 @@ class DataSet(pd.DataFrame):
1195
1263
  for param in params:
1196
1264
  param1 = self.cell.__getattribute__(param)
1197
1265
  param2 = other.cell.__getattribute__(param)
1198
- if (np.abs((param1 - param2)) / 100.0) > cell_threshold:
1266
+ diff = 200.0 * np.abs(param1 - param2) / (param1 + param2)
1267
+ if diff > cell_threshold:
1199
1268
  return False
1200
1269
 
1201
1270
  return True
@@ -1565,24 +1634,6 @@ class DataSet(pd.DataFrame):
1565
1634
  warnings.simplefilter("always")
1566
1635
  warnings.warn(message, DeprecationWarning)
1567
1636
 
1568
- if dmin is not None:
1569
- ds = self.loc[self.compute_dHKL().dHKL >= dmin, [key]]
1570
- else:
1571
- ds = self.loc[:, [key]]
1572
-
1573
- if gridsize is None:
1574
- gridsize = self.get_reciprocal_grid_size(dmin=dmin, sample_rate=sample_rate)
1575
-
1576
- # Set up P1 unit cell
1577
- p1 = ds.expand_to_p1()
1578
- p1 = p1.expand_anomalous()
1579
-
1580
- # Get data and indices
1581
- data = p1[key].to_numpy()
1582
- H = p1.get_hkls()
1583
-
1584
- # Populate grid
1585
- grid = np.zeros(gridsize, dtype=data.dtype)
1586
- grid[H[:, 0], H[:, 1], H[:, 2]] = data
1587
-
1588
- return grid
1637
+ return self.to_reciprocal_grid(
1638
+ key, sample_rate=sample_rate, dmin=dmin, grid_size=gridsize
1639
+ )
@@ -4,6 +4,8 @@ from inspect import signature
4
4
  import gemmi
5
5
  import numpy as np
6
6
 
7
+ import reciprocalspaceship as rs
8
+
7
9
 
8
10
  def inplace(f):
9
11
  """
@@ -46,9 +48,11 @@ def range_indexed(f):
46
48
  names = ds.index.names
47
49
  ds = ds._index_from_names([None], inplace=True)
48
50
  result = f(ds, *args, **kwargs)
49
- result = result._index_from_names(names, inplace=True)
50
51
  ds = ds._index_from_names(names, inplace=True)
51
- return result.__finalize__(ds)
52
+ if isinstance(result, rs.DataSet):
53
+ result = result._index_from_names(names, inplace=True)
54
+ result = result.__finalize__(ds)
55
+ return result
52
56
 
53
57
  return wrapped
54
58
 
@@ -1359,7 +1359,7 @@ class NumericArray(BaseMaskedArray):
1359
1359
 
1360
1360
  @wraps(libmissing.is_numeric_na)
1361
1361
  def is_numeric_na(values):
1362
- allowed_dtypes = ("float32", "int32")
1362
+ allowed_dtypes = ("float64", "float32", "int32")
1363
1363
  if isinstance(values, np.ndarray) and values.dtype in allowed_dtypes:
1364
1364
  return np.isnan(values)
1365
1365
  return libmissing.is_numeric_na(values)
@@ -1,6 +1,7 @@
1
1
  from reciprocalspaceship.io.ccp4map import write_ccp4_map
2
2
  from reciprocalspaceship.io.crystfel import read_crystfel
3
3
  from reciprocalspaceship.io.csv import read_csv
4
+ from reciprocalspaceship.io.dials import print_refl_info, read_dials_stills
4
5
  from reciprocalspaceship.io.mtz import (
5
6
  from_gemmi,
6
7
  read_cif,
@@ -0,0 +1,48 @@
1
+ import logging
2
+ import warnings
3
+ from contextlib import contextmanager
4
+ from importlib.util import find_spec
5
+
6
+
7
+ def set_ray_loglevel(level):
8
+ logger = logging.getLogger("ray")
9
+ logger.setLevel(level)
10
+ for handler in logger.handlers:
11
+ handler.setLevel(level)
12
+
13
+
14
+ def check_for_ray():
15
+ has_ray = True
16
+ if find_spec("ray") is None:
17
+ has_ray = False
18
+
19
+ message = (
20
+ "ray (https://www.ray.io/) is not available..." "Falling back to serial."
21
+ )
22
+ warnings.warn(message, ImportWarning)
23
+ return has_ray
24
+
25
+
26
+ def check_for_mpi():
27
+ try:
28
+ from mpi4py import MPI
29
+
30
+ return True
31
+ except Exception as err:
32
+ message = (
33
+ f"Failed `from mpi4py import MPI` with {err}. Falling back to serial mode."
34
+ )
35
+ warnings.warn(message, ImportWarning)
36
+ return False
37
+
38
+
39
+ @contextmanager
40
+ def ray_context(log_level="DEBUG", **ray_kwargs):
41
+ import ray
42
+
43
+ set_ray_loglevel(log_level)
44
+ ray.init(**ray_kwargs)
45
+ try:
46
+ yield ray
47
+ finally:
48
+ ray.shutdown()
@@ -1,13 +1,12 @@
1
1
  import mmap
2
2
  import re
3
- from contextlib import contextmanager
4
- from importlib.util import find_spec
5
3
  from typing import Union
6
4
 
7
5
  import gemmi
8
6
  import numpy as np
9
7
 
10
8
  from reciprocalspaceship import DataSet, concat
9
+ from reciprocalspaceship.io.common import check_for_ray, ray_context
11
10
  from reciprocalspaceship.utils import angle_between, eV2Angstroms
12
11
 
13
12
  # See Rupp Table 5-2
@@ -60,17 +59,6 @@ _block_markers = {
60
59
  }
61
60
 
62
61
 
63
- @contextmanager
64
- def ray_context(**ray_kwargs):
65
- import ray
66
-
67
- ray.init(**ray_kwargs)
68
- try:
69
- yield ray
70
- finally:
71
- ray.shutdown()
72
-
73
-
74
62
  class StreamLoader(object):
75
63
  """
76
64
  An object that loads stream files into rs.DataSet objects in parallel.
@@ -304,15 +292,7 @@ class StreamLoader(object):
304
292
 
305
293
  # Check whether ray is available
306
294
  if use_ray:
307
- if find_spec("ray") is None:
308
- use_ray = False
309
- import warnings
310
-
311
- message = (
312
- "ray (https://www.ray.io/) is not available..."
313
- "Falling back to serial stream file parser."
314
- )
315
- warnings.warn(message, ImportWarning)
295
+ use_ray = check_for_ray()
316
296
 
317
297
  with open(self.filename, "r") as f:
318
298
  memfile = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
@@ -507,10 +487,9 @@ def read_crystfel(
507
487
  The type of byte-encoding (optional, 'utf-8').
508
488
  columns : list (optional)
509
489
  Optionally specify the columns of the output by a list of strings.
510
- The default list is:
511
- [ "H", "K", "L", "I", "SigI", "BATCH", "s1x", "s1y", "s1z", "ewald_offset",
512
- "angular_ewald_offset", "XDET", "YDET" ]
513
- See `rs.io.crystfel.StreamLoader().available_column_names` for a list of available column names.
490
+ The default list is: [ "H", "K", "L", "I", "SigI", "BATCH", "s1x", "s1y", "s1z", "ewald_offset", "angular_ewald_offset", "XDET", "YDET" ]
491
+ See `rs.io.crystfel.StreamLoader().available_column_names` for a list of available
492
+ column names and *Notes* for a description of the returned columns
514
493
  parallel : bool (optional)
515
494
  Read the stream file in parallel using [ray.io](https://docs.ray.io) if it is available.
516
495
  num_cpus : int (optional)
@@ -524,6 +503,18 @@ def read_crystfel(
524
503
  Returns
525
504
  --------
526
505
  rs.DataSet
506
+
507
+ Notes
508
+ -----
509
+ The following columns are included in the returned DataSet object:
510
+
511
+ - H, K, L: Miller indices of each reflection
512
+ - I, SigI: Intensity and associated uncertainty
513
+ - BATCH: Image number
514
+ - s1x, s1y, s1z: scattered beam wavevector which points from the sample to the bragg peak
515
+ - ewald_offset: the distance in cartesian space (1/angstroms) between the observed reflection and the ewald sphere
516
+ - angular_ewald_offset: the distance in polar coordinates (degrees) between the observed reflection and the ewald sphere
517
+ - XDET, YDET: Internal detector panel coordinates
527
518
  """
528
519
  if not streamfile.endswith(".stream"):
529
520
  raise ValueError("Stream file should end with .stream")