class XPCSProcessor(ParameterTree): def __init__(self, *args, **kwargs): super(XPCSProcessor, self).__init__() self._paramName = 'Algorithm' self._name = 'XPCS Processor' self.workflow = None self.param = None self._workflows = dict() self.listParameter = ListParameter(name=self._paramName, values={'': ''}, value='') self.param = Parameter(children=[self.listParameter], name=self._name) self.setParameters(self.param, showTop=False) def update(self, *_): for child in self.param.childs[1:]: child.remove() self.workflow = self._workflows.get(self.listParameter.value().name, self.listParameter.value()()) self._workflows[self.workflow.name] = self.workflow for process in self.workflow.processes: self.param.addChild(process.parameter)
class CorrelationParameterTree(ParameterTree): """Parameter tree that captures XPCS correlation adjustable parameters. Starting point to attempt to allow selecting an 'algorithm' and then repopulating the parameter tree accordingly. Any visible input parameters in the associated workflow will be adjustable here. The workflow can also be run here. """ def __init__(self, parent=None, showHeader=True, processor: Callable[[], None] = None): """Create the parameter tree, optionally providing a workflow. When a workflow is provided, Parameters ---------- parent See pyqtgraph.ParameterTree.__init__. showHeader See pyqtgraph.ParameterTree.__init__. processor If provided, creates a 'Run' button that is connected to the callable passed (default is None). For example, this callable could grab the necessary data to pass into a workflow, then execute it. """ super(CorrelationParameterTree, self).__init__(parent, showHeader) self._paramName = 'Algorithm' self._name = 'Correlation Processor' self.processor = processor self.param = None self.workflow = None self._workflows = dict() # List of algorithms available # key -> algorithm name (workflow.name) # value -> algorithm callable (workflow) self.listParameter = ListParameter(name=self._paramName, values={'':''}, value='') self.param = Parameter(name=self._name) self.param.addChild(self.listParameter) self.setParameters(self.param, showTop=False) if self.processor: # Button added separately since update removes then adds all children in self.param self.processButton = ActionParameter(name="Run") self.processButton.sigActivated.connect(self.processor) self.addParameters(self.processButton) def update(self, *_): """Update the parameter tree according to which algorithm (workflow) is selected.""" # for child in self.param.children(): # this doesn't seem to work... for child in self.param.childs[1:]: child.remove() # Based on current workflow (listParameter value), re-populate the tree. self.workflow = self._workflows.get(self.listParameter.value().name, self.listParameter.value()()) self._workflows[self.workflow.name] = self.workflow for operation in self.workflow.operations: self.param.addChild(Parameter(name=operation.name, type='group', children=operation.as_parameter()))
class DeviceProfiles(SettingsPlugin): sigRequestRedraw = Signal() sigRequestReduce = Signal() sigSimulateCalibrant = Signal() name = 'Device Profiles' def __init__(self): self.headermodel = None self.selectionmodel = None self.multiAI = MultiGeometry([]) self.AIs = dict() widget = ParameterTree() energy = SimpleParameter(name='Energy', type='float', value=10000, siPrefix=True, suffix='eV') wavelength = SimpleParameter(name='Wavelength', type='float', value=1.239842e-6 / 10000, siPrefix=True, suffix='m') self.parameter = Parameter(name="Device Profiles", type='group', children=[energy, wavelength]) widget.setParameters(self.parameter, showTop=False) icon = QIcon(str(path('icons/calibrate.png'))) super(DeviceProfiles, self).__init__(icon, "Device Profiles", widget) self.parameter.sigValueChanged.connect(self.sigRequestRedraw) self.parameter.sigValueChanged.connect(self.sigRequestReduce) self.parameter.sigTreeStateChanged.connect(self.simulateCalibrant) self.parameter.sigTreeStateChanged.connect(self.genAIs) self.parameter.sigValueChanged.connect(self.simulateCalibrant) def simulateCalibrant(self, *args): self.sigSimulateCalibrant.emit() def genAIs(self, parent, changes): for parameter, key, value in changes: if parameter.name == 'Wavelength': self.parameter.param('Energy').setValue( 1.239842e-6 / self.param('Wavelength').value(), blockSignal=self.parameter.sigTreeStateChanged) elif parameter.name == 'Energy': self.parameter.param('Wavelength').setValue( 1.239842e-6 / self.param('Energy').value(), blockSignal=self.WavelengthChanged) for parameter in self.parameter.children(): if isinstance(parameter, DeviceParameter): device = parameter.name() ai = self.AI(device) ai.set_wavelength(self.parameter['Wavelength']) ai.detector = parameter['Detector']() ai.detector.set_binning([parameter['Binning']] * 2) ai.detector.set_pixel1(parameter['Pixel Size X']) ai.detector.set_pixel2(parameter['Pixel Size Y']) fit2d = ai.getFit2D() fit2d['centerX'] = parameter['Center X'] fit2d['centerY'] = parameter['Center Y'] fit2d['directDist'] = parameter['Detector Distance'] * 1000 fit2d['tilt'] = parameter['Detector Tilt'] fit2d['tiltPlanRotation'] = parameter['Detector Rotation'] ai.setFit2D(**fit2d) def AI(self, device): if device not in self.AIs: self.addDevice(device) return self.AIs[device] def setAI(self, ai: AzimuthalIntegrator, device: str): self.AIs[device] = ai self.multiAI.ais = self.AIs.values() # propagate new ai to parameter fit2d = ai.getFit2D() try: self.setSilence(True) self.parameter.child(device, 'Detector').setValue(type(ai.detector)) self.parameter.child(device, 'Binning').setValue(ai.detector.binning[0]) self.parameter.child(device, 'Detector Tilt').setValue( fit2d['tiltPlanRotation']) self.parameter.child(device, 'Detector Rotation').setValue(fit2d['tilt']) self.parameter.child(device, 'Pixel Size X').setValue(ai.pixel1) self.parameter.child(device, 'Pixel Size Y').setValue(ai.pixel2) self.parameter.child(device, 'Center X').setValue(fit2d['centerX']) self.parameter.child(device, 'Center Y').setValue(fit2d['centerY']) self.parameter.child(device, 'Detector Distance').setValue( fit2d['directDist'] / 1000) self.parameter.child('Wavelength').setValue(ai.wavelength) finally: self.setSilence(False) self.simulateCalibrant() def setSilence(self, silence): if silence: self.parameter.sigTreeStateChanged.disconnect( self.simulateCalibrant) self.parameter.sigTreeStateChanged.disconnect(self.genAIs) else: self.parameter.sigTreeStateChanged.connect(self.simulateCalibrant) self.parameter.sigTreeStateChanged.connect(self.genAIs) def addDevice(self, device): try: self.setSilence(True) devicechild = DeviceParameter(device) self.parameter.addChild(devicechild) ai = AzimuthalIntegrator(wavelength=self.parameter['Wavelength']) self.AIs[device] = ai self.multiAI.ais = list(self.AIs.values()) finally: self.setSilence(False) def setModels(self, headermodel, selectionmodel): self.headermodel = headermodel self.headermodel.dataChanged.connect(self.dataChanged) self.selectionmodel = selectionmodel def dataChanged(self, start, end): devices = self.headermodel.item( self.selectionmodel.currentIndex()).header.devices() for device in devices: if device not in self.AIs: self.addDevice(device) def apply(self): AI = AzimuthalIntegrator( wavelength=self.parameter.child('Wavelength').value()) # if Calibration.isChecked(): # AI.setFit2D(self.getvalue('Detector Distance') * 1000., # self.getvalue('Center X'), # self.getvalue('Center Y'), # self.getvalue('Detector Tilt'), # 360. - self.getvalue('Detector Rotation'), # self.getvalue('Pixel Size Y') * 1.e6, # self.getvalue('Pixel Size X') * 1.e6) # elif self.wxdiffstyle.isChecked(): # AI.setFit2D(self.getvalue('Detector Distance') * 1000., # self.getvalue('Center X'), # self.getvalue('Center Y'), # self.getvalue('Detector Tilt') / 2. / np.pi * 360., # 360. - (2 * np.pi - self.getvalue('Detector Rotation')) / 2. / np.pi * 360., # self.getvalue('Pixel Size Y') * 1.e6, # self.getvalue('Pixel Size X') * 1.e6) # AI.set_wavelength(self.getvalue('Wavelength')) # # print AI activeCalibration = AI def save(self): self.apply() return self.parameter.saveState(filter='user') def restore(self, state): pass # self.parameter.restoreState(state, addChildren=False, removeChildren=False) def wavelengthChanged(self): self.param('Energy').setValue(1.239842e-6 / self.param('Wavelength').value(), blockSignal=self.EnergyChanged) def energyChanged(self): self.param('Wavelength').setValue(1.239842e-6 / self.param('Energy').value(), blockSignal=self.WavelengthChanged)