diff --git a/docs/source/release/v3.14.0/direct_inelastic.rst b/docs/source/release/v3.14.0/direct_inelastic.rst index f518ed0199701ebdcb7ad8a55f185e4f2be21ab4..e8e3a703a04f1b0bee68e5e3ec20a40777bf1a13 100644 --- a/docs/source/release/v3.14.0/direct_inelastic.rst +++ b/docs/source/release/v3.14.0/direct_inelastic.rst @@ -9,5 +9,21 @@ Direct Inelastic Changes putting new features at the top of the section, followed by improvements, followed by bug fixes. + +Interfaces +---------- + + +New features +############ + +- Added the ability to save the results of the TOFTOF reduction as Ascii files. + + +Improvements +############ + +- improved ``Save``-section of the TOFTOF reduction dialog. + :ref:`Release 3.14.0 <v3.14.0>` diff --git a/scripts/Interface/reduction_gui/reduction/toftof/toftof_reduction.py b/scripts/Interface/reduction_gui/reduction/toftof/toftof_reduction.py index 9762851c610f70b494f8c2adf434517fa85b7ea2..d15fcd07abecfaa339e94ef251d3278d103f76f7 100644 --- a/scripts/Interface/reduction_gui/reduction/toftof/toftof_reduction.py +++ b/scripts/Interface/reduction_gui/reduction/toftof/toftof_reduction.py @@ -7,7 +7,7 @@ TOFTOF reduction workflow gui. """ from __future__ import (absolute_import, division, print_function) -from itertools import repeat +from itertools import repeat, compress import xml.dom.minidom from reduction_gui.reduction.scripter import BaseScriptElement, BaseReductionScripter @@ -69,11 +69,11 @@ class TOFTOFScriptElement(BaseScriptElement): DEF_normalise = NORM_NONE DEF_correctTof = CORR_TOF_NONE - DEF_saveSofQW = False - DEF_saveSofTW = False - DEF_saveNXSPE = False - DEF_saveNexus = False - DEF_saveAscii = False + DEF_saveSofTWNxspe = False + DEF_saveSofTWNexus = False + DEF_saveSofTWAscii = False + DEF_saveSofQWNexus = False + DEF_saveSofQWAscii = False XML_TAG = 'TOFTOFReduction' @@ -123,11 +123,11 @@ class TOFTOFScriptElement(BaseScriptElement): # save data self.saveDir = '' - self.saveSofQW = self.DEF_saveSofQW - self.saveSofTW = self.DEF_saveSofTW - self.saveNXSPE = self.DEF_saveNXSPE - self.saveNexus = self.DEF_saveNexus - self.saveAscii = self.DEF_saveAscii + self.saveSofTWNxspe = self.DEF_saveSofTWNxspe + self.saveSofTWNexus = self.DEF_saveSofTWNexus + self.saveSofTWAscii = self.DEF_saveSofTWAscii + self.saveSofQWNexus = self.DEF_saveSofQWNexus + self.saveSofQWAscii = self.DEF_saveSofQWAscii def to_xml(self): res = [''] @@ -171,11 +171,11 @@ class TOFTOFScriptElement(BaseScriptElement): put('keep_steps', self.keepSteps) put('save_dir', self.saveDir) - put('save_sofqw', self.saveSofQW) - put('save_softw', self.saveSofTW) - put('save_nxspe', self.saveNXSPE) - put('save_nexus', self.saveNexus) - put('save_ascii', self.saveAscii) + put('saveSofTWNxspe', self.saveSofTWNxspe) + put('saveSofTWNexus', self.saveSofTWNexus) + put('saveSofTWAscii', self.saveSofTWAscii) + put('saveSofQWNexus', self.saveSofQWNexus) + put('saveSofQWAscii', self.saveSofQWAscii) return '<{0}>\n{1}</{0}>\n'.format(self.XML_TAG, res[0]) @@ -255,11 +255,19 @@ class TOFTOFScriptElement(BaseScriptElement): self.keepSteps = get_bol('keep_steps', self.DEF_keepSteps) self.saveDir = get_str('save_dir') - self.saveSofQW = get_bol('save_sofqw', self.DEF_saveSofQW) - self.saveSofTW = get_bol('save_softw', self.DEF_saveSofTW) - self.saveNXSPE = get_bol('save_nxspe', self.DEF_saveNXSPE) - self.saveNexus = get_bol('save_nexus', self.DEF_saveNexus) - self.saveAscii = get_bol('save_ascii', self.DEF_saveAscii) + + # for backwards compatibility: + SofQW = get_bol('save_sofqw', False) + SofTW = get_bol('save_softw', False) + NXSPE = get_bol('save_nxspe', False) + Nexus = get_bol('save_nexus', False) + Ascii = get_bol('save_ascii', False) + + self.saveSofTWNxspe = get_bol('saveSofTWNxspe', (SofTW and NXSPE) or self.DEF_saveSofTWNxspe) + self.saveSofTWNexus = get_bol('saveSofTWNexus', (SofTW and Nexus) or self.DEF_saveSofTWNexus) + self.saveSofTWAscii = get_bol('saveSofTWAscii', (SofTW and Ascii) or self.DEF_saveSofTWAscii) + self.saveSofQWNexus = get_bol('saveSofQWNexus', (SofQW and Nexus) or self.DEF_saveSofQWNexus) + self.saveSofQWAscii = get_bol('saveSofQWAscii', (SofQW and Ascii) or self.DEF_saveSofQWAscii) def validate_inputs(self): # must have vanadium for TOF correction @@ -293,15 +301,9 @@ class TOFTOFScriptElement(BaseScriptElement): self.error('missing vanadium comment') # saving settings must be consistent - if self.saveNXSPE or self.saveNexus or self.saveAscii: - if not self.saveDir: - self.error('missing directory to save the data') - elif not (self.saveSofQW or self.saveSofTW): - self.error('you must select workspaces to save') - elif self.saveSofQW or self.saveSofTW: - if not self.saveDir: - self.error('missing directory to save the data') - self.error('missing data format to save') + if any([self.saveSofTWNxspe, self.saveSofTWNexus, self.saveSofTWAscii, + self.saveSofQWNexus, self.saveSofQWAscii] ) and not self.saveDir: + self.error('missing directory to save the data') @staticmethod def error(message): @@ -384,14 +386,21 @@ class TOFTOFScriptElement(BaseScriptElement): def get_time(self, workspace): return self.get_log(workspace, 'duration') - def save_wsgroup(self, wsgroup, suffix): + allowed_save_formats = ['nxspe', 'nexus', 'ascii'] + + def save_wsgroup(self, wsgroup, suffix, spectrumMetaData, saveFormats): + assert(saveFormats <= set(self.allowed_save_formats)) + if len(saveFormats) == 0: + return self.l("# save {}".format(wsgroup)) self.l("for ws in {}:".format(wsgroup)) self.l(" name = ws.getComment() + {}".format(suffix)) - if self.saveNXSPE and self.binEon: - self.l(" SaveNXSPE(ws, join(r'{}', name + '.nxspe'), Efixed=Ei)".format(self.saveDir)) - if self.saveNexus: + if 'nxspe' in saveFormats: + self.l(" SaveNXSPE(ws, join(r'{}', name + '.nxspe'), Efixed=Ei)".format(self.saveDir,)) + if 'nexus' in saveFormats: self.l(" SaveNexus(ws, join(r'{}', name + '.nxs'))".format(self.saveDir)) + if 'ascii' in saveFormats: + self.l(" SaveAscii(ws, join(r'{}', name + '.txt'), SpectrumMetaData='{}')".format(self.saveDir, spectrumMetaData)) self.l() def normalize_data(self, gPrefix, gDataRuns, wsEC='', wsVan=''): @@ -655,9 +664,11 @@ class TOFTOFScriptElement(BaseScriptElement): self.l("DeleteWorkspaces('step1,step2,step3')") self.l() - if self.saveSofTW: - suf = "'_Ei_{}'.format(round(Ei,2))" - self.save_wsgroup(gLast, suf) + # save S(2theta, w): + suf = "'_Ei_{}'.format(round(Ei,2))" + #nxspe only if self.binEon + saveFormats = set(compress(self.allowed_save_formats, [self.saveSofTWNxspe, self.saveSofTWNexus, self.saveSofTWAscii])) + self.save_wsgroup(gLast, suf, 'Angle', saveFormats) if self.binQon and self.binEon: gDataBinQ = gData + 'SQW' @@ -669,8 +680,10 @@ class TOFTOFScriptElement(BaseScriptElement): if self.replaceNaNs: self.l("{} = ReplaceSpecialValues({}, NaNValue=0, NaNError=1)".format(gDataBinQ, gDataBinQ)) self.l() - if self.saveSofQW: - self.save_wsgroup(gDataBinQ, "'_SQW'") + + # save S(Q, w) + saveFormats = set(compress(self.allowed_save_formats, [False, self.saveSofQWNexus, self.saveSofQWAscii])) + self.save_wsgroup(gDataBinQ, "'_SQW'", 'Q', saveFormats) self.rename_workspaces(gData) diff --git a/scripts/Interface/reduction_gui/widgets/toftof/toftof_setup.py b/scripts/Interface/reduction_gui/widgets/toftof/toftof_setup.py index 7aebda582c0e28cca1fd1cecc44d8030bac6238d..0ebf899ce574ebc8b369139cc825a36ba5ef0293 100644 --- a/scripts/Interface/reduction_gui/widgets/toftof/toftof_setup.py +++ b/scripts/Interface/reduction_gui/widgets/toftof/toftof_setup.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- #pylint: disable = too-many-instance-attributes, too-many-branches, too-many-public-methods #pylint: disable = W0622 """ @@ -76,7 +77,7 @@ class TOFTOFSetupWidget(BaseWidget): TIP_chkSofTW = '' TIP_chkNxspe = 'Save for MSlice' TIP_chkNexus = 'Save for Mantid' - TIP_chkAscii = 'Will be available soon' + TIP_chkAscii = 'Save as text' TIP_rbtNormaliseNone = '' TIP_rbtNormaliseMonitor = '' @@ -109,6 +110,14 @@ class TOFTOFSetupWidget(BaseWidget): widget.setToolTip(text) return widget + def setEnabled(widget, *widgets): + """enables widget, when value of all widgets evaluates to true""" + def setEnabled(): + widget.setEnabled(all(w.isChecked() for w in widgets)) + for w in widgets: + w.toggled.connect(setEnabled) + return widget + def DoubleEdit(): edit = SmallQLineEdit() edit.setValidator(QDoubleValidator()) @@ -130,18 +139,18 @@ class TOFTOFSetupWidget(BaseWidget): set_spin(self.ecFactor, 0, 1) self.binEon = tip(QCheckBox(), self.TIP_binEon) - self.binEstart = tip(QDoubleSpinBox(), self.TIP_binEstart) - self.binEstep = tip(QDoubleSpinBox(), self.TIP_binEstep) - self.binEend = tip(QDoubleSpinBox(), self.TIP_binEend) + self.binEstart = setEnabled(tip(QDoubleSpinBox(), self.TIP_binEstart), self.binEon) + self.binEstep = setEnabled(tip(QDoubleSpinBox(), self.TIP_binEstep), self.binEon) + self.binEend = setEnabled(tip(QDoubleSpinBox(), self.TIP_binEend), self.binEon) set_spin(self.binEstart) set_spin(self.binEstep, decimals = 4) set_spin(self.binEend) - self.binQon = tip(QCheckBox(), self.TIP_binQon) - self.binQstart = tip(QDoubleSpinBox(), self.TIP_binQstart) - self.binQstep = tip(QDoubleSpinBox(), self.TIP_binQstep) - self.binQend = tip(QDoubleSpinBox(), self.TIP_binQend) + self.binQon = setEnabled(tip(QCheckBox(), self.TIP_binQon), self.binEon) + self.binQstart = setEnabled(tip(QDoubleSpinBox(), self.TIP_binQstart), self.binEon, self.binQon) + self.binQstep = setEnabled(tip(QDoubleSpinBox(), self.TIP_binQstep), self.binEon, self.binQon) + self.binQend = setEnabled(tip(QDoubleSpinBox(), self.TIP_binQend), self.binEon, self.binQon) set_spin(self.binQstart) set_spin(self.binQstep) @@ -160,15 +169,17 @@ class TOFTOFSetupWidget(BaseWidget): self.btnSaveDir = tip(QPushButton('Browse'), self.TIP_btnSaveDir) self.chkSubtractECVan = tip(QCheckBox('Subtract empty can from vanadium'), self.TIP_chkSubtractECVan) - self.chkReplaceNaNs = tip(QCheckBox('Replace special values in S(Q,W) with 0'), self.TIP_chkReplaceNaNs) - self.chkCreateDiff = tip(QCheckBox('Create diffractograms'), self.TIP_chkCreateDiff) + self.chkReplaceNaNs = setEnabled(tip(QCheckBox(u'Replace special values in S(Q, ω) with 0'), self.TIP_chkReplaceNaNs), + self.binEon) + self.chkCreateDiff = setEnabled(tip(QCheckBox('Create diffractograms'), self.TIP_chkCreateDiff), self.binEon) self.chkKeepSteps = tip(QCheckBox('Keep intermediate steps'), self.TIP_chkKeepSteps) - self.chkSofQW = tip(QCheckBox('S(Q,W)'), self.TIP_chkSofQW) - self.chkSofTW = tip(QCheckBox('S(2theta,W)'), self.TIP_chkSofTW) - self.chkNxspe = tip(QCheckBox('NXSPE'), self.TIP_chkNxspe) - self.chkNexus = tip(QCheckBox('NeXus'), self.TIP_chkNexus) - self.chkAscii = tip(QCheckBox('Ascii'), self.TIP_chkAscii) + self.chkSofTWNxspe = setEnabled(tip(QCheckBox('NXSPE'), self.TIP_chkNxspe), self.binEon) + self.chkSofTWNexus = tip(QCheckBox('NeXus'), self.TIP_chkNexus) + self.chkSofTWAscii = tip(QCheckBox('Ascii'), self.TIP_chkAscii) + + self.chkSofQWNexus = setEnabled(tip(QCheckBox('NeXus'), self.TIP_chkNexus), self.binEon, self.binQon) + self.chkSofQWAscii = setEnabled(tip(QCheckBox('Ascii'), self.TIP_chkAscii), self.binEon, self.binQon) self.rbtNormaliseNone = tip(QRadioButton('none'), self.TIP_rbtNormaliseNone) self.rbtNormaliseMonitor = tip(QRadioButton('to monitor'), self.TIP_rbtNormaliseMonitor) @@ -202,10 +213,12 @@ class TOFTOFSetupWidget(BaseWidget): label.setToolTip(tip) return label + self.gbSave = QGroupBox('Save reduced data') + self.gbSave.setCheckable(True) + gbDataDir = QGroupBox('Data search directory') gbPrefix = QGroupBox('Workspace prefix') gbOptions = QGroupBox('Options') - gbSave = QGroupBox('Save reduced data') gbInputs = QGroupBox('Inputs') gbBinning = QGroupBox('Binning') gbData = QGroupBox('Data') @@ -213,7 +226,7 @@ class TOFTOFSetupWidget(BaseWidget): box = QVBoxLayout() self._layout.addLayout(box) - box.addLayout(hbox(vbox(gbDataDir, gbInputs, gbBinning, gbOptions, 1), vbox(gbPrefix, gbData, gbSave))) + box.addLayout(hbox(vbox(gbDataDir, gbInputs, gbBinning, gbOptions, 1), vbox(gbPrefix, gbData, self.gbSave))) gbDataDir.setLayout(hbox(self.dataDir, self.btnDataDir)) gbPrefix.setLayout(hbox(self.prefix,)) @@ -286,25 +299,23 @@ class TOFTOFSetupWidget(BaseWidget): gbData.setLayout(hbox(self.dataRunsView)) grid = QGridLayout() - grid.addWidget(QLabel('Workspaces'), 0, 0) - grid.addWidget(self.chkSofQW, 1, 0) - grid.addWidget(self.chkSofTW, 1, 1) - grid.addWidget(QLabel('Format'), 2, 0) - grid.addWidget(self.chkNxspe, 3, 0) - grid.addWidget(self.chkNexus, 3, 1) - grid.addWidget(self.chkAscii, 3, 2) - grid.setColumnStretch(3, 1) - - # disable save Ascii, it is not available for the moment - self.chkAscii.setEnabled(False) - - gbSave.setLayout(vbox(label('Directory',''), hbox(self.saveDir, self.btnSaveDir), grid)) + saveDirGroup = hbox(self.saveDir, self.btnSaveDir) + grid.addWidget(QLabel('Directory'), 0, 0) + grid.addLayout(saveDirGroup, 0, 1, 1, 4) + grid.addWidget(setEnabled(QLabel(u'S(Q, ω):'), self.binEon), 1, 0) + grid.addWidget(self.chkSofQWNexus, 1, 1) + grid.addWidget(self.chkSofQWAscii, 1, 2) + grid.addItem(QSpacerItem(5, 5, hPolicy=QSizePolicy.Expanding), 1, 4) + grid.addWidget(QLabel(u'S(2θ, ω):'), 2, 0) + grid.addWidget(self.chkSofTWNexus, 2, 1) + grid.addWidget(self.chkSofTWAscii, 2, 2) + grid.addWidget(self.chkSofTWNxspe, 2, 3) + + self.gbSave.setLayout(grid) # handle signals self.btnDataDir.clicked.connect(self._onDataDir) self.btnSaveDir.clicked.connect(self._onSaveDir) - self.binEon.clicked.connect(self._onBinEon) - self.binQon.clicked.connect(self._onBinQon) self.runDataModel.selectCell.connect(self._onSelectedCell) def _onDataDir(self): @@ -317,19 +328,6 @@ class TOFTOFSetupWidget(BaseWidget): if dirname: self.saveDir.setText(dirname) - def _onBinEon(self, onVal): - if not onVal: - self.chkNxspe.setChecked(False) - self.chkReplaceNaNs.setChecked(False) - self.binQon.setChecked(False) - for widget in (self.binEstart, self.binEstep, self.binEend, self.chkCreateDiff, self.chkNxspe, self.binQon, - self.binQstart, self.binQstep, self.binQend, self.chkReplaceNaNs, self.chkSofQW): - widget.setEnabled(onVal) - - def _onBinQon(self, onVal): - for widget in (self.binQstart, self.binQstep, self.binQend, self.chkReplaceNaNs, self.chkSofQW): - widget.setEnabled(onVal) - def _onSelectedCell(self, index): self.dataRunsView.setCurrentIndex(index) self.dataRunsView.setFocus() @@ -340,45 +338,48 @@ class TOFTOFSetupWidget(BaseWidget): def line_text(lineEdit): return lineEdit.text().strip() + def is_checked(checkBox): + return checkBox.isChecked() and checkBox.isEnabled() + elem.facility_name = self._settings.facility_name elem.instrument_name = self._settings.instrument_name - elem.prefix = line_text(self.prefix) - elem.dataDir = line_text(self.dataDir) + elem.prefix = line_text(self.prefix) + elem.dataDir = line_text(self.dataDir) - elem.vanRuns = line_text(self.vanRuns) - elem.vanCmnt = line_text(self.vanCmnt) - elem.vanTemp = OptionalFloat(line_text(self.vanTemp)) + elem.vanRuns = line_text(self.vanRuns) + elem.vanCmnt = line_text(self.vanCmnt) + elem.vanTemp = OptionalFloat(line_text(self.vanTemp)) - elem.ecRuns = line_text(self.ecRuns) - elem.ecTemp = OptionalFloat(line_text(self.ecTemp)) - elem.ecFactor = self.ecFactor.value() + elem.ecRuns = line_text(self.ecRuns) + elem.ecTemp = OptionalFloat(line_text(self.ecTemp)) + elem.ecFactor = self.ecFactor.value() - elem.dataRuns = self.runDataModel.tableData + elem.dataRuns = self.runDataModel.tableData - elem.binEon = self.binEon.isChecked() - elem.binEstart = self.binEstart.value() - elem.binEstep = self.binEstep.value() - elem.binEend = self.binEend.value() + elem.binEon = is_checked(self.binEon) + elem.binEstart = self.binEstart.value() + elem.binEstep = self.binEstep.value() + elem.binEend = self.binEend.value() - elem.binQon = self.binQon.isChecked() - elem.binQstart = self.binQstart.value() - elem.binQstep = self.binQstep.value() - elem.binQend = self.binQend.value() + elem.binQon = is_checked(self.binQon) + elem.binQstart = self.binQstart.value() + elem.binQstep = self.binQstep.value() + elem.binQend = self.binQend.value() - elem.maskDetectors = line_text(self.maskDetectors) + elem.maskDetectors = line_text(self.maskDetectors) - elem.subtractECVan = self.chkSubtractECVan.isChecked() - elem.replaceNaNs = self.chkReplaceNaNs.isChecked() - elem.createDiff = self.chkCreateDiff.isChecked() - elem.keepSteps = self.chkKeepSteps.isChecked() + elem.subtractECVan = is_checked(self.chkSubtractECVan) + elem.replaceNaNs = is_checked(self.chkReplaceNaNs) + elem.createDiff = is_checked(self.chkCreateDiff) + elem.keepSteps = is_checked(self.chkKeepSteps) - elem.saveDir = line_text(self.saveDir) - elem.saveSofQW = self.chkSofQW.isChecked() - elem.saveSofTW = self.chkSofTW.isChecked() - elem.saveNXSPE = self.chkNxspe.isChecked() - elem.saveNexus = self.chkNexus.isChecked() - elem.saveAscii = self.chkAscii.isChecked() + elem.saveDir = line_text(self.saveDir) + elem.saveSofTWNxspe = is_checked(self.chkSofTWNxspe) + elem.saveSofTWNexus = is_checked(self.chkSofTWNexus) + elem.saveSofTWAscii = is_checked(self.chkSofTWAscii) + elem.saveSofQWNexus = is_checked(self.chkSofQWNexus) + elem.saveSofQWAscii = is_checked(self.chkSofQWAscii) elem.normalise = elem.NORM_MONITOR if self.rbtNormaliseMonitor.isChecked() else \ elem.NORM_TIME if self.rbtNormaliseTime.isChecked() else \ @@ -408,14 +409,12 @@ class TOFTOFSetupWidget(BaseWidget): self.runDataModel.reset() self.binEon.setChecked(elem.binEon) - self._onBinEon(elem.binEon) self.binEstart.setValue(elem.binEstart) self.binEstep.setValue(elem.binEstep) self.binEend.setValue(elem.binEend) self.binQon.setChecked(elem.binQon) - self._onBinQon(elem.binQon) self.binQstart.setValue(elem.binQstart) self.binQstep.setValue(elem.binQstep) @@ -429,11 +428,15 @@ class TOFTOFSetupWidget(BaseWidget): self.chkKeepSteps.setChecked(elem.keepSteps) self.saveDir.setText(elem.saveDir) - self.chkSofQW.setChecked(elem.saveSofQW) - self.chkSofTW.setChecked(elem.saveSofTW) - self.chkNxspe.setChecked(elem.saveNXSPE) - self.chkNexus.setChecked(elem.saveNexus) - self.chkAscii.setChecked(elem.saveAscii) + self.chkSofTWNxspe.setChecked(elem.saveSofTWNxspe) + self.chkSofTWNexus.setChecked(elem.saveSofTWNexus) + self.chkSofTWAscii.setChecked(elem.saveSofTWAscii) + self.chkSofQWNexus.setChecked(elem.saveSofQWNexus) + self.chkSofQWAscii.setChecked(elem.saveSofQWAscii) + self.gbSave.setChecked( + any((elem.saveSofTWNxspe, elem.saveSofTWNexus, + elem.saveSofTWAscii, elem.saveSofQWNexus, + elem.saveSofQWAscii))) if elem.normalise == elem.NORM_MONITOR: self.rbtNormaliseMonitor.setChecked(True)