Example #1
0
 def __init__(self,
              name,
              idgap,
              dcmenergy,
              lut,
              gap_offset=None,
              feedbackPVs=None):
     """
     Constructor - Only succeeds if it finds the lookup table,
     otherwise raises exception.
     """
     self.lut = readLookupTable(
         LocalProperties.get("gda.config") + "/lookupTables/" + lut)
     self.gap = idgap
     self.mono_energy = dcmenergy
     self.lambdau = 27  # undulator period
     self.scannables = ScannableGroup(name, [dcmenergy, idgap])
     self.detune = gap_offset
     self.feedbackPVs = feedbackPVs
     self._busy = 0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.inputNames = [name]
     self.order = 3
     self.SCANNING = False
     self.logger = logger.getChild(self.__class__.__name__)
Example #2
0
def pathscan(*args):  #@UndefinedVariable
    ''' 
    Scan a group of scannables following the specified path and 
    collect data at each point from scannables args
    '''
    starttime = time.ctime()
    if PRINTTIME: print "=== Scan started: " + starttime
    newargs = []
    i = 0
    while i < len(args):
        arg = args[i]
        if type(arg) == TupleType:
            if allElementsAreScannable(arg):
                scannableGroup = ScannableGroup("pathgroup")
                for each in arg:
                    scannableGroup.addGroupMember(each)
                newargs.append(scannableGroup)
            elif allElementsAreListOfNumber(arg):
                newargs.append(arg)
            else:
                raise TypeError, "Only tuple of scannables and tuple of list of numbers are supported."
        else:
            newargs.append(arg)
        i = i + 1
    scan(newargs)
    if PRINTTIME:
        print("=== Scan ended: " + time.ctime() +
              ". Elapsed time: %.0f seconds" % (time.time() - starttime))
Example #3
0
 def __init__(self, name, idctrl, pgmenergy, lut="JIDEnergy2GapCalibrations.csv", energyConstant=False, polarisationConstant=False, gap_offset=None, feedbackPV=None):
     '''Constructor - Only succeed if it find the lookupTable table, otherwise raise exception.'''
     self.lut,self.header = load_lookup_table(LocalProperties.get("gda.config")+"/lookupTables/"+lut)
     self.idscannable = idctrl
     self.mono_energy = pgmenergy
     self.scannables = ScannableGroup(name, [pgmenergy, idctrl])
     self.detune = gap_offset
     self.feedbackPV = feedbackPV
     self._busy = 0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.setInputNames([name])
     self.setExtraNames([])
     self.polarisation = 'LH'
     self.gap = 50
     self.phase = 0
     self.energyConstant = energyConstant
     self.polarisationConstant = polarisationConstant
     self.SCANNING = False
     if self.energyConstant and self.polarisationConstant:
         raise RuntimeError("Cannot create an instance with both energy and polarisation being constant.")
     self.isConfigured = False
     self.inputSignSwitched = False
     self.beamlinename = LocalProperties.get(LocalProperties.GDA_BEAMLINE_NAME)
     self.logger = logger.getChild(self.__class__.__name__)
Example #4
0
    def create_group_and_tuples(self):
        """Function to create a scannable group from scannables passed in"""
        # If scan_group has already been defined in the namespace, remove scannables
        global scan_group
        if "scan_group" not in globals():
            scan_group = ScannableGroup()
            self.insert_into_namespace("scan_group", scan_group)
        else:
            group_member_names = scan_group.getGroupMemberNames()
            for name in group_member_names:
                scan_group.removeGroupMemberByScannable(scan_group.getGroupMember(name))

        # Add the primary scannable to the group
        self.add_scannable_to_group(self.scannable_func_list[0])

        # Add the other list members to the group and append their function values to tuple list
        for scannable, func, scannable_start_val in self.scannable_func_list[1:]:
            self.add_scannable_to_group(scannable)
            self.append_function_values(func, scannable_start_val)

        # Configure the scan_group
        scan_group.setName("scan_group")
        scan_group.configure()
        tuples = tuple(self.tuple_list)
        self.insert_into_namespace("scan_points", tuples)
        return tuples
Example #5
0
 def __init__(self, name, idctrl, pgmenergy, lut="JIDEnergy2GapCalibrations.txt", energyConstant=False, polarisationConstant=False):
     '''Constructor - Only succeed if it find the lookupTable table, otherwise raise exception.'''
     self.lut=loadLookupTable(LocalProperties.get("gda.config")+"/lookupTables/"+lut)
     self.idscannable=idctrl
     self.pgmenergy=pgmenergy
     self.scannables=ScannableGroup(name, [pgmenergy, idctrl])
     self._busy=0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.setInputNames([name])
     self.setExtraNames([])
     self.order=1
     self.polarisation=0.0
     self.gap=50
     self.polarisationMode='UNKNOWN'
     self.phase=0
     self.energyConstant=energyConstant
     self.polarisationConstant=polarisationConstant
     self.SCANNING=False
     if self.energyConstant and self.polarisationConstant:
         raise Exception("Cannot create an instance with both energy and polarisation being constant.")
     self.isConfigured=False
     self.inputSignSwitched=False
     self.beamlinename=LocalProperties.get(LocalProperties.GDA_BEAMLINE_NAME)
     self.logger = logger.getChild(self.__class__.__name__)
Example #6
0
def analyserpathscan(*args):
    '''
    perform single/multiple regions analyser data collection at each point on the specified path,
    and produce a single scan file recording all scannables' poistions and metadata, along with
    analyser scan data under region's name as NXdetector node.
    
    implementation details:
    This function pre-process sequence file to set up analyser 'ew4000' ready for data collection.
    It creates scannable group to support point-to-point concurrent scan.
    '''
    starttime = time.ctime()
    if PRINTTIME: print "=== Scan started: " + starttime
    newargs = []
    i = 0
    while i < len(args):
        arg = args[i]
        if type(arg) == TupleType:
            if allElementsAreScannable(arg):
                scannableGroup = ScannableGroup("pathgroup")
                for each in arg:
                    scannableGroup.addGroupMember(each)
                newargs.append(scannableGroup)
            elif allElementsAreListOfNumber(arg):
                newargs.append(arg)
            else:
                raise TypeError, "Only tuple of scannables and tuple of list of numbers are supported."
        else:
            newargs.append(arg)
        i = i + 1
        if isinstance(arg, EW4000):
            controller = Finder.find("SequenceFileObserver")
            xmldir = InterfaceProvider.getPathConstructor(
            ).createFromDefaultProperty() + "xml" + os.sep
            filename = xmldir + args[i]
            if (OsUtil.isWindows()):
                FilenameUtil.setPrefix("D:")
                filename = FilenameUtil.convertSeparator(filename)
            controller.update(controller, SequenceFileChangeEvent(filename))
            sleep(2.0)
            jythonServerStatus = InterfaceProvider.getJythonServerStatusProvider(
            ).getJythonServerStatus()
            while (jythonServerStatus.isScriptOrScanPaused()):
                sleep(1.0)
            arg.setSequenceFilename(filename)
            sequence = arg.loadSequenceData(filename)
            if isinstance(arg.getCollectionStrategy(),
                          EW4000CollectionStrategy):
                arg.getCollectionStrategy().setSequence(sequence)
            i = i + 1
    scan(newargs)
    if PRINTTIME:
        print("=== Scan ended: " + time.ctime() +
              ". Elapsed time: %.0f seconds" % (time.time() - starttime))
Example #7
0
 def __init__(self, name, detectorToUse=edxd):#@UndefinedVariable
     self.name=name
     self.sg = ScannableGroup()
     self.pointid=[]
     self.path=[]
     self.startline=1
     self.lastline=10
     self.scannablelist=[]
     self.scannableunitlist=[]
     self.detector=detectorToUse
     self.detectorunit="s"
     self.exposuretime=[]
 def setup_method(self):
     self.a = MockMotor()
     self.b = MockMotor()
     self.c = MockMotor()
     self.d = MockMotor()
     self.e = MockMotor()
     self.f = MockMotor()
     self.grp = ScannableGroup(
         'grp', [self.a, self.b, self.c, self.d, self.e, self.f])
     self.grp.configure()
     self.sg = DiffractometerScannableGroup('sixc', MockDiffcalc(6),
                                            self.grp)
    def setup_method(self):
        class BadMockAngleCalculator:
            def angles_to_hkl(self, pos):
                raise Exception("Problem")

        dummy = createDummyAxes(
            ['alpha', 'delta', 'gamma', 'omega', 'chi', 'phi'])
        self.group = ScannableGroup('grp', dummy)
        self.group.configure()
        self.sg = DiffractometerScannableGroup('sixc',
                                               BadMockAngleCalculator(),
                                               self.group)
