Mercurial > repos > rv43 > tomo
comparison detector.py @ 65:f31ef7bfb430 draft
"planemo upload for repository https://github.com/rolfverberg/galaxytools commit d55db09b45d0b542f966cef17892858bb55d94f7"
author | rv43 |
---|---|
date | Thu, 18 Aug 2022 14:57:39 +0000 |
parents | 15288e9746e0 |
children |
comparison
equal
deleted
inserted
replaced
64:15288e9746e0 | 65:f31ef7bfb430 |
---|---|
2 import os | 2 import os |
3 import yaml | 3 import yaml |
4 from functools import cache | 4 from functools import cache |
5 from copy import deepcopy | 5 from copy import deepcopy |
6 | 6 |
7 from general import * | 7 from general import illegal_value, is_int, is_num, input_yesno |
8 | 8 |
9 #from hexrd.instrument import HEDMInstrument, PlanarDetector | 9 #from hexrd.instrument import HEDMInstrument, PlanarDetector |
10 | 10 |
11 class DetectorConfig: | 11 class DetectorConfig: |
12 def __init__(self, config_source): | 12 def __init__(self, config_source): |
13 | |
14 self._config_source = config_source | 13 self._config_source = config_source |
15 | 14 |
16 if isinstance(self._config_source, ((str, bytes, os.PathLike, int))): | 15 if isinstance(self._config_source, ((str, bytes, os.PathLike, int))): |
17 self._config_file = self._config_source | 16 self._config_file = self._config_source |
18 self._config = self._load_config_file() | 17 self._config = self._load_config_file() |
24 self._config = False | 23 self._config = False |
25 | 24 |
26 self._valid = self._validate() | 25 self._valid = self._validate() |
27 | 26 |
28 if not self.valid: | 27 if not self.valid: |
29 logging.error(f'Cannot create a valid instance of {self.__class__.__name__} from {self._config_source}') | 28 logging.error(f'Cannot create a valid instance of {self.__class__.__name__} '+ |
29 f'from {self._config_source}') | |
30 | 30 |
31 def __repr__(self): | 31 def __repr__(self): |
32 return(f'{self.__class__.__name__}({self._config_source.__repr__()})') | 32 return(f'{self.__class__.__name__}({self._config_source.__repr__()})') |
33 def __str__(self): | 33 def __str__(self): |
34 return(f'{self.__class__.__name__} generated from {self._config_source}') | 34 return(f'{self.__class__.__name__} generated from {self._config_source}') |
35 | 35 |
36 @property | 36 @property |
37 def config_file(self): | 37 def config_file(self): |
38 return(self._config_file) | 38 return(self._config_file) |
39 | |
39 @property | 40 @property |
40 def config(self): | 41 def config(self): |
41 return(deepcopy(self._config)) | 42 return(deepcopy(self._config)) |
43 | |
42 @property | 44 @property |
43 def valid(self): | 45 def valid(self): |
44 return(self._valid) | 46 return(self._valid) |
45 | 47 |
46 def load_config_file(self): | 48 def load_config_file(self): |
47 raise(NotImplementedError) | 49 raise(NotImplementedError) |
50 | |
48 def validate(self): | 51 def validate(self): |
49 raise(NotImplementedError) | 52 raise(NotImplementedError) |
50 | 53 |
51 def _load_config_file(self): | 54 def _load_config_file(self): |
52 if not os.path.isfile(self.config_file): | 55 if not os.path.isfile(self.config_file): |
53 logging.error(f'{self.config_file} is not a file.') | 56 logging.error(f'{self.config_file} is not a file.') |
54 return(False) | 57 return(False) |
55 else: | 58 else: |
56 return(self.load_config_file()) | 59 return(self.load_config_file()) |
60 | |
57 def _validate(self): | 61 def _validate(self): |
58 if not self.config: | 62 if not self.config: |
59 logging.error('A configuration must be loaded prior to calling Detector._validate') | 63 logging.error('A configuration must be loaded prior to calling Detector._validate') |
60 return(False) | 64 return(False) |
61 else: | 65 else: |
62 return(self.validate()) | 66 return(self.validate()) |
67 | |
63 def _write_to_file(self, out_file): | 68 def _write_to_file(self, out_file): |
64 out_file = os.path.abspath(out_file) | 69 out_file = os.path.abspath(out_file) |
65 | 70 |
66 current_config_valid = self.validate() | 71 current_config_valid = self.validate() |
67 if not current_config_valid: | 72 if not current_config_valid: |
68 write_invalid_config = input_yesno(s=f'This {self.__class__.__name__} is not currently valid. Write the configuration to {out_file} anyways?', default='no') | 73 write_invalid_config = input_yesno(s=f'This {self.__class__.__name__} is currently '+ |
74 f'invalid. Write the configuration to {out_file} anyways?', default='no') | |
69 if not write_invalid_config: | 75 if not write_invalid_config: |
70 logging.info(f'In accordance with user input, the invalid configuration will not be written to {out_file}') | 76 logging.info('In accordance with user input, the invalid configuration will '+ |
77 f'not be written to {out_file}') | |
71 return | 78 return |
72 | 79 |
73 if os.access(out_file, os.W_OK): | 80 if os.access(out_file, os.W_OK): |
74 if os.path.exists(out_file): | 81 if os.path.exists(out_file): |
75 overwrite = input_yesno(s=f'{out_file} already exists. Overwrite?', default='no') | 82 overwrite = input_yesno(s=f'{out_file} already exists. Overwrite?', default='no') |
76 if overwrite: | 83 if overwrite: |
77 self.write_to_file(out_file) | 84 self.write_to_file(out_file) |
78 else: | 85 else: |
79 logging.info(f'In accordance with user input, {out_file} will not be overwritten') | 86 logging.info(f'In accordance with user input, {out_file} will not be '+ |
87 'overwritten') | |
80 else: | 88 else: |
81 self.write_to_file(out_file) | 89 self.write_to_file(out_file) |
82 else: | 90 else: |
83 logging.error(f'Insufficient permissions to write to {out_file}') | 91 logging.error(f'Insufficient permissions to write to {out_file}') |
84 | 92 |
89 def __init__(self, config_source, validate_yaml_pars=[]): | 97 def __init__(self, config_source, validate_yaml_pars=[]): |
90 self._validate_yaml_pars = validate_yaml_pars | 98 self._validate_yaml_pars = validate_yaml_pars |
91 super().__init__(config_source) | 99 super().__init__(config_source) |
92 | 100 |
93 def load_config_file(self): | 101 def load_config_file(self): |
94 with open(self.config_file, 'r') as infile: | 102 if not os.path.splitext(self._config_file)[1]: |
103 if os.path.isfile(f'{self._config_file}.yml'): | |
104 self._config_file = f'{self._config_file}.yml' | |
105 if os.path.isfile(f'{self._config_file}.yaml'): | |
106 self._config_file = f'{self._config_file}.yaml' | |
107 if not os.path.isfile(self._config_file): | |
108 logging.error(f'Unable to load {self._config_file}') | |
109 return(False) | |
110 with open(self._config_file, 'r') as infile: | |
95 config = yaml.safe_load(infile) | 111 config = yaml.safe_load(infile) |
96 if isinstance(config, dict): | 112 if isinstance(config, dict): |
97 return(config) | 113 return(config) |
98 else: | 114 else: |
99 logging.error(f'Unable to load {self.config_file} as a dictionary') | 115 logging.error(f'Unable to load {self._config_file} as a dictionary') |
100 return(False) | 116 return(False) |
101 | 117 |
102 def validate(self): | 118 def validate(self): |
103 if not self._validate_yaml_pars: | 119 if not self._validate_yaml_pars: |
104 logging.warning('There are no required parameters provided for this detector configuration.') | 120 logging.warning('There are no required parameters provided for this detector '+ |
121 'configuration') | |
105 return(True) | 122 return(True) |
106 | 123 |
107 def validate_nested_pars(config, validate_yaml_par): | 124 def validate_nested_pars(config, validate_yaml_par): |
108 | |
109 yaml_par_levels = validate_yaml_par.split(':') | 125 yaml_par_levels = validate_yaml_par.split(':') |
110 first_level_par = yaml_par_levels[0] | 126 first_level_par = yaml_par_levels[0] |
111 try: | 127 try: |
112 first_level_par = int(first_level_par) | 128 first_level_par = int(first_level_par) |
113 except: | 129 except: |
120 else: | 136 else: |
121 return(True) | 137 return(True) |
122 except: | 138 except: |
123 return(False) | 139 return(False) |
124 | 140 |
125 pars_missing = [p for p in self._validate_yaml_pars if not validate_nested_pars(self.config, p)] | 141 pars_missing = [p for p in self._validate_yaml_pars |
142 if not validate_nested_pars(self.config, p)] | |
126 if len(pars_missing) > 0: | 143 if len(pars_missing) > 0: |
127 logging.error(f'Missing item(s) in configuration: {", ".join(pars_missing)}') | 144 logging.error(f'Missing item(s) in configuration: {", ".join(pars_missing)}') |
128 return(False) | 145 return(False) |
129 else: | 146 else: |
130 return(True) | 147 return(True) |
147 @cache | 164 @cache |
148 def lens_magnification(self): | 165 def lens_magnification(self): |
149 lens_magnification = self.config.get('lens_magnification') | 166 lens_magnification = self.config.get('lens_magnification') |
150 if not isinstance(lens_magnification, (int, float)) or lens_magnification <= 0.: | 167 if not isinstance(lens_magnification, (int, float)) or lens_magnification <= 0.: |
151 illegal_value(lens_magnification, 'lens_magnification', 'detector file') | 168 illegal_value(lens_magnification, 'lens_magnification', 'detector file') |
152 logging.warning('Using default lens_magnification value of 1.0.') | 169 logging.warning('Using default lens_magnification value of 1.0') |
153 return(1.0) | 170 return(1.0) |
154 else: | 171 else: |
155 return(lens_magnification) | 172 return(lens_magnification) |
156 | 173 |
157 @property | 174 @property |
189 return(None) | 206 return(None) |
190 num_columns = pixels.get('columns') | 207 num_columns = pixels.get('columns') |
191 if not is_int(num_columns, 1): | 208 if not is_int(num_columns, 1): |
192 illegal_value(num_columns, 'columns', 'detector file') | 209 illegal_value(num_columns, 'columns', 'detector file') |
193 return(None) | 210 return(None) |
194 | |
195 return(num_rows, num_columns) | 211 return(num_rows, num_columns) |
196 | 212 |
197 | 213 |
198 class EDDDetectorConfig(YamlDetectorConfig): | 214 class EDDDetectorConfig(YamlDetectorConfig): |
199 def __init__(self, config_source): | 215 def __init__(self, config_source): |
229 illegal_value(self.config['max_E'], 'max_E') | 245 illegal_value(self.config['max_E'], 'max_E') |
230 return(None) | 246 return(None) |
231 | 247 |
232 @property | 248 @property |
233 def bin_energies(self): | 249 def bin_energies(self): |
234 return(self.slope * np.linspace(0, self.max_E, self.num_bins, endpoint=False) + self.intercept) | 250 return(self.slope * np.linspace(0, self.max_E, self.num_bins, endpoint=False) + |
251 self.intercept) | |
235 | 252 |
236 @property | 253 @property |
237 def tth_angle(self): | 254 def tth_angle(self): |
238 try: | 255 try: |
239 return(float(self.config['tth_angle'])) | 256 return(float(self.config['tth_angle'])) |