reciprocalspaceship 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl
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.
- reciprocalspaceship/VERSION +1 -1
- reciprocalspaceship/__init__.py +9 -2
- reciprocalspaceship/algorithms/scale_merged_intensities.py +8 -7
- reciprocalspaceship/dataset.py +28 -3
- reciprocalspaceship/decorators.py +8 -4
- reciprocalspaceship/dtypes/floating.py +24 -28
- reciprocalspaceship/dtypes/integer.py +38 -37
- reciprocalspaceship/dtypes/internals.py +243 -49
- reciprocalspaceship/io/__init__.py +1 -0
- reciprocalspaceship/io/common.py +48 -0
- reciprocalspaceship/io/crystfel.py +559 -234
- reciprocalspaceship/io/dials.py +330 -0
- reciprocalspaceship/io/dials_mpi.py +44 -0
- reciprocalspaceship/io/mtz.py +4 -5
- reciprocalspaceship/utils/__init__.py +6 -1
- reciprocalspaceship/utils/cell.py +5 -0
- reciprocalspaceship/utils/stats.py +5 -7
- reciprocalspaceship/utils/structurefactors.py +5 -0
- reciprocalspaceship/utils/units.py +14 -4
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/METADATA +27 -28
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/RECORD +28 -24
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/WHEEL +1 -1
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/entry_points.txt +0 -1
- tests/test_dataseries.py +1 -1
- tests/test_dataset.py +42 -0
- tests/test_dataset_signatures.py +53 -0
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/LICENSE +0 -0
- {reciprocalspaceship-1.0.1.dist-info → reciprocalspaceship-1.0.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import msgpack
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas
|
|
7
|
+
|
|
8
|
+
LOGGER = logging.getLogger("rs.io.dials")
|
|
9
|
+
if not LOGGER.handlers:
|
|
10
|
+
LOGGER.setLevel(logging.DEBUG)
|
|
11
|
+
console = logging.StreamHandler(stream=sys.stdout)
|
|
12
|
+
console.setLevel(logging.DEBUG)
|
|
13
|
+
LOGGER.addHandler(console)
|
|
14
|
+
|
|
15
|
+
import reciprocalspaceship as rs
|
|
16
|
+
from reciprocalspaceship.decorators import cellify, spacegroupify
|
|
17
|
+
from reciprocalspaceship.io.common import check_for_ray, set_ray_loglevel
|
|
18
|
+
|
|
19
|
+
MSGPACK_DTYPES = {
|
|
20
|
+
"double": np.float64,
|
|
21
|
+
"float": np.float32,
|
|
22
|
+
"int": np.int32,
|
|
23
|
+
"cctbx::miller::index<>": np.int32,
|
|
24
|
+
"vec3<double>": np.float64,
|
|
25
|
+
"std::size_t": np.intp,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
DEFAULT_COLS = [
|
|
29
|
+
"miller_index",
|
|
30
|
+
"intensity.sum.value",
|
|
31
|
+
"intensity.sum.variance",
|
|
32
|
+
"xyzcal.px",
|
|
33
|
+
"s1",
|
|
34
|
+
"delpsical.rad",
|
|
35
|
+
"id",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _set_logger(verbose):
|
|
40
|
+
level = logging.CRITICAL
|
|
41
|
+
if verbose:
|
|
42
|
+
level = logging.DEBUG
|
|
43
|
+
|
|
44
|
+
for log_name in ("rs.io.dials", "ray"):
|
|
45
|
+
logger = logging.getLogger(log_name)
|
|
46
|
+
logger.setLevel(level)
|
|
47
|
+
for handler in logger.handlers:
|
|
48
|
+
handler.setLevel(level)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_msgpack_data(data, name):
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
data: msgpack data dict
|
|
57
|
+
name: msgpack data key
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
numpy array of values
|
|
62
|
+
"""
|
|
63
|
+
dtype, (num, buff) = data[name]
|
|
64
|
+
if dtype in MSGPACK_DTYPES:
|
|
65
|
+
dtype = MSGPACK_DTYPES[dtype]
|
|
66
|
+
else:
|
|
67
|
+
dtype = None # should we warn here ?
|
|
68
|
+
vals = np.frombuffer(buff, dtype).reshape((num, -1))
|
|
69
|
+
data_dict = {}
|
|
70
|
+
for i, col_data in enumerate(vals.T):
|
|
71
|
+
data_dict[f"{name}.{i}"] = col_data
|
|
72
|
+
|
|
73
|
+
# remove the .0 suffix if data is a scalar type
|
|
74
|
+
if len(data_dict) == 1:
|
|
75
|
+
data_dict[name] = data_dict.pop(f"{name}.0")
|
|
76
|
+
|
|
77
|
+
return data_dict
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _concat(refl_data):
|
|
81
|
+
"""combine output of _get_refl_data"""
|
|
82
|
+
LOGGER.debug("Combining and formatting tables!")
|
|
83
|
+
if isinstance(refl_data, rs.DataSet):
|
|
84
|
+
ds = refl_data
|
|
85
|
+
else:
|
|
86
|
+
refl_data = [ds for ds in refl_data if ds is not None]
|
|
87
|
+
ds = rs.concat(refl_data, check_isomorphous=False)
|
|
88
|
+
expt_ids = set(ds.BATCH)
|
|
89
|
+
LOGGER.debug(f"Found {len(ds)} refls from {len(expt_ids)} expts.")
|
|
90
|
+
LOGGER.debug("Mapping batch column.")
|
|
91
|
+
expt_id_map = {name: i for i, name in enumerate(expt_ids)}
|
|
92
|
+
ds.BATCH = [expt_id_map[eid] for eid in ds.BATCH]
|
|
93
|
+
rename_map = {"miller_index.0": "H", "miller_index.1": "K", "miller_index.2": "L"}
|
|
94
|
+
ds.rename(columns=rename_map, inplace=True)
|
|
95
|
+
LOGGER.debug("Finished combining tables!")
|
|
96
|
+
return ds
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _get_refl_data(fname, unitcell, spacegroup, extra_cols=None):
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
fname: integrated refl file
|
|
105
|
+
unitcell: gemmi.UnitCell instance
|
|
106
|
+
spacegroup: gemmi.SpaceGroup instance
|
|
107
|
+
extra_cols: list of additional columns to read
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
RS dataset (pandas Dataframe)
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
LOGGER.debug(f"Loading {fname}")
|
|
115
|
+
pack = _get_refl_pack(fname)
|
|
116
|
+
refl_data = pack["data"]
|
|
117
|
+
expt_id_map = pack["identifiers"]
|
|
118
|
+
|
|
119
|
+
if "miller_index" not in refl_data:
|
|
120
|
+
raise IOError("refl table must have a miller_index column")
|
|
121
|
+
|
|
122
|
+
ds_data = {}
|
|
123
|
+
col_names = DEFAULT_COLS if extra_cols is None else DEFAULT_COLS + extra_cols
|
|
124
|
+
for col_name in col_names:
|
|
125
|
+
if col_name in refl_data:
|
|
126
|
+
col_data = get_msgpack_data(refl_data, col_name)
|
|
127
|
+
LOGGER.debug(f"... Read in data for {col_name}")
|
|
128
|
+
ds_data = {**col_data, **ds_data}
|
|
129
|
+
|
|
130
|
+
if "id" in ds_data:
|
|
131
|
+
ds_data["BATCH"] = np.array([expt_id_map[li] for li in ds_data.pop("id")])
|
|
132
|
+
ds = rs.DataSet(
|
|
133
|
+
ds_data,
|
|
134
|
+
cell=unitcell,
|
|
135
|
+
spacegroup=spacegroup,
|
|
136
|
+
)
|
|
137
|
+
ds["PARTIAL"] = True
|
|
138
|
+
return ds
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _read_dials_stills_serial(fnames, unitcell, spacegroup, extra_cols=None, **kwargs):
|
|
142
|
+
"""run read_dials_stills without trying to import ray"""
|
|
143
|
+
result = [
|
|
144
|
+
_get_refl_data(fname, unitcell, spacegroup, extra_cols) for fname in fnames
|
|
145
|
+
]
|
|
146
|
+
return result
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _read_dials_stills_ray(fnames, unitcell, spacegroup, numjobs=10, extra_cols=None):
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
fnames: integration files
|
|
155
|
+
unitcell: gemmi.UnitCell instance
|
|
156
|
+
spacegroup: gemmi.SpaceGroup instance
|
|
157
|
+
numjobs: number of jobs
|
|
158
|
+
extra_cols: list of additional columns to read from refl tables
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
RS dataset (pandas Dataframe)
|
|
163
|
+
"""
|
|
164
|
+
from reciprocalspaceship.io.common import ray_context
|
|
165
|
+
|
|
166
|
+
with ray_context(
|
|
167
|
+
log_level=LOGGER.level,
|
|
168
|
+
num_cpus=numjobs,
|
|
169
|
+
log_to_driver=LOGGER.level == logging.DEBUG,
|
|
170
|
+
) as ray:
|
|
171
|
+
# get the refl data
|
|
172
|
+
get_refl_data = ray.remote(_get_refl_data)
|
|
173
|
+
refl_data = ray.get(
|
|
174
|
+
[
|
|
175
|
+
get_refl_data.remote(fname, unitcell, spacegroup, extra_cols)
|
|
176
|
+
for fname in fnames
|
|
177
|
+
]
|
|
178
|
+
)
|
|
179
|
+
return refl_data
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def dials_to_mtz_dtypes(ds, inplace=True):
|
|
183
|
+
"""
|
|
184
|
+
Coerce the dtypes in ds into ones that can be written to an mtz file.
|
|
185
|
+
This will downcast doubles to single precision. If "variance" columns
|
|
186
|
+
are present, they will be converted to "sigma" and assigned
|
|
187
|
+
StandardDeviationDtype.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
ds : rs.DataSet
|
|
192
|
+
inplace : bool (optional)
|
|
193
|
+
Convert ds dtypes in place without makeing a copy. Defaults to True.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
ds : rs.DataSet
|
|
198
|
+
"""
|
|
199
|
+
rename_map = {}
|
|
200
|
+
for name in ds:
|
|
201
|
+
if "variance" in name:
|
|
202
|
+
new_name = name.replace("variance", "sigma")
|
|
203
|
+
rename_map[name] = new_name
|
|
204
|
+
ds[name] = np.sqrt(ds[name]).astype("Q")
|
|
205
|
+
LOGGER.debug(
|
|
206
|
+
f"Converted column {name} to MTZ-Type Q, took sqrt of the values, and renamed to {new_name}."
|
|
207
|
+
)
|
|
208
|
+
ds.rename(columns=rename_map, inplace=True)
|
|
209
|
+
ds.infer_mtz_dtypes(inplace=True)
|
|
210
|
+
return ds
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@cellify
|
|
214
|
+
@spacegroupify
|
|
215
|
+
def read_dials_stills(
|
|
216
|
+
fnames,
|
|
217
|
+
unitcell=None,
|
|
218
|
+
spacegroup=None,
|
|
219
|
+
numjobs=10,
|
|
220
|
+
parallel_backend=None,
|
|
221
|
+
extra_cols=None,
|
|
222
|
+
verbose=False,
|
|
223
|
+
comm=None,
|
|
224
|
+
mtz_dtypes=False,
|
|
225
|
+
):
|
|
226
|
+
"""
|
|
227
|
+
Read reflections from still images processed by DIALS from fnames and return
|
|
228
|
+
them as a DataSet. By default, this function will not convert the data from
|
|
229
|
+
dials into an MTZ compatible format.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
fnames : list or tuple or string
|
|
234
|
+
A list or tuple of filenames (strings) or a single filename.
|
|
235
|
+
unitcell : gemmi.UnitCell or similar (optional)
|
|
236
|
+
The unit cell assigned to the returned dataset.
|
|
237
|
+
spacegroup : gemmi.SpaceGroup or similar (optional)
|
|
238
|
+
The spacegroup assigned to the returned dataset.
|
|
239
|
+
numjobs : int
|
|
240
|
+
If backend==ray, specify the number of jobs (ignored if backend==mpi).
|
|
241
|
+
parallel_backend : string (optional)
|
|
242
|
+
"ray", "mpi", or None for serial.
|
|
243
|
+
extra_cols : list (optional)
|
|
244
|
+
Optional list of additional column names to extract from the refltables. By default, this method will search for
|
|
245
|
+
miller_index, id, s1, xyzcal.px, intensity.sum.value, intensity.sum.variance, delpsical.rad
|
|
246
|
+
verbose : bool
|
|
247
|
+
Whether to print logging info to stdout
|
|
248
|
+
comm : mpi4py.MPI.Comm
|
|
249
|
+
Optionally override the communicator used by backend='mpi'
|
|
250
|
+
mtz_dtypes : bool (optional)
|
|
251
|
+
Optionally convert columns to mtz compatible dtypes. Note this will downcast double precision (64-bit)
|
|
252
|
+
floats to single precision (32-bit).
|
|
253
|
+
|
|
254
|
+
Returns
|
|
255
|
+
-------
|
|
256
|
+
ds : rs.DataSet
|
|
257
|
+
The dataset containing reflection info aggregated from fnames. This method will not convert any of the
|
|
258
|
+
columns to native rs MTZ dtypes. DIALS data are natively double precision (64-bit). Converting to MTZ
|
|
259
|
+
will downcast them to 32-bit. Use ds.infer_mtz_dtypes() to convert to native rs dtypes if required.
|
|
260
|
+
"""
|
|
261
|
+
_set_logger(verbose)
|
|
262
|
+
if isinstance(fnames, str):
|
|
263
|
+
fnames = [fnames]
|
|
264
|
+
|
|
265
|
+
if parallel_backend not in ["ray", "mpi", None]:
|
|
266
|
+
raise NotImplementedError("parallel_backend should be ray, mpi, or none")
|
|
267
|
+
|
|
268
|
+
kwargs = {
|
|
269
|
+
"fnames": fnames,
|
|
270
|
+
"unitcell": unitcell,
|
|
271
|
+
"spacegroup": spacegroup,
|
|
272
|
+
"extra_cols": extra_cols,
|
|
273
|
+
}
|
|
274
|
+
reader = _read_dials_stills_serial
|
|
275
|
+
if parallel_backend == "ray":
|
|
276
|
+
kwargs["numjobs"] = numjobs
|
|
277
|
+
from reciprocalspaceship.io.common import check_for_ray
|
|
278
|
+
|
|
279
|
+
if check_for_ray():
|
|
280
|
+
reader = _read_dials_stills_ray
|
|
281
|
+
elif parallel_backend == "mpi":
|
|
282
|
+
from reciprocalspaceship.io.common import check_for_mpi
|
|
283
|
+
|
|
284
|
+
if check_for_mpi():
|
|
285
|
+
from reciprocalspaceship.io.dials_mpi import read_dials_stills_mpi as reader
|
|
286
|
+
|
|
287
|
+
kwargs["comm"] = comm
|
|
288
|
+
result = reader(**kwargs)
|
|
289
|
+
if result is not None:
|
|
290
|
+
result = _concat(result)
|
|
291
|
+
if mtz_dtypes:
|
|
292
|
+
dials_to_mtz_dtypes(result, inplace=True)
|
|
293
|
+
return result
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _get_refl_pack(filename):
|
|
297
|
+
pack = msgpack.load(open(filename, "rb"), strict_map_key=False)
|
|
298
|
+
try:
|
|
299
|
+
assert len(pack) == 3
|
|
300
|
+
_, _, pack = pack
|
|
301
|
+
except (TypeError, AssertionError):
|
|
302
|
+
raise IOError("File does not appear to be dials::af::reflection_table")
|
|
303
|
+
return pack
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def print_refl_info(reflfile):
|
|
307
|
+
"""print contents of `fname`, a reflection table file saved with DIALS"""
|
|
308
|
+
pack = _get_refl_pack(reflfile)
|
|
309
|
+
if "identifiers" in pack:
|
|
310
|
+
idents = pack["identifiers"]
|
|
311
|
+
print(f"\nFound {len(idents)} experiment identifiers in {reflfile}:")
|
|
312
|
+
for i, ident in idents.items():
|
|
313
|
+
print(f"\t{i}: {ident}")
|
|
314
|
+
if "data" in pack:
|
|
315
|
+
data = pack["data"]
|
|
316
|
+
columns = []
|
|
317
|
+
col_space = 0
|
|
318
|
+
for name in data:
|
|
319
|
+
dtype, (_, buff) = data[name]
|
|
320
|
+
columns.append((name, dtype))
|
|
321
|
+
col_space = max(len(dtype), len(name), col_space)
|
|
322
|
+
names, dtypes = zip(*columns)
|
|
323
|
+
df = pandas.DataFrame({"names": names, "dtypes": dtypes})
|
|
324
|
+
print(
|
|
325
|
+
"\nReflection contents:\n"
|
|
326
|
+
+ df.to_string(index=False, col_space=col_space + 5, justify="center")
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
if "nrows" in pack:
|
|
330
|
+
print(f"\nNumber of reflections: {pack['nrows']} \n")
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from itertools import chain
|
|
2
|
+
|
|
3
|
+
from reciprocalspaceship.decorators import cellify, spacegroupify
|
|
4
|
+
from reciprocalspaceship.io import dials
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def mpi_starmap(comm, func, iterable):
|
|
8
|
+
results = []
|
|
9
|
+
for i, item in enumerate(iterable):
|
|
10
|
+
if i % comm.size == comm.rank:
|
|
11
|
+
results.append(func(*item))
|
|
12
|
+
results = comm.gather(results)
|
|
13
|
+
if comm.rank == 0:
|
|
14
|
+
return chain.from_iterable(results)
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@cellify
|
|
19
|
+
@spacegroupify
|
|
20
|
+
def read_dials_stills_mpi(fnames, unitcell, spacegroup, extra_cols=None, comm=None):
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
fnames: integrated reflection tables
|
|
26
|
+
unitcell: unit cell tuple (6 params Ang,Ang,Ang,deg,deg,deg)
|
|
27
|
+
spacegroup: space group name e.g. P4
|
|
28
|
+
extra_cols: list of additional column names to read from the refl table
|
|
29
|
+
comm: Optionally override the MPI communicator. The default is MPI.COMM_WORLD
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
RS dataset (pandas Dataframe) if MPI rank==0 else None
|
|
34
|
+
"""
|
|
35
|
+
if comm is None:
|
|
36
|
+
from mpi4py import MPI
|
|
37
|
+
|
|
38
|
+
comm = MPI.COMM_WORLD
|
|
39
|
+
ds = mpi_starmap(
|
|
40
|
+
comm,
|
|
41
|
+
dials._get_refl_data,
|
|
42
|
+
((f, unitcell, spacegroup, extra_cols) for f in fnames),
|
|
43
|
+
)
|
|
44
|
+
return ds
|
reciprocalspaceship/io/mtz.py
CHANGED
|
@@ -133,16 +133,15 @@ def to_gemmi(
|
|
|
133
133
|
mtz.datasets[0].dataset_name = dataset_name
|
|
134
134
|
|
|
135
135
|
# Construct data for Mtz object
|
|
136
|
-
|
|
136
|
+
# GH#255: DataSet is provided using the range_indexed decorator
|
|
137
137
|
columns = []
|
|
138
|
-
for c in
|
|
139
|
-
cseries =
|
|
138
|
+
for c in dataset.columns:
|
|
139
|
+
cseries = dataset[c]
|
|
140
140
|
if isinstance(cseries.dtype, MTZDtype):
|
|
141
141
|
mtz.add_column(label=c, type=cseries.dtype.mtztype)
|
|
142
142
|
columns.append(c)
|
|
143
143
|
# Special case for CENTRIC and PARTIAL flags
|
|
144
144
|
elif cseries.dtype.name == "bool" and c in ["CENTRIC", "PARTIAL"]:
|
|
145
|
-
temp[c] = temp[c].astype("MTZInt")
|
|
146
145
|
mtz.add_column(label=c, type="I")
|
|
147
146
|
columns.append(c)
|
|
148
147
|
elif skip_problem_mtztypes:
|
|
@@ -152,7 +151,7 @@ def to_gemmi(
|
|
|
152
151
|
f"column {c} of type {cseries.dtype} cannot be written to an MTZ file. "
|
|
153
152
|
f"To skip columns without explicit MTZ dtypes, set skip_problem_mtztypes=True"
|
|
154
153
|
)
|
|
155
|
-
mtz.set_data(
|
|
154
|
+
mtz.set_data(dataset[columns].to_numpy(dtype="float32"))
|
|
156
155
|
|
|
157
156
|
# Handle Unmerged data
|
|
158
157
|
if not dataset.merged and not all_in_asu:
|
|
@@ -52,4 +52,9 @@ from reciprocalspaceship.utils.symmetry import (
|
|
|
52
52
|
phase_shift,
|
|
53
53
|
polar_axes,
|
|
54
54
|
)
|
|
55
|
-
from reciprocalspaceship.utils.units import
|
|
55
|
+
from reciprocalspaceship.utils.units import (
|
|
56
|
+
Angstroms2eV,
|
|
57
|
+
angstroms2ev,
|
|
58
|
+
ev2angstroms,
|
|
59
|
+
eV2Angstroms,
|
|
60
|
+
)
|
|
@@ -24,6 +24,11 @@ def compute_dHKL(H, cell):
|
|
|
24
24
|
# Compress the hkls so we don't do redudant computation
|
|
25
25
|
H = np.array(H, dtype=np.float32)
|
|
26
26
|
hkls, inverse = np.unique(H, axis=0, return_inverse=True)
|
|
27
|
+
|
|
28
|
+
# The behavior of np.unique changed with v2.0. This block maintains v1 compatibility
|
|
29
|
+
if inverse.shape[-1] == 1:
|
|
30
|
+
inverse = inverse.squeeze(-1)
|
|
31
|
+
|
|
27
32
|
F = np.array(cell.fractionalization_matrix.tolist()).astype(np.float64)
|
|
28
33
|
dhkls = np.reciprocal(np.linalg.norm((hkls @ F), 2, 1)).astype(np.float32)
|
|
29
34
|
return dhkls[inverse]
|
|
@@ -41,8 +41,6 @@ def compute_redundancy(
|
|
|
41
41
|
if dmin is None:
|
|
42
42
|
dmin = dhkl.min()
|
|
43
43
|
hobs = hobs[dhkl >= dmin]
|
|
44
|
-
decimals = 5.0 # Round after this many decimals
|
|
45
|
-
dmin = np.floor(dmin * 10**decimals) * 10**-decimals
|
|
46
44
|
hobs, isym = rs.utils.hkl_to_asu(hobs, spacegroup)
|
|
47
45
|
if anomalous:
|
|
48
46
|
fminus = isym % 2 == 0
|
|
@@ -107,15 +105,15 @@ def weighted_pearsonr(x, y, w):
|
|
|
107
105
|
"""
|
|
108
106
|
z = np.reciprocal(w.sum(-1))
|
|
109
107
|
|
|
110
|
-
mx = z * (w
|
|
111
|
-
my = z * (w
|
|
108
|
+
mx = z * np.einsum("...a,...a->...", w, x)
|
|
109
|
+
my = z * np.einsum("...a,...a->...", w, y)
|
|
112
110
|
|
|
113
111
|
dx = x - np.expand_dims(mx, axis=-1)
|
|
114
112
|
dy = y - np.expand_dims(my, axis=-1)
|
|
115
113
|
|
|
116
|
-
cxy = z * (w
|
|
117
|
-
cx = z * (w
|
|
118
|
-
cy = z * (w
|
|
114
|
+
cxy = z * np.einsum("...a,...a,...a->...", w, dx, dy)
|
|
115
|
+
cx = z * np.einsum("...a,...a,...a->...", w, dx, dx)
|
|
116
|
+
cy = z * np.einsum("...a,...a,...a->...", w, dy, dy)
|
|
119
117
|
|
|
120
118
|
r = cxy / np.sqrt(cx * cy)
|
|
121
119
|
return r
|
|
@@ -104,6 +104,11 @@ def is_centric(H, spacegroup):
|
|
|
104
104
|
"""
|
|
105
105
|
group_ops = spacegroup.operations()
|
|
106
106
|
hkl, inverse = np.unique(H, axis=0, return_inverse=True)
|
|
107
|
+
|
|
108
|
+
# The behavior of np.unique changed with v2.0. This block maintains v1 compatibility
|
|
109
|
+
if inverse.shape[-1] == 1:
|
|
110
|
+
inverse = inverse.squeeze(-1)
|
|
111
|
+
|
|
107
112
|
centric = group_ops.centric_flag_array(hkl)
|
|
108
113
|
return centric[inverse]
|
|
109
114
|
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
import numpy as np
|
|
1
2
|
from scipy.constants import Planck, c, electron_volt
|
|
2
3
|
|
|
4
|
+
_conversion_factor = Planck * c / 1e-10 / electron_volt
|
|
3
5
|
|
|
4
|
-
def ev2angstroms(ev):
|
|
5
|
-
return Planck * c / ev / 1e-10 / electron_volt
|
|
6
6
|
|
|
7
|
+
def eV2Angstroms(ev):
|
|
8
|
+
out = np.empty_like(ev)
|
|
9
|
+
np.divide(_conversion_factor, ev, out=out)
|
|
10
|
+
return out
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
|
|
13
|
+
def Angstroms2eV(angstroms):
|
|
14
|
+
return eV2Angstroms(angstroms)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Add legacy aliases
|
|
18
|
+
ev2angstroms = eV2Angstroms
|
|
19
|
+
angstroms2ev = Angstroms2eV
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: reciprocalspaceship
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
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
|
|
@@ -9,7 +9,6 @@ License: MIT
|
|
|
9
9
|
Project-URL: Bug Tracker, https://github.com/rs-station/reciprocalspaceship/issues
|
|
10
10
|
Project-URL: Documentation, https://rs-station.github.io/reciprocalspaceship/
|
|
11
11
|
Project-URL: Source Code, https://github.com/rs-station/reciprocalspaceship
|
|
12
|
-
Platform: UNKNOWN
|
|
13
12
|
Classifier: Development Status :: 3 - Alpha
|
|
14
13
|
Classifier: Intended Audience :: Developers
|
|
15
14
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -18,36 +17,38 @@ Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
|
18
17
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
19
|
Classifier: Programming Language :: Python
|
|
21
|
-
Requires-Python:
|
|
20
|
+
Requires-Python: >=3.9
|
|
22
21
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: gemmi
|
|
24
|
-
Requires-Dist: pandas
|
|
22
|
+
Requires-Dist: gemmi<=0.6.7,>=0.5.5
|
|
23
|
+
Requires-Dist: pandas<=2.2.3,>=2.2.2
|
|
25
24
|
Requires-Dist: numpy
|
|
26
25
|
Requires-Dist: scipy
|
|
27
26
|
Requires-Dist: ipython
|
|
27
|
+
Requires-Dist: msgpack
|
|
28
28
|
Provides-Extra: dev
|
|
29
|
-
Requires-Dist: pytest
|
|
30
|
-
Requires-Dist: pytest-cov
|
|
31
|
-
Requires-Dist: pytest-xdist
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: sphinx
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
Requires-Dist:
|
|
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"
|
|
44
45
|
Provides-Extra: examples
|
|
45
|
-
Requires-Dist: jupyter
|
|
46
|
-
Requires-Dist: tqdm
|
|
47
|
-
Requires-Dist: matplotlib
|
|
48
|
-
Requires-Dist: seaborn
|
|
49
|
-
Requires-Dist: celluloid
|
|
50
|
-
Requires-Dist: scikit-image
|
|
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"
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
``reciprocalspaceship`` provides a ``pandas``-style interface for
|
|
@@ -68,5 +69,3 @@ Features of this library include:
|
|
|
68
69
|
use space groups, unit cell parameters, and crystallographic symmetry
|
|
69
70
|
operations.
|
|
70
71
|
- Support for reading and writing MTZ reflection files.
|
|
71
|
-
|
|
72
|
-
|
|
@@ -1,58 +1,62 @@
|
|
|
1
|
-
reciprocalspaceship/VERSION,sha256=
|
|
2
|
-
reciprocalspaceship/__init__.py,sha256=
|
|
1
|
+
reciprocalspaceship/VERSION,sha256=9eXJU0UyhA_NRbsALmnthcYduidTRQ4mtEi33xSB4k0,6
|
|
2
|
+
reciprocalspaceship/__init__.py,sha256=m6pXLI-HuXwefCfSE2Rs_2McqzuHw5W6yMBXEbceke8,2034
|
|
3
3
|
reciprocalspaceship/concat.py,sha256=v2eg8-RBiNLYHkkPDeaozh3HvGCaFbmlC15FaeNJMgY,1695
|
|
4
4
|
reciprocalspaceship/dataseries.py,sha256=ibU1bHMd8zORFxRtDswtvLh_n-miAyBqO0ghLmY29Js,6188
|
|
5
|
-
reciprocalspaceship/dataset.py,sha256=
|
|
6
|
-
reciprocalspaceship/decorators.py,sha256=
|
|
5
|
+
reciprocalspaceship/dataset.py,sha256=6GMIMWVdKzOFhFsgODgvFn2-hrrMRMPw3-oDzlbL0YQ,57698
|
|
6
|
+
reciprocalspaceship/decorators.py,sha256=sZAPAV5fk5zUlwzub2VZy-u28XVNXjBpnqwnKjESWgY,5721
|
|
7
7
|
reciprocalspaceship/algorithms/__init__.py,sha256=r5IYCGswTHXpSs9Q7c6PfEz8_P8d1fEei2SyTkp5aYY,258
|
|
8
8
|
reciprocalspaceship/algorithms/intensity.py,sha256=iDHaqqrMAe0v-aTVT5jf54JwkNQLSQ7HhezPw6qZndg,2657
|
|
9
9
|
reciprocalspaceship/algorithms/merge.py,sha256=iwPrDfjtliBwLqEzHbcIfoTkvS_0s2_CszS5IfrEUXI,2154
|
|
10
|
-
reciprocalspaceship/algorithms/scale_merged_intensities.py,sha256=
|
|
10
|
+
reciprocalspaceship/algorithms/scale_merged_intensities.py,sha256=hNKKISCCDvchail1PZ_0r6sq1Rbgoraqaz1aDCayTYQ,11269
|
|
11
11
|
reciprocalspaceship/commandline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
reciprocalspaceship/commandline/mtzdump.py,sha256=JBg_W-CWQ6rbOOVmtK7TsErFXhCBR5pmC5RRSCapEZg,2939
|
|
13
13
|
reciprocalspaceship/dtypes/__init__.py,sha256=cO0M2F6pO_0jtqx-MlkbzqxLSmK1Ibmon5p_ksWmcbk,1038
|
|
14
14
|
reciprocalspaceship/dtypes/base.py,sha256=1X56U4jKt_wjVkW930C9gP2Di0RpCMDZsDKNTxYle5I,1052
|
|
15
|
-
reciprocalspaceship/dtypes/floating.py,sha256=
|
|
15
|
+
reciprocalspaceship/dtypes/floating.py,sha256=jOQ25GZEE4QromaJA3_oeu0Tkjq1iT4dHCke_7W6TYo,19675
|
|
16
16
|
reciprocalspaceship/dtypes/inference.py,sha256=jLgF8VfKtITGRzQbfeyZzEoJ1fQlbHXB_gXIJ9-AQxk,3029
|
|
17
|
-
reciprocalspaceship/dtypes/integer.py,sha256=
|
|
18
|
-
reciprocalspaceship/dtypes/internals.py,sha256=
|
|
17
|
+
reciprocalspaceship/dtypes/integer.py,sha256=fPaLTWfMsJ-wuEPkm9oEJez3NDqzB4XKVHFRFEb585A,15816
|
|
18
|
+
reciprocalspaceship/dtypes/internals.py,sha256=YNv6Dz4miazjZVFJCOTFudH-0ejUbOcu_snCq1RU2Nw,47607
|
|
19
19
|
reciprocalspaceship/dtypes/summarize.py,sha256=1w6-N3odFcI3ZEQP5qgrog6ucbGjO71vSgabmjklkbc,1114
|
|
20
|
-
reciprocalspaceship/io/__init__.py,sha256=
|
|
20
|
+
reciprocalspaceship/io/__init__.py,sha256=UquHOv850aJGdKnWEG-KTkHPgye7ldYFge62O5N6G_w,476
|
|
21
21
|
reciprocalspaceship/io/ccp4map.py,sha256=yztiHPTdyR9FiCKRg-eVmL-_MyZTKThPI9uuHuuPF_0,1029
|
|
22
|
-
reciprocalspaceship/io/
|
|
22
|
+
reciprocalspaceship/io/common.py,sha256=_XzdAFeE6B-Q_ORc4bkOR7ANwNT4dNqYtlejzYJfWxs,1055
|
|
23
|
+
reciprocalspaceship/io/crystfel.py,sha256=N6CufOt3yESbOC4niFVPfBx2PSp9UpLlnmsuGXDdeIM,21877
|
|
23
24
|
reciprocalspaceship/io/csv.py,sha256=A2ZnqAnFwFUQskF7_3EsQAPCcrJ5KEgjhZls6MDViv8,1194
|
|
24
|
-
reciprocalspaceship/io/
|
|
25
|
+
reciprocalspaceship/io/dials.py,sha256=FQQa3eT9TQw7h43ohyvNI3huViHE-eP9Y4IbRQL5dIc,10137
|
|
26
|
+
reciprocalspaceship/io/dials_mpi.py,sha256=wvm-sQqFG7N7bgcnxd5jn94eyKveimA3rvP8ns1B5Jg,1212
|
|
27
|
+
reciprocalspaceship/io/mtz.py,sha256=_gdlx7Vi6Z0HyFBZFP6Ptmla7Pd_mON2KaGL4Q3N7Ik,8071
|
|
25
28
|
reciprocalspaceship/io/pickle.py,sha256=clnSTK8T2O_d7midS_E54WHmXEHrL10d386gWx7ztsM,818
|
|
26
29
|
reciprocalspaceship/io/precognition.py,sha256=DWRE2erXPVpm9-y5DjIWUHfmv9jZcsqoa47ienp1Sao,3641
|
|
27
30
|
reciprocalspaceship/stats/__init__.py,sha256=jdAWbpD_CKAn0W0sO_MKSnTu3bZSoLAXgb1_Y6jDMzk,197
|
|
28
31
|
reciprocalspaceship/stats/completeness.py,sha256=1QM-Ac_V58nTLJoewbOK5CL69qsb0C0sc8L0c59WorQ,6702
|
|
29
|
-
reciprocalspaceship/utils/__init__.py,sha256=
|
|
32
|
+
reciprocalspaceship/utils/__init__.py,sha256=bKJwbkxXa-TX2etIQgIESKkv9kdag1rHL77JLhI-2B8,1714
|
|
30
33
|
reciprocalspaceship/utils/asu.py,sha256=WwxvIq-_QEF2UvyELuNudVo53daty9wiN-vaOYAUbKI,8680
|
|
31
34
|
reciprocalspaceship/utils/binning.py,sha256=CHf5z8EsHSg34ZgC-yM_8Gd3D2BB8cqTtHAf7vwfgLo,2786
|
|
32
|
-
reciprocalspaceship/utils/cell.py,sha256=
|
|
35
|
+
reciprocalspaceship/utils/cell.py,sha256=aNIaugA3F8CRs9n8Ck0Rjc8YI7qHZcW3lJPE7yvj0dk,2053
|
|
33
36
|
reciprocalspaceship/utils/grid.py,sha256=xB7sw1xrhgzFojrVHbC_uVBT3NMTBsvKsCqaRrVfvTQ,1893
|
|
34
37
|
reciprocalspaceship/utils/math.py,sha256=m6Iq9u0fjiieftzjQPAEHTN2htBIOwLhBCJdrcIN5Ao,1019
|
|
35
38
|
reciprocalspaceship/utils/phases.py,sha256=zyiE99bq-TV_4aI6ZhBi4MLAvKwE3Sx1dFqppJL5rkE,2438
|
|
36
39
|
reciprocalspaceship/utils/rfree.py,sha256=qFgepLOfgdU-cvZIMu8WfzlFExTc4jILff2ro7iu8FQ,3411
|
|
37
|
-
reciprocalspaceship/utils/stats.py,sha256=
|
|
38
|
-
reciprocalspaceship/utils/structurefactors.py,sha256=
|
|
40
|
+
reciprocalspaceship/utils/stats.py,sha256=p_1R3bTVVAVlDWh-hzcurlT8GOHkJA8ovFuQjD0w5AY,3681
|
|
41
|
+
reciprocalspaceship/utils/structurefactors.py,sha256=ZW6CVPn_04dxay0DDnA0-byUrZnGraQ0kItqN1m5F3k,3686
|
|
39
42
|
reciprocalspaceship/utils/symmetry.py,sha256=xsYmEUo0PTH57-kctJdUq_-k14ci5LUGeG5LwzmjjPU,2963
|
|
40
|
-
reciprocalspaceship/utils/units.py,sha256=
|
|
43
|
+
reciprocalspaceship/utils/units.py,sha256=ng-2hzZBERYo9bnQDPr-HLr7xPah-JzOthfrpHH816Y,388
|
|
41
44
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
45
|
tests/conftest.py,sha256=bQZClqzu3lonsI01OdP5X38asMd7F76fAGzlWWYPXAI,3930
|
|
43
|
-
tests/test_dataseries.py,sha256=
|
|
44
|
-
tests/test_dataset.py,sha256=
|
|
46
|
+
tests/test_dataseries.py,sha256=go-q5tT8lLq3tlRVnmrwUytK7PlaoKs3CBPjWryGfGg,3309
|
|
47
|
+
tests/test_dataset.py,sha256=Ir9cFhrzAtMAnoLZikrkiLqKUbDvCTr3xqdzeaKLH3M,23759
|
|
45
48
|
tests/test_dataset_anomalous.py,sha256=LQb1inSS_oDbVYEIyyx_GBFAkXGlEQYZ-ZhpwMeyMmQ,6963
|
|
46
49
|
tests/test_dataset_binning.py,sha256=NgD_vy-TUh3vQrUVgysVBSZu75xN66LR6hRu2_qAUTs,3564
|
|
47
50
|
tests/test_dataset_grid.py,sha256=S2EswVAbcg08WT9TjLtQ3YF1_zJmEKcucHrN3Lw5EM8,4086
|
|
48
51
|
tests/test_dataset_index.py,sha256=-6sMVgAKkkcYRc7UfLuVEH3p7D83o1S7e7c6MbrOrZo,2842
|
|
49
52
|
tests/test_dataset_preserve_attributes.py,sha256=gwQQJGsiBZld2KKmLrcMkuc9zesR3FD7GVnPDNRScto,5314
|
|
53
|
+
tests/test_dataset_signatures.py,sha256=ZbH9JNzqAWJDfVh9gqZVQXx8glmmBUhsbPmQBHe8Cuo,1554
|
|
50
54
|
tests/test_dataset_symops.py,sha256=PV86tLu1qDACuk-YqjYQszk8Ctb0-h_NsQRnuCDFnOU,10864
|
|
51
55
|
tests/test_decorators.py,sha256=ExR7mCU0iIqhHo4ho6ywPrZIEaGcsElaI4jtH9o5afE,5331
|
|
52
56
|
tests/test_summarize_mtz_dtypes.py,sha256=JE0ctXMWii1AV-cmKogF6hjb8NCHrgvxNZ0ZRCHh-Ho,696
|
|
53
|
-
reciprocalspaceship-1.0.
|
|
54
|
-
reciprocalspaceship-1.0.
|
|
55
|
-
reciprocalspaceship-1.0.
|
|
56
|
-
reciprocalspaceship-1.0.
|
|
57
|
-
reciprocalspaceship-1.0.
|
|
58
|
-
reciprocalspaceship-1.0.
|
|
57
|
+
reciprocalspaceship-1.0.3.dist-info/LICENSE,sha256=E22aZlYy5qJsJCJ94EkO_Vt3COio5UcLg59dZLPam7I,1093
|
|
58
|
+
reciprocalspaceship-1.0.3.dist-info/METADATA,sha256=nvD6MJEEv_RHH-Dx5gj5fIvyHRRoTVUfkZxts37goQ4,3079
|
|
59
|
+
reciprocalspaceship-1.0.3.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
|
60
|
+
reciprocalspaceship-1.0.3.dist-info/entry_points.txt,sha256=Bqjl2J8UrG4UAHHhPbdH5r-xYaOdLCEdyRH6zJ9joDw,76
|
|
61
|
+
reciprocalspaceship-1.0.3.dist-info/top_level.txt,sha256=tOo679MsLFS7iwiYZDwnKTuTpJLYVFBk6g9xnnB_s-w,26
|
|
62
|
+
reciprocalspaceship-1.0.3.dist-info/RECORD,,
|