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'])) |
