def prepareForCollection(self): """ Method called before a scan starts. May be used to setup detector for collection, for example MAR345 uses this to erase. """ if self.verbose: simpleLog("%s:%s() started... collectionTime=%r" % (self.name, self.pfuncname(), self.collectionTime)) #self.setupZebra() Doing this every time adds 40 seconds to the time it takes to prepare the scan self.acquire_time_in_pulses = self.collectionTime * 10 # 10Hz self.pvs['PC_GATE_NGATE'].caput(TIMEOUT, self.acquire_time_in_pulses) self.pvs['PC_PULSE_STEP'].caput(TIMEOUT, self.acquire_time_per_pulse_s + 0.001) self.pvs['PC_PULSE_DLY'].caput(TIMEOUT, self.acquire_time_per_pulse_s) # PC_PULSE is only used to determine when the capture is performed. # If PC_PULSE_DLY were less than acquire_time_per_pulse_s then the # capture of the final point would be too early and we would miss some # counts. self.pvs['PULSE1_DLY'].caput(TIMEOUT, self.absolute_delay_after_rise_s) self.pvs['PULSE1_WID'].caput(TIMEOUT, self.acquire_time_per_pulse_s) self.pvs['PULSE2_DLY'].caput(TIMEOUT, self.absolute_delay_after_fall_s) self.pvs['PULSE2_WID'].caput(TIMEOUT, self.acquire_time_per_pulse_s) # Ensure that the SOFT_IN1 is reset so we don't think we have started collection already.. self.pvs['SOFT_IN:B0'].caput(TIMEOUT, 0) # SOFT_IN1 if self.verbose: simpleLog("%s:%s() completed." % (self.name, self.pfuncname())) # def endCollection(self): """ Method called at the end of collection to tell detector when a
def createsOwnFiles(self): """ Returns a value which indicates whether the detector creates its own files. If it does (return true) the readout() method returns the name of the latest file created as a string. If it does not (return false) the readout() method will return the data directly. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return False
def integratesBetweenPoints(self): """ Detectors that sample some value at the time of a trigger should return False. Detectors such as counter timers should return True. If true ,TrajectoryScanLine will generate a trigger half a point before the motor reaches a demanded point such that the resulting bin of data is centred on the demand position. Area detectors that will be triggered by the first pulse should also return true.""" if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return True
def moveTo(self, position): help_stop_me = ", to stop rocking run 'pos %s [%f 0]'" % (self.parent.name, self.centre) if self.parent.verbose: msg = self.name + ": Moving " + self.scannable.name + " to %f (%d)" % (position, self.rockCount) + help_stop_me simpleLog(msg) elif (datetime.now() - self.movelog_time) > timedelta(seconds=30): simpleLog("Continuously rocking" + help_stop_me) self.movelog_time = datetime.now() self.scannable.moveTo(position)
def run(self): if self.parent.verbose: simpleLog(self.name + ": Running...") while (self.running): self.moveTo(self.centre-self.delta) self.rockCount+=1 if not self.running or self.delta == 0: break self.moveTo(self.centre+self.delta) self.rockCount+=1 simpleLog(self.name + ": Stopped.")
def asynchronousMoveTo(self, position): assert(len(position)==2) if self.thread and self.thread.running: if (abs(self.thread.centre-position[0]) < 0.00001 and abs(self.thread.delta-position[1]) < 0.00001): simpleLog(self.name + ": New positions same as old.") return self.stop() self.thread.join() self.thread=RockerThread(self.name, self.scannable, position[0], position[1], self.rockCount, self) simpleLog(self.name + ": Starting RockerThread...") self.thread.start()
def collectData(self): """ Tells the detector to begin to collect a set of data, then returns immediately. """ if self.verbose: simpleLog("%s:%s() started... collectionTime=%r" % (self.name, self.pfuncname(), self.collectionTime)) # Ensure that the SOFT_IN1 is reset before RESET is performed to ensure # that the Arm is not triggered by the RESET. self.pvs['SOFT_IN:B0'].caput(TIMEOUT, 0) # SOFT_IN1 # Perform a Zebra RESET to clear the DIV counters. self.pvs['SYS_RESET.PROC'].caput(TIMEOUT, 1) # Reset the last number of points captured so we don't finish before we've started self.pvs['PC_NUM_CAP'].caput(TIMEOUT, 0) # Set the SOFT_IN1 so that the next PULSE1 will Arm the position compare self.pvs['SOFT_IN:B0'].caput(TIMEOUT, 1) """ This delays the start of the first count until the first PULSE so that we only ever count over the whole PULSE period and never get a partial pulse at the start of acquisition: Option 1, SOFT_IN1 goes high while IN1_TTL is Low: 10Hz (IN1_TTL) ____~~~~____~~~~____ SOFT_IN1 __~~~~~~~~~~~~~~~~~~ GATE1 __~~________________ Not GATE1 (OR1) ~~__~~~~~~~~~~~~~~~~ Arm triggers ^ Option 2, SOFT_IN1 goes high while IN1_TTL is High, : 10Hz (IN1_TTL) ____~~~~____~~~~____ SOFT_IN1 ______~~~~~~~~~~~~~~ GATE1 ______~~~~~~________ Not GATE1 (OR1) ~~~~~~______~~~~~~~~ Arm triggers ^ """ if self.verbose: simpleLog("%s:%s() completed." % (self.name, self.pfuncname())) # def setCollectionTime(self): """ Sets the collection time, in seconds, to be used during the next call of collectData. self.collectionTime defined by DetectorBase """ # def getCollectionTime(self): """ Returns the time, in seconds, the detector collects for during the
def setDelayAfterFall(self, delay_after_fall_s): """ Time from 10Hz fall to start of acquire, in seconds. """ if delay_after_fall_s < 0.: simpleLog( "Note that %s delay_after_fall_s (%r) < 0 so %rs will be added at acquire time." % (self.name, delay_after_fall_s, self.negative_offset)) self.absolute_delay_after_fall_s = delay_after_fall_s + self.negative_offset #low_limit = 0.05 #high_limit = 0.1-self.acquire_time_per_pulse_s else: self.absolute_delay_after_fall_s = delay_after_fall_s #low_limit = 0 #high_limit = 0.05-self.acquire_time_per_pulse_s # TODO: Work out how to sanity check these values. #if self.absolute_delay_after_fall_s < low_limit : # simpleLog("Warning, %r is less than %r so acquire time per pulse should be reduced for this delay." % (delay_after_fall_s, low_limit)) #if self.absolute_delay_after_fall_s > high_limit : # simpleLog("Warning, %r is more than %r so acquire time per pulse should be reduced for this delay." % (delay_after_fall_s, high_limit)) self.delay_after_fall_s = delay_after_fall_s
def readout(self): """ Returns the latest data collected. The size of the Object returned must be consistent with the values returned by getDataDimensions and getExtraNames. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) wait_count = 0 while True: sleep(.1) num_downloaded = int(float(self.pvs['PC_NUM_DOWN'].caget())) if num_downloaded == self.acquire_time_in_pulses: if self.verbose: simpleLog( "Number of points downloaded (%r) == acquire time in pulses (%r)" % (num_downloaded, self.acquire_time_in_pulses)) break if wait_count > 50: simpleLog( "Waiting for Number of points downloaded (%r) == acquire time in pulses (%r)" % (num_downloaded, self.acquire_time_in_pulses)) wait_count = 0 wait_count += 1 # TODO: We really should return different values when delays are negative, since this also swaps the signals mon_rise = float(self.pvs['PC_DIV1_LAST'].caget()) mon_fall = float(self.pvs['PC_DIV2_LAST'].caget()) det_rise = float(self.pvs['PC_DIV3_LAST'].caget()) det_fall = float(self.pvs['PC_DIV4_LAST'].caget()) return [ self.acquire_time_in_pulses * self.acquire_time_per_pulse_s, mon_rise, mon_fall, mon_rise - mon_fall, det_rise, det_fall, det_rise - det_fall ]
def getReadOutTime(self): if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return 0.1 # ToDo: Word out if zero is appropriate here
def getHardwareTriggerProvider(self): """ Get the HardwareTriggerProvider that represents the controller this Detector is wired to.""" if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return self.continuousMoveController
def getDetectorType(self): """ The type of detector. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return "FastDichroismZebraDetector"
def getDetectorID(self): """ A identifier for this detector. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return self.name
def getDescription(self): """ A description of the detector. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return "Fast Dicroism Zebra Detector"
def setupZebra(self): if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) DISCONNECT = 0 IN1_TTL = 1 IN2_TTL = 4 IN3_TTL = 7 PC_ARM = 29 AND1 = 32 AND2 = 33 AND3 = 34 AND4 = 35 OR1 = 36 GATE1 = 40 PULSE1 = 52 PULSE2 = 53 SOFT_IN1 = 60 Yes = 1 No = 0 TriggerOnRisingEdge = No TriggerOnFallingEdge = Yes DivFirstPulseNumbered1_OUTN = No # Perform a Zebra RESET to ensure all of the PVs can be configured. self.pvs['SYS_RESET.PROC'].caput(TIMEOUT, 1) # The Position compare is used to control the length of acquisition # according to the number of pulses acquired, and capture the # total number of detector pulses for each phase of the acquisition. self.pvs['PC_BIT_CAP:B0'].caput(TIMEOUT, No) # Enc1 self.pvs['PC_BIT_CAP:B1'].caput(TIMEOUT, No) # Enc2 self.pvs['PC_BIT_CAP:B2'].caput(TIMEOUT, No) # Enc3 self.pvs['PC_BIT_CAP:B3'].caput(TIMEOUT, No) # Enc4 self.pvs['PC_BIT_CAP:B4'].caput(TIMEOUT, No) # Sys1 self.pvs['PC_BIT_CAP:B5'].caput(TIMEOUT, No) # Sys2 self.pvs['PC_BIT_CAP:B6'].caput(TIMEOUT, Yes) # Div1 self.pvs['PC_BIT_CAP:B7'].caput(TIMEOUT, Yes) # Div2 self.pvs['PC_BIT_CAP:B8'].caput(TIMEOUT, Yes) # Div3 self.pvs['PC_BIT_CAP:B9'].caput(TIMEOUT, Yes) # Div4 self.pvs['PC_ARM_SEL'].caput(TIMEOUT, 'External') self.pvs['PC_ARM_INP'].caput(TIMEOUT, OR1) self.pvs['PC_GATE_SEL'].caput(TIMEOUT, 'External') self.pvs['PC_GATE_INP'].caput(TIMEOUT, PULSE2) # PC_PULSE is only used to determine when the capture is performed. # If PC_PULSE_DLY were less than acquire_time_per_pulse_s then the # capture of the final point would be too early and we would miss some # counts. self.pvs['PC_PULSE_SEL'].caput(TIMEOUT, 'Time') self.pvs['PC_TSPRE'].caput(TIMEOUT, 's') # The AND gates are used to ensure that Detector and Monitor signals # are gated according to both the appropriate windows and whether the # acquisition is in progress. self.pvs['AND1_ENA:B0'].caput(TIMEOUT, Yes) # INP1_ENA self.pvs['AND1_ENA:B1'].caput(TIMEOUT, Yes) # INP2_ENA self.pvs['AND1_ENA:B2'].caput(TIMEOUT, Yes) # INP3_ENA self.pvs['AND1_ENA:B3'].caput(TIMEOUT, No) # INP4_ENA self.pvs['AND1_INP1'].caput(TIMEOUT, IN2_TTL) self.pvs['AND1_INP2'].caput(TIMEOUT, PULSE1) self.pvs['AND1_INP3'].caput(TIMEOUT, PC_ARM) self.pvs['AND1_INP4'].caput(TIMEOUT, DISCONNECT) self.pvs['AND1_INV:B0'].caput(TIMEOUT, No) # INP1_INV self.pvs['AND1_INV:B1'].caput(TIMEOUT, No) # INP2_INV self.pvs['AND1_INV:B2'].caput(TIMEOUT, No) # INP3_INV self.pvs['AND1_INV:B3'].caput(TIMEOUT, No) # INP4_INV self.pvs['AND2_ENA:B0'].caput(TIMEOUT, Yes) # INP1_ENA self.pvs['AND2_ENA:B1'].caput(TIMEOUT, Yes) # INP2_ENA self.pvs['AND2_ENA:B2'].caput(TIMEOUT, Yes) # INP3_ENA self.pvs['AND2_ENA:B3'].caput(TIMEOUT, No) # INP4_ENA self.pvs['AND2_INP1'].caput(TIMEOUT, IN2_TTL) self.pvs['AND2_INP2'].caput(TIMEOUT, PULSE2) self.pvs['AND2_INP3'].caput(TIMEOUT, PC_ARM) self.pvs['AND2_INP4'].caput(TIMEOUT, DISCONNECT) self.pvs['AND2_INV:B0'].caput(TIMEOUT, No) # INP1_INV self.pvs['AND2_INV:B1'].caput(TIMEOUT, No) # INP2_INV self.pvs['AND2_INV:B2'].caput(TIMEOUT, No) # INP3_INV self.pvs['AND2_INV:B3'].caput(TIMEOUT, No) # INP4_INV self.pvs['AND3_ENA:B0'].caput(TIMEOUT, Yes) # INP1_ENA self.pvs['AND3_ENA:B1'].caput(TIMEOUT, Yes) # INP2_ENA self.pvs['AND3_ENA:B2'].caput(TIMEOUT, Yes) # INP3_ENA self.pvs['AND3_ENA:B3'].caput(TIMEOUT, No) # INP4_ENA self.pvs['AND3_INP1'].caput(TIMEOUT, IN3_TTL) self.pvs['AND3_INP2'].caput(TIMEOUT, PULSE1) self.pvs['AND3_INP3'].caput(TIMEOUT, PC_ARM) self.pvs['AND3_INP4'].caput(TIMEOUT, DISCONNECT) self.pvs['AND3_INV:B0'].caput(TIMEOUT, No) # INP1_INV self.pvs['AND3_INV:B1'].caput(TIMEOUT, No) # INP2_INV self.pvs['AND3_INV:B2'].caput(TIMEOUT, No) # INP3_INV self.pvs['AND3_INV:B3'].caput(TIMEOUT, No) # INP4_INV self.pvs['AND4_ENA:B0'].caput(TIMEOUT, Yes) # INP1_ENA self.pvs['AND4_ENA:B1'].caput(TIMEOUT, Yes) # INP2_ENA self.pvs['AND4_ENA:B2'].caput(TIMEOUT, Yes) # INP3_ENA self.pvs['AND4_ENA:B3'].caput(TIMEOUT, No) # INP4_ENA self.pvs['AND4_INP1'].caput(TIMEOUT, IN3_TTL) self.pvs['AND4_INP2'].caput(TIMEOUT, PULSE2) self.pvs['AND4_INP3'].caput(TIMEOUT, PC_ARM) self.pvs['AND4_INP4'].caput(TIMEOUT, DISCONNECT) self.pvs['AND4_INV:B0'].caput(TIMEOUT, No) # INP1_INV self.pvs['AND4_INV:B1'].caput(TIMEOUT, No) # INP2_INV self.pvs['AND4_INV:B2'].caput(TIMEOUT, No) # INP3_INV self.pvs['AND4_INV:B3'].caput(TIMEOUT, No) # INP4_INV # OR1 is being used as a NOT gate, since there is no option to invert # the output of GATE1 self.pvs['OR1_ENA:B0'].caput(TIMEOUT, Yes) # INP1_ENA self.pvs['OR1_ENA:B1'].caput(TIMEOUT, No) # INP2_ENA self.pvs['OR1_ENA:B2'].caput(TIMEOUT, No) # INP3_ENA self.pvs['OR1_ENA:B3'].caput(TIMEOUT, No) # INP4_ENA self.pvs['OR1_INP1'].caput(TIMEOUT, GATE1) self.pvs['OR1_INP2'].caput(TIMEOUT, DISCONNECT) self.pvs['OR1_INP3'].caput(TIMEOUT, DISCONNECT) self.pvs['OR1_INP4'].caput(TIMEOUT, DISCONNECT) self.pvs['OR1_INV:B0'].caput(TIMEOUT, Yes) # INP1_INV self.pvs['OR1_INV:B1'].caput(TIMEOUT, No) # INP2_INV self.pvs['OR1_INV:B2'].caput(TIMEOUT, No) # INP3_INV self.pvs['OR1_INV:B3'].caput(TIMEOUT, No) # INP4_INV # GATE1 is used to ensure that only whole acquisition windows are # acquired. See collectData() for details of how this works. self.pvs['GATE1_INP1'].caput(TIMEOUT, SOFT_IN1) self.pvs['POLARITY:B0'].caput(TIMEOUT, TriggerOnRisingEdge) # GATE1 Set self.pvs['GATE1_INP2'].caput(TIMEOUT, PULSE1) self.pvs['POLARITY:B4'].caput(TIMEOUT, TriggerOnRisingEdge) # GATE1 Reset # The DIV blocks are used to accumulate the detector counts during the # acquisition windows defined. MaxPulseCount = 1000000000 self.pvs['DIV1_INP'].caput(TIMEOUT, AND1) self.pvs['POLARITY:B8'].caput(TIMEOUT, TriggerOnRisingEdge) # DIV1 trigger self.pvs['DIV1_DIV'].caput(TIMEOUT, MaxPulseCount) self.pvs['DIV1_DIV'].caput( TIMEOUT, MaxPulseCount ) # Setting is not reliable, three times seems to be the charm self.pvs['DIV1_DIV'].caput( TIMEOUT, MaxPulseCount) # TODO: Remove when this fixed self.pvs['DIV_FIRST:B0'].caput(TIMEOUT, DivFirstPulseNumbered1_OUTN) # DIV1 self.pvs['DIV2_INP'].caput(TIMEOUT, AND2) self.pvs['POLARITY:B9'].caput(TIMEOUT, TriggerOnRisingEdge) # DIV2 trigger self.pvs['DIV2_DIV'].caput(TIMEOUT, MaxPulseCount) self.pvs['DIV2_DIV'].caput( TIMEOUT, MaxPulseCount ) # Setting is not reliable, three times seems to be the charm self.pvs['DIV2_DIV'].caput( TIMEOUT, MaxPulseCount) # TODO: Remove when this fixed self.pvs['DIV_FIRST:B1'].caput(TIMEOUT, DivFirstPulseNumbered1_OUTN) # DIV2 self.pvs['DIV3_INP'].caput(TIMEOUT, AND3) self.pvs['POLARITY:BA'].caput(TIMEOUT, TriggerOnRisingEdge) # DIV3 trigger self.pvs['DIV3_DIV'].caput(TIMEOUT, MaxPulseCount) self.pvs['DIV3_DIV'].caput( TIMEOUT, MaxPulseCount ) # Setting is not reliable, three times seems to be the charm self.pvs['DIV3_DIV'].caput( TIMEOUT, MaxPulseCount) # TODO: Remove when this fixed self.pvs['DIV_FIRST:B2'].caput(TIMEOUT, DivFirstPulseNumbered1_OUTN) # DIV3 self.pvs['DIV4_INP'].caput(TIMEOUT, AND4) self.pvs['POLARITY:BB'].caput(TIMEOUT, TriggerOnRisingEdge) # DIV4 self.pvs['DIV4_DIV'].caput(TIMEOUT, MaxPulseCount) self.pvs['DIV4_DIV'].caput( TIMEOUT, MaxPulseCount ) # Setting is not reliable, three times seems to be the charm self.pvs['DIV4_DIV'].caput( TIMEOUT, MaxPulseCount) # TODO: Remove when this fixed self.pvs['DIV_FIRST:B3'].caput(TIMEOUT, DivFirstPulseNumbered1_OUTN) # DIV4 self.pvs['PULSE1_INP'].caput(TIMEOUT, IN1_TTL) self.pvs['POLARITY:BC'].caput(TIMEOUT, TriggerOnRisingEdge) # PULSE1 trigger self.pvs['PULSE1_PRE'].caput(TIMEOUT, 's') self.pvs['PULSE2_INP'].caput(TIMEOUT, IN1_TTL) self.pvs['POLARITY:BD'].caput(TIMEOUT, TriggerOnFallingEdge) # PULSE2 trigger self.pvs['PULSE2_PRE'].caput(TIMEOUT, 's') if self.verbose: simpleLog("%s:%s() completed." % (self.name, self.pfuncname()))
def getDataDimensions(self): """ Returns the dimensions of the data object returned by the readout() method. """ if self.verbose: simpleLog("%s:%s() started..." % (self.name, self.pfuncname())) return [1]
def tomoScan( description, inBeamPosition, outOfBeamPosition, exposureTime=1.0, start=0.0, stop=180.0, step=0.1, darkFieldInterval=0, flatFieldInterval=0, imagesPerDark=10, imagesPerFlat=10, optimizeBeamInterval=0, pattern="default", tomoRotationAxis=0, addNXEntry=True, autoAnalyse=True, additionalScannables=[], ): """ Function to collect a tomography step scan Arguments: description - description of the scan or the sample that is being scanned. This is generally user-specific information that may be used to map to this scan later and is available in the NeXus file) inBeamPosition - position of X drive to move sample into the beam to take a projection outOfBeamPosition - position of X drive to move sample out of the beam to take a flat field image exposureTime - exposure time in seconds (default=1.0) start - first rotation angle (default=0.0) stop - last rotation angle (default=180.0) step - rotation step size (default=0.1) darkFieldInterval - number of projections between each dark-field sub-sequence. NOTE: at least 1 dark is ALWAYS taken both at the start and end of the scan provided imagesPerDark>0 (default=0: use this value if you DON'T want to take any darks between projections) flatFieldInterval - number of projections between each flat-field sub-sequence. NOTE: at least 1 flat is ALWAYS taken both at the start and end the scan provided imagesPerFlat>0 (default=0: use this value if you DON'T want to take any flats between projections) imagesPerDark - number of images to be taken for each dark-field sub-sequence (default=10) imagesPerFlat - number of images to be taken for each flat-field sub-sequence (default=10) General scan sequence is: D, F, P,..., P, F, D where D stands for dark field, F - for flat field, and P - for projection. """ dataFormat = LocalProperties.get("gda.data.scan.datawriter.dataFormat") try: darkFieldInterval = int(darkFieldInterval) flatFieldInterval = int(flatFieldInterval) optimizeBeamInterval = int(optimizeBeamInterval) jns = beamline_parameters.JythonNameSpaceMapping(InterfaceProvider.getJythonNamespace()) tomography_theta = jns.tomography_theta if tomography_theta is None: raise "tomography_theta is not defined in Jython namespace" tomography_shutter = jns.tomography_shutter if tomography_shutter is None: raise "tomography_shutter is not defined in Jython namespace" tomography_translation = jns.tomography_translation if tomography_translation is None: raise "tomography_translation is not defined in Jython namespace" tomography_detector = jns.tomography_detector if tomography_detector is None: raise "tomography_detector is not defined in Jython namespace" tomography_optimizer = jns.tomography_optimizer if tomography_optimizer is None: raise "tomography_optimizer is not defined in Jython namespace" tomography_time = jns.tomography_time if tomography_time is None: raise "tomography_time is not defined in Jython namespace" tomography_beammonitor = jns.tomography_beammonitor if tomography_beammonitor is None: raise "tomography_beammonitor is not defined in Jython namespace" tomography_camera_stage = jns.tomography_camera_stage if tomography_camera_stage is None: raise "tomography_camera_stage is not defined in Jython namespace" tomography_sample_stage = jns.tomography_sample_stage if tomography_sample_stage is None: raise "tomography_sample_stage is not defined in Jython namespace" tomo_additional_scannables = jns.tomography_additional_scannables if tomo_additional_scannables is None: raise "tomo_additional_scannables is not defined in Jython namespace" index = SimpleScannable() index.setCurrentPosition(0.0) index.setInputNames(["imageNumber"]) index.setName("imageNumber") index.configure() image_key = SimpleScannable() image_key.setCurrentPosition(0.0) image_key.setInputNames(["image_key"]) image_key.setName("image_key") image_key.configure() tomoScanDevice = make_tomoScanDevice( tomography_theta, tomography_shutter, tomography_translation, tomography_optimizer, image_key, index ) # return tomoScanDevice # generate list of positions numberSteps = ScannableUtils.getNumberSteps(tomography_theta, start, stop, step) theta_points = [] theta_points.append(start) previousPoint = start for i in range(numberSteps): nextPoint = ScannableUtils.calculateNextPoint(previousPoint, step) theta_points.append(nextPoint) previousPoint = nextPoint # generateScanPoints optimizeBeamNo = 0 optimizeBeamYes = 1 shutterOpen = 1 shutterClosed = 0 shutterNoChange = 2 scan_points = [] theta_pos = theta_points[0] index = 0 # Added shutterNoChange state for the shutter. The scan points are added using the (pseudo) ternary operator, # if index is 0 then the shutterPosition is added to the scan point, else shutterNoChange is added to scan points. for i in range(imagesPerDark): scan_points.append( ( theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index, ) ) # dark index = index + 1 for i in range(imagesPerFlat): scan_points.append( ( theta_pos, [shutterOpen, shutterNoChange][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index, ) ) # flat index = index + 1 scan_points.append((theta_pos, shutterOpen, inBeamPosition, optimizeBeamNo, image_key_project, index)) # first index = index + 1 imageSinceDark = 1 imageSinceFlat = 1 optimizeBeam = 0 for i in range(numberSteps): theta_pos = theta_points[i + 1] scan_points.append( ( theta_pos, [shutterOpen, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_project, index, ) ) # main image index = index + 1 imageSinceFlat = imageSinceFlat + 1 if imageSinceFlat == flatFieldInterval and flatFieldInterval != 0: for i in range(imagesPerFlat): scan_points.append( ( theta_pos, [shutterOpen, shutterNoChange][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index, ) ) index = index + 1 imageSinceFlat = 0 imageSinceDark = imageSinceDark + 1 if imageSinceDark == darkFieldInterval and darkFieldInterval != 0: for i in range(imagesPerDark): scan_points.append( ( theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index, ) ) index = index + 1 imageSinceDark = 0 optimizeBeam = optimizeBeam + 1 if optimizeBeam == optimizeBeamInterval and optimizeBeamInterval != 0: scan_points.append( ( theta_pos, [shutterOpen, shutterNoChange][i != 0], inBeamPosition, optimizeBeamYes, image_key_project, index, ) ) index = index + 1 optimizeBeam = 0 # add dark and flat only if not done in last steps if imageSinceFlat != 0: for i in range(imagesPerFlat): scan_points.append( ( theta_pos, [shutterOpen, shutterNoChange][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index, ) ) # flat index = index + 1 if imageSinceDark != 0: for i in range(imagesPerDark): scan_points.append( ( theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index, ) ) # dark index = index + 1 scan_points1 = generateScanPoints( inBeamPosition, outOfBeamPosition, theta_points, darkFieldInterval, flatFieldInterval, imagesPerDark, imagesPerFlat, optimizeBeamInterval, pattern=pattern, ) if pattern == "default" or pattern == "DFPFD": i = 0 for pt1 in scan_points1: pt = scan_points[i] if pt1 != pt: print "Mismatch - please tell Kaz about your scan and its arguments!" print "i = ", i print "pt = ", pt print "pt1 = ", pt1 i += 1 # return None positionProvider = tomoScan_positions( start, stop, step, darkFieldInterval, imagesPerDark, flatFieldInterval, imagesPerFlat, inBeamPosition, outOfBeamPosition, optimizeBeamInterval, scan_points, ) scan_args = [ tomoScanDevice, positionProvider, tomography_time, tomography_beammonitor, tomography_detector, exposureTime, tomography_camera_stage, tomography_sample_stage, ] # scan_args.append(RotationAxisScannable("approxCOR", tomoRotationAxis)) # meta_add(RotationAxisScannable("approxCOR", tomoRotationAxis)) # meta_add("RotationCoord_as_list", [tomoRotationAxis]) meta_add("approxCOR", tomoRotationAxis) for scannable in additionalScannables: scan_args.append(scannable) for scannable in tomo_additional_scannables: scan_args.append(scannable) """ setting the description provided as the title""" if not description == None: setTitle(description) else: setTitle("undefined") dataFormat = LocalProperties.get("gda.data.scan.datawriter.dataFormat") if not dataFormat == "NexusDataWriter": handle_messages.simpleLog( "Data format inconsistent. Setting 'gda.data.scan.datawriter.dataFormat' to 'NexusDataWriter'" ) LocalProperties.set("gda.data.scan.datawriter.dataFormat", "NexusDataWriter") scanObject = createConcurrentScan(scan_args) if addNXEntry: addNXTomoSubentry(scanObject, tomography_detector.name, tomography_theta.name) scanObject.runScan() if autoAnalyse: lsdp = jns.lastScanDataPoint() OSCommandRunner.runNoWait( ["/dls_sw/apps/tomopy/tomopy/bin/gda/tomo_at_scan_end", lsdp.currentFilename], OSCommandRunner.LOGOPTION.ALWAYS, None, ) return scanObject except InterruptedException: exceptionType, exception, traceback = sys.exc_info() handle_messages.log(None, "User interrupted the scan", exceptionType, exception, traceback, False) raise InterruptedException("User interrupted the scan") except: exceptionType, exception, traceback = sys.exc_info() handle_messages.log(None, "Error during tomography scan", exceptionType, exception, traceback, False) raise Exception("Error during tomography scan", exception) finally: handle_messages.simpleLog("Data Format reset to the original setting: " + dataFormat) LocalProperties.set("gda.data.scan.datawriter.dataFormat", dataFormat)
def tomoScanWithFrames(description, inBeamPosition, outOfBeamPosition, exposureTime=1., start=0., stop=180., step=0.1, darkFieldInterval=0, flatFieldInterval=0, imagesPerDark=10, imagesPerFlat=10, optimizeBeamInterval=0, pattern="default", nframes=1, tomoRotationAxis=0, addNXEntry=True, autoAnalyse=True, additionalScannables=[]): """ Function to collect a tomography step scan with multiple projection frames per scan point Arguments: description - description of the scan or the sample that is being scanned. This is generally user-specific information that may be used to map to this scan later and is available in the NeXus file) inBeamPosition - position of X drive to move sample into the beam to take a projection outOfBeamPosition - position of X drive to move sample out of the beam to take a flat field image exposureTime - exposure time in seconds (default=1.0) start - first rotation angle (default=0.0) stop - last rotation angle (default=180.0) step - rotation step size (default=0.1) darkFieldInterval - number of projection-frame sub-series between each dark-field sub-series. NOTE: at least 1 dark is ALWAYS taken both at the start and end of the scan, provided imagesPerDark>0 (default=0: use this value if you DON'T want to take any darks between projections) flatFieldInterval - number of projection-frame sub-series between each flat-field sub-series. NOTE: at least 1 flat is ALWAYS taken both at the start and end the scan, provided imagesPerFlat>0 (default=0: use this value if you DON'T want to take any flats between projections) imagesPerDark - number of images to be taken in each dark-field sub-series (default=10) imagesPerFlat - number of images to be taken in each flat-field sub-series (default=10) nframes - number of projection frames per angular position (default=1) General scan sequence is: D, F, P,..., P, F, D where D stands for dark field, F - for flat field, and P - for projection. """ dataFormat = LocalProperties.get("gda.data.scan.datawriter.dataFormat") try: darkFieldInterval = int(darkFieldInterval) flatFieldInterval = int(flatFieldInterval) optimizeBeamInterval = int(optimizeBeamInterval) image_key_frame = 3 nframes = int(nframes) if nframes < 1: nframes = 1 jns = beamline_parameters.JythonNameSpaceMapping( InterfaceProvider.getJythonNamespace()) tomography_theta = jns.tomography_theta if tomography_theta is None: raise NameError( "tomography_theta is not defined in Jython namespace") tomography_shutter = jns.tomography_shutter if tomography_shutter is None: raise NameError( "tomography_shutter is not defined in Jython namespace") tomography_translation = jns.tomography_translation if tomography_translation is None: raise NameError( "tomography_translation is not defined in Jython namespace") tomography_detector = jns.tomography_detector if tomography_detector is None: raise NameError( "tomography_detector is not defined in Jython namespace") tomography_optimizer = jns.tomography_optimizer if tomography_optimizer is None: raise NameError( "tomography_optimizer is not defined in Jython namespace") tomography_time = jns.tomography_time if tomography_time is None: raise NameError( "tomography_time is not defined in Jython namespace") tomography_beammonitor = jns.tomography_beammonitor if tomography_beammonitor is None: raise NameError( "tomography_beammonitor is not defined in Jython namespace") tomography_camera_stage = jns.tomography_camera_stage if tomography_camera_stage is None: raise NameError( "tomography_camera_stage is not defined in Jython namespace") tomography_sample_stage = jns.tomography_sample_stage if tomography_sample_stage is None: raise NameError( "tomography_sample_stage is not defined in Jython namespace") tomo_additional_scannables = jns.tomography_additional_scannables if tomo_additional_scannables is None: raise NameError( "tomo_additional_scannables is not defined in Jython namespace" ) index = SimpleScannable() index.setCurrentPosition(0.0) index.setInputNames(["imageNumber"]) index.setName("imageNumber") index.configure() image_key = SimpleScannable() image_key.setCurrentPosition(0.0) image_key.setInputNames(["image_key"]) image_key.setName("image_key") image_key.configure() tomoScanDevice = make_tomoScanDevice(tomography_theta, tomography_shutter, tomography_translation, tomography_optimizer, image_key, index) # return tomoScanDevice #generate list of positions numberSteps = ScannableUtils.getNumberSteps(tomography_theta, start, stop, step) theta_points = [] theta_points.append(start) previousPoint = start for i in range(numberSteps): nextPoint = ScannableUtils.calculateNextPoint(previousPoint, step) theta_points.append(nextPoint) previousPoint = nextPoint #generateScanPoints optimizeBeamNo = 0 optimizeBeamYes = 1 shutterOpen = 1 shutterClosed = 0 shutterNoChange = 2 scan_points = [] theta_pos = theta_points[0] index = 0 #Added shutterNoChange state for the shutter. The scan points are added using the (pseudo) ternary operator, #if index is 0 then the shutterPosition is added to the scan point, else shutterNoChange is added to scan points. for i in range(imagesPerDark): scan_points.append( (theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index)) #dark index = index + 1 for i in range(imagesPerFlat): scan_points.append( (theta_pos, [shutterOpen, shutterNoChange][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index)) #flat index = index + 1 for frm in range(nframes): scan_points.append( (theta_pos, shutterOpen, inBeamPosition, optimizeBeamNo, image_key_project if frm == 0 else image_key_frame, index)) #first index = index + 1 imageSinceDark = 1 imageSinceFlat = 1 optimizeBeam = 0 for i in range(numberSteps): theta_pos = theta_points[i + 1] for frm in range(nframes): scan_points.append( (theta_pos, [shutterOpen, shutterNoChange ][i != 0], inBeamPosition, optimizeBeamNo, image_key_project if frm == 0 else image_key_frame, index)) #main image index = index + 1 imageSinceFlat = imageSinceFlat + 1 if imageSinceFlat == flatFieldInterval and flatFieldInterval != 0: for i in range(imagesPerFlat): scan_points.append( (theta_pos, [shutterOpen, shutterNoChange ][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index)) index = index + 1 imageSinceFlat = 0 imageSinceDark = imageSinceDark + 1 if imageSinceDark == darkFieldInterval and darkFieldInterval != 0: for i in range(imagesPerDark): scan_points.append( (theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index)) index = index + 1 imageSinceDark = 0 optimizeBeam = optimizeBeam + 1 if optimizeBeam == optimizeBeamInterval and optimizeBeamInterval != 0: scan_points.append( (theta_pos, [shutterOpen, shutterNoChange][i != 0], inBeamPosition, optimizeBeamYes, image_key_project, index)) index = index + 1 optimizeBeam = 0 #add dark and flat only if not done in last steps if imageSinceFlat != 0: for i in range(imagesPerFlat): scan_points.append( (theta_pos, [shutterOpen, shutterNoChange][i != 0], outOfBeamPosition, optimizeBeamNo, image_key_flat, index)) #flat index = index + 1 if imageSinceDark != 0: for i in range(imagesPerDark): scan_points.append( (theta_pos, [shutterClosed, shutterNoChange][i != 0], inBeamPosition, optimizeBeamNo, image_key_dark, index)) #dark index = index + 1 # scan_points1 = generateScanPoints(inBeamPosition, outOfBeamPosition, theta_points, darkFieldInterval, flatFieldInterval, # imagesPerDark, imagesPerFlat, optimizeBeamInterval, pattern=pattern) # if pattern == 'default' or pattern == 'DFPFD': # i = 0 # for pt1 in scan_points1: # pt = scan_points[i] # if pt1 != pt: # print "Mismatch - please tell Kaz about your scan and its arguments!" # print "i = ", i # print "pt = ", pt # print "pt1 = ", pt1 # i += 1 #return None positionProvider = tomoScan_positions(start, stop, step, darkFieldInterval, imagesPerDark, flatFieldInterval, imagesPerFlat, \ inBeamPosition, outOfBeamPosition, optimizeBeamInterval, scan_points) scan_args = [ tomoScanDevice, positionProvider, tomography_time, tomography_beammonitor, tomography_detector, exposureTime, tomography_camera_stage, tomography_sample_stage ] #scan_args.append(RotationAxisScannable("approxCOR", tomoRotationAxis)) #meta_add(RotationAxisScannable("approxCOR", tomoRotationAxis)) #meta_add("RotationCoord_as_list", [tomoRotationAxis]) meta_add("approxCOR", tomoRotationAxis) for scannable in additionalScannables: scan_args.append(scannable) for scannable in tomo_additional_scannables: scan_args.append(scannable) ''' setting the description provided as the title''' if not description == None: setTitle(description) else: setTitle("undefined") dataFormat = LocalProperties.get("gda.data.scan.datawriter.dataFormat") if not dataFormat == "NexusDataWriter": handle_messages.simpleLog( "Data format inconsistent. Setting 'gda.data.scan.datawriter.dataFormat' to 'NexusDataWriter'" ) LocalProperties.set("gda.data.scan.datawriter.dataFormat", "NexusDataWriter") scanObject = createConcurrentScan(scan_args) if addNXEntry: addNXTomoSubentry(scanObject, tomography_detector.name, tomography_theta.name) scanObject.runScan() if autoAnalyse: lsdp = jns.lastScanDataPoint() OSCommandRunner.runNoWait([ "/dls_sw/apps/tomopy/tomopy/bin/gda/tomo_at_scan_end_kz", lsdp.currentFilename ], OSCommandRunner.LOGOPTION.ALWAYS, None) return scanObject except InterruptedException: exceptionType, exception, traceback = sys.exc_info() handle_messages.log(None, "User interrupted the scan", exceptionType, exception, traceback, False) raise InterruptedException("User interrupted the scan") except: exceptionType, exception, traceback = sys.exc_info() handle_messages.log(None, "Error during tomography scan", exceptionType, exception, traceback, False) raise Exception("Error during tomography scan", exception) finally: handle_messages.simpleLog( "Data Format reset to the original setting: " + dataFormat) LocalProperties.set("gda.data.scan.datawriter.dataFormat", dataFormat)
def localStation_exception(exc_info, msg): typ, exception, traceback = exc_info simpleLog("! Failure %s !" % msg) localStation_exceptions.append(" %s" % msg) handle_messages.log(None, "Error %s - " % msg , typ, exception, traceback, False)
wherescannables = [tth, th, chi, phi, h, k, l, en] # @UndefinedVariable try: wh = PositionWrapper(wherescannables) ##can only be used with diffcalc except: localStation_exception(sys.exc_info(), "create wh error.") alias('wh') from scannable.rocking.detectorWithRockingMotion import NXDetectorWithRockingMotion # @UnusedImport from gdaserver import pimte, pixis # @UnresolvedImport thpimte = NXDetectorWithRockingMotion("thpimte", th, pimte) thpixis = NXDetectorWithRockingMotion("thpixis", th, pixis) from scannable.positions.magnet_instances import magnetCurrent, magnetField # @UnusedImport #Please leave Panic stop customisation last - specify scannables to be excluded from Panic stop from i10commands.stopJythonScannables import stopJythonScannablesExceptExcluded # @UnusedImport STOP_ALL_EXCLUSIONS = [] # @UndefinedVariable if len(localStation_exceptions) > 0: simpleLog("=============== %r ERRORS DURING STARTUP ================" % len(localStation_exceptions)) for localStationException in localStation_exceptions: simpleLog(localStationException) print "**************************************************" print "localStation.py completed." print "**************************************************"