Mercurial > repos > rv43 > tomo
comparison workflow/models.py @ 71:1cf15b61cd83 draft
planemo upload for repository https://github.com/rolfverberg/galaxytools commit 366e516aef0735af2998c6ff3af037181c8d5213
author | rv43 |
---|---|
date | Mon, 20 Mar 2023 13:56:57 +0000 |
parents | fba792d5f83b |
children |
comparison
equal
deleted
inserted
replaced
70:97c4e2cbbad9 | 71:1cf15b61cd83 |
---|---|
9 import os | 9 import os |
10 import yaml | 10 import yaml |
11 | 11 |
12 from functools import cache | 12 from functools import cache |
13 from pathlib import PosixPath | 13 from pathlib import PosixPath |
14 from pydantic import validator, ValidationError, conint, confloat, constr, \ | |
15 conlist, FilePath, PrivateAttr | |
16 from pydantic import BaseModel as PydanticBaseModel | 14 from pydantic import BaseModel as PydanticBaseModel |
15 from pydantic import validator, ValidationError, conint, confloat, constr, conlist, FilePath, \ | |
16 PrivateAttr | |
17 from nexusformat.nexus import * | 17 from nexusformat.nexus import * |
18 from time import time | 18 from time import time |
19 from typing import Optional, Literal | 19 from typing import Optional, Literal |
20 from typing_extensions import TypedDict | 20 from typing_extensions import TypedDict |
21 try: | 21 try: |
22 from pyspec.file.spec import FileSpec | 22 from pyspec.file.spec import FileSpec |
23 except: | 23 except: |
24 pass | 24 pass |
25 | 25 |
26 from msnctools.general import is_int, is_num, input_int, input_int_list, input_num, input_yesno, \ | 26 try: |
27 input_menu, index_nearest, string_to_list, file_exists_and_readable | 27 from msnctools.general import is_int, is_num, input_int, input_int_list, input_num, \ |
28 input_yesno, input_menu, index_nearest, string_to_list, file_exists_and_readable | |
29 except: | |
30 from general import is_int, is_num, input_int, input_int_list, input_num, \ | |
31 input_yesno, input_menu, index_nearest, string_to_list, file_exists_and_readable | |
28 | 32 |
29 | 33 |
30 def import_scanparser(station): | 34 def import_scanparser(station): |
31 if station in ('id1a3', 'id3a'): | 35 if station in ('id1a3', 'id3a'): |
32 from msnctools.scanparsers import SMBRotationScanParser | 36 try: |
33 globals()['ScanParser'] = SMBRotationScanParser | 37 from msnctools.scanparsers import SMBRotationScanParser |
38 globals()['ScanParser'] = SMBRotationScanParser | |
39 except: | |
40 try: | |
41 from scanparsers import SMBRotationScanParser | |
42 globals()['ScanParser'] = SMBRotationScanParser | |
43 except: | |
44 pass | |
34 elif station in ('id3b'): | 45 elif station in ('id3b'): |
35 from msnctools.scanparsers import FMBRotationScanParser | 46 try: |
36 globals()['ScanParser'] = FMBRotationScanParser | 47 from msnctools.scanparsers import FMBRotationScanParser |
48 globals()['ScanParser'] = FMBRotationScanParser | |
49 except: | |
50 try: | |
51 from scanparsers import FMBRotationScanParser | |
52 globals()['ScanParser'] = FMBRotationScanParser | |
53 except: | |
54 pass | |
37 else: | 55 else: |
38 raise RuntimeError(f'Invalid station: {station}') | 56 raise RuntimeError(f'Invalid station: {station}') |
39 | 57 |
40 @cache | 58 @cache |
41 def get_available_scan_numbers(spec_file:str): | 59 def get_available_scan_numbers(spec_file:str): |
43 scan_numbers = list(scans.keys()) | 61 scan_numbers = list(scans.keys()) |
44 for scan_number in scan_numbers.copy(): | 62 for scan_number in scan_numbers.copy(): |
45 try: | 63 try: |
46 parser = ScanParser(spec_file, scan_number) | 64 parser = ScanParser(spec_file, scan_number) |
47 try: | 65 try: |
48 scan_type = parser.get_scan_type() | 66 scan_type = parser.scan_type |
49 except: | 67 except: |
50 scan_type = None | 68 scan_type = None |
51 pass | |
52 except: | 69 except: |
53 scan_numbers.remove(scan_number) | 70 scan_numbers.remove(scan_number) |
54 return(scan_numbers) | 71 return(scan_numbers) |
55 | 72 |
56 @cache | 73 @cache |
432 return(None) | 449 return(None) |
433 | 450 |
434 def get_scanparser(self, scan_number): | 451 def get_scanparser(self, scan_number): |
435 return(get_scanparser(self.spec_file, scan_number)) | 452 return(get_scanparser(self.spec_file, scan_number)) |
436 | 453 |
437 # def get_detector_data(self, detector_prefix, scan_number=None, scan_step_index=None): | |
438 # if scan_number is None: | |
439 # scan_number = self.scan_numbers[0] | |
440 # if scan_step_index is None: | |
441 # scan_info = self.stack_info[self.get_scan_index(scan_number)] | |
442 # scan_step_index = scan_info['starting_image_offset'] | |
443 # parser = self.get_scanparser(scan_number) | |
444 # return(parser.get_detector_data(detector_prefix, scan_step_index)) | |
445 | |
446 def get_detector_data(self, detector_prefix, scan_number=None, scan_step_index=None): | 454 def get_detector_data(self, detector_prefix, scan_number=None, scan_step_index=None): |
447 image_stacks = [] | 455 image_stacks = [] |
448 if scan_number is None: | 456 if scan_number is None: |
449 scan_numbers = self.scan_numbers | 457 scan_numbers = self.scan_numbers |
450 else: | 458 else: |
458 image_stacks.append(parser.get_detector_data(detector_prefix, | 466 image_stacks.append(parser.get_detector_data(detector_prefix, |
459 (image_offset, image_offset+num_image))) | 467 (image_offset, image_offset+num_image))) |
460 else: | 468 else: |
461 image_stacks.append(parser.get_detector_data(detector_prefix, | 469 image_stacks.append(parser.get_detector_data(detector_prefix, |
462 image_offset+scan_step_index)) | 470 image_offset+scan_step_index)) |
463 if len(image_stacks) == 1: | 471 if scan_number is not None and scan_step_index is not None: |
472 # Return a single image for a specific scan_number and scan_step_index request | |
464 return(image_stacks[0]) | 473 return(image_stacks[0]) |
465 else: | 474 else: |
475 # Return a list otherwise | |
466 return(image_stacks) | 476 return(image_stacks) |
477 return(image_stacks) | |
467 | 478 |
468 def scan_numbers_cli(self, attr_desc, **kwargs): | 479 def scan_numbers_cli(self, attr_desc, **kwargs): |
469 available_scan_numbers = self.available_scan_numbers | 480 available_scan_numbers = self.available_scan_numbers |
470 station = kwargs.get('station') | 481 station = kwargs.get('station') |
471 if (station is not None and station in ('id1a3', 'id3a') and | 482 if (station is not None and station in ('id1a3', 'id3a') and |
473 scan_type = kwargs['scan_type'] | 484 scan_type = kwargs['scan_type'] |
474 if scan_type == 'ts1': | 485 if scan_type == 'ts1': |
475 available_scan_numbers = [] | 486 available_scan_numbers = [] |
476 for scan_number in self.available_scan_numbers: | 487 for scan_number in self.available_scan_numbers: |
477 parser = self.get_scanparser(scan_number) | 488 parser = self.get_scanparser(scan_number) |
478 if parser.scan_type == scan_type: | 489 try: |
479 available_scan_numbers.append(scan_number) | 490 if parser.scan_type == scan_type: |
491 available_scan_numbers.append(scan_number) | |
492 except: | |
493 pass | |
480 elif scan_type == 'df1': | 494 elif scan_type == 'df1': |
481 tomo_scan_numbers = kwargs['tomo_scan_numbers'] | 495 tomo_scan_numbers = kwargs['tomo_scan_numbers'] |
482 available_scan_numbers = [] | 496 available_scan_numbers = [] |
483 for scan_number in tomo_scan_numbers: | 497 for scan_number in tomo_scan_numbers: |
484 parser = self.get_scanparser(scan_number-2) | 498 parser = self.get_scanparser(scan_number-2) |
585 image_offset = parser.starting_image_offset | 599 image_offset = parser.starting_image_offset |
586 num_image = parser.get_num_image(detector_prefix.upper()) | 600 num_image = parser.get_num_image(detector_prefix.upper()) |
587 scan_index = self.get_scan_index(scan_number) | 601 scan_index = self.get_scan_index(scan_number) |
588 | 602 |
589 # Select the image set | 603 # Select the image set |
590 last_image_index = image_offset+num_image-1 | 604 last_image_index = image_offset+num_image |
591 print(f'Available good image set index range: [{image_offset}, {last_image_index}]') | 605 print(f'Available good image set index range: [{image_offset}, {last_image_index})') |
592 image_set_approved = False | 606 image_set_approved = False |
593 if scan_index is not None: | 607 if scan_index is not None: |
594 scan_info = stack_info[scan_index] | 608 scan_info = stack_info[scan_index] |
595 print(f'Current starting image offset and number of images: '+ | 609 print(f'Current starting image offset and number of images: '+ |
596 f'{scan_info["starting_image_offset"]} and {scan_info["num_image"]}') | 610 f'{scan_info["starting_image_offset"]} and {scan_info["num_image"]}') |
597 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') | 611 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') |
598 if not image_set_approved: | 612 if not image_set_approved: |
599 print(f'Default starting image offset and number of images: '+ | 613 print(f'Default starting image offset and number of images: '+ |
600 f'{image_offset} and {last_image_index-image_offset}') | 614 f'{image_offset} and {num_image}') |
601 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') | 615 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') |
602 if image_set_approved: | 616 if image_set_approved: |
603 offset = image_offset | 617 offset = image_offset |
604 num = last_image_index-offset | 618 num = last_image_index-offset |
605 while not image_set_approved: | 619 while not image_set_approved: |
606 offset = input_int(f'Enter the starting image offset', ge=image_offset, | 620 offset = input_int(f'Enter the starting image offset', ge=image_offset, |
607 le=last_image_index-1)#, default=image_offset) | 621 lt=last_image_index)#, default=image_offset) |
608 num = input_int(f'Enter the number of images', ge=1, | 622 num = input_int(f'Enter the number of images', ge=1, |
609 le=last_image_index-offset+1)#, default=last_image_index-offset+1) | 623 le=last_image_index-offset)#, default=last_image_index-offset) |
610 print(f'Current starting image offset and number of images: {offset} and {num}') | 624 print(f'Current starting image offset and number of images: {offset} and {num}') |
611 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') | 625 image_set_approved = input_yesno(f'Accept these values (y/n)?', 'y') |
612 if scan_index is not None: | 626 if scan_index is not None: |
613 scan_info['starting_image_offset'] = offset | 627 scan_info['starting_image_offset'] = offset |
614 scan_info['num_image'] = num | 628 scan_info['num_image'] = num |
686 scan_numbers = self.scan_numbers | 700 scan_numbers = self.scan_numbers |
687 else: | 701 else: |
688 scan_numbers = [scan_number] | 702 scan_numbers = [scan_number] |
689 for scan_number in scan_numbers: | 703 for scan_number in scan_numbers: |
690 parser = self.get_scanparser(scan_number) | 704 parser = self.get_scanparser(scan_number) |
691 horizontal_shifts.append(parser.get_horizontal_shift()) | 705 horizontal_shifts.append(parser.horizontal_shift) |
692 if len(horizontal_shifts) == 1: | 706 if len(horizontal_shifts) == 1: |
693 return(horizontal_shifts[0]) | 707 return(horizontal_shifts[0]) |
694 else: | 708 else: |
695 return(horizontal_shifts) | 709 return(horizontal_shifts) |
696 | 710 |
700 scan_numbers = self.scan_numbers | 714 scan_numbers = self.scan_numbers |
701 else: | 715 else: |
702 scan_numbers = [scan_number] | 716 scan_numbers = [scan_number] |
703 for scan_number in scan_numbers: | 717 for scan_number in scan_numbers: |
704 parser = self.get_scanparser(scan_number) | 718 parser = self.get_scanparser(scan_number) |
705 vertical_shifts.append(parser.get_vertical_shift()) | 719 vertical_shifts.append(parser.vertical_shift) |
706 if len(vertical_shifts) == 1: | 720 if len(vertical_shifts) == 1: |
707 return(vertical_shifts[0]) | 721 return(vertical_shifts[0]) |
708 else: | 722 else: |
709 return(vertical_shifts) | 723 return(vertical_shifts) |
710 | 724 |
726 f'\n\tScan {scan_number}: {theta_vals}'+ | 740 f'\n\tScan {scan_number}: {theta_vals}'+ |
727 f'\n\tScan {self.scan_numbers[0]}: {parser.theta_vals}') | 741 f'\n\tScan {self.scan_numbers[0]}: {parser.theta_vals}') |
728 return | 742 return |
729 | 743 |
730 # Select the theta range for the tomo reconstruction from the first scan | 744 # Select the theta range for the tomo reconstruction from the first scan |
745 theta_range_approved = False | |
731 thetas = np.linspace(spec_theta_start, spec_theta_end, spec_num_theta) | 746 thetas = np.linspace(spec_theta_start, spec_theta_end, spec_num_theta) |
732 delta_theta = thetas[1]-thetas[0] | 747 delta_theta = thetas[1]-thetas[0] |
733 theta_range_approved = False | 748 print(f'Theta range obtained from SPEC data: [{spec_theta_start}, {spec_theta_end}]') |
734 print(f'Theta range obtained from SPEC data: [{spec_theta_start}, {spec_theta_end})') | |
735 print(f'Theta step size = {delta_theta}') | 749 print(f'Theta step size = {delta_theta}') |
736 print(f'Number of theta values: {spec_num_theta}') | 750 print(f'Number of theta values: {spec_num_theta}') |
737 exit('Done') | |
738 default_start = None | 751 default_start = None |
739 default_end = None | 752 default_end = None |
740 if station in ('id1a3', 'id3a'): | 753 if station in ('id1a3', 'id3a'): |
741 theta_range_approved = input_yesno(f'Accept this theta range (y/n)?', 'y') | 754 theta_range_approved = input_yesno(f'Accept this theta range (y/n)?', 'y') |
742 if theta_range_approved: | 755 if theta_range_approved: |
743 theta_start = spec_theta_start | 756 self.theta_range = {'start': float(spec_theta_start), 'end': float(spec_theta_end), |
744 theta_end = spec_theta_end | 757 'num': int(spec_num_theta), 'start_index': 0} |
745 num_theta = spec_num_theta | 758 return |
746 theta_index_start = 0 | |
747 elif station in ('id3b'): | 759 elif station in ('id3b'): |
748 if spec_theta_start <= 0.0 and spec_theta_end >= 180.0: | 760 if spec_theta_start <= 0.0 and spec_theta_end >= 180.0: |
749 default_start = 0 | 761 default_start = 0 |
750 default_end = 180 | 762 default_end = 180 |
751 elif spec_theta_end-spec_theta_start == 180: | 763 elif spec_theta_end-spec_theta_start == 180: |
763 num_theta = theta_index_end-theta_index_start | 775 num_theta = theta_index_end-theta_index_start |
764 print(f'Selected theta range: [{theta_start}, {theta_start+delta_theta}, ..., '+ | 776 print(f'Selected theta range: [{theta_start}, {theta_start+delta_theta}, ..., '+ |
765 f'{theta_end})') | 777 f'{theta_end})') |
766 print(f'Number of theta values: {num_theta}') | 778 print(f'Number of theta values: {num_theta}') |
767 theta_range_approved = input_yesno(f'Accept this theta range (y/n)?', 'y') | 779 theta_range_approved = input_yesno(f'Accept this theta range (y/n)?', 'y') |
768 self.thetas = np.linspace(theta_start, theta_end, num_theta) | 780 self.theta_range = {'start': float(theta_start), 'end': float(theta_end), |
781 'num': int(num_theta), 'start_index': int(theta_index_start)} | |
769 | 782 |
770 def image_range_cli(self, attr_desc, detector_prefix): | 783 def image_range_cli(self, attr_desc, detector_prefix): |
771 stack_info = self.stack_info | 784 stack_info = self.stack_info |
772 for scan_number in self.scan_numbers: | 785 for scan_number in self.scan_numbers: |
773 # Parse the available image range | 786 # Parse the available image range |
803 attr_desc = '' | 816 attr_desc = '' |
804 cycle = cli_kwargs.get('cycle') | 817 cycle = cli_kwargs.get('cycle') |
805 btr = cli_kwargs.get('btr') | 818 btr = cli_kwargs.get('btr') |
806 station = cli_kwargs.get('station') | 819 station = cli_kwargs.get('station') |
807 detector = cli_kwargs.get('detector') | 820 detector = cli_kwargs.get('detector') |
821 sample_name = cli_kwargs.get('sample_name') | |
808 print(f'\n -- Configure the location of the {attr_desc}scan data -- ') | 822 print(f'\n -- Configure the location of the {attr_desc}scan data -- ') |
809 if station in ('id1a3', 'id3a'): | 823 if station in ('id1a3', 'id3a'): |
810 basedir = f'/nfs/chess/{station}/{cycle}/{btr}' | 824 basedir = f'/nfs/chess/{station}/{cycle}/{btr}' |
811 runs = [d for d in os.listdir(basedir) if os.path.isdir(os.path.join(basedir, d))] | 825 runs = [d for d in os.listdir(basedir) if os.path.isdir(os.path.join(basedir, d))] |
812 #RV index = 15-1 | 826 #RV index = 15-1 |
813 #RV index = 7-1 | 827 #RV index = 7-1 |
814 index = input_menu(runs, header='Choose a sample directory') | 828 if sample_name is not None and sample_name in runs: |
829 index = runs.index(sample_name) | |
830 else: | |
831 index = input_menu(runs, header='Choose a sample directory') | |
815 self.spec_file = f'{basedir}/{runs[index]}/spec.log' | 832 self.spec_file = f'{basedir}/{runs[index]}/spec.log' |
816 self.scan_numbers_cli(attr_desc, station=station, scan_type='ts1') | 833 self.scan_numbers_cli(attr_desc, station=station, scan_type='ts1') |
817 else: | 834 else: |
818 self.set_single_attr_cli('spec_file', attr_desc+'SPEC file path') | 835 self.set_single_attr_cli('spec_file', attr_desc+'SPEC file path') |
819 self.scan_numbers_cli(attr_desc) | 836 self.scan_numbers_cli(attr_desc) |
843 config['z_translation'] = nxsample.z_translation.nxdata | 860 config['z_translation'] = nxsample.z_translation.nxdata |
844 return(cls(**config)) | 861 return(cls(**config)) |
845 | 862 |
846 def cli(self): | 863 def cli(self): |
847 print('\n -- Configure the sample metadata -- ') | 864 print('\n -- Configure the sample metadata -- ') |
848 #RV self.name = 'test' | |
849 #RV self.name = 'sobhani-3249-A' | 865 #RV self.name = 'sobhani-3249-A' |
866 #RV self.name = 'tenstom_1304r-1' | |
850 self.set_single_attr_cli('name', 'the sample name') | 867 self.set_single_attr_cli('name', 'the sample name') |
851 #RV self.description = 'test sample' | 868 #RV self.description = 'test sample' |
852 self.set_single_attr_cli('description', 'a description of the sample (optional)') | 869 self.set_single_attr_cli('description', 'a description of the sample (optional)') |
853 | 870 |
854 | 871 |
915 use_detector_config = False | 932 use_detector_config = False |
916 if hasattr(self.detector, 'prefix') and len(self.detector.prefix): | 933 if hasattr(self.detector, 'prefix') and len(self.detector.prefix): |
917 use_detector_config = input_yesno(f'Current detector settings:\n{self.detector}\n'+ | 934 use_detector_config = input_yesno(f'Current detector settings:\n{self.detector}\n'+ |
918 f'Keep these settings? (y/n)') | 935 f'Keep these settings? (y/n)') |
919 if not use_detector_config: | 936 if not use_detector_config: |
920 #RV have_detector_config = True | 937 menu_options = ['not listed', 'andor2', 'manta', 'retiga'] |
921 have_detector_config = input_yesno(f'Is a detector configuration file available? (y/n)') | 938 input_mode = input_menu(menu_options, header='Choose one of the following detector '+ |
922 if have_detector_config: | 939 'configuration options') |
923 #RV detector_config_file = 'retiga.yaml' | 940 if input_mode: |
924 #RV detector_config_file = 'andor2.yaml' | 941 detector_config_file = f'{menu_options[input_mode]}.yaml' |
925 detector_config_file = input(f'Enter detector configuration file name: ') | |
926 have_detector_config = self.detector.construct_from_yaml(detector_config_file) | 942 have_detector_config = self.detector.construct_from_yaml(detector_config_file) |
943 else: | |
944 have_detector_config = False | |
927 if not have_detector_config: | 945 if not have_detector_config: |
928 self.set_single_attr_cli('detector', 'detector') | 946 self.set_single_attr_cli('detector', 'detector') |
929 self.set_single_attr_cli('tomo_fields', 'Tomo field', chain_attr_desc=True, | 947 self.set_single_attr_cli('tomo_fields', 'Tomo field', chain_attr_desc=True, |
930 cycle=self.cycle, btr=self.btr, station=self.station, detector=self.detector) | 948 cycle=self.cycle, btr=self.btr, station=self.station, detector=self.detector, |
949 sample_name=self.sample.name) | |
931 if self.station in ('id1a3', 'id3a'): | 950 if self.station in ('id1a3', 'id3a'): |
932 have_dark_field = True | 951 have_dark_field = True |
933 tomo_spec_file = self.tomo_fields.spec_file | 952 tomo_spec_file = self.tomo_fields.spec_file |
934 else: | 953 else: |
935 have_dark_field = input_yesno(f'Are Dark field images available? (y/n)') | 954 have_dark_field = input_yesno(f'Are Dark field images available? (y/n)') |
999 thetas = None | 1018 thetas = None |
1000 # Add the scans in a single spec file | 1019 # Add the scans in a single spec file |
1001 nxspec_scans[field_name] = field.construct_nxcollection(image_key, thetas, | 1020 nxspec_scans[field_name] = field.construct_nxcollection(image_key, thetas, |
1002 self.detector) | 1021 self.detector) |
1003 if include_raw_data: | 1022 if include_raw_data: |
1004 image_stacks.append(field.get_detector_data(self.detector.prefix)) | 1023 image_stacks += field.get_detector_data(self.detector.prefix) |
1005 for scan_number in field.scan_numbers: | 1024 for scan_number in field.scan_numbers: |
1006 parser = field.get_scanparser(scan_number) | 1025 parser = field.get_scanparser(scan_number) |
1007 scan_info = field.stack_info[field.get_scan_index(scan_number)] | 1026 scan_info = field.stack_info[field.get_scan_index(scan_number)] |
1008 num_image = scan_info['num_image'] | 1027 num_image = scan_info['num_image'] |
1009 image_keys += num_image*[image_key] | 1028 image_keys += num_image*[image_key] |