Skip to content
Snippets Groups Projects
dnsdata.py 8.77 KiB
Newer Older
Marina Ganeva's avatar
Marina Ganeva committed
import sys, re
import datetime

class DNSdata:
    """
    class which describes the DNS data structure
Marina Ganeva's avatar
Marina Ganeva committed
    will be used for data read-in and write-out routines
    """
    def __init__(self):
        self.title = ""
        self.experiment_number = ""
        self.run_number = ""
        self.start_time = ""
        self.end_time = ""
        self.duration = None
        self.deterota = 0
        self.wavelength = None          # Angstrom
        self.incident_energy = None     # meV
        self.ndet = 24
        self.sample_name = ""
        self.userid = ""
        self.user_name = ""
        self.sample_description = ""
        self.coil_status = ""
        self.befilter_status = ""
        self.notes = ""
        self.monochromator_angle = None         # degree
        self.monochromator_position = None
        self.huber = None
        self.cradle_lower = None
        self.cradle_upper = None
        self.slit_i_upper_blade_position = None
        self.slit_i_lower_blade_position = None
        self.slit_i_left_blade_position = None
        self.slit_i_right_blade_position = None
        self.slit_f_upper_blade_position = None
        self.slit_f_lower_blade_position = None
        self.detector_position_vertical = None
        self.polarizer_translation = None
        self.polarizer_rotation = None
        self.flipper_precession_current = None
        self.flipper_z_compensation_current = None
        self.a_coil_current = None
        self.b_coil_current = None
        self.c_coil_current = None
        self.z_coil_current = None
        self.t1 = None       # T1
        self.t2 = None       # T2
        self.tsp = None      # T_setpoint
        self.tof_channel_number = None
        self.tof_channel_width = None
        self.tof_delay_time = None
        self.tof_elastic_channel = None
        self.chopper_rotation_speed = None
        self.chopper_slits = None
        self.monitor_counts = None


    def read_legacy(self, filename):
        """
        reads the DNS legacy ascii file into the DNS data object
        """
        with open(filename, 'r') as fhandler:
            # read file content and split it into blocks
Marina Ganeva's avatar
Marina Ganeva committed
            splitsymbol = \
                    '#--------------------------------------------------------------------------'
            unparsed = fhandler.read()
            blocks = unparsed.split(splitsymbol)

Marina Ganeva's avatar
Marina Ganeva committed
            # parse each block
            # parse block 0 (header)
            res = parse_header(blocks[0])
Marina Ganeva's avatar
Marina Ganeva committed
            #if not res: raise Exception "wrong file format" else
            try:
                self.run_number = res['file']
                self.experiment_number = res['exp']
                self.sample_name = res['sample']
                self.userid = res['userid']
            except:
                raise ValueError("The file %s does not contain valid DNS data format." % filename)
            # parse block 1 (general information)
            b1splitted = map(str.strip, blocks[1].split('#'))
Marina Ganeva's avatar
Marina Ganeva committed
            b1rest = [el for el in b1splitted]
            r_user = re.compile("User:\s*(?P<name>.*?$)")
            r_sample = re.compile("Sample:\s*(?P<sample>.*?$)")
            r_coil = re.compile("^(?P<coil>.*?)\s*xyz-coil.*")
            r_filter = re.compile("^(?P<filter>.*?)\s*Be-filter.*")
            for line in b1splitted:
Marina Ganeva's avatar
Marina Ganeva committed
                res = r_user.match(line)
Marina Ganeva's avatar
Marina Ganeva committed
                    self.user_name = res.group("name")
                    b1rest.remove(line)
Marina Ganeva's avatar
Marina Ganeva committed
                res = r_sample.match(line)
Marina Ganeva's avatar
Marina Ganeva committed
                    self.sample_description = res.group("sample")
                    b1rest.remove(line)
Marina Ganeva's avatar
Marina Ganeva committed
                res = r_coil.match(line)
Marina Ganeva's avatar
Marina Ganeva committed
                    self.coil_status = res.group("coil")
                    b1rest.remove(line)
Marina Ganeva's avatar
Marina Ganeva committed
                res = r_filter.match(line)
Marina Ganeva's avatar
Marina Ganeva committed
                    self.befilter_status = res.group("filter")
                    b1rest.remove(line)
                # the rest unparsed lines go to notes for the moment
Marina Ganeva's avatar
Marina Ganeva committed
                # [TODO]: parse more information about the sample
                self.notes = ' '.join(b1rest)

            # parse block 2 (wavelength and mochromator angle)
            # for the moment, only theta and lambda are needed
            b2splitted = map(str.strip, blocks[2].split('#'))
            # assume that theta and lambda are always on the fixed positions
            # assume theta is give in degree, lambda in nm
            line = b2splitted[2].split()
