예제 #1
0
class CellParametersModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._a_role, self._b_role, self._c_role, self._alpha_role, self._beta_role, self._gamma_role = [
            Qt.UserRole + 1 + i for i in range(6)
        ]
        self._model.setItemRoleNames({
            self._a_role: b'length_a',
            self._b_role: b'length_b',
            self._c_role: b'length_c',
            self._alpha_role: b'angle_alpha',
            self._beta_role: b'angle_beta',
            self._gamma_role: b'angle_gamma'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set helper data list
            data = [{
                self._a_role:
                phase_dict.getItemByPath(['cell', 'length_a']).value,
                self._b_role:
                phase_dict.getItemByPath(['cell', 'length_b']).value,
                self._c_role:
                phase_dict.getItemByPath(['cell', 'length_c']).value,
                self._alpha_role:
                phase_dict.getItemByPath(['cell', 'angle_alpha']).value,
                self._beta_role:
                phase_dict.getItemByPath(['cell', 'angle_beta']).value,
                self._gamma_role:
                phase_dict.getItemByPath(['cell', 'angle_gamma']).value,
            }]
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data list created above
            for row_index, dict in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
예제 #2
0
class AtomMspsModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._label_role = Qt.UserRole + 1
        self._type_role = Qt.UserRole + 2
        self._chiiso_role = Qt.UserRole + 3
        self._chi11_role = Qt.UserRole + 4
        self._chi22_role = Qt.UserRole + 5
        self._chi33_role = Qt.UserRole + 6
        self._chi12_role = Qt.UserRole + 7
        self._chi13_role = Qt.UserRole + 8
        self._chi23_role = Qt.UserRole + 9
        self._model.setItemRoleNames({
            self._label_role: b'label',
            self._type_role: b'type',
            self._chiiso_role: b'chiiso',
            self._chi11_role: b'chi11',
            self._chi22_role: b'chi22',
            self._chi33_role: b'chi33',
            self._chi12_role: b'chi12',
            self._chi13_role: b'chi13',
            self._chi23_role: b'chi23'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set list of atoms
            data = []
            for atom_id, atom_dict in phase_dict['atoms'].items():
                data.append({
                    self._label_role:
                    atom_id,
                    self._type_role:
                    atom_dict.getItemByPath(['MSP', 'type']).value,
                    self._chiiso_role:
                    "",
                    self._chi11_role:
                    atom_dict.getItemByPath(['MSP', 'chi_11']).value,
                    self._chi22_role:
                    atom_dict.getItemByPath(['MSP', 'chi_22']).value,
                    self._chi33_role:
                    atom_dict.getItemByPath(['MSP', 'chi_33']).value,
                    self._chi12_role:
                    atom_dict.getItemByPath(['MSP', 'chi_12']).value,
                    self._chi13_role:
                    atom_dict.getItemByPath(['MSP', 'chi_13']).value,
                    self._chi23_role:
                    atom_dict.getItemByPath(['MSP', 'chi_23']).value,
                })
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data list created above
            for row_index, dict_value in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict_value.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
예제 #3
0
class FitablesModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._log = logger.getLogger(self.__class__.__module__)
        # limits
        self._left_limit_for_zero_value = -1
        self._right_limit_for_zero_value = 1
        self._limit_percentage_deviation = 0.2
        # minor properties
        self._first_role = Qt.UserRole + 1
        self._edit_role_increment = 100
        self._edit_role_name_suffix = 'Edit'
        # major properties
        self._model = QStandardItemModel()
        # set role names
        self._role_names_list = [
            'path', 'label', 'value', 'error', 'min', 'max', 'refine', 'unit',
            'labelList'
        ]  # 257 - 265
        self._roles_list = []
        self._roles_dict = {}
        self._setRolesListAndDict()
        self._model.setItemRoleNames(self._roles_dict)
        # connect signals
        self._model.dataChanged.connect(self.onModelChanged)

    def _setRolesListAndDict(self):
        """
        Create the display and edit role list and dict from role names.
        """
        for i, role_name in enumerate(self._role_names_list):
            display_role = self._first_role + i
            edit_role = display_role + self._edit_role_increment

            self._roles_dict[display_role] = role_name.encode()
            self._roles_dict[edit_role] = '{}{}'.format(
                role_name, self._edit_role_name_suffix).encode()
            self._roles_list.append(display_role)
            self._roles_list.append(edit_role)

        self._log.debug(f"roles: {self._roles_dict}")

    def _setModelsFromProjectDict(self):
        """
        Create the initial data list with structure for GUI fitables table.
        """
        self._log.info("Starting to set Model from Project Dict")

        # block model signals
        self._model.blockSignals(True)

        # reset model
        self._model.setColumnCount(
            0)  # faster than clear(); clear() crashes app! why?
        self._model.setRowCount(0)

        # sort background
        for experiment in self._project_dict['experiments'].keys():
            self._project_dict['experiments'][experiment]['background'].sort()

        # set column
        column = []
        for path in find_in_obj(self._project_dict.asDict(), 'refine'):
            keys_list = path[:-1]
            hide = self._project_dict.getItemByPath(keys_list + ['hide'])
            if hide:
                continue

            item = QStandardItem()
            for role, role_name_bytes in self._roles_dict.items():
                role_name = role_name_bytes.decode()
                if role_name.endswith(self._edit_role_name_suffix):
                    continue
                if role_name == 'path':
                    value = keys_list
                elif role_name == 'labelList':
                    value = keys_list[0:-1]
                    # Insert elements according to CIF
                    if len(value) > 0 and value[-1] == "offset":
                        value.insert(-1, "setup")
                    if len(value) > 0 and value[-1] == "wavelength":
                        value.insert(-1, "setup")
                    # Renaming according to CIF
                    if len(value) > 0 and value[-1] == "offset":
                        value[-1] = "offset_2theta"
                    if len(value) > 2 and value[2] == "atoms":
                        value[2] = "atom_site"
                    if len(value) > 2 and value[2] == "resolution":
                        value[2] = "pd_instr_resolution"
                    if len(value) > 2 and value[2] == "polarization":
                        value[2] = "diffrn_radiation"
                    if len(value) > 2 and value[2] == "background":
                        value.insert(3, "2theta")
                    if len(value) > 5 and value[4] == "MSP":
                        value[5] = "susceptibility_" + value[5]
                        del value[4]
                elif role_name == 'label':
                    value = ' '.join(keys_list[:-1])
                elif role_name == 'value':
                    value = self._project_dict.getItemByPath(
                        keys_list[:-1]).value
                elif role_name == 'min':
                    value = self._project_dict.getItemByPath(keys_list).min
                elif role_name == 'max':
                    value = self._project_dict.getItemByPath(keys_list).max
                elif role_name == 'unit':
                    # conversion to str is needed if role = unit !
                    value = str(
                        nested_get(self._project_dict,
                                   keys_list + [role_name]))
                else:
                    value = nested_get(self._project_dict,
                                       keys_list + [role_name])
                item.setData(value, role)

            column.append(item)

        # set model
        self._model.appendColumn(column)  # dataChanged is not emited. why?

        # unblock signals and emit model layout changed
        self._model.blockSignals(False)
        self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
        # Emit signal which is caught by the QStandardItemModel-based
        # QML GUI elements in order to update their views

    def _updateProjectByIndexAndRole(self, index, edit_role):
        """
        Update project element, which is changed in the model, depends on its index and role.
        """
        self._log.info("Starting updating Project Dict from Model")

        display_role = edit_role - self._edit_role_increment
        display_role_name = self._roles_dict[display_role].decode()
        path_role = self._role_names_list.index('path') + self._first_role
        keys_list = self._model.data(index, path_role) + [display_role_name]
        edit_value = self._model.data(index, edit_role)
        display_value = self._model.data(index, display_role)
        self._log.debug(f"edit_role: {edit_role}")
        self._log.debug(f"display_role: {display_role}")
        self._log.debug(f"display_role_name: {display_role_name}")
        self._log.debug(f"path_role: {path_role}")
        self._log.debug(f"keys_list: {keys_list}")
        self._log.debug(f"edit_value: {edit_value}")
        self._log.debug(f"display_value: {display_value}")

        fitable_name = '.'.join(keys_list[:-2])
        fitable_value = edit_value
        data_block_name = keys_list[0]
        self._log.debug(f"fitable_name: {fitable_name}")
        self._log.debug(f"fitable_value: {fitable_value}")
        self._log.debug(f"data_block_name: {data_block_name}")

        if display_role_name == 'refine':
            undo_redo_text = f"Changing '{fitable_name}' refine state to '{fitable_value}'"
            self._log.debug(f"undo_redo_text: {undo_redo_text}")
            self._calculator_interface.project_dict.startBulkUpdate(
                undo_redo_text)
            self._calculator_interface.canUndoOrRedoChanged.emit()
            if data_block_name == 'phases':
                try:
                    self._calculator_interface.setPhaseRefine(
                        keys_list[1], keys_list[2:-2], edit_value)
                except AttributeError:
                    # In this case the calculator/dict are out of phase :-/ So fallback to manual.
                    self._calculator_interface.project_dict.setItemByPath(
                        keys_list, edit_value)
                # self._calculator_interface.updatePhases()
            elif data_block_name == 'experiments':
                try:
                    self._calculator_interface.setExperimentRefine(
                        keys_list[1], keys_list[2:-2], edit_value)
                except AttributeError:
                    self._calculator_interface.project_dict.setItemByPath(
                        keys_list, edit_value)
                # self._calculator_interface.updateExperiments()
            else:
                self._calculator_interface.setDictByPath(keys_list, edit_value)
            self._calculator_interface.projectDictChanged.emit()

        elif display_role_name == 'value':
            undo_redo_text = f"Changing '{fitable_name}' to '{fitable_value:.4f}'"
            self._log.debug(f"undo_redo_text: {undo_redo_text}")
            self._calculator_interface.project_dict.startBulkUpdate(
                undo_redo_text)
            self._calculator_interface.canUndoOrRedoChanged.emit()
            if data_block_name == 'phases':
                try:
                    self._calculator_interface.setPhaseValue(
                        keys_list[1], keys_list[2:-2], edit_value)
                except AttributeError:
                    self._calculator_interface.project_dict.setItemByPath(
                        keys_list, edit_value)
                    self._calculator_interface.updatePhases()
                self._calculator_interface.updateCalculations(
                )  # phases also updated ?
            elif data_block_name == 'experiments':
                try:
                    self._calculator_interface.setExperimentValue(
                        keys_list[1], keys_list[2:-2], edit_value)
                except AttributeError:
                    self._calculator_interface.project_dict.setItemByPath(
                        keys_list, edit_value)
                    self._calculator_interface.updateExperiments()
                self._calculator_interface.updateCalculations(
                )  # experiments also updated ?
            else:
                self._calculator_interface.setDictByPath(keys_list, edit_value)
            # Update min and max if value is outside [min, max] range
            value = self._calculator_interface.project_dict.getItemByPath(
                keys_list)
            min_value = self._calculator_interface.project_dict.getItemByPath(
                [*keys_list[:-1], 'min'])
            max_value = self._calculator_interface.project_dict.getItemByPath(
                [*keys_list[:-1], 'max'])
            self._log.debug(f"initial min: {min}, max: {max}")
            # TODO: the code below duplicates the code from BaseClasses.py - class Base - def updateMinMax
            # stacked changes (for GUI triggered changes)
            if np.isclose([value], [0]):
                min_value = self._left_limit_for_zero_value
                max_value = self._right_limit_for_zero_value
            if value < min_value:
                if value > 0:
                    min_value = value * (1 - self._limit_percentage_deviation)
                else:
                    min_value = value * (1 + self._limit_percentage_deviation)
            if value > max_value:
                if value > 0:
                    max_value = value * (1 + self._limit_percentage_deviation)
                else:
                    max_value = value * (1 - self._limit_percentage_deviation)
            # Update min and max in project dict
            self._log.debug(f"re-calculated min: {min}, max: {max}")
            self._calculator_interface.project_dict.setItemByPath(
                [*keys_list[:-1], 'min'], min_value)
            self._calculator_interface.project_dict.setItemByPath(
                [*keys_list[:-1], 'max'], max_value)
            self._calculator_interface.projectDictChanged.emit()

        elif display_role_name == 'min' or display_role_name == 'max':
            undo_redo_text = f"Changing '{fitable_name}' {display_role_name} to '{fitable_value}'"
            self._log.debug(f"undo_redo_text: {undo_redo_text}")
            self._calculator_interface.project_dict.startBulkUpdate(
                undo_redo_text)
            self._calculator_interface.canUndoOrRedoChanged.emit()
            # TODO: try to use setDictByPath below
            # self._calculator_interface.setDictByPath(keys_list, edit_value)
            # Temporary (?) solution until above is fixed
            self._calculator_interface.project_dict.setItemByPath(
                keys_list, edit_value)
            self._calculator_interface.projectDictChanged.emit()

        else:
            self._log.warning(f"unsupported role: {display_role_name}")
            return

        self._calculator_interface.project_dict.endBulkUpdate()
        self._calculator_interface.canUndoOrRedoChanged.emit()
        self._log.info("Finished updating Project Dict from Model")

    def onModelChanged(self, top_left_index, bottom_right_index, roles):
        """
        Define what to do if model is changed, e.g. from GUI.
        """
        role = roles[0]
        role_name = self._roles_dict[role].decode()
        self._log.debug(f"roles: {roles}")
        self._log.debug(f"role: {role}")
        self._log.debug(f"role_name: {role_name}")

        if role_name.endswith(self._edit_role_name_suffix):
            self._updateProjectByIndexAndRole(top_left_index, role)
예제 #4
0
class AtomSitesModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._label_role = Qt.UserRole + 1
        self._atom_role = Qt.UserRole + 2
        self._color_role = Qt.UserRole + 3
        self._x_role = Qt.UserRole + 4
        self._y_role = Qt.UserRole + 5
        self._z_role = Qt.UserRole + 6
        self._occupancy_role = Qt.UserRole + 7
        self._model.setItemRoleNames({
            self._label_role: b'label',
            self._atom_role: b'atom',
            self._color_role: b'colorStr',
            self._x_role: b'xPos',
            self._y_role: b'yPos',
            self._z_role: b'zPos',
            self._occupancy_role: b'occupancy'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set list of atoms
            data = []
            for atom_id, atom_dict in phase_dict['atoms'].items():
                label = atom_id
                atom = str(atom_dict['type_symbol'].value)
                color = atom_dict['scat_length_neutron'].value.real
                x = atom_dict['fract_x'].value
                y = atom_dict['fract_x'].value
                z = atom_dict['fract_x'].value
                occupancy = atom_dict['occupancy'].value
                data.append({
                    self._label_role: label,
                    self._atom_role: atom,
                    self._color_role: color,
                    self._x_role: x,
                    self._y_role: y,
                    self._z_role: z,
                    self._occupancy_role: occupancy
                })
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data array created above
            for row_index, dict_value in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict_value.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
예제 #5
0
class CellBoxModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._x_role, self._y_role, self._z_role = [
            Qt.UserRole + 1 + i for i in range(3)
        ]
        self._model.setItemRoleNames({
            self._x_role: b'xPos',
            self._y_role: b'yPos',
            self._z_role: b'zPos'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI structure chart (unit cell box)."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # get lattice parameters
            a = phase_dict.getItemByPath(['cell', 'length_a']).value
            b = phase_dict.getItemByPath(['cell', 'length_b']).value
            c = phase_dict.getItemByPath(['cell', 'length_c']).value
            # get number of dots along different axes
            dots_per_angstrom = 30
            dots_along_a = int(a * dots_per_angstrom)
            dots_along_b = int(b * dots_per_angstrom)
            dots_along_c = int(c * dots_per_angstrom)
            # set data array for different axes
            data = []
            for i in range(dots_along_a):
                data.append({
                    self._x_role: i * a / dots_along_a,
                    self._y_role: 0,
                    self._z_role: 0
                })
                data.append({
                    self._x_role: i * a / dots_along_a,
                    self._y_role: b,
                    self._z_role: 0
                })
                data.append({
                    self._x_role: i * a / dots_along_a,
                    self._y_role: 0,
                    self._z_role: c
                })
                data.append({
                    self._x_role: i * a / dots_along_a,
                    self._y_role: b,
                    self._z_role: c
                })
            for i in range(dots_along_b):
                data.append({
                    self._x_role: 0,
                    self._y_role: i * b / dots_along_b,
                    self._z_role: 0
                })
                data.append({
                    self._x_role: a,
                    self._y_role: i * b / dots_along_b,
                    self._z_role: 0
                })
                data.append({
                    self._x_role: 0,
                    self._y_role: i * b / dots_along_b,
                    self._z_role: c
                })
                data.append({
                    self._x_role: a,
                    self._y_role: i * b / dots_along_b,
                    self._z_role: c
                })
            for i in range(dots_along_c):
                data.append({
                    self._x_role: 0,
                    self._y_role: 0,
                    self._z_role: i * c / dots_along_c
                })
                data.append({
                    self._x_role: a,
                    self._y_role: 0,
                    self._z_role: i * c / dots_along_c
                })
                data.append({
                    self._x_role: 0,
                    self._y_role: b,
                    self._z_role: i * c / dots_along_c
                })
                data.append({
                    self._x_role: a,
                    self._y_role: b,
                    self._z_role: i * c / dots_along_c
                })
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data array created above
            for row_index, dict in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")