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]