Marina Ganeva's avatar
Marina Ganeva committed
            self.monochromator_angle = float(line[2])
            self.wavelength = float(line[3])*10.0
            self.incident_energy = float(line[4])

            # parse block 3 (motors position)
            b3splitted = map(str.strip, blocks[3].split('#'))
            self.monochromator_position = float(b3splitted[2].split()[1])
            # DeteRota, angle of rotation of detector bank
            self.deterota = float(b3splitted[3].split()[1])
            # Huber default units degree
            self.huber = float(b3splitted[5].split()[1])
            self.cradle_lower = float(b3splitted[6].split()[1])
            self.cradle_upper = float(b3splitted[7].split()[1])
            # Slit_i, convert mm to meter
Marina Ganeva's avatar
Marina Ganeva committed
            self.slit_i_upper_blade_position = \
                    0.001*float(b3splitted[9].split()[2])
            self.slit_i_lower_blade_position = \
                    0.001*float(b3splitted[10].split()[1])
            self.slit_i_left_blade_position = \
                    0.001*float(b3splitted[11].split()[2])
            self.slit_i_right_blade_position = \
                    0.001*float(b3splitted[12].split()[1])
Marina Ganeva's avatar
Marina Ganeva committed
            self.slit_f_upper_blade_position = \
                    0.001*float(b3splitted[14].split()[1])
            self.slit_f_lower_blade_position = \
                    0.001*float(b3splitted[15].split()[1])
            # Detector_position vertical
Marina Ganeva's avatar
Marina Ganeva committed
            self.detector_position_vertical = \
                    0.001*float(b3splitted[16].split()[1])
Marina Ganeva's avatar
Marina Ganeva committed
            self.polarizer_translation = \
                    0.001*float(b3splitted[19].split()[1])
            self.polarizer_rotation = float(b3splitted[20].split()[1])

            # parse block 4 (B-fields), only currents in A are taken
            b4splitted = map(str.strip, blocks[4].split('#'))
            self.flipper_precession_current = float(b4splitted[2].split()[1])
            self.flipper_z_compensation_current = float(b4splitted[3].split()[1])
            self.a_coil_current = float(b4splitted[4].split()[1])
            self.b_coil_current = float(b4splitted[5].split()[1])
            self.c_coil_current = float(b4splitted[6].split()[1])
            self.z_coil_current = float(b4splitted[7].split()[1])


            # parse block 5 (Temperatures)
            # assume: T1=cold_head_temperature, T2=sample_temperature
            b5splitted = map(str.strip, blocks[5].split('#'))
Marina Ganeva's avatar
Marina Ganeva committed
            self.t1 = float(b5splitted[2].split()[1])
            self.t2 = float(b5splitted[3].split()[1])
            self.tsp = float(b5splitted[4].split()[1])

            # parse block 6 (TOF parameters)
            b6splitted = map(str.strip, blocks[6].split('#'))
            self.tof_channel_number = int(b6splitted[2].split()[2])
            self.tof_channel_width = float(b6splitted[3].split()[3])
            self.tof_delay_time = float(b6splitted[4].split()[2])
            self.tof_elastic_channel = int(b6splitted[6].split()[3])
            # chopper rotation speed
            self.chopper_rotation_speed = float(b6splitted[7].split()[2])
            # chopper number of slits
            self.chopper_slits = int(b6splitted[5].split()[2])

            # parse block 7 (Time and monitor)
            # assume everything to be at the fixed positions
            b7splitted = map(str.strip, blocks[7].split('#'))
            # duration
            line = b7splitted[2].split()
            self.duration = float(line[1]) # assume seconds [TODO]: check
            # monitor data
            line = b7splitted[3].split()
            self.monitor_counts = int(line[1])
            # start_time and end_time
            outfmt = "%Y-%m-%dT%H:%M:%S"
            sinfmt = "start   at %a %b  %d %H:%M:%S %Y"
            einfmt = "stopped at %a %b  %d %H:%M:%S %Y"
            self.start_time = datetime.datetime.strptime(b7splitted[5], sinfmt).strftime(outfmt)
            self.end_time = datetime.datetime.strptime(b7splitted[6], einfmt).strftime(outfmt)

def parse_header(h):
    """
    parses the header string and returns the parsed dictionary
    """
    d = {}
Marina Ganeva's avatar
Marina Ganeva committed
    regexp = re.compile("(\w+)=(\w+)")
    result = regexp.finditer(h)
    for r in result:
        d[r.groups()[0]] = r.groups()[1]
    return d
Marina Ganeva's avatar
Marina Ganeva committed
if __name__ == '__main__':
    fname = sys.argv[1]
Marina Ganeva's avatar
Marina Ganeva committed
    dns_data = DNSdata()
    dns_data.read_legacy(fname)
    print dns_data.__dict__