class TestDiffractometerScannableGroup(unittest.TestCase):

    def setUp(self):
        self.a = MockMotor()
        self.b = MockMotor()
        self.c = MockMotor()
        self.d = MockMotor()
        self.e = MockMotor()
        self.f = MockMotor()
        self.grp = ScannableGroup(
            'grp', [self.a, self.b, self.c, self.d, self.e, self.f])
        self.grp.configure()
        self.sg = DiffractometerScannableGroup(
            'sixc', MockDiffcalc(6), self.grp)

    def testInit(self):
        self.assertEqual(list(self.sg.getPosition()), [0., 0., 0., 0., 0., 0.])

    def testAsynchronousMoveTo(self):
        self.sg.asynchronousMoveTo([1, 2.0, 3, 4, 5, 6])
        self.assertEqual(list(self.sg.getPosition()), [1., 2., 3., 4., 5., 6.])

    def testAsynchronousMoveToWithNones(self):
        self.sg.asynchronousMoveTo([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
        self.sg.asynchronousMoveTo([None, None, 3.2, None, 5.2, None])
        self.assertEqual(list(self.sg.getPosition()),
                         [1., 2., 3.2, 4., 5.2, 6.])

    def testGetPosition(self):
        #implicitely tested above
        pass

    def testWhereMoveTo(self):
        # just check for exceptions
        print self.sg.simulateMoveTo((1.23, 2, 3, 4, 5, 6))

    def testIsBusy(self):
        self.assertEqual(self.sg.isBusy(), False)
        self.sg.asynchronousMoveTo([1.0, 2.0, 3.0, 4, 5, 6])
        self.assertEqual(self.sg.isBusy(), True)
        self.b.makeNotBusy()
        self.assertEqual(self.sg.isBusy(), True)
        self.a.makeNotBusy()
        self.c.makeNotBusy()
        self.d.makeNotBusy()
        self.e.makeNotBusy()
        self.f.makeNotBusy()
        self.assertEqual(self.sg.isBusy(), False)

    def testRepr(self):
        print self.sg.__repr__()
class TestDiffractometerScannableGroup(object):
    def setup_method(self):
        self.a = MockMotor()
        self.b = MockMotor()
        self.c = MockMotor()
        self.d = MockMotor()
        self.e = MockMotor()
        self.f = MockMotor()
        self.grp = ScannableGroup(
            'grp', [self.a, self.b, self.c, self.d, self.e, self.f])
        self.grp.configure()
        self.sg = DiffractometerScannableGroup('sixc', MockDiffcalc(6),
                                               self.grp)

    def testInit(self):
        assert list(self.sg.getPosition()) == [0., 0., 0., 0., 0., 0.]

    def testAsynchronousMoveTo(self):
        self.sg.asynchronousMoveTo([1, 2.0, 3, 4, 5, 6])
        assert list(self.sg.getPosition()) == [1., 2., 3., 4., 5., 6.]

    def testAsynchronousMoveToWithNones(self):
        self.sg.asynchronousMoveTo([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
        self.sg.asynchronousMoveTo([None, None, 3.2, None, 5.2, None])
        assert list(self.sg.getPosition()) == [1., 2., 3.2, 4., 5.2, 6.]

    def testGetPosition(self):
        #implicitely tested above
        pass

    def testWhereMoveTo(self):
        # just check for exceptions
        print self.sg.simulateMoveTo((1.23, 2, 3, 4, 5, 6))

    def testIsBusy(self):
        assert not self.sg.isBusy()
        self.sg.asynchronousMoveTo([1.0, 2.0, 3.0, 4, 5, 6])
        assert self.sg.isBusy()
        self.b.makeNotBusy()
        assert self.sg.isBusy()
        self.a.makeNotBusy()
        self.c.makeNotBusy()
        self.d.makeNotBusy()
        self.e.makeNotBusy()
        self.f.makeNotBusy()
        assert not self.sg.isBusy()

    def testRepr(self):
        print self.sg.__repr__()
Example #12
0
class TestDiffractometerScannableGroupWithFailingAngleCalculator(object):

    def setup_method(self):
        class BadMockAngleCalculator:
            def angles_to_hkl(self, pos):
                raise Exception("Problem")
        dummy = createDummyAxes(['alpha', 'delta', 'gamma', 'omega', 'chi',
                                 'phi'])
        self.group = ScannableGroup('grp', dummy)
        self.group.configure()
        self.sg = DiffractometerScannableGroup(
            'sixc', BadMockAngleCalculator(), self.group)

    def testGetPosition(self):
        self.sg.getPosition()

    def testSimulateMoveTo(self):
        assert (self.sg.simulateMoveTo([1., 2., 3., 4., 5., 6.])
                == "Error: Problem")
Example #13
0
 def setup_method(self):
     class BadMockAngleCalculator:
         def angles_to_hkl(self, pos):
             raise Exception("Problem")
     dummy = createDummyAxes(['alpha', 'delta', 'gamma', 'omega', 'chi',
                              'phi'])
     self.group = ScannableGroup('grp', dummy)
     self.group.configure()
     self.sg = DiffractometerScannableGroup(
         'sixc', BadMockAngleCalculator(), self.group)
class TestDiffractometerScannableGroupWithFailingAngleCalculator(object):
    def setup_method(self):
        class BadMockAngleCalculator:
            def angles_to_hkl(self, pos):
                raise Exception("Problem")

        dummy = createDummyAxes(
            ['alpha', 'delta', 'gamma', 'omega', 'chi', 'phi'])
        self.group = ScannableGroup('grp', dummy)
        self.group.configure()
        self.sg = DiffractometerScannableGroup('sixc',
                                               BadMockAngleCalculator(),
                                               self.group)

    def testGetPosition(self):
        self.sg.getPosition()

    def testSimulateMoveTo(self):
        assert (self.sg.simulateMoveTo([1., 2., 3., 4., 5.,
                                        6.]) == "Error: Problem")
Example #15
0
 def __init__(self, name, lut):
     """
     Constructor - Only succeeds if it finds the lookup table,
     otherwise raises exception.
     """
     self.lut = readLookupTable(
         LocalProperties.get("gda.config") + "/lookupTables/" + lut)
     self.gap = "igap"
     self.dcm = "dcmenergy"
     self.lambdau = 27  # undulator period
     self.scannableNames = ["dcmenergy", "igap"]
     self.scannables = ScannableGroup(
         name, [Finder.find(x) for x in self.scannableNames])
     self._busy = 0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.inputNames = [name]
     self.order = 3
     self.logger = logger.getChild(self.__class__.__name__)
    def setup_method(self):
        class BadMockAngleCalculator:
            def angles_to_hkl(self, pos):
                raise Exception("Problem in angles_to_hkl")

        dummy = createDummyAxes(['alpha', 'delta', 'gamma', 'omega', 'chi',
                                 'phi'])
        self.group = ScannableGroup('grp', dummy)
        self.SixCircleGammaOnArmGeometry = DiffractometerScannableGroup(
            'SixCircleGammaOnArmGeometry', MockDiffcalc(6), self.group)
        self.hkl = Hkl('hkl', self.SixCircleGammaOnArmGeometry,
                       BadMockAngleCalculator())
Example #17
0
 def setup_method(self):
     self.a = MockMotor()
     self.b = MockMotor()
     self.c = MockMotor()
     self.d = MockMotor()
     self.e = MockMotor()
     self.f = MockMotor()
     self.grp = ScannableGroup(
         'grp', [self.a, self.b, self.c, self.d, self.e, self.f])
     self.grp.configure()
     self.sg = DiffractometerScannableGroup(
         'sixc', MockDiffcalc(6), self.grp)
Example #18
0
 def __init__(self, name, idgap, pgmenergy, lut, gap_offset=None, feedbackPV=None):
     """
     Constructor -
     Only succeeds if it finds the lookup table, otherwise raises exception.
     """
     self.lut = readLookupTable(LocalProperties.get("gda.config") + "/lookupTables/" + lut)
     self.gap = idgap
     self.mono_energy = pgmenergy
     self.scannables = ScannableGroup(name, [pgmenergy, idgap])
     self.detune=gap_offset
     self.feedbackPV=feedbackPV
     self._busy = 0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.inputNames = [name]
     self.SCANNING=False
     self.order = 1
     self.polarisation = 'LH'
     self.jidphase = Finder.find("jidphase")
     self.logger = logger.getChild(self.__class__.__name__)
Example #19
0
def pathscan(scannables, path, detector, exposure, *args):  #@UndefinedVariable
    ''' Scan a group of scannables following the specified path and collect data at each point from specified detector and time'''
    sg = ScannableGroup()
    for each in scannables:
        sg.addGroupMember(each)
    sg.setName("pathgroup")
    scan([sg, path, detector, exposure] + list(args))
Example #20
0
 def __init__(self, name, gap="jgap", dcm="pgmenergy", undulatorperiod=27, lut="JIDCalibrationTable.txt"):
     '''Constructor - Only succeed if it find the lookup table, otherwise raise exception.'''
     self.lut=readLookupTable(LocalProperties.get("gda.config")+"/lookupTables/"+lut)
     self.gap=gap
     self.dcm=dcm
     self.lambdau=undulatorperiod
     if dcm is None:
         self.scannableNames=[gap]
     else:
         self.scannableNames=[dcm,gap]
     self.scannables=ScannableGroup(name, [Finder.find(x) for x in self.scannableNames])
     self._busy=0
     self.setName(name)
     self.setLevel(3)
     self.setOutputFormat(["%10.6f"])
     self.inputNames=[name]
     if self.dcm == "dcmenergy":
         self.order=3
     else:
         self.order=1
     self.energy=self.scannables.getGroupMember(self.scannableNames[0]).getPosition()
     self.polarisation='H'
Example #21
0
def pathscan(scannables, path, args=[]):  #@UndefinedVariable
    ''' 
    Scan a group of scannables following the specified path and 
    collect data at each point from scannables args
    '''
    sg = ScannableGroup()
    for each in scannables:
        sg.addGroupMember(each)
    sg.setName("pathgroup")
    scan([sg, path] + args)
Example #22
0
class SoftEnergy(ScannableMotionBase):
    """
    Create beam energy scannable that encapsulates and fan-outs control to
    ID gap and DCM energy.

    This pseudo device requires a lookup table object to provide allowed energy ranges.
    However The lookup table object must be created before
    the instance creation of this class.
    Equations to calculate insertion device gaps are hard-coded into this class.
    The child scannables or pseudo devices must exist in Jython's global
    namespace prior to any method call of this class instance.
    The lookup Table object is described by gda.function.LookupTable
    class.
    """

    def __init__(self, name, idgap, pgmenergy, lut, gap_offset=None, feedbackPV=None):
        """
        Constructor -
        Only succeeds if it finds the lookup table, otherwise raises exception.
        """
        self.lut = readLookupTable(LocalProperties.get("gda.config") + "/lookupTables/" + lut)
        self.gap = idgap
        self.mono_energy = pgmenergy
        self.scannables = ScannableGroup(name, [pgmenergy, idgap])
        self.detune=gap_offset
        self.feedbackPV=feedbackPV
        self._busy = 0
        self.setName(name)
        self.setLevel(3)
        self.setOutputFormat(["%10.6f"])
        self.inputNames = [name]
        self.SCANNING=False
        self.order = 1
        self.polarisation = 'LH'
        self.jidphase = Finder.find("jidphase")
        self.logger = logger.getChild(self.__class__.__name__)

    def setPolarisation(self, value):
        """Sets the polarisation."""
        if value == "LH" or value == "LH3":
            self.jidphase.hortizontal() 
            self.polarisation=value
        elif value == "LV":
            self.jidphase.vertical()
            self.polarisation = value
        elif value == "CL":
            self.jidphase.circular_left()
            self.polarisation = value
        elif value == "CR":
            self.jidphase.circular_right()
            self.polarisation = value
        else:
            raise ValueError("Input " + str(value) + " invalid. Valid values are 'LH', 'LV', 'CL' and 'CR'.")

        # Move back to the current position i.e. the correct gap for the new polarisation
        # Note this also causes the ID to actually move, if the gap demand is exactly the same it will never!
        self.asynchronousMoveTo(self.getPosition())
        while (self.isBusy()) :
            sleep(0.5)

    def getPolarisation(self):
        """Returns the current polarisation (cached in object not directly from EPICS)"""
        return self.polarisation 

    def harmonicEnergyRanges(self):
        """Prints out a table of harmonics with corresponding min and max energies"""
        print ("%s\t%s\t%s" % ("Harmonic", "Min Energy", "Max Energy"))
        keys = [int(key) for key in self.lut.keys()]
        for key in sorted(keys):
            print ("%8.0d\t%10.2f\t%10.2f" % (key, self.lut[key][2], self.lut[key][3]))

    def energyRangeForOrder(self, order):
        """Returns a tuple with min and max energies for a harmonic order

        Args:
            order (int): The order of the harmonic

        Returns:
            (min_energy, max_energy) (tuple)
        """
        return (self.lut[order][2], self.lut[order][3])

    def idgap(self, Ep, n):
        """
        Function to calculate the insertion device gap

        Arguments:
        Ep -- Energy
        n  -- order
        """
        gap = 20.0
        self.logger.debug("'idgap' function called with energy {} and order {}"
                          .format(Ep, n))
        self.logger.debug("Current cached polarisation is {}"
                          .format(self.polarisation))
        # Soft ID J branch
        # Linear Horizontal
        if self.getPolarisation() == "LH":
            if (Ep < 0.104 or Ep > 1.2):
                raise ValueError("Polarisation = LH  but the demanding energy is outside the valid range between 0.104 and 1.2 keV!")
#            gap=3.06965 +177.99974*Ep -596.79184*Ep**2 +1406.28911*Ep**3 -2046.90669*Ep**4 +1780.26621*Ep**5 -844.81785*Ep**6 +168.99039*Ep**7
#            gap=2.75529 + 184.24255*Ep - 639.07279*Ep**2 +1556.23192*Ep**3 -2340.01233*Ep**4 +2100.81252*Ep**5 -1027.88771*Ep**6 +211.47063*Ep**7
            gap=0.52071 + 238.56372*Ep - 1169.06966*Ep**2 +4273.03275*Ep**3 -10497.36261*Ep**4 +17156.91928*Ep**5 -18309.05195*Ep**6 +12222.50318*Ep**7 -4623.70738*Ep**8 +755.90853*Ep**9
            if (gap < 16 or gap > 60):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16, 60)!")


        # Linear Horizontal 3rd Harmonic for 400 line/mm grating
        elif (self.getPolarisation()=="LH3"):
            if (Ep<0.7 or Ep > 1.95):
                raise ValueError("Polarisation = LH3  but the demanding energy is outside the valid range between 0.7 and 1.9 keV!")
            gap=10.98969 + 25.8301*Ep - 9.36535*Ep**2 + 1.74461*Ep**3
            if (gap < 16 or gap > 60):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16, 60)!")

        # Linear Vertical
        elif self.getPolarisation() == "LV":
            if (Ep < 0.22 or Ep > 1.0):
                raise ValueError("Demanding energy must lie between 0.22 and 1.0 eV!")
            gap = (5.33595 + 72.53678 * Ep - 133.96826 * Ep ** 2 + 179.99229 * Ep ** 3
                   - 128.83048 * Ep ** 4 + 39.34346 * Ep ** 5)
            if (gap < 16.01 or gap > 60):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16, 60)!")

        # Circular left
        elif self.getPolarisation() == "CL":
            if (Ep < 0.145 or Ep > 1.2):
                raise ValueError("Demanding energy must lie between 0.146 and 1.2 eV!")
            # Circular left gap polymonimal
            gap = (5.32869 + 101.28316 * Ep - 192.74788 * Ep ** 2 + 249.91788 * Ep ** 3
                   - 167.93323 * Ep ** 4 + 47.22008 * Ep ** 5 - 0.054 * Ep - .0723)

            # Check the gap is possible
            if (gap < 16.01 or gap > 60):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16, 60)!")

        # Circular right
        elif self.getName() == "jenergy" and self.getPolarisation() == "CR":
            if (Ep < 0.145 or Ep > 1.2):
                raise ValueError("Demanding energy must lie between 0.1 and 1.2 eV!")
            # Circular right gap polymonimal
            gap = (5.32869 + 101.28316 * Ep - 192.74788 * Ep ** 2 + 249.91788 * Ep ** 3
                   - 167.93323 * Ep ** 4 + 47.22008 * Ep ** 5)

            # Check the gap is possible
            if (gap < 16.01 or gap > 60):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16, 60)!")

        # Unsupported
        else:
            raise ValueError("Unsupported scannable or polarisation mode")
        return gap

    def rawGetPosition(self):
        """returns the current position of the beam energy."""
        return self.mono_energy.getPosition()/1000.0

    def calc(self, energy, order):
        return self.idgap(energy, order)

    def moveDevices(self, energy, gap):
        for s in self.scannables.getGroupMembers():
            if s.getName() == self.gap.getName():
                try:
                    if self.detune:
                        gap = gap + float(self.detune.getPosition())
                    self.logger.debug("Calling asynchronousMoveTo() on {} with gap {}".format(s.getName(), gap))
                    s.asynchronousMoveTo(gap)
                except:
                    self.logger.error("cannot set " + s.getName() + " to " + str(gap), exc_info=True)
                    raise
            else:
                try:
                    self.logger.debug("Calling asynchronousMoveTo() on {} with energy {}".format(s.getName(), energy * 1000))
                    s.asynchronousMoveTo(energy * 1000)
                    # Allow time for s to become busy
                    sleep(0.1)
                except:
                    self.logger.error("Can not set " + s.getName() + " to " + str(energy), exc_info=True)
                    raise

    def rawAsynchronousMoveTo(self, new_position):
        """
        move beam energy to specified value.
        At the background this moves both ID gap and Mono Bragg to the values corresponding to this energy.
        If a child scannable can not be reached for whatever reason, it just prints out a message, then continue to next.
        """
        energy = float(new_position)
        gap = self.idgap(energy, self.order)

        if self.feedbackPV is not None and not self.SCANNING:
            caput(self.feedbackPV, 1)
            self.moveDevices(energy, gap)
            self.waitWhileBusy()
            caput(self.feedbackPV, 0)
        else:
            self.moveDevices(energy, gap)

    def isBusy(self):
        """
        checks the busy status of all child scannable.

        If and only if all child scannable are done this will be set to False.
        """
        self._busy = 0
        for s in self.scannables.getGroupMembers():
            try:
                self._busy += s.isBusy()
            except:
                print ("%s isBusy() throws exception" % (s.getName()), sys.exc_info())
                raise
        if self._busy == 0:
            return 0
        else:
            return 1

    def toString(self):
        """formats what to print to the terminal console."""
        return self.name + " : " + str(self.rawGetPosition())

    def atScanStart(self):
        self.SCANNING=True
            
    def atScanEnd(self):
        self.SCANNING=False
