reciprocalspaceship 1.0.0__py3-none-any.whl → 1.0.2__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.

Files changed (41) hide show
  1. reciprocalspaceship/VERSION +1 -1
  2. reciprocalspaceship/__init__.py +1 -0
  3. reciprocalspaceship/algorithms/scale_merged_intensities.py +8 -7
  4. reciprocalspaceship/commandline/mtzdump.py +0 -1
  5. reciprocalspaceship/dataset.py +7 -1
  6. reciprocalspaceship/decorators.py +2 -2
  7. reciprocalspaceship/dtypes/__init__.py +16 -14
  8. reciprocalspaceship/dtypes/base.py +21 -266
  9. reciprocalspaceship/dtypes/floating.py +691 -0
  10. reciprocalspaceship/dtypes/integer.py +537 -0
  11. reciprocalspaceship/dtypes/internals.py +1365 -0
  12. reciprocalspaceship/io/__init__.py +7 -1
  13. reciprocalspaceship/io/crystfel.py +568 -234
  14. reciprocalspaceship/io/mtz.py +25 -0
  15. reciprocalspaceship/stats/completeness.py +0 -1
  16. reciprocalspaceship/utils/__init__.py +6 -1
  17. reciprocalspaceship/utils/asu.py +6 -0
  18. reciprocalspaceship/utils/cell.py +5 -0
  19. reciprocalspaceship/utils/stats.py +5 -7
  20. reciprocalspaceship/utils/structurefactors.py +5 -0
  21. reciprocalspaceship/utils/units.py +14 -4
  22. {reciprocalspaceship-1.0.0.dist-info → reciprocalspaceship-1.0.2.dist-info}/METADATA +26 -28
  23. reciprocalspaceship-1.0.2.dist-info/RECORD +58 -0
  24. {reciprocalspaceship-1.0.0.dist-info → reciprocalspaceship-1.0.2.dist-info}/WHEEL +1 -1
  25. {reciprocalspaceship-1.0.0.dist-info → reciprocalspaceship-1.0.2.dist-info}/entry_points.txt +0 -1
  26. tests/test_dataseries.py +1 -1
  27. tests/test_dataset_preserve_attributes.py +3 -9
  28. reciprocalspaceship/dtypes/anomalousdifference.py +0 -25
  29. reciprocalspaceship/dtypes/batch.py +0 -25
  30. reciprocalspaceship/dtypes/hklindex.py +0 -23
  31. reciprocalspaceship/dtypes/intensity.py +0 -47
  32. reciprocalspaceship/dtypes/m_isym.py +0 -25
  33. reciprocalspaceship/dtypes/mtzint.py +0 -23
  34. reciprocalspaceship/dtypes/mtzreal.py +0 -25
  35. reciprocalspaceship/dtypes/phase.py +0 -50
  36. reciprocalspaceship/dtypes/stddev.py +0 -69
  37. reciprocalspaceship/dtypes/structurefactor.py +0 -72
  38. reciprocalspaceship/dtypes/weight.py +0 -25
  39. reciprocalspaceship-1.0.0.dist-info/RECORD +0 -66
  40. {reciprocalspaceship-1.0.0.dist-info → reciprocalspaceship-1.0.2.dist-info}/LICENSE +0 -0
  41. {reciprocalspaceship-1.0.0.dist-info → reciprocalspaceship-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,691 @@
1
+ # BSD 3-Clause License
2
+ #
3
+ # Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
4
+ # All rights reserved.
5
+ #
6
+ # Copyright (c) 2011-2023, Open source contributors.
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice, this
12
+ # list of conditions and the following disclaimer.
13
+ #
14
+ # * Redistributions in binary form must reproduce the above copyright notice,
15
+ # this list of conditions and the following disclaimer in the documentation
16
+ # and/or other materials provided with the distribution.
17
+ #
18
+ # * Neither the name of the copyright holder nor the names of its
19
+ # contributors may be used to endorse or promote products derived from
20
+ # this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ from __future__ import annotations
34
+
35
+ import numpy as np
36
+ from pandas._libs import lib
37
+ from pandas._typing import ArrayLike, DtypeObj
38
+ from pandas.util._decorators import cache_readonly
39
+
40
+ try:
41
+ from pandas.core.dtypes.cast import astype_nansafe
42
+ except:
43
+ from pandas.core.dtypes.astype import _astype_nansafe as astype_nansafe
44
+
45
+ from pandas import Float32Dtype, Float64Dtype
46
+ from pandas.core.arrays import ExtensionArray
47
+ from pandas.core.dtypes.cast import np_find_common_type
48
+ from pandas.core.dtypes.common import (
49
+ is_bool_dtype,
50
+ is_float,
51
+ is_float_dtype,
52
+ is_integer_dtype,
53
+ is_numeric_dtype,
54
+ is_object_dtype,
55
+ pandas_dtype,
56
+ )
57
+ from pandas.core.dtypes.dtypes import ExtensionDtype, register_extension_dtype
58
+ from pandas.core.tools.numeric import to_numeric
59
+
60
+ from reciprocalspaceship.dtypes.base import MTZDtype
61
+ from reciprocalspaceship.dtypes.internals import NumericArray, is_numeric_na
62
+
63
+
64
+ class MTZFloat32Dtype(MTZDtype):
65
+ """
66
+ An ExtensionDtype to hold a single size of floating dtype.
67
+
68
+ These specific implementations are subclasses of the non-public
69
+ MTZFloat32Dtype. For example we have Float32Dtype to represent float32.
70
+
71
+ The attributes name & type are set when these subclasses are created.
72
+ """
73
+
74
+ type = np.float32
75
+
76
+ def _get_common_dtype(self, dtypes: list[DtypeObj]) -> DtypeObj | None:
77
+ # for now only handle other floating types
78
+ if len(set(dtypes)) == 1:
79
+ # only itself
80
+ return self
81
+ if not all(isinstance(t, MTZFloat32Dtype) for t in dtypes):
82
+ return None
83
+ np_dtype = np_find_common_type(
84
+ # error: Item "ExtensionDtype" of "Union[Any, ExtensionDtype]" has no
85
+ # attribute "numpy_dtype"
86
+ [t.numpy_dtype for t in dtypes], # type: ignore[union-attr]
87
+ [],
88
+ )
89
+ if np.issubdtype(np_dtype, np.floating):
90
+ return Float32Dtype()
91
+ return None
92
+
93
+
94
+ def coerce_to_array(
95
+ values, dtype=None, mask=None, copy: bool = False
96
+ ) -> tuple[np.ndarray, np.ndarray]:
97
+ """
98
+ Coerce the input values array to numpy arrays with a mask.
99
+
100
+ Parameters
101
+ ----------
102
+ values : 1D list-like
103
+ dtype : float dtype
104
+ mask : bool 1D array, optional
105
+ copy : bool, default False
106
+ if True, copy the input
107
+
108
+ Returns
109
+ -------
110
+ tuple of (values, mask)
111
+ """
112
+ # if values is floating numpy array, preserve its dtype
113
+ if dtype is None and hasattr(values, "dtype"):
114
+ if is_float_dtype(values.dtype):
115
+ dtype = values.dtype
116
+
117
+ if dtype is not None:
118
+ if isinstance(dtype, str) and dtype.startswith("Float"):
119
+ # Avoid DeprecationWarning from NumPy about np.dtype("Float64")
120
+ # https://github.com/numpy/numpy/pull/7476
121
+ dtype = dtype.lower()
122
+
123
+ if not issubclass(type(dtype), MTZFloat32Dtype):
124
+ try:
125
+ dtype = FLOAT_STR_TO_DTYPE[str(np.dtype(dtype))]
126
+ except KeyError as err:
127
+ raise ValueError(f"invalid dtype specified {dtype}") from err
128
+
129
+ if isinstance(values, MTZFloatArray):
130
+ values, mask = values._data, values._mask
131
+ if dtype is not None:
132
+ values = values.astype(dtype.numpy_dtype, copy=False)
133
+
134
+ if copy:
135
+ values = values.copy()
136
+ mask = mask.copy()
137
+ return values, mask
138
+
139
+ if copy:
140
+ values = np.array(values, copy=copy)
141
+ else:
142
+ values = np.asarray(values)
143
+
144
+ if is_object_dtype(values.dtype):
145
+ inferred_type = lib.infer_dtype(values, skipna=True)
146
+ if inferred_type == "empty":
147
+ pass
148
+ elif inferred_type not in [
149
+ "floating",
150
+ "integer",
151
+ "mixed-integer",
152
+ "integer-na",
153
+ "mixed-integer-float",
154
+ ]:
155
+ raise TypeError(f"{values.dtype} cannot be converted to a MTZFloat32Dtype")
156
+
157
+ elif is_bool_dtype(values) and is_float_dtype(dtype):
158
+ values = np.array(values, dtype=float, copy=copy)
159
+
160
+ elif not (is_integer_dtype(values) or is_float_dtype(values)):
161
+ raise TypeError(f"{values.dtype} cannot be converted to a MTZFloat32Dtype")
162
+
163
+ if values.ndim != 1:
164
+ raise TypeError("values must be a 1D list-like")
165
+
166
+ if mask is None:
167
+ mask = is_numeric_na(values)
168
+
169
+ else:
170
+ assert len(mask) == len(values)
171
+
172
+ if not mask.ndim == 1:
173
+ raise TypeError("mask must be a 1D list-like")
174
+
175
+ # infer dtype if needed
176
+ if dtype is None:
177
+ dtype = np.dtype("float64")
178
+ else:
179
+ dtype = dtype.type
180
+
181
+ # if we are float, let's make sure that we can
182
+ # safely cast
183
+
184
+ # we copy as need to coerce here
185
+ # TODO should this be a safe cast?
186
+ if mask.any():
187
+ values = values.copy()
188
+ values[mask] = np.nan
189
+ values = values.astype(dtype, copy=False) # , casting="safe")
190
+
191
+ return values, mask
192
+
193
+
194
+ class MTZFloatArray(NumericArray):
195
+ """
196
+ Array of floating (optional missing) values.
197
+
198
+ .. versionadded:: 1.2.0
199
+
200
+ .. warning::
201
+
202
+ MTZFloatArray is currently experimental, and its API or internal
203
+ implementation may change without warning. Especially the behaviour
204
+ regarding NaN (distinct from NA missing values) is subject to change.
205
+
206
+ We represent a MTZFloatArray with 2 numpy arrays:
207
+
208
+ - data: contains a numpy float array of the appropriate dtype
209
+ - mask: a boolean array holding a mask on the data, True is missing
210
+
211
+ To construct an MTZFloatArray from generic array-like input, use
212
+ :func:`pandas.array` with one of the float dtypes (see examples).
213
+
214
+ See :ref:`integer_na` for more.
215
+
216
+ Parameters
217
+ ----------
218
+ values : numpy.ndarray
219
+ A 1-d float-dtype array.
220
+ mask : numpy.ndarray
221
+ A 1-d boolean-dtype array indicating missing values.
222
+ copy : bool, default False
223
+ Whether to copy the `values` and `mask`.
224
+
225
+ Attributes
226
+ ----------
227
+ None
228
+
229
+ Methods
230
+ -------
231
+ None
232
+
233
+ Returns
234
+ -------
235
+ MTZFloatArray
236
+
237
+ Examples
238
+ --------
239
+ Create an MTZFloatArray with :func:`pandas.array`:
240
+
241
+ >>> pd.array([0.1, None, 0.3], dtype=pd.Float32Dtype())
242
+ <MTZFloatArray>
243
+ [0.1, <NA>, 0.3]
244
+ Length: 3, dtype: Float32
245
+
246
+ String aliases for the dtypes are also available. They are capitalized.
247
+
248
+ >>> pd.array([0.1, None, 0.3], dtype="Float32")
249
+ <MTZFloatArray>
250
+ [0.1, <NA>, 0.3]
251
+ Length: 3, dtype: Float32
252
+ """
253
+
254
+ # The value used to fill '_data' to avoid upcasting
255
+ _internal_fill_value = 0.0
256
+ # Fill values used for any/all
257
+ _truthy_value = 1.0
258
+ _falsey_value = 0.0
259
+
260
+ @cache_readonly
261
+ def dtype(self) -> MTZFloat32Dtype:
262
+ return self._dtype
263
+
264
+ def __init__(self, values: np.ndarray, mask: np.ndarray, copy: bool = False):
265
+ if not (isinstance(values, np.ndarray) and values.dtype.kind == "f"):
266
+ raise TypeError(
267
+ "values should be floating numpy array. Use "
268
+ "the 'pd.array' function instead"
269
+ )
270
+ if values.dtype == np.float16:
271
+ # If we don't raise here, then accessing self.dtype would raise
272
+ raise TypeError("MTZFloatArray does not support np.float16 dtype.")
273
+
274
+ super().__init__(values, mask, copy=copy)
275
+
276
+ @classmethod
277
+ def _from_sequence(
278
+ cls, scalars, *, dtype=None, copy: bool = False
279
+ ) -> MTZFloatArray:
280
+ values, mask = coerce_to_array(scalars, dtype=dtype, copy=copy)
281
+ return cls(values, mask)
282
+
283
+ @classmethod
284
+ def _from_sequence_of_strings(
285
+ cls, strings, *, dtype=None, copy: bool = False
286
+ ) -> MTZFloatArray:
287
+ scalars = to_numeric(strings, errors="raise")
288
+ return cls._from_sequence(scalars, dtype=dtype, copy=copy)
289
+
290
+ def _coerce_to_array(self, value) -> tuple[np.ndarray, np.ndarray]:
291
+ return coerce_to_array(value, dtype=self.dtype)
292
+
293
+ def _maybe_mask_result(self, result, mask):
294
+ """
295
+ Parameters
296
+ ----------
297
+ result : array-like
298
+ mask : array-like bool
299
+ """
300
+ # if we have a float operand we are by-definition
301
+ # a float result
302
+ # or our op is a divide
303
+ if result.dtype.kind == "f":
304
+ return type(self)(result, mask, copy=False)
305
+ return super()._maybe_mask_result(result=result, mask=mask)
306
+
307
+ def astype(self, dtype, copy: bool = True) -> ArrayLike:
308
+ """
309
+ Cast to a NumPy array or ExtensionArray with 'dtype'.
310
+
311
+ Parameters
312
+ ----------
313
+ dtype : str or dtype
314
+ Typecode or data-type to which the array is cast.
315
+ copy : bool, default True
316
+ Whether to copy the data, even if not necessary. If False,
317
+ a copy is made only if the old dtype does not match the
318
+ new dtype.
319
+
320
+ Returns
321
+ -------
322
+ ndarray or ExtensionArray
323
+ NumPy ndarray, or BooleanArray, IntegerArray or MTZFloatArray with
324
+ 'dtype' for its dtype.
325
+
326
+ Raises
327
+ ------
328
+ TypeError
329
+ if incompatible type with an MTZFloat32Dtype, equivalent of same_kind
330
+ casting
331
+ """
332
+ dtype = pandas_dtype(dtype)
333
+
334
+ if isinstance(dtype, ExtensionDtype):
335
+ return super().astype(dtype, copy=copy)
336
+
337
+ # coerce
338
+ if is_float_dtype(dtype):
339
+ # In astype, we consider dtype=float to also mean na_value=np.nan
340
+ kwargs = {"na_value": np.nan}
341
+ else:
342
+ kwargs = {}
343
+
344
+ # error: Argument 2 to "to_numpy" of "BaseMaskedArray" has incompatible
345
+ # type "**Dict[str, float]"; expected "bool"
346
+ data = self.to_numpy(dtype=dtype, **kwargs) # type: ignore[arg-type]
347
+ return astype_nansafe(data, dtype, copy=False)
348
+
349
+ def _values_for_argsort(self) -> np.ndarray:
350
+ return self._data
351
+
352
+ def to_numpy(self, dtype=None, copy=False, **kwargs):
353
+ """
354
+ Convert to a NumPy Array.
355
+
356
+ If `dtype` is None it will default to a float32 ndarray.
357
+
358
+ Parameters
359
+ ----------
360
+ dtype : dtype, default np.float32
361
+ The numpy dtype to return
362
+ copy : bool, default False
363
+ Whether to ensure that the returned value is a not a view on
364
+ the array. Note that ``copy=False`` does not *ensure* that
365
+ ``to_numpy()`` is no-copy. Rather, ``copy=True`` ensure that
366
+ a copy is made, even if not strictly necessary. This is typically
367
+ only possible when no missing values are present and `dtype`
368
+ is the equivalent numpy dtype.
369
+
370
+ Returns
371
+ -------
372
+ numpy.ndarray
373
+ """
374
+ if dtype is None:
375
+ dtype = np.float32
376
+
377
+ # na_value is hard-coded to np.nan -- this prevents other functions
378
+ # from resetting it.
379
+ return super().to_numpy(dtype=dtype, copy=copy, na_value=np.nan)
380
+
381
+
382
+ # create the Dtype
383
+ @register_extension_dtype
384
+ class AnomalousDifferenceDtype(MTZFloat32Dtype):
385
+ """Dtype for anomalous difference data in reflection tables"""
386
+
387
+ name = "AnomalousDifference"
388
+ mtztype = "D"
389
+
390
+ def is_friedel_dtype(self):
391
+ return False
392
+
393
+ @classmethod
394
+ def construct_array_type(cls):
395
+ return AnomalousDifferenceArray
396
+
397
+
398
+ class AnomalousDifferenceArray(MTZFloatArray):
399
+ """ExtensionArray for supporting AnomalousDifferenceDtype"""
400
+
401
+ _dtype = AnomalousDifferenceDtype()
402
+ pass
403
+
404
+
405
+ @register_extension_dtype
406
+ class IntensityDtype(MTZFloat32Dtype):
407
+ """Dtype for Intensity data in reflection tables"""
408
+
409
+ name = "Intensity"
410
+ mtztype = "J"
411
+
412
+ def is_friedel_dtype(self):
413
+ return False
414
+
415
+ @classmethod
416
+ def construct_array_type(cls):
417
+ return IntensityArray
418
+
419
+
420
+ class IntensityArray(MTZFloatArray):
421
+ """ExtensionArray for supporting IntensityDtype"""
422
+
423
+ _dtype = IntensityDtype()
424
+ pass
425
+
426
+
427
+ @register_extension_dtype
428
+ class FriedelIntensityDtype(MTZFloat32Dtype):
429
+ """Dtype for I(+) or I(-) data in reflection tables"""
430
+
431
+ name = "FriedelIntensity"
432
+ mtztype = "K"
433
+
434
+ def is_friedel_dtype(self):
435
+ return True
436
+
437
+ @classmethod
438
+ def construct_array_type(cls):
439
+ return FriedelIntensityArray
440
+
441
+
442
+ class FriedelIntensityArray(MTZFloatArray):
443
+ """ExtensionArray for supporting FriedelIntensityDtype"""
444
+
445
+ _dtype = FriedelIntensityDtype()
446
+ pass
447
+
448
+
449
+ @register_extension_dtype
450
+ class MTZRealDtype(MTZFloat32Dtype):
451
+ """Dtype for generic MTZ real data"""
452
+
453
+ name = "MTZReal"
454
+ mtztype = "R"
455
+
456
+ def is_friedel_dtype(self):
457
+ return False
458
+
459
+ @classmethod
460
+ def construct_array_type(cls):
461
+ return MTZRealArray
462
+
463
+
464
+ class MTZRealArray(MTZFloatArray):
465
+ """ExtensionArray for supporting MtzRealDtype"""
466
+
467
+ _dtype = MTZRealDtype()
468
+ pass
469
+
470
+
471
+ @register_extension_dtype
472
+ class PhaseDtype(MTZFloat32Dtype):
473
+ """Dtype for representing phase data in reflection tables"""
474
+
475
+ name = "Phase"
476
+ mtztype = "P"
477
+
478
+ def is_friedel_dtype(self):
479
+ return False
480
+
481
+ @classmethod
482
+ def construct_array_type(cls):
483
+ return PhaseArray
484
+
485
+
486
+ class PhaseArray(MTZFloatArray):
487
+ """ExtensionArray for supporting PhaseDtype"""
488
+
489
+ _dtype = PhaseDtype()
490
+ pass
491
+
492
+
493
+ @register_extension_dtype
494
+ class HendricksonLattmanDtype(MTZFloat32Dtype):
495
+ """
496
+ Dtype for representing phase probability coefficients
497
+ (Hendrickson-Lattman) in reflection tables
498
+ """
499
+
500
+ name = "HendricksonLattman"
501
+ mtztype = "A"
502
+
503
+ def is_friedel_dtype(self):
504
+ return False
505
+
506
+ @classmethod
507
+ def construct_array_type(cls):
508
+ return HendricksonLattmanArray
509
+
510
+
511
+ class HendricksonLattmanArray(MTZFloatArray):
512
+ """ExtensionArray for supporting HendricksonLattmanDtype"""
513
+
514
+ _dtype = HendricksonLattmanDtype()
515
+ pass
516
+
517
+
518
+ @register_extension_dtype
519
+ class StandardDeviationDtype(MTZFloat32Dtype):
520
+ """Dtype for standard deviation of observables: J, F, D or other"""
521
+
522
+ name = "Stddev"
523
+ mtztype = "Q"
524
+
525
+ def is_friedel_dtype(self):
526
+ return False
527
+
528
+ @classmethod
529
+ def construct_array_type(cls):
530
+ return StandardDeviationArray
531
+
532
+
533
+ class StandardDeviationArray(MTZFloatArray):
534
+ """ExtensionArray for supporting StandardDeviationDtype"""
535
+
536
+ _dtype = StandardDeviationDtype()
537
+ pass
538
+
539
+
540
+ @register_extension_dtype
541
+ class StandardDeviationFriedelSFDtype(MTZFloat32Dtype):
542
+ """Dtype for standard deviation of F(+) or F(-)"""
543
+
544
+ name = "StddevFriedelSF"
545
+ mtztype = "L"
546
+
547
+ def is_friedel_dtype(self):
548
+ return True
549
+
550
+ @classmethod
551
+ def construct_array_type(cls):
552
+ return StandardDeviationFriedelSFArray
553
+
554
+
555
+ class StandardDeviationFriedelSFArray(MTZFloatArray):
556
+ """ExtensionArray for supporting StandardDeviationFriedelSFDtype"""
557
+
558
+ _dtype = StandardDeviationFriedelSFDtype()
559
+ pass
560
+
561
+
562
+ @register_extension_dtype
563
+ class StandardDeviationFriedelIDtype(MTZFloat32Dtype):
564
+ """Dtype for standard deviation of I(+) or I(-)"""
565
+
566
+ name = "StddevFriedelI"
567
+ mtztype = "M"
568
+
569
+ def is_friedel_dtype(self):
570
+ return True
571
+
572
+ @classmethod
573
+ def construct_array_type(cls):
574
+ return StandardDeviationFriedelIArray
575
+
576
+
577
+ class StandardDeviationFriedelIArray(MTZFloatArray):
578
+ """ExtensionArray for supporting StandardDeviationFriedelIDtype"""
579
+
580
+ _dtype = StandardDeviationFriedelIDtype()
581
+ pass
582
+
583
+
584
+ @register_extension_dtype
585
+ class StructureFactorAmplitudeDtype(MTZFloat32Dtype):
586
+ """Dtype for structure factor amplitude data"""
587
+
588
+ name = "SFAmplitude"
589
+ mtztype = "F"
590
+
591
+ def is_friedel_dtype(self):
592
+ return False
593
+
594
+ @classmethod
595
+ def construct_array_type(cls):
596
+ return StructureFactorAmplitudeArray
597
+
598
+
599
+ class StructureFactorAmplitudeArray(MTZFloatArray):
600
+ """ExtensionArray for supporting StructureFactorAmplitudeDtype"""
601
+
602
+ _dtype = StructureFactorAmplitudeDtype()
603
+ pass
604
+
605
+
606
+ @register_extension_dtype
607
+ class FriedelStructureFactorAmplitudeDtype(MTZFloat32Dtype):
608
+ """
609
+ Dtype for structure factor amplitude data from Friedel pairs --
610
+ F(+) or F(-)
611
+ """
612
+
613
+ name = "FriedelSFAmplitude"
614
+ mtztype = "G"
615
+
616
+ def is_friedel_dtype(self):
617
+ return True
618
+
619
+ @classmethod
620
+ def construct_array_type(cls):
621
+ return FriedelStructureFactorAmplitudeArray
622
+
623
+
624
+ class FriedelStructureFactorAmplitudeArray(MTZFloatArray):
625
+ """ExtensionArray for supporting FriedelStructureFactorAmplitudeDtype"""
626
+
627
+ _dtype = FriedelStructureFactorAmplitudeDtype()
628
+ pass
629
+
630
+
631
+ @register_extension_dtype
632
+ class NormalizedStructureFactorAmplitudeDtype(MTZFloat32Dtype):
633
+ """Dtype for normalized structure factor amplitude data"""
634
+
635
+ name = "NormalizedSFAmplitude"
636
+ mtztype = "E"
637
+
638
+ def is_friedel_dtype(self):
639
+ return False
640
+
641
+ @classmethod
642
+ def construct_array_type(cls):
643
+ return NormalizedStructureFactorAmplitudeArray
644
+
645
+
646
+ class NormalizedStructureFactorAmplitudeArray(MTZFloatArray):
647
+ """ExtensionArray for supporting NormalizedStructureFactorAmplitudeDtype"""
648
+
649
+ _dtype = NormalizedStructureFactorAmplitudeDtype()
650
+ pass
651
+
652
+
653
+ @register_extension_dtype
654
+ class WeightDtype(MTZFloat32Dtype):
655
+ """Dtype for representing weights"""
656
+
657
+ name = "Weight"
658
+ mtztype = "W"
659
+
660
+ def is_friedel_dtype(self):
661
+ return False
662
+
663
+ @classmethod
664
+ def construct_array_type(cls):
665
+ return WeightArray
666
+
667
+
668
+ class WeightArray(MTZFloatArray):
669
+ """ExtensionArray for supporting WeightDtype"""
670
+
671
+ _dtype = WeightDtype()
672
+ pass
673
+
674
+
675
+ FLOAT_STR_TO_DTYPE = {
676
+ "AnomalousDifference": AnomalousDifferenceDtype(),
677
+ "Intensity": IntensityDtype(),
678
+ "FriedelIntensity": FriedelIntensityDtype(),
679
+ "MTZReal": MTZRealDtype(),
680
+ "Phase": PhaseDtype(),
681
+ "HendricksonLattman": HendricksonLattmanDtype(),
682
+ "Stddev": StandardDeviationDtype(),
683
+ "StddevFriedelSF": StandardDeviationFriedelSFDtype(),
684
+ "StddevFriedelI": StandardDeviationFriedelIDtype(),
685
+ "SFAmplitude": StructureFactorAmplitudeDtype(),
686
+ "FriedelSFAmplitude": FriedelStructureFactorAmplitudeDtype(),
687
+ "NormalizedSFAmplitude": NormalizedStructureFactorAmplitudeDtype(),
688
+ "Weight": WeightDtype(),
689
+ "float32": Float32Dtype(),
690
+ "float64": Float64Dtype(),
691
+ }