ChessAnalysisPipeline 0.0.11__tar.gz → 0.0.13__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 ChessAnalysisPipeline might be problematic. Click here for more details.
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/__init__.py +2 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/__init__.py +6 -2
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/models/map.py +217 -70
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/processor.py +249 -155
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/reader.py +175 -130
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/writer.py +150 -94
- ChessAnalysisPipeline-0.0.13/CHAP/edd/models.py +876 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/edd/processor.py +614 -354
- ChessAnalysisPipeline-0.0.13/CHAP/edd/utils.py +875 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/tomo/models.py +22 -18
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/tomo/processor.py +1215 -892
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/fit.py +211 -127
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/general.py +789 -610
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/parfile.py +1 -9
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/scanparsers.py +101 -52
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13/ChessAnalysisPipeline.egg-info}/PKG-INFO +2 -1
- {ChessAnalysisPipeline-0.0.11/ChessAnalysisPipeline.egg-info → ChessAnalysisPipeline-0.0.13}/PKG-INFO +2 -1
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/setup.py +1 -1
- ChessAnalysisPipeline-0.0.11/CHAP/edd/models.py +0 -680
- ChessAnalysisPipeline-0.0.11/CHAP/edd/utils.py +0 -364
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/TaskManager.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/models/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/common/models/integration.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/edd/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/edd/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/edd/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/inference/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/inference/processor.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/inference/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/inference/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/pipeline.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/processor.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/runner.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/saxswaxs/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/saxswaxs/processor.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/saxswaxs/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/saxswaxs/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/server.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/sin2psi/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/sin2psi/processor.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/sin2psi/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/sin2psi/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/tomo/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/tomo/reader.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/tomo/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/utils/material.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/CHAP/writer.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/ChessAnalysisPipeline.egg-info/SOURCES.txt +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/ChessAnalysisPipeline.egg-info/dependency_links.txt +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/ChessAnalysisPipeline.egg-info/entry_points.txt +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/ChessAnalysisPipeline.egg-info/requires.txt +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/ChessAnalysisPipeline.egg-info/top_level.txt +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/LICENSE +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/MLaaS/__init__.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/MLaaS/ktrain.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/MLaaS/mnist_img.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/MLaaS/tfaas_client.py +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/README.md +0 -0
- {ChessAnalysisPipeline-0.0.11 → ChessAnalysisPipeline-0.0.13}/setup.cfg +0 -0
|
@@ -9,14 +9,17 @@ validating input data in some `Processor`s.
|
|
|
9
9
|
|
|
10
10
|
from CHAP.common.reader import (
|
|
11
11
|
BinaryFileReader,
|
|
12
|
-
|
|
12
|
+
H5Reader,
|
|
13
13
|
MapReader,
|
|
14
14
|
NexusReader,
|
|
15
|
+
SpecReader,
|
|
15
16
|
URLReader,
|
|
16
17
|
YAMLReader,
|
|
17
18
|
)
|
|
18
19
|
from CHAP.common.processor import (
|
|
20
|
+
AnimationProcessor,
|
|
19
21
|
AsyncProcessor,
|
|
22
|
+
ImageProcessor,
|
|
20
23
|
IntegrationProcessor,
|
|
21
24
|
IntegrateMapProcessor,
|
|
22
25
|
MapProcessor,
|
|
@@ -30,9 +33,10 @@ from CHAP.common.processor import (
|
|
|
30
33
|
)
|
|
31
34
|
from CHAP.common.writer import (
|
|
32
35
|
ExtractArchiveWriter,
|
|
36
|
+
FileTreeWriter,
|
|
37
|
+
MatplotlibAnimationWriter,
|
|
33
38
|
MatplotlibFigureWriter,
|
|
34
39
|
NexusWriter,
|
|
35
40
|
YAMLWriter,
|
|
36
41
|
TXTWriter,
|
|
37
|
-
FileTreeWriter,
|
|
38
42
|
)
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# System modules
|
|
2
|
-
from
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from functools import (
|
|
4
|
+
cache,
|
|
5
|
+
lru_cache,
|
|
6
|
+
)
|
|
3
7
|
import os
|
|
4
|
-
from typing import
|
|
8
|
+
from typing import (
|
|
9
|
+
Literal,
|
|
10
|
+
Optional,
|
|
11
|
+
Union,
|
|
12
|
+
)
|
|
5
13
|
|
|
6
14
|
# Third party modules
|
|
7
15
|
import numpy as np
|
|
8
|
-
from pydantic import (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
from pydantic import (
|
|
17
|
+
BaseModel,
|
|
18
|
+
conint,
|
|
19
|
+
conlist,
|
|
20
|
+
constr,
|
|
21
|
+
FilePath,
|
|
22
|
+
PrivateAttr,
|
|
23
|
+
root_validator,
|
|
24
|
+
validator,
|
|
25
|
+
)
|
|
15
26
|
from pyspec.file.spec import FileSpec
|
|
16
27
|
|
|
17
28
|
|
|
@@ -39,7 +50,7 @@ class SpecScans(BaseModel):
|
|
|
39
50
|
scan_numbers: conlist(item_type=conint(gt=0), min_items=1)
|
|
40
51
|
|
|
41
52
|
@validator('spec_file', allow_reuse=True)
|
|
42
|
-
def validate_spec_file(cls, spec_file):
|
|
53
|
+
def validate_spec_file(cls, spec_file, values):
|
|
43
54
|
"""Validate the specified SPEC file.
|
|
44
55
|
|
|
45
56
|
:param spec_file: Path to the SPEC file.
|
|
@@ -55,7 +66,7 @@ class SpecScans(BaseModel):
|
|
|
55
66
|
raise ValueError(f'Invalid SPEC file {spec_file}')
|
|
56
67
|
return spec_file
|
|
57
68
|
|
|
58
|
-
@validator('scan_numbers', allow_reuse=True)
|
|
69
|
+
@validator('scan_numbers', pre=True, allow_reuse=True)
|
|
59
70
|
def validate_scan_numbers(cls, scan_numbers, values):
|
|
60
71
|
"""Validate the specified list of scan numbers.
|
|
61
72
|
|
|
@@ -68,6 +79,12 @@ class SpecScans(BaseModel):
|
|
|
68
79
|
:return: List of scan numbers.
|
|
69
80
|
:rtype: list of int
|
|
70
81
|
"""
|
|
82
|
+
if isinstance(scan_numbers, str):
|
|
83
|
+
# Local modules
|
|
84
|
+
from CHAP.utils.general import string_to_list
|
|
85
|
+
|
|
86
|
+
scan_numbers = string_to_list(scan_numbers)
|
|
87
|
+
|
|
71
88
|
spec_file = values.get('spec_file')
|
|
72
89
|
if spec_file is not None:
|
|
73
90
|
spec_scans = FileSpec(spec_file)
|
|
@@ -550,6 +567,28 @@ class SpecConfig(BaseModel):
|
|
|
550
567
|
experiment_type: Literal['SAXSWAXS', 'EDD', 'XRF', 'TOMO']
|
|
551
568
|
spec_scans: conlist(item_type=SpecScans, min_items=1)
|
|
552
569
|
|
|
570
|
+
@root_validator(pre=True)
|
|
571
|
+
def validate_config(cls, values):
|
|
572
|
+
"""Ensure that a valid configuration was provided and finalize
|
|
573
|
+
spec_file filepaths.
|
|
574
|
+
|
|
575
|
+
:param values: Dictionary of class field values.
|
|
576
|
+
:type values: dict
|
|
577
|
+
:return: The validated list of `values`.
|
|
578
|
+
:rtype: dict
|
|
579
|
+
"""
|
|
580
|
+
inputdir = values.get('inputdir')
|
|
581
|
+
if inputdir is not None:
|
|
582
|
+
spec_scans = values.get('spec_scans')
|
|
583
|
+
for i, scans in enumerate(deepcopy(spec_scans)):
|
|
584
|
+
spec_file = scans['spec_file']
|
|
585
|
+
if not os.path.isabs(spec_file):
|
|
586
|
+
spec_scans[i]['spec_file'] = os.path.join(
|
|
587
|
+
inputdir, spec_file)
|
|
588
|
+
spec_scans[i] = SpecScans(**spec_scans[i], **values)
|
|
589
|
+
values['spec_scans'] = spec_scans
|
|
590
|
+
return values
|
|
591
|
+
|
|
553
592
|
@validator('experiment_type')
|
|
554
593
|
def validate_experiment_type(cls, value, values):
|
|
555
594
|
"""Ensure values for the station and experiment_type fields are
|
|
@@ -606,19 +645,26 @@ class MapConfig(BaseModel):
|
|
|
606
645
|
map. In the NeXus file representation of the map, datasets for
|
|
607
646
|
these values will be included.
|
|
608
647
|
:type scalar_values: Optional[list[PointByPointScanData]]
|
|
648
|
+
:ivar map_type: Type of map, structured or unstructured,
|
|
649
|
+
defaults to `'structured'`.
|
|
650
|
+
:type map_type: Optional[Literal['structured', 'unstructured']]
|
|
609
651
|
"""
|
|
610
652
|
title: constr(strip_whitespace=True, min_length=1)
|
|
611
653
|
station: Literal['id1a3','id3a','id3b']
|
|
612
654
|
experiment_type: Literal['SAXSWAXS', 'EDD', 'XRF', 'TOMO']
|
|
613
655
|
sample: Sample
|
|
614
656
|
spec_scans: conlist(item_type=SpecScans, min_items=1)
|
|
615
|
-
independent_dimensions: conlist(
|
|
616
|
-
|
|
657
|
+
independent_dimensions: conlist(
|
|
658
|
+
item_type=IndependentDimension, min_items=1)
|
|
617
659
|
presample_intensity: Optional[PresampleIntensity]
|
|
618
660
|
dwell_time_actual: Optional[DwellTimeActual]
|
|
619
661
|
postsample_intensity: Optional[PostsampleIntensity]
|
|
620
662
|
scalar_data: Optional[list[PointByPointScanData]] = []
|
|
663
|
+
map_type: Optional[Literal['structured', 'unstructured']] = 'structured'
|
|
621
664
|
_coords: dict = PrivateAttr()
|
|
665
|
+
_dims: tuple = PrivateAttr()
|
|
666
|
+
_scan_step_indices: list = PrivateAttr()
|
|
667
|
+
_shape: tuple = PrivateAttr()
|
|
622
668
|
|
|
623
669
|
_validate_independent_dimensions = validator(
|
|
624
670
|
'independent_dimensions',
|
|
@@ -638,6 +684,75 @@ class MapConfig(BaseModel):
|
|
|
638
684
|
each_item=True,
|
|
639
685
|
allow_reuse=True)(validate_data_source_for_map_config)
|
|
640
686
|
|
|
687
|
+
@root_validator(pre=True)
|
|
688
|
+
def validate_config(cls, values):
|
|
689
|
+
"""Ensure that a valid configuration was provided and finalize
|
|
690
|
+
spec_file filepaths.
|
|
691
|
+
|
|
692
|
+
:param values: Dictionary of class field values.
|
|
693
|
+
:type values: dict
|
|
694
|
+
:return: The validated list of `values`.
|
|
695
|
+
:rtype: dict
|
|
696
|
+
"""
|
|
697
|
+
inputdir = values.get('inputdir')
|
|
698
|
+
if inputdir is not None:
|
|
699
|
+
spec_scans = values.get('spec_scans')
|
|
700
|
+
for i, scans in enumerate(deepcopy(spec_scans)):
|
|
701
|
+
spec_file = scans['spec_file']
|
|
702
|
+
if not os.path.isabs(spec_file):
|
|
703
|
+
spec_scans[i]['spec_file'] = os.path.join(
|
|
704
|
+
inputdir, spec_file)
|
|
705
|
+
spec_scans[i] = SpecScans(**spec_scans[i], **values)
|
|
706
|
+
values['spec_scans'] = spec_scans
|
|
707
|
+
return values
|
|
708
|
+
|
|
709
|
+
@validator('map_type', pre=True, always=True)
|
|
710
|
+
def validate_map_type(cls, map_type, values):
|
|
711
|
+
"""Validate the map_type field.
|
|
712
|
+
|
|
713
|
+
:param map_type: Type of map, structured or unstructured,
|
|
714
|
+
defaults to `'structured'`.
|
|
715
|
+
:type map_type: Literal['structured', 'unstructured']]
|
|
716
|
+
:param values: Dictionary of values for all fields of the model.
|
|
717
|
+
:type values: dict
|
|
718
|
+
:return: The validated value for map_type.
|
|
719
|
+
:rtype: str
|
|
720
|
+
"""
|
|
721
|
+
dims = {}
|
|
722
|
+
spec_scans = values.get('spec_scans')
|
|
723
|
+
independent_dimensions = values.get('independent_dimensions')
|
|
724
|
+
import_scanparser(values.get('station'), values.get('experiment_type'))
|
|
725
|
+
for i, dim in enumerate(deepcopy(independent_dimensions)):
|
|
726
|
+
dims[dim.label] = []
|
|
727
|
+
for scans in spec_scans:
|
|
728
|
+
for scan_number in scans.scan_numbers:
|
|
729
|
+
scanparser = scans.get_scanparser(scan_number)
|
|
730
|
+
for scan_step_index in range(
|
|
731
|
+
scanparser.spec_scan_npts):
|
|
732
|
+
dims[dim.label].append(dim.get_value(
|
|
733
|
+
scans, scan_number, scan_step_index))
|
|
734
|
+
dims[dim.label] = np.unique(dims[dim.label])
|
|
735
|
+
if dim.end is None:
|
|
736
|
+
dim.end = len(dims[dim.label])
|
|
737
|
+
dims[dim.label] = dims[dim.label][slice(
|
|
738
|
+
dim.start, dim.end, dim.step)]
|
|
739
|
+
independent_dimensions[i] = dim
|
|
740
|
+
|
|
741
|
+
coords = np.zeros([v.size for v in dims.values()], dtype=np.int64)
|
|
742
|
+
for scans in spec_scans:
|
|
743
|
+
for scan_number in scans.scan_numbers:
|
|
744
|
+
scanparser = scans.get_scanparser(scan_number)
|
|
745
|
+
for scan_step_index in range(scanparser.spec_scan_npts):
|
|
746
|
+
coords[tuple([
|
|
747
|
+
list(dims[dim.label]).index(
|
|
748
|
+
dim.get_value(scans, scan_number, scan_step_index))
|
|
749
|
+
for dim in independent_dimensions])] += 1
|
|
750
|
+
if any(True for v in coords.flatten() if v == 0 or v > 1):
|
|
751
|
+
return 'unstructured'
|
|
752
|
+
else:
|
|
753
|
+
return 'structured'
|
|
754
|
+
|
|
755
|
+
|
|
641
756
|
@validator('experiment_type')
|
|
642
757
|
def validate_experiment_type(cls, value, values):
|
|
643
758
|
"""Ensure values for the station and experiment_type fields are
|
|
@@ -659,17 +774,26 @@ class MapConfig(BaseModel):
|
|
|
659
774
|
f'Supplied experiment type {value} is not allowed.')
|
|
660
775
|
return value
|
|
661
776
|
|
|
777
|
+
@property
|
|
778
|
+
def all_scalar_data(self):
|
|
779
|
+
"""Return a list of all instances of `PointByPointScanData`
|
|
780
|
+
for which this map configuration will collect dataset-like
|
|
781
|
+
data (as opposed to axes-like data).
|
|
782
|
+
|
|
783
|
+
This will be any and all of the items in the
|
|
784
|
+
corrections-data-related fields, as well as any additional
|
|
785
|
+
items in the optional `scalar_data` field.
|
|
786
|
+
"""
|
|
787
|
+
return [getattr(self, label, None)
|
|
788
|
+
for label in CorrectionsData.reserved_labels()
|
|
789
|
+
if getattr(self, label, None) is not None] + self.scalar_data
|
|
790
|
+
|
|
662
791
|
@property
|
|
663
792
|
def coords(self):
|
|
664
793
|
"""Return a dictionary of the values of each independent
|
|
665
794
|
dimension across the map.
|
|
666
|
-
|
|
667
|
-
:returns: A dictionary ofthe map's coordinate values.
|
|
668
|
-
:rtype: dict[str,list[float]]
|
|
669
795
|
"""
|
|
670
|
-
|
|
671
|
-
coords = self._coords
|
|
672
|
-
except:
|
|
796
|
+
if not hasattr(self, "_coords"):
|
|
673
797
|
coords = {}
|
|
674
798
|
for dim in self.independent_dimensions:
|
|
675
799
|
coords[dim.label] = []
|
|
@@ -680,67 +804,106 @@ class MapConfig(BaseModel):
|
|
|
680
804
|
scanparser.spec_scan_npts):
|
|
681
805
|
coords[dim.label].append(dim.get_value(
|
|
682
806
|
scans, scan_number, scan_step_index))
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
dim.end = len(coords[dim.label])
|
|
686
|
-
coords[dim.label] = coords[dim.label][slice(
|
|
687
|
-
dim.start, dim.end, dim.step)]
|
|
807
|
+
if self.map_type == 'structured':
|
|
808
|
+
coords[dim.label] = np.unique(coords[dim.label])
|
|
688
809
|
self._coords = coords
|
|
689
|
-
return
|
|
810
|
+
return self._coords
|
|
690
811
|
|
|
691
812
|
@property
|
|
692
813
|
def dims(self):
|
|
693
814
|
"""Return a tuple of the independent dimension labels for the
|
|
694
815
|
map.
|
|
695
816
|
"""
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
in self.independent_dimensions[::-1]]
|
|
817
|
+
if not hasattr(self, "_dims"):
|
|
818
|
+
self._dims = [
|
|
819
|
+
dim.label for dim in self.independent_dimensions[::-1]]
|
|
820
|
+
return self._dims
|
|
821
|
+
|
|
822
|
+
@property
|
|
823
|
+
def scan_step_indices(self):
|
|
824
|
+
"""Return an ordered list in which we can look up the SpecScans
|
|
825
|
+
object, the scan number, and scan step index for every point
|
|
826
|
+
on the map.
|
|
827
|
+
"""
|
|
828
|
+
if not hasattr(self, "_scan_step_indices"):
|
|
829
|
+
scan_step_indices = []
|
|
830
|
+
for scans in self.spec_scans:
|
|
831
|
+
for scan_number in scans.scan_numbers:
|
|
832
|
+
scanparser = scans.get_scanparser(scan_number)
|
|
833
|
+
for scan_step_index in range(scanparser.spec_scan_npts):
|
|
834
|
+
scan_step_indices.append(
|
|
835
|
+
(scans, scan_number, scan_step_index))
|
|
836
|
+
self._scan_step_indices = scan_step_indices
|
|
837
|
+
return self._scan_step_indices
|
|
699
838
|
|
|
700
839
|
@property
|
|
701
840
|
def shape(self):
|
|
702
841
|
"""Return the shape of the map -- a tuple representing the
|
|
703
842
|
number of unique values of each dimension across the map.
|
|
704
843
|
"""
|
|
705
|
-
|
|
844
|
+
if not hasattr(self, "_shape"):
|
|
845
|
+
if self.map_type == 'structured':
|
|
846
|
+
self._shape = tuple(
|
|
847
|
+
[len(v) for k, v in self.coords.items()][::-1])
|
|
848
|
+
else:
|
|
849
|
+
self._shape = (len(self.scan_step_indices),)
|
|
850
|
+
return self._shape
|
|
851
|
+
|
|
852
|
+
def get_coords(self, map_index):
|
|
853
|
+
"""Return a dictionary of the coordinate names and values of
|
|
854
|
+
each independent dimension for a given point on the map.
|
|
855
|
+
|
|
856
|
+
:param map_index: The map index to return coordinates for.
|
|
857
|
+
:type map_index: tuple
|
|
858
|
+
:return: A list of coordinate values.
|
|
859
|
+
:rtype: dict
|
|
860
|
+
"""
|
|
861
|
+
if self.map_type == 'structured':
|
|
862
|
+
return {dim:self.coords[dim][i]
|
|
863
|
+
for dim, i in zip(self.dims, map_index)}
|
|
864
|
+
else:
|
|
865
|
+
return {dim:self.coords[dim][map_index[0]] for dim in self.dims}
|
|
706
866
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
for which this map configuration will collect dataset-like
|
|
711
|
-
data (as opposed to axes-like data).
|
|
867
|
+
def get_detector_data(self, detector_name, map_index):
|
|
868
|
+
"""Return detector data collected by this map for a given
|
|
869
|
+
point on the map.
|
|
712
870
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
871
|
+
:param detector_name: Name of the detector for which to return
|
|
872
|
+
data. Usually the value of the detector's EPICS
|
|
873
|
+
areaDetector prefix macro, $P.
|
|
874
|
+
:type detector_name: str
|
|
875
|
+
:param map_index: The map index to return detector data for.
|
|
876
|
+
:type map_index: tuple
|
|
877
|
+
:return: One frame of raw detector data.
|
|
878
|
+
:rtype: np.ndarray
|
|
716
879
|
"""
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
880
|
+
scans, scan_number, scan_step_index = \
|
|
881
|
+
self.get_scan_step_index(map_index)
|
|
882
|
+
scanparser = scans.get_scanparser(scan_number)
|
|
883
|
+
return scanparser.get_detector_data(detector_name, scan_step_index)
|
|
720
884
|
|
|
721
885
|
def get_scan_step_index(self, map_index):
|
|
722
886
|
"""Return parameters to identify a single SPEC scan step that
|
|
723
887
|
corresponds to the map point at the index provided.
|
|
724
888
|
|
|
725
889
|
:param map_index: The index of a map point to identify as a
|
|
726
|
-
specific SPEC scan step index
|
|
890
|
+
specific SPEC scan step index.
|
|
727
891
|
:type map_index: tuple
|
|
728
892
|
:return: A `SpecScans` configuration, scan number, and scan
|
|
729
|
-
step index
|
|
893
|
+
step index.
|
|
730
894
|
:rtype: tuple[SpecScans, int, int]
|
|
731
895
|
"""
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
raise RuntimeError(f'Unable to match coordinates {coords}')
|
|
896
|
+
if self.map_type == 'structured':
|
|
897
|
+
map_coords = self.get_coords(map_index)
|
|
898
|
+
for scans, scan_number, scan_step_index in self.scan_step_indices:
|
|
899
|
+
coords = {dim.label:dim.get_value(
|
|
900
|
+
scans, scan_number, scan_step_index)
|
|
901
|
+
for dim in self.independent_dimensions}
|
|
902
|
+
if coords == map_coords:
|
|
903
|
+
return scans, scan_number, scan_step_index
|
|
904
|
+
raise RuntimeError(f'Unable to match coordinates {coords}')
|
|
905
|
+
else:
|
|
906
|
+
return self.scan_step_indices[map_index[0]]
|
|
744
907
|
|
|
745
908
|
def get_value(self, data, map_index):
|
|
746
909
|
"""Return the raw data collected by a single device at a
|
|
@@ -757,22 +920,6 @@ class MapConfig(BaseModel):
|
|
|
757
920
|
self.get_scan_step_index(map_index)
|
|
758
921
|
return data.get_value(scans, scan_number, scan_step_index)
|
|
759
922
|
|
|
760
|
-
def get_detector_data(self, detector_name, map_index):
|
|
761
|
-
"""Return detector data collected by this map.
|
|
762
|
-
|
|
763
|
-
:param detector_name: Name of the detector for which to return
|
|
764
|
-
data. Usually the value of the detector's EPICS
|
|
765
|
-
areaDetector prefix macro, $P.
|
|
766
|
-
:type detector_name: str
|
|
767
|
-
:param map_index: The map index to return detector data for.
|
|
768
|
-
:return: One frame of raw detector data
|
|
769
|
-
:rtype: np.ndarray
|
|
770
|
-
"""
|
|
771
|
-
scans, scan_number, scan_step_index = \
|
|
772
|
-
self.get_scan_step_index(map_index)
|
|
773
|
-
scanparser = scans.get_scanparser(scan_number)
|
|
774
|
-
return scanparser.get_detector_data(detector_name, scan_step_index)
|
|
775
|
-
|
|
776
923
|
|
|
777
924
|
def import_scanparser(station, experiment):
|
|
778
925
|
"""Given the name of a CHESS station and experiment type, import
|