Example #23
0
def analyserscan(*args):
    ''' a more generalised scan that extends standard GDA scan syntax to support 
    1. scannable tuple (e.g. (s1,s2,...) argument) as scannable group and 
    2. its corresponding path tuple (e.g. tuple of position lists), if exist, and
    3. EW4000 analyser detector that takes a reion sequence file name as input, if exist, and
    4. syntax 'analyserscan ew4000 "user.seq ...' for analyser scan only
    It parses input parameters described above before delegating to the standard GDA scan to do the actual data collection.
    Thus it can be used anywhere the standard GDA 'scan' is used.
    '''
    starttime = time.ctime()
    if PRINTTIME: print "=== Scan started: " + starttime
    newargs = []
    i = 0
    while i < len(args):
        arg = args[i]
        if i == 0 and isinstance(arg, EW4000):
            newargs.append(zeroScannable)
            newargs.append(0)
            newargs.append(0)
            newargs.append(1)
            newargs.append(arg)
        elif type(arg) == TupleType:
            if allElementsAreScannable(arg):
                #parsing (scannable1, scannable2,...) as scannable group
                scannableGroup = ScannableGroup()
                for each in arg:
                    scannableGroup.addGroupMember(each)
                scannableGroup.setName("pathgroup")
                newargs.append(scannableGroup)
            elif allElementsAreListOfNumber(arg):
                #parsing scannable group's position lists
                newargs.append(arg)
            elif allElementsAreNumber(arg):
                #parsing scannable group's position lists
                newargs.append(arg)
            elif allElementsAreTuplesOfNumbers(arg):
                # This case is to fix BLIX-206 when using a scannable group with a tuple of tuples of positions
                newargs.append(arg)
            else:
                raise TypeError, "Only tuple of scannables, tuple of numbers, tuple of tuples of numbers, or list of numbers are supported."
        else:
            newargs.append(arg)
        i = i + 1
        if isinstance(arg, EW4000):
            controller = Finder.find("SequenceFileObserver")
            xmldir = InterfaceProvider.getPathConstructor(
            ).getVisitSubdirectory('xml') + os.sep
            filename = xmldir + args[i]
            if (OsUtil.isWindows()):
                FilenameUtil.setPrefix("D:")
                filename = FilenameUtil.convertSeparator(filename)
            controller.update(controller, SequenceFileChangeEvent(
                filename))  #update client sequence view
            sleep(2.0)
            jythonServerStatus = InterfaceProvider.getJythonServerStatusProvider(
            ).getJythonServerStatus()
            while (jythonServerStatus.isScriptOrScanPaused()):
                sleep(1.0)  # wait for user saving dirty file
            arg.setSequenceFilename(filename)
            sequence = arg.loadSequenceData(filename)
            if isinstance(arg.getCollectionStrategy(),
                          EW4000CollectionStrategy):
                arg.getCollectionStrategy().setSequence(sequence)
            i = i + 1
    scan(newargs)
    if ENABLEZEROSUPPLIES:
        zerosupplies()  # @UndefinedVariable

    if PRINTTIME:
        print("=== Scan ended: " + time.ctime() +
              ". Elapsed time: %.0f seconds" % (time.time() - starttime))
