Exemple #1
0
def viewResults(r, scenIdall, detector):
    """
    Opens Results table
    """
    # need a correspondence table in order to display results!
    session = Session()
    settings = RaseSettings()
    default_corr_table = session.query(CorrespondenceTable).filter_by(
        is_default=True).one_or_none()
    if not default_corr_table:
        msgbox = QMessageBox(
            QMessageBox.Question, 'No Correspondence Table set!',
            'No correspondence table set! Would you like to set a correspondence table now?'
        )
        msgbox.addButton(QMessageBox.Yes)
        msgbox.addButton(QMessageBox.No)
        answer = msgbox.exec()
        if answer == QMessageBox.Yes:
            CorrespondenceTableDialog().exec_()
            settings.setIsAfterCorrespondenceTableCall(True)
        else:
            return

    selected_scenarios = scenIdall
    r.calculateScenarioStats(1, selected_scenarios, detector)
    ViewResultsDialog(r, selected_scenarios, detector).exec_()
Exemple #2
0
 def set_otherCols_fromMat(self, units, matName, doseItem):
     if matName:
         if not doseItem.text():
             doseItem.setText('0.1')
         if not units.text():
             textSet = False
             if self.comboDetectorSelect.currentIndex() == 0:
                 detector_list = [
                     detector for detector in Session().query(Detector)
                 ]
             else:
                 detector_list = [
                     Session().query(Detector).filter_by(
                         name=self.comboDetectorSelect.currentText()).first(
                         )
                 ]
             for detector in detector_list:
                 for baseSpectrum in detector.base_spectra:
                     if baseSpectrum.material.name == matName and not textSet:
                         units.tableWidget().blockSignals(True)
                         if isinstance(baseSpectrum.rase_sensitivity,
                                       float):
                             units.setText(units_labels['DOSE'])
                             units.setData(Qt.UserRole, 'DOSE')
                             textSet = True
                         else:
                             units.setText(units_labels['FLUX'])
                             units.setData(Qt.UserRole, 'FLUX')
                         units.tableWidget().blockSignals(False)
Exemple #3
0
    def __init__(self, parent=None, groups=[], scens=None, del_groups=False):
        QDialog.__init__(self, parent)
        self.groups = groups
        self.scens = scens
        self.del_groups = del_groups
        self.session = Session()

        self.makeLayout()
Exemple #4
0
 def showDetailView(self, index):
     scen_det_key = self.results_model.headerData(index.row(), Qt.Vertical, Qt.UserRole)
     resultMap = self.parent.result_super_map[scen_det_key]
     scen_id = scen_det_key.split('*')[0]
     det_name = "".join(scen_det_key.split('*')[1:])
     scenario = Session().query(Scenario).filter_by(id=scen_id).first()
     detector = Session().query(Detector).filter_by(name=det_name).first()
     DetailedResultsDialog(resultMap, scenario, detector).exec_()
Exemple #5
0
def export_scenarios(scenarios_ids, file_path):
    """
    Export scenarios from database to xml file
    """
    session = Session()
    scenarios = [session.query(Scenario).filter_by(id=scenid).first() for scenid in scenarios_ids]

    scen_io = ScenariosIO()
    xml_str = scen_io.scenario_export(scenarios)
    Path(file_path).write_text(xml_str)
Exemple #6
0
def initializeDatabase(databaseFilepath):
    """
    binds Session to database and creates new database if none exists

    :param databaseFilepath: path to src.sqlite file
    """
    Session.remove()
    engine = create_engine('sqlite:///' + databaseFilepath)
    Session.configure(bind=engine)
    if not os.path.exists(databaseFilepath):
        Base.metadata.create_all(engine)
Exemple #7
0
    def createEditor(self, parent, option, index):
        if index.column() == self.matCol:
            # generate material list
            fd_units = self.tblMat.item(index.row(),
                                        self.unitsCol).data(Qt.UserRole)
            material_list = []
            if not self.selected_detname:
                for detector in Session().query(Detector):
                    for baseSpectrum in detector.base_spectra:
                        if baseSpectrum.material.name not in material_list:
                            if ((isinstance(baseSpectrum.rase_sensitivity,
                                            float) and (fd_units == 'DOSE')) or
                                (isinstance(baseSpectrum.flux_sensitivity,
                                            float) and (fd_units == 'FLUX'))
                                    or not fd_units):
                                material_list.append(
                                    baseSpectrum.material.name)
                material_list = sorted(material_list)
            else:
                detector = Session().query(Detector).filter_by(
                    name=self.selected_detname).first()
                material_list = sorted([
                    baseSpectrum.material.name
                    for baseSpectrum in detector.base_spectra
                    if ((isinstance(baseSpectrum.rase_sensitivity, float) and
                         (fd_units == 'DOSE')) or
                        (isinstance(baseSpectrum.flux_sensitivity, float) and
                         (fd_units == 'FLUX')) or not fd_units)
                ])
            # remove any materials already used
            for row in range(self.tblMat.rowCount()):
                item = self.tblMat.item(row, self.matCol)
                if item and item.text() in material_list:
                    material_list.remove(item.text())

            #create and populate comboEdit
            comboEdit = QComboBox(parent)
            comboEdit.setEditable(self.editable)
            comboEdit.setSizeAdjustPolicy(0)
            comboEdit.setMaxVisibleItems(25)
            comboEdit.addItem('')
            comboEdit.addItems(material_list)
            return comboEdit
        elif index.column() == self.intensityCol:
            editor = QLineEdit(parent)
            editor.setValidator(RegExpSetValidator(editor, self.auto_s))
            return editor
        elif index.column() == self.unitsCol:
            return self.unitsEditor(parent, index)
        else:
            return super(MaterialDoseDelegate,
                         self).createEditor(parent, option, index)
Exemple #8
0
 def __init__(self, resultMap, scenario, detector):
     QDialog.__init__(self)
     self.setupUi(self)
     self.settings = RaseSettings()
     self.headerLabels = ['File', 'Tp', 'Fn', 'Fp', 'Precision', 'Recall', 'Fscore', 'IDs']
     self.NUM_COLS = len(self.headerLabels)
     self.session = Session()
     self.scenario = scenario
     self.detector = detector
     self.tblDetailedResults.setContextMenuPolicy(Qt.CustomContextMenu)
     self.tblDetailedResults.setColumnCount(self.NUM_COLS)
     self.tblDetailedResults.setHorizontalHeaderLabels(self.headerLabels)
     self.tblDetailedResults.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
     self.tblDetailedResults.setRowCount(0)
     row=0
     for file in sorted(resultMap, key=natural_keys):
         results = resultMap[file]
         results.insert(0, file)
         self.tblDetailedResults.insertRow(row)
         for col in range(self.NUM_COLS):
             self.tblDetailedResults.setItem(row, col, QTableWidgetItem(results[col]))
         row = row + 1
         results.pop(0)
     self.tblDetailedResults.resizeColumnsToContents()
     self.tblDetailedResults.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
     self.buttonOK.clicked.connect(self.closeSelected)
     self.buttonExport.clicked.connect(self.handleExport)
Exemple #9
0
def cleanup_scenarios(rangefind_rep, scenIds):
    """Remove scenarios from the database that were rangefinders, i.e.: low replication scenarios"""
    settings = RaseSettings()
    session = Session()

    scenarios = []
    for scen in scenIds:
        scenarios.append(session.query(Scenario).filter_by(id=scen).first())

    scens_to_delete = []
    for scen in scenarios:
        if scen.replication == rangefind_rep:
            scens_to_delete.append(scen.id)

    delete_scenario(scens_to_delete, settings.getSampleDirectory())

    session.commit()
Exemple #10
0
 def set_otherCols_fromUnit(self, units, matName, doseItem):
     textKeep = False
     if self.comboDetectorSelect.currentIndex() == 0:
         detector_list = [
             detector for detector in Session().query(Detector)
         ]
     else:
         detector_list = [
             Session().query(Detector).filter_by(
                 name=self.comboDetectorSelect.currentText()).first()
         ]
     for detector in detector_list:
         for baseSpectrum in detector.base_spectra:
             if baseSpectrum.material.name == matName.text(
             ) and not textKeep:
                 if (units.data(Qt.UserRole) == 'DOSE' and isinstance(baseSpectrum.rase_sensitivity, float)) or \
                    (units.data(Qt.UserRole) == 'FLUX' and isinstance(baseSpectrum.flux_sensitivity, float)):
                     textKeep = True
     if not textKeep:
         matName.setText('')
Exemple #11
0
def delete_scenario(scenario_ids, sample_root_dir):
    """
    Delete scenarios from database and cleanup sample folders
    """
    session = Session()
    for id in scenario_ids:
        scenDelete = session.query(Scenario).filter(Scenario.id == id)
        matDelete = session.query(ScenarioMaterial).filter(ScenarioMaterial.scenario_id == id)
        backgMatDelete = session.query(ScenarioBackgroundMaterial).filter(ScenarioBackgroundMaterial.scenario_id == id)

        # folders
        folders = [name for name in glob.glob(os.path.join(sample_root_dir, "*" + id + "*"))]
        for folder in folders:
            shutil.rmtree(folder)

        # database
        scenObj = scenDelete.first()
        scenObj.scenario_groups.clear()
        matDelete.delete()
        backgMatDelete.delete()
        scenDelete.delete()
        session.commit()

    session.close()
Exemple #12
0
class GroupSettings(QDialog):
    """Simple Dialog to allow the user to select which groups a scenario is in.
    This information is stored in the scenario_groups table value for each scenario.

    :param parent: the parent dialog
    """
    def __init__(self, parent=None, groups=[], scens=None, del_groups=False):
        QDialog.__init__(self, parent)
        self.groups = groups
        self.scens = scens
        self.del_groups = del_groups
        self.session = Session()

        self.makeLayout()

    def makeLayout(self):
        cols_list = [grp.name for grp in self.session.query(ScenarioGroup)]
        cols_list.insert(0, cols_list.pop(cols_list.index('default_group')))
        cb_list = [QCheckBox(v.replace('&', '&&')) for v in cols_list]

        self.layout = QVBoxLayout()
        self.checklayout = QVBoxLayout()
        self.buttonlayout = QVBoxLayout()

        for cb in cb_list:
            self.checklayout.addWidget(cb)
            if cb.text() in self.groups:
                cb.setChecked(True)
            if cb.text() == 'default_group' and self.del_groups:
                cb.setEnabled(False)

        self.btn_newgroup = QPushButton('Add New Group')
        self.buttonlayout.addWidget(self.btn_newgroup)
        self.btn_newgroup.clicked.connect(self.addCheckbox)
        self.buttonBox = QDialogButtonBox(self)

        if self.del_groups:
            self.btn_deletegroup = QPushButton('Remove Group(s)')
            self.buttonlayout.addWidget(self.btn_deletegroup)
            self.btn_deletegroup.clicked.connect(self.delGroup)
            self.buttonBox.setStandardButtons(QDialogButtonBox.Close)
            self.buttonBox.rejected.connect(self.reject)
        else:
            self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                              | QDialogButtonBox.Ok)
            self.buttonBox.accepted.connect(self.accept)
            self.buttonBox.rejected.connect(self.reject)
        self.buttonlayout.addWidget(self.buttonBox)

        self.layout.addLayout(self.checklayout)
        self.layout.addLayout(self.buttonlayout)
        if not self.del_groups and self.scens and len(self.scens) > 1:
            self.info = QLabel(
                'NOTE: A group box is checked if\nany one of the selected scenarios\nis in that '
                'group. Pressing OK will\nadd all selected scenarios to the\nselected groups.'
            )
            self.layout.addWidget(self.info)
        self.setLayout(self.layout)

    def _cb_list(self):
        return [
            self.checklayout.itemAt(i).widget()
            for i in range(self.checklayout.count())
        ]

    def addCheckbox(self):
        newgroup, okPressed = QInputDialog.getText(self,
                                                   "Add New Scenario Group",
                                                   "Scenario Group name:",
                                                   QLineEdit.Normal, "")
        collist = [grp.name for grp in self.session.query(ScenarioGroup)]
        if okPressed and (newgroup != '' and newgroup not in collist):
            self.checklayout.addWidget(QCheckBox(newgroup))
            self.setLayout(self.layout)
            self.add_groups(self.session, newgroup)

    def delGroup(self):
        del_groups = [cb.text() for cb in self._cb_list() if cb.isChecked()]
        if len(del_groups) > 1:
            answer = QMessageBox(
                QMessageBox.Question, 'Delete Scenario Groups',
                'Are you sure you want to delete these scenario groups? '
                'Scenarios in these groups will not be deleted')
        else:
            answer = QMessageBox(
                QMessageBox.Question, 'Delete Scenario Group',
                'Are you sure you want to delete this scenario group? '
                'Scenarios in this group will not be deleted')
        answer.addButton(QMessageBox.Yes)
        answer.addButton(QMessageBox.No)
        ans_hold = answer.exec()
        if ans_hold == QMessageBox.Yes:
            for group in del_groups:
                self.delete_groups(self.session, group)
            for cb in self._cb_list():
                if cb.text() in del_groups:
                    self.checklayout.removeWidget(cb)
                    cb.deleteLater()

    @staticmethod
    def delete_groups(session, group):
        group_delete = session.query(ScenarioGroup).filter(
            ScenarioGroup.name == group)
        group_delete.delete()
        session.commit()

    @staticmethod
    def add_groups(session, group):
        session.add(ScenarioGroup(name=group))
        session.commit()

    @pyqtSlot()
    def accept(self):
        """
        Adds the scenario to the checked groups
        """
        self.n_groups = [cb.text() for cb in self._cb_list() if cb.isChecked()]
        if self.scens:
            for scen in self.scens:
                scen.scenario_groups.clear()
                for groupname in self.n_groups:
                    scen.scenario_groups.append(
                        self.session.query(ScenarioGroup).filter_by(
                            name=groupname).first())
            self.session.commit()
        return QDialog.accept(self)
Exemple #13
0
    def __init__(self, rase_gui, id=None, duplicate=[], auto_s=False):
        QDialog.__init__(self)
        self.setupUi(self)
        self.rase_gui = rase_gui
        self.tblMaterial.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tblBackground.setContextMenuPolicy(Qt.CustomContextMenu)
        self.id = id
        self.auto_s = auto_s
        self.settings = RaseSettings()
        self.scenarioHasChanged = False
        self.groupHasChanged = False
        self.duplicate = duplicate
        self.session = Session()

        self.txtAcqTime.setText('30')
        self.txtAcqTime.setToolTip(
            "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
        )
        self.txtReplication_2.setText('100')
        int_validator = QIntValidator()
        self.txtAcqTime.setValidator(RegExpSetValidator())
        self.txtReplication_2.setValidator(int_validator)

        self.tblMaterial.setHorizontalHeaderItem(INTENSITY,
                                                 QTableWidgetItem('Intensity'))
        self.tblBackground.setHorizontalHeaderItem(
            INTENSITY, QTableWidgetItem('Intensity'))

        self.tblMaterial.customContextMenuRequested.connect(
            lambda x, table=self.tblMaterial: self.context_auto_range(
                x, self.tblMaterial))
        self.tblBackground.customContextMenuRequested.connect(
            lambda x, table=self.tblBackground: self.context_auto_range(
                x, self.tblBackground))

        # set material table
        self.tblMaterial.setItemDelegate(
            MaterialDoseDelegate(self.tblMaterial,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY))
        self.tblMaterial.setRowCount(10)
        for row in range(self.tblMaterial.rowCount()):
            self.tblMaterial.setItem(row, UNITS, QTableWidgetItem())
            self.tblMaterial.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblMaterial.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblMaterial.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblMaterial.setRowHeight(row, 22)

        # set background table
        self.tblBackground.setItemDelegate(
            MaterialDoseDelegate(self.tblBackground,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 auto_s=self.auto_s))
        self.tblBackground.setRowCount(10)
        for row in range(self.tblBackground.rowCount()):
            self.tblBackground.setItem(row, UNITS, QTableWidgetItem())
            self.tblBackground.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblBackground.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblBackground.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblBackground.setRowHeight(row, 22)

        # fill influence list
        for influence in self.session.query(Influence):
            self.lstInfluences.addItem(QListWidgetItem(influence.name))

        self.comboDetectorSelect.addItems(
            ["all detectors"] +
            [s.name for s in self.session.query(Detector).all()])
        self.comboDetectorSelect.currentIndexChanged.connect(
            self.updateTableDelegate)

        # display a previous scenario if defined
        if self.id:
            if not self.duplicate:
                self.setWindowTitle("Scenario Edit")
                scenario = self.session.query(Scenario).get(id)
                materials = scenario.scen_materials
                bckg_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                for table, mat_list in zip(
                    (self.tblMaterial, self.tblBackground),
                    (materials, bckg_materials)):
                    for rowCount, mat in enumerate(mat_list):
                        item = QTableWidgetItem(units_labels[mat.fd_mode])
                        item.setData(Qt.UserRole, mat.fd_mode)
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(mat.material_name))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(mat.dose)))
                self.txtAcqTime.setText(str(scenario.acq_time))
                self.txtReplication_2.setText(str(scenario.replication))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

            else:
                self.setWindowTitle("Build Scenario from Other Scenario")
                scens = [
                    self.session.query(Scenario).filter_by(id=scen).first()
                    for scen in self.duplicate
                ]
                scenario = scens[0]
                materials = scenario.scen_materials
                back_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                mat_dict = {}
                back_dict = {}
                mat_fd = []
                back_fd = []
                for mat in materials:
                    mat_fd.append((mat.material_name, mat.fd_mode))
                    mat_dict[mat.material_name] = set([mat.dose])
                for back in back_materials:
                    back_fd.append((back.material_name, back.fd_mode))
                    back_dict[back.material_name] = set([back.dose])

                if len(scens) > 1:
                    for scen in scens[1:]:
                        mat_dict = self.make_matDict(scen.scen_materials,
                                                     mat_dict)
                        back_dict = self.make_matDict(scen.scen_bckg_materials,
                                                      back_dict)
                        if influences:
                            influences.append[scen.influences]
                        else:
                            influences = scen.influences

                for table, material_dictionary, fd_list in \
                        zip((self.tblMaterial, self.tblBackground), (mat_dict, back_dict), (mat_fd, back_fd)):
                    mat_list_tup = [(k, v)
                                    for k, v in material_dictionary.items()]
                    for rowCount, (mat, fd_mode) in enumerate(
                            zip(mat_list_tup, fd_list)):
                        doses = [str(d) for d in sorted(mat[1])]
                        item = QTableWidgetItem(units_labels[fd_mode[1]])
                        item.setData(Qt.UserRole, fd_mode[1])
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(str(mat[0])))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(','.join(doses))))
                self.txtAcqTime.setText(str(scenario.acq_time))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

        else:
            self.groups = []

        if self.auto_s and self.rase_gui.static_background:
            for rowCount, mat in enumerate(self.rase_gui.static_background):
                mat = mat[0]
                item = QTableWidgetItem(units_labels[mat[0]])
                item.setData(Qt.UserRole, mat[0])
                self.tblBackground.setItem(rowCount, 0, item)
                self.tblBackground.setItem(rowCount, 1,
                                           QTableWidgetItem(mat[1].name))
                self.tblBackground.setItem(rowCount, 2,
                                           QTableWidgetItem(str(mat[2])))

        # signal/slot connections (this has to be done after_ the previous scenario is loaded)
        self.tblMaterial.cellChanged.connect(self.scenarioChanged)
        self.tblBackground.cellChanged.connect(self.scenarioChanged)
        self.tblMaterial.cellChanged.connect(self.updateScenariosList)
        self.tblBackground.cellChanged.connect(self.updateScenariosList)
        self.lstInfluences.itemSelectionChanged.connect(self.scenarioChanged)
        self.txtAcqTime.textChanged.connect(self.scenarioChanged)
        self.txtReplication_2.textChanged.connect(self.scenarioChanged)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
Exemple #14
0
class ScenarioDialog(ui_create_scenario_dialog.Ui_ScenarioDialog, QDialog):
    def __init__(self, rase_gui, id=None, duplicate=[], auto_s=False):
        QDialog.__init__(self)
        self.setupUi(self)
        self.rase_gui = rase_gui
        self.tblMaterial.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tblBackground.setContextMenuPolicy(Qt.CustomContextMenu)
        self.id = id
        self.auto_s = auto_s
        self.settings = RaseSettings()
        self.scenarioHasChanged = False
        self.groupHasChanged = False
        self.duplicate = duplicate
        self.session = Session()

        self.txtAcqTime.setText('30')
        self.txtAcqTime.setToolTip(
            "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
        )
        self.txtReplication_2.setText('100')
        int_validator = QIntValidator()
        self.txtAcqTime.setValidator(RegExpSetValidator())
        self.txtReplication_2.setValidator(int_validator)

        self.tblMaterial.setHorizontalHeaderItem(INTENSITY,
                                                 QTableWidgetItem('Intensity'))
        self.tblBackground.setHorizontalHeaderItem(
            INTENSITY, QTableWidgetItem('Intensity'))

        self.tblMaterial.customContextMenuRequested.connect(
            lambda x, table=self.tblMaterial: self.context_auto_range(
                x, self.tblMaterial))
        self.tblBackground.customContextMenuRequested.connect(
            lambda x, table=self.tblBackground: self.context_auto_range(
                x, self.tblBackground))

        # set material table
        self.tblMaterial.setItemDelegate(
            MaterialDoseDelegate(self.tblMaterial,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY))
        self.tblMaterial.setRowCount(10)
        for row in range(self.tblMaterial.rowCount()):
            self.tblMaterial.setItem(row, UNITS, QTableWidgetItem())
            self.tblMaterial.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblMaterial.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblMaterial.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblMaterial.setRowHeight(row, 22)

        # set background table
        self.tblBackground.setItemDelegate(
            MaterialDoseDelegate(self.tblBackground,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 auto_s=self.auto_s))
        self.tblBackground.setRowCount(10)
        for row in range(self.tblBackground.rowCount()):
            self.tblBackground.setItem(row, UNITS, QTableWidgetItem())
            self.tblBackground.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblBackground.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblBackground.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblBackground.setRowHeight(row, 22)

        # fill influence list
        for influence in self.session.query(Influence):
            self.lstInfluences.addItem(QListWidgetItem(influence.name))

        self.comboDetectorSelect.addItems(
            ["all detectors"] +
            [s.name for s in self.session.query(Detector).all()])
        self.comboDetectorSelect.currentIndexChanged.connect(
            self.updateTableDelegate)

        # display a previous scenario if defined
        if self.id:
            if not self.duplicate:
                self.setWindowTitle("Scenario Edit")
                scenario = self.session.query(Scenario).get(id)
                materials = scenario.scen_materials
                bckg_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                for table, mat_list in zip(
                    (self.tblMaterial, self.tblBackground),
                    (materials, bckg_materials)):
                    for rowCount, mat in enumerate(mat_list):
                        item = QTableWidgetItem(units_labels[mat.fd_mode])
                        item.setData(Qt.UserRole, mat.fd_mode)
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(mat.material_name))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(mat.dose)))
                self.txtAcqTime.setText(str(scenario.acq_time))
                self.txtReplication_2.setText(str(scenario.replication))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

            else:
                self.setWindowTitle("Build Scenario from Other Scenario")
                scens = [
                    self.session.query(Scenario).filter_by(id=scen).first()
                    for scen in self.duplicate
                ]
                scenario = scens[0]
                materials = scenario.scen_materials
                back_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                mat_dict = {}
                back_dict = {}
                mat_fd = []
                back_fd = []
                for mat in materials:
                    mat_fd.append((mat.material_name, mat.fd_mode))
                    mat_dict[mat.material_name] = set([mat.dose])
                for back in back_materials:
                    back_fd.append((back.material_name, back.fd_mode))
                    back_dict[back.material_name] = set([back.dose])

                if len(scens) > 1:
                    for scen in scens[1:]:
                        mat_dict = self.make_matDict(scen.scen_materials,
                                                     mat_dict)
                        back_dict = self.make_matDict(scen.scen_bckg_materials,
                                                      back_dict)
                        if influences:
                            influences.append[scen.influences]
                        else:
                            influences = scen.influences

                for table, material_dictionary, fd_list in \
                        zip((self.tblMaterial, self.tblBackground), (mat_dict, back_dict), (mat_fd, back_fd)):
                    mat_list_tup = [(k, v)
                                    for k, v in material_dictionary.items()]
                    for rowCount, (mat, fd_mode) in enumerate(
                            zip(mat_list_tup, fd_list)):
                        doses = [str(d) for d in sorted(mat[1])]
                        item = QTableWidgetItem(units_labels[fd_mode[1]])
                        item.setData(Qt.UserRole, fd_mode[1])
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(str(mat[0])))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(','.join(doses))))
                self.txtAcqTime.setText(str(scenario.acq_time))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

        else:
            self.groups = []

        if self.auto_s and self.rase_gui.static_background:
            for rowCount, mat in enumerate(self.rase_gui.static_background):
                mat = mat[0]
                item = QTableWidgetItem(units_labels[mat[0]])
                item.setData(Qt.UserRole, mat[0])
                self.tblBackground.setItem(rowCount, 0, item)
                self.tblBackground.setItem(rowCount, 1,
                                           QTableWidgetItem(mat[1].name))
                self.tblBackground.setItem(rowCount, 2,
                                           QTableWidgetItem(str(mat[2])))

        # signal/slot connections (this has to be done after_ the previous scenario is loaded)
        self.tblMaterial.cellChanged.connect(self.scenarioChanged)
        self.tblBackground.cellChanged.connect(self.scenarioChanged)
        self.tblMaterial.cellChanged.connect(self.updateScenariosList)
        self.tblBackground.cellChanged.connect(self.updateScenariosList)
        self.lstInfluences.itemSelectionChanged.connect(self.scenarioChanged)
        self.txtAcqTime.textChanged.connect(self.scenarioChanged)
        self.txtReplication_2.textChanged.connect(self.scenarioChanged)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def make_matDict(self, mats, m_dict):
        for mat in mats:
            m_dict[mat.material_name].update([mat.dose])
        return m_dict

    def getGroups(self):
        if self.id:
            if not self.duplicate:
                scen_edit = self.session.query(Scenario).filter_by(
                    id=self.id).first()
                return [grp.name for grp in scen_edit.scenario_groups]
            else:
                scens = [
                    self.session.query(Scenario).filter_by(id=scen).first()
                    for scen in self.duplicate
                ]
                grps = set()
                for scen in scens:
                    grps.update([grp.name for grp in scen.scenario_groups])
                return grps
        else:
            return []

    @pyqtSlot()
    def scenarioChanged(self):
        """
        Listens for Scenario changed
        """
        self.scenarioHasChanged = True

    @pyqtSlot()
    def groupChanged(self):
        """
        Listens for group changed
        """
        self.groupHasChanged = True

    @pyqtSlot(int)
    def updateTableDelegate(self, index):
        if index == 0:
            selected_detname = None
        else:
            selected_detname = self.comboDetectorSelect.currentText()
        self.tblMaterial.setItemDelegate(
            MaterialDoseDelegate(self.tblMaterial,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 selected_detname=selected_detname))
        self.tblBackground.setItemDelegate(
            MaterialDoseDelegate(self.tblBackground,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 selected_detname=selected_detname,
                                 auto_s=self.auto_s))

    @pyqtSlot(QPoint)
    def context_auto_range(self, point, table):
        current_cell = table.itemAt(point)
        # show the context menu only if on an a valid part of the table
        if current_cell:
            column = current_cell.column()
            if column == 2:
                autorangeAction = QAction('Auto-Define Range', self)
                menu = QMenu(table)
                menu.addAction(autorangeAction)
                action = menu.exec_(table.mapToGlobal(point))
                if action == autorangeAction:
                    auto_list = self.auto_range()
                    if auto_list:
                        current_cell.setText(','.join(auto_list))

    @pyqtSlot(bool)
    def auto_range(self):
        dialog = ScenarioRange(self)
        dialog.setWindowModality(Qt.WindowModal)
        if dialog.exec_():
            if dialog.points:
                return dialog.points

    @pyqtSlot()
    def updateScenariosList(self):
        materialStr = ""
        for row in range(self.tblMaterial.rowCount()):
            untStr = self.tblMaterial.item(row, UNITS).text()
            matStr = self.tblMaterial.item(row, MATERIAL).text()
            intStr = self.tblMaterial.item(row, INTENSITY).text()
            if matStr and untStr and intStr:
                if (len(materialStr) > 0):
                    materialStr = materialStr + "\n "
                materialStr = materialStr + '{}({})'.format(matStr, ', '.join("{:.5f}".format(float(dose)) for
                                  dose in self.getSet(self.tblMaterial.item(row, INTENSITY)))) + \
                                  ', Units: ' + self.tblMaterial.item(row, UNITS).data(Qt.UserRole).title()

        backgroundStr = ""
        for row in range(self.tblBackground.rowCount()):
            untStr = self.tblBackground.item(row, UNITS).text()
            matStr = self.tblBackground.item(row, MATERIAL).text()
            intStr = self.tblBackground.item(row, INTENSITY).text()
            if matStr and untStr and intStr:
                if (len(backgroundStr) > 0):
                    backgroundStr = backgroundStr + "\n "
                backgroundStr = backgroundStr + '{}({})'.format(matStr, ', '.join("{:.5f}".format(float(dose)) for
                                  dose in self.getSet(self.tblBackground.item(row, INTENSITY)))) + \
                                  ', Units: ' + self.tblBackground.item(row, UNITS).data(Qt.UserRole).title()
        self.txtScenariosList_2.setText(
            f"Source materials:\n {materialStr} \n\nBackground materials:\n {backgroundStr}"
        )

    @pyqtSlot(bool)
    def on_btnGroups_clicked(self, checked):
        dialog = GroupSettings(self, groups=self.groups)
        dialog.setWindowModality(Qt.WindowModal)
        if dialog.exec_():
            self.groups = dialog.n_groups

    @pyqtSlot()
    def accept(self):
        if self.auto_s:
            materials_doses = []
            for matsT in [self.tblBackground]:
                for row in range(matsT.rowCount()):
                    matName = matsT.item(row, MATERIAL).text()
                    if matName:
                        matArr = []
                        for dose in self.getSet(matsT.item(row, 2)):
                            mat = self.session.query(Material).filter_by(
                                name=matName).first()
                            fd_mat = matsT.item(row, UNITS).data(Qt.UserRole)
                            matArr.append((fd_mat, mat, dose))
                        materials_doses.append(matArr)

            self.rase_gui.static_background = materials_doses
            return QDialog.accept(self)

        self.tblMaterial.setCurrentIndex(QModelIndex(
        ))  # so that if table item is being edited it will commit the data

        # if this is edit rather than create, need to treat differently:
        if self.id and not self.duplicate:
            # check if the scenario has been changed by the user
            # Note that this approach considers a change even if
            # the user rewrites the previous entry identically
            if not self.scenarioHasChanged:
                # update just the group for the same scenario
                # so as not to change the scenario ID
                scen = self.session.query(Scenario).get(self.id)
                self.provide_message_new_groups = False
                self.add_groups_to_scen(scen, self.groups, add_groups=True)
                self.session.commit()
                return QDialog.accept(self)
            else:
                # clear the existing scenario first
                self.scenario_delete()

        # replication and influences
        replication = int(self.txtReplication_2.text())
        influences = []  # element type: Influence
        for index in self.lstInfluences.selectedIndexes():
            influences.append(
                self.session.query(Influence).filter_by(
                    name=self.lstInfluences.itemFromIndex(
                        index).text()).first())

        materials_doses = [[], []]
        for i, matsT in enumerate([self.tblMaterial, self.tblBackground]):
            for row in range(matsT.rowCount()):
                matName = matsT.item(row, MATERIAL).text()
                if matName:
                    matArr = []
                    for dose in self.getSet(matsT.item(row, 2)):
                        mat = self.session.query(Material).filter_by(
                            name=matName).first()
                        fd_mat = matsT.item(row, UNITS).data(Qt.UserRole)
                        matArr.append((fd_mat, mat, dose))
                    materials_doses[i].append(matArr)

        # cartesian product to break out scenarios from scenario group
        integrity_fail = False
        duplicate = False
        self.provide_message_new_groups = True
        for acqTime in self.getSet(self.txtAcqTime):
            mm = product(*materials_doses[0])
            bb = product(*materials_doses[1])
            for mat_dose_arr, bckg_mat_dose_arr in product(mm, bb):
                scenMaterials = [
                    ScenarioMaterial(material=m, dose=float(d), fd_mode=u)
                    for u, m, d in mat_dose_arr
                ]
                bcgkScenMaterials = [
                    ScenarioBackgroundMaterial(material=m,
                                               dose=float(d),
                                               fd_mode=u)
                    for u, m, d in bckg_mat_dose_arr
                ]
                scen_groups = []
                try:
                    for groupname in self.groups:
                        scen_groups.append(
                            self.session.query(ScenarioGroup).filter_by(
                                name=groupname).first())
                    if not scen_groups:
                        scen_groups.append(
                            self.session.query(ScenarioGroup).filter_by(
                                name='default_group').first())
                    # if just changing groups, add to new group without creating a new scenario
                    scen_hash = Scenario.scenario_hash(float(acqTime),
                                                       scenMaterials,
                                                       bcgkScenMaterials,
                                                       influences)
                    scen_exists = self.session.query(Scenario).filter_by(
                        id=scen_hash).first()
                    add_groups = False
                    if scen_exists:
                        # and (sorted([g.name for g in scen_exists.scenario_groups]) !=
                        #                 sorted([g.name for g in scen_groups])):
                        for group in scen_groups:
                            if group not in scen_exists.scenario_groups:
                                add_groups = True
                                break
                        all_groups = set(g.name
                                         for g in scen_exists.scenario_groups +
                                         scen_groups)
                        all_groups.update(self.groups)
                        # don't allow duplicate scenarios, unless there are other scenarios in the group that are
                        # simply having their group changed. In which case, pass by those groups without impact.
                        duplicate = self.add_groups_to_scen(
                            scen_exists, all_groups, add_groups=add_groups)
                    else:
                        Scenario(float(acqTime), replication, scenMaterials,
                                 bcgkScenMaterials, influences, scen_groups)
                # if inputting multiple scenarios with at least one preexisting scenario (i.e.: this only happens when
                # the loop traverses more than once and the database is accessed again)
                except (IntegrityError, FlushError):
                    self.integrity_message(materials_doses)
                    integrity_fail = True
                    break

        # if inputting a single scenario that already exists
        if not integrity_fail:
            if duplicate:
                self.integrity_message(materials_doses)
            else:
                try:
                    self.session.commit()
                    return QDialog.accept(self)
                except (IntegrityError, FlushError):
                    self.integrity_message(materials_doses)

    def add_groups_to_scen(self, scen, all_groups, add_groups=False):
        """
        Clear groups associated with a scenario and append new ones
        """
        if add_groups:
            scen.scenario_groups.clear()
            for groupname in all_groups:
                scen.scenario_groups.append(
                    self.session.query(ScenarioGroup).filter_by(
                        name=groupname).first())
                if self.provide_message_new_groups:
                    QMessageBox.information(
                        self, 'Record Exists',
                        'At least one defined scenario is already in the database; '
                        'adding scenario to additional groups.')
                    self.provide_message_new_groups = False
        elif self.provide_message_new_groups:
            return True
        return False

    def scenario_delete(self):
        """
        Clear existing scenario before adding the modified version
        """
        scenDelete = self.session.query(Scenario).filter(
            Scenario.id == self.id)
        matDelete = self.session.query(ScenarioMaterial).filter(
            ScenarioMaterial.scenario_id == self.id)
        bckgMatDelete = self.session.query(ScenarioBackgroundMaterial).filter(
            ScenarioBackgroundMaterial.scenario_id == self.id)
        scenTableAssocDelete = scenDelete.first()
        scenTableAssocDelete.scenario_groups.clear()
        scenTableAssocDelete.influences.clear()
        matDelete.delete()
        bckgMatDelete.delete()
        scenDelete.delete()

    def integrity_message(self, materials_doses):
        if (materials_doses[0] and len(list(product(*materials_doses[0]))) > 1) or \
                (materials_doses[1] and len(list(product(*materials_doses[1]))) > 1):
            QMessageBox.critical(
                self, 'Record Exists',
                'At least one defined scenario is already in the database! '
                'Please change scenarios.')
        else:
            QMessageBox.critical(
                self, 'Record Exists',
                'This scenario is already in the database! Please change scenario.'
            )
        self.session.rollback()

    # TODO: combine these two methods using a cellChanged.connect()
    @pyqtSlot(int, int)
    def on_tblMaterial_cellChanged(self, row, col):
        """
        Listens for Material table cell changed
        """
        if col == UNITS:
            if self.tblMaterial.item(row, MATERIAL) and self.tblMaterial.item(
                    row, INTENSITY):
                if not self.tblMaterial.item(row, UNITS).data(Qt.UserRole):
                    self.tblMaterial.item(row, MATERIAL).setText('')
                    self.tblMaterial.item(row, INTENSITY).setText('')
                elif self.tblMaterial.item(row, MATERIAL):
                    units = self.tblMaterial.item(row, UNITS)
                    matName = self.tblMaterial.item(row, MATERIAL)
                    doseItem = self.tblMaterial.item(row, INTENSITY)
                    self.set_otherCols_fromUnit(units, matName, doseItem)

        if col == MATERIAL:
            units = self.tblMaterial.item(row, UNITS)
            matName = self.tblMaterial.item(row, MATERIAL).text()
            doseItem = self.tblMaterial.item(row, INTENSITY)
            self.set_otherCols_fromMat(units, matName, doseItem)

    @pyqtSlot(int, int)
    def on_tblBackground_cellChanged(self, row, col):
        """
        Listens for Material table cell changed
        """
        if col == UNITS:
            if self.tblBackground.item(
                    row, MATERIAL) and self.tblBackground.item(row, INTENSITY):
                if not self.tblBackground.item(row, UNITS).data(Qt.UserRole):
                    self.tblBackground.item(row, MATERIAL).setText('')
                    self.tblBackground.item(row, INTENSITY).setText('')
                elif self.tblBackground.item(row, MATERIAL):
                    units = self.tblBackground.item(row, UNITS)
                    matName = self.tblBackground.item(row, MATERIAL)
                    doseItem = self.tblBackground.item(row, INTENSITY)
                    self.set_otherCols_fromUnit(units, matName, doseItem)
        if col == MATERIAL:
            units = self.tblBackground.item(row, UNITS)
            matName = self.tblBackground.item(row, MATERIAL).text()
            doseItem = self.tblBackground.item(row, INTENSITY)
            self.set_otherCols_fromMat(units, matName, doseItem)

    def set_otherCols_fromUnit(self, units, matName, doseItem):
        textKeep = False
        if self.comboDetectorSelect.currentIndex() == 0:
            detector_list = [
                detector for detector in Session().query(Detector)
            ]
        else:
            detector_list = [
                Session().query(Detector).filter_by(
                    name=self.comboDetectorSelect.currentText()).first()
            ]
        for detector in detector_list:
            for baseSpectrum in detector.base_spectra:
                if baseSpectrum.material.name == matName.text(
                ) and not textKeep:
                    if (units.data(Qt.UserRole) == 'DOSE' and isinstance(baseSpectrum.rase_sensitivity, float)) or \
                       (units.data(Qt.UserRole) == 'FLUX' and isinstance(baseSpectrum.flux_sensitivity, float)):
                        textKeep = True
        if not textKeep:
            matName.setText('')

    def set_otherCols_fromMat(self, units, matName, doseItem):
        if matName:
            if not doseItem.text():
                doseItem.setText('0.1')
            if not units.text():
                textSet = False
                if self.comboDetectorSelect.currentIndex() == 0:
                    detector_list = [
                        detector for detector in Session().query(Detector)
                    ]
                else:
                    detector_list = [
                        Session().query(Detector).filter_by(
                            name=self.comboDetectorSelect.currentText()).first(
                            )
                    ]
                for detector in detector_list:
                    for baseSpectrum in detector.base_spectra:
                        if baseSpectrum.material.name == matName and not textSet:
                            units.tableWidget().blockSignals(True)
                            if isinstance(baseSpectrum.rase_sensitivity,
                                          float):
                                units.setText(units_labels['DOSE'])
                                units.setData(Qt.UserRole, 'DOSE')
                                textSet = True
                            else:
                                units.setText(units_labels['FLUX'])
                                units.setData(Qt.UserRole, 'FLUX')
                            units.tableWidget().blockSignals(False)

    def getSet(self, dialogField):
        values = []
        groups = dialogField.text().split(',')
        for group in groups:
            group = group.strip()
            if '-' in group and ':' in group:
                start, stop, step = [
                    float(x)
                    for x in re.match(r'([^-]+)-([^:]+):(.*)', group).groups()
                ]
                if step == 0:
                    values.append(start)
                    values.append(stop)
                else:
                    while start <= stop:
                        values.append(start)
                        start += step
            else:
                values.append(group)
        return values
Exemple #15
0
class AutomatedSCurve(ui_auto_scurve.Ui_AutoSCurveDialog, QDialog):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setWindowTitle('Automated S-Curve Generation')
        self.Rase = parent
        self.settings = RaseSettings()
        self.setupUi(self)
        self.session = Session()

        # setting default states
        self.detName = None
        self.detReplay = None
        self.static_background = []
        self.setInstrumentItems()
        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)

        # Validators
        self.line_rep.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_initrep.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_edge.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_dwell.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_minx.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_maxx.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_addpoints.setValidator(
            QRegularExpressionValidator(
                QRegularExpression(
                    r"((((\d+\.\d*)|(\d*\.\d+))|(\d+))((((,\d*\.\d+)|(,\d+\.\d*))|(,\d+))*)(,|,\.)?)"
                )))
        self.line_lowerbound.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_upperbound.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))

        # connections
        self.combo_inst.currentTextChanged.connect(self.updateMaterials)
        self.combo_mat.currentTextChanged[str].connect(
            lambda mat: self.updateUnits(mat, self.combo_matdose))
        self.btn_bgnd.clicked.connect(self.defineBackground)

        # Confirm enables
        self.combo_matdose.currentTextChanged.connect(self.enableOk)

        # Set values of various things based on user inputs
        self.line_rep.editingFinished.connect(
            lambda: self.setminval(self.line_rep, '2'))
        self.line_initrep.editingFinished.connect(
            lambda: self.setminval(self.line_initrep, '1'))
        self.line_edge.editingFinished.connect(
            lambda: self.setminval(self.line_edge, '1'))
        self.line_dwell.editingFinished.connect(
            lambda: self.setminval(self.line_dwell, '1', '0.00000000001'))
        self.line_minx.editingFinished.connect(lambda: self.setminval(
            self.line_minx, '0.00000001', '0.00000000001'))
        self.line_maxx.editingFinished.connect(
            lambda: self.setminval(self.line_maxx, '0.001', '0.00000000001'))
        self.line_lowerbound.editingFinished.connect(
            lambda: self.setminval(self.line_lowerbound, '0'))
        self.line_lowerbound.editingFinished.connect(
            lambda: self.setmaxval(self.line_lowerbound, '.99'))
        self.line_upperbound.editingFinished.connect(
            lambda: self.setmaxval(self.line_upperbound, '1'))
        self.line_minx.editingFinished.connect(self.checkMaxX)
        self.line_maxx.editingFinished.connect(self.checkMaxX)
        self.line_lowerbound.editingFinished.connect(self.checkMaxY)
        self.line_upperbound.editingFinished.connect(self.checkMaxY)
        self.line_addpoints.editingFinished.connect(self.removeZeroPoint)
        self.check_minx.stateChanged.connect(self.setDefaultMin)
        self.check_maxx.stateChanged.connect(self.setDefaultMax)
        self.check_addpoints.stateChanged.connect(self.setAddPoints)
        self.check_name.stateChanged.connect(self.setDefaultName)

    def setInstrumentItems(self):
        for det in self.session.query(Detector):
            if det.replay and det.replay.is_cmd_line:
                self.combo_inst.addItem(det.name)

    @pyqtSlot(str)
    def updateMaterials(self, detName):
        """
        Updates the possible material selection based on the selected instrument.
        Also identify the name of the replay associated with the chosen detector
        and set it for S-curve processing
        """
        self.combo_mat.clear()
        self.combo_mat.addItem('')

        if not detName.strip():
            self.combo_mat.setCurrentIndex(0)
            self.combo_mat.setEnabled(False)
            self.btn_bgnd.setEnabled(False)
            self.detName = None
            self.detReplay = None
        else:
            self.detName = detName
            self.combo_mat.setEnabled(True)
            self.btn_bgnd.setEnabled(True)
            det = self.session.query(Detector).filter_by(name=detName).first()
            self.detReplay = det.replay.name
            for baseSpectrum in det.base_spectra:
                self.combo_mat.addItem(baseSpectrum.material.name)

    def updateUnits(self, matName, combobox):
        """
        General function call for updating the flux/dose setting in the
        combobox after material has been selected
        """
        combobox.clear()
        combobox.addItem('')
        if not matName.strip():
            combobox.setCurrentIndex(0)
            combobox.setEnabled(False)
        else:
            combobox.setEnabled(True)
            det = self.session.query(Detector).filter_by(
                name=self.detName).first()
            for baseSpectrum in det.base_spectra:
                if baseSpectrum.material_name == matName:
                    if baseSpectrum.rase_sensitivity:
                        combobox.addItem('DOSE (\u00B5Sv/h)')
                        combobox.setCurrentIndex(1)
                    if baseSpectrum.flux_sensitivity:
                        combobox.addItem('FLUX (\u03B3/(cm\u00B2s))')

    @pyqtSlot(str)
    def enableOk(self, intensity):
        """Only enable the okay button if all the relevant points are selected"""
        if self.combo_matdose.currentText() and self.line_dwell.text() and \
                self.line_maxx.text() and self.line_minx.text():
            self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
        else:
            self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)

    def changeMinMax(self):
        """Change the min and max guess based on the background intensity"""

        if not self.check_minx.isChecked():
            minv = str(1E-7)
            minv = self.checkSciNote(minv)
            self.line_minx.setText(minv)
            self.checkMaxX()
            self.setAddPoints()
        if not self.check_maxx.isChecked():
            maxv = str(1E-2)
            maxv = self.checkSciNote(maxv)
            self.line_maxx.setText(maxv)
            self.checkMaxX()

    def checkSciNote(self, val):
        """If there is scientific notation, remove it so as to not break regex"""
        if 'E' in val.upper():
            sci = val.upper().split('E')
            if int(sci[1]) < 0:
                val = '0.' + ''.zfill(abs(int(sci[1])) - 1) + sci[0].replace(
                    '.', '')
            else:
                val = str(float(sci[0]) * 10**int(sci[1]))
        return val

    def setminval(self, line, setval='0.00000001', minval=None):
        if not minval:
            minval = setval
        try:
            if float(line.text()) <= float(minval):
                line.setText(setval)
        except:  # if the user enters a decimal point or something nonsensical
            line.setText(setval)

    def setmaxval(self, line, setval='1', maxval=None):
        if not maxval:
            maxval = setval
        try:
            if float(line.text()) >= float(maxval):
                line.setText(setval)
        except:  # if the user enters a decimal point or something nonsensical
            line.setText(setval)

    def checkMaxX(self):
        """Make sure the maximum x value is larger than the minimum x value"""
        if self.line_maxx.text() and self.line_minx.text():
            if float(self.line_maxx.text()) <= float(self.line_minx.text()):
                self.line_maxx.setText(str(float(self.line_minx.text()) * 1E5))

    def checkMaxY(self):
        """Make sure that the bounds don't overlap each other"""
        if self.line_upperbound.text() and self.line_lowerbound.text():
            if float(self.line_upperbound.text()) <= float(
                    self.line_lowerbound.text()):
                self.line_upperbound.setText(
                    str(max([0.9,
                             float(self.line_lowerbound.text()) * 1.01])))

    def setDefaultMin(self):
        """Set the default minimum x value if it has been unchecked"""
        if not self.check_minx.isChecked():
            self.line_minx.setText('0.00000001')
            self.setAddPoints()
            self.checkMaxX()

    def setDefaultMax(self):
        """Set the default max x value if it has been unchecked"""
        if not self.check_maxx.isChecked():
            self.line_maxx.setText('0.001')
            self.checkMaxX()

    def setAddPoints(self):
        """Set default user-added points and clears them if the box is unchecked"""
        if self.check_addpoints.isChecked():
            if not self.line_addpoints.text():
                self.line_addpoints.setText(self.line_minx.text())
        else:
            self.line_addpoints.setText('')

    def setDefaultName(self):
        """Set name back to [Default] if the checkbox is unchecked"""
        if not self.check_name.isChecked():
            self.line_name.setText('[Default]')

    def removeZeroPoint(self):
        """Disallow the user to add a point with 0 dose/flux"""
        if self.line_addpoints.text():
            self.line_addpoints.setText(
                self.endRecurse(self.line_addpoints.text()))
            addpoints = [
                float(i) for i in self.line_addpoints.text().split(',')
            ]
            if 0 in addpoints:
                addpoints = [i for i in addpoints if i != 0]
            addpoints = list(dict.fromkeys(addpoints))
            addpoints.sort()
            addpoints = [self.checkSciNote(str(i)) for i in addpoints]
            addpoints = str(addpoints)[1:-1].replace('\'', '').replace(' ', '')
            self.line_addpoints.setText(addpoints)

    def endRecurse(self, line):
        """Remove commas/periods at the end of the uesr-adde points list, recursively"""
        if (line[-1] == ',') or (line[-1] == '.'):
            return self.endRecurse(line[:-1])
        else:
            return line

    def defineBackground(self):
        dialog = ScenarioDialog(self, auto_s=True)
        dialog.comboDetectorSelect.setCurrentText(
            self.combo_inst.currentText())
        remove_layouts = [dialog.horizontalLayout, dialog.horizontalLayout_4]
        for layout in remove_layouts:
            for i in reversed(range(layout.count())):
                item = layout.itemAt(i)
                if isinstance(item, QWidgetItem):
                    item.widget().hide()
        dialog.pushButton.hide()
        dialog.tblMaterial.hide()
        dialog.label_scenlist.hide()
        dialog.txtScenariosList_2.hide()
        dialog.label_influences.hide()
        dialog.lstInfluences.hide()
        dialog.resize(440, 340)
        dialog.setWindowTitle('Set static background for the ' +
                              self.combo_inst.currentText() + '.')
        dialog.exec_()

    @pyqtSlot()
    def accept(self):
        if self.line_addpoints.text():
            addpoints = [
                float(i) for i in self.line_addpoints.text().split(',')
            ]
        else:
            addpoints = []
        self.input_d = {
            "instrument": self.detName,
            "replay": self.detReplay,
            "source": self.combo_mat.currentText(),
            "source_fd": self.combo_matdose.currentText().split()[0],
            "background": self.static_background,
            "dwell_time": float(self.line_dwell.text()),
            "results_type": self.combo_resulttype.currentText(),
            "input_reps": int(self.line_rep.text()),
            "invert_curve": self.check_invert.isChecked()
        }

        self.input_advanced = {
            "rise_points": int(self.line_edge.text()),
            "min_guess": float(self.line_minx.text()),
            "max_guess": float(self.line_maxx.text()),
            "repetitions": int(self.line_initrep.text()),
            "add_points": addpoints,
            "cleanup": self.check_cleanup.isChecked(),
            "custom_name": self.line_name.text(),
            "num_points": 6,  # hardcode for now
            "lower_bound": float(self.line_lowerbound.text()),
            "upper_bound": float(self.line_upperbound.text())
        }

        return QDialog.accept(self)
Exemple #16
0
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setWindowTitle('Automated S-Curve Generation')
        self.Rase = parent
        self.settings = RaseSettings()
        self.setupUi(self)
        self.session = Session()

        # setting default states
        self.detName = None
        self.detReplay = None
        self.static_background = []
        self.setInstrumentItems()
        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)

        # Validators
        self.line_rep.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_initrep.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_edge.setValidator(
            QRegularExpressionValidator(QRegularExpression("[0-9]{0,9}")))
        self.line_dwell.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_minx.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_maxx.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_addpoints.setValidator(
            QRegularExpressionValidator(
                QRegularExpression(
                    r"((((\d+\.\d*)|(\d*\.\d+))|(\d+))((((,\d*\.\d+)|(,\d+\.\d*))|(,\d+))*)(,|,\.)?)"
                )))
        self.line_lowerbound.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))
        self.line_upperbound.setValidator(
            QRegularExpressionValidator(
                QRegularExpression("((\d*\.\d*)|(\d*))")))

        # connections
        self.combo_inst.currentTextChanged.connect(self.updateMaterials)
        self.combo_mat.currentTextChanged[str].connect(
            lambda mat: self.updateUnits(mat, self.combo_matdose))
        self.btn_bgnd.clicked.connect(self.defineBackground)

        # Confirm enables
        self.combo_matdose.currentTextChanged.connect(self.enableOk)

        # Set values of various things based on user inputs
        self.line_rep.editingFinished.connect(
            lambda: self.setminval(self.line_rep, '2'))
        self.line_initrep.editingFinished.connect(
            lambda: self.setminval(self.line_initrep, '1'))
        self.line_edge.editingFinished.connect(
            lambda: self.setminval(self.line_edge, '1'))
        self.line_dwell.editingFinished.connect(
            lambda: self.setminval(self.line_dwell, '1', '0.00000000001'))
        self.line_minx.editingFinished.connect(lambda: self.setminval(
            self.line_minx, '0.00000001', '0.00000000001'))
        self.line_maxx.editingFinished.connect(
            lambda: self.setminval(self.line_maxx, '0.001', '0.00000000001'))
        self.line_lowerbound.editingFinished.connect(
            lambda: self.setminval(self.line_lowerbound, '0'))
        self.line_lowerbound.editingFinished.connect(
            lambda: self.setmaxval(self.line_lowerbound, '.99'))
        self.line_upperbound.editingFinished.connect(
            lambda: self.setmaxval(self.line_upperbound, '1'))
        self.line_minx.editingFinished.connect(self.checkMaxX)
        self.line_maxx.editingFinished.connect(self.checkMaxX)
        self.line_lowerbound.editingFinished.connect(self.checkMaxY)
        self.line_upperbound.editingFinished.connect(self.checkMaxY)
        self.line_addpoints.editingFinished.connect(self.removeZeroPoint)
        self.check_minx.stateChanged.connect(self.setDefaultMin)
        self.check_maxx.stateChanged.connect(self.setDefaultMax)
        self.check_addpoints.stateChanged.connect(self.setAddPoints)
        self.check_name.stateChanged.connect(self.setDefaultName)
Exemple #17
0
def _getCountsDoseAndSensitivity(scenario, detector, degradations=None):
    """

    :param scenario:
    :param detector:
    :return:
    """
    session = Session()

    # distortion:  distort ecal with influence factors
    ecal = [detector.ecal3, detector.ecal2, detector.ecal1, detector.ecal0]
    energies = np.polyval(ecal, np.arange(detector.chan_count))
    new_influences = []
    bin_widths = np.zeros([len(scenario.influences), len(energies)])
    for index, influence in enumerate(scenario.influences):
        detInfl = session.query(DetectorInfluence).filter_by(influence_name=influence.name).first()
        new_infl = [detInfl.infl_0, detInfl.infl_1, detInfl.infl_2, detInfl.fixed_smear, detInfl.linear_smear]
        if degradations:
            new_infl = [infl + deg for infl, deg in zip(new_infl, degradations[index])]
            # deal with potential negative values
            for position, n_inf in enumerate(new_infl):
                if n_inf < 0:
                    if not position == 1:
                        new_infl[position] = 0
                    else:
                        new_infl[position] = 0.0001

        new_influences.append(new_infl)

        if new_infl[0] != 0 or new_infl[2] != 0 or new_infl[1] != 1:
            energies = np.polyval([new_infl[2], (new_infl[1]), new_infl[0]], energies)
        # convert fixed energy smear distortion from energy to bins
        if new_infl[3] != 0:
            e_width = new_infl[3] / 2
            for sub_index, energy in enumerate(energies):
                b0 = np.roots([new_infl[2], new_infl[1], new_infl[0] - (energy - e_width)])
                b1 = np.roots([new_infl[2], new_infl[1], new_infl[0] - (energy + e_width)])
                bin_widths[index][sub_index] = max(b1) - max(b0)

    # get dose, counts and sensitivity for each material
    countsDoseAndSensitivity = []
    for scenMaterial in scenario.scen_materials + scenario.scen_bckg_materials:
        baseSpectrum = (session.query(BaseSpectrum)
                        .filter_by(detector_name=detector.name,
                                   material_name=scenMaterial.material_name)
                        ).first()
        counts = baseSpectrum.get_counts_as_np()

        if scenario.influences:
            for index, infl in enumerate(new_influences):
                counts = apply_distortions(infl, counts, bin_widths[index], energies, ecal)

        if scenMaterial.fd_mode == 'FLUX':
            countsDoseAndSensitivity.append((counts, scenMaterial.dose, baseSpectrum.flux_sensitivity))
        else:
            countsDoseAndSensitivity.append((counts, scenMaterial.dose, baseSpectrum.rase_sensitivity))

    # if the detector has an internal calibration source, it needs to be added with special treatment
    if detector.includeSecondarySpectrum and detector.secondary_type == secondary_type['internal']:

        secondary_spectrum = (session.query(BackgroundSpectrum).filter_by(detector_name=detector.name)).first()
        counts = secondary_spectrum.get_counts_as_np()

        # apply distortion on counts
        if scenario.influences:
            for index, infl in enumerate(new_influences):
                counts = apply_distortions(infl, counts, bin_widths[index], energies, ecal)

        # extract counts per second
        cps = sum(counts)/secondary_spectrum.livetime

        # the internal calibration spectrum is scaled only by time
        # so the sensitivity parameter is set to the cps and the dose to 1
        countsDoseAndSensitivity.append((counts, 1.0, cps))

    return countsDoseAndSensitivity
Exemple #18
0
def generate_curve(r, input_data, advanced):
    """Primary function where the points that make up the S-curve are determined"""
    session = Session()
    if advanced['custom_name'] == '[Default]':
        group_name = ("AutoScurve_" + input_data['instrument'] + '_' +
                      input_data['source'])
    else:
        suffix = 0
        while True:
            if session.query(ScenarioGroup).filter_by(
                    name=advanced['custom_name']).first():
                if not session.query(ScenarioGroup).filter_by(
                        name=advanced['custom_name']).first().scenarios:
                    group_name = (advanced['custom_name'])
                    break
                else:
                    suffix += 1
                    advanced['custom_name'] = advanced[
                        'custom_name'] + '_' + str(suffix)
            else:
                group_name = (advanced['custom_name'])
                break

    detName = [input_data['instrument']]
    detector = session.query(Detector).filter_by(name=detName[0]).first()
    condition = False
    already_done = False

    expand = 0
    first_run = True
    # All scenarios within the group that have the same source/backgrounds
    make_scen_group(session, group_name, input_data)
    scenIdall = make_scenIdall(session, input_data)
    # scenarios that will be rerun in this run
    scenIds_no_persist = []

    maxback = 0
    if input_data['background']:
        for bmat in input_data['background']:
            bmat = bmat[0]
            if bmat[0] == input_data['source_fd']:
                if maxback == 0:
                    maxback = float(bmat[2])
                else:
                    maxback = max(maxback, float(bmat[2]))
    if not maxback:
        maxback = 0.1

    while not condition:

        # newly generated scenIds, and all scenIds with source/backgrounds as defined in the auto s-curve gui
        scenIds, scenIds_no_persist, scenIdall = gen_scens(
            input_data, advanced, session, scenIdall, scenIds_no_persist,
            group_name, advanced['repetitions'])
        abort = run_scenarios(r, scenIds, detector, input_data['replay'],
                              condition, expand, first_run)
        first_run = False
        if abort:
            cleanup_scenarios(advanced['repetitions'], scenIds_no_persist)
            return

        r.calculateScenarioStats(1, scenIdall, detName)

        if input_data['results_type'] == 'C&C':
            results = r.scenario_stats_df['C&C']
        elif input_data['results_type'] == 'TP':
            results = r.scenario_stats_df['TP']
        elif input_data['results_type'] == 'Precision':
            results = r.scenario_stats_df['Precision']
        elif input_data['results_type'] == 'Recall':
            results = r.scenario_stats_df['Recall']
        elif input_data['results_type'] == 'Fscore':
            results = r.scenario_stats_df['F_Score']
        else:  # to add more later
            results = r.scenario_stats_df['PID']
        if not input_data['invert_curve']:
            results = results.sort_values()
        else:
            results = results.sort_values(ascending=False)

        if max(results) >= advanced['upper_bound'] and min(
                results) <= advanced['lower_bound']:
            """If there are values surrounding the rising edge"""
            # find scenarios in for cases
            ids_on_edge = []
            start_list = []
            end_list = []
            prev_point = False
            for index, result in enumerate(results):
                if (not input_data['invert_curve'] and result <= advanced['lower_bound']) or \
                        (input_data['invert_curve'] and result >= advanced['upper_bound']):
                    start_list.append(results.index[index].split('*')[0])
                    if prev_point:
                        ids_on_edge = [
                        ]  # rose and then dropped back down (i.e.: fluctuations)
                        prev_point = False
                elif advanced['lower_bound'] <= result <= advanced[
                        'upper_bound']:
                    ids_on_edge.append(results.index[index].split('*')[0])
                    prev_point = True
                elif (not input_data['invert_curve'] and result >= advanced['upper_bound']) or \
                        (input_data['invert_curve'] and result <= advanced['lower_bound']):
                    end_list.append(results.index[index].split('*')[0])
            # Grab doses for scenarios on the edges of the S-curve. The first value in each list is
            # the value that is the second closest to the rising edge, and the second is the closest
            start_val = [-1, -1]
            end_val = [-1, -1]

            for scenid in scenIdall:
                scen = session.query(Scenario).filter_by(id=scenid).first()
                if scenid in start_list:
                    if start_val[1] == -1 or scen.scen_materials[
                            0].dose >= start_val[1]:
                        start_val = set_bounds(start_val,
                                               scen.scen_materials[0].dose)
                if scen.id in end_list:
                    if end_val[1] == -1 or scen.scen_materials[
                            0].dose < end_val[1]:
                        end_val = set_bounds(end_val,
                                             scen.scen_materials[0].dose)

            # check if there are enough points on the rising edge
            if len(ids_on_edge) >= advanced['rise_points']:
                condition = True
                # to avoid persistence errors by reusing a value with the same ID but different replications
                edge_count, bound_scens_start, bound_scens_end = check_edge_ids(
                    session, input_data['input_reps'], start_list, end_list,
                    ids_on_edge, detector)
                if edge_count < advanced[
                        'rise_points'] or bound_scens_start < 2 or bound_scens_end < 2:
                    advanced['min_guess'] = start_val[0] * 0.9
                    advanced['max_guess'] = end_val[0] * 1.1
                    advanced['num_points'] = advanced['rise_points'] + 4
                else:
                    already_done = True
            else:
                # avoid infinite loop due to being stuck on edge cases. Moves slightly inward to better populate edge
                if start_val[1] == advanced['min_guess']:
                    advanced['min_guess'] = start_val[1] + (
                        end_val[1] - start_val[1]) * 0.01
                else:
                    advanced['min_guess'] = start_val[1]
                if end_val[1] == advanced['max_guess']:
                    advanced['max_guess'] = end_val[1] - (end_val[1] -
                                                          start_val[1]) * 0.01
                else:
                    advanced['max_guess'] = end_val[1]
                advanced['num_points'] = advanced['rise_points']  # + 4

        elif min(results) >= advanced['lower_bound']:
            """If the quoted results aren't small enough yet"""
            expand += 1
            dose_list = []
            for scenId in scenIdall:
                scen = session.query(Scenario).filter_by(id=scenId).first()
                dose_list.append(scen.scen_materials[0].dose)
            dose_list.sort()

            if not input_data['invert_curve']:
                dose_bound = dose_list[0]
                if (0 < dose_bound <= 1E-9 * maxback
                        and len(scenIdall) >= 9) or 0 < dose_bound <= 1E-12:
                    fail_never(r, scenIdall, [input_data['instrument']])
                    return
                if len(dose_list) > 1:
                    step_ratio = dose_list[0] / dose_list[1]
                else:
                    step_ratio = dose_list[0] * 0.9
                advanced['min_guess'] = advanced['min_guess'] * step_ratio
                advanced['max_guess'] = advanced['min_guess']
                advanced['num_points'] = 1
            else:
                dose_bound = dose_list[-1]
                if dose_bound >= 40 * maxback and len(scenIdall) >= 9:
                    fail_never(r, scenIdall, [input_data['instrument']])
                    return
                if len(dose_list) > 1:
                    step_ratio = dose_list[-1] / dose_list[-2]
                else:
                    step_ratio = dose_list[0] * 1.1
                advanced['min_guess'] = advanced['max_guess'] * step_ratio
                advanced['max_guess'] = advanced['min_guess']
                advanced['num_points'] = 1

        elif max(results) <= advanced['upper_bound']:
            """If the quoted results aren't large enough yet"""
            expand += 1
            dose_list = []
            for scenId in scenIdall:
                scen = session.query(Scenario).filter_by(id=scenId).first()
                # for scen in session.query(ScenarioGroup).filter_by(name=group_name).first().scenarios:
                dose_list.append(scen.scen_materials[0].dose)
            dose_list.sort()
            if not input_data['invert_curve']:
                dose_bound = dose_list[-1]
                if dose_bound >= 40 * maxback and len(scenIdall) >= 9:
                    fail_always(r, scenIdall, [input_data['instrument']])
                    return
                if len(dose_list) > 1:
                    step_ratio = dose_list[-1] / dose_list[-2]
                else:
                    step_ratio = dose_list[0] * 1.1
                advanced['min_guess'] = advanced['max_guess'] * step_ratio
                advanced['max_guess'] = advanced['min_guess']
                advanced['num_points'] = 1
            else:
                dose_bound = dose_list[0]
                if (0 < dose_bound <= 1E-9 * maxback
                        and len(scenIdall) >= 9) or 0 < dose_bound <= 1E-12:
                    fail_always(r, scenIdall, [input_data['instrument']])
                    return
                if len(dose_list) > 1:
                    step_ratio = dose_list[0] / dose_list[1]
                else:
                    step_ratio = dose_list[0] * 0.9
                advanced['min_guess'] = advanced['min_guess'] * step_ratio
                advanced['max_guess'] = advanced['min_guess']
                advanced['num_points'] = 1

    if condition:
        if not already_done:
            scenIds, _, _ = gen_scens(input_data, advanced, session, scenIdall,
                                      scenIds_no_persist, group_name,
                                      input_data['input_reps'], condition)
            detector = session.query(Detector).filter_by(
                name=detName[0]).first()
            abort = run_scenarios(r, scenIds, detector, input_data['replay'],
                                  condition)
            if abort:
                cleanup_scenarios(advanced['repetitions'], scenIds_no_persist)
                cleanup_scenarios(input_data['input_reps'], scenIds)
                return

        if advanced['cleanup']:
            cleanup_scenarios(advanced['repetitions'], scenIds_no_persist)
            r.populateScenarios()

        msgbox = QMessageBox(QMessageBox.Question,
                             'S-Curve generation complete!',
                             'Would you like to view the results?')
        msgbox.addButton(QMessageBox.Yes)
        msgbox.addButton(QMessageBox.No)
        answer = msgbox.exec()
        if answer == QMessageBox.Yes:
            viewResults(r, scenIds, [input_data['instrument']])