def test_fix_yaw(self) -> None: CloneWorkspace(InputWorkspace='test_workspace_TOF', OutputWorkspace='perturbed') RotateInstrumentComponent(Workspace='perturbed', ComponentName='bank1', X=0, Y=0, z=1, Angle=5, RelativeRotation=True) r"""Pass option FixYaw=True""" CorelliPowderCalibrationCreate(InputWorkspace='perturbed', OutputWorkspacesPrefix='cal_', TofBinning=[300, 1.0, 16666.7], PeakPositions=self.spacings_reference, SourceToSampleDistance=10.0, ComponentList='bank1', ComponentMaxTranslation=0.2, FixYaw=True, ComponentMaxRotation=10, Minimizer='L-BFGS-B') # Check no change in the rotations around Z-axis of first bank row = mtd['cal_displacements'].row(0) self.assertAlmostEquals(row['DeltaGamma'], 0.0, places=5) DeleteWorkspaces(['perturbed'])
def _create_workspaces(self): cal=CreateSampleWorkspace(NumBanks=1,BinWidth=20000,PixelSpacing=0.1,BankPixelWidth=100) RotateInstrumentComponent(cal, ComponentName='bank1', X=1, Y=0.5, Z=2, Angle=35) MoveInstrumentComponent(cal, ComponentName='bank1', X=1, Y=1, Z=5) bkg=CloneWorkspace(cal) data=CloneWorkspace(cal) AddSampleLog(cal, LogName="gd_prtn_chrg", LogType='Number', NumberType='Double', LogText='200') AddSampleLog(bkg, LogName="gd_prtn_chrg", LogType='Number', NumberType='Double', LogText='50') AddSampleLog(data, LogName="gd_prtn_chrg", LogType='Number', NumberType='Double', LogText='100') AddSampleLog(cal, LogName="duration", LogType='Number', NumberType='Double', LogText='20') AddSampleLog(bkg, LogName="duration", LogType='Number', NumberType='Double', LogText='5') AddSampleLog(data, LogName="duration", LogType='Number', NumberType='Double', LogText='10') def get_cal_counts(n): if n < 5000: return 0.9 else: return 1.0 def get_bkg_counts(n): return 1.5*get_cal_counts(n) def get_data_counts(n,twoTheta): tt1=30 tt2=45 return get_bkg_counts(n)+10*np.exp(-(twoTheta-tt1)**2/1)+20*np.exp(-(twoTheta-tt2)**2/0.2) for i in range(cal.getNumberHistograms()): cal.setY(i, [get_cal_counts(i)*2.0]) bkg.setY(i, [get_bkg_counts(i)/2.0]) twoTheta=data.getInstrument().getDetector(i+10000).getTwoTheta(V3D(0,0,0),V3D(0,0,1))*180/np.pi data.setY(i, [get_data_counts(i,twoTheta)]) return data, cal, bkg
def _correctForFractionalForegroundCentre(self, ws, summedForeground): """ This needs to be called after having summed the foreground but before transfering to momentum transfer. This needs to be called in both coherent and incoherent cases, regardless the angle calibration option. The reason for this is that up to this point is the fractional workspace index that correponds to the calibrated 2theta. However the momentum transfer calculation, which normally comes after summing the foreground, takes the 2theta from the spectrumInfo of the summed foreground workspace. Hence this code below translated the detector by the difference of the fractional and integer foreground centre along the detector plane. It also applies local rotation so that the detector continues to face the sample. Note that this translation has nothing to do with the difference of foreground centres in direct and reflected beams, which is handled already in pre-process algorithm. Here it's only about the difference of the fractional and integer foreground centre of the reflected beam with already calibrated angle no matter the option. Note also, that this could probably be avoided, if the loader placed the integer foreground at the given angle and not the fractional one. Fractional foreground centre only matter when calculating the difference between direct and reflected beams. But for the final Q (and sigma) calculation, it takes the position/angle from spectrumInfo()...(0), which corresponds to the centre of the pixel.""" foreground = self._foregroundIndices(ws) # integer foreground centre beamPosIndex = foreground[1] # fractional foreground centre linePosition = ws.run().getProperty( common.SampleLogs.LINE_POSITION).value l2 = ws.run().getProperty('L2').value instr = common.instrumentName(ws) pixelSize = common.pixelSize(instr) # the distance between the fractional and integer foreground centres along the detector plane dist = pixelSize * (linePosition - beamPosIndex) if dist != 0.: detPoint1 = ws.spectrumInfo().position(0) detPoint2 = ws.spectrumInfo().position(20) beta = numpy.math.atan2((detPoint2[0] - detPoint1[0]), (detPoint2[2] - detPoint1[2])) xvsy = numpy.math.sin(beta) * dist mz = numpy.math.cos(beta) * dist if instr == 'D17': mx = xvsy my = 0.0 rotationAxis = [0, 1, 0] else: mx = 0.0 my = xvsy rotationAxis = [-1, 0, 0] MoveInstrumentComponent(Workspace=summedForeground, ComponentName='detector', X=mx, Y=my, Z=mz, RelativePosition=True) angle_corr = numpy.arctan2(dist, l2) * 180 / numpy.pi RotateInstrumentComponent(Workspace=summedForeground, ComponentName='detector', X=rotationAxis[0], Y=rotationAxis[1], Z=rotationAxis[2], Angle=angle_corr, RelativeRotation=True) return summedForeground
def setUp(self) -> None: r"""Fixture runs at the beginning of every test method""" spacings_reference = [ 0.9179, 0.9600, 1.0451, 1.2458, 1.3576, 1.5677, 1.6374, 3.1353 ] # silicon # add one Gaussian peak for every reference d-spacing peak_functions = list() for spacing in spacings_reference: peak_function = f'name=Gaussian, PeakCentre={spacing}, Height={10 * np.sqrt(spacing)}, Sigma={0.003 * spacing}' peak_functions.append(peak_function) function = ';'.join(peak_functions) begin, end, bin_width = spacings_reference[ 0] - 0.5, spacings_reference[-1] + 0.5, 0.0001 # Single 10x10 rectangular detector, located 4m downstream the sample along the X-axis # Each detector has the same histogram of intensities, showing eight Gaussian peaks with centers at the # reference d-spacings CreateSampleWorkspace(WorkspaceType='Histogram', Function='User Defined', UserDefinedFunction=function, XUnit='dSpacing', XMin=begin, XMax=end, BinWidth=bin_width, NumBanks=1, PixelSpacing=0.02, SourceDistanceFromSample=10.0, BankDistanceFromSample=4.0, OutputWorkspace='test_workspace_dSpacing') RotateInstrumentComponent(Workspace='test_workspace_dSpacing', ComponentName='bank1', X=0., Y=1., z=0., Angle=90, RelativeRotation=True) MoveInstrumentComponent(Workspace='test_workspace_dSpacing', ComponentName='bank1', X=4.0, y=0.0, z=0.0, RelativePosition=False) # Eight peaks now in TOF. Only when the instrument is located 4m downstream along the X-axis will we obtain # the correct d-Spacings if we convert back to dSpacings units. If we perturb the instrument and convert # back to dSpacing units, we'll obtain eight peaks centered at d-spacings sligthly different than the # reference values ConvertUnits(InputWorkspace='test_workspace_dSpacing', Target='TOF', EMode='Elastic', OutputWorkspace='test_workspace_TOF') Rebin(InputWorkspace='test_workspace_TOF', Params=[300, 1.0, 16666.7], OutputWorkspace='test_workspace_TOF') ConvertUnits(InputWorkspace='test_workspace_TOF', Target='dSpacing', EMode='Elastic', OutputWorkspace='test_workspace_dSpacing') self.spacings_reference = spacings_reference
def test_rotation(self): CloneWorkspace(InputWorkspace='test_workspace_TOF', OutputWorkspace='perturbed') RotateInstrumentComponent(Workspace='perturbed', ComponentName='bank1', X=0, Y=0, z=1, Angle=5, RelativeRotation=True) assert self.spacings_recovered('perturbed', calibrate=False) is False assert self.spacings_recovered('perturbed', calibrate=True) DeleteWorkspaces(['perturbed'])
def serve_instrument(output_workspace): scattering_angle = 20 # in degrees # Instrument with four spectra. Each spectrum has one single Gaussian peak in TOF, centered at 10000 CreateSampleWorkspace(OutputWorkspace=output_workspace, BinWidth=0.1, NumBanks=1, BankPixelWidth=2, Function='User Defined', UserDefinedFunction='name=Gaussian, PeakCentre=10000, Height=100, Sigma=2', Xmin=9900, Xmax=10100, BankDistanceFromSample=2, SourceDistanceFromSample=20) MoveInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', RelativePosition=False, X=0, Y=0.0, Z=0) # move to the origin RotateInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', X=0, Y=1, Z=0, Angle=scattering_angle, RelativeRotation=False) sin, cos = np.sin(np.radians(scattering_angle)), np.cos(np.radians(scattering_angle)) # detector pixel width is 0.008m, perpendicular to the scattered beam. Detector is 2m away from the sample z, x = 2 * cos + 0.004 * sin, 2 * sin - 0.004 * cos MoveInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', RelativePosition=False, X=x, Y=0, Z=z) # translate 2 meters away and center the detector return mtd['original']
def testAlignComponentsRotationY(self): CreateSampleWorkspace(OutputWorkspace='testWS', NumBanks=1, BankPixelWidth=4) component = 'bank1' MoveInstrumentComponent(Workspace='testWS', ComponentName=component, X=2.00, Y=0, Z=2.00, RelativePosition=False) RotateInstrumentComponent(Workspace='testWS', ComponentName='bank1', X=0, Y=1, Z=0, Angle=50, RelativeRotation=False) ### Detector should rotate to +45deg around Y ### Calibration table generated with: # CreateSampleWorkspace(OutputWorkspace='sample2', NumBanks=1,BankPixelWidth=4) # MoveInstrumentComponent(Workspace='sample2',ComponentName='bank1',X=2.0,Y=0.0,Z=2.0,RelativePosition=False) # RotateInstrumentComponent(Workspace='sample2',ComponentName='bank1',X=0,Y=1,Z=0,Angle=45,RelativeRotation=False) # CalculateDIFC(InputWorkspace='sample2', OutputWorkspace='sample2') # d=mtd['sample2'].extractY() # for i in range(len(d)): # print "calTable.addRow(["+str(i+16)+", "+str(d[i][0])+"])" calTable = CreateEmptyTableWorkspace() calTable.addColumn("int", "detid") calTable.addColumn("double", "difc") calTable.addRow([16, 2481.89300158]) calTable.addRow([17, 2481.90717397]) calTable.addRow([18, 2481.94969]) calTable.addRow([19, 2482.02054626]) calTable.addRow([20, 2490.36640334]) calTable.addRow([21, 2490.38050851]) calTable.addRow([22, 2490.42282292]) calTable.addRow([23, 2490.49334316]) calTable.addRow([24, 2498.83911141]) calTable.addRow([25, 2498.85314962]) calTable.addRow([26, 2498.89526313]) calTable.addRow([27, 2498.96544859]) calTable.addRow([28, 2507.31101837]) calTable.addRow([29, 2507.32498986]) calTable.addRow([30, 2507.36690322]) calTable.addRow([31, 2507.43675513]) ws = mtd["testWS"] startPos = ws.getInstrument().getComponentByName(component).getPos() startRot = ws.getInstrument().getComponentByName( component).getRotation().getEulerAngles("YZX") #YZX AlignComponents(CalibrationTable="calTable", Workspace="testWS", ComponentList=component, AlphaRotation=True) ws = mtd["testWS"] endPos = ws.getInstrument().getComponentByName(component).getPos() endRot = ws.getInstrument().getComponentByName( component).getRotation().getEulerAngles("YZX") #YZX self.assertEqual(startPos, endPos) self.assertAlmostEqual(endRot[0], 45.0, places=0) self.assertEqual(startRot[1], endRot[1]) self.assertEqual(startRot[2], endRot[2])
def PyExec(self): fn = self.getPropertyValue("Filename") wsn = self.getPropertyValue("OutputWorkspace") #print (fn, wsn) self.fxml = self.getPropertyValue("InstrumentXML") #load data parms_dict, det_udet, det_count, det_tbc, data = self.read_file(fn) nrows = int(parms_dict['NDET']) #nbins=int(parms_dict['NTC']) xdata = np.array(det_tbc) xdata_mon = np.linspace(xdata[0], xdata[-1], len(xdata)) ydata = data.astype(np.float) ydata = ydata.reshape(nrows, -1) edata = np.sqrt(ydata) #CreateWorkspace(OutputWorkspace=wsn,DataX=xdata,DataY=ydata,DataE=edata, # NSpec=nrows,UnitX='TOF',WorkspaceTitle='Data',YUnitLabel='Counts') nr, nc = ydata.shape ws = WorkspaceFactory.create("Workspace2D", NVectors=nr, XLength=nc + 1, YLength=nc) for i in range(nrows): ws.setX(i, xdata) ws.setY(i, ydata[i]) ws.setE(i, edata[i]) ws.getAxis(0).setUnit('tof') AnalysisDataService.addOrReplace(wsn, ws) #self.setProperty("OutputWorkspace", wsn) #print ("ws:", wsn) #ws=mtd[wsn] # fix the x values for the monitor for i in range(nrows - 2, nrows): ws.setX(i, xdata_mon) self.log().information("set detector IDs") #set detetector IDs for i in range(nrows): ws.getSpectrum(i).setDetectorID(det_udet[i]) #Sample_logs the header values are written into the sample logs log_names = [sl.encode('ascii', 'ignore') for sl in parms_dict.keys()] log_values = [ sl.encode('ascii', 'ignore') if isinstance(sl, types.UnicodeType) else str(sl) for sl in parms_dict.values() ] AddSampleLogMultiple(Workspace=wsn, LogNames=log_names, LogValues=log_values) SetGoniometer(Workspace=wsn, Goniometers='Universal') if (self.fxml == ""): LoadInstrument(Workspace=wsn, InstrumentName="Exed", RewriteSpectraMap=True) else: LoadInstrument(Workspace=wsn, Filename=self.fxml, RewriteSpectraMap=True) RotateInstrumentComponent( Workspace=wsn, ComponentName='Tank', Y=1, Angle=-float(parms_dict['phi'].encode('ascii', 'ignore')), RelativeRotation=False) # Separate monitors into seperate workspace ExtractSpectra(InputWorkspace=wsn, WorkspaceIndexList=','.join( [str(s) for s in range(nrows - 2, nrows)]), OutputWorkspace=wsn + '_Monitors') MaskDetectors(Workspace=wsn, WorkspaceIndexList=','.join( [str(s) for s in range(nrows - 2, nrows)])) RemoveMaskedSpectra(InputWorkspace=wsn, OutputWorkspace=wsn) self.setProperty("OutputWorkspace", wsn)
def PyExec(self): fn = self.getPropertyValue("Filename") wsn = self.getPropertyValue("OutputWorkspace") monitor_workspace_name = self.getPropertyValue( "OutputMonitorWorkspace") if monitor_workspace_name == "": self.setPropertyValue("OutputMonitorWorkspace", wsn + '_Monitors') # print (fn, wsn) self.override_angle = self.getPropertyValue("AngleOverride") self.fxml = self.getPropertyValue("InstrumentXML") # load data parms_dict, det_udet, det_count, det_tbc, data = self.read_file(fn) nrows = int(parms_dict['NDET']) # nbins=int(parms_dict['NTC']) xdata = np.array(det_tbc) xdata_mon = np.linspace(xdata[0], xdata[-1], len(xdata)) ydata = data.astype(float) ydata = ydata.reshape(nrows, -1) edata = np.sqrt(ydata) # CreateWorkspace(OutputWorkspace=wsn,DataX=xdata,DataY=ydata,DataE=edata, # NSpec=nrows,UnitX='TOF',WorkspaceTitle='Data',YUnitLabel='Counts') nr, nc = ydata.shape ws = WorkspaceFactory.create("Workspace2D", NVectors=nr, XLength=nc + 1, YLength=nc) for i in range(nrows): ws.setX(i, xdata) ws.setY(i, ydata[i]) ws.setE(i, edata[i]) ws.getAxis(0).setUnit('tof') AnalysisDataService.addOrReplace(wsn, ws) # self.setProperty("OutputWorkspace", wsn) # print ("ws:", wsn) # ws=mtd[wsn] # fix the x values for the monitor for i in range(nrows - 2, nrows): ws.setX(i, xdata_mon) self.log().information("set detector IDs") # set detetector IDs for i in range(nrows): ws.getSpectrum(i).setDetectorID(det_udet[i]) # Sample_logs the header values are written into the sample logs log_names = [ str(sl.encode('ascii', 'ignore').decode()) for sl in parms_dict.keys() ] log_values = [ str(sl.encode('ascii', 'ignore').decode()) if isinstance( sl, UnicodeType) else str(sl) for sl in parms_dict.values() ] for i in range(len(log_values)): if ('nan' in log_values[i]) or ('NaN' in log_values[i]): log_values[i] = '-1.0' AddSampleLogMultiple(Workspace=wsn, LogNames=log_names, LogValues=log_values) SetGoniometer(Workspace=wsn, Goniometers='Universal') if (self.fxml == ""): LoadInstrument(Workspace=wsn, InstrumentName="Exed", RewriteSpectraMap=True) else: LoadInstrument(Workspace=wsn, Filename=self.fxml, RewriteSpectraMap=True) try: RotateInstrumentComponent( Workspace=wsn, ComponentName='Tank', Y=1, Angle=-float(parms_dict['phi'].encode('ascii', 'ignore')), RelativeRotation=False) except: self.log().warning( "The instrument does not contain a 'Tank' component. " "This means that you are using a custom XML instrument definition. " "OMEGA_MAG will be ignored.") self.log().warning( "Please make sure that the detector positions in the instrument definition are correct." ) # Separate monitors into seperate workspace __temp_monitors = ExtractSpectra( InputWorkspace=wsn, WorkspaceIndexList=','.join( [str(s) for s in range(nrows - 2, nrows)]), OutputWorkspace=self.getPropertyValue("OutputMonitorWorkspace")) # ExtractSpectra(InputWorkspace = wsn, WorkspaceIndexList = ','.join([str(s) for s in range(nrows-2, nrows)]), # OutputWorkspace = wsn + '_Monitors') MaskDetectors(Workspace=wsn, WorkspaceIndexList=','.join( [str(s) for s in range(nrows - 2, nrows)])) RemoveMaskedSpectra(InputWorkspace=wsn, OutputWorkspace=wsn) self.setProperty("OutputWorkspace", wsn) self.setProperty("OutputMonitorWorkspace", __temp_monitors)
def _sumForegroundInLambda(self, ws): """Sum the foreground region into a single histogram.""" foreground = self._foregroundIndices(ws) sumIndices = [i for i in range(foreground[0], foreground[2] + 1)] beamPosIndex = foreground[1] foregroundWSName = self._names.withSuffix('grouped') foregroundWS = ExtractSingleSpectrum(InputWorkspace=ws, OutputWorkspace=foregroundWSName, WorkspaceIndex=beamPosIndex, EnableLogging=self._subalgLogging) maxIndex = ws.getNumberHistograms() - 1 foregroundYs = foregroundWS.dataY(0) foregroundEs = foregroundWS.dataE(0) numpy.square(foregroundEs, out=foregroundEs) for i in sumIndices: if i == beamPosIndex: continue if i < 0 or i > maxIndex: self.log().warning( 'Foreground partially out of the workspace.') addeeWSName = self._names.withSuffix('addee') addeeWS = ExtractSingleSpectrum(InputWorkspace=ws, OutputWorkspace=addeeWSName, WorkspaceIndex=i, EnableLogging=self._subalgLogging) addeeWS = RebinToWorkspace(WorkspaceToRebin=addeeWS, WorkspaceToMatch=foregroundWS, OutputWorkspace=addeeWSName, EnableLogging=self._subalgLogging) ys = addeeWS.readY(0) foregroundYs += ys es = addeeWS.readE(0) foregroundEs += es**2 self._cleanup.cleanup(addeeWS) self._cleanup.cleanup(ws) numpy.sqrt(foregroundEs, out=foregroundEs) # Move the detector to the fractional linePosition linePosition = ws.run().getProperty( common.SampleLogs.LINE_POSITION).value instr = common.instrumentName(ws) pixelSize = common.pixelSize(instr) dist = pixelSize * (linePosition - beamPosIndex) if dist != 0.: detPoint1 = ws.spectrumInfo().position(0) detPoint2 = ws.spectrumInfo().position(20) beta = numpy.math.atan2((detPoint2[0] - detPoint1[0]), (detPoint2[2] - detPoint1[2])) xvsy = numpy.math.sin(beta) * dist mz = numpy.math.cos(beta) * dist if instr == 'D17': mx = xvsy my = 0.0 rotationAxis = [0, 1, 0] else: mx = 0.0 my = xvsy rotationAxis = [-1, 0, 0] MoveInstrumentComponent(Workspace=foregroundWS, ComponentName='detector', X=mx, Y=my, Z=mz, RelativePosition=True) theta = foregroundWS.spectrumInfo().twoTheta(0) / 2. RotateInstrumentComponent(Workspace=foregroundWS, ComponentName='detector', X=rotationAxis[0], Y=rotationAxis[1], Z=rotationAxis[2], Angle=theta, RelativeRotation=True) return foregroundWS
def testAlignComponentsPosition(self): r""" CreateSampleWorkspace here generates one bank of 2x2 pixels. All pixels have a single peak at TOF=10000 micro-seconds. The bank is facing the sample, centered along the vertical axis (Y), and at a scattering angle from the beam axis (Z). Because the pixels are at different locations, converting units to d-spacing results in peaks at different values of d-spacing. For the bank in this test we have: workspace index | 0 | 1 | 2 | 3 | ----------------------|--------|--------|--------|--------| detector ID | 4 | 5 | 6 | 6 | ----------------------|--------|--------|--------|--------| peack-center TOF |10000 | 10000 | 10000 | 10000 | ----------------------|--------|--------|--------|--------| peak-center d-spacing | 5.2070 | 5.2070 | 5.1483 | 5.1483 | The first workspace index corresponds to a pixel centered on the beam axis, hence the scattering angle is zero and the corresponding d-spacing is infinite. Correspondence betwee """ def serve_instrument(output_workspace): scattering_angle = 20 # in degrees # Instrument with four spectra. Each spectrum has one single Gaussian peak in TOF, centered at 10000 CreateSampleWorkspace(OutputWorkspace=output_workspace, BinWidth=0.1, NumBanks=1, BankPixelWidth=2, Function='User Defined', UserDefinedFunction='name=Gaussian, PeakCentre=10000, Height=100, Sigma=2', Xmin=9900, Xmax=10100, BankDistanceFromSample=2, SourceDistanceFromSample=20) MoveInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', RelativePosition=False, X=0, Y=0.0, Z=0) # move to the origin RotateInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', X=0, Y=1, Z=0, Angle=scattering_angle, RelativeRotation=False) sin, cos = np.sin(np.radians(scattering_angle)), np.cos(np.radians(scattering_angle)) # detector pixel width is 0.008m, perpendicular to the scattered beam. Detector is 2m away from the sample z, x = 2 * cos + 0.004 * sin, 2 * sin - 0.004 * cos MoveInstrumentComponent(Workspace=output_workspace, ComponentName='bank1', RelativePosition=False, X=x, Y=0, Z=z) # translate 2 meters away and center the detector return mtd['original'] serve_instrument('original') # Convert to d-spacing ConvertUnits(InputWorkspace='original', Target='dSpacing', EMode='Elastic', OutputWorkspace='original_dspacing') # Find the bin boundaries limiting the peak maximum Max(InputWorkspace='original_dspacing', OutputWorkspace='original_d_at_max') # Average the two bin boundaries to find the bin center, taken to be the location of the peak center original_d = np.average(mtd['original_d_at_max'].extractX(), axis=1) peak_positions = [5.1483, 5.2070] # reference peak positions in d-spacing (Angstroms) # Generate a table of peak centers in TOF units table_tofs = CreateEmptyTableWorkspace(OutputWorkspace='table_tofs') column_info = [('int', 'detid'), ('double', '@5.1483'), ('double', '@5.2070')] [table_tofs.addColumn(c_type, c_name) for c_type, c_name in column_info] table_tofs.addRow([4, float('nan'), 10000.0]) table_tofs.addRow([5, float('nan'), 10000.0]) # a peak in TOF correspoding to a peak of 306.5928 Angstroms table_tofs.addRow([6, 10000.0, float('nan')]) # a peak in TOF correspoding to a peak of 306.5928 Angstroms table_tofs.addRow([7, 10000.0, float('nan')]) # a peak in TOF correspoding to a peak of 216.7940 Angstroms # perturb the position of the bank with a translation or the order of a few milimeters component = 'bank1' xyz_shift = V3D(0.005, 0.010, 0.007) CloneWorkspace(InputWorkspace='original', OutputWorkspace='perturbed') MoveInstrumentComponent(Workspace='perturbed', ComponentName='bank1', RelativePosition=True, X=xyz_shift.X(), Y=xyz_shift.Y(), Z=xyz_shift.Z()) # calibrate the perturbed bank AlignComponents(PeakCentersTofTable='table_tofs', PeakPositions=peak_positions, OutputWorkspace='calibrated', InputWorkspace='perturbed', ComponentList=component, AdjustmentsTable='adjustments', Xposition=True, Yposition=True, Zposition=True) # compare the peak-centers (in d-spacing units) between the original and calibrated # spectra, up to 0.001 Angstroms ConvertUnits(InputWorkspace='calibrated', Target='dSpacing', EMode='Elastic', OutputWorkspace='calibrated_dspacing') Max(InputWorkspace='calibrated_dspacing', OutputWorkspace='calibrated_d_at_max') calibrated_d = np.average(mtd['calibrated_d_at_max'].extractX(), axis=1) assert np.allclose(original_d, calibrated_d, atol=0.001) # perturb the orientation of the bank with a rotation of a small angle around an axis almost parallel # to the vertical axis_shift, angle_shift = V3D(0.2, 0.8, np.sqrt(1 - 0.2 ** 2 - 0.8 ** 2)), 9.0 # angle shift in degrees CloneWorkspace(InputWorkspace='original', OutputWorkspace='perturbed') RotateInstrumentComponent(Workspace='perturbed', ComponentName='bank1', RelativeRotation=True, X=axis_shift.X(), Y=axis_shift.Y(), Z=axis_shift.Z(), Angle=angle_shift) ConvertUnits(InputWorkspace='perturbed', OutputWorkspace='perturbed_dspacing', Target='dSpacing', Emode='Elastic') # calibrate the perturbed bank AlignComponents(PeakCentersTofTable='table_tofs', PeakPositions=peak_positions, OutputWorkspace='calibrated', InputWorkspace='perturbed', ComponentList=component, AdjustmentsTable='adjustments', AlphaRotation=True, BetaRotation=True, GammaRotation=True) ConvertUnits(InputWorkspace='calibrated', OutputWorkspace='calibrated_dspacing', Target='dSpacing', Emode='Elastic') # compare the peak-centers (in d-spacing units) between the original and calibrated # spectra, up to 0.001 Angstroms Max(InputWorkspace='calibrated_dspacing', OutputWorkspace='calibrated_d_at_max') calibrated_d = np.average(mtd['calibrated_d_at_max'].extractX(), axis=1) assert np.allclose(original_d, calibrated_d, atol=0.001)
def get_target_instrument(self): self.ws_target = "ws_target" LoadEmptyInstrument(Filename="CORELLI_Definition.xml", OutputWorkspace=self.ws_target) ConvertToEventWorkspace(InputWorkspace=self.ws_target, OutputWorkspace=self.ws_target) # explicitly translate component TO designated location MoveInstrumentComponent( Workspace=self.ws_target, ComponentName="moderator", X=0, Y=0, Z=-19.9997, RelativePosition=False, ) MoveInstrumentComponent( Workspace=self.ws_target, ComponentName="sample-position", X=0, Y=0, Z=0, RelativePosition=False, ) MoveInstrumentComponent( Workspace=self.ws_target, ComponentName="bank7/sixteenpack", X=2.25637, Y=-0.814864, Z=-0.883485, RelativePosition=False, ) MoveInstrumentComponent( Workspace=self.ws_target, ComponentName="bank42/sixteenpack", X=2.58643, Y=0.0725628, Z=0.0868798, RelativePosition=False, ) MoveInstrumentComponent( Workspace=self.ws_target, ComponentName="bank57/sixteenpack", X=0.4545, Y=0.0788326, Z=2.53234, RelativePosition=False, ) # explicitly rotate component TO designated orientation RotateInstrumentComponent( Workspace=self.ws_target, ComponentName="bank7/sixteenpack", X=-0.0244456, Y=-0.99953, Z=-0.0184843, Angle=69.4926, RelativeRotation=False, ) RotateInstrumentComponent( Workspace=self.ws_target, ComponentName="bank42/sixteenpack", X=-0.011362, Y=-0.999935, Z=-0.000173303, Angle=91.8796, RelativeRotation=False, ) RotateInstrumentComponent( Workspace=self.ws_target, ComponentName="bank42/sixteenpack", X=-0.0158497, Y=-0.999694, Z=0.0189818, Angle=169.519, RelativeRotation=False, )