Example #24
0
'''
Created on 1 Aug 2019

@author: fy65
'''
from epics.motor.positionCompareMotorClass import PositionCompareMotorClass
from future.singleEpicsPositionerNoStatusClassDeadbandOrStop import SingleEpicsPositionerNoStatusClassDeadbandOrStop
from utils.ExceptionLogs import localStation_exception
import sys
from gda.device.scannable.scannablegroup import ScannableGroup

try:
    m3m5_x = PositionCompareMotorClass("m3m5_x", "BL10I-OP-SWTCH-01:X.VAL", "BL10I-OP-SWTCH-01:X.RBV", "BL10I-OP-SWTCH-01:X.STOP", 0.002, "mm", "%.3f")
    m3m5_y = PositionCompareMotorClass("m3m5_y", "BL10I-OP-SWTCH-01:Y.VAL", "BL10I-OP-SWTCH-01:Y.RBV", "BL10I-OP-SWTCH-01:Y.STOP", 0.002, "mm", "%.3f")
    m3m5_z = PositionCompareMotorClass("m3m5_z", "BL10I-OP-SWTCH-01:Z.VAL", "BL10I-OP-SWTCH-01:Z.RBV", "BL10I-OP-SWTCH-01:Z.STOP", 0.002, "mm", "%.3f")
    m3m5_yaw = PositionCompareMotorClass("m3m5_yaw", "BL10I-OP-SWTCH-01:YAW.VAL", "BL10I-OP-SWTCH-01:YAW.RBV", "BL10I-OP-SWTCH-01:YAW.STOP", 0.002, "urad", "%.3f")
    m3m5_pitch = PositionCompareMotorClass("m3m5_pitch", "BL10I-OP-SWTCH-01:PITCH.VAL", "BL10I-OP-SWTCH-01:PITCH.RBV", "BL10I-OP-SWTCH-01:PITCH.STOP", 0.002, "urad", "%.3f")
    m3m5_roll = PositionCompareMotorClass("m3m5_roll", "BL10I-OP-SWTCH-01:ROLL.VAL", "BL10I-OP-SWTCH-01:ROLL.RBV", "BL10I-OP-SWTCH-01:ROLL.STOP", 0.002, "urad", "%.3f")
    m3m5fpitch = SingleEpicsPositionerNoStatusClassDeadbandOrStop('m3m5fpitch', 'BL10I-OP-SWTCH-01:FPITCH:DMD:AO', 'BL10I-OP-SWTCH-01:FPITCH:RBV:AI', 'V', '%.3f', 0.001)
    m3m5=ScannableGroup("m3m5", [m3m5_x, m3m5_y, m3m5_z, m3m5_yaw, m3m5_pitch, m3m5_roll, m3m5fpitch])
except:
    localStation_exception(sys.exc_info(), "initialising m3m5 hexapod and fpitch scannables")
Example #25
0
                                     "BL10J-OP-FOCA-01:X.STOP", 0.002, "mm",
                                     "%.3f")
    m6_y = PositionCompareMotorClass("m6_y", "BL10J-OP-FOCA-01:Y.VAL",
                                     "BL10J-OP-FOCA-01:Y.RBV",
                                     "BL10J-OP-FOCA-01:Y.STOP", 0.002, "mm",
                                     "%.3f")
    m6_z = PositionCompareMotorClass("m6_z", "BL10J-OP-FOCA-01:Z.VAL",
                                     "BL10J-OP-FOCA-01:Z.RBV",
                                     "BL10J-OP-FOCA-01:Z.STOP", 0.002, "mm",
                                     "%.3f")
    m6_yaw = PositionCompareMotorClass("m6_yaw", "BL10J-OP-FOCA-01:YAW.VAL",
                                       "BL10J-OP-FOCA-01:YAW.RBV",
                                       "BL10J-OP-FOCA-01:YAW.STOP", 0.002,
                                       "urad", "%.3f")
    m6_pitch = PositionCompareMotorClass("m6_pitch",
                                         "BL10J-OP-FOCA-01:PITCH.VAL",
                                         "BL10J-OP-FOCA-01:PITCH.RBV",
                                         "BL10J-OP-FOCA-01:PITCH.STOP", 0.002,
                                         "urad", "%.3f")
    m6_roll = PositionCompareMotorClass("m6_roll", "BL10J-OP-FOCA-01:ROLL.VAL",
                                        "BL10J-OP-FOCA-01:ROLL.RBV",
                                        "BL10J-OP-FOCA-01:ROLL.STOP", 0.002,
                                        "urad", "%.3f")
    m6fpitch = SingleEpicsPositionerNoStatusClassDeadbandOrStop(
        'm6fpitch', 'BL10J-OP-FOCA-01:FPITCH:DMD:AO',
        'BL10J-OP-FOCA-01:FPITCH:RBV:AI', 'V', '%.3f', 0.001)
    m6 = ScannableGroup(
        "m6", [m6_x, m6_y, m6_z, m6_yaw, m6_pitch, m6_roll, m6fpitch])
except:
    localStation_exception(sys.exc_info(),
                           "initialising m6 hexapod and fpitch scannables")
