def __init__(self, release_config_file_path, parent=None): self.__log = logger.getLogger(__name__) self.__log.info("") super().__init__(parent) self.info = Config(release_config_file_path)['release'] self.projectChanged.connect(self.onProjectChanged) self._project_rcif_path = None self._samples_rcif_path = None self._experiment_rcif_path = None self._calculator_interface = QtCalculatorInterface(CryspyCalculator()) self._project_dict_copy = {} self._project_control = ProjectControl() self._measured_data_model = MeasuredDataModel() self._calculated_data_model = CalculatedDataModel() self._bragg_peaks_model = BraggPeaksModel() self._cell_parameters_model = CellParametersModel() self._cell_box_model = CellBoxModel() self._atom_sites_model = AtomSitesModel() self._atom_adps_model = AtomAdpsModel() self._atom_msps_model = AtomMspsModel() self._fitables_model = FitablesModel() self._status_model = StatusModel() self._refine_thread = None self._refinement_running = False self._refinement_done = False self._refinement_result = {} self._calculator_interface.clearUndoStack() self._need_to_save = False
def test_setPhaseDefinition(cal): calc = CryspyCalculator('') interface = QtCalculatorInterface(calc) interface.setPhaseDefinition(phase_path) phase_added = interface.getPhase('Fe3O4') phase_ref = cal.getPhase('Fe3O4') assert phase_added['phasename'] == phase_ref['phasename'] assert phase_added['spacegroup']['crystal_system'].value == phase_ref[ 'spacegroup']['crystal_system'].value assert phase_added['spacegroup'][ 'space_group_name_HM_ref'].value == phase_ref['spacegroup'][ 'space_group_name_HM_ref'].value assert phase_added['spacegroup'][ 'space_group_IT_number'].value == phase_ref['spacegroup'][ 'space_group_IT_number'].value assert phase_added['spacegroup']['origin_choice'].value == phase_ref[ 'spacegroup']['origin_choice'].value assert phase_added['cell']['length_a'].value == phase_ref['cell'][ 'length_a'].value assert phase_added['cell']['length_b'].value == phase_ref['cell'][ 'length_b'].value assert phase_added['cell']['length_c'].value == phase_ref['cell'][ 'length_c'].value assert phase_added['cell']['angle_alpha'].value == phase_ref['cell'][ 'angle_alpha'].value assert phase_added['cell']['angle_beta'].value == phase_ref['cell'][ 'angle_beta'].value assert phase_added['cell']['angle_gamma'].value == phase_ref['cell'][ 'angle_gamma'].value assert phase_added['atoms']['Fe3A']['fract_x'].value == phase_ref['atoms'][ 'Fe3A']['fract_x'].value assert phase_added['atoms']['Fe3B']['fract_y'].value == phase_ref['atoms'][ 'Fe3B']['fract_y'].value assert phase_added['atoms']['O']['fract_z'].value == phase_ref['atoms'][ 'O']['fract_z'].value
def test_CellBoxModelModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert m._x_role == 257 assert m._y_role == 258 assert m._z_role == 259 assert isinstance(m._model, QStandardItemModel) assert isinstance(m._project_dict, ProjectDict) assert len(m._model.roleNames()) == 3 # assure _setModelFromProject got called assert m._model.rowCount() == 3000 assert m._model.columnCount() == 1 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data(role=m._x_role) == 0.0 assert m._model.item(0, 0).data(role=m._y_role) == 0.0 assert m._model.item(0, 0).data(role=m._z_role) == 0.0 assert m._model.item(2999, 0).data(role=m._x_role) == 8.36212 assert m._model.item(2999, 0).data(role=m._y_role) == 8.36212 assert m._model.item(2999, 0).data(role=m._z_role) == pytest.approx(8.32867) # test asModel assert m._model == m.asModel()
def test_FileStructureModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) # assure _setModelFromProject got called assert m._model.rowCount() == 1 assert m._model.columnCount() == 1 phaseRole = Qt.UserRole + 1 expRole = Qt.UserRole + 2 calcRole = Qt.UserRole + 3 assert len(m._model.roleNames()) == 3 assert m._model.roleNames()[phaseRole] == b"phasesRole" assert str(m._model.roleNames()[expRole]) == "b'experimentsRole'" assert str(m._model.roleNames()[calcRole]) == "b'calculationsRole'" assert 'data_Fe3O4' in m._model.item(0, 0).data(role=phaseRole) assert 'data_pd' in m._model.item(0, 0).data(role=expRole) assert '_refln_index_k' in m._model.item(0, 0).data(role=calcRole)
def test_CellParametersModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert m._a_role == 257 assert m._gamma_role == 262 assert isinstance(m._model, QStandardItemModel) assert isinstance(m._project_dict, ProjectDict) assert len(m._model.roleNames()) == 6 # assure _setModelFromProject got called assert m._model.rowCount() == 1 assert m._model.columnCount() == 1 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data(role=m._a_role) == 8.36212 assert m._model.item(0, 0).data(role=m._b_role) == 8.36212 assert m._model.item(0, 0).data(role=m._c_role) == 8.36212 assert m._model.item(0, 0).data(role=m._alpha_role) == 90.0 assert m._model.item(0, 0).data(role=m._beta_role) == 90.0 assert m._model.item(0, 0).data(role=m._gamma_role) == 90.0 # test asModel assert m._model == m.asModel()
def test_CalculatedDataModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) assert isinstance(m._headers_model, QStandardItemModel) assert isinstance(m._project_dict, ProjectDict) # assure _setModelFromProject got called assert m._model.rowCount() == 381 assert m._model.columnCount() == 8 assert m._headers_model.rowCount() == 1 assert m._headers_model.columnCount() == 8 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data(role=Qt.DisplayRole) == 4.0 assert pytest.approx( m._model.item(0, 3).data(role=Qt.DisplayRole), 438.3046174533981) assert m._model.item(380, 0).data(role=Qt.DisplayRole) == 80.0 assert pytest.approx( m._model.item(380, 3).data(role=Qt.DisplayRole), -58.83263649312255) # test asModel assert m._model == m.asModel() assert m._headers_model == m.asHeadersModel()
def initialize(self): self.__log.info("") self._project_rcif_path = self._project_control.project_rcif_path #logging.info(self._calculator.asCifDict()) # TODO This is where you would choose the calculator and import the module self._calculator_interface = QtCalculatorInterface( CryspyCalculator(self._project_rcif_path)) self._calculator_interface.project_dict['app']['name'] = self.info[ 'name'] self._calculator_interface.project_dict['app']['version'] = self.info[ 'version'] self._calculator_interface.project_dict['app']['url'] = self.info[ 'url'] self._calculator_interface.projectDictChanged.connect( self.projectChanged) self._calculator_interface.canUndoOrRedoChanged.connect( self.canUndoOrRedoChanged) self._calculator_interface.clearUndoStack() # TODO generates dictdiffer # `ValueError: The truth value of an array with more than one element is ambiguous` # Temp fix - Andrew self.onProjectSaved() models = [ self._measured_data_model, self._calculated_data_model, self._bragg_peaks_model, self._cell_parameters_model, self._cell_box_model, self._atom_sites_model, self._atom_adps_model, self._atom_msps_model, self._fitables_model, self._status_model ] for model in models: model.setCalculatorInterface(self._calculator_interface) self._refine_thread = Refiner(self._calculator_interface, 'refine') self._refine_thread.failed.connect(self._thread_failed) self._refine_thread.finished.connect(self._thread_finished) self._refine_thread.finished.connect( self._status_model.onRefinementDone) # We can't link signals as the manager signals emitted before the dict is updated :-( self.projectChanged.emit()
def test_AtomMspsModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) assert isinstance(m._project_dict, ProjectDict) assert m._label_role == 257 assert m._chi23_role == 265 # assure _setModelFromProject got called assert m._model.rowCount() == 3 assert m._model.columnCount() == 1 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data() == 'Fe3A' assert m._model.item(0, 0).data(role=m._type_role) == 'Cani' assert m._model.item(0, 0).data(role=m._chiiso_role) == '' assert m._model.item(0, 0).data(role=m._chi11_role) == -3.468 assert m._model.item(0, 0).data(role=m._chi22_role) == -3.468 assert m._model.item(0, 0).data(role=m._chi33_role) == -3.468 assert m._model.item(0, 0).data(role=m._chi12_role) == 0.0 assert m._model.item(0, 0).data(role=m._chi13_role) == 0.0 assert m._model.item(0, 0).data(role=m._chi23_role) == 0.0 assert m._model.item(1, 0).data() == 'Fe3B' assert m._model.item(1, 0).data(role=m._type_role) == 'Cani' assert m._model.item(1, 0).data(role=m._chiiso_role) == '' assert m._model.item(1, 0).data(role=m._chi11_role) == 3.041 assert m._model.item(1, 0).data(role=m._chi22_role) == 3.041 assert m._model.item(1, 0).data(role=m._chi33_role) == 3.041 assert m._model.item(1, 0).data(role=m._chi12_role) == 0.0 assert m._model.item(1, 0).data(role=m._chi13_role) == 0.0 assert m._model.item(1, 0).data(role=m._chi23_role) == 0.0 assert m._model.item(2, 0).data() == 'O' assert m._model.item(2, 0).data(role=m._type_role) is None assert m._model.item(2, 0).data(role=m._chi11_role) is None assert m._model.item(2, 0).data(role=m._chi11_role) is None assert m._model.item(2, 0).data(role=m._chi22_role) is None assert m._model.item(2, 0).data(role=m._chi33_role) is None assert m._model.item(2, 0).data(role=m._chi12_role) is None assert m._model.item(2, 0).data(role=m._chi13_role) is None assert m._model.item(2, 0).data(role=m._chi23_role) is None # test asModel assert m._model == m.asModel()
def test_addExperimentDefinition(cal): calc = CryspyCalculator('') interface = QtCalculatorInterface(calc) interface.setPhaseDefinition(phase_path) interface.addExperimentDefinition(exp_path) exp_added = interface.getExperiment('pd') exp_ref = cal.getExperiment('pd') assert exp_added['name'] == exp_ref['name'] assert exp_added['wavelength'].value == exp_ref['wavelength'].value assert exp_added['offset'].value == exp_ref['offset'].value assert exp_added['phase']['Fe3O4']['name'] == exp_ref['phase']['Fe3O4'][ 'name'] assert exp_added['phase']['Fe3O4']['scale'].value == exp_ref['phase'][ 'Fe3O4']['scale'].value
def test_AtomSitesModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) assert isinstance(m._project_dict, ProjectDict) assert m._label_role == 257 assert m._occupancy_role == 263 # assure _setModelFromProject got called assert m._model.rowCount() == 3 assert m._model.columnCount() == 1 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data() == 'Fe3A' assert m._model.item(0, 0).data(role=m._atom_role) == 'Fe3+' assert m._model.item(0, 0).data(role=m._color_role) == 0.945 assert m._model.item(0, 0).data(role=m._x_role) == 0.125 assert m._model.item(0, 0).data(role=m._y_role) == 0.125 assert m._model.item(0, 0).data(role=m._z_role) == 0.125 assert m._model.item(0, 0).data(role=m._occupancy_role) == 1.0 assert m._model.item(1, 0).data() == 'Fe3B' assert m._model.item(1, 0).data(role=m._atom_role) == 'Fe3+' assert m._model.item(1, 0).data(role=m._color_role) == 0.945 assert m._model.item(1, 0).data(role=m._x_role) == 0.5 assert m._model.item(1, 0).data(role=m._y_role) == 0.5 assert m._model.item(1, 0).data(role=m._z_role) == 0.5 assert m._model.item(1, 0).data(role=m._occupancy_role) == 1.0 assert m._model.item(2, 0).data() == 'O' assert m._model.item(2, 0).data(role=m._atom_role) == 'O2-' assert m._model.item(2, 0).data(role=m._color_role) == 0.5803 assert m._model.item(2, 0).data(role=m._x_role) == 0.25521 assert m._model.item(2, 0).data(role=m._y_role) == 0.25521 assert m._model.item(2, 0).data(role=m._z_role) == 0.25521 assert m._model.item(2, 0).data(role=m._occupancy_role) == 1.0 # test asModel assert m._model == m.asModel()
def test_StatusModelModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._statusBarModel, QStandardItemModel) assert isinstance(m._chartDisplayModel, QStandardItemModel) # assure _setModelFromProject got called assert m._statusBarModel.rowCount() == 4 assert m._statusBarModel.columnCount() == 1 assert m._chartDisplayModel.rowCount() == 2 assert m._chartDisplayModel.columnCount() == 1 assert len(m._statusBarModel.roleNames()) == len(m._roles_dict['status']) assert len(m._chartDisplayModel.roleNames()) == len(m._roles_dict['plot']) assert b'label' in m._roles_dict['status'].values() assert b'value' in m._roles_dict['status'].values() assert b'label' in m._roles_dict['plot'].values() assert b'value' in m._roles_dict['plot'].values() fr = Qt.UserRole + 1 offset = 100 assert m._statusBarModel.item(0, 0).data(role=fr + 1) == pytest.approx(340.79) assert m._statusBarModel.item(2, 0).data(role=fr + 1) == 1 assert m._statusBarModel.item(3, 0).data(role=fr + 1) == 1 assert m._statusBarModel.item(1, 0).data(role=fr + 1) == 1 assert m._chartDisplayModel.item(0, 0).data(role=fr + offset + 1) == pytest.approx(340.79) assert m._chartDisplayModel.item(1, 0).data(role=fr + offset + 1) == 1 assert m._statusBarModel == m.returnStatusBarModel() assert m._chartDisplayModel == m.returnChartModel()
def test_MeasuredDataModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) assert isinstance(m._headers_model, QStandardItemModel) # assure _setModelFromProject got called assert m._model.rowCount() == 381 assert m._model.columnCount() == 9 assert m._headers_model.rowCount() == 1 assert m._headers_model.columnCount() == 9 # Test stuff from _setModelFromProject here assert m._model.item(0, 0).data(role=Qt.DisplayRole) == 4.0 assert m._model.item(0, 6).data(role=Qt.DisplayRole) == 128.97 assert m._model.item(380, 0).data(role=Qt.DisplayRole) == 80.0 assert m._model.item(380, 6).data(role=Qt.DisplayRole) == 27.81 assert m._headers_model.item(0, 0).data(role=Qt.DisplayRole) == 'x' assert m._headers_model.item(0, 1).data(role=Qt.DisplayRole) == 'y_obs' assert m._headers_model.item(0, 2).data(role=Qt.DisplayRole) == 'sy_obs' assert m._headers_model.item(0, 3).data(role=Qt.DisplayRole) == 'y_obs_diff' assert m._headers_model.item(0, 4).data(role=Qt.DisplayRole) == 'sy_obs_diff' assert m._headers_model.item(0, 5).data(role=Qt.DisplayRole) == 'y_obs_up' assert m._headers_model.item(0, 6).data(role=Qt.DisplayRole) == 'sy_obs_up' assert m._headers_model.item(0, 7).data(role=Qt.DisplayRole) == 'y_obs_down' assert m._headers_model.item(0, 8).data(role=Qt.DisplayRole) == 'sy_obs_down' # test asModel assert m._model == m.asModel() assert m._headers_model == m.asHeadersModel()
def test_FitablesModelModel(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) assert isinstance(m._model, QStandardItemModel) # assure _setModelFromProject got called assert m._model.rowCount() == 24 assert m._model.columnCount() == 1 assert len(m._model.roleNames()) == len(m._roles_dict) assert b'path' in m._roles_dict.values() assert b'refine' in m._roles_dict.values() # Test stuff from _setModelFromProject here # first and last row assert m._model.item(0, 0).data(role=Qt.UserRole+2) == 'phases Fe3O4 cell length_a' assert m._model.item(0, 0).data(role=Qt.UserRole+3) == 8.36212 assert m._model.item(0, 0).data(role=Qt.UserRole+4) == 0.0 assert m._model.item(0, 0).data(role=Qt.UserRole+5) == pytest.approx(6.68969) assert m._model.item(0, 0).data(role=Qt.UserRole+6) == 10.034544 assert m._model.item(0, 0).data(role=Qt.UserRole+7) is True assert m._model.item(0, 0).data(role=Qt.UserRole+8) == '\u212B' assert m._model.item(21, 0).data(role=Qt.UserRole+2) == 'experiments pd resolution y' assert m._model.item(21, 0).data(role=Qt.UserRole+3) == 0.0 assert m._model.item(21, 0).data(role=Qt.UserRole+4) == 0.0 assert m._model.item(21, 0).data(role=Qt.UserRole+5) == -1.0 assert m._model.item(21, 0).data(role=Qt.UserRole+6) == 1.0 assert m._model.item(21, 0).data(role=Qt.UserRole+7) is False assert m._model.item(21, 0).data(role=Qt.UserRole+8) == '' # test asModel assert m._model == m.asModel()
def test_creation_Empty(): calc = CryspyCalculator() interface = QtCalculatorInterface(calc)
def test_creation_WrongStr(): path = os.path.join(test_data, 'mainf.cif') calc = CryspyCalculator(path) interface = QtCalculatorInterface(calc)
def test_creation_None(): calc = CryspyCalculator(None) interface = QtCalculatorInterface(calc)
def cal(): calc = CryspyCalculator(file_path) interface = QtCalculatorInterface(calc) return interface
def test_setPhaseDefinition_EmptyStr(): calc = CryspyCalculator('') interface = QtCalculatorInterface(calc) interface.setPhaseDefinition('')
def test_setPhaseDefinition_None(): calc = CryspyCalculator('') interface = QtCalculatorInterface(calc) interface.setPhaseDefinition(None)
class ProxyPyQml(QObject): def __init__(self, release_config_file_path, parent=None): self.__log = logger.getLogger(__name__) self.__log.info("") super().__init__(parent) self.info = Config(release_config_file_path)['release'] self.projectChanged.connect(self.onProjectChanged) self._project_rcif_path = None self._samples_rcif_path = None self._experiment_rcif_path = None self._calculator_interface = QtCalculatorInterface(CryspyCalculator()) self._project_dict_copy = {} self._project_control = ProjectControl() self._measured_data_model = MeasuredDataModel() self._calculated_data_model = CalculatedDataModel() self._bragg_peaks_model = BraggPeaksModel() self._cell_parameters_model = CellParametersModel() self._cell_box_model = CellBoxModel() self._atom_sites_model = AtomSitesModel() self._atom_adps_model = AtomAdpsModel() self._atom_msps_model = AtomMspsModel() self._fitables_model = FitablesModel() self._status_model = StatusModel() self._refine_thread = None self._refinement_running = False self._refinement_done = False self._refinement_result = {} self._calculator_interface.clearUndoStack() self._need_to_save = False @Slot() def loadPhasesFromFile(self): """ Replace internal structure models based on requested content from CIF """ self._samples_rcif_path = self._project_control.phases_rcif_path self._calculator_interface.addPhaseDefinition(self._samples_rcif_path) # explicit emit required for the view to reload the model content self._calculator_interface.clearUndoStack() self.projectChanged.emit() self._need_to_save = False self.projectSaveStateChanged.emit() #self.onProjectUnsaved() @Slot() def loadExperiment(self): """ Selects the appropriate loading algorithm """ if self._project_control.experiment_file_format == "cif": self.loadExperimentFromCif() elif self._project_control.experiment_file_format == "xye": self.loadExperimentFromXye() else: raise IOError( "Unexpected experiment_file_format in ProjectControl.") def loadExperimentFromXye(self): """ Loads non cif data files, adds fake cif information, and loads """ cif_string = self._project_control._cif_string cif_string = cif_string.replace( "PHASE_NAME", self._calculator_interface.phasesIds()[0]) self._calculator_interface.addExperimentDefinitionFromString( cif_string) self._measured_data_model.setCalculatorInterface( self._calculator_interface) # explicit emit required for the view to reload the model content self._calculator_interface.clearUndoStack() self.projectChanged.emit() self._need_to_save = False self.projectSaveStateChanged.emit() #self.onProjectUnsaved() def loadExperimentFromCif(self): """ Replace internal experiment models based on requested content from CIF """ self._experiment_rcif_path = self._project_control.experiment_rcif_path self._calculator_interface.addExperimentDefinition( self._experiment_rcif_path) self._measured_data_model.setCalculatorInterface( self._calculator_interface) # explicit emit required for the view to reload the model content self._calculator_interface.updateCalculations() self._calculator_interface.clearUndoStack() self.projectChanged.emit() self._need_to_save = False self.projectSaveStateChanged.emit() #self.onProjectUnsaved() @Slot(str) def updateMainCifFromGui(self, cif_string): name_list = [ str_line for str_line in cif_string.split('\n') if str_line.startswith('_name ') ] if len(name_list) != 1: self.__log.warning( 'Project name can not be set. Returning previous value') return name = name_list[0].split('_name ')[1] if name[-1] == ' ': name = name[:-1] keywords_list = [ str_line for str_line in cif_string.split('\n') if str_line.startswith('_keywords ') ] if len(keywords_list) != 1: self.__log.warning( 'Project keywords can not be set. Returning previous values') return keywords = keywords_list[0].split('_keywords ')[1] if keywords[-1] == ' ': keywords = keywords[:-1] keywords = keywords.strip('\'') keywords = keywords.split(',') keywords = [ keyword[1:] if keyword[0] == ' ' else keyword for keyword in keywords ] keywords = [ keyword[:-1] if keyword[-1] == ' ' else keyword for keyword in keywords ] self._project_control.manager.projectName = name self._calculator_interface.setProjectName(name) self._project_control.manager.projectKeywords = keywords self._calculator_interface.setProjectKeywords(keywords) self._need_to_save = True self.projectSaveStateChanged.emit() @Slot(str) def updatePhaseFromGui(self, cif_string): phase_name = self._calculator_interface.phasesIds()[0] cif_string = cif_string[cif_string.find('data_'):] new_phase = self._calculator_interface.getPhaseFromCif(cif_string) old_phase = self._calculator_interface.getPhase(phase_name) keys, values, modifier = old_phase.dictComparison(new_phase) modded_keys = [['phases', phase_name, *key] for key, value in zip(keys, values) if key[-1] != 'mapping' and key[-1] != 'hide'] modded_values = [ value for key, value in zip(keys, values) if key[-1] != 'mapping' and key[-1] != 'hide' ] self._calculator_interface.project_dict.startBulkUpdate( 'Manual update of samples.cif') self._calculator_interface.project_dict.bulkUpdate( modded_keys, modded_values) self._calculator_interface.setCalculatorFromProject() self._calculator_interface.updateCalculations() self._calculator_interface.project_dict.endBulkUpdate() #self.projectChanged.emit() self._calculator_interface.projectDictChanged.emit() self._need_to_save = True self.projectSaveStateChanged.emit() @Slot(str) def updateExperimentFromGui(self, cif_string): exp_name = self._calculator_interface.experimentsIds()[0] cif_string = cif_string[cif_string.find('data_'):] new_experiment = self._calculator_interface.getExperimentFromCif( cif_string) old_exp = self._calculator_interface.getExperiment(exp_name) keys, values, modifier = old_exp.dictComparison(new_experiment) modded_keys = [['experiments', exp_name, *key] for key in keys if key[-1] != 'mapping' and key[-1] != 'hide'] modded_values = [ value for key, value in zip(keys, values) if key[-1] != 'mapping' and key[-1] != 'hide' ] self._calculator_interface.project_dict.startBulkUpdate( 'Manual update of experiments.cif') self._calculator_interface.project_dict.bulkUpdate( modded_keys, modded_values) self._calculator_interface.setCalculatorFromProject() self._calculator_interface.updateCalculations() self._calculator_interface.project_dict.endBulkUpdate() #self.projectChanged.emit() self._calculator_interface.projectDictChanged.emit() self._need_to_save = True self.projectSaveStateChanged.emit() # Load CIF method, accessible from QML @Slot() def initialize(self): self.__log.info("") self._project_rcif_path = self._project_control.project_rcif_path #logging.info(self._calculator.asCifDict()) # TODO This is where you would choose the calculator and import the module self._calculator_interface = QtCalculatorInterface( CryspyCalculator(self._project_rcif_path)) self._calculator_interface.project_dict['app']['name'] = self.info[ 'name'] self._calculator_interface.project_dict['app']['version'] = self.info[ 'version'] self._calculator_interface.project_dict['app']['url'] = self.info[ 'url'] self._calculator_interface.projectDictChanged.connect( self.projectChanged) self._calculator_interface.canUndoOrRedoChanged.connect( self.canUndoOrRedoChanged) self._calculator_interface.clearUndoStack() # TODO generates dictdiffer # `ValueError: The truth value of an array with more than one element is ambiguous` # Temp fix - Andrew self.onProjectSaved() models = [ self._measured_data_model, self._calculated_data_model, self._bragg_peaks_model, self._cell_parameters_model, self._cell_box_model, self._atom_sites_model, self._atom_adps_model, self._atom_msps_model, self._fitables_model, self._status_model ] for model in models: model.setCalculatorInterface(self._calculator_interface) self._refine_thread = Refiner(self._calculator_interface, 'refine') self._refine_thread.failed.connect(self._thread_failed) self._refine_thread.finished.connect(self._thread_finished) self._refine_thread.finished.connect( self._status_model.onRefinementDone) # We can't link signals as the manager signals emitted before the dict is updated :-( self.projectChanged.emit() @Slot() def createProjectZip(self): self.__log.debug("") self._calculator_interface.writeMainCif( self._project_control.tempDir.name) writeEmptyProject(self._project_control, self._project_control.project_file) self.onProjectSaved() @Slot(str) def createProject(self, file_path): self.__log.debug("") self._project_control.createProject(file_path) # Note that the main rcif of self._project_control.project_rcif_path has not ben cleared self._project_control.project_rcif_path = '' self.onProjectSaved() self.initialize() self.projectChanged.emit() @Slot(str) def saveProjectAs(self, file_path): self.__log.debug("") self._project_control.project_file = file_path self.saveProject() @Slot() def saveProject(self): self.__log.debug("") self._calculator_interface.saveCifs(self._project_control.tempDir.name) writeProject(self._project_control, self._project_control.project_file) self.onProjectSaved() def onProjectSaved(self): self.__log.debug("") self._project_dict_copy = deepcopy( self._calculator_interface.project_dict) self._need_to_save = False self.projectSaveStateChanged.emit() self.projectChanged.emit( ) # update project.cif in gui (when filenames changed) def onProjectUnsaved(self): self.__log.debug("") self._need_to_save = True self.projectSaveStateChanged.emit() def onProjectChanged(self): keys, _, _ = self._calculator_interface.project_dict.dictComparison( self._project_dict_copy) self.__log.debug(f"keys: {keys}") self._need_to_save = True if not keys: self._need_to_save = False self.__log.debug(f"needToSave: {self._need_to_save}") self.projectSaveStateChanged.emit() def calculatorInterface(self): self.__log.debug("---") return self._calculator_interface def needToSave(self): self.__log.debug("+++") return self._need_to_save def projectFilePathSelected(self): self.__log.debug("***") return bool(self._project_control.project_file) # ############## # QML Properties # ############## # Notifications of changes for QML GUI about projectDictChanged, # which calls another signal projectChanged projectChanged = Signal() projectSaveStateChanged = Signal() canUndoOrRedoChanged = Signal() _calculatorInterface = Property('QVariant', calculatorInterface, notify=projectChanged) _needToSave = Property(bool, needToSave, notify=projectSaveStateChanged) _projectFilePathSelected = Property(bool, projectFilePathSelected, notify=projectSaveStateChanged) _undoText = Property('QVariant', lambda self: self._calculator_interface.undoText(), notify=canUndoOrRedoChanged) _redoText = Property('QVariant', lambda self: self._calculator_interface.redoText(), notify=canUndoOrRedoChanged) _canUndo = Property('QVariant', lambda self: self._calculator_interface.canUndo(), notify=canUndoOrRedoChanged) _canRedo = Property('QVariant', lambda self: self._calculator_interface.canRedo(), notify=canUndoOrRedoChanged) # Notifications of changes for QML GUI are done, when needed, in the # respective classes via dataChanged.emit() or layotChanged.emit() signals _proxy = Property('QVariant', lambda self: self, constant=True) _releaseInfo = Property('QVariant', lambda self: self.releaseInfo, constant=True) _projectControl = Property('QVariant', lambda self: self._project_control, constant=True) _projectManager = Property('QVariant', lambda self: self._project_control.manager, constant=True) _measuredData = Property('QVariant', lambda self: self._measured_data_model, constant=True) _calculatedData = Property('QVariant', lambda self: self._calculated_data_model, constant=True) _braggPeaks = Property('QVariant', lambda self: self._bragg_peaks_model, constant=True) _cellParameters = Property( 'QVariant', lambda self: self._cell_parameters_model.asModel(), constant=True) _cellBox = Property('QVariant', lambda self: self._cell_box_model.asModel(), constant=True) _atomSites = Property('QVariant', lambda self: self._atom_sites_model.asModel(), constant=True) _atomAdps = Property('QVariant', lambda self: self._atom_adps_model.asModel(), constant=True) _atomMsps = Property('QVariant', lambda self: self._atom_msps_model.asModel(), constant=True) _fitables = Property('QVariant', lambda self: self._fitables_model.asModel(), constant=True) _statusInfo = Property( 'QVariant', lambda self: self._status_model.returnStatusBarModel(), constant=True) _chartInfo = Property('QVariant', lambda self: self._status_model.returnChartModel(), constant=True) _releaseInfo = Property('QVariant', lambda self: self.info, constant=True) # ############### # REFINEMENT TYPE # ############### def refineSum(self): if not self._calculator_interface.experimentsIds(): return False experiment_name = self._calculator_interface.experimentsIds()[0] return self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].sum def refineDiff(self): if not self._calculator_interface.experimentsIds(): return False experiment_name = self._calculator_interface.experimentsIds()[0] return self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].diff def setRefineSum(self, state): experiment_name = self._calculator_interface.experimentsIds()[0] if self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].sum == state: return self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].sum = state def setRefineDiff(self, state): experiment_name = self._calculator_interface.experimentsIds()[0] if self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].diff == state: return self._calculator_interface.project_dict['experiments'][ experiment_name]['refinement_type'].diff = state _refineSum = Property(bool, refineSum, setRefineSum, notify=projectChanged) _refineDiff = Property(bool, refineDiff, setRefineDiff, notify=projectChanged) # ########## # REFINEMENT # ########## def _thread_finished(self, res): """ Notfy the listeners about refinement results """ self._refinement_running = False self._refinement_done = True self._refinement_result = deepcopy(res) self.refinementStatusChanged.emit() def _thread_failed(self, reason): """ Notify the GUI about failure so a message can be shown """ self.__log.info("Refinement failed: " + str(reason)) self._refinement_running = False self._refinement_done = False self.refinementStatusChanged.emit() @Slot() def refine(self): """ Start refinement as a separate thread """ self._calculator_interface.setCalculatorFromProject() self.__log.info("") if self._refinement_running: self.__log.info("Fitting stopped") # This lacks actual stopping functionality, needs to be added self._refinement_running = False self._refinement_done = True self.refinementStatusChanged.emit() return self._refinement_running = True self._refinement_done = False self.refinementStatusChanged.emit() self._refine_thread.start() refinementStatusChanged = Signal() _refinementStatus = Property('QVariant', lambda self: [ self._refinement_running, self. _refinement_done, self._refinement_result ], notify=refinementStatusChanged) # ###### # REPORT # ###### @Slot(str) def store_report(self, report=""): """ Keep the QML generated HTML report for saving """ self.report_html = report @Slot(str, str) def save_report(self, filename="", extension=".HTML"): """ Save the generated report to the specified file Currently only html """ full_filename = filename + extension.lower() full_filename = os.path.join( self._project_control.get_project_dir_absolute_path(), full_filename) if not self.report_html: self.__log.info("No report to save") return if extension == '.HTML': # HTML can contain non-ascii, so need to open with right encoding with open(full_filename, 'w', encoding='utf-8') as report_file: report_file.write(self.report_html) self.__log.info("Report written") elif extension == '.PDF': document = QTextDocument(parent=None) document.setHtml(self.report_html) printer = QPdfWriter(full_filename) printer.setPageSize(printer.A3) # A3 to fit A4 page document.print_(printer) else: raise NotImplementedError # Show the generated report in the default browser url = os.path.realpath(full_filename) open_url(url=url)
def test_onModelChanged(): file_path = QUrl(TEST_FILE).toLocalFile() calculator = CryspyCalculator(file_path) interface = QtCalculatorInterface(calculator) m = Model() m.setCalculatorInterface(interface) phase_index = m._model.index(2, 0) # 3rd element (from phase block) experiment_index = m._model.index(m._model.rowCount()-3, 0) # 4th from below (from experiment block) # ###################### # Check unsupported role # ###################### edit_role = Qt.UserRole + 101 # path edit role new_edit = [] m._model.setData(phase_index, new_edit, edit_role) # ###################### # Check refine parameter # ###################### display_role = Qt.UserRole + 7 edit_role = Qt.UserRole + 107 old_display = False new_display = True old_edit = None new_edit = True # Initial state assert m._model.data(phase_index, display_role) == old_display assert m._model.data(phase_index, edit_role) == old_edit assert m._model.data(experiment_index, display_role) == old_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via display role m._model.setData(phase_index, new_display, display_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_display, display_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via edit role m._model.setData(phase_index, new_edit, edit_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_edit, edit_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # ##################### # Check value parameter # ##################### display_role = Qt.UserRole + 3 edit_role = Qt.UserRole + 103 old_display = 0 old_edit = None new_display = 0.5 new_edit = 0.5 # Initial state assert m._model.data(phase_index, display_role) == old_display assert m._model.data(phase_index, edit_role) == old_edit assert m._model.data(experiment_index, display_role) == old_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via display role m._model.setData(phase_index, new_display, display_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_display, display_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via edit role m._model.setData(phase_index, new_edit, edit_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_edit, edit_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via edit role outside min/max limits m._model.setData(phase_index, -100, Qt.UserRole + 103) assert m._model.data(phase_index, Qt.UserRole + 5) == -120 m._model.setData(phase_index, 100, Qt.UserRole + 103) assert m._model.data(phase_index, Qt.UserRole + 6) == 120 m._model.setData(phase_index, 1000, Qt.UserRole + 103) m._model.setData(phase_index, 1000, Qt.UserRole + 105) m._model.setData(phase_index, 1000, Qt.UserRole + 106) m._model.setData(phase_index, 100, Qt.UserRole + 103) assert m._model.data(phase_index, Qt.UserRole + 5) == 80 m._model.setData(phase_index, -1000, Qt.UserRole + 103) m._model.setData(phase_index, -1000, Qt.UserRole + 105) m._model.setData(phase_index, -1000, Qt.UserRole + 106) m._model.setData(phase_index, -100, Qt.UserRole + 103) assert m._model.data(phase_index, Qt.UserRole + 6) == -80 m._model.setData(phase_index, 0, Qt.UserRole + 105) m._model.setData(phase_index, 0, Qt.UserRole + 106) m._model.setData(phase_index, 0, Qt.UserRole + 103) assert m._model.data(phase_index, Qt.UserRole + 5) == -1 assert m._model.data(phase_index, Qt.UserRole + 6) == 1 m._model.setData(experiment_index, 0, Qt.UserRole + 105) m._model.setData(experiment_index, 0, Qt.UserRole + 106) m._model.setData(experiment_index, 0, Qt.UserRole + 103) assert m._model.data(experiment_index, Qt.UserRole + 5) == -1 assert m._model.data(experiment_index, Qt.UserRole + 6) == 1 # ################### # Check min parameter # ################### display_role = Qt.UserRole + 5 edit_role = Qt.UserRole + 105 old_display = -1 old_edit = None new_display = -0.5 new_edit = -0.5 # Initial state assert m._model.data(phase_index, display_role) == old_display assert m._model.data(phase_index, edit_role) == old_edit assert m._model.data(experiment_index, display_role) == old_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via display role m._model.setData(phase_index, new_display, display_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_display, display_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via edit role m._model.setData(phase_index, new_edit, edit_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_edit, edit_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # ################### # Check max parameter # ################### display_role = Qt.UserRole + 6 edit_role = Qt.UserRole + 106 old_display = 1 old_edit = None new_display = 0.5 new_edit = 0.5 # Initial state assert m._model.data(phase_index, display_role) == old_display assert m._model.data(phase_index, edit_role) == old_edit assert m._model.data(experiment_index, display_role) == old_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via display role m._model.setData(phase_index, new_display, display_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_display, display_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit # Model changes via edit role m._model.setData(phase_index, new_edit, edit_role) assert m._model.data(phase_index, display_role) == new_display assert m._model.data(phase_index, edit_role) == old_edit m._model.setData(experiment_index, new_edit, edit_role) assert m._model.data(experiment_index, display_role) == new_display assert m._model.data(experiment_index, edit_role) == old_edit