Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace API {

void renameWorkspacesInQENSFit(Algorithm *qensFit, IAlgorithm_sptr renameAlgorithm,
const WorkspaceGroup_sptr &outputGroup, std::string const &outputBaseName,
std::string const &groupSuffix,
std::function<std::string(std::size_t)> const &getNameSuffix);

bool containsMultipleData(const std::vector<MatrixWorkspace_sptr> &workspaces);
Expand Down
12 changes: 3 additions & 9 deletions Framework/CurveFitting/src/Algorithms/QENSFitSequential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ void renameWorkspacesWith(const WorkspaceGroup_sptr &groupWorkspace, F const &ge
template <typename F>
void renameWorkspacesInQENSFit(Algorithm *qensFit, const Algorithm_sptr &renameAlgorithm,
WorkspaceGroup_sptr outputGroup, std::string const &outputBaseName,
std::string const &groupSuffix, const F &getNameSuffix) {
const F &getNameSuffix) {
Progress renamerProg(qensFit, 0.98, 1.0, outputGroup->size() + 1);
renamerProg.report("Renaming group workspaces...");

Expand All @@ -246,10 +246,6 @@ void renameWorkspacesInQENSFit(Algorithm *qensFit, const Algorithm_sptr &renameA
renamerProg.report("Renamed workspace in group.");
};
renameWorkspacesWith(outputGroup, getName, renamer);

auto const groupName = outputBaseName + groupSuffix;
if (outputGroup->getName() != groupName)
renameWorkspace(renameAlgorithm, outputGroup, groupName);
}

std::vector<std::size_t> createDatasetGrouping(const std::vector<MatrixWorkspace_sptr> &workspaces,
Expand Down Expand Up @@ -690,16 +686,14 @@ void QENSFitSequential::renameWorkspaces(WorkspaceGroup_sptr outputGroup, std::v
std::string workspaceName = inputWorkspaceNames[i] + "_" + spectra[i] + endOfSuffix;
return workspaceName;
};
return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, endOfSuffix + "s",
getNameSuffix);
return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, getNameSuffix);
}

void QENSFitSequential::renameWorkspaces(WorkspaceGroup_sptr outputGroup, std::vector<std::string> const &spectra,
std::string const &outputBaseName, std::string const &endOfSuffix) {
auto rename = createChildAlgorithm("RenameWorkspace", -1.0, -1.0, false);
auto getNameSuffix = [&](std::size_t i) { return spectra[i] + endOfSuffix; };
return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, endOfSuffix + "s",
getNameSuffix);
return renameWorkspacesInQENSFit(this, rename, std::move(outputGroup), outputBaseName, getNameSuffix);
}

void QENSFitSequential::renameGroupWorkspace(std::string const &currentName, std::vector<std::string> const &spectra,
Expand Down
4 changes: 2 additions & 2 deletions Framework/CurveFitting/src/Algorithms/QENSFitSimultaneous.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,15 +654,15 @@ void QENSFitSimultaneous::renameWorkspaces(const API::WorkspaceGroup_sptr &outpu
std::string workspaceName = inputWorkspaceNames[i] + "_" + spectra[i] + endOfSuffix;
return workspaceName;
};
return renameWorkspacesInQENSFit(this, rename, outputGroup, outputBaseName, endOfSuffix + "s", getNameSuffix);
return renameWorkspacesInQENSFit(this, rename, outputGroup, outputBaseName, getNameSuffix);
}

void QENSFitSimultaneous::renameWorkspaces(const API::WorkspaceGroup_sptr &outputGroup,
std::vector<std::string> const &spectra, std::string const &outputBaseName,
std::string const &endOfSuffix) {
auto rename = createChildAlgorithm("RenameWorkspace", -1.0, -1.0, false);
auto getNameSuffix = [&](std::size_t i) { return spectra[i] + endOfSuffix; };
return renameWorkspacesInQENSFit(this, rename, outputGroup, outputBaseName, endOfSuffix + "s", getNameSuffix);
return renameWorkspacesInQENSFit(this, rename, outputGroup, outputBaseName, getNameSuffix);
}

} // namespace Mantid::CurveFitting::Algorithms
2 changes: 1 addition & 1 deletion Framework/CurveFitting/src/Algorithms/QENSFitUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ bool containsMultipleData(const std::vector<MatrixWorkspace_sptr> &workspaces) {

void renameWorkspacesInQENSFit(Algorithm *qensFit, IAlgorithm_sptr renameAlgorithm,
const WorkspaceGroup_sptr &outputGroup, std::string const &outputBaseName,
std::string const &, std::function<std::string(std::size_t)> const &getNameSuffix) {
std::function<std::string(std::size_t)> const &getNameSuffix) {
Progress renamerProg(qensFit, 0.98, 1.0, outputGroup->size() + 1);
renamerProg.report("Renaming group workspaces...");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,46 @@
PropertyMode,
WorkspaceGroup,
)
from typing import List, Union
from mantid.kernel import Direction


def string_ends_with(string, delimiter):
delimiter_length = len(delimiter)
return string[-delimiter_length:] == delimiter if len(string) > delimiter_length else False
def string_ends_with(string: str, delimiters: List[str]) -> bool:
return any([string.endswith(delimiter) for delimiter in delimiters])


def exists_in_ads(workspace_name):
def exists_in_ads(workspace_name: str) -> bool:
return AnalysisDataService.doesExist(workspace_name)


def get_ads_workspace(workspace_name):
def get_ads_workspace(workspace_name: str) -> bool:
return AnalysisDataService.retrieve(workspace_name) if exists_in_ads(workspace_name) else None


def contains_workspace(group, workspace):
def contains_workspace(group: WorkspaceGroup, workspace) -> bool:
return group.contains(workspace) if isinstance(group, WorkspaceGroup) else False


def filter_by_contents(workspace_names, workspace):
def filter_by_contents(workspace_names: List[str], workspace: str) -> List[str]:
return [name for name in workspace_names if contains_workspace(get_ads_workspace(name), workspace)]


def filter_by_name_end(workspace_names, delimiter):
return [name for name in workspace_names if string_ends_with(name, delimiter)]
def filter_by_name_end(workspace_names: List[str], delimiters: List[str]) -> List[str]:
return [name for name in workspace_names if string_ends_with(name, delimiters)]


def find_result_group_containing(workspace_name, group_extension):
workspace_names = AnalysisDataService.Instance().getObjectNames()
result_groups = filter_by_name_end(workspace_names, group_extension)
def find_result_group_containing(workspace_name: str, group_extension: List[str]) -> Union[None, MatrixWorkspace]:
group_names = [ws for ws in AnalysisDataService.Instance().getObjectNames() if isinstance(get_ads_workspace(ws), WorkspaceGroup)]
result_groups = filter_by_name_end(group_names, group_extension)
groups = filter_by_contents(result_groups, workspace_name)
return groups[0] if groups else None


def is_equal(a, b, tolerance):
def is_equal(a: float, b: float, tolerance: float) -> bool:
return abs(a - b) <= tolerance * max(abs(a), abs(b))


def get_bin_index_of_value(workspace, value):
def get_bin_index_of_value(workspace: MatrixWorkspace, value: float) -> int:
x_axis = workspace.getAxis(0)
for i in range(0, x_axis.length()):
if is_equal(x_axis.getValue(i), value, 0.000001):
Expand All @@ -62,19 +62,21 @@ def get_bin_index_of_value(workspace, value):
raise ValueError("The corresponding bin in the input workspace could not be found.")


def get_x_insertion_index(input_workspace, single_fit_workspace):
def get_x_insertion_index(input_workspace: MatrixWorkspace, single_fit_workspace: MatrixWorkspace) -> int:
single_fit_x_axis = single_fit_workspace.getAxis(0)
bin_value = float(single_fit_x_axis.label(0))
return get_bin_index_of_value(input_workspace, bin_value)


def get_indices_of_equivalent_labels(input_workspace, destination_workspace):
def get_indices_of_equivalent_labels(input_workspace: MatrixWorkspace, destination_workspace: MatrixWorkspace) -> List[int]:
input_labels = input_workspace.getAxis(1).extractValues()
labels = destination_workspace.getAxis(1).extractValues()
return [index for index, label in enumerate(labels) if label in input_labels]


def fit_parameter_missing(single_fit_workspace, destination_workspace, exclude_parameters):
def fit_parameter_missing(
single_fit_workspace: MatrixWorkspace, destination_workspace: MatrixWorkspace, exclude_parameters: List[str]
) -> bool:
single_parameters = single_fit_workspace.getAxis(1).extractValues()
destination_parameters = destination_workspace.getAxis(1).extractValues()
return any([parameter not in destination_parameters and parameter not in exclude_parameters for parameter in single_parameters])
Expand All @@ -91,7 +93,8 @@ class IndirectReplaceFitResult(PythonAlgorithm):
_insertion_y_indices = None

_result_group = None
_allowed_extension = "_Result"
_allowed_ws_extension = "_Result"
_allowed_group_extensions = ["_Result", "_Results"]

def category(self):
return "Workflow\\DataHandling;Inelastic\\Indirect"
Expand All @@ -117,19 +120,18 @@ def PyInit(self):

def validateInputs(self):
issues = dict()

input_name = self.getPropertyValue("InputWorkspace")
single_fit_name = self.getPropertyValue("SingleFitWorkspace")
output_name = self.getPropertyValue("OutputWorkspace")

input_workspace = self.getProperty("InputWorkspace").value
single_fit_workspace = self.getProperty("SingleFitWorkspace").value

if not string_ends_with(input_name, self._allowed_extension):
issues["InputWorkspace"] = "The input workspace must have a name ending in {0}".format(self._allowed_extension)
if not string_ends_with(input_name, [self._allowed_ws_extension]):
issues["InputWorkspace"] = "The input workspace must have a name ending in {0}".format(self._allowed_ws_extension)

if not string_ends_with(single_fit_name, self._allowed_extension):
issues["SingleFitWorkspace"] = "This workspace must have a name ending in {0}".format(self._allowed_extension)
if not string_ends_with(single_fit_name, [self._allowed_ws_extension]):
issues["SingleFitWorkspace"] = "This workspace must have a name ending in {0}".format(self._allowed_ws_extension)

if not output_name:
issues["OutputWorkspace"] = "No OutputWorkspace name was provided."
Expand Down Expand Up @@ -177,7 +179,7 @@ def _setup(self):
self._row_indices = get_indices_of_equivalent_labels(input_workspace, single_fit_workspace)
self._insertion_y_indices = get_indices_of_equivalent_labels(single_fit_workspace, input_workspace)

self._result_group = find_result_group_containing(self._input_workspace, self._allowed_extension + "s")
self._result_group = find_result_group_containing(self._input_workspace, self._allowed_group_extensions)

def PyExec(self):
self._setup()
Expand All @@ -192,7 +194,7 @@ def _copy_data(self):
for from_index, to_index in zip(self._row_indices[1:], self._insertion_y_indices[1:]):
self._copy_value(from_index, to_index, self._output_workspace)

def _copy_value(self, row_index, insertion_index, destination_workspace):
def _copy_value(self, row_index: int, insertion_index: int, destination_workspace: MatrixWorkspace):
copy_algorithm = self.createChildAlgorithm(name="CopyDataRange", startProgress=0.1, endProgress=1.0, enableLogging=True)
copy_algorithm.setAlwaysStoreInADS(True)

Expand Down
2 changes: 2 additions & 0 deletions docs/source/release/v6.13.0/Inelastic/Bugfixes/38827.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- :ref:`QENSFitting <interface-inelastic-qens-fitting>` interface will generate a group workspace after fitting with suffix `_Result` when the output fit is a single fit, and suffix `_Results` when is a multiple fit.
- Clicking plot button after a fit from :ref:`QENSFitting <interface-inelastic-qens-fitting>` no longer plot results twice.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ namespace MantidQt::CustomInterfaces::Inelastic {
EditResultsDialog::EditResultsDialog(QWidget *parent) : QDialog(parent) {
m_uiForm.setupUi(this);
m_uiForm.wsInputWorkspace->setLowerBinLimit(2);
m_uiForm.wsInputWorkspace->showWorkspaceGroups(false);

m_uiForm.wsSingleFitWorkspace->setUpperBinLimit(1);
m_uiForm.wsSingleFitWorkspace->showWorkspaceGroups(false);

connect(m_uiForm.pbPasteInputName, &QPushButton::clicked, this, &EditResultsDialog::setOutputWorkspaceName);
connect(m_uiForm.pbReplaceFitResult, &QPushButton::clicked, this, &EditResultsDialog::replaceSingleFitResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ template <typename Predicate> void removeVectorElements(std::vector<std::string>
strings.erase(std::remove_if(strings.begin(), strings.end(), filter), strings.end());
}

bool doesStringEndWith(std::string const &str, std::string const &delimiter) {
if (str.size() > delimiter.size())
return str.substr(str.size() - delimiter.size(), str.size()) == delimiter;
return false;
bool doesStringEndWith(std::string const &str, std::vector<std::string> const &delimiters) {
return std::any_of(delimiters.cbegin(), delimiters.cend(),
[&str](std::string const &delimiter) { return str.ends_with(delimiter); });
}

std::vector<std::string> filterByEndSuffix(std::vector<std::string> &strings, std::string const &delimiter) {
removeVectorElements(strings, [&delimiter](std::string const &str) { return !doesStringEndWith(str, delimiter); });
std::vector<std::string> filterByEndSuffix(std::vector<std::string> &strings,
std::vector<std::string> const &delimiters) {
removeVectorElements(strings, [&delimiters](std::string const &str) { return !doesStringEndWith(str, delimiters); });
return strings;
}

Expand All @@ -160,7 +160,7 @@ std::string filterByContents(std::vector<std::string> &strings, MatrixWorkspace_

std::string findGroupWorkspaceContaining(MatrixWorkspace_sptr workspace) {
auto workspaceNames = AnalysisDataService::Instance().getObjectNames();
auto resultGroups = filterByEndSuffix(workspaceNames, "_Results");
auto resultGroups = filterByEndSuffix(workspaceNames, std::vector<std::string>({"_Result", "_Results"}));
return !resultGroups.empty() ? filterByContents(resultGroups, std::move(workspace)) : "";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ FitOutputOptionsView::FitOutputOptionsView(QWidget *parent)
connect(m_outputOptions->cbGroupWorkspace, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[=](int index) { this->notifyGroupWorkspaceChanged(m_outputOptions->cbGroupWorkspace->itemText(index)); });
connect(m_outputOptions->pbPlot, &QPushButton::clicked, this, &FitOutputOptionsView::notifyPlotClicked);
connect(m_outputOptions->pbPlot, &QPushButton::clicked, this, &FitOutputOptionsView::notifyPlotClicked);
connect(m_outputOptions->pbSave, &QPushButton::clicked, this, &FitOutputOptionsView::notifySaveClicked);
connect(m_outputOptions->pbEditResult, &QPushButton::clicked, this, &FitOutputOptionsView::handleEditResultClicked);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ std::string FittingModel::createOutputName(const std::string &fitMode, const std
const std::string &spectra) const {
std::string inputWorkspace = isMultiFit() ? "Multi" : workspaceName;
std::string inputSpectra = isMultiFit() ? "" : spectra;
return inputWorkspace + "_" + m_fitType + "_" + fitMode + "_" + m_fitString + "_" + inputSpectra + "_Results";
return inputWorkspace + "_" + m_fitType + "_" + fitMode + "_" + m_fitString + "_" + inputSpectra + getResultsSuffix();
}

std::optional<std::string> FittingModel::sequentialFitOutputName() const {
Expand Down Expand Up @@ -608,16 +608,16 @@ IAlgorithm_sptr FittingModel::createSimultaneousFit(const MultiDomainFunction_sp
fitAlgorithm->setProperty("OutputWorkspace", *outputName);
return fitAlgorithm;
}

std::string FittingModel::getResultsSuffix() const { return isMultiFit() ? "_Results" : "_Result"; }
std::string FittingModel::singleFitOutputName(std::string workspaceName, WorkspaceIndex spectrum) const {
std::string inputWorkspace = isMultiFit() ? "Multi" : workspaceName;
std::string spectra = std::to_string(spectrum.value);
return inputWorkspace + "_" + m_fitType + "_" + m_fitString + "_" + spectra + "_Results";
return inputWorkspace + "_" + m_fitType + "_" + m_fitString + "_" + spectra + getResultsSuffix();
}

std::optional<std::string> FittingModel::getOutputBasename() const {
if (auto const outputName = sequentialFitOutputName())
return cutLastOf(*outputName, "_Results");
return cutLastOf(*outputName, getResultsSuffix());
return std::nullopt;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class MANTIDQT_INELASTIC_DLL FittingModel : public IFittingModel {

private:
void removeWorkspaceFromFittingData(WorkspaceID const &workspaceIndex);
std::string getResultsSuffix() const;

Mantid::API::IAlgorithm_sptr createSequentialFit(Mantid::API::IFunction_sptr function) const;
Mantid::API::IAlgorithm_sptr createSequentialFit(const Mantid::API::IFunction_sptr function,
Expand Down
Loading