Example #26
0
class HardEnergy(ScannableMotionBase):
    """
    Create beam energy scannable that encapsulates and fan-outs control to
    ID gap and DCM energy.

    This pseudo device requies a lookup table object to provide ID
    parameters for calculation of ID gap from beam energy required
    and harmonic order. The lookup table object must be created before
    the instance creation of this class.
    The child scannables or pseudo devices must exist in jython's global
    namespace prior to any method call of this class instance.
    The lookup Table object is described by gda.function.LookupTable
    class.
    """
    def __init__(self,
                 name,
                 idgap,
                 dcmenergy,
                 lut,
                 gap_offset=None,
                 feedbackPVs=None):
        """
        Constructor - Only succeeds if it finds the lookup table,
        otherwise raises exception.
        """
        self.lut = readLookupTable(
            LocalProperties.get("gda.config") + "/lookupTables/" + lut)
        self.gap = idgap
        self.mono_energy = dcmenergy
        self.lambdau = 27  # undulator period
        self.scannables = ScannableGroup(name, [dcmenergy, idgap])
        self.detune = gap_offset
        self.feedbackPVs = feedbackPVs
        self._busy = 0
        self.setName(name)
        self.setLevel(3)
        self.setOutputFormat(["%10.6f"])
        self.inputNames = [name]
        self.order = 3
        self.SCANNING = False
        self.logger = logger.getChild(self.__class__.__name__)

    def harmonicEnergyRanges(self):
        """
        Prints out a table of harmonics with corresponding minimum and maximum energies
        """
        print("%s\t%s\t%s" % ("Harmonic", "Min Energy", "Max Energy"))
        keys = [int(key) for key in self.lut.keys()]
        for key in sorted(keys):
            print("%8.0d\t%10.2f\t%10.2f" %
                  (key, self.lut[key][2], self.lut[key][3]))

    def energyRangeForOrder(self, order):
        """Returns a tuple with min and max energies for a harmonic order

        Args:
            order (int): The order of the harmonic

        Returns:
            (min_energy, max_energy) (tuple)
        """
        return (self.lut[order][2], self.lut[order][3])

    def setOrder(self, n):
        """Method to set the harmonic order"""
        self.order = n

    def getOrder(self):
        """Method to retrieve the harmonic order"""
        return self.order

    def idgap(self, Ep, n):
        """
        Function to calculate the insertion device gap

        Arguments:
        Ep -- Energy
        n  -- order
        """
        lambda_u = self.lambdau
        M = 4
        h = 16
        me = 0.510999
        gamma = 1000 * self.lut[n][0] / me
        k_squared = (4.959368e-6 * (n * gamma * gamma / (lambda_u * Ep)) - 2)
        if k_squared < 0:
            raise ValueError("k_squared must be positive!")
        K = math.sqrt(k_squared)
        A = ((2 * 0.0934 * lambda_u * self.lut[n][1] * M / math.pi) *
             math.sin(math.pi / M) *
             (1 - math.exp(-2 * math.pi * h / lambda_u)))
        gap = (lambda_u / math.pi) * math.log(A / K) + self.lut[n][6]
        if self.detune:
            gap = gap + float(self.detune.getPosition())
        self.logger.debug("Required gap calculated to be {}".format(gap))
        return gap

    def rawGetPosition(self):
        """Returns the current position of the beam energy."""
        return self.mono_energy.getPosition()

    def calc(self, energy, order):
        return self.idgap(energy, order)

    def moveDevices(self, energy, gap):
        for scannable in self.scannables.getGroupMembers():
            if scannable.getName() == self.gap.getName():
                try:
                    scannable.asynchronousMoveTo(gap)
                except:
                    print("cannot set %s to %f " % (scannable.getName(), gap))
                    raise
            elif scannable.getName() == self.mono_energy.getName():
                try:
                    scannable.asynchronousMoveTo(energy)
                    sleep(0.1)  # Allow time for s to become busy
                except:
                    print("cannot set %s to %f" %
                          (scannable.getName(), energy))
                    raise

    def rawAsynchronousMoveTo(self, new_position):
        """
        move beam energy to specified value.
        In the background this moves both ID gap and Mono Bragg to the values
        corresponding to this energy. If a child scannable can not be reached
        for whatever reason, it just prints out a message, then continue to next.
        """
        min_energy, max_energy = self.energyRangeForOrder(self.order)
        energy = float(new_position)
        self.logger.debug(
            ("rawAsynchronousMoveTo called for energy {}. "
             "min_energy for order is: {}, max_energy is: {}").format(
                 energy, min_energy, max_energy))

        gap = self.idgap(energy, self.order)

        if not min_energy < energy < max_energy:
            raise ValueError(("Requested photon energy {} is out of range for "
                              "harmonic {}: min: {}, max: {}").format(
                                  energy, self.order, min_energy, max_energy))

        if self.feedbackPVs is not None and not self.SCANNING:
            caput(self.feedbackPVs[0], 1)
            caput(self.feedbackPVs[1], 1)
            self.moveDevices(energy, gap)
            self.waitWhileBusy()
            caput(self.feedbackPVs[0], 0)
            caput(self.feedbackPVs[1], 0)
        else:
            self.moveDevices(energy, gap)

    def isBusy(self):
        """
        Checks the busy status of all child scannable.

        If and only if all child scannable are done this will be set to False.
        """
        self._busy = 0
        for scannable in self.scannables.getGroupMembers():
            try:
                self._busy += scannable.isBusy()
            except:
                self.logger.error(scannable.getName() +
                                  "isBusy() method threw exception:",
                                  exc_info=True)
                raise
        if self._busy == 0:
            return 0
        else:
            return 1

    def toString(self):
        """formats what to print to the terminal console."""
        return self.name + " : " + str(self.rawGetPosition())

    def atScanStart(self):
        self.SCANNING = True

    def atScanEnd(self):
        self.SCANNING = False
Example #27
0
                                     "BL10I-OP-FOCS-01:X.STOP", 0.002, "mm",
                                     "%.3f")
    m4_y = PositionCompareMotorClass("m4_y", "BL10I-OP-FOCS-01:Y.VAL",
                                     "BL10I-OP-FOCS-01:Y.RBV",
                                     "BL10I-OP-FOCS-01:Y.STOP", 0.002, "mm",
                                     "%.3f")
    m4_z = PositionCompareMotorClass("m4_z", "BL10I-OP-FOCS-01:Z.VAL",
                                     "BL10I-OP-FOCS-01:Z.RBV",
                                     "BL10I-OP-FOCS-01:Z.STOP", 0.002, "mm",
                                     "%.3f")
    m4_yaw = PositionCompareMotorClass("m4_yaw", "BL10I-OP-FOCS-01:YAW.VAL",
                                       "BL10I-OP-FOCS-01:YAW.RBV",
                                       "BL10I-OP-FOCS-01:YAW.STOP", 0.002,
                                       "urad", "%.3f")
    m4_pitch = PositionCompareMotorClass("m4_pitch",
                                         "BL10I-OP-FOCS-01:PITCH.VAL",
                                         "BL10I-OP-FOCS-01:PITCH.RBV",
                                         "BL10I-OP-FOCS-01:PITCH.STOP", 0.002,
                                         "urad", "%.3f")
    m4_roll = PositionCompareMotorClass("m4_roll", "BL10I-OP-FOCS-01:ROLL.VAL",
                                        "BL10I-OP-FOCS-01:ROLL.RBV",
                                        "BL10I-OP-FOCS-01:ROLL.STOP", 0.002,
                                        "urad", "%.3f")
    m4fpitch = SingleEpicsPositionerNoStatusClassDeadbandOrStop(
        'm4fpitch', 'BL10I-OP-FOCS-01:FPITCH:DMD:AO',
        'BL10I-OP-FOCS-01:FPITCH:RBV:AI', 'V', '%.3f', 0.001)
    m4 = ScannableGroup(
        "m4", [m4_x, m4_y, m4_z, m4_yaw, m4_pitch, m4_roll, m4fpitch])
except:
    localStation_exception(sys.exc_info(),
                           "initialising m4 hexapod and fpitch scannables")
Example #28
0
def make_tomoScanDevice(tomography_theta, tomography_shutter,
                        tomography_translation, tomography_optimizer,
                        image_key, tomography_imageIndex):

    tomoScanDevice = ScannableGroup()
    tomoScanDevice.addGroupMember(tomography_theta)
    tomoScanDevice.addGroupMember(
        EnumPositionerDelegateScannable("tomography_shutter",
                                        tomography_shutter))
    tomoScanDevice.addGroupMember(tomography_translation)
    tomoScanDevice.addGroupMember(tomography_optimizer)
    tomoScanDevice.addGroupMember(image_key)
    tomoScanDevice.addGroupMember(tomography_imageIndex)
    tomoScanDevice.setName("tomoScanDevice")
    tomoScanDevice.configure()
    return tomoScanDevice
Example #29
0
    print "    (change threshold with checkrc.minumumThreshold=12345)"
    print " 2. 'checktopup_time', - avoid topup period, pause 5 seconds before topup starts, 5s wait after topup finished."
    print " 3. 'checkfe', - check Front end shutter, pause when shutter closed, resume 60s after shutter opened."
    print " 4. 'checkbeam', - composite scannable of above 3 scannables"
    print " Checking is done every second!"

    from gdascripts.scannable.beamokay import WaitWhileScannableBelowThreshold, WaitForScannableState
    from gda.device.scannable.scannablegroup import ScannableGroup

    checkrc = WaitWhileScannableBelowThreshold('checkrc',
                                               ringcurrent,
                                               190,
                                               secondsBetweenChecks=1,
                                               secondsToWaitAfterBeamBackUp=5)
    checktopup_time = WaitWhileScannableBelowThreshold(
        'checktopup_time',
        topup_time,
        5,
        secondsBetweenChecks=1,
        secondsToWaitAfterBeamBackUp=5)
    checkfe = WaitForScannableState('checkfe',
                                    fepb,
                                    secondsBetweenChecks=1,
                                    secondsToWaitAfterBeamBackUp=60)
    checkbeam = ScannableGroup('checkbeam',
                               [checkrc, checkfe, checktopup_time])
    checkbeam.configure()

except:
    localStation_exception(sys.exc_info(), "creating checkbeam objects")
Example #30
0
timekeeper = ShowTimeClass('timekeeper')
timekeeper.autoReset = False
clock = ShowClockClass('clock')

print 'For time measuring, using "lineTime" and "pointTime" for the time spent on one line of a scan and each scan point, respectively'
lineTime = LineTimeClass('lineTime')
pointTime = PointTimeClass('pointTime')

print "To control the speed of a scan, using 'waitTimer' for wait delay or 'scanTimer' or 'timer' as scannable"
waitTimer = WaitTimerClass('waitTimer')

#To scan against time.
timer = ScanTimerClass('timer')
scanTimer = ScanTimerClass('scanTimer')

Timers = ScannableGroup()
Timers.setName('Timers')
Timers.addGroupMember(clock)
Timers.addGroupMember(stopwatch)
Timers.addGroupMember(timekeeper)
Timers.addGroupMember(lineTime)
Timers.addGroupMember(pointTime)
Timers.addGroupMember(waitTimer)
Timers.addGroupMember(timer)
Timers.addGroupMember(scanTimer)

dummyCounter = SoftCounterClass('dummyCounter')
dummyCounter1 = SoftCounterClass('dummyCounter1')
dummyCounter2 = SoftCounterClass('dummyCounter2')

from Diamond.PseudoDevices.DummyShutter import DummyShutterClass
Example #31
0
class PathScan():
    def __init__(self, name, detectorToUse=edxd):#@UndefinedVariable
        self.name=name
        self.sg = ScannableGroup()
        self.pointid=[]
        self.path=[]
        self.startline=1
        self.lastline=10
        self.scannablelist=[]
        self.scannableunitlist=[]
        self.detector=detectorToUse
        self.detectorunit="s"
        self.exposuretime=[]
        
    def read_scan_path(self,filename):
        f = open(filename, "r")
        lines = f.readlines()
        f.close()
        lines = map(string.split, map(string.strip, lines))
        self.pointid=[]
        self.path=[]
        self.scannablelist=[]
        self.scannableunitlist=[]
        self.exposuretime=[]
        # parsing the input data
        for line in lines:
            print line
            if line[0].startswith("#"):     #ignore comment
                continue
            elif line[0].startswith("First"):
                self.startline=line[-1]
            elif line[0].startswith("Last"):
                self.lastline=line[-1]
            elif line[0].startswith("ScannableNames"):
                self.scannablelist=[globals()[x] for x in line[1:]] # get all motors
                self.sg.setName("pathscangroup")
                self.sg.setGroupMembers(self.scannablelist)
                self.sg.configure()
            elif line[0].startswith("ScannableUnits"):
                self.scannableunitlist=[x for x in line[1:]]
            else: #real data go here
                if int(line[0])>= self.startline or int(line[0]) <= self.lastline:
                    self.pointid.append(int(line[0]))
                    self.path.append([float(x) for x in line[1:]])
                    
    def setStartPoint(self, start):
        self.startline=start
    
    def getStartPoint(self):
        return self.startline
    
    def setStopPoint(self, stop):
        self.lastline=stop
        
    def getStopPoint(self):
        return self.lastline
    
    def setDetector(self, det):
        self.detector=det
        
    def getDetector(self):
        return self.detector
    
    def getPath(self):
        return self.path
    
    def setPath(self, path):
        self.path=path
        
    def getPointIDs(self):
        return self.pointid
    
    def setPointIDs(self, points):
        self.pointid=points

    def start(self,filename, exposureTime):
        ''' kept for backward compatibility'''
        self.read_scan_path(filename)
        print self.pointid
        print self.path
        print self.exposuretime
        pathPositions=tuple(self.path)
        print pathPositions
        scan([self.sg, pathPositions, self.detector, exposureTime])
    
    def startScan(self,filename, exposureTime):
        print self.pointid
        print self.exposuretime
        pathPositions=tuple(self.path)
        print pathPositions
        scan([self.sg, pathPositions, self.detector, exposureTime])
            
    def setName(self, name):
        self.name=name
        
    def getName(self):
        return self.name
Example #32
0
def miscan(*args):
    '''   a more generalised scan that extends standard GDA scan syntax to support 
        1. scannable tuple (e.g. (s1,s2,...) argument) as scannable group, 
        2. its corresponding path tuple (e.g. list of position tuples), if exist, and
        3. area detector that takes 2 input numbers - 1st input is the number of images to be collected at each point,
           if omitted it default to 1, and 2nd input is detector exposure time which must be provided,
        4. syntax 'miscan mpx 10 0.1 ...' is supported for collecting 10 images at a single point.
    
        It parses input parameters described above before delegating to the standard GDA scan to do the actual data collection.
        Thus it can be used anywhere the standard GDA 'scan' is used.
    '''
    starttime = time.ctime()
    if PRINTTIME: print "=== Scan started: " + starttime
    newargs = []
    i = 0
    while i < len(args):
        arg = args[i]
        if i == 0 and isinstance(arg, NXDetector):
            newargs.append(zeroScannable)
            newargs.append(0)
            newargs.append(0)
            newargs.append(1)
            newargs.append(arg)
        elif type(arg) == TupleType:
            if allElementsAreScannable(arg):
                #parsing (scannable1, scannable2,...) as scannable group
                scannableGroup = ScannableGroup()
                for each in arg:
                    scannableGroup.addGroupMember(each)
                scannableGroup.setName("pathgroup")
                newargs.append(scannableGroup)
            elif allElementsAreListOfNumber(arg):
                #parsing scannable group's position lists
                newargs.append(arg)
            elif allElementsAreNumber(arg):
                #parsing scannable group's position lists
                newargs.append(arg)
            elif allElementsAreTuplesOfNumbers(arg):
                # This case is to fix BLIX-206 when using a scannable group with a tuple of tuples of positions
                newargs.append(arg)
            elif allElementsAreString(arg):
                newargs.append(arg)
            else:
                raise TypeError, "Only tuple of scannables, tuple of numbers, tuple of tuples of numbers, list of numbers, or tuple of Strings are supported."
        else:
            newargs.append(arg)
        i = i + 1
        if isinstance(arg, NXDetector):
            decoratee = arg.getCollectionStrategy().getDecoratee()
            if isinstance(decoratee, ImageModeDecorator):
                if i < len(
                        args) - 1:  # more than 2 arguments following detector
                    if type(args[i]) == IntType and (
                            type(args[i + 1]) == IntType
                            or type(args[i + 1]) == FloatType):
                        #support the miscan command - first input after detector is number of images per data point
                        decoratee.setNumberOfImagesPerCollection(args[i])
                    elif type(args[i]) == FloatType and (
                            type(args[i + 1]) == IntType
                            or type(args[i + 1]) == FloatType):
                        raise TypeError, "Number of images to collect per scan data point must be Int type."
                    elif type(args[i]) == FloatType and not (
                            type(args[i + 1]) == IntType
                            or type(args[i + 1]) == FloatType):
                        decoratee.setNumberOfImagesPerCollection(1)
                elif i == len(
                        args
                ) - 1:  #followed by only one argument - must be exposure time
                    decoratee.setNumberOfImagesPerCollection(1)

            else:  #exposure time is the last one in the scan command
                newargs.append(args[i])  #single image per data point
            i = i + 1
    scan([e for e in newargs])

    if PRINTTIME:
        print("=== Scan ended: " + time.ctime() +
              ". Elapsed time: %.0f seconds" % (time.time() - starttime))
Example #33
0
def make_tomoScanDevice(
    tomography_theta, tomography_shutter, tomography_translation, tomography_optimizer, image_key, tomography_imageIndex
):

    tomoScanDevice = ScannableGroup()
    tomoScanDevice.addGroupMember(tomography_theta)
    tomoScanDevice.addGroupMember(EnumPositionerDelegateScannable("tomography_shutter", tomography_shutter))
    tomoScanDevice.addGroupMember(tomography_translation)
    tomoScanDevice.addGroupMember(tomography_optimizer)
    tomoScanDevice.addGroupMember(image_key)
    tomoScanDevice.addGroupMember(tomography_imageIndex)
    tomoScanDevice.setName("tomoScanDevice")
    tomoScanDevice.configure()
    return tomoScanDevice
Example #34
0
class BeamEnergyPolarisationClass(ScannableMotionBase):
    '''Coupled beam energy and polarisation scannable that encapsulates and fan-outs control to ID gap, row phase, and PGM energy.

        This pseudo device requires a lookupTable table object to provide ID parameters for calculation of ID idgap from beam
        energy required and harmonic order. The lookupTable table object must be created before the instance creation of this class.
        The child scannables or pseudo devices must exist in jython's global namespace prior to any method call of this class
        instance.
        '''
    harmonicOrder = 1

    def __init__(self, name, idctrl, pgmenergy, lut="JIDEnergy2GapCalibrations.csv", energyConstant=False, polarisationConstant=False, gap_offset=None, feedbackPV=None):
        '''Constructor - Only succeed if it find the lookupTable table, otherwise raise exception.'''
        self.lut,self.header = load_lookup_table(LocalProperties.get("gda.config")+"/lookupTables/"+lut)
        self.idscannable = idctrl
        self.mono_energy = pgmenergy
        self.scannables = ScannableGroup(name, [pgmenergy, idctrl])
        self.detune = gap_offset
        self.feedbackPV = feedbackPV
        self._busy = 0
        self.setName(name)
        self.setLevel(3)
        self.setOutputFormat(["%10.6f"])
        self.setInputNames([name])
        self.setExtraNames([])
        self.polarisation = 'LH'
        self.gap = 50
        self.phase = 0
        self.energyConstant = energyConstant
        self.polarisationConstant = polarisationConstant
        self.SCANNING = False
        if self.energyConstant and self.polarisationConstant:
            raise RuntimeError("Cannot create an instance with both energy and polarisation being constant.")
        self.isConfigured = False
        self.inputSignSwitched = False
        self.beamlinename = LocalProperties.get(LocalProperties.GDA_BEAMLINE_NAME)
        self.logger = logger.getChild(self.__class__.__name__)

    def configure(self):
        if self.idscannable is not None:
            self.maxGap=self.idscannable.getController().getMaxGapPos()
            self.minGap=self.idscannable.getController().getMinGapPos()
            self.maxPhase=self.idscannable.getController().getMaxPhaseMotorPos()
        self.isConfigured=True

    def getIDPositions(self):
        '''get gap and phase from ID hardware controller, and set polarisation mode in GDA 'idscannable' instance
        This method sync current object states with ID state in EPICS IOC.
        '''
        result = list(self.idscannable.getPosition())
        gap = float(result[0])
        polarisation = str(result[1])
        if BeamEnergyPolarisationClass.harmonicOrder > 1: # support other harmonic
            polarisation = str(polarisation)+str(BeamEnergyPolarisationClass.harmonicOrder)
        phase = float(result[2])
        return (gap, polarisation, phase)

    def showFittingCoefficentsLookupTable(self):
        formatstring="%4s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s"
        print (formatstring % tuple([x for x in self.header]))
        for key, value in sorted(self.lut.iteritems()):
            print (formatstring % tuple([x for x in key] + [x for x in value]))

    def setOrder(self,n):
        BeamEnergyPolarisationClass.harmonicOrder = n

    def getOrder(self):
        return BeamEnergyPolarisationClass.harmonicOrder

    def idgap(self, energy):
        '''return gap for the given energy for current polarisation.
            used in cvscan where polarisation doesn't change during continuous energy moving.
        '''
        gap, polarisation, phase = self.getIDPositions()  # @UnusedVariable
        gap, phase = self.idgapphase(Ep=energy, mode=polarisation)  # @UnusedVariable
        return gap

    def idgapphase(self, Ep=None, mode='LH'):
        '''coverts energy and polarisation to  gap and phase. It supports polarisation modes: LH, LV, CR, CL, and LH3
        '''

        phase = 0 #phase value for LH and LV is ignored by self.idscannable
        if mode in ["LH", "LV", "CR", "CL", "LH3"]:
            #polarisation is constant in these modes
            coef = get_fitting_coefficents(mode, Ep, self.lut)
            gap = coef[0] + coef[1]*Ep + coef[2]*Ep**2 +coef[3]*Ep**3 + coef[4]*Ep**4 + coef[5]*Ep**5 + coef[6]*Ep**6 + coef[7]*Ep**7 + coef[8]*Ep**8 + coef[9]*Ep**9
            #adjust gap
            if self.detune:
                gap = gap + float(self.detune.getPosition())

            if (gap<self.minGap or gap>self.maxGap): #IDGroup Excel table only cover this range
                raise ValueError("Required Soft X-Ray ID gap is %s out side allowable bound (%s, %s)!" % (gap, self.minGap, self.maxGap))

            if mode == "LH3":
                BeamEnergyPolarisationClass.harmonicOrder = 3
            if mode == "LH":
                BeamEnergyPolarisationClass.harmonicOrder = 1
                
            if mode == "LV":
                BeamEnergyPolarisationClass.harmonicOrder = 1
                phase = self.maxPhase

            if mode in ["CR", "CL"]:
                BeamEnergyPolarisationClass.harmonicOrder = 1
                phase=15.0

        else:
            raise ValueError("Unsupported polarisation mode, only LH, LV, CR, CL, and LH3 are supported.")
        if phase < 0 or phase > self.maxPhase: #Physical limits of ID Row Phase
            raise ValueError("Required Soft X-Ray ID phase is %s out side allowable bound (%s, %s)!" % (phase, 0, self.maxPhase))
        return (gap, phase)

    def calc(self, energy, order=1):
        message = "'order' input is no longer required. this is now merged into polarisation mode in the calibration lookup table!"
        print(message)
        self.logger.warn(message)
        return self.idgap(energy)

    def rawGetPosition(self):
        '''returns the current beam energy, or polarisation, or both.'''

        gap, polarisation, phase = self.getIDPositions()  # @UnusedVariable
        energy=float(self.mono_energy.getPosition()/1000.0) #energy unit is in keV

        if polarisation in ["LH","LV","CR","CL","LH3"]:
            if self.polarisationConstant:
                return energy
            elif self.energyConstant:
                self.setOutputFormat(["%s"])
                self.polarisation = polarisation
                return polarisation
            else:
                self.setOutputFormat(["%10.6f","%s"])
                self.polarisation = polarisation
                return energy, polarisation


    def moveDevices(self, gap, new_polarisation, phase, energy):
        for s in self.scannables.getGroupMembers():
            if str(s.getName()) == str(self.idscannable.getName()):
                try:
                    if new_polarisation == "LH3" :
                        new_polarisation = "LH"
                    s.asynchronousMoveTo([gap, new_polarisation, phase])
                except:
                    print("cannot set %s to [%f, %s, %f]" % (s.getName(), gap, new_polarisation, phase))
                    raise
            elif not self.energyConstant:
                try:
                    s.asynchronousMoveTo(energy * 1000)
                except:
                    print("cannot set %s to %f." % (s.getName(), energy))
                    raise

    def rawAsynchronousMoveTo(self, new_position):
        '''move beam energy, polarisation, or both to specified values.
        At the background this moves both ID gap, phase, and PGM energy to the values corresponding to this energy, polarisation or both.
        If a child scannable can not be reached for whatever reason, it just prints out a message, then continue to next.'''
        gap = 20
        new_polarisation = None
        phase = 0
        try:
            if not self.SCANNING:  #ensure ID hardware in sync in 'pos' command
                self.rawGetPosition()
            #parse arguments as it could be 1 or 2 inputs, string or number type, depending on polarisation mode and instance attribute value
            if not isinstance(new_position, list): # single argument
                self.logger.debug("Single argument: {} given".format(type(new_position)))
                if isinstance(new_position, basestring):
                    #polarisation change requested
                    energy=float(self.mono_energy.getPosition())/1000.0 #get existing energy
                    if self.polarisationConstant: #input must be for energy
                        raise ValueError("Input value must be a number.")
                    new_polarisation=str(new_position)
                    if not new_polarisation in ["LH", "LV","CR", "CL", "LH3"]:
                        raise ValueError('Input value must be one of valid polarisation mode: "LH", "LV","CR", "CL", "LH3"')
                elif isinstance(new_position, numbers.Number):
                    # energy change requested
                    if self.polarisationConstant: #input must be for energy
                        energy=float(new_position) 
                        gap, new_polarisation, phase = self.getIDPositions() #get existing polarisation
                    else:
                        raise ValueError("Polarisation is not constant, but a number: {} was given".format(new_position))
                else:
                    raise ValueError("Input value must be a string or number.")
            else: #2 arguments
                args = list(new_position)
                if len(args) != 2:
                    raise ValueError("Expect 2 arguments but got %s" % len(args))
                if isinstance(args[0], numbers.Number):
                    self.logger.debug("Two arguments given and first argument {} is a number".format(args[0]))
                    energy = float(args[0]) #range validation is done later
                else:
                    raise ValueError("1st input for energy must be a number")
                if isinstance(args[1], basestring):
                    new_polarisation = args[1]
                else:
                    raise ValueError("2nd input  for polarisation must be a string")
                
            gap, phase=self.idgapphase(Ep=energy, mode=new_polarisation)
        except:
            raise #re-raise any exception from above try block

        if self.feedbackPV is not None and not self.SCANNING:
            #stop feedback
            from gdascripts.utils import caput
            caput(self.feedbackPV, 1)        
            self.moveDevices(gap, new_polarisation, phase, energy)
            self.waitWhileBusy()
            caput(self.feedbackPV, 0)
        else:
            self.moveDevices(gap, new_polarisation, phase, energy)

    def isBusy(self):
        '''checks the busy status of all child scannables.
        If and only if all child scannables are done this will be set to False.
        '''
        if self.getName() == "dummyenergy" or self.getName()=="dummypolarisation":
            sleep(0.1)
            return False
        else: #real hardware
            self._busy=0
            for s in self.scannables.getGroupMembers():
                try:
                    self._busy += s.isBusy()
                except:
                    print (s.getName() + " isBusy() throws exception ", sys.exc_info())
                    raise
            if self._busy == 0:
                return 0
            else:
                return 1

    def stop(self):
        self.mono_energy.stop()
        if installation.isLive():
            print("ID motion stop is not supported according to ID-Group instruction. Please wait for the Gap motion to complete!")
        else:  
            self.idscannable.stop()

    def atScanStart(self):
        self.rawGetPosition() #ensure ID hardware in sync at start of scan
        self.SCANNING=True
 
    def atScanEnd(self):
        self.SCANNING=False
Example #35
0
    def __init__(self, name):
        self.name = name
        self.inputNames = ['epoch']
        self.extraNames = []
        self.outputFormat = ['%.3f']
        self.level = 9
        self.target_time = None

    def asynchronousMoveTo(self, time):
        self.target_time = time
        
    def isBusy(self):
        if self.target_time is None:
            return False
        return time.time() <= self.target_time
    
    def getPosition(self):
        return time.time()
       

t = TimeSinceScanStart('t')
dt = TimeSinceLastGetPosition("dt")
w = Wait("w")
clock = TimeOfDay('clock')
epoch = TimeSinceEpoch('epoch')

timerelated = ScannableGroup()
timerelated.setName("timerelated")
timerelated.setGroupMembers([t, dt, w, clock, epoch])
Example #36
0
class BeamEnergy(ScannableMotionBase):
    '''Create beam energy scannable that encapsulates and fan-outs control to ID gap and DCM energy.
    
        This pseudo device requies a lookup table object to provide ID parameters for calculation of ID gap from beam 
        energy required and harmonic order. The lookup table object must be created before the instance creation of this class.
        The child scannables or pseudo devices must exist in jython's global namespace prior to any method call of this class 
        instance.
        The lookup Table object is described by gda.function.LookupTable class.'''
        
    def __init__(self, name, gap="jgap", dcm="pgmenergy", undulatorperiod=27, lut="JIDCalibrationTable.txt"):
        '''Constructor - Only succeed if it find the lookup table, otherwise raise exception.'''
        self.lut=readLookupTable(LocalProperties.get("gda.config")+"/lookupTables/"+lut)
        self.gap=gap
        self.dcm=dcm
        self.lambdau=undulatorperiod
        if dcm is None:
            self.scannableNames=[gap]
        else:
            self.scannableNames=[dcm,gap]
        self.scannables=ScannableGroup(name, [Finder.find(x) for x in self.scannableNames])
        self._busy=0
        self.setName(name)
        self.setLevel(3)
        self.setOutputFormat(["%10.6f"])
        self.inputNames=[name]
        if self.dcm == "dcmenergy":
            self.order=3
        else:
            self.order=1
        self.energy=self.scannables.getGroupMember(self.scannableNames[0]).getPosition()
        self.polarisation='H'
    
    def setPolarisation(self, value):
        if self.getName()=="jenergy":
            if value == "H" or value == "V":
                self.polarisation=value
            else:
                raise ValueError("Input "+str(value)+" invalid. Valid values are 'H' or 'V'.")
        else:
            print "No polaristion parameter for Hard X-ray ID"
    
    def getPolarisation(self):
        if self.getName()=="jenergy":
            return self.polarisation
        else:
            return "No polaristion parameter for Hard X-ray ID"
    
    def HarmonicEnergyRanges(self):
        print ("%s\t%s\t%s" % ("Harmonic", "Min Energy", "Max Energy"))
        keys=[int(key) for key in self.lut.keys()]
        for key in sorted(keys):
            print ("%8.0d\t%10.2f\t%10.2f" % (key,self.lut[key][2],self.lut[key][3]))
            
    def eneryRangeForOrder(self, order):
        return [self.lut[order][2],self.lut[order][3]]
        
    def setOrder(self,n):
        self.order=n
        
    def getOrder(self):
        return self.order
    
    def idgap(self, Ep, n):
        gap=20.0
        if self.getName() == "ienergy":
            lambdaU=self.lambdau
            M=4
            h=16
            me=0.510999
            gamma=1000*self.lut[n][0]/me
            Ksquared=(4.959368e-6*(n*gamma*gamma/(lambdaU*Ep))-2)
            if Ksquared < 0:
                raise ValueError("Ksquared must be positive!")
            K=math.sqrt(Ksquared)
            A=(2*0.0934*lambdaU*self.lut[n][1]*M/math.pi)*math.sin(math.pi/M)*(1-math.exp(-2*math.pi*h/lambdaU))
            gap=(lambdaU/math.pi) * math.log(A/K)+self.lut[n][6]
#            if self.gap=="igap" and (gap<5.1 or gap>9.1):
#                raise ValueError("Required Hard X-Ray ID gap is out side allowable bound (5.1, 9.1)!")
            if self.gap=="jgap" and gap<16:
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (>=16)!")
        elif (self.getName() == "jenergy" and self.getPolarisation()=="H"):
            if (Ep<0.11 or Ep > 1.2):
                raise ValueError("Demanding energy must lie between 0.11 and 1.2 keV!")
            Epgap = Ep*1000
#            gap=3.46389+0.17197*Epgap + -5.84455e-4*Epgap**2 + 1.43759e-6*Epgap**3 + -2.2321e-9*Epgap**4 + 2.09444e-12*Epgap**5 + -1.07453e-15*Epgap**6 + 2.3039e-19*Epgap**7 
            gap= 0.70492 + 232.97156*Ep - 1100.88615*Ep**2 + 3841.94972*Ep**3 - 8947.83296*Ep**4 + 13823.07663*Ep**5 - 13942.57738*Ep**6 + 8816.18277*Ep**7 - 3170.55571*Ep**8 + 495.16057*Ep**9
            if self.gap=="jgap" and (gap<16 or gap>200):
                raise ValueError("Required Soft X-Ray ID gap is below the lower bound 0f 16 mm!")
        elif self.getName() == "jenergy" and self.getPolarisation()=="V":
            if (Ep<0.21 or Ep > 1.2):
                raise ValueError("Demanding energy must lie between 0.21 and 1.2 keV!")
            gap = 4.02266 + 89.86963*Ep - 220.65942*Ep**2 + 365.46127*Ep**3 - 168.84016*Ep**4 - 560.87782*Ep**5 + 1255.06201*Ep**6 - 1164.15704*Ep**7 + 531.63871*Ep**8 - 97.25326*Ep**9
            if self.gap=="jgap" and (gap<16.05 or gap>40.24):
                raise ValueError("Required Soft X-Ray ID gap is out side allowable bound (16.05, 40.24)!")
        else:
            raise ValueError("Unsupported scannable or polarisation mode")
        return gap
        
    def rawGetPosition(self):
        '''returns the current position of the beam energy.'''
        self.energy=self.scannables.getGroupMember(self.scannableNames[0]).getPosition()
        return self.energy;
    
    def calc(self, energy, order):
        return self.idgap(energy, order)

    def rawAsynchronousMoveTo(self, new_position):
        '''move beam energy to specified value.
        At the background this moves both ID gap and Mono Bragg to the values corresponding to this energy.
        If a child scannable can not be reached for whatever reason, it just prints out a message, then continue to next.'''
        self.energy = float(new_position)
        gap = 7
        try:
            if self.getName() == "dummyenergy":
                gap=self.energy
            else:
                gap=self.idgap(self.energy, self.order)
        except:
            raise
        if self.getName() == "ienergy":
            if self.energy<self.eneryRangeForOrder(self.order)[0] or self.energy>self.eneryRangeForOrder(self.order)[1]:
                raise ValueError("Requested photon energy is out of range for this harmonic!")
        for s in self.scannables.getGroupMembers():
            if s.getName() == self.gap:
                try:
                    s.asynchronousMoveTo(gap)
                except:
                    print "cannot set " + s.getName() + " to " + str(gap)
                    raise
            else:
                try:
                    if s.getName() == "pgmenergy":
                        s.asynchronousMoveTo(self.energy*1000)
                        # caput("ELECTRON-ANALYSER-01:TEST:EXCITATION_ENERGY", self.energy*1000)
                    else:
                        s.asynchronousMoveTo(self.energy)
                        # caput("ELECTRON-ANALYSER-01:TEST:EXCITATION_ENERGY", self.energy*1000)
                except:
                    print "cannot set " + s.getName() + " to " + str(self.energy)
                    raise
                
    def isBusy(self):
        '''checks the busy status of all child scannable.
        
        If and only if all child scannable are done this will be set to False.'''  
        self._busy=0      
        for s in self.scannables.getGroupMembers():
            try:
                self._busy += s.isBusy()
            except:
                print s.getName() + " isBusy() throws exception ", sys.exc_info()
                raise
        if self._busy == 0:
            return 0
        else:
            return 1

    def toString(self):
        '''formats what to print to the terminal console.'''
        return self.name + " : " + str(self.rawGetPosition())