diff --git a/Framework/API/src/Algorithm.cpp b/Framework/API/src/Algorithm.cpp index 795addd969ac721041278f3aabd435256340af8d..22239ea2e19b5fbc61d4647d2ff60a2e76503683 100644 --- a/Framework/API/src/Algorithm.cpp +++ b/Framework/API/src/Algorithm.cpp @@ -1711,7 +1711,7 @@ void Algorithm::execMasterOnly() { * non-master ranks in master-only execution. */ void Algorithm::execNonMaster() { // If there is no output we can simply do nothing. - if (m_pureOutputWorkspaceProps.size() == 0) + if (m_pureOutputWorkspaceProps.empty()) return; // Does Algorithm have exactly one input and one output workspace property? if (m_inputWorkspaceProps.size() == 1 && diff --git a/Framework/API/src/DetectorSearcher.cpp b/Framework/API/src/DetectorSearcher.cpp index 76d8f93ebde94c6401f725623b7312ce259264d0..6170612c8930c7bb2f62217ece071b2444bc7cfe 100644 --- a/Framework/API/src/DetectorSearcher.cpp +++ b/Framework/API/src/DetectorSearcher.cpp @@ -148,7 +148,7 @@ DetectorSearcher::searchUsingNearestNeighbours(const V3D &q) { // find where this Q vector should intersect with "extended" space const auto neighbours = m_detectorCacheSearch->findNearest(Eigen::Vector3d(q[0], q[1], q[2]), 5); - if (neighbours.size() == 0) + if (neighbours.empty()) return std::make_tuple(false, 0); const auto result = checkInteceptWithNeighbours(detectorDir, neighbours); diff --git a/Framework/API/src/IndexTypeProperty.cpp b/Framework/API/src/IndexTypeProperty.cpp index df454100350d4ab71ce1c45378f118277c757c7d..7a45c4741b78f912e8a8650e3c810070a876abcb 100644 --- a/Framework/API/src/IndexTypeProperty.cpp +++ b/Framework/API/src/IndexTypeProperty.cpp @@ -10,7 +10,7 @@ IndexTypeProperty::IndexTypeProperty(const std::string &name, if (indexType & IndexType::SpectrumNum) m_allowedValues.push_back("SpectrumNumber"); - if (m_allowedValues.size() == 0) + if (m_allowedValues.empty()) throw std::invalid_argument("Argument indexType incorrectly specified"); m_value = m_allowedValues[0]; diff --git a/Framework/API/src/MatrixWorkspace.cpp b/Framework/API/src/MatrixWorkspace.cpp index 2a1794eb532b86a58fcf5e927b5977f18d57a124..c07904a0494dddf5f2d9e7a94e421caa57f69130 100644 --- a/Framework/API/src/MatrixWorkspace.cpp +++ b/Framework/API/src/MatrixWorkspace.cpp @@ -239,7 +239,7 @@ void MatrixWorkspace::initialize(const std::size_t &NVectors, void MatrixWorkspace::initialize(const std::size_t &NVectors, const HistogramData::Histogram &histogram) { // Check validity of arguments - if (NVectors == 0 || histogram.x().size() == 0) { + if (NVectors == 0 || histogram.x().empty()) { throw std::out_of_range( "All arguments to init must be positive and non-zero"); } diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h index 7c9aa809d1604520a24a14c59e89ae1c4966700e..49a8f680da0f60ef7bbbee69bdc303e11b73c018 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h @@ -8,6 +8,9 @@ namespace Mantid { namespace API { class SpectrumInfo; } +namespace Geometry { +class ReferenceFrame; +} namespace HistogramData { class HistogramX; class HistogramY; @@ -88,6 +91,8 @@ private: // convert to momentum transfer Mantid::API::MatrixWorkspace_sptr convertToQ(Mantid::API::MatrixWorkspace_sptr inputWS); + // Get the twoTheta width of a given detector + double getDetectorTwoThetaRange(const size_t spectrumIdx); // Utility function to create name for diagnostic workspaces std::string createDebugWorkspaceName(const std::string &inputName); // Utility function to output a diagnostic workspace to the ADS @@ -152,6 +157,7 @@ private: API::MatrixWorkspace_sptr m_runWS; const API::SpectrumInfo *m_spectrumInfo; + boost::shared_ptr<const Mantid::Geometry::ReferenceFrame> m_refFrame; bool m_convertUnits; // convert the input workspace to lambda bool m_normaliseMonitors; // normalise by monitors and direct beam bool m_normaliseTransmission; // transmission or algorithmic correction diff --git a/Framework/Algorithms/src/AddSampleLog.cpp b/Framework/Algorithms/src/AddSampleLog.cpp index 5b7be49cd1ec18313fc9cb234d05186019b4b4dd..7abbf956b7f33aed2183fa248bec3a15b7963bee 100644 --- a/Framework/Algorithms/src/AddSampleLog.cpp +++ b/Framework/Algorithms/src/AddSampleLog.cpp @@ -228,7 +228,7 @@ void AddSampleLog::addTimeSeriesProperty(Run &run_obj, is_int_series = true; } else if (prop_number_type == autoTypeOption) { // auto type. by default - if (prop_value.size() == 0) + if (prop_value.empty()) g_log.warning("For sample log in TimeSeriesProperty and values are given " "by MarixWorkspace, the default data type " "is double."); @@ -248,8 +248,8 @@ void AddSampleLog::addTimeSeriesProperty(Run &run_obj, // check using workspace or some specified start value std::string tsp_ws_name = getPropertyValue("TimeSeriesWorkspace"); - bool use_ws = tsp_ws_name.size() > 0; - bool use_single_value = prop_value.size() > 0; + bool use_ws = !tsp_ws_name.empty(); + bool use_single_value = !prop_value.empty(); if (use_ws && use_single_value) { throw std::runtime_error("Both TimeSeries workspace and sing value are " "specified. It is not allowed."); diff --git a/Framework/Algorithms/src/ChangeTimeZero.cpp b/Framework/Algorithms/src/ChangeTimeZero.cpp index 631e7068f154165958d57d7d2dd56897c1dabdad..5494590af12673237310f09444f63aac815b0dfc 100644 --- a/Framework/Algorithms/src/ChangeTimeZero.cpp +++ b/Framework/Algorithms/src/ChangeTimeZero.cpp @@ -331,7 +331,7 @@ bool ChangeTimeZero::checkForDateTime(const std::string &val) const { // Hedge for bad lexical casts in the DateTimeValidator try { DateTimeValidator validator = DateTimeValidator(); - isDateTime = validator.isValid(val) == ""; + isDateTime = validator.isValid(val).empty(); } catch (...) { isDateTime = false; } diff --git a/Framework/Algorithms/src/ConvertAxisByFormula.cpp b/Framework/Algorithms/src/ConvertAxisByFormula.cpp index ada62fb7d4e67eb951a6db5656442b4f7a2f0481..de1ab2350a84783216df15414e77d9a00103c55e 100644 --- a/Framework/Algorithms/src/ConvertAxisByFormula.cpp +++ b/Framework/Algorithms/src/ConvertAxisByFormula.cpp @@ -105,7 +105,7 @@ void ConvertAxisByFormula::exec() { RefAxis *refAxisPtr = dynamic_cast<RefAxis *>(axisPtr); if (refAxisPtr != nullptr) { CommonBinsValidator sameBins; - if (sameBins.isValid(outputWs) != "") { + if (!sameBins.isValid(outputWs).empty()) { isRaggedBins = true; } isRefAxis = true; @@ -245,14 +245,14 @@ void ConvertAxisByFormula::exec() { } // Set the Unit of the Axis - if ((axisUnits != "") || (axisTitle != "")) { + if ((!axisUnits.empty()) || (!axisTitle.empty())) { try { axisPtr->unit() = UnitFactory::Instance().create(axisUnits); } catch (Exception::NotFoundError &) { - if (axisTitle == "") { + if (axisTitle.empty()) { axisTitle = axisPtr->unit()->caption(); } - if (axisUnits == "") { + if (axisUnits.empty()) { axisUnits = axisPtr->unit()->label(); } axisPtr->unit() = boost::make_shared<Units::Label>(axisTitle, axisUnits); diff --git a/Framework/Algorithms/src/ConvertUnits.cpp b/Framework/Algorithms/src/ConvertUnits.cpp index 33fa5a87287359031c52e4df80af0856e4246cf9..7f58d71c62d25f033a5ca0ac5004ac5dbd73a63a 100644 --- a/Framework/Algorithms/src/ConvertUnits.cpp +++ b/Framework/Algorithms/src/ConvertUnits.cpp @@ -337,7 +337,7 @@ ConvertUnits::convertQuickly(API::MatrixWorkspace_const_sptr inputWS, // First a quick check using the validator CommonBinsValidator sameBins; bool commonBoundaries = false; - if (sameBins.isValid(inputWS) == "") { + if (sameBins.isValid(inputWS).empty()) { commonBoundaries = WorkspaceHelpers::commonBoundaries(*inputWS); // Only do the full check if the quick one passes if (commonBoundaries) { diff --git a/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp b/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp index 5136276a2e8c353b52b37d9a0c0f0579530102c0..24381be1b96d7f0ff0d4f7065ef00ae70228f5ad 100644 --- a/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp +++ b/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp @@ -299,7 +299,7 @@ void DiffractionEventCalibrateDetectors::exec() { std::vector<boost::shared_ptr<RectangularDetector>> detList; // --------- Loading only one bank ---------------------------------- std::string onebank = getProperty("BankName"); - bool doOneBank = (onebank != ""); + bool doOneBank = (!onebank.empty()); for (int i = 0; i < inst->nelements(); i++) { boost::shared_ptr<RectangularDetector> det; boost::shared_ptr<ICompAssembly> assem; diff --git a/Framework/Algorithms/src/DiffractionFocussing2.cpp b/Framework/Algorithms/src/DiffractionFocussing2.cpp index 5465caa11d939c648c23b353671c930ae19ecbca..875954fbee9fa68cd2a12920b9a98e9431644b36 100644 --- a/Framework/Algorithms/src/DiffractionFocussing2.cpp +++ b/Framework/Algorithms/src/DiffractionFocussing2.cpp @@ -109,7 +109,7 @@ void DiffractionFocussing2::exec() { throw std::invalid_argument("Workspace Invalid Spacing/UnitID"); } // --- Do we need to read the grouping workspace? ---- - if (groupingFileName != "") { + if (!groupingFileName.empty()) { progress(0.01, "Reading grouping file"); IAlgorithm_sptr childAlg = createChildAlgorithm("CreateGroupingWorkspace"); childAlg->setProperty( diff --git a/Framework/Algorithms/src/ExportTimeSeriesLog.cpp b/Framework/Algorithms/src/ExportTimeSeriesLog.cpp index bdce22f34a065590d40664d9e3b8f1a82431eeda..35c15bc9fa4cbb290bda06618c27f87ce484d0df 100644 --- a/Framework/Algorithms/src/ExportTimeSeriesLog.cpp +++ b/Framework/Algorithms/src/ExportTimeSeriesLog.cpp @@ -429,7 +429,7 @@ void ExportTimeSeriesLog::calculateFirstDerivative(bool is_event_ws) { // error message std::string errmsg = errmsg_ss.str(); - if (errmsg.size() > 0) + if (!errmsg.empty()) g_log.error(errmsg); return; diff --git a/Framework/Algorithms/src/FilterByTime.cpp b/Framework/Algorithms/src/FilterByTime.cpp index dd08a9f46bd68884002419ff6e3d53e8ce330d44..fe151e505ff1fcfcacbe1372c99766a0c8938212 100644 --- a/Framework/Algorithms/src/FilterByTime.cpp +++ b/Framework/Algorithms/src/FilterByTime.cpp @@ -77,12 +77,12 @@ void FilterByTime::exec() { start_str = getPropertyValue("AbsoluteStartTime"); stop_str = getPropertyValue("AbsoluteStopTime"); - if ((start_str != "") && (stop_str != "") && (start_dbl <= 0.0) && + if ((!start_str.empty()) && (!stop_str.empty()) && (start_dbl <= 0.0) && (stop_dbl <= 0.0)) { // Use the absolute string start = DateAndTime(start_str); stop = DateAndTime(stop_str); - } else if ((start_str == "") && (stop_str == "") && + } else if ((start_str.empty()) && (stop_str.empty()) && ((start_dbl > 0.0) || (stop_dbl > 0.0))) { // Use the relative times in seconds. DateAndTime first = inputWS->getFirstPulseTime(); diff --git a/Framework/Algorithms/src/FilterByTime2.cpp b/Framework/Algorithms/src/FilterByTime2.cpp index 74ab57080842fac8b8418fb0c8327b9b52d0218f..71d70f362807d68d22e2b6c138781d9a8a9e9824 100644 --- a/Framework/Algorithms/src/FilterByTime2.cpp +++ b/Framework/Algorithms/src/FilterByTime2.cpp @@ -73,12 +73,12 @@ void FilterByTime2::exec() { std::string absstoptime = this->getProperty("AbsoluteStopTime"); std::string start, stop; - if ((absstarttime != "") && (absstoptime != "") && (starttime <= 0.0) && + if ((!absstarttime.empty()) && (!absstoptime.empty()) && (starttime <= 0.0) && (stoptime <= 0.0)) { // Use the absolute string start = absstarttime; stop = absstoptime; - } else if ((absstarttime != "" || absstoptime != "") && + } else if ((!absstarttime.empty() || !absstoptime.empty()) && (starttime > 0.0 || stoptime > 0.0)) { throw std::invalid_argument( "It is not allowed to provide both absolute time and relative time."); diff --git a/Framework/Algorithms/src/FilterEvents.cpp b/Framework/Algorithms/src/FilterEvents.cpp index 9f6b05f04ff7d53d837271dba8553b3b3afe4b43..c4a4cf3116eb8a013bd7e65b0c7f5051326923dc 100644 --- a/Framework/Algorithms/src/FilterEvents.cpp +++ b/Framework/Algorithms/src/FilterEvents.cpp @@ -792,7 +792,7 @@ void FilterEvents::convertSplittersWorkspaceToVectors() { Kernel::SplittingInterval splitter = m_splitters[i_splitter]; int64_t start_time_i64 = splitter.start().totalNanoseconds(); int64_t stop_time_i64 = splitter.stop().totalNanoseconds(); - if (m_vecSplitterTime.size() == 0) { + if (m_vecSplitterTime.empty()) { // first entry: add m_vecSplitterTime.push_back(start_time_i64); m_vecSplitterTime.push_back(stop_time_i64); @@ -949,7 +949,7 @@ void FilterEvents::processTableSplittersWorkspace() { int64_t stop_64 = filter_shift_time + static_cast<int64_t>(stop_time * 1.E9); - if (m_vecSplitterTime.size() == 0) { + if (m_vecSplitterTime.empty()) { // first splitter: push the start time to vector m_vecSplitterTime.push_back(start_64); } else if (start_64 - m_vecSplitterTime.back() > TOLERANCE) { @@ -973,7 +973,7 @@ void FilterEvents::processTableSplittersWorkspace() { // convert string-target to integer target bool addnew = false; int int_target(-1); - if (m_targetIndexMap.size() == 0) { + if (m_targetIndexMap.empty()) { addnew = true; } else { std::map<std::string, int>::iterator mapiter = diff --git a/Framework/Algorithms/src/GenerateIPythonNotebook.cpp b/Framework/Algorithms/src/GenerateIPythonNotebook.cpp index 529b33549073a74d25262e8d5c7f7ee6288da4d6..e5e90cd9a25919dd1ca18464b53e17adb9231662 100644 --- a/Framework/Algorithms/src/GenerateIPythonNotebook.cpp +++ b/Framework/Algorithms/src/GenerateIPythonNotebook.cpp @@ -80,8 +80,8 @@ void GenerateIPythonNotebook::exec() { } // Need at least a start time to do time filter - if (startTime != "") { - if (endTime == "") { + if (!startTime.empty()) { + if (endTime.empty()) { // If no end time was given then filter up to now view->filterBetweenExecDate(DateAndTime(startTime)); } else { diff --git a/Framework/Algorithms/src/GeneratePythonScript.cpp b/Framework/Algorithms/src/GeneratePythonScript.cpp index 5ee5894becf7f62babb485492b17bdbe834ab4b9..01ee8704fcf951b7ea6119890d47ff0c0de46658 100644 --- a/Framework/Algorithms/src/GeneratePythonScript.cpp +++ b/Framework/Algorithms/src/GeneratePythonScript.cpp @@ -79,8 +79,8 @@ void GeneratePythonScript::exec() { } // Need at least a start time to do time filter - if (startTime != "") { - if (endTime == "") { + if (!startTime.empty()) { + if (endTime.empty()) { // If no end time was given then filter up to now view->filterBetweenExecDate(DateAndTime(startTime)); } else { diff --git a/Framework/Algorithms/src/Q1DWeighted.cpp b/Framework/Algorithms/src/Q1DWeighted.cpp index 36fc5177d2c2f4530407f4927210575af9e9b409..d12104bab2f4c436808e876943745427a871f2ea 100644 --- a/Framework/Algorithms/src/Q1DWeighted.cpp +++ b/Framework/Algorithms/src/Q1DWeighted.cpp @@ -213,7 +213,7 @@ void Q1DWeighted::exec() { // For reference - in the case where we don't use sub-pixels, simply // use: // double sinTheta = sin( spectrumInfo.twoTheta(i)/2.0 ); - V3D pos = spectrumInfo.position(i) - V3D(sub_x, sub_y, 0.0); + V3D pos = spectrumInfo.position(i) - V3D(sub_x, sub_y, 0.0) - samplePos; double sinTheta = sin(0.5 * pos.angle(beamLine)); double factor = fmp * sinTheta; double q = factor * 2.0 / (XIn[j] + XIn[j + 1]); diff --git a/Framework/Algorithms/src/ReflectometryReductionOne2.cpp b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp index 181ab0a98afe857255351f6e327cb825fae53810..e6c3288f561814ec1a9a1eb974fd7108c13b003e 100644 --- a/Framework/Algorithms/src/ReflectometryReductionOne2.cpp +++ b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp @@ -4,18 +4,22 @@ #include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/WorkspaceFactory.h" +#include "MantidGeometry/Objects/BoundingBox.h" #include "MantidHistogramData/LinearGenerator.h" #include "MantidIndexing/IndexInfo.h" #include "MantidKernel/MandatoryValidator.h" #include "MantidKernel/StringTokenizer.h" #include "MantidKernel/Unit.h" #include "MantidGeometry/IDetector.h" +#include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/ReferenceFrame.h" #include <algorithm> #include <boost/lexical_cast.hpp> using namespace Mantid::Kernel; using namespace Mantid::API; +using namespace Mantid::Geometry; using namespace Mantid::HistogramData; using namespace Mantid::Indexing; @@ -37,27 +41,6 @@ double getDetectorTwoTheta(const SpectrumInfo *spectrumInfo, return spectrumInfo->signedTwoTheta(spectrumIdx); } -/** Get the twoTheta angle range for the top/bottom of the detector associated -* with the given spectrum -* -* @param spectrumInfo : the spectrum info -* @param spectrumIdx : the workspace index of the spectrum -* @return : the twoTheta angle in radians -*/ -double getDetectorTwoThetaRange(const SpectrumInfo *spectrumInfo, - const size_t spectrumIdx) { - // Assume the range covered by this pixel is the diff between this - // pixel's twoTheta and the next/prev pixel) - double twoTheta = getDetectorTwoTheta(spectrumInfo, spectrumIdx); - double bTwoTheta = 0; - - if (spectrumIdx + 1 < spectrumInfo->size()) { - bTwoTheta = getDetectorTwoTheta(spectrumInfo, spectrumIdx + 1) - twoTheta; - } - - return bTwoTheta; -} - /** Get the start/end of the lambda range for the detector associated * with the given spectrum * @@ -328,6 +311,34 @@ std::string createProcessingCommandsFromDetectorWS( return result; } + +/** +* Get the topbottom extent of a detector for the given axis +* +* @param axis [in] : the axis to get the extent for +* @param top [in] : if true, get the max extent, or min otherwise +* @return : the max/min extent on the given axis +*/ +double getBoundingBoxExtent(const BoundingBox &boundingBox, + const PointingAlong axis, const bool top) { + + double result = 0.0; + switch (axis) { + case X: + result = top ? boundingBox.xMax() : boundingBox.xMin(); + break; + case Y: + result = top ? boundingBox.yMax() : boundingBox.yMin(); + break; + case Z: + result = top ? boundingBox.zMax() : boundingBox.zMin(); + break; + default: + throw std::runtime_error("Axis is not X/Y/Z"); + break; + } + return result; +} } // Register the algorithm into the AlgorithmFactory @@ -434,7 +445,10 @@ void ReflectometryReductionOne2::exec() { throw std::invalid_argument( "InputWorkspace must have units of TOF or Wavelength"); + // Cache the spectrum info and reference frame m_spectrumInfo = &m_runWS->spectrumInfo(); + auto instrument = m_runWS->getInstrument(); + m_refFrame = instrument->getReferenceFrame(); // Find and cache detector groups and theta0 findDetectorGroups(); @@ -463,6 +477,44 @@ void ReflectometryReductionOne2::exec() { setProperty("OutputWorkspace", IvsQ); } +/** Get the twoTheta angle range for the top/bottom of the detector associated +* with the given spectrum +* +* @param spectrumIdx : the workspace index of the spectrum +* @return : the twoTheta range in radians +*/ +double +ReflectometryReductionOne2::getDetectorTwoThetaRange(const size_t spectrumIdx) { + + double bTwoTheta = 0; + + // Get the sample->detector distance along the beam + const V3D detSample = + m_spectrumInfo->position(spectrumIdx) - m_spectrumInfo->samplePosition(); + const double beamOffset = + m_refFrame->vecPointingAlongBeam().scalar_prod(detSample); + // Get the bounding box for this detector/group + BoundingBox boundingBox; + auto detector = m_runWS->getDetector(spectrumIdx); + detector->getBoundingBox(boundingBox); + // Get the top and bottom on the axis pointing up + const double top = + getBoundingBoxExtent(boundingBox, m_refFrame->pointingUp(), true); + const double bottom = + getBoundingBoxExtent(boundingBox, m_refFrame->pointingUp(), false); + // Calculate the difference in twoTheta between the top and bottom + const double twoThetaTop = std::atan(top / beamOffset); + const double twoThetaBottom = std::atan(bottom / beamOffset); + bTwoTheta = twoThetaTop - twoThetaBottom; + + // We must have non-zero width to project a range + if (bTwoTheta < Tolerance) { + throw std::runtime_error("Error calculating pixel size."); + } + + return bTwoTheta; +} + /** * Utility function to create a unique workspace name for diagnostic outputs * based on a given input workspace name @@ -856,9 +908,19 @@ void ReflectometryReductionOne2::findDetectorGroups() { return a.front() < b.front(); }); - if (m_detectorGroups.size() == 0) { + if (m_detectorGroups.empty()) { throw std::runtime_error("Invalid processing instructions"); } + + for (const auto &group : m_detectorGroups) { + for (const auto &spIdx : group) { + if (spIdx > m_spectrumInfo->size() - 1) { + throw std::runtime_error( + "ProcessingInstructions contains an out-of-range index: " + + std::to_string(spIdx)); + } + } + } } /** @@ -993,8 +1055,7 @@ void ReflectometryReductionOne2::findIvsLamRange( const size_t spIdxMin = detectors.front(); const double twoThetaMin = getDetectorTwoTheta(m_spectrumInfo, spIdxMin); - const double bTwoThetaMin = - getDetectorTwoThetaRange(m_spectrumInfo, spIdxMin); + const double bTwoThetaMin = getDetectorTwoThetaRange(spIdxMin); // For bLambda, use the average bin size for this spectrum auto xValues = detectorWS->x(spIdxMin); double bLambda = (xValues[xValues.size() - 1] - xValues[0]) / @@ -1004,8 +1065,7 @@ void ReflectometryReductionOne2::findIvsLamRange( const size_t spIdxMax = detectors.back(); const double twoThetaMax = getDetectorTwoTheta(m_spectrumInfo, spIdxMax); - const double bTwoThetaMax = - getDetectorTwoThetaRange(m_spectrumInfo, spIdxMax); + const double bTwoThetaMax = getDetectorTwoThetaRange(spIdxMax); xValues = detectorWS->x(spIdxMax); bLambda = (xValues[xValues.size() - 1] - xValues[0]) / static_cast<int>(xValues.size()); @@ -1092,7 +1152,7 @@ ReflectometryReductionOne2::sumInQ(MatrixWorkspace_sptr detectorWS) { for (auto spIdx : detectors) { // Get the angle of this detector and its size in twoTheta const double twoTheta = getDetectorTwoTheta(m_spectrumInfo, spIdx); - const double bTwoTheta = getDetectorTwoThetaRange(m_spectrumInfo, spIdx); + const double bTwoTheta = getDetectorTwoThetaRange(spIdx); // Check X length is Y length + 1 const auto &inputX = detectorWS->x(spIdx); @@ -1228,11 +1288,19 @@ void ReflectometryReductionOne2::sumInQShareCounts( } // Add a share of the input counts to this bin based on the proportion of // overlap. - const double overlapWidth = - std::min({bLambda, lambdaMax - binStart, binEnd - lambdaMin}); - const double fraction = overlapWidth / totalWidth; - outputY[outIdx] += inputCounts * fraction; - outputE[outIdx] += inputErr * fraction; + if (totalWidth > Tolerance) { + // Share counts out proportionally based on the overlap of this range + const double overlapWidth = + std::min({bLambda, lambdaMax - binStart, binEnd - lambdaMin}); + const double fraction = overlapWidth / totalWidth; + outputY[outIdx] += inputCounts * fraction; + outputE[outIdx] += inputErr * fraction; + } else { + // Projection to a single value. Put all counts in the overlapping output + // bin. + outputY[outIdx] += inputCounts; + outputE[outIdx] += inputCounts; + } } } diff --git a/Framework/Algorithms/src/RenameWorkspaces.cpp b/Framework/Algorithms/src/RenameWorkspaces.cpp index 9a6855d499bc8585e95af1a14b04ae49ecc1ba51..7af32cd87e4807dc7ad30c1331f03c76c3a6214c 100644 --- a/Framework/Algorithms/src/RenameWorkspaces.cpp +++ b/Framework/Algorithms/src/RenameWorkspaces.cpp @@ -61,15 +61,15 @@ std::map<std::string, std::string> RenameWorkspaces::validateInputs() { std::string suffix = getPropertyValue("Suffix"); // Check properties - if (newWsName.empty() && prefix == "" && suffix == "") { + if (newWsName.empty() && prefix.empty() && suffix.empty()) { errorList["WorkspaceNames"] = "No list of Workspace names, prefix or suffix has been supplied."; } - if (!newWsName.empty() && (prefix != "" || suffix != "")) { + if (!newWsName.empty() && (!prefix.empty() || !suffix.empty())) { errorList["WorkspaceNames"] = "Both a list of workspace names and a prefix " "or suffix has been supplied."; - if (prefix != "") { + if (!prefix.empty()) { errorList["Prefix"] = "Both a list of workspace names and a prefix " "or suffix has been supplied."; } else { diff --git a/Framework/Algorithms/src/ResampleX.cpp b/Framework/Algorithms/src/ResampleX.cpp index 42d065d13e0cdf07e53ddc75b9197adf743d4260..82c462f4fcd50725b9f2c74e4873f577b573a110 100644 --- a/Framework/Algorithms/src/ResampleX.cpp +++ b/Framework/Algorithms/src/ResampleX.cpp @@ -114,8 +114,21 @@ map<string, string> ResampleX::validateInputs() { */ string determineXMinMax(MatrixWorkspace_sptr inputWS, vector<double> &xmins, vector<double> &xmaxs) { - bool updateXMins = xmins.empty(); // they weren't set - bool updateXMaxs = xmaxs.empty(); // they weren't set + const size_t numSpectra = inputWS->getNumberHistograms(); + + // pad out the ranges by copying the first value to the rest that are needed + if (xmins.size() == 1 && numSpectra > xmins.size()) { + const double value = xmins.front(); + xmins.insert(xmins.end(), numSpectra - xmins.size(), value); + } + if (xmaxs.size() == 1 && numSpectra > xmaxs.size()) { + const double value = xmaxs.front(); + xmaxs.insert(xmaxs.end(), numSpectra - xmaxs.size(), value); + } + + // should the individiual values be calculated? + const bool updateXMins = xmins.empty(); // they weren't set + const bool updateXMaxs = xmaxs.empty(); // they weren't set stringstream msg; @@ -129,7 +142,6 @@ string determineXMinMax(MatrixWorkspace_sptr inputWS, vector<double> &xmins, xmax_wksp = inputEventWS->getTofMax(); } - size_t numSpectra = inputWS->getNumberHistograms(); for (size_t i = 0; i < numSpectra; ++i) { // determine ranges if necessary if (updateXMins || updateXMaxs) { @@ -283,7 +295,7 @@ void ResampleX::exec() { bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); - int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); + const int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); @@ -335,8 +347,8 @@ void ResampleX::exec() { if (common_limits) { // get the delta from the first since they are all the same BinEdges xValues(0); - double delta = this->determineBinning(xValues.mutableRawData(), - xmins[0], xmaxs[0]); + const double delta = this->determineBinning(xValues.mutableRawData(), + xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { @@ -348,7 +360,7 @@ void ResampleX::exec() { for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION BinEdges xValues(0); - double delta = this->determineBinning( + const double delta = this->determineBinning( xValues.mutableRawData(), xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] @@ -378,7 +390,7 @@ void ResampleX::exec() { // Set the X axis for each output histogram MantidVec xValues; - double delta = + const double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; @@ -458,8 +470,8 @@ void ResampleX::exec() { // create new output X axis MantidVec XValues_new; - double delta = this->determineBinning(XValues_new, xmins[wkspIndex], - xmaxs[wkspIndex]); + const double delta = this->determineBinning(XValues_new, xmins[wkspIndex], + xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; diff --git a/Framework/Algorithms/src/Stitch1DMany.cpp b/Framework/Algorithms/src/Stitch1DMany.cpp index afb9e4feefd4a4d3c78f8e8d38006a298f6218a6..77f76abccba7ac53328b35b749bb6657eac50dda 100644 --- a/Framework/Algorithms/src/Stitch1DMany.cpp +++ b/Framework/Algorithms/src/Stitch1DMany.cpp @@ -205,7 +205,7 @@ void Stitch1DMany::validateGroupWorkspacesInputs() { // Log all errors and throw a runtime error if an error is found validateCommonInputs(errors); - if (errors.size() > 0) { + if (!errors.empty()) { auto &warnLog = getLogger().warning(); for (const auto &error : errors) { warnLog << "Invalid value for " << error.first << ": " << error.second @@ -241,7 +241,7 @@ void Stitch1DMany::validateCommonInputs( m_useManualScaleFactors = this->getProperty("UseManualScaleFactors"); m_manualScaleFactors = this->getProperty("ManualScaleFactors"); - if (m_manualScaleFactors.size() > 0) { + if (!m_manualScaleFactors.empty()) { if (m_manualScaleFactors.size() == 1) { // Single value: fill with list of the same scale factor value m_manualScaleFactors = std::vector<double>(numStitchableWS - 1, diff --git a/Framework/Algorithms/test/ReflectometryReductionOne2Test.h b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h index a81db535a25473585f77dc4c8a3e26cb88f5bd66..66c6b76ee504fe00e961d1d49d8b648e56261ad7 100644 --- a/Framework/Algorithms/test/ReflectometryReductionOne2Test.h +++ b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h @@ -18,6 +18,7 @@ using namespace WorkspaceCreationHelper; class ReflectometryReductionOne2Test : public CxxTest::TestSuite { private: + MatrixWorkspace_sptr m_singleDetectorWS; MatrixWorkspace_sptr m_multiDetectorWS; MatrixWorkspace_sptr m_transmissionWS; @@ -33,6 +34,8 @@ public: ReflectometryReductionOne2Test() { FrameworkManager::Instance(); + // A single detector ws + m_singleDetectorWS = create2DWorkspaceWithReflectometryInstrument(0); // A multi detector ws m_multiDetectorWS = create2DWorkspaceWithReflectometryInstrumentMultiDetector(0, 0.1); @@ -447,12 +450,12 @@ public: alg.setProperty("ThetaIn", 25.0); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 12); - TS_ASSERT_DELTA(outLam->x(0)[0], 0.927132, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[3], 5.165740, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[7], 10.817217, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 2.773699, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[3], 2.828460, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[7], 2.816935, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], 0.934991, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[3], 5.173599, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[7], 10.825076, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 2.768185, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[3], 2.792649, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[7], 2.787410, 1e-6); } void test_sum_in_q_non_flat_sample() { @@ -469,12 +472,12 @@ public: alg.setProperty("ReductionType", "NonFlatSample"); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 10); - TS_ASSERT_DELTA(outLam->x(0)[0], 0.822974, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[3], 5.061582, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[7], 10.713059, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 3.140302, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[3], 3.140457, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[7], 3.140644, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], 0.825488, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[3], 5.064095, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[7], 10.715573, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 3.141858, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[3], 3.141885, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[7], 3.141920, 1e-6); } void test_sum_in_q_direct_beam() { @@ -492,12 +495,12 @@ public: alg.setProperty("ThetaIn", 25.0); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 11); - TS_ASSERT_DELTA(outLam->x(0)[0], 0.913144, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[3], 5.151752, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[7], 10.803229, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 0.447237, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[3], 0.454605, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[7], 0.451946, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], 0.920496, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[3], 5.159104, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[7], 10.810581, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 0.446571, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[3], 0.449843, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[7], 0.448591, 1e-6); } void test_sum_in_q_monitor_normalization() { @@ -527,12 +530,12 @@ public: alg.setProperty("ThetaIn", 25.0); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 13); - TS_ASSERT_DELTA(outLam->x(0)[0], -0.742692, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[5], 6.321654, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[9], 11.973131, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 5.044175, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[5], 2.118472, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[9], 2.280546, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], -0.748671, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[5], 6.315674, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[9], 11.967151, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 5.040302, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[5], 2.193649, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[9], 2.255101, 1e-6); } void test_sum_in_q_transmission_correction_run() { @@ -546,12 +549,12 @@ public: alg.setProperty("ThetaIn", 25.0); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 12); - TS_ASSERT_DELTA(outLam->x(0)[0], 0.927132, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[3], 5.165740, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[7], 10.817217, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 0.620714, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[3], 0.899935, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[7], 0.896268, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], 0.934991, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[3], 5.173599, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[7], 10.825076, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 0.631775, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[3], 0.888541, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[7], 0.886874, 1e-6); } void test_sum_in_q_exponential_correction() { @@ -567,12 +570,12 @@ public: alg.setProperty("C1", 0.1); MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 11); - TS_ASSERT_DELTA(outLam->x(0)[0], 0.913144, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[3], 5.151752, 1e-6); - TS_ASSERT_DELTA(outLam->x(0)[7], 10.803229, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[0], 16.353662, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[3], 24.261270, 1e-6); - TS_ASSERT_DELTA(outLam->y(0)[7], 39.844321, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[0], 0.920496, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[3], 5.159104, 1e-6); + TS_ASSERT_DELTA(outLam->x(0)[7], 10.810581, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[0], 16.351599, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[3], 23.963539, 1e-6); + TS_ASSERT_DELTA(outLam->y(0)[7], 39.756738, 1e-6); } void test_sum_in_q_IvsQ() { @@ -590,13 +593,38 @@ public: MatrixWorkspace_sptr outQ = runAlgorithmQ(alg, 11); // X range in outQ - TS_ASSERT_DELTA(outQ->x(0)[0], 0.292253, 1e-6); - TS_ASSERT_DELTA(outQ->x(0)[3], 0.393656, 1e-6); - TS_ASSERT_DELTA(outQ->x(0)[7], 0.732554, 1e-6); + TS_ASSERT_DELTA(outQ->x(0)[0], 0.292122, 1e-6); + TS_ASSERT_DELTA(outQ->x(0)[3], 0.393419, 1e-6); + TS_ASSERT_DELTA(outQ->x(0)[7], 0.731734, 1e-6); // Y counts - TS_ASSERT_DELTA(outQ->y(0)[0], 2.891639, 1e-6); - TS_ASSERT_DELTA(outQ->y(0)[3], 2.854571, 1e-6); - TS_ASSERT_DELTA(outQ->y(0)[7], 2.871364, 1e-6); + TS_ASSERT_DELTA(outQ->y(0)[0], 2.852088, 1e-6); + TS_ASSERT_DELTA(outQ->y(0)[3], 2.833380, 1e-6); + TS_ASSERT_DELTA(outQ->y(0)[7], 2.841288, 1e-6); + } + + void test_sum_in_q_IvsQ_point_detector() { + // Test IvsQ workspace for a point detector + // No monitor normalization + // No direct beam normalization + // No transmission correction + // Processing instructions : 0 + + ReflectometryReductionOne2 alg; + setupAlgorithm(alg, 1.5, 15.0, "0"); + alg.setProperty("InputWorkspace", m_singleDetectorWS); + alg.setProperty("SummationType", "SumInQ"); + alg.setProperty("ReductionType", "DivergentBeam"); + alg.setProperty("ThetaIn", 25.0); + MatrixWorkspace_sptr outQ = runAlgorithmQ(alg, 28); + + // X range in outQ + TS_ASSERT_DELTA(outQ->x(0)[0], 0.279882, 1e-6); + TS_ASSERT_DELTA(outQ->x(0)[3], 0.310524, 1e-6); + TS_ASSERT_DELTA(outQ->x(0)[7], 0.363599, 1e-6); + // Y counts + TS_ASSERT_DELTA(outQ->y(0)[0], 2.900305, 1e-6); + TS_ASSERT_DELTA(outQ->y(0)[3], 2.886947, 1e-6); + TS_ASSERT_DELTA(outQ->y(0)[7], 2.607359, 1e-6); } private: diff --git a/Framework/Crystal/inc/MantidCrystal/CentroidPeaks.h b/Framework/Crystal/inc/MantidCrystal/CentroidPeaks.h index c621ce01755f3e645015975161539b1aea0e029d..f5e0c4fdfaaca15b3c2636ac752e6593f164d9fe 100644 --- a/Framework/Crystal/inc/MantidCrystal/CentroidPeaks.h +++ b/Framework/Crystal/inc/MantidCrystal/CentroidPeaks.h @@ -39,6 +39,7 @@ private: void integrateEvent(); int findPixelID(std::string bankName, int col, int row); void removeEdgePeaks(Mantid::DataObjects::PeaksWorkspace &peakWS); + void sizeBanks(const std::string &bankName, int &nCols, int &nRows); Geometry::Instrument_const_sptr inst; /// Input 2D Workspace diff --git a/Framework/Crystal/src/CentroidPeaks.cpp b/Framework/Crystal/src/CentroidPeaks.cpp index 4fa430714de92f41eba24da27c61a25c3d91f6f3..af82de22733023657f267dee28f6fc9d584f5562 100644 --- a/Framework/Crystal/src/CentroidPeaks.cpp +++ b/Framework/Crystal/src/CentroidPeaks.cpp @@ -5,6 +5,8 @@ #include "MantidKernel/VectorHelper.h" #include "MantidGeometry/Crystal/OrientedLattice.h" #include "MantidGeometry/Crystal/EdgePixel.h" +#include "MantidGeometry/Instrument/ComponentInfo.h" +#include <boost/algorithm/clamp.hpp> using Mantid::DataObjects::PeaksWorkspace; @@ -106,6 +108,8 @@ void CentroidPeaks::integrate() { const auto &X = inWS->x(workspaceIndex); int chan = Kernel::VectorHelper::getBinIndex(X.rawData(), TOFPeakd); std::string bankName = peak.getBankName(); + int nCols = 0, nRows = 0; + sizeBanks(bankName, nCols, nRows); double intensity = 0.0; double chancentroid = 0.0; @@ -114,10 +118,10 @@ void CentroidPeaks::integrate() { int chanend = std::min(static_cast<int>(X.size()), chan + PeakRadius); double rowcentroid = 0.0; int rowstart = std::max(0, row - PeakRadius); - int rowend = row + PeakRadius; + int rowend = std::min(nRows - 1, row + PeakRadius); double colcentroid = 0.0; - int colstart = col - PeakRadius; - int colend = col + PeakRadius; + int colstart = std::max(0, col - PeakRadius); + int colend = std::min(nCols - 1, col + PeakRadius); for (int ichan = chanstart; ichan <= chanend; ++ichan) { for (int irow = rowstart; irow <= rowend; ++irow) { for (int icol = colstart; icol <= colend; ++icol) { @@ -140,16 +144,15 @@ void CentroidPeaks::integrate() { } // Set pixelID to change row and col row = int(rowcentroid / intensity); - row = std::max(0, row); + boost::algorithm::clamp(row, 0, nRows - 1); col = int(colcentroid / intensity); - col = std::max(0, col); + boost::algorithm::clamp(col, 0, nCols - 1); chan = int(chancentroid / intensity); - chan = std::max(0, chan); - chan = std::min(static_cast<int>(inWS->blocksize()), chan); + boost::algorithm::clamp(chan, 0, static_cast<int>(inWS->blocksize())); - peak.setDetectorID(findPixelID(bankName, col, row)); // Set wavelength to change tof for peak object if (!edgePixel(inst, bankName, col, row, Edge)) { + peak.setDetectorID(findPixelID(bankName, col, row)); it = wi_to_detid_map.find(findPixelID(bankName, col, row)); workspaceIndex = (it->second); Mantid::Kernel::Units::Wavelength wl; @@ -224,6 +227,8 @@ void CentroidPeaks::integrateEvent() { int row = peak.getRow(); double TOFPeakd = peak.getTOF(); std::string bankName = peak.getBankName(); + int nCols = 0, nRows = 0; + sizeBanks(bankName, nCols, nRows); double intensity = 0.0; double tofcentroid = 0.0; @@ -234,10 +239,10 @@ void CentroidPeaks::integrateEvent() { double tofend = TOFPeakd * std::pow(1.004, PeakRadius); double rowcentroid = 0.0; int rowstart = std::max(0, row - PeakRadius); - int rowend = row + PeakRadius; + int rowend = std::min(nRows - 1, row + PeakRadius); double colcentroid = 0.0; int colstart = std::max(0, col - PeakRadius); - int colend = col + PeakRadius; + int colend = std::min(nCols - 1, col + PeakRadius); for (int irow = rowstart; irow <= rowend; ++irow) { for (int icol = colstart; icol <= colend; ++icol) { if (edgePixel(inst, bankName, icol, irow, Edge)) @@ -263,9 +268,9 @@ void CentroidPeaks::integrateEvent() { } // Set pixelID to change row and col row = int(rowcentroid / intensity); - row = std::max(0, row); + boost::algorithm::clamp(row, 0, nRows - 1); col = int(colcentroid / intensity); - col = std::max(0, col); + boost::algorithm::clamp(col, 0, nCols - 1); if (!edgePixel(inst, bankName, col, row, Edge)) { peak.setDetectorID(findPixelID(bankName, col, row)); @@ -340,7 +345,7 @@ void CentroidPeaks::removeEdgePeaks( Mantid::DataObjects::PeaksWorkspace &peakWS) { int Edge = getProperty("EdgePixels"); std::vector<int> badPeaks; - size_t numPeaks = peakWS.getNumberPeaks() - 1; + size_t numPeaks = peakWS.getNumberPeaks(); for (int i = 0; i < static_cast<int>(numPeaks); i++) { // Get a direct ref to that peak. const auto &peak = peakWS.getPeak(i); @@ -355,5 +360,33 @@ void CentroidPeaks::removeEdgePeaks( peakWS.removePeaks(std::move(badPeaks)); } +void CentroidPeaks::sizeBanks(const std::string &bankName, int &nCols, + int &nRows) { + if (bankName == "None") + return; + ExperimentInfo expInfo; + expInfo.setInstrument(inst); + const auto &compInfo = expInfo.componentInfo(); + + // Get a single bank + auto bank = inst->getComponentByName(bankName); + auto bankID = bank->getComponentID(); + auto allBankDetectorIndexes = + compInfo.detectorsInSubtree(compInfo.indexOf(bankID)); + + nRows = static_cast<int>( + compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() - + allBankDetectorIndexes.size() - 1); + nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows; + + if (nCols * nRows != static_cast<int>(allBankDetectorIndexes.size())) { + // Need grandchild instead of child + nRows = static_cast<int>( + compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() - + allBankDetectorIndexes.size() - 2); + nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows; + } +} + } // namespace Mantid } // namespace Crystal diff --git a/Framework/Crystal/src/PeakHKLErrors.cpp b/Framework/Crystal/src/PeakHKLErrors.cpp index cccd488248ddfcb56420e10905411ddbcdb0bdee..08e2cac4993df840ad6fa7b85ff76bd66eaf5d8c 100644 --- a/Framework/Crystal/src/PeakHKLErrors.cpp +++ b/Framework/Crystal/src/PeakHKLErrors.cpp @@ -51,7 +51,7 @@ void PeakHKLErrors::init() { declareParameter("GonRotz", 0.0, "1st Rotation of Goniometer about the z axis"); initMode = 1; - if (OptRuns == "") + if (OptRuns.empty()) return; initMode = 2; diff --git a/Framework/Crystal/src/SCDPanelErrors.cpp b/Framework/Crystal/src/SCDPanelErrors.cpp index 07fd84a64f618a8b3b05eee9563c8f9cdc1497eb..d6da4f78916bdb4fe7d7a27fe6d3987c7f521a27 100644 --- a/Framework/Crystal/src/SCDPanelErrors.cpp +++ b/Framework/Crystal/src/SCDPanelErrors.cpp @@ -263,7 +263,7 @@ void SCDPanelErrors::setAttribute(const std::string &attName, } FileValidator fval; std::string error = fval.isValid(fileName); - if (error == "") { + if (error.empty()) { storeAttributeValue(attName, Attribute(fileName, true)); storeAttributeValue("Workspace", Attribute("")); } else { diff --git a/Framework/Crystal/test/CentroidPeaksTest.h b/Framework/Crystal/test/CentroidPeaksTest.h index 8da626a7a5d904e310dedb1945956b61e162362e..58897139904b4a5bd94627160871fe7f0f2f86de 100644 --- a/Framework/Crystal/test/CentroidPeaksTest.h +++ b/Framework/Crystal/test/CentroidPeaksTest.h @@ -139,10 +139,14 @@ public: PeaksWorkspace_sptr pkws(new PeaksWorkspace()); // pkws->setName("TOPAZ"); - // Create a single peak on that particular detector - Peak PeakObj(in_ws->getInstrument(), 5050, 2., V3D(1, 1, 1)); + // Create two peaks on that particular detector + // First peak is at edge to check EdgePixels option + Peak PeakObj(in_ws->getInstrument(), 0, 2., V3D(1, 1, 1)); PeakObj.setRunNumber(3007); pkws->addPeak(PeakObj); + Peak PeakObj2(in_ws->getInstrument(), 5050, 2., V3D(1, 1, 1)); + PeakObj2.setRunNumber(3007); + pkws->addPeak(PeakObj2); AnalysisDataService::Instance().addOrReplace("TOPAZ", pkws); inputW->mutableRun().addProperty("run_number", 3007); diff --git a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp index 390821af3be5437760ca7a6fd877039181b7760f..1db18580faec19def2ff5663f27bf94881c73300 100644 --- a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp +++ b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp @@ -289,7 +289,7 @@ void ConvertToYSpace::createOutputWorkspace() { m_outputWS->setYUnitLabel(""); // q-Space output workspace - if (getPropertyValue("QWorkspace") != "") { + if (!getPropertyValue("QWorkspace").empty()) { m_qOutputWS = WorkspaceFactory::Instance().create(m_inputWS); m_qOutputWS->getAxis(0)->unit() = xLabel; diff --git a/Framework/CurveFitting/src/Algorithms/Fit.cpp b/Framework/CurveFitting/src/Algorithms/Fit.cpp index a0d584825b5fc0c7eeeee2d8605d4888f4b7652a..95f0f78800031337e3134444e8b879338c782122 100644 --- a/Framework/CurveFitting/src/Algorithms/Fit.cpp +++ b/Framework/CurveFitting/src/Algorithms/Fit.cpp @@ -138,7 +138,7 @@ void Fit::copyMinimizerOutput(const API::IFuncMinimizer &minimizer) { auto &properties = minimizer.getProperties(); for (auto property : properties) { if ((*property).direction() == Kernel::Direction::Output && - (*property).isValid() == "") { + (*property).isValid().empty()) { auto clonedProperty = std::unique_ptr<Kernel::Property>((*property).clone()); declareProperty(std::move(clonedProperty)); diff --git a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp index 97d725beb899d6fe4466f15e30a17dd4bf51e52d..b744e8480cf9bf89d9c9dbd6b8dd10653c4684d3 100644 --- a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp +++ b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp @@ -646,7 +646,7 @@ std::string PlotPeakByLogValue::getMinimizerString(const std::string &wsName, dynamic_cast<Mantid::API::WorkspaceProperty<> *>(minimizerProp); if (wsProp) { const std::string &wsPropValue = minimizerProp->value(); - if (wsPropValue != "") { + if (!wsPropValue.empty()) { const std::string &wsPropName = minimizerProp->name(); m_minimizerWorkspaces[wsPropName].push_back(wsPropValue); } diff --git a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp index 9cd6f62a1920daf4dab915a1b389015631baa581..1978323b913878a7139faac8ff1427371338052f 100644 --- a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp +++ b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp @@ -223,7 +223,7 @@ void SplineInterpolation::exec() { } // Store the output workspaces std::string derivWsName = getPropertyValue("OutputWorkspaceDeriv"); - if (order > 0 && derivWsName != "") { + if (order > 0 && !derivWsName.empty()) { // Store derivatives in a grouped workspace WorkspaceGroup_sptr wsg = WorkspaceGroup_sptr(new WorkspaceGroup); for (size_t i = 0; i < histNo; ++i) { diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp index 009155d4c25ceaaf4d73cc43692b0713eebb7f1c..246fec09c7f9e1398a8f8b857c20006f2e891e37 100644 --- a/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp +++ b/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp @@ -266,7 +266,7 @@ void CrystalFieldMultiSpectrum::calcExcitations( // using an index instead of a name for performance reasons auto &source = dynamic_cast<Peaks &>(*m_source); double intensityScaling; - if (source.m_IntensityScalingIdx.size() == 0) { + if (source.m_IntensityScalingIdx.empty()) { intensityScaling = getParameter(m_nOwnParams - nSpec + iSpec); } else { intensityScaling = getParameter(source.m_IntensityScalingIdx[iSpec]); diff --git a/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp b/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp index a10ed3ab8ab1cd167fe5c6b144c5081ca3fe39e7..a9fe5275204464c18984f565e77659b684cba22e 100644 --- a/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp +++ b/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp @@ -174,7 +174,7 @@ void TabulatedFunction::setAttribute(const std::string &attName, } FileValidator fval; std::string error = fval.isValid(fileName); - if (error == "") { + if (error.empty()) { storeAttributeValue(attName, Attribute(fileName, true)); storeAttributeValue("Workspace", Attribute("")); } else { diff --git a/Framework/DataHandling/src/DataBlockComposite.cpp b/Framework/DataHandling/src/DataBlockComposite.cpp index 73da894721584cf8180be6ef52c776476cc5b804..50d25d844d1a87d2e834b82e15c32e358dab14d9 100644 --- a/Framework/DataHandling/src/DataBlockComposite.cpp +++ b/Framework/DataHandling/src/DataBlockComposite.cpp @@ -412,6 +412,7 @@ void DataBlockComposite::removeSpectra(DataBlockComposite &toRemove) { // Get intervals for the data blocks which should be removed auto removeBlocks = toRemove.getDataBlocks(); std::vector<std::pair<int64_t, int64_t>> toRemoveIntervals; + toRemoveIntervals.reserve(removeBlocks.size()); for (const auto &dataBlock : removeBlocks) { toRemoveIntervals.emplace_back(dataBlock.getMinSpectrumID(), dataBlock.getMaxSpectrumID()); diff --git a/Framework/DataHandling/src/DownloadInstrument.cpp b/Framework/DataHandling/src/DownloadInstrument.cpp index 5bd0af84487f294cd50e03b5147aa47a95407ef7..1b45d90322b641f2f5e3fa1c6cac454bb072bde9 100644 --- a/Framework/DataHandling/src/DownloadInstrument.cpp +++ b/Framework/DataHandling/src/DownloadInstrument.cpp @@ -204,7 +204,7 @@ DownloadInstrument::StringToStringMap DownloadInstrument::processRepository() { if ((sha != installSha) && (sha != localSha)) { fileMap.emplace(htmlUrl, filePath.toString()); // ACTION - DOWNLOAD to localPath - } else if ((localSha != "") && (sha == installSha) && + } else if ((!localSha.empty()) && (sha == installSha) && (sha != localSha)) // matches install, but different local { fileMap.emplace( diff --git a/Framework/DataHandling/src/LoadAscii2.cpp b/Framework/DataHandling/src/LoadAscii2.cpp index e5ccb44c41b46c8b3b262c1f4f4c205941c92a1e..3ffa5ed3b66a2eeec3fbfd0622c02719f9b90e55 100644 --- a/Framework/DataHandling/src/LoadAscii2.cpp +++ b/Framework/DataHandling/src/LoadAscii2.cpp @@ -671,7 +671,7 @@ void LoadAscii2::exec() { std::string sep; // If the custom separator property is not empty, then we use that under any // circumstance. - if (custom != "") { + if (!custom.empty()) { sep = custom; } // Else if the separator drop down choice is not UserDefined then we use that. diff --git a/Framework/DataHandling/src/LoadFITS.cpp b/Framework/DataHandling/src/LoadFITS.cpp index 0754635782a1e2666c4d2080767dc144d87ef623..694bbb047437c4c6b578030dab7f6793a178b0b1 100644 --- a/Framework/DataHandling/src/LoadFITS.cpp +++ b/Framework/DataHandling/src/LoadFITS.cpp @@ -293,7 +293,7 @@ void LoadFITS::loadHeader(const std::string &filePath, FITSInfo &header) { } // scale parameter, header BSCALE in the fits standard - if ("" == header.headerKeys[m_headerScaleKey]) { + if (header.headerKeys[m_headerScaleKey].empty()) { header.scale = 1; } else { try { @@ -308,7 +308,7 @@ void LoadFITS::loadHeader(const std::string &filePath, FITSInfo &header) { } // data offsset parameter, header BZERO in the fits standard - if ("" == header.headerKeys[m_headerOffsetKey]) { + if (header.headerKeys[m_headerOffsetKey].empty()) { header.offset = 0; } else { try { @@ -361,7 +361,7 @@ void LoadFITS::loadHeader(const std::string &filePath, FITSInfo &header) { void LoadFITS::headerSanityCheck(const FITSInfo &hdr, const FITSInfo &hdrFirst) { bool valid = true; - if (hdr.extension != "") { + if (!hdr.extension.empty()) { valid = false; g_log.error() << "File " << hdr.filePath << ": extensions found in the header.\n"; @@ -625,7 +625,7 @@ void LoadFITS::parseHeader(FITSInfo &headerInfo) { if (key == g_END_KEYNAME) endFound = true; - if (key != "") + if (!key.empty()) headerInfo.headerKeys[key] = value; } } @@ -1141,7 +1141,7 @@ void LoadFITS::setupDefaultKeywordNames() { * Maps the header keys to specified values */ void LoadFITS::mapHeaderKeys() { - if ("" == getPropertyValue(g_HEADER_MAP_NAME)) + if (getPropertyValue(g_HEADER_MAP_NAME).empty()) return; // If a map file is selected, use that. @@ -1157,19 +1157,19 @@ void LoadFITS::mapHeaderKeys() { while (getline(fStream, line)) { boost::split(lineSplit, line, boost::is_any_of("=")); - if (lineSplit[0] == g_ROTATION_NAME && lineSplit[1] != "") + if (lineSplit[0] == g_ROTATION_NAME && !lineSplit[1].empty()) m_headerRotationKey = lineSplit[1]; - if (lineSplit[0] == g_BIT_DEPTH_NAME && lineSplit[1] != "") + if (lineSplit[0] == g_BIT_DEPTH_NAME && !lineSplit[1].empty()) m_headerBitDepthKey = lineSplit[1]; - if (lineSplit[0] == g_AXIS_NAMES_NAME && lineSplit[1] != "") { + if (lineSplit[0] == g_AXIS_NAMES_NAME && !lineSplit[1].empty()) { m_headerAxisNameKeys.clear(); boost::split(m_headerAxisNameKeys, lineSplit[1], boost::is_any_of(",")); } - if (lineSplit[0] == g_IMAGE_KEY_NAME && lineSplit[1] != "") { + if (lineSplit[0] == g_IMAGE_KEY_NAME && !lineSplit[1].empty()) { m_headerImageKeyKey = lineSplit[1]; } } diff --git a/Framework/DataHandling/src/LoadFullprofResolution.cpp b/Framework/DataHandling/src/LoadFullprofResolution.cpp index 32c8bc93506f25537b1ce06e6e4902bd4996d301..cb0e15e01287afd33a56ae11450e397fa30c3717 100644 --- a/Framework/DataHandling/src/LoadFullprofResolution.cpp +++ b/Framework/DataHandling/src/LoadFullprofResolution.cpp @@ -189,7 +189,7 @@ void LoadFullprofResolution::exec() { // Generate output table workspace API::ITableWorkspace_sptr outTabWs = genTableWorkspace(bankparammap); - if (getPropertyValue("OutputTableWorkspace") != "") { + if (!getPropertyValue("OutputTableWorkspace").empty()) { // Output the output table workspace setProperty("OutputTableWorkspace", outTabWs); } @@ -225,7 +225,7 @@ void LoadFullprofResolution::exec() { loadParamAlg->execute(); } } - } else if (getPropertyValue("OutputTableWorkspace") == "") { + } else if (getPropertyValue("OutputTableWorkspace").empty()) { // We don't know where to output throw std::runtime_error( "Either the OutputTableWorkspace or Workspace property must be set."); diff --git a/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp b/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp index 239ea187ff49047152f221f36e53d16d585be4f9..ca4e25413be5a612a4dec884a2942202e9543b29 100644 --- a/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp +++ b/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp @@ -151,7 +151,7 @@ void LoadGSASInstrumentFile::exec() { WorkspaceGroup_sptr wsg = getProperty("Workspace"); // Generate output table workspace API::ITableWorkspace_sptr outTabWs = genTableWorkspace(bankparammap); - if (getPropertyValue("OutputTableWorkspace") != "") { + if (!getPropertyValue("OutputTableWorkspace").empty()) { // Output the output table workspace setProperty("OutputTableWorkspace", outTabWs); } diff --git a/Framework/DataHandling/src/LoadIDFFromNexus.cpp b/Framework/DataHandling/src/LoadIDFFromNexus.cpp index f68ae54eb58d351ee064453a00349d043824e8ed..74305f3eedfbe26a71f97511f9b6c905e52a2abd 100644 --- a/Framework/DataHandling/src/LoadIDFFromNexus.cpp +++ b/Framework/DataHandling/src/LoadIDFFromNexus.cpp @@ -88,7 +88,7 @@ void LoadIDFFromNexus::exec() { // Look for parameter correction file std::string parameterCorrectionFile = getPropertyValue("ParameterCorrectionFilePath"); - if (parameterCorrectionFile == "") { + if (parameterCorrectionFile.empty()) { parameterCorrectionFile = getParameterCorrectionFile(localWorkspace->getInstrument()->getName()); } @@ -98,7 +98,7 @@ void LoadIDFFromNexus::exec() { // Read parameter correction file, if found std::string correctionParameterFile; bool append = false; - if (parameterCorrectionFile != "") { + if (!parameterCorrectionFile.empty()) { // Read parameter correction file // to find out which parameter file to use // and whether it is appended to default parameters. @@ -112,7 +112,7 @@ void LoadIDFFromNexus::exec() { // Load default parameters if either there is no correction parameter file or // it is to be appended. - if (correctionParameterFile == "" || append) { + if (correctionParameterFile.empty() || append) { LoadParameters(&nxfile, localWorkspace); } else { // Else clear the parameters g_log.notice() << "Parameters to be replaced are cleared.\n"; @@ -120,7 +120,7 @@ void LoadIDFFromNexus::exec() { } // Load parameters from correction parameter file, if it exists - if (correctionParameterFile != "") { + if (!correctionParameterFile.empty()) { Poco::Path corrFilePath(parameterCorrectionFile); g_log.debug() << "Correction file path: " << corrFilePath.toString() << "\n"; @@ -200,7 +200,7 @@ void LoadIDFFromNexus::readParameterCorrectionFile( append = false; // Check the date. - if (date == "") { + if (date.empty()) { g_log.notice() << "No date is supplied for parameter correction file " << correction_file << ". Correction file is ignored.\n"; return; diff --git a/Framework/DataHandling/src/LoadILLDiffraction.cpp b/Framework/DataHandling/src/LoadILLDiffraction.cpp index 707c1e4661b527c36f25c600b3d8d85ece95de9f..f04af6189a05e10c1f842ad5e917aba0237955e1 100644 --- a/Framework/DataHandling/src/LoadILLDiffraction.cpp +++ b/Framework/DataHandling/src/LoadILLDiffraction.cpp @@ -480,7 +480,7 @@ std::vector<double> LoadILLDiffraction::getScannedVaribleByPropertyName( } } - if (scannedVariable.size() == 0) + if (scannedVariable.empty()) throw std::runtime_error( "Can not load file because scanned variable with property name " + propertyName + " was not found"); diff --git a/Framework/DataHandling/src/LoadILLIndirect2.cpp b/Framework/DataHandling/src/LoadILLIndirect2.cpp index 4a40a4d3eb8c1a6041b6cf02746190d1be245d6d..9360967a296c627d32fd0d4707f02cd177d87ce5 100644 --- a/Framework/DataHandling/src/LoadILLIndirect2.cpp +++ b/Framework/DataHandling/src/LoadILLIndirect2.cpp @@ -130,7 +130,7 @@ void LoadILLIndirect2::exec() { void LoadILLIndirect2::setInstrumentName( const NeXus::NXEntry &firstEntry, const std::string &instrumentNamePath) { - if (instrumentNamePath == "") { + if (instrumentNamePath.empty()) { std::string message("Cannot set the instrument name from the Nexus file!"); g_log.error(message); throw std::runtime_error(message); diff --git a/Framework/DataHandling/src/LoadILLReflectometry.cpp b/Framework/DataHandling/src/LoadILLReflectometry.cpp index 8a5b69d8b49a622c19b667de27f1fe062e352fc3..f5f647ae8293b110d1457b82e47dbcb28641bdf1 100644 --- a/Framework/DataHandling/src/LoadILLReflectometry.cpp +++ b/Framework/DataHandling/src/LoadILLReflectometry.cpp @@ -176,7 +176,7 @@ void LoadILLReflectometry::exec() { void LoadILLReflectometry::setInstrumentName( const NeXus::NXEntry &firstEntry, const std::string &instrumentNamePath) { - if (instrumentNamePath == "") { + if (instrumentNamePath.empty()) { std::string message("Cannot set the instrument name from the Nexus file!"); g_log.error(message); throw std::runtime_error(message); diff --git a/Framework/DataHandling/src/LoadILLSANS.cpp b/Framework/DataHandling/src/LoadILLSANS.cpp index 4e04e099d398ab98adc552eb294f460eb6c5f790..b9c0d3667cb8c838b019b135c8574639b6e48914 100644 --- a/Framework/DataHandling/src/LoadILLSANS.cpp +++ b/Framework/DataHandling/src/LoadILLSANS.cpp @@ -107,7 +107,7 @@ void LoadILLSANS::exec() { void LoadILLSANS::setInstrumentName(const NeXus::NXEntry &firstEntry, const std::string &instrumentNamePath) { - if (instrumentNamePath == "") { + if (instrumentNamePath.empty()) { std::string message("Cannot set the instrument name from the Nexus file!"); g_log.error(message); throw std::runtime_error(message); diff --git a/Framework/DataHandling/src/LoadILLTOF2.cpp b/Framework/DataHandling/src/LoadILLTOF2.cpp index 50f76c1d0245aa0fb47e150412614312bc4f9e88..9cc3f2e0a7070bf0101ccfd29655e4acf10c3899 100644 --- a/Framework/DataHandling/src/LoadILLTOF2.cpp +++ b/Framework/DataHandling/src/LoadILLTOF2.cpp @@ -144,7 +144,7 @@ void LoadILLTOF2::loadInstrumentDetails(NeXus::NXEntry &firstEntry) { m_instrumentPath = m_loader.findInstrumentNexusPath(firstEntry); - if (m_instrumentPath == "") { + if (m_instrumentPath.empty()) { throw std::runtime_error( "Cannot set the instrument name from the Nexus file!"); } diff --git a/Framework/DataHandling/src/LoadIsawDetCal.cpp b/Framework/DataHandling/src/LoadIsawDetCal.cpp index f2a479594d1dc83a2400d48665e0a06a681d3210..54638a6518b1b4a2d2dfae8e931dea9cc74fb345 100644 --- a/Framework/DataHandling/src/LoadIsawDetCal.cpp +++ b/Framework/DataHandling/src/LoadIsawDetCal.cpp @@ -92,7 +92,7 @@ std::map<std::string, std::string> LoadIsawDetCal::validateInputs() { // two detcal files is only valid for snap std::vector<std::string> filenames = getFilenames(); - if (filenames.size() == 0) { + if (filenames.empty()) { result["Filename"] = "Must supply .detcal file"; } else if (filenames.size() == 2) { Workspace_const_sptr wksp = getProperty("InputWorkspace"); diff --git a/Framework/DataHandling/src/LoadLLB.cpp b/Framework/DataHandling/src/LoadLLB.cpp index 83f047c87824f9ae25676b5a12dfb0baa1543b7b..6599483496a88d39b8bb412576b4539f2a9a867b 100644 --- a/Framework/DataHandling/src/LoadLLB.cpp +++ b/Framework/DataHandling/src/LoadLLB.cpp @@ -104,7 +104,7 @@ void LoadLLB::setInstrumentName(NeXus::NXEntry &entry) { m_instrumentName = m_loader.getStringFromNexusPath(entry, m_instrumentPath + "/name"); - if (m_instrumentName == "") { + if (m_instrumentName.empty()) { throw std::runtime_error( "Cannot read the instrument name from the Nexus file!"); } diff --git a/Framework/DataHandling/src/LoadMLZ.cpp b/Framework/DataHandling/src/LoadMLZ.cpp index 1ad5df0508499856145ab39f86435dfc5956a9cf..23159b7e7906fa1d292d109799748df2adcff780 100644 --- a/Framework/DataHandling/src/LoadMLZ.cpp +++ b/Framework/DataHandling/src/LoadMLZ.cpp @@ -149,7 +149,7 @@ void LoadMLZ::loadInstrumentDetails(NeXus::NXEntry &firstEntry) { m_instrumentPath = m_mlzloader.findInstrumentNexusPath(firstEntry); - if (m_instrumentPath == "") { + if (m_instrumentPath.empty()) { throw std::runtime_error( "Cannot set the instrument name from the Nexus file!"); } diff --git a/Framework/DataHandling/src/LoadSINQFocus.cpp b/Framework/DataHandling/src/LoadSINQFocus.cpp index d7a6a56b7bae9efbc38ec8c7c1bf29f8e529b04b..3494437cfa328e6b800cd8cdf2bdc7615a251e3f 100644 --- a/Framework/DataHandling/src/LoadSINQFocus.cpp +++ b/Framework/DataHandling/src/LoadSINQFocus.cpp @@ -112,7 +112,7 @@ void LoadSINQFocus::setInstrumentName(NeXus::NXEntry &entry) { m_instrumentPath = m_loader.findInstrumentNexusPath(entry); - if (m_instrumentPath == "") { + if (m_instrumentPath.empty()) { throw std::runtime_error( "Cannot set the instrument name from the Nexus file!"); } diff --git a/Framework/DataHandling/src/LoadSassena.cpp b/Framework/DataHandling/src/LoadSassena.cpp index 3713595548fa142b7461364372b931ab719b8f00..ba2054ea9fd5b72345ba5ad38a7d7abaf6aa8ebc 100644 --- a/Framework/DataHandling/src/LoadSassena.cpp +++ b/Framework/DataHandling/src/LoadSassena.cpp @@ -136,6 +136,7 @@ LoadSassena::loadQvectors(const hid_t &h5file, API::WorkspaceGroup_sptr gws, if (getProperty("SortByQVectors")) { std::vector<mypair> qvmodpair; + qvmodpair.reserve(nq); for (int iq = 0; iq < nq; iq++) qvmodpair.emplace_back(qvmod[iq], iq); std::sort(qvmodpair.begin(), qvmodpair.end(), compare); diff --git a/Framework/DataHandling/src/LoadSpice2D.cpp b/Framework/DataHandling/src/LoadSpice2D.cpp index c6a47228130e52fe6c0781238a51dbfcd691786c..04096230e33114217af96c9348b82ed5c73dd46e 100644 --- a/Framework/DataHandling/src/LoadSpice2D.cpp +++ b/Framework/DataHandling/src/LoadSpice2D.cpp @@ -468,6 +468,7 @@ void LoadSpice2D::setBeamTrapRunProperty( // store trap diameters in use std::vector<double> trapDiametersInUse; + trapDiametersInUse.reserve(trapIndexInUse.size()); for (auto index : trapIndexInUse) { trapDiametersInUse.push_back(trapDiameters[index]); } diff --git a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp index eb82237827233b88a0bdd756785990ad0460ec80..f8eda027c8d1960e700628c4e700621d8d0eb0f5 100644 --- a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp +++ b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp @@ -231,7 +231,7 @@ void LoadSpiceXML2DDet::processInputs() { if (vec_pixelgeom.size() == 2) { m_numPixelX = vec_pixelgeom[0]; m_numPixelY = vec_pixelgeom[1]; - } else if (vec_pixelgeom.size() == 0) { + } else if (vec_pixelgeom.empty()) { m_numPixelX = 0; m_numPixelY = 0; } else { @@ -714,7 +714,7 @@ LoadSpiceXML2DDet::parseDetectorNode(const std::string &detvaluestr, size_t num_empty_line = 0; size_t num_weird_line = 0; for (size_t iline = 0; iline < vecLines.size(); ++iline) { - if (vecLines[iline].size() == 0) + if (vecLines[iline].empty()) ++num_empty_line; else if (vecLines[iline].size() < 100) ++num_weird_line; diff --git a/Framework/DataHandling/src/LoadTBL.cpp b/Framework/DataHandling/src/LoadTBL.cpp index 1eeaff23a342af8e5aa0729defd686fe1bccbe2f..b5ab7f31e6329b39b45803ba8f5642188566c3ec 100644 --- a/Framework/DataHandling/src/LoadTBL.cpp +++ b/Framework/DataHandling/src/LoadTBL.cpp @@ -342,7 +342,7 @@ void LoadTBL::exec() { std::string line; int stitchID = 1; while (Kernel::Strings::extractToEOL(file, line)) { - if (line == "" || line == ",,,,,,,,,,,,,,,,") { + if (line.empty() || line == ",,,,,,,,,,,,,,,,") { continue; } getCells(line, rowVec, 16, isOld); @@ -351,8 +351,8 @@ void LoadTBL::exec() { // check if the first run in the row has any data associated with it // 0 = runs, 1 = theta, 2 = trans, 3 = qmin, 4 = qmax - if (rowVec[0] != "" || rowVec[1] != "" || rowVec[2] != "" || - rowVec[3] != "" || rowVec[4] != "") { + if (!rowVec[0].empty() || !rowVec[1].empty() || !rowVec[2].empty() || + !rowVec[3].empty() || !rowVec[4].empty()) { TableRow row = ws->appendRow(); row << stitchStr; for (int i = 0; i < 5; ++i) { @@ -364,8 +364,8 @@ void LoadTBL::exec() { // check if the second run in the row has any data associated with it // 5 = runs, 6 = theta, 7 = trans, 8 = qmin, 9 = qmax - if (rowVec[5] != "" || rowVec[6] != "" || rowVec[7] != "" || - rowVec[8] != "" || rowVec[9] != "") { + if (!rowVec[5].empty() || !rowVec[6].empty() || !rowVec[7].empty() || + !rowVec[8].empty() || !rowVec[9].empty()) { TableRow row = ws->appendRow(); row << stitchStr; for (int i = 5; i < 10; ++i) { @@ -377,8 +377,8 @@ void LoadTBL::exec() { // check if the third run in the row has any data associated with it // 10 = runs, 11 = theta, 12 = trans, 13 = qmin, 14 = qmax - if (rowVec[10] != "" || rowVec[11] != "" || rowVec[12] != "" || - rowVec[13] != "" || rowVec[14] != "") { + if (!rowVec[10].empty() || !rowVec[11].empty() || !rowVec[12].empty() || + !rowVec[13].empty() || !rowVec[14].empty()) { TableRow row = ws->appendRow(); row << stitchStr; for (int i = 10; i < 17; ++i) { @@ -413,7 +413,7 @@ void LoadTBL::exec() { } size_t expectedCommas = columnHeadings.size() - 1; while (Kernel::Strings::extractToEOL(file, line)) { - if (line == "" || line == ",,,,,,,,,,,,,,,,") { + if (line.empty() || line == ",,,,,,,,,,,,,,,,") { // skip over any empty lines continue; } diff --git a/Framework/DataHandling/src/RemoveLogs.cpp b/Framework/DataHandling/src/RemoveLogs.cpp index e29203f4db23251365da50db228a706f500f2526..78d2a8a53587594478a995694cd0a775f3a8975a 100644 --- a/Framework/DataHandling/src/RemoveLogs.cpp +++ b/Framework/DataHandling/src/RemoveLogs.cpp @@ -62,6 +62,7 @@ void RemoveLogs::exec() { localWorkspace->run().getLogData(); std::vector<std::string> keepLogs = getProperty("KeepLogs"); std::vector<std::string> logNames; + logNames.reserve(logData.size()); for (const auto property : logData) { logNames.push_back(property->name()); } diff --git a/Framework/DataHandling/src/SaveAscii.cpp b/Framework/DataHandling/src/SaveAscii.cpp index 090452f80897cbb9e72b013c0da017e7add7fc1b..2b10f7211f0e1cf6208c4e26a2e3855ac0451895 100644 --- a/Framework/DataHandling/src/SaveAscii.cpp +++ b/Framework/DataHandling/src/SaveAscii.cpp @@ -111,7 +111,7 @@ void SaveAscii::exec() { std::string sep; // If the custom separator property is not empty, then we use that under any // circumstance. - if (custom != "") { + if (!custom.empty()) { sep = custom; } // Else if the separator drop down choice is not UserDefined then we use that. diff --git a/Framework/DataHandling/src/SaveAscii2.cpp b/Framework/DataHandling/src/SaveAscii2.cpp index e44f640c9e590fbf517dd567532e29532f97a532..55a10b34c34d516607d3aa774885395208c06c75 100644 --- a/Framework/DataHandling/src/SaveAscii2.cpp +++ b/Framework/DataHandling/src/SaveAscii2.cpp @@ -166,7 +166,7 @@ void SaveAscii2::exec() { const std::string custom = getPropertyValue("CustomSeparator"); // If the custom separator property is not empty, then we use that under any // circumstance. - if (custom != "") { + if (!custom.empty()) { m_sep = custom; } // Else if the separator drop down choice is not UserDefined then we use that. diff --git a/Framework/DataHandling/src/SaveDiffFittingAscii.cpp b/Framework/DataHandling/src/SaveDiffFittingAscii.cpp index 1a499698b74dced9a685e490a027347163daa3c8..c7fa62e19a9c75ac305896b0f021f7616fddb983 100644 --- a/Framework/DataHandling/src/SaveDiffFittingAscii.cpp +++ b/Framework/DataHandling/src/SaveDiffFittingAscii.cpp @@ -86,6 +86,7 @@ bool SaveDiffFittingAscii::processGroups() { AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(name); std::vector<API::ITableWorkspace_sptr> input_ws; + input_ws.reserve(inputGroup->getNumberOfEntries()); for (int i = 0; i < inputGroup->getNumberOfEntries(); ++i) { input_ws.push_back( boost::dynamic_pointer_cast<ITableWorkspace>(inputGroup->getItem(i))); diff --git a/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Framework/DataHandling/src/SaveReflCustomAscii.cpp index 6b9a61892c157d851e748b78045e009ac348ee3d..2630e931e3ea1bbdadd0f79fe1f1970db238a00d 100644 --- a/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -34,7 +34,7 @@ void SaveReflCustomAscii::extraHeaders(std::ofstream &file) { std::string subtitleEntry; std::string title = getProperty("Title"); - if (title != "") // if is toggled + if (!title.empty()) // if is toggled { file << "#" << title << '\n'; } diff --git a/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index 29b9218c24ea1de02e57c71e0e2a5321bb4d0467..cf8c9cd7013801a4880ac92aa98f8b7cb27fb5c6 100644 --- a/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -28,7 +28,7 @@ void SaveReflThreeColumnAscii::extraHeaders(std::ofstream &file) { auto samp = m_ws->run(); std::string title = getProperty("Title"); - if (title != "") // if is toggled + if (!title.empty()) // if is toggled { file << "#" << title << '\n'; } diff --git a/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp b/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp index b44854c1b2ffcd7e7b9859d041bca976a5b69bed..38625424c86340cf3b68e44562635a4de5e3b837 100644 --- a/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp +++ b/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp @@ -560,13 +560,13 @@ int SaveToSNSHistogramNexus::WriteGroup(int is_definition) { } //--------------------------------------------------------------------------------------- - if (data_label == "data" && (bank != "")) { + if (data_label == "data" && (!bank.empty())) { if (this->WriteDataGroup(bank, is_definition) != NX_OK) return NX_ERROR; ; } //--------------------------------------------------------------------------------------- - else if (data_label == "time_of_flight" && (bank != "")) { + else if (data_label == "time_of_flight" && (!bank.empty())) { // Get the original info if (NXgetinfo(inId, &dataRank, dataDimensions, &dataType) != NX_OK) return NX_ERROR; diff --git a/Framework/DataObjects/src/EventList.cpp b/Framework/DataObjects/src/EventList.cpp index 9471b3bf95b5582ee9268e4a4176cfaad5588f43..64dd418bad5f778f723e338dadd2e63921ec7b79 100644 --- a/Framework/DataObjects/src/EventList.cpp +++ b/Framework/DataObjects/src/EventList.cpp @@ -4403,7 +4403,7 @@ void EventList::splitByPulseTimeWithMatrix( } // Split - if (vec_target.size() == 0) { + if (vec_target.empty()) { // No splitter: copy all events to group workspace = -1 (*outputs[-1]) = (*this); } else { diff --git a/Framework/DataObjects/src/MDHistoWorkspace.cpp b/Framework/DataObjects/src/MDHistoWorkspace.cpp index 0b2c563a92242ce5dc0818927df67bcfac233a72..d08c9ffeef6815b3399bc7efbba006dbab01f0c8 100644 --- a/Framework/DataObjects/src/MDHistoWorkspace.cpp +++ b/Framework/DataObjects/src/MDHistoWorkspace.cpp @@ -130,6 +130,7 @@ MDHistoWorkspace::~MDHistoWorkspace() { void MDHistoWorkspace::init( std::vector<Mantid::Geometry::MDHistoDimension_sptr> &dimensions) { std::vector<IMDDimension_sptr> dim2; + dim2.reserve(dimensions.size()); for (auto &dimension : dimensions) dim2.push_back(boost::dynamic_pointer_cast<IMDDimension>(dimension)); this->init(dim2); diff --git a/Framework/DataObjects/src/PeaksWorkspace.cpp b/Framework/DataObjects/src/PeaksWorkspace.cpp index a08a5e0b6e51e4a50024a811d388f8439b2a1a50..d38c71e134721f311ab3efe3b8022464955b96ca 100644 --- a/Framework/DataObjects/src/PeaksWorkspace.cpp +++ b/Framework/DataObjects/src/PeaksWorkspace.cpp @@ -156,20 +156,19 @@ void PeaksWorkspace::removePeak(const int peakNum) { void PeaksWorkspace::removePeaks(std::vector<int> badPeaks) { if (badPeaks.empty()) return; - std::sort(badPeaks.begin(), badPeaks.end()); - auto index = peaks.begin(); - auto end = peaks.end(); - auto result = index; - for (int i = 0; index < end; ++index, ++i) { - // if index of peak is not in badPeaks - if (!std::binary_search(badPeaks.begin(), badPeaks.end(), i)) { - // include in result - *result = std::move(*index); - ++result; - } - } - // erase peaks outside of result - peaks.erase(result, peaks.end()); + // if index of peak is in badPeaks remove + int ip = -1; + auto it = + std::remove_if(peaks.begin(), peaks.end(), [&ip, badPeaks](Peak &pk) { + (void)pk; + ip++; + for (auto ibp = badPeaks.begin(); ibp != badPeaks.end(); ++ibp) { + if (*ibp == ip) + return true; + } + return false; + }); + peaks.erase(it, peaks.end()); } //--------------------------------------------------------------------------------------------- diff --git a/Framework/Geometry/src/Crystal/ProductOfCyclicGroups.cpp b/Framework/Geometry/src/Crystal/ProductOfCyclicGroups.cpp index 3aa2a64504e67418b8aa7b0ffd2f50c4fecea00a..460194a240c20e7c7cc997329f6d9b975859e8dd 100644 --- a/Framework/Geometry/src/Crystal/ProductOfCyclicGroups.cpp +++ b/Framework/Geometry/src/Crystal/ProductOfCyclicGroups.cpp @@ -31,7 +31,7 @@ ProductOfCyclicGroups::getGeneratedGroup(const std::string &generators) const { std::vector<Group_const_sptr> ProductOfCyclicGroups::getFactorGroups( const std::vector<SymmetryOperation> &symmetryOperations) const { std::vector<Group_const_sptr> groups; - + groups.reserve(symmetryOperations.size()); for (const auto &symmetryOperation : symmetryOperations) { groups.push_back( GroupFactory::create<CyclicGroup>(symmetryOperation.identifier())); diff --git a/Framework/Geometry/src/Crystal/SymmetryElementFactory.cpp b/Framework/Geometry/src/Crystal/SymmetryElementFactory.cpp index 09c5dfd1b37e2d2265dc3f2f764ddf5ae6629340..471c225be685c17caa1f65a81234382fe53b5d1b 100644 --- a/Framework/Geometry/src/Crystal/SymmetryElementFactory.cpp +++ b/Framework/Geometry/src/Crystal/SymmetryElementFactory.cpp @@ -313,7 +313,7 @@ std::string SymmetryElementMirrorGenerator::determineSymbol( * proper symbol, so the general symbol "g" is used for these cases. * Examples can be found in No. 227 (Fd-3m). */ - if (symbol == "") { + if (symbol.empty()) { return "g"; } diff --git a/Framework/Geometry/src/Crystal/SymmetryOperationFactory.cpp b/Framework/Geometry/src/Crystal/SymmetryOperationFactory.cpp index 35651a9b6bab229e43c57a1090536092dd3c68a0..4630469d7cc882ba38354ce7173a286600812f04 100644 --- a/Framework/Geometry/src/Crystal/SymmetryOperationFactory.cpp +++ b/Framework/Geometry/src/Crystal/SymmetryOperationFactory.cpp @@ -32,6 +32,7 @@ SymmetryOperationFactoryImpl::createSymOps(const std::string &identifiers) { std::vector<SymmetryOperation> SymmetryOperationFactoryImpl::createSymOps( const std::vector<std::string> &identifiers) { std::vector<SymmetryOperation> symOps; + symOps.reserve(identifiers.size()); for (const auto &identifier : identifiers) { symOps.push_back(createSymOp(boost::trim_copy(identifier))); } diff --git a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp index f079aa5fa59343da650e578f8558d9952af781b0..62e0b6d875c8f4330375bd646fbd4ba9a06d0a87 100644 --- a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp +++ b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp @@ -1282,7 +1282,7 @@ void InstrumentDefinitionParser::createDetectorOrMonitor( std::stringstream ss1, ss2; ss1 << idList.vec.size(); ss2 << idList.counted; - if (idList.idname == "") { + if (idList.idname.empty()) { g_log.error("No list of detector IDs found for location element " + name); throw Kernel::Exception::InstrumentDefinitionError( "Detector location element " + name + " has no idlist.", filename); diff --git a/Framework/Geometry/src/MDGeometry/MDGeometryXMLParser.cpp b/Framework/Geometry/src/MDGeometry/MDGeometryXMLParser.cpp index 8cb0b237fa16105e36e04d6084f91a5bc0ba90fc..14f37e578f8364453b0babdd394f66d877a99f6c 100644 --- a/Framework/Geometry/src/MDGeometry/MDGeometryXMLParser.cpp +++ b/Framework/Geometry/src/MDGeometry/MDGeometryXMLParser.cpp @@ -93,8 +93,10 @@ void MDGeometryXMLParser::execute() { throw std::invalid_argument("Cannot determine x-dimension mapping."); } m_xDimension = *xDimensionIt; - vecNonMappedDims.erase(std::remove_if( - vecNonMappedDims.begin(), vecNonMappedDims.end(), findID(xDimId))); + vecNonMappedDims.erase(std::remove_if(vecNonMappedDims.begin(), + vecNonMappedDims.end(), + findID(xDimId)), + vecNonMappedDims.end()); } Poco::XML::Element *yDimensionElement = geometryXMLElement->getChildElement( @@ -112,8 +114,10 @@ void MDGeometryXMLParser::execute() { throw std::invalid_argument("Cannot determine y-dimension mapping."); } m_yDimension = *yDimensionIt; - vecNonMappedDims.erase(std::remove_if( - vecNonMappedDims.begin(), vecNonMappedDims.end(), findID(yDimId))); + vecNonMappedDims.erase(std::remove_if(vecNonMappedDims.begin(), + vecNonMappedDims.end(), + findID(yDimId)), + vecNonMappedDims.end()); } Poco::XML::Element *zDimensionElement = geometryXMLElement->getChildElement( @@ -131,8 +135,10 @@ void MDGeometryXMLParser::execute() { throw std::invalid_argument("Cannot determine z-dimension mapping."); } m_zDimension = *zDimensionIt; - vecNonMappedDims.erase(std::remove_if( - vecNonMappedDims.begin(), vecNonMappedDims.end(), findID(zDimId))); + vecNonMappedDims.erase(std::remove_if(vecNonMappedDims.begin(), + vecNonMappedDims.end(), + findID(zDimId)), + vecNonMappedDims.end()); } Poco::XML::Element *tDimensionElement = geometryXMLElement->getChildElement( @@ -150,8 +156,10 @@ void MDGeometryXMLParser::execute() { } m_tDimension = *tDimensionIt; if (!vecNonMappedDims.empty()) { - vecNonMappedDims.erase(std::remove_if( - vecNonMappedDims.begin(), vecNonMappedDims.end(), findID(tDimId))); + vecNonMappedDims.erase(std::remove_if(vecNonMappedDims.begin(), + vecNonMappedDims.end(), + findID(tDimId)), + vecNonMappedDims.end()); } } m_vecNonMappedDims = vecNonMappedDims; // Copy with strong guarantee. diff --git a/Framework/HistogramData/src/CountStandardDeviations.cpp b/Framework/HistogramData/src/CountStandardDeviations.cpp index 40fc5823bcd4ea06f3a2525bf358587c0018fb02..439692a50a0fe4ef7d767735a13a146abc643b13 100644 --- a/Framework/HistogramData/src/CountStandardDeviations.cpp +++ b/Framework/HistogramData/src/CountStandardDeviations.cpp @@ -24,7 +24,7 @@ CountStandardDeviations::CountStandardDeviations( throw std::logic_error("CountStandardDeviations: Cannot construct from " "FrequencyStandardDeviations -- BinEdges are NULL."); if ((frequencies.size() + 1) != edges.size()) - if (frequencies.size() != 0 || edges.size() != 0) + if (!frequencies.empty() || !edges.empty()) throw std::logic_error("CountStandardDeviations: Cannot construct from " "FrequencyStandardDeviations -- BinEdges size " "does not " diff --git a/Framework/HistogramData/src/CountVariances.cpp b/Framework/HistogramData/src/CountVariances.cpp index 3153e6f540e15c08ab1bd0482191ccf8ffb2bfe7..baf7b9c4c558921a25901aec5e1d4c50c63218bf 100644 --- a/Framework/HistogramData/src/CountVariances.cpp +++ b/Framework/HistogramData/src/CountVariances.cpp @@ -23,7 +23,7 @@ CountVariances::CountVariances(FrequencyVariances &&frequencies, throw std::logic_error("CountVariances: Cannot construct from " "FrequencyVariances -- BinEdges are NULL."); if ((frequencies.size() + 1) != edges.size()) - if (frequencies.size() != 0 || edges.size() != 0) + if (!frequencies.empty() || !edges.empty()) throw std::logic_error("CountVariances: Cannot construct from " "FrequencyVariances -- BinEdges size does not " "match."); diff --git a/Framework/HistogramData/src/Counts.cpp b/Framework/HistogramData/src/Counts.cpp index f63e47a0da03f21c57883c07a5ad8f0566e87731..3c5b7e0461fc8daec1982dc5d81b142afa8419bb 100644 --- a/Framework/HistogramData/src/Counts.cpp +++ b/Framework/HistogramData/src/Counts.cpp @@ -17,7 +17,7 @@ Counts::Counts(Frequencies &&frequencies, const BinEdges &edges) { throw std::logic_error( "Counts: Cannot construct from Frequencies -- BinEdges are NULL."); if ((frequencies.size() + 1) != edges.size()) - if (frequencies.size() != 0 || edges.size() != 0) + if (!frequencies.empty() || !edges.empty()) throw std::logic_error("Counts: Cannot construct from Frequencies -- " "BinEdges size does not match."); // Cannot move frequencies private data since it is of different type. diff --git a/Framework/HistogramData/src/Frequencies.cpp b/Framework/HistogramData/src/Frequencies.cpp index 21b8836351a4a392a0cb226589b4316ddee4705f..6623ee0b2f8e62e2ebee81bbd310400088d324bf 100644 --- a/Framework/HistogramData/src/Frequencies.cpp +++ b/Framework/HistogramData/src/Frequencies.cpp @@ -17,7 +17,7 @@ Frequencies::Frequencies(Counts &&counts, const BinEdges &edges) { throw std::logic_error( "Frequencies: Cannot construct from Counts -- BinEdges are NULL."); if ((counts.size() + 1) != edges.size()) - if (counts.size() != 0 || edges.size() != 0) + if (!counts.empty() || !edges.empty()) throw std::logic_error("Frequencies: Cannot construct from Counts -- " "BinEdges size does not match."); // Cannot move counts private data since it is of different type. diff --git a/Framework/HistogramData/src/FrequencyStandardDeviations.cpp b/Framework/HistogramData/src/FrequencyStandardDeviations.cpp index a4b568727b1d96b0f3a6ef51986ee5143ce0b837..99665e08cf84e9a483d07793f88446a83e571904 100644 --- a/Framework/HistogramData/src/FrequencyStandardDeviations.cpp +++ b/Framework/HistogramData/src/FrequencyStandardDeviations.cpp @@ -23,7 +23,7 @@ FrequencyStandardDeviations::FrequencyStandardDeviations( throw std::logic_error("FrequencyStandardDeviations: Cannot construct from " "CountStandardDeviations -- BinEdges are NULL."); if ((counts.size() + 1) != edges.size()) - if (counts.size() != 0 || edges.size() != 0) + if (!counts.empty() || !edges.empty()) throw std::logic_error("FrequencyStandardDeviations: Cannot construct " "from CountStandardDeviations -- BinEdges size " "does not match."); diff --git a/Framework/HistogramData/src/FrequencyVariances.cpp b/Framework/HistogramData/src/FrequencyVariances.cpp index 86c7c47bb61678b0be314e8b1f456c5f0882b02e..a68c1c1ac073dad057b5293b0abe06f031e16d14 100644 --- a/Framework/HistogramData/src/FrequencyVariances.cpp +++ b/Framework/HistogramData/src/FrequencyVariances.cpp @@ -23,7 +23,7 @@ FrequencyVariances::FrequencyVariances(CountVariances &&counts, throw std::logic_error("FrequencyVariances: Cannot construct from " "CountVariances -- BinEdges are NULL."); if ((counts.size() + 1) != edges.size()) - if (counts.size() != 0 || edges.size() != 0) + if (!counts.empty() || !edges.empty()) throw std::logic_error("FrequencyVariances: Cannot construct from " "CountVariances -- BinEdges size does not match."); // Cannot move counts private data since it is of different type. diff --git a/Framework/HistogramData/src/Histogram.cpp b/Framework/HistogramData/src/Histogram.cpp index d6367b8cd828eeccdf3530a70ece473b25707cd6..80b28a8e525c9dba994193518abe0547ec73d27b 100644 --- a/Framework/HistogramData/src/Histogram.cpp +++ b/Framework/HistogramData/src/Histogram.cpp @@ -1,4 +1,5 @@ #include "MantidHistogramData/Histogram.h" +#include <sstream> namespace Mantid { namespace HistogramData { @@ -251,8 +252,12 @@ template <> void Histogram::checkSize(const BinEdges &binEdges) const { // 0 points -> 0 edges, otherwise edges are 1 more than points. if (xMode() == XMode::Points && target > 0) target++; - if (target != binEdges.size()) - throw std::logic_error("Histogram: size mismatch of BinEdges\n"); + if (target != binEdges.size()) { + std::stringstream msg; + msg << "Histogram: size mismatch of BinEdges: (" << target + << " != " << binEdges.size() << ")"; + throw std::logic_error(msg.str()); + } } /** Resets the size of the internal x, dx, y, and e data structures diff --git a/Framework/HistogramData/src/Points.cpp b/Framework/HistogramData/src/Points.cpp index 78edbfac5fb4bd5c442fe3b325b23a0a62fc9849..a375c2c64f944b47d0760fb3281dfb9c521f1779 100644 --- a/Framework/HistogramData/src/Points.cpp +++ b/Framework/HistogramData/src/Points.cpp @@ -10,7 +10,7 @@ Points::Points(const BinEdges &edges) { return; if (edges.size() == 1) throw std::logic_error("Points: Cannot construct from BinEdges of size 1"); - if (edges.size() == 0) { + if (edges.empty()) { m_data = Kernel::make_cow<HistogramX>(0); return; } diff --git a/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc index 134f38a8d0c9fc4f11c22beb4fde5d9d4ffa1f55..a4902017dbb7104790d56d09cb1a6fcb93393f37 100644 --- a/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc +++ b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc @@ -271,7 +271,7 @@ TYPE &PropertyWithValue<TYPE>::operator=(const TYPE &value) { m_value = value; } std::string problem = this->isValid(); - if (problem == "") { + if (problem.empty()) { return m_value; } else if (problem == "_alias") { m_value = getValueForAlias(value); diff --git a/Framework/Kernel/src/CompositeValidator.cpp b/Framework/Kernel/src/CompositeValidator.cpp index b87ecc4f290104bb1ed23eca042d291e5ac90418..55fd549ab0d6c74c636de5df72cf20184198bb90 100644 --- a/Framework/Kernel/src/CompositeValidator.cpp +++ b/Framework/Kernel/src/CompositeValidator.cpp @@ -74,7 +74,7 @@ std::string CompositeValidator::check(const boost::any &value) const { std::string error = (*itr)->check(value); // exit on the first error, to avoid passing doing more tests on invalid // objects that could fail - if (error != "") + if (!error.empty()) return error; } // there were no errors diff --git a/Framework/Kernel/src/ConfigService.cpp b/Framework/Kernel/src/ConfigService.cpp index 92f5b6b5d4ccb139e745f1f21ee6875600f62774..59ca2639dfb3f5ecfb7605f28ae18f7c238ddf6a 100644 --- a/Framework/Kernel/src/ConfigService.cpp +++ b/Framework/Kernel/src/ConfigService.cpp @@ -372,7 +372,7 @@ void ConfigServiceImpl::loadConfig(const std::string &filename, bool good = readFile(filename, temp); // check if we have failed to open the file - if ((!good) || (temp == "")) { + if ((!good) || (temp.empty())) { if (filename == getUserPropertiesDir() + m_user_properties_file_name) { // write out a fresh file createUserPropertiesFile(); @@ -382,7 +382,7 @@ void ConfigServiceImpl::loadConfig(const std::string &filename, } // store the property string - if ((append) && (m_PropertyString != "")) { + if ((append) && (!m_PropertyString.empty())) { m_PropertyString = m_PropertyString + "\n" + temp; } else { m_PropertyString = temp; diff --git a/Framework/Kernel/src/UsageService.cpp b/Framework/Kernel/src/UsageService.cpp index 5b77d1be8fa7c5f5b337f7777abcfdfe6d687b6b..54ab2d4a49e74e64a2919b2cc2e6fd49f236f7e6 100644 --- a/Framework/Kernel/src/UsageService.cpp +++ b/Framework/Kernel/src/UsageService.cpp @@ -263,7 +263,7 @@ std::string UsageServiceImpl::generateFeatureUsageMessage() { thisFeature["count"] = featureItem.second; features.append(thisFeature); } - if (features.size() > 0) { + if (!features.empty()) { message["features"] = features; return writer.write(message); } diff --git a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp index e11d0a2a9c98131cf29363fb787b4066361e7c5d..943900034c059d7d2c7a6042ced52845479c1b8a 100644 --- a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp +++ b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp @@ -341,7 +341,7 @@ void CompareMDWorkspaces::exec() { this->doComparison(); - if (m_result != "") { + if (!m_result.empty()) { g_log.notice() << "The workspaces did not match: " << m_result << '\n'; this->setProperty("Equals", false); } else { diff --git a/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace3.cpp b/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace3.cpp index 3eb926cae75671c33b69422a520973ab76117c8d..639462ab74555749e74240d3b1a2b3383a94f12f 100644 --- a/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace3.cpp +++ b/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace3.cpp @@ -70,7 +70,7 @@ void ConvertToDiffractionMDWorkspace3::convertExtents( minVal[d] = Extents[2 * d + 0]; maxVal[d] = Extents[2 * d + 1]; } - } else if (Extents.size() == 0) { + } else if (Extents.empty()) { calculateExtentsFromData(minVal, maxVal); } else throw std::invalid_argument( diff --git a/Framework/MDAlgorithms/src/Integrate3DEvents.cpp b/Framework/MDAlgorithms/src/Integrate3DEvents.cpp index 60178eb2fed080109d67838e00033f81baed3960..c59cb394f431e2719ac470f1e8a7c23fd3dabeb4 100644 --- a/Framework/MDAlgorithms/src/Integrate3DEvents.cpp +++ b/Framework/MDAlgorithms/src/Integrate3DEvents.cpp @@ -98,9 +98,9 @@ Integrate3DEvents::integrateStrongPeak(const IntegrationParameters ¶ms, std::vector<V3D> eigen_vectors; getEigenVectors(cov_matrix, eigen_vectors); - std::vector<double> sigmas; + std::vector<double> sigmas(3); for (int i = 0; i < 3; i++) { - sigmas.push_back(stdDev(events, eigen_vectors[i], params.regionRadius)); + sigmas[i] = stdDev(events, eigen_vectors[i], params.regionRadius); } bool invalid_peak = @@ -248,9 +248,9 @@ double Integrate3DEvents::estimateSignalToNoiseRatio( std::vector<V3D> eigen_vectors; getEigenVectors(cov_matrix, eigen_vectors); - std::vector<double> sigmas; + std::vector<double> sigmas(3); for (int i = 0; i < 3; i++) { - sigmas.push_back(stdDev(events, eigen_vectors[i], params.regionRadius)); + sigmas[i] = stdDev(events, eigen_vectors[i], params.regionRadius); } const auto max_sigma = *std::max_element(sigmas.begin(), sigmas.end()); @@ -404,9 +404,9 @@ Integrate3DEvents::ellipseIntegrateEvents( std::vector<V3D> eigen_vectors; getEigenVectors(cov_matrix, eigen_vectors); - std::vector<double> sigmas; + std::vector<double> sigmas(3); for (int i = 0; i < 3; i++) { - sigmas.push_back(stdDev(some_events, eigen_vectors[i], m_radius)); + sigmas[i] = stdDev(some_events, eigen_vectors[i], m_radius); } bool invalid_peak = diff --git a/Framework/Nexus/src/NexusFileIO.cpp b/Framework/Nexus/src/NexusFileIO.cpp index 502ab8330ec4a90527813dfe3382817c877bc0ea..e373e252dbb4b65913fe202969850358a9c6a311 100644 --- a/Framework/Nexus/src/NexusFileIO.cpp +++ b/Framework/Nexus/src/NexusFileIO.cpp @@ -264,7 +264,7 @@ bool NexusFileIO::writeNxNote(const std::string ¬eName, m_filehandle->makeGroup(noteName, "NXnote", true); std::vector<std::string> attributes, avalues; - if (date != "") { + if (!date.empty()) { attributes.emplace_back("date"); avalues.push_back(date); } diff --git a/Framework/PythonInterface/mantid/CMakeLists.txt b/Framework/PythonInterface/mantid/CMakeLists.txt index 0787726737ba6f196bef090ec6afa77e7fef391a..ea78516c4a88b4637858d3f15065e5aef29af3a1 100644 --- a/Framework/PythonInterface/mantid/CMakeLists.txt +++ b/Framework/PythonInterface/mantid/CMakeLists.txt @@ -15,6 +15,7 @@ set ( OUTPUT_DIR ${PYTHON_PKG_ROOT} ) set ( PY_FILES __init__.py simpleapi.py + fitfunctions.py ) copy_files_to_dir ( "${PY_FILES}" ${CMAKE_CURRENT_SOURCE_DIR} ${OUTPUT_DIR} diff --git a/Framework/PythonInterface/mantid/api/CMakeLists.txt b/Framework/PythonInterface/mantid/api/CMakeLists.txt index 17a8ea2024cd65837afdf288e0dc596590c4c50a..c1a7146b29db548f74f3ade9a3bde4ab0eb95e08 100644 --- a/Framework/PythonInterface/mantid/api/CMakeLists.txt +++ b/Framework/PythonInterface/mantid/api/CMakeLists.txt @@ -75,6 +75,7 @@ set ( EXPORT_FILES src/Exports/Projection.cpp src/Exports/FunctionProperty.cpp src/Exports/AlgorithmProperty.cpp + src/Exports/MultiDomainFunction.cpp ) set ( MODULE_DEFINITION ${CMAKE_CURRENT_BINARY_DIR}/api.cpp ) diff --git a/Framework/PythonInterface/mantid/api/src/Exports/CompositeFunction.cpp b/Framework/PythonInterface/mantid/api/src/Exports/CompositeFunction.cpp index 538cec6a0462f2ce18c83660911c924787262b25..9085e895a26f1b8c20773144861667ac42bdb75d 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/CompositeFunction.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/CompositeFunction.cpp @@ -1,12 +1,39 @@ +#include "MantidPythonInterface/kernel/GetPointer.h" #include "MantidAPI/CompositeFunction.h" #include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> +#include <boost/python/register_ptr_to_python.hpp> using Mantid::API::CompositeFunction; using Mantid::API::IFunction; using namespace boost::python; +GET_POINTER_SPECIALIZATION(CompositeFunction) + +namespace { + +typedef double (CompositeFunction::*getParameterType1)(size_t) const; +typedef double (CompositeFunction::*getParameterType2)( + const std::string &) const; + +typedef void (CompositeFunction::*setParameterType2)(const std::string &, + const double &, bool); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#endif +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(setParameterType2_Overloads, + setParameter, 2, 3) +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace + void export_CompositeFunction() { + register_ptr_to_python<boost::shared_ptr<CompositeFunction>>(); + class_<CompositeFunction, bases<IFunction>, boost::noncopyable>( "CompositeFunction", "Composite Fit functions") .def("nFunctions", &CompositeFunction::nFunctions, arg("self"), @@ -17,6 +44,23 @@ void export_CompositeFunction() { (arg("self"), arg("i")), "Get the i-th function.") .def("__getitem__", &CompositeFunction::getFunction, (arg("self"), arg("i")), "Get the i-th function.") + .def("__setitem__", &CompositeFunction::replaceFunction, + (arg("self"), arg("i"), arg("f")), + "Put function in place of the i-th function.") .def("add", &CompositeFunction::addFunction, - (arg("self"), arg("function")), "Add a member function."); + (arg("self"), arg("function")), "Add a member function.") + .def("getParameterValue", + (getParameterType1)&CompositeFunction::getParameter, + (arg("self"), arg("i")), "Get value of parameter of given index.") + .def("getParameterValue", + (getParameterType2)&CompositeFunction::getParameter, + (arg("self"), arg("name")), "Get value of parameter of given name.") + .def("__getitem__", (getParameterType2)&CompositeFunction::getParameter, + (arg("self"), arg("name")), "Get value of parameter of given name.") + .def("__setitem__", (setParameterType2)&CompositeFunction::setParameter, + setParameterType2_Overloads( + (arg("self"), arg("name"), arg("value"), arg("explicitlySet")), + "Get value of parameter of given name.")) + .def("__delitem__", &CompositeFunction::removeFunction, + (arg("self"), arg("index"))); } diff --git a/Framework/PythonInterface/mantid/api/src/Exports/FunctionFactory.cpp b/Framework/PythonInterface/mantid/api/src/Exports/FunctionFactory.cpp index 1e72c23d4613305bc2cff295b94653c3a2a7f488..bc9e49abf89f4271780d4e233ab7eaaadd22e363 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/FunctionFactory.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/FunctionFactory.cpp @@ -1,5 +1,6 @@ #include "MantidAPI/FunctionFactory.h" #include "MantidAPI/IFunction.h" +#include "MantidAPI/CompositeFunction.h" #include "MantidKernel/WarningSuppressions.h" #include "MantidPythonInterface/kernel/GetPointer.h" #include "MantidPythonInterface/kernel/PythonObjectInstantiator.h" @@ -47,6 +48,28 @@ PyObject *getFunctionNames(FunctionFactoryImpl &self) { return registered; } +//------------------------------------------------------------------------------------------------------ +/** +* Something that makes Function Factory return to python a composite function +* for Product function, Convolution or +* any similar superclass of composite function. +* @param self :: Enables it to be called as a member function on the +* FunctionFactory class +* @param name :: Name of the superclass of composite function, +* e.g. "ProductFunction". +*/ +Mantid::API::CompositeFunction_sptr +createCompositeFunction(FunctionFactoryImpl &self, const std::string &name) { + auto fun = self.createFunction(name); + auto composite = + boost::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun); + if (composite) { + return composite; + } + std::string error_message = name + " is not a composite function."; + throw std::invalid_argument(error_message); +} + //--------------------------------------------- Function registration //------------------------------------------------ @@ -96,6 +119,9 @@ void export_FunctionFactory() { no_init) .def("getFunctionNames", &getFunctionNames, arg("self"), "Returns a list of the currently available functions") + .def("createCompositeFunction", &createCompositeFunction, + (arg("self"), arg("name")), + "Return a pointer to the requested function") .def("createFunction", &FunctionFactoryImpl::createFunction, (arg("self"), arg("type")), "Return a pointer to the requested function") diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp index 889e326b37407529948cd91e19f6da1a88b608af..6115a7a2561c14ec7e23ea0d510e92633f980f0f 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp @@ -93,7 +93,7 @@ struct MandatoryFirst { /// in the list bool operator()(const Property *p1, const Property *p2) const { // this is false, unless p1 is not valid and p2 is valid - return (p1->isValid() != "") && (p2->isValid() == ""); + return (!p1->isValid().empty()) && (p2->isValid().empty()); } }; diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IFunction.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IFunction.cpp index 686b34f78e7a8a3f87118289bba12ed05a6c814d..26560ceb1b371bb4a0a49d91d882109a98349d74 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/IFunction.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/IFunction.cpp @@ -1,6 +1,7 @@ #include "MantidKernel/WarningSuppressions.h" #include "MantidPythonInterface/kernel/GetPointer.h" #include "MantidPythonInterface/api/FitFunctions/IFunctionAdapter.h" +#include "MantidAPI/CompositeFunction.h" #include <boost/python/class.hpp> #include <boost/python/def.hpp> @@ -60,6 +61,8 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fixParameter_Overloads, fixParameter, 1, 2) BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fix_Overloads, fix, 1, 2) BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fixAll_Overloads, fixAll, 0, 1) +typedef void (IFunction::*removeTieByName)(const std::string &); + GCC_DIAG_ON(conversion) #ifdef __clang__ #pragma clang diagnostic pop @@ -92,6 +95,12 @@ void export_IFunction() { .def("attributeNames", &IFunction::getAttributeNames, arg("self"), "The names of all the attributes") + .def("hasAttribute", &IFunction::hasAttribute, (arg("self"), arg("name")), + "Return whether there is an attribute of the given name") + + .def("hasParameter", &IFunction::hasParameter, (arg("self"), arg("name")), + "Return whether there is an parameter of the given name") + .def("nParams", &IFunction::nParams, arg("self"), "Return the number of parameters") @@ -114,6 +123,10 @@ void export_IFunction() { IFunction::getParameter, (arg("self"), arg("name")), "Get the value of the named parameter") + .def("__getitem__", (double (IFunction::*)(const std::string &) const) & + IFunction::getParameter, + (arg("self"), arg("name")), "Get the value of the named parameter") + .def("setParameter", (setParameterType1)&IFunction::setParameter, setParameterType1_Overloads( (arg("self"), arg("i"), arg("value"), arg("explicitlySet")), @@ -124,6 +137,11 @@ void export_IFunction() { (arg("self"), arg("name"), arg("value"), arg("explicitlySet")), "Sets the value of the named parameter")) + .def("__setitem__", (setParameterType2)&IFunction::setParameter, + setParameterType2_Overloads( + (arg("self"), arg("name"), arg("value"), arg("explicitlySet")), + "Sets the value of the named parameter")) + .def("declareAttribute", &IFunctionAdapter::declareAttribute, (arg("self"), arg("name"), arg("default_value")), "Declare an attribute with an initial value") @@ -204,6 +222,9 @@ void export_IFunction() { "Split this function (if needed) into a list of " "independent functions") + .def("nDomains", &IFunction::getNumberDomains, arg("self"), + "Get the number of domains.") + //-- Deprecated functions that have the wrong names -- .def("categories", &getCategories, arg("self"), "Returns a list of the categories for an algorithm") @@ -219,6 +240,7 @@ void export_IFunction() { .def("getParamValue", (double (IFunction::*)(std::size_t) const) & IFunction::getParameter, (arg("self"), arg("i")), "Get the value of the ith parameter") + //-- Python special methods -- .def("__repr__", &IFunction::asString, arg("self"), "Return a string representation of the function"); diff --git a/Framework/PythonInterface/mantid/api/src/Exports/MultiDomainFunction.cpp b/Framework/PythonInterface/mantid/api/src/Exports/MultiDomainFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2751fb1c80edc5596a9a76ba5845133529603fb8 --- /dev/null +++ b/Framework/PythonInterface/mantid/api/src/Exports/MultiDomainFunction.cpp @@ -0,0 +1,24 @@ +#include "MantidAPI/MultiDomainFunction.h" +#include <boost/python/class.hpp> + +using Mantid::API::MultiDomainFunction; +using Mantid::API::CompositeFunction; +using namespace boost::python; + +void export_MultiDomainFunction() { + class_<MultiDomainFunction, bases<CompositeFunction>, boost::noncopyable>( + "MultiDomainFunction", "Multi-Domain Fit functions") + .def("nFunctions", &MultiDomainFunction::nFunctions, arg("self"), + "Get the number of member functions.") + .def("__len__", &MultiDomainFunction::nFunctions, arg("self"), + "Get the number of member functions.") + .def("getFunction", &MultiDomainFunction::getFunction, + (arg("self"), arg("i")), "Get the i-th function.") + .def("__getitem__", &MultiDomainFunction::getFunction, + (arg("self"), arg("i")), "Get the i-th function.") + .def("add", &MultiDomainFunction::addFunction, + (arg("self"), arg("function")), "Add a member function.") + .def("setDomainIndex", &MultiDomainFunction::setDomainIndex, + (arg("self"), arg("funIndex"), arg("domainIndex")), + "Associate a function and a domain."); +} diff --git a/Framework/PythonInterface/mantid/api/src/Exports/ProductFunction.cpp b/Framework/PythonInterface/mantid/api/src/Exports/ProductFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2ef62e9d76421c213ded80dd4de24de3852ef45 --- /dev/null +++ b/Framework/PythonInterface/mantid/api/src/Exports/ProductFunction.cpp @@ -0,0 +1,48 @@ +#include "MantidAPI/ProductFunction.h" +#include <boost/python/class.hpp> +#include <boost/python/overloads.hpp> + +using Mantid::API::ProductFunction; +using Mantid::API::IFunction; +using namespace boost::python; + +namespace { + +typedef double (ProductFunction::*getParameterType1)(size_t) const; +typedef double (ProductFunction::*getParameterType2)(const std::string &) const; + +typedef void (ProductFunction::*setParameterType2)(const std::string &, + const double &, bool); +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(setParameterType2_Overloads, + setParameter, 2, 3) +} + +void export_ProductFunction() { + + class_<ProductFunction, bases<IFunction>, boost::noncopyable>( + "ProductFunction", "Composite Fit functions") + .def("nFunctions", &ProductFunction::nFunctions, arg("self"), + "Get the number of member functions.") + .def("__len__", &ProductFunction::nFunctions, arg("self"), + "Get the number of member functions.") + .def("getFunction", &ProductFunction::getFunction, + (arg("self"), arg("i")), "Get the i-th function.") + .def("__getitem__", &ProductFunction::getFunction, + (arg("self"), arg("i")), "Get the i-th function.") + .def("add", &ProductFunction::addFunction, (arg("self"), arg("function")), + "Add a member function.") + .def("getParameterValue", + (getParameterType1)&ProductFunction::getParameter, + (arg("self"), arg("i")), "Get value of parameter of given index.") + .def("getParameterValue", + (getParameterType2)&ProductFunction::getParameter, + (arg("self"), arg("name")), "Get value of parameter of given name.") + .def("__getitem__", (getParameterType2)&ProductFunction::getParameter, + (arg("self"), arg("name")), "Get value of parameter of given name.") + .def("__setitem__", (setParameterType2)&ProductFunction::setParameter, + setParameterType2_Overloads( + (arg("self"), arg("name"), arg("value"), arg("explicitlySet")), + "Get value of parameter of given name.")) + .def("__delitem__", &ProductFunction::removeFunction, + (arg("self"), arg("index"))); +} diff --git a/Framework/PythonInterface/mantid/fitfunctions.py b/Framework/PythonInterface/mantid/fitfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..38ccdb912b1f6a51f48aa528cce026f7f88aa3b3 --- /dev/null +++ b/Framework/PythonInterface/mantid/fitfunctions.py @@ -0,0 +1,523 @@ +from mantid.api import FunctionFactory + +class FunctionWrapper(object): + """ Wrapper class for Fitting Function + """ + def __init__ (self, name, **kwargs): + """ + Called when creating an instance + :param name: name of fitting function to create or + an Ifunction object to wrap. + :param **kwargs: standard argument for __init__ function + """ + if not isinstance(name, str): + self.fun = name + else: + self.fun = FunctionFactory.createFunction(name) + # Deal with attributes first + for key in kwargs: + if key == "attributes": + atts = kwargs[key] + for keya in atts: + self.fun.setAttributeValue(keya, atts[keya]) + elif self.fun.hasAttribute(key): + self.fun.setAttributeValue(key, kwargs[key]) + + # Then deal with parameters + for key in kwargs: + if key != "attributes" and not self.fun.hasAttribute(key): + self.fun.setParameter(key, kwargs[key]) + + def __getattr__(self, item): + """ + __getattr__ invoked when attribute item not found in the instance, + nor in the class, nor its superclasses. + :param item: named attribute + :return: attribute of self.fun instance, or any of the fitting + parameters or function attributes + """ + if 'fun' in self.__dict__: + if hasattr(self.fun, item): + return getattr(self.fun, item) + else: + return self.__getitem__(item) + + def __setattr__(self, key, value): + """ + __setattr__ invoked when attribute key not found in the instance, + nor in the class, nor its superclasses. + Enables direct access to the attributes of self.fun instance, and + also to its fitting parameters and function attributes + :param key: named attribute + :param value: new value for the named attribute + """ + if key == 'fun': + self.__dict__['fun'] = value # initialize self.fun + elif 'fun' in self.__dict__ and hasattr(self.fun, key): + setattr(self.fun, key, value) # key is attribute of instance self.fun + elif 'fun' in self.__dict__ and self.fun.hasAttribute(key): + self.fun.setAttributeValue(key, value) # key is function attribute + elif 'fun' in self.__dict__ and self.fun.hasParameter(key): + self.fun.setParameter(key, value) # key is fitting parameter + else: + self.__dict__[key] = value # initialize self.key + + def __getitem__ (self, name): + """ Called from array-like access on RHS + It should not be called directly. + :param name: name that appears in the [] + """ + if type(name) == type('string') and self.fun.hasAttribute(name): + return self.fun.getAttributeValue(name) + else: + return self.fun.getParameterValue(name) + + def __setitem__ (self, name, value): + """ Called from array-like access on LHS + It should not be called directly. + + :param name: name that appears in the [] + :param value: new value of this item + """ + if type(name) == type('string') and self.fun.hasAttribute(name): + self.fun.setAttributeValue(name, value) + else: + self.fun.setParameter(name, value) + + def __str__ (self): + """ Return string giving contents of function. + Used in unit tests. + """ + return self.fun.__str__() + + def __add__ (self, other): + """ Implement + operator for composite function + + :param other: functionWrapper to be added to self + """ + sum = CompositeFunctionWrapper(self, other) + if sum.pureAddition: + sum = sum.flatten() + return sum + + def __mul__ (self, other): + """ Implement * operator for product function + + :param other: functionWrapper to multiply self by + """ + prod = ProductFunctionWrapper(self, other) + if prod.pureMultiplication: + prod = prod.flatten() + return prod + + def tie (self, *args, **kwargs): + """ Add ties. + :param *args: one or more dictionaries of ties + :param **kwargs: one or more ties + """ + for a in args: + if isinstance(a, dict): + for key in a: + self.fun.tie(key, str(a[key])) + + for key in kwargs: + self.fun.tie(key, str(kwargs[key])) + + def fix(self, name): + """ Fix a parameter. + + :param name: name of parameter to be fixed + """ + self.fun.fixParameter(name) + + def fixAllParameters(self): + """ Fix all parameters. + """ + for i in range(0, self.fun.numParams()): + self.fix(self.getParameterName(i)) + + def untie(self, name): + """ Remove tie from parameter. + + :param name: name of parameter to be untied + """ + self.fun.removeTie(name) + + def untieAllParameters(self): + """ Remove ties from all parameters. + """ + for i in range(0, self.fun.numParams()): + self.fun.removeTie(self.getParameterName(i)) + + + def constrain(self, expressions): + """ Add constraints + + :param expressions: string of tie expressions + """ + self.fun.addConstraints( expressions ) + + def unconstrain(self, name): + """ Remove constraints from a parameter + + :param name: name of parameter to be unconstrained + """ + self.fun.removeConstraint(name) + + def free(self, name): + """ Free a parameter from tie or constraint + + :param name: name of parameter to be freed + """ + self.fun.removeTie(name) + self.fun.removeConstraint(name) + + def getParameterName(self, index): + """ Get the name of the parameter of given index + + :param index: index of parameter + """ + return self.fun.getParamName(index) + + @property + def function(self): + """ Return the underlying IFunction object + """ + return self.fun + + @property + def name(self): + """ Return the name of the function + """ + return self.fun.name() + +class CompositeFunctionWrapper(FunctionWrapper): + """ Wrapper class for Composite Fitting Function + """ + def __init__ (self, *args): + """ Called when creating an instance + It should not be called directly + :param *args: names of functions in composite function + """ + self.pureAddition = True + self.pureMultiplication = False + return self.initByName("CompositeFunction", *args) + + def initByName(self, name, *args): + """ intialise composite function of named type. + E.g. "ProductFunction" + This function would be protected in c++ + and should not be called directly except + by __init__ functions of this class and + subclasses. + + :param name: name of class calling this. + :param *args: names of functions in composite function + """ + if len(args) == 1 and not isinstance(args[0], FunctionWrapper): + # We have a composite function to wrap + self.fun = args[0] + else: + self.fun = FunctionFactory.createCompositeFunction(name) + + #Add the functions, checking for Composite & Product functions + for a in args: + if not isinstance(a, int): + if isinstance(a, CompositeFunctionWrapper): + if self.pureAddition: + self.pureAddition = a.pureAddition + if self.pureMultiplication: + self.pureMultiplication = a.pureMultiplication + functionToAdd = FunctionFactory.createInitialized( a.fun.__str__() ) + self.fun.add(functionToAdd) + + def getParameter(self, name): + """ get value of parameter of specified name + + :param name: name of parameter + """ + return self.fun.getParameterValue(name) + + def getCompositeParameterName(self, name, index): + """ get composite parameter name of parameter of + given name of member function of given index + """ + return "f"+str(index)+"."+name + + def getIndexOfFunction (self, name): + """ get index of function specified by name, + such as "LinearBackground" for the only + LinearBackground function or + "Gaussian1" for the second Gaussian function. + + :param name: name specifying the function + """ + # Only a shallow search is done. + + delimiter = " " + if name.count(delimiter) == 0: + fname = name + occurrence = 0 + else: + fname, n = name.split(delimiter) + occurrence = int(n) + + index = 0 + count = 0 + for f in self: + if f.fun.name() == fname: + if( count == occurrence): + return index + else: + count += 1 + index += 1 + + raise RuntimeError("Specified function not found.") + + def f (self, name): + """ get function specified by name, + such as "LinearBackground" for the only + LinearBackground function or + "Gaussian1" for the second Gaussian function. + + :param name: name specifying the function + """ + index = self.getIndexOfFunction(name) + return self[index] + + def __getitem__ (self, nameorindex): + """ get function of specified index or parameter of specified name + called for array-like access on RHS. + It should not be called directly. + + :param name: name or index in the [] + """ + + comp = self.fun + item = comp[nameorindex] + if isinstance(item, float): + return item + elif item.name() == "CompositeFunction": + return CompositeFunctionWrapper(item) + elif item.name() == "ProductFunction": + return ProductFunctionWrapper(item) + elif item.name() == "Convolution": + return ConvolutionWrapper(item) + else: + return FunctionWrapper(item) + + def __setitem__ (self, name, newValue): + """ Called from array-like access on LHS + It should not be called directly. + + :param name: name or index in the [] + :param newValue: new value for item + """ + comp = self.fun + if isinstance( newValue, FunctionWrapper): + comp[name] = newValue.fun + else: + comp[name] = newValue + + def __iadd__ (self, other): + """ Implement += operator. + It should not be called directly. + + :param other: object to add + """ + self.fun.add(other.fun) + return self + + def __delitem__ (self, index): + """ Delete item of given index from composite function. + It should not be called directly. + + :param index: index of item + """ + self.fun.__delitem__(index) + + def __len__ (self): + """ Return number of items in composite function. + Implement len() function. + It should not be called directly. + """ + + composite = self.fun + return composite.__len__() + + + def tieAll (self, name): + """ For each member function, tie the parameter of the given name + to the parameter of that name in the first member function. + The named parameter must occur in all the member functions. + + :param name: name of parameter + """ + expr = self.getCompositeParameterName(name, 0) + self.tie({self.getCompositeParameterName(name, i): expr for i in range(1,len(self)) }) + + def fixAll (self, name): + """ Fix all parameters with the given local name. + Every member function must have a parameter of this name. + + :param name: name of parameter + """ + for f in self: + f.fix(name) + + + def constrainAll (self, expressions): + """ Constrain all parameters according local names in expressions. + + :param expressions: string of expressions + """ + for i in range(0, len(self)): + if isinstance( self[i], CompositeFunctionWrapper ): + self[i].constrainAll(expressions) + else: + try: + self[i].constrain(expressions) + except: + pass + + def unconstrainAll (self, name): + """ Unconstrain all parameters of given local name. + + :param name: local name of parameter + """ + for i in range(0, len(self)): + if isinstance( self[i], CompositeFunctionWrapper ): + self[i].unconstrainAll(name) + else: + try: + self[i].unconstrain(name) + except: + pass + + def untieAll (self, name): + """ Untie all parameters with the given local name. + Every member function must have a parameter of this name. + + :param name: local name of parameter + """ + for i in range(0, len(self)): + self.untie(self.getCompositeParameterName(name, i)) + + def flatten (self): + """ Return composite function, equal to self, but with + every composite function within replaced by + its list of functions, so having a pure list of functions. + This makes it possible to index and iterate all the functions + and use tieAll() and untieAll(). + Not to be used with a mixture of product and sum + composite functions, because the arithmetic + may no longer be correct. + The return value is not independent of self. + """ + # If there are no composite functions, do nothing + needToFlatten = False + for i in range(0, len(self)): + if not needToFlatten and isinstance(self[i],CompositeFunctionWrapper): + needToFlatten = True + + if not needToFlatten : + return self + + # Now we know there is a composite function. + if isinstance(self,ProductFunctionWrapper): + flatSelf = ProductFunctionWrapper() + else: + flatSelf = CompositeFunctionWrapper() + + for i in range(0, len(self)): + if isinstance(self[i],CompositeFunctionWrapper): + currentFunction = self[i].flatten() + for j in range(0, len(currentFunction)): + flatSelf.fun.add(currentFunction[j].fun) + else: + flatSelf.fun.add(self[i].fun) + + return flatSelf + +class ProductFunctionWrapper(CompositeFunctionWrapper): + """ Wrapper class for Product Fitting Function + """ + def __init__ (self, *args): + """ Called when creating an instance + It should not be called directly. + :param *args: names of functions in composite function + """ + self.pureAddition = False + self.pureMultiplication = True + return self.initByName("ProductFunction", *args) + +class ConvolutionWrapper(CompositeFunctionWrapper): + """ Wrapper class for Convolution Fitting Function + """ + def __init__ (self, *args): + """ Called when creating an instance + It should not be called directly. + :param *args: names of functions in composite function + """ + self.pureAddition = False + self.pureMultiplication = False + return self.initByName("Convolution", *args) + +class MultiDomainFunctionWrapper(CompositeFunctionWrapper): + """ Wrapper class for Product Fitting Function + """ + def __init__ (self, *args, **kwargs): + """ Called when creating an instance + It should not be called directly + :param *args: names of functions in composite function + """ + # Assume it's not safe to flatten + self.pureAddition = False + self.pureMultiplication = False + + # Create and populate with copied functions + self.initByName("MultiDomainFunction", *args) + + # Tie the global parameters + if 'Global' in kwargs: + list = kwargs['Global'] + for name in list: + self.tieAll(name) + + # Set domain indices: 1 to 1 + for i in range(0, len(self)): + self.fun.setDomainIndex(i, i) + + @property + def nDomains (self): + """ Return number of domains + """ + return self.fun.nDomains() + + +def _create_wrapper_function(name): + """Create fake functions for the given name + It should not be called directly + + :param name: name of fake function + """ + # ------------------------------------------------------------------------------------------------ + def wrapper_function(*args, **kwargs): + name_to_constructor = { + 'CompositeFunction': CompositeFunctionWrapper, + 'ProductFunction': ProductFunctionWrapper, + 'Convolution': ConvolutionWrapper, + 'MultiDomainFunction': MultiDomainFunctionWrapper, + } + # constructor is FunctionWrapper if the name is not in the registry. + constructor = name_to_constructor.get(name, FunctionWrapper) + return constructor(name, *args, **kwargs) + + # ------------------------------------------------------------------------------------------------ + wrapper_function.__name__ = name + # _replace_signature(fake_function, ("", "")) + globals()[name] = wrapper_function + +fnames = FunctionFactory.getFunctionNames() +for i, val in enumerate(fnames): + _create_wrapper_function(val) diff --git a/Framework/PythonInterface/mantid/simpleapi.py b/Framework/PythonInterface/mantid/simpleapi.py index 0cb3001e546ac8b7713f61999572c192b561074d..b0ad72f4e3b81b3bf974789c99c9df08f531d83b 100644 --- a/Framework/PythonInterface/mantid/simpleapi.py +++ b/Framework/PythonInterface/mantid/simpleapi.py @@ -36,6 +36,7 @@ from .kernel.funcinspect import customise_func as _customise_func from . import apiVersion, __gui__ from .kernel._aliases import * from .api._aliases import * +from .fitfunctions import * # ------------------------ Specialized function calls -------------------------- # List of specialized algorithms @@ -314,6 +315,10 @@ def fitting_algorithm(f): if type(function) == str and function in _api.AnalysisDataService: raise ValueError("Fit API has changed. The function must now come " "first in the argument list and the workspace second.") + # Deal with case where function is a FunctionWrapper. + if isinstance(function,FunctionWrapper): + function = function.__str__() + # Create and execute algm = _create_algorithm_object(function_name) _set_logging_option(algm, kwargs) @@ -361,7 +366,8 @@ def Fit(*args, **kwargs): It can work with arbitrary data sources and therefore some options are only available when the function & workspace type are known. - This simple wrapper takes the Function (as a string) & the InputWorkspace + This simple wrapper takes the Function (as a string or a + FunctionWrapper object) and the InputWorkspace as the first two arguments. The remaining arguments must be specified by keyword. @@ -376,7 +382,7 @@ def Fit(*args, **kwargs): @fitting_algorithm def CalculateChiSquared(*args, **kwargs): """ - This function calculates chi squared claculation for a function and a data set. + This function calculates chi squared calculation for a function and a data set. The data set is defined in a way similar to Fit algorithm. Example: diff --git a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt index 438c607131f58d1f88c62b44c31ca312fc5f7a41..ebc2daab04df3cfc578a112dccbeac2e6e801e9b 100644 --- a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt +++ b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt @@ -13,6 +13,7 @@ set ( TEST_PY_FILES SimpleAPILoadTest.py SimpleAPIFitTest.py SimpleAPIRenameWorkspaceTest.py + FitFunctionsTest.py ) if ( MAKE_VATES ) diff --git a/Framework/PythonInterface/test/python/mantid/FitFunctionsTest.py b/Framework/PythonInterface/test/python/mantid/FitFunctionsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..6ad62bef89e76d01a3af6f5fe7120e9710533a6a --- /dev/null +++ b/Framework/PythonInterface/test/python/mantid/FitFunctionsTest.py @@ -0,0 +1,581 @@ +""" + Test of fitfunctions.py and related classes +""" +from __future__ import (absolute_import, division, print_function) + +import unittest +import testhelpers +import platform +from mantid.simpleapi import CreateWorkspace, EvaluateFunction, Fit, FitDialog +from mantid.simpleapi import FunctionWrapper, CompositeFunctionWrapper, ProductFunctionWrapper, ConvolutionWrapper, MultiDomainFunctionWrapper +from mantid.simpleapi import Gaussian, LinearBackground, Polynomial +from mantid.api import mtd, MatrixWorkspace, ITableWorkspace +import numpy as np +from testhelpers import run_algorithm + +class FitFunctionsTest(unittest.TestCase): + + _raw_ws = None + + def setUp(self): + pass + + def test_creation(self): + testhelpers.assertRaisesNothing(self, FunctionWrapper, "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + + def test_name(self): + g = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + self.assertEqual(g.name,"Gaussian") + + def test_read_array_elements(self): + g = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + self.assertAlmostEqual(g["Height"],7.5,10) + + def test_write_array_elements(self): + g = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g["Height"] = 8 + self.assertAlmostEqual(g["Height"],8,10) + + def test_dot_operator(self): + g = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + self.assertAlmostEqual(g.Height,7.5,10) + g.Height = 8 + self.assertAlmostEqual(g.Height,8,10) + + def test_compositefunction_creation(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + testhelpers.assertRaisesNothing(self, CompositeFunctionWrapper, g0, g1) + + def test_copy_on_compositefunction_creation(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper( g0, g1 ) + g0["Height"] = 10.0 + g1["Height"] = 11.0 + # Check that the composite function remains unmodified. + self.assertAlmostEqual( c["f0.Height"],7.5) + self.assertAlmostEqual( c["f1.Height"],8.5) + + def test_getindexoffunction_in_compositefunction(self): + lb = FunctionWrapper("LinearBackground", A0=0.5, A1=1.5) + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper( lb, g0, g1 ) + index_lb = c.getIndexOfFunction("LinearBackground") + self.assertEqual( index_lb, 0) + index_g0 = c.getIndexOfFunction("Gaussian 0") + self.assertEqual( index_g0, 1) + index_g1 = c.getIndexOfFunction("Gaussian 1") + self.assertEqual( index_g1, 2) + + def test_compositefunction_f (self): + lb = FunctionWrapper("LinearBackground", A0=0.5, A1=1.5) + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper( lb, g0, g1 ) + + lbx = c.f("LinearBackground") + lbx_str = str(lbx) + lb_str = str(lb) + self.assertEqual(lbx_str, lb_str) + + g1x = c.f("Gaussian 1") + g1x_str = str(g1x) + g1_str = str(g1) + self.assertEqual(g1x_str, g1_str) + + def test_compositefunction_read_array_elements(self): + lb = FunctionWrapper("LinearBackground", A0=0.5, A1=1.5) + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper( lb, g0, g1 ) + + self.assertAlmostEqual(c["f0.A1"], 1.5,10) + self.assertAlmostEqual(c["f1.Height"], 7.5,10) + self.assertAlmostEqual(c["f2.Height"], 8.5,10) + + self.assertAlmostEqual(c[0]["A1"], 1.5,10) + self.assertAlmostEqual(c[1]["Height"], 7.5,10) + self.assertAlmostEqual(c[2]["Height"], 8.5,10) + + def test_compositefunction_write_array_elements(self): + lb = FunctionWrapper("LinearBackground", A0=0.5, A1=1.5) + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper( lb, g0, g1 ) + + c["f0.A1"] = 0.0 + self.assertAlmostEqual(c["f0.A1"], 0.0,10) + c[0]["A1"] = 1.0 + self.assertAlmostEqual(c["f0.A1"], 1.0,10) + + c["f1.Height"] = 10.0 + self.assertAlmostEqual(c[1]["Height"], 10.0,10) + c[1]["Height"] = 11.0 + self.assertAlmostEqual(c[1]["Height"], 11.0,10) + + g0a = FunctionWrapper( "Gaussian", Height=7.0, Sigma=1.2, PeakCentre=9) + c[1] = g0a + self.assertAlmostEqual(c[1]["Height"], 7.0,10) + + def test_attributes(self): + testhelpers.assertRaisesNothing(self, FunctionWrapper, "Polynomial", attributes={'n': 3}, A0=4, A1=3, A2=2, A3=1) + testhelpers.assertRaisesNothing(self, FunctionWrapper, "Polynomial", n=3, A0=4, A1=3, A2=2, A3=1) + p = Polynomial(n=3, A0=1, A1=2, A2=4, A3=3) + self.assertEqual(p['n'],3) + p['n'] = 4 + self.assertEqual(p['n'],4) + + def test_fix(self): + g = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=15) + + g.fix("Sigma") + g_str = str(g) + self.assertEqual(g_str.count("ties="),1) + self.assertEqual(g_str.count("ties=(Sigma=1.2)"),1) + + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper(g0, g1) + + c.fix("f1.Sigma") + c_str = str(c) + self.assertEqual(c_str.count("ties="),1) + self.assertEqual(c_str.count("ties=(Sigma=1.2"),1) + + # remove non-existent tie and test it has no effect + c.untie("f1.Height") + cu_str = str(c) + self.assertEqual(c_str, cu_str) + + # remove actual tie + c.untie("f1.Sigma") + cz_str = str(c) + self.assertEqual(cz_str.count("ties="),0) + + def test_fix_all(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper(g0, g1) + + c.fixAll("Sigma") + c_str = str(c) + self.assertEqual(c_str.count("ties="),2) + self.assertEqual(c_str.count("ties=(Sigma="),2) + + # remove non-existent ties and test it has no effect + c.untieAll("Height") + cu_str = str(c) + self.assertEqual(c_str, cu_str) + + # remove actual ties + c.untieAll("Sigma") + cz_str = str(c) + self.assertEqual(cz_str.count("ties="),0) + + def test_fix_all_parameters(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + c = CompositeFunctionWrapper(g0, g1) + + c.fixAllParameters() + c_str = str(c) + self.assertEqual(c_str.count("ties="),2) + self.assertEqual(c_str.count("ties=(Height=7.5,PeakCentre=10,Sigma=1.2)"),2) + + c.untieAllParameters() + cz_str = str(c) + self.assertEqual(cz_str.count("ties="),0) + + + def test_tie(self): + g = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=15) + + g.tie(Sigma="0.1*Height") + g_str = str(g) + self.assertEqual(g_str.count("ties="),1) + self.assertEqual(g_str.count("ties=(Sigma=0.1*Height)"),1) + + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper(g0, g1) + + c.tie({"f1.Sigma":"f0.Sigma"}) + c_str = str(c) + self.assertEqual(c_str.count("ties="),1) + self.assertEqual(c_str.count("ties=(f1.Sigma=f0.Sigma)"),1) + + c.untie("f1.Sigma") + cz_str = str(c) + self.assertEqual(cz_str.count("ties="),0) + + def test_tie_all(self): + + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper(g0, g1) + + c.tieAll("Sigma") + c_str = str(c) + self.assertEqual(c_str.count("ties="),1) + self.assertEqual(c_str.count("ties=(f1.Sigma=f0.Sigma)"),1) + + c.untieAll("Sigma") + cz_str = str(c) + self.assertEqual(cz_str.count("ties="),0) + + def test_constrain(self): + g = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=15) + + g.constrain("Sigma < 2.0, Height > 7.0") + g_str = str(g) + self.assertEqual(g_str.count("constraints="),1) + self.assertEqual(g_str.count("Sigma<2"),1) + self.assertEqual(g_str.count("7<Height"),1) + + + g.unconstrain("Height") + g1_str = str(g) + self.assertEqual(g1_str.count("constraints="),1) + self.assertEqual(g1_str.count("constraints=(Sigma<2)"),1) + + g.unconstrain("Sigma") + gz_str = str(g) + self.assertEqual(gz_str.count("constraints="),0) + + def test_constrain_composite(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + c = CompositeFunctionWrapper(g0, g1) + + c.constrain("f1.Sigma < 2, f0.Height > 7") + c_str = str(c) + self.assertEqual(c_str.count("f1.Sigma<2"),1) + self.assertEqual(c_str.count("7<f0.Height"),1) + + c.unconstrain("f1.Sigma") + c.unconstrain("f0.Height") + cz_str = str(c) + self.assertEqual(cz_str.count("Constraints="),0) + + def test_constrainall(self): + lb = FunctionWrapper("LinearBackground", A0=0.5, A1=1.5) + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + g2 = FunctionWrapper( "Gaussian", Height=9.5, Sigma=1.2, PeakCentre=12) + c0 = CompositeFunctionWrapper( g1, g2 ) + c = CompositeFunctionWrapper( lb, g0, c0) + c.constrainAll("Sigma < 1.8") + + c_str = str(c) + self.assertEqual(c_str.count("constraints="),3) + self.assertEqual(c_str.count("Sigma<1.8"),3) + + lb_str = str(c[0]) + self.assertEqual(lb_str.count("constraints="),0) + + g0_str = str(c[1]) + self.assertEqual(g0_str.count("constraints="),1) + self.assertEqual(g0_str.count("Sigma<1.8"),1) + + g1_str = str(c[2][0]) + self.assertEqual(g1_str.count("constraints="),1) + self.assertEqual(g1_str.count("Sigma<1.8"),1) + + g2_str = str(c[2][1]) + self.assertEqual(g2_str.count("constraints="),1) + self.assertEqual(g2_str.count("Sigma<1.8"),1) + + c.unconstrainAll("Sigma") + + cz_str = str(c) + self.assertEqual(cz_str.count("constraints="),0) + + def test_free(self): + g = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=15) + + g.constrain("Sigma < 2.0, Height > 7.0") + g.tie({"PeakCentre":"2*Height"}) + + g.free("Height") + g1_str = str(g) + self.assertEqual(g1_str.count("ties="),1) + self.assertEqual(g1_str.count("constraints="),1) + self.assertEqual(g1_str.count("constraints=(Sigma<2)"),1) + + g.free("PeakCentre") + g2_str = str(g) + self.assertEqual(g2_str.count("ties="),0) + self.assertEqual(g2_str.count("constraints="),1) + + g.free("Sigma") + gz_str = str(g) + self.assertEqual(gz_str.count("constraints="),0) + + def test_pureaddition_and_puremultiplication(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + + sum = CompositeFunctionWrapper(g0, g1) + self.assertEqual(sum.pureAddition, True) + self.assertEqual(sum.pureMultiplication, False) + + product = ProductFunctionWrapper(g0, g1) + self.assertEqual(product.pureAddition, False) + self.assertEqual(product.pureMultiplication, True) + + sum2 = CompositeFunctionWrapper(sum, g1) + self.assertEqual(sum2.pureAddition, True) + self.assertEqual(sum2.pureMultiplication, False) + + product2 = ProductFunctionWrapper(product, g1) + self.assertEqual(product2.pureAddition, False) + self.assertEqual(product2.pureMultiplication, True) + + mixed1 = CompositeFunctionWrapper(product, g1) + self.assertEqual(mixed1.pureAddition, False) + self.assertEqual(mixed1.pureMultiplication, False) + + mixed2 = CompositeFunctionWrapper(g1, product) + self.assertEqual(mixed2.pureAddition, False) + self.assertEqual(mixed2.pureMultiplication, False) + + mixed3 = ProductFunctionWrapper(sum, g1) + self.assertEqual(mixed3.pureAddition, False) + self.assertEqual(mixed3.pureMultiplication, False) + + mixed4 = ProductFunctionWrapper(g1, sum) + self.assertEqual(mixed4.pureAddition, False) + self.assertEqual(mixed4.pureMultiplication, False) + + def test_flatten(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + g2 = FunctionWrapper( "Gaussian", Height=9.5, Sigma=1.3, PeakCentre=14) + l = FunctionWrapper("Lorentzian",PeakCentre=9, Amplitude=2.4, FWHM=3) + lb = FunctionWrapper("LinearBackground") + + # Test already flat composite function, no change should occur + c1 = CompositeFunctionWrapper(lb, g0, g1 ) + fc1 = c1.flatten() + c1_str = str(c1) + fc1_str = str(fc1) + self.assertEqual(fc1_str,c1_str) + + # Test composite function of depth 1 + c2 = CompositeFunctionWrapper(c1, l) + fc2 = c2.flatten() + fc2_str = str(fc2) + self.assertEqual(fc2_str.count("("),0) + self.assertEqual(fc2_str.count("PeakCentre"),3) + self.assertEqual(fc2_str.count("Sigma="),2) + self.assertEqual(fc2_str.count("Sigma=1.25"),1) + + # Test composite function of depth 2 + c3 = CompositeFunctionWrapper( g2, c2) + fc3 = c3.flatten() + fc3_str = str(fc3) + self.assertEqual(fc3_str.count("("),0) + self.assertEqual(fc3_str.count("PeakCentre"),4) + self.assertEqual(fc3_str.count("Sigma="),3) + self.assertEqual(fc3_str.count("Sigma=1.25"),1) + self.assertEqual(fc3_str.count("Sigma=1.3"),1) + + # Test product function of depth 1 + p1 = ProductFunctionWrapper(lb, g0, g1 ) + p2 = ProductFunctionWrapper(p1, l) + fp2 = p2.flatten() + self.assertTrue( isinstance (fp2, ProductFunctionWrapper)) + fp2_str = str(fp2) + self.assertEqual(fp2_str.count("("),0) + self.assertEqual(fp2_str.count("PeakCentre"),3) + self.assertEqual(fp2_str.count("Sigma="),2) + self.assertEqual(fp2_str.count("Sigma=1.25"),1) + + def test_add(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + c = lb + g0 + g1 + + self.assertTrue( isinstance( c, CompositeFunctionWrapper) ) + c_str = str(c) + # self.assertEqual(c_str.count("("),0) + self.assertEqual(c_str.count("LinearBackground"),1) + self.assertEqual(c_str.count("Gaussian"),2) + + #lb_str = str(lb) + #c0_str = str(c[0]) + #self.assertEqual(c0_str, lb_str) + + #g0_str = str(g0) + #c1_str = str(c[1]) + #self.assertEqual(c1_str, g0_str) + + #g1_str = str(g1) + #c2_str = str(c[2]) + #self.assertEqual(c2_str, g1_str) + + def test_incremental_add(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + c = CompositeFunctionWrapper( lb, g0) + c += g1 + c_str = str(c) + self.assertEqual(c_str.count("("),0) + self.assertEqual(c_str.count("LinearBackground"),1) + self.assertEqual(c_str.count("Gaussian"),2) + + lb_str = str(lb) + c0_str = str(c[0]) + self.assertEqual(c0_str, lb_str) + + g0_str = str(g0) + c1_str = str(c[1]) + self.assertEqual(c1_str, g0_str) + + g1_str = str(g1) + c2_str = str(c[2]) + self.assertEqual(c2_str, g1_str) + + def test_del(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + c = CompositeFunctionWrapper( lb, g0, g1) + del c[1] + + c_str = str(c) + self.assertEqual(c_str.count("("),0) + self.assertEqual(c_str.count("LinearBackground"),1) + self.assertEqual(c_str.count("Gaussian"),1) + self.assertEqual(c_str.count("Height=8.5"),1) + + def test_len(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + c = CompositeFunctionWrapper( lb, g0, g1) + self.assertEqual( len(c), 3) + + def test_iteration(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + c = CompositeFunctionWrapper( lb, g0, g1) + count = 0 + for f in c: + count += 1 + self.assertEqual( count, 3) + + def test_productfunction_creation(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + testhelpers.assertRaisesNothing(self, ProductFunctionWrapper, g0, g1) + + def test_mul(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.25, PeakCentre=12) + lb = FunctionWrapper("LinearBackground") + + p = lb * g0 * g1 + + self.assertTrue( isinstance( p, ProductFunctionWrapper) ) + p_str = str(p) + self.assertEqual(p_str.count("("),0) + self.assertEqual(p_str.count("LinearBackground"),1) + self.assertEqual(p_str.count("Gaussian"),2) + + lb_str = str(lb) + p0_str = str(p[0]) + self.assertEqual(p0_str, lb_str) + + g0_str = str(g0) + p1_str = str(p[1]) + self.assertEqual(p1_str, g0_str) + + g1_str = str(g1) + p2_str = str(p[2]) + self.assertEqual(p2_str, g1_str) + + def test_convolution_creation(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + testhelpers.assertRaisesNothing(self, ConvolutionWrapper, g0, g1) + + def test_multidomainfunction_creation(self): + g0 = FunctionWrapper( "Gaussian", Height=7.5, Sigma=1.2, PeakCentre=10) + g1 = FunctionWrapper( "Gaussian", Height=8.5, Sigma=1.2, PeakCentre=11) + testhelpers.assertRaisesNothing(self, MultiDomainFunctionWrapper, g0, g1) + m = MultiDomainFunctionWrapper( g0, g1, Global=["Height"]) + self.assertEqual( m.nDomains, 2) + m_str = str(m) + self.assertEqual( m_str.count("ties"),1) + self.assertEqual( m_str.count("Height"),4) # 2 in functions 2 in ties + + def test_generatedfunction(self): + testhelpers.assertRaisesNothing(self, Gaussian, Height=7.5, Sigma=1.2, PeakCentre=10) + lb = LinearBackground() + g = Gaussian(Height=7.5, Sigma=1.2, PeakCentre=10) + s = lb + g + self.assertTrue( isinstance( s, CompositeFunctionWrapper) ) + + def test_evaluation(self): + l0 = FunctionWrapper( "LinearBackground", A0=0, A1=2) + l1 = FunctionWrapper( "LinearBackground", A0=5, A1=-1) + + ws = CreateWorkspace(DataX=[0,1,2,3,4], DataY=[5,5,5,5]) + + c = CompositeFunctionWrapper(l0, l1) + cws = EvaluateFunction(c,"ws", OutputWorkspace='out') + cvals = cws.readY(1) + self.assertAlmostEqual(cvals[0], 5.5) + self.assertAlmostEqual(cvals[1], 6.5) + self.assertAlmostEqual(cvals[2], 7.5) + self.assertAlmostEqual(cvals[3], 8.5) + + p = ProductFunctionWrapper(l0, l1) + pws = EvaluateFunction(p,"ws", OutputWorkspace='out') + pvals = pws.readY(1) + self.assertAlmostEqual(pvals[0], 4.5) + self.assertAlmostEqual(pvals[1], 10.5) + self.assertAlmostEqual(pvals[2], 12.5) + self.assertAlmostEqual(pvals[3], 10.5) + + sq = Polynomial(attributes={'n': 2}, A0=0, A1=0.0, A2=1.0) + sqws = EvaluateFunction(sq,"ws", OutputWorkspace='out') + sqvals = sqws.readY(1) + self.assertAlmostEqual(sqvals[0], 0.25) + self.assertAlmostEqual(sqvals[1], 2.25) + self.assertAlmostEqual(sqvals[2], 6.25) + + def test_arithmetic(self): + l0 = FunctionWrapper( "LinearBackground", A0=0, A1=2) + l1 = FunctionWrapper( "LinearBackground", A0=5, A1=-1) + + ws = CreateWorkspace(DataX=[0,1], DataY=[5]) + + c = CompositeFunctionWrapper(l0, l1) + p = ProductFunctionWrapper(l0, l1) + + s1 = c + p + s1ws = EvaluateFunction(s1,"ws", OutputWorkspace='out') + s1vals = s1ws.readY(1) + self.assertAlmostEqual(s1vals[0], 10.0) + + s2 = p + c + s2ws = EvaluateFunction(s2,"ws", OutputWorkspace='out') + s2vals = s2ws.readY(1) + self.assertAlmostEqual(s2vals[0], 10.0) + + + +if __name__ == '__main__': + unittest.main() diff --git a/Framework/PythonInterface/test/python/mantid/SimpleAPIFitTest.py b/Framework/PythonInterface/test/python/mantid/SimpleAPIFitTest.py index 0972a92591a4c38bfa0666f4ae9c0194d614d9c6..2d604d2f71f2e3102826ec7bc038dd3779e3ea0d 100644 --- a/Framework/PythonInterface/test/python/mantid/SimpleAPIFitTest.py +++ b/Framework/PythonInterface/test/python/mantid/SimpleAPIFitTest.py @@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function) import unittest import testhelpers import platform -from mantid.simpleapi import CreateWorkspace, Fit, FitDialog +from mantid.simpleapi import CreateWorkspace, Fit, FitDialog, FunctionWrapper from mantid.api import mtd, MatrixWorkspace, ITableWorkspace import numpy as np from testhelpers import run_algorithm @@ -26,6 +26,12 @@ class SimpleAPIFitTest(unittest.TestCase): if platform.system() == 'Darwin': # crashes return testhelpers.assertRaisesNothing(self, Fit, "name=FlatBackground", self._raw_ws) + + def test_minimal_positional_arguments_with_functionwrapper_work(self): + if platform.system() == 'Darwin': # crashes + return + fb = FunctionWrapper("FlatBackground") + testhelpers.assertRaisesNothing(self, Fit, fb, self._raw_ws) def test_function_positional_and_workspace_keyword_arguments_work(self): if platform.system() == 'Darwin': # crashes diff --git a/Framework/SINQ/src/PoldiPeakSearch.cpp b/Framework/SINQ/src/PoldiPeakSearch.cpp index f6091db34bbda36f2cffc36a54bbcce16d7fb2ca..2b502b516b603112695686036ad0ccf2fc074b6f 100644 --- a/Framework/SINQ/src/PoldiPeakSearch.cpp +++ b/Framework/SINQ/src/PoldiPeakSearch.cpp @@ -564,7 +564,7 @@ void PoldiPeakSearch::exec() { Unit_sptr xUnit = correlationWorkspace->getAxis(0)->unit(); - if (xUnit->caption() == "") { + if (xUnit->caption().empty()) { g_log.information() << " Workspace does not have unit, defaulting to MomentumTransfer.\n"; diff --git a/Framework/TestHelpers/src/FileComparisonHelper.cpp b/Framework/TestHelpers/src/FileComparisonHelper.cpp index 5da64ccbeec582d9a8877421d18e9b54c03481c2..ccf783e80f24838877556223c3d75f81d45e8f30 100644 --- a/Framework/TestHelpers/src/FileComparisonHelper.cpp +++ b/Framework/TestHelpers/src/FileComparisonHelper.cpp @@ -112,7 +112,7 @@ bool areIteratorsEqual(streamCharIter refStream, streamCharIter testStream, Mantid::Kernel::Logger g_log("FileComparisonHelper"); g_log.error("Length of both files were not identical"); areStreamsEqual = false; - } else if (numNewLines == 0 && seenChars.size() == 0) { + } else if (numNewLines == 0 && seenChars.empty()) { Mantid::Kernel::Logger g_log("FileComparisonHelper"); g_log.error("No characters checked in FileComparisonHelper"); areStreamsEqual = false; @@ -190,7 +190,7 @@ bool isEqualToReferenceFile(const std::string &referenceFileName, const std::string referenceFilePath = Mantid::API::FileFinder::Instance().getFullPath(referenceFileName); - if (referenceFilePath == "") { + if (referenceFilePath.empty()) { throw std::invalid_argument("No reference file with the name: " + referenceFileName + " could be found by FileComparisonHelper"); diff --git a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp index c5536b678ce7ba80ca84eae5e8d21f99c5ce6294..ca1966529fef5d90e05ca6d0897d5e8365f43bbb 100644 --- a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp +++ b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp @@ -579,24 +579,44 @@ void EQSANSLoad::exec() { throw std::runtime_error("Could not cast (interpret) the property " + dzName + " as a time series property value."); sfdd = dp->getStatistics().mean; - s2d = sfdd; // Modify SDD according to the DetectorDistance offset if given const double sampleflange_det_offset = getProperty("DetectorOffset"); if (!isEmpty(sampleflange_det_offset)) sfdd += sampleflange_det_offset; - // Modify S2D according to the SampleDistance offset if given - // This assumes that a positive offset moves the sample toward the detector - const double sampleflange_sample_offset = getProperty("SampleOffset"); - if (!isEmpty(sampleflange_sample_offset)) - s2d = s2d - sampleflange_sample_offset + sampleflange_det_offset; - - // Modify SDD according to SampleDetectorDistanceOffset offset if given + // Modify SDD according to SampleDetectorDistanceOffset offset if given. + // This is here for backward compatibility. const double sample_det_offset = getProperty("SampleDetectorDistanceOffset"); if (!isEmpty(sample_det_offset)) - s2d += sample_det_offset; + sfdd += sample_det_offset; + if (!isEmpty(sample_det_offset) && !isEmpty(sampleflange_det_offset)) + g_log.error() << "Both DetectorOffset and SampleDetectorDistanceOffset " + "are set. Only one should be used.\n"; + + s2d = sfdd; + // Modify S2D according to the SampleDistance offset if given + // This assumes that a positive offset moves the sample toward the detector + const double sampleflange_sample_offset = getProperty("SampleOffset"); + if (!isEmpty(sampleflange_sample_offset)) { + s2d -= sampleflange_sample_offset; + + // Move the sample to its correct position + IAlgorithm_sptr mvAlg = + createChildAlgorithm("MoveInstrumentComponent", 0.2, 0.4); + mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS); + mvAlg->setProperty("ComponentName", "sample-position"); + mvAlg->setProperty("Z", sampleflange_sample_offset / 1000.0); + mvAlg->setProperty("RelativePosition", false); + mvAlg->executeAsChildAlg(); + g_log.information() << "Moving sample to " + << sampleflange_sample_offset / 1000.0 << " meters\n"; + m_output_message += " Sample position: " + + Poco::NumberFormatter::format( + sampleflange_sample_offset / 1000.0, 3) + + " m\n"; + } } dataWS->mutableRun().addProperty("sampleflange_detector_distance", sfdd, "mm", true); @@ -812,7 +832,6 @@ void EQSANSLoad::exec() { getPropertyValue("OutputWorkspace"), true); setProperty<MatrixWorkspace_sptr>( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS)); - // m_output_message = "Loaded " + fileName + '\n' + m_output_message; setPropertyValue("OutputMessage", m_output_message); } diff --git a/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py b/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py index 51971cb36097c9111a61cadc9a91c40848e79b0b..3adc980142a5e1b65dd653d5599f40b916ab4b57 100644 --- a/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py +++ b/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py @@ -1,6 +1,7 @@ #pylint: disable=no-init import stresstesting from mantid.simpleapi import * +from six import PY2 def rel_err_less_delta(val, ref, epsilon): @@ -234,7 +235,8 @@ class EnginXCalibrateFullThenCalibrateTest(stresstesting.MantidStressTest): for idx in [0, 12, 516, 789, 891, 1112]: cell_val = self.peaks_info.cell(idx,1) self.assertTrue(isinstance(cell_val, str)) - self.assertEquals(cell_val[0:11], '{"1": {"A":') + if PY2: # This test depends on consistent ordering of a dict which is not guaranteed for python 3 + self.assertEquals(cell_val[0:11], '{"1": {"A":') self.assertEquals(cell_val[-2:], '}}') self.assertEquals(self.difa, 0) diff --git a/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py b/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py index e9faa5b9a02dc3d199b3c7fc5f69fd29a572301d..542abbf0f7add7821efb4f9802f403983405d37a 100644 --- a/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py +++ b/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py @@ -106,7 +106,8 @@ BANNED_FILES = ['80_tubes_Top_and_Bottom_April_2015.xml', 'TolueneLargerOrderAbins.out', 'TolueneScale.out', 'TolueneScratchAbins.out', - 'SingleCrystalDiffuseReduction_UB.mat' + 'SingleCrystalDiffuseReduction_UB.mat', + 'Na2SiF6_DMOL3.outmol' ] EXPECTED_EXT = '.expected' diff --git a/docs/source/algorithms/AbsorptionCorrection-v1.rst b/docs/source/algorithms/AbsorptionCorrection-v1.rst index 471c597be764b4007cc817d67d41e605c2371cc5..8a79dfef66b416f82e30cc1a3fd39f3b31f784fe 100644 --- a/docs/source/algorithms/AbsorptionCorrection-v1.rst +++ b/docs/source/algorithms/AbsorptionCorrection-v1.rst @@ -21,6 +21,9 @@ calculated for the centre-point of each element, and a numerical integration is carried out using these path lengths over the volume elements. +The output workspace will contain the attenuation factors. To apply +the correction you must divide your data set by the resulting factors. + Note that the duration of this algorithm is strongly dependent on the element size chosen, and that too small an element size can cause the algorithm to fail because of insufficient memory. @@ -75,12 +78,12 @@ Usage **Example: A simple spherical sample** .. testcode:: ExSimpleSpere - + #setup the sample shape sphere = '''<sphere id="sample-sphere"> - <centre x="0" y="0" z="0"/> - <radius val="0.1" /> - </sphere>''' + <centre x="0" y="0" z="0"/> + <radius val="0.1" /> + </sphere>''' ws = CreateSampleWorkspace("Histogram",NumBanks=1,BankPixelWidth=1) ws = ConvertUnits(ws,"Wavelength") @@ -90,14 +93,21 @@ Usage #restrict the number of wavelength points to speed up the example wsOut = AbsorptionCorrection(ws, NumberOfWavelengthPoints=5, ElementSize=3) + wsCorrected = ws / wsOut print "The created workspace has one entry for each spectra: %i" % wsOut.getNumberHistograms() + print "Original y values: ", ws.readY(0) + print "Corrected y values: ", wsCorrected.readY(0) Output: .. testoutput:: ExSimpleSpere The created workspace has one entry for each spectra: 1 + Original y values: [ 5.68751434 5.68751434 15.68751434 5.68751434 5.68751434 + 1.56242829] + Corrected y values: [ 818.30188422 2375.96165593 14211.52238463 9472.21381511 + 15718.79220638 5747.16759791] .. categories:: diff --git a/docs/source/concepts/FitFunctionsInPython.rst b/docs/source/concepts/FitFunctionsInPython.rst new file mode 100644 index 0000000000000000000000000000000000000000..eec35460f982004de9106f39ebf4c06fd142f504 --- /dev/null +++ b/docs/source/concepts/FitFunctionsInPython.rst @@ -0,0 +1,170 @@ +.. _FitFunctionsInPython: + +Fit Functions In Python +======================= + +Introduction +------------ + +Mantid enables Fit function objects to be produced in python. For example + +.. code:: python + + g = Gaussian() + +will make ``g`` into a Gaussian function with default values and + +.. code:: python + + g = Gaussian(Height=1, Sigma=0.1) + +will make ``g`` into a Gaussian function with ``Height`` set to 1, ``Sigma`` set to 0.1 and ``PeakCentre`` set to default value. + +One can also make function with attributes such as + +.. code:: python + + p = Polynomial(n=3, A0=1, A1=2, A2=4, A3=3) + +One can get and set function parameters and attributes, by array operations, for example: + +.. code:: python + + gSigma = g["Sigma"] + g["Height"] = 1.5 + +One can also get and set function parameters and attributes, by dot operations, for example: + +.. code:: python + + gSigma = g.Sigma + g.Height = 1.5 + +Composite Functions +------------------- +Composite functions can be created by means of the plus operation and +individual functions can be accessed by array index operations. +For example: + +.. code:: python + + spectrum = LinearBackground() + Gaussian(PeakCentre=1) + Gaussian(PeakCentre=2) + peak1 = spectrum[1] + peak1['Sigma'] = 0.123 + spectrum[2] = Lorentzian(PeakCentre=2) + +which sets ``Sigma`` of the second function (first Gaussian) to 0.123 and changes the third function to a Lorentzian. + +Similarly product functions can be constructed using the multiplication operator. + +.. code:: python + + p = ExpDecay() * Gaussian(Height=1,Sigma=0.2) + +One can get and set the parameters of a composite function, by array operations, +but not by dot operations because the parameter name already contains a dot, for example: + +.. code:: python + + f1Sigma = spectrum["f1.Sigma"] + spectrum["f1.Height"] = 1.5 + +One can add a function by the ``+-`` operator or remove be the ``del`` function. + +.. code:: python + + spectrum += Lorentzian(PeakCentre=3) + del spectrum[1] + +Also available is the ``len`` function and iteration over the member functions: + +.. code:: python + + n_peaks = len(spectrum) + for func in spectrum: + print(func) + +The plus and times operators are associative and +so may not preserve a composite function within a composite function as such, +but replace it with a list of its member functions. +Instead you may use: + +.. code:: python + + spectrum = CompositeFunctionWrapper(LinearBackground(), Gaussian(PeakCentre=1), Gaussian(PeakCentre=2)) + P = ProductFunctionWrapper(ExpDecay(), Gaussian(Height=1,Sigma=0.2)) + +Multi-Domain Functions +---------------------- +Multi-Domain functions can be constructed like this: + +.. code:: python + + md_fun = MultiDomainFunction(Gaussian(PeakCentre=1, Sigma=0.1), Gaussian(PeakCentre=1, Sigma=0.2), ..., global=['Height']) + +Setting Ties +------------ +The parameters of functions can be tied or fixed like this: + +.. code:: python + + func1.tie(A0=2.0) + func2.tie({'f1.A2': '2*f0.A1', 'f2.A2': '3*f0.A1 + 1'}) + func3.fix('A0') + func4.fix('f2.A2') + +Both fixes and ties can be removed by ``untie``: + +.. code:: python + + func.untie('f3.Sigma') + +To tie all parameters of the same local name in a composite function, one can use ``TieAll``: + +.. code:: python + + func.tieAll('Sigma') + +All members of the composite function must have this parameter (in this case ``Sigma``). +Similarly with fixing: + +.. code:: python + + spectrum1.fixAll('FWHM') + +Also parameters of a function can be fixed with ``fixAllParameters`` and unfixed with ``untieAllParameters``. + +.. code:: python + + c.fixAllParameters() + ... + c.untieAllParameters() + + +Setting Constraints +------------------- +One can set and remove constraints as follows: + +.. code:: python + + g.constrain("Sigma < 2.0, Height > 7.0") + ... + g.unconstrain("Sigma") + g.unconstrain("Height") + + comp.constrain("f1.Sigma < 2, f0.Height > 7") + ... + comp.unconstrain("f1.Sigma") + comp.unconstrain("f0.Height") + +One can all constrain a given parameter in all members of a composite function that have this parameter +and also remove such constraints. + +.. code:: python + + comp.constrainAll("Sigma < 1.8") + ... + comp.unconstrainAll("Sigma") + + +.. categories:: Concepts diff --git a/docs/source/release/v3.11.0/diffraction.rst b/docs/source/release/v3.11.0/diffraction.rst index 3bd30339ef17998c433e9410ed1cb45a874d428f..88951c92c9d55378872e66dc3591b6cc701da4b1 100644 --- a/docs/source/release/v3.11.0/diffraction.rst +++ b/docs/source/release/v3.11.0/diffraction.rst @@ -22,9 +22,9 @@ Powder Diffraction - :ref:`LoadILLDiffraction <algm-LoadILLDiffraction>` now supports loading D2B data with detector scans. The D2B IDF has been updated, as previously it contained some errors in the positions of the tubes and size of the pixels. - :ref:`AlignAndFocusPowder <algm-AlignAndFocusPowder>` now correctly supports overloading the grouping file in the presence of a masking workspace. - :ref:`PDCalibration <algm-PDCalibration>` has changed how it calculates constants from peak positions to use a simplex optimization rather than Gauss-Markov method. +- :ref:`ResampleX <algm-ResampleX>` has a bug fix in how it automatically determines the data range for a workspace with multiple spectra. - The powder diffraction GUI has had numerous bugfixes and now has an option to override the detector grouping. - Single Crystal Diffraction -------------------------- diff --git a/docs/source/release/v3.11.0/framework.rst b/docs/source/release/v3.11.0/framework.rst index e96671623b79fee6443565aa58e533af8d4ff521..5b5b641c1302b93fc41240c6321781e5d9ca1359 100644 --- a/docs/source/release/v3.11.0/framework.rst +++ b/docs/source/release/v3.11.0/framework.rst @@ -104,6 +104,8 @@ Python Fit Functions #################### - A bug that makes it difficult to define and use attributes in python fit functions has been fixed. +- The usability of the fit functions has been improved, enabling users to construct and modify the functions as objects rather than strings + as described :ref:`here <FitFunctionsInPython>`. | diff --git a/docs/source/release/v3.11.0/indirect_inelastic.rst b/docs/source/release/v3.11.0/indirect_inelastic.rst index f6f3e78edca36c84cc18434bb91035d9b2a91f42..1ee658911c81ea36176ed4da1417b2ddd583eabd 100644 --- a/docs/source/release/v3.11.0/indirect_inelastic.rst +++ b/docs/source/release/v3.11.0/indirect_inelastic.rst @@ -38,6 +38,21 @@ Bugfixes - Correct treatment of the resolution function: convolve sample and resolution spectra with same momentum transfer. - Property to pass the workspace index added to :ref:`algm-ConvolutionFitSequential`. +Elwin +~~~~~ + +Bugfixes +-------- +- Save Result now writes to file the temperature-dependent elastic intensity normalized to the lowest temperature. + +ConvFit +~~~~~~~ + +Bugfixes +-------- +- Correct treatment of the resolution function: convolve sample and resolution spectra with same momentum transfer. +- Property to pass the workspace index added to :ref:`algm-ConvolutionFitSequential`. + Jump Fit ~~~~~~~~ diff --git a/docs/source/release/v3.11.0/reflectometry.rst b/docs/source/release/v3.11.0/reflectometry.rst index 709724662d82a02a4c0ec5b541ecb9df2a852a49..57ba862cb5cf3cdd8e5653f7a02701f249274a0d 100644 --- a/docs/source/release/v3.11.0/reflectometry.rst +++ b/docs/source/release/v3.11.0/reflectometry.rst @@ -11,6 +11,7 @@ Algorithms - The following bugs have been fixed in the summation in Q functionality in :ref:`algm-ReflectometryReductionOne`: - the incorrect angle was being used in the final conversion to Q in the divergent beam case - the input was being cropped, causing loss of counts + - summation in Q was giving incorrect results for a point detector - A new property, ``Diagnostics``, has been added to :ref:`algm-ReflectometryReductionOne` to allow the output of additional interim workspaces for debug purposes. Reflectometry Reduction Interface diff --git a/docs/source/release/v3.11.0/sans.rst b/docs/source/release/v3.11.0/sans.rst index cdcd6e4947a919860b66b08a427bca65a05aaafd..8b75217d5b181bbfae9442a2004f7e52485d5a15 100644 --- a/docs/source/release/v3.11.0/sans.rst +++ b/docs/source/release/v3.11.0/sans.rst @@ -16,6 +16,9 @@ Bug Fixes - Displaying the masked workspace in the mask tab now makes sure that the masks are displayed in a grey color. -| +EQSANS +------ + +- Following hardware changes in the instrument, sample and detector offsets were added as parameters of the reduction. `Full list of changes on github <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.11%22+is%3Amerged+label%3A%22Component%3A+SANS%22>`__ diff --git a/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx index 703d923eb41335d1a6186c91f2352388cdbf7182..ef1b8714bffbed5105fe993e3aca4b218a501481 100644 --- a/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx +++ b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx @@ -18,7 +18,7 @@ #include "vtkAppendPolyData.h" #include "vtkPlane.h" -#include <math.h> +#include <cmath> vtkStandardNewMacro(AlignedThreeSliceFilter); diff --git a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx index 5edce31a5ca28f8bd51dd5e665328918a6ae98b2..f7230cb6108e7c2ed40086ca3adf9b895b1c9ec6 100644 --- a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx +++ b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx @@ -85,7 +85,7 @@ public: return true; } static bool ExtractCachedBounds(vtkDataObject *dataObject, double bounds[6]) { - if (dataObject == NULL || dataObject->GetFieldData() == NULL) { + if (dataObject == nullptr || dataObject->GetFieldData() == nullptr) { return false; } vtkFieldData *fd = dataObject->GetFieldData(); @@ -108,9 +108,8 @@ public: static vtkGSRGeometryFilter *New(); vtkTypeMacro(vtkGSRGeometryFilter, vtkPVGeometryFilter); - virtual int RequestData(vtkInformation *req, - vtkInformationVector **inputVector, - vtkInformationVector *outputVector) VTK_OVERRIDE { + int RequestData(vtkInformation *req, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) VTK_OVERRIDE { vtkSmartPointer<vtkDataObject> inputDO = vtkDataObject::GetData(inputVector[0]); vtkSmartPointer<vtkMatrix4x4> changeOfBasisMatrix = @@ -165,7 +164,7 @@ public: protected: vtkGSRGeometryFilter() {} - virtual ~vtkGSRGeometryFilter() {} + ~vtkGSRGeometryFilter() override {} private: vtkGSRGeometryFilter(const vtkGSRGeometryFilter &); @@ -214,7 +213,7 @@ void vtkAlignedGeometrySliceRepresentation::SetupDefaults() { this->Internals->OutlineSource->GetOutputPort()); this->Internals->OutlineActor->SetMapper( this->Internals->OutlineMapper.GetPointer()); - this->Internals->OutlineActor->SetUseBounds(0); + this->Internals->OutlineActor->SetUseBounds(false); this->Internals->OutlineActor->SetVisibility(0); } diff --git a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h index 1e24e767c3bd85c30b843c992bfb12c348d4e559..9bfad8b3434ab0b91ab862237de9435cfb4765f2 100644 --- a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h +++ b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h @@ -35,9 +35,9 @@ public: vtkGeometryRepresentation); void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE; - virtual int ProcessViewRequest(vtkInformationRequestKey *request_type, - vtkInformation *inInfo, - vtkInformation *outInfo) VTK_OVERRIDE; + int ProcessViewRequest(vtkInformationRequestKey *request_type, + vtkInformation *inInfo, + vtkInformation *outInfo) VTK_OVERRIDE; enum { X_SLICE_ONLY, Y_SLICE_ONLY, Z_SLICE_ONLY, ALL_SLICES }; vtkSetClampMacro(Mode, int, X_SLICE_ONLY, ALL_SLICES); @@ -53,15 +53,14 @@ public: protected: vtkAlignedGeometrySliceRepresentation(); - ~vtkAlignedGeometrySliceRepresentation(); + ~vtkAlignedGeometrySliceRepresentation() override; - virtual void SetupDefaults() VTK_OVERRIDE; - virtual int RequestData(vtkInformation *request, - vtkInformationVector **inputVector, - vtkInformationVector *outputVector) VTK_OVERRIDE; + void SetupDefaults() VTK_OVERRIDE; + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) VTK_OVERRIDE; - virtual bool AddToView(vtkView *view) VTK_OVERRIDE; - virtual bool RemoveFromView(vtkView *view) VTK_OVERRIDE; + bool AddToView(vtkView *view) VTK_OVERRIDE; + bool RemoveFromView(vtkView *view) VTK_OVERRIDE; private: vtkAlignedGeometrySliceRepresentation( diff --git a/qt/paraview_ext/VatesAPI/src/EventNexusLoadingPresenter.cpp b/qt/paraview_ext/VatesAPI/src/EventNexusLoadingPresenter.cpp index 72f9f932108be9198b967126a34b4757b1d3aa21..301e885bcd6d0fed8a3ddfa8f77a8a91eb3ccf92 100644 --- a/qt/paraview_ext/VatesAPI/src/EventNexusLoadingPresenter.cpp +++ b/qt/paraview_ext/VatesAPI/src/EventNexusLoadingPresenter.cpp @@ -44,7 +44,7 @@ EventNexusLoadingPresenter::EventNexusLoadingPresenter( */ bool EventNexusLoadingPresenter::canReadFile() const { if (!canLoadFileBasedOnExtension(m_filename, ".nxs")) { - return 0; + return false; } std::unique_ptr<NeXus::File> file; @@ -55,7 +55,7 @@ bool EventNexusLoadingPresenter::canReadFile() const { file->openGroup("entry", "NXentry"); } catch (::NeXus::Exception &) { file->close(); - return 0; + return false; } // But only eventNexus files have bank123_events as a group name std::map<std::string, std::string> entries = file->getEntries(); @@ -74,7 +74,7 @@ bool EventNexusLoadingPresenter::canReadFile() const { if (file) file->close(); } - return 0; + return false; } /* diff --git a/qt/paraview_ext/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp b/qt/paraview_ext/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp index 81cc8b7afd0a2764e51dec715f01108be679c5ea..02d1db6ebf552f3778e264aca8b201e7429a107d 100644 --- a/qt/paraview_ext/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp +++ b/qt/paraview_ext/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp @@ -43,19 +43,19 @@ is attempted to be loaded. bool MDEWEventNexusLoadingPresenter::canReadFile() const { // Quick check based on extension. if (!canLoadFileBasedOnExtension(m_filename, ".nxs")) { - return 0; + return false; } auto file = Kernel::make_unique<::NeXus::File>(this->m_filename); // MDEventWorkspace file has a different name for the entry try { file->openGroup("MDEventWorkspace", "NXentry"); - return 1; + return true; } catch (::NeXus::Exception &) { // If the entry name does not match, then it can't read the file. - return 0; + return false; } - return 0; + return false; } /* diff --git a/qt/paraview_ext/VatesAPI/src/MDHWNexusLoadingPresenter.cpp b/qt/paraview_ext/VatesAPI/src/MDHWNexusLoadingPresenter.cpp index e8654c3c990a163327961a2d90c1ba6170b48bfa..92eaa9ad25f37c84016930f9d38dceac933a4f5e 100644 --- a/qt/paraview_ext/VatesAPI/src/MDHWNexusLoadingPresenter.cpp +++ b/qt/paraview_ext/VatesAPI/src/MDHWNexusLoadingPresenter.cpp @@ -43,18 +43,18 @@ MDHWNexusLoadingPresenter::MDHWNexusLoadingPresenter( bool MDHWNexusLoadingPresenter::canReadFile() const { // Quick check based on extension. if (!canLoadFileBasedOnExtension(m_filename, ".nxs")) { - return 0; + return false; } auto file = Kernel::make_unique<::NeXus::File>(this->m_filename); // MDHistoWorkspace file has a different name for the entry try { file->openGroup("MDHistoWorkspace", "NXentry"); - return 1; + return true; } catch (::NeXus::Exception &) { // If the entry name does not match, then it can't read the file. - return 0; + return false; } - return 0; + return false; } /** diff --git a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraReactionNonOrthogonalAxes.cpp b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraReactionNonOrthogonalAxes.cpp index 75b67ee37970f2714b40fca42a7e3e9bb41fe101..bf37322877cfa255ab623cbd0e0521b1f17d7ac0 100644 --- a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraReactionNonOrthogonalAxes.cpp +++ b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraReactionNonOrthogonalAxes.cpp @@ -93,7 +93,7 @@ void pqCameraReactionNonOrthogonalAxes::updateEnableState() { this->parentAction()->setEnabled(true); } else if (rview) { if (this->ReactionMode == ZOOM_TO_DATA) { - this->parentAction()->setEnabled(source != 0); + this->parentAction()->setEnabled(source != nullptr); } else { // Check hints to see if actions should be disabled bool cameraResetButtonsEnabled = true; diff --git a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraToolbarNonOrthogonalAxes.cpp b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraToolbarNonOrthogonalAxes.cpp index 1b9410c7dffefc0e3974689cbfe763d803092a61..9482ec1aa71da8e20962e34b1ae989c0bf39f188 100644 --- a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraToolbarNonOrthogonalAxes.cpp +++ b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/pqCameraToolbarNonOrthogonalAxes.cpp @@ -68,7 +68,7 @@ void pqCameraToolbarNonOrthogonalAxes::constructor() { this->ZoomToDataAction = ui.actionZoomToData; this->ZoomToDataAction->setEnabled( - pqActiveObjects::instance().activeSource() != 0); + pqActiveObjects::instance().activeSource() != nullptr); QObject::connect(&pqActiveObjects::instance(), SIGNAL(viewChanged(pqView *)), this, SLOT(updateEnabledState())); diff --git a/scripts/Inelastic/CrystalField/CrystalFieldMultiSite.py b/scripts/Inelastic/CrystalField/CrystalFieldMultiSite.py index ff4d2aeb490a8aa6c8c1d5b0ef411594144d11b4..bf457812eed90c70c091832db4025344a1d9eb4f 100644 --- a/scripts/Inelastic/CrystalField/CrystalFieldMultiSite.py +++ b/scripts/Inelastic/CrystalField/CrystalFieldMultiSite.py @@ -28,6 +28,8 @@ class CrystalFieldMultiSite(object): self._makeFunction(Ions, Symmetries) self.Ions = Ions self.Symmetries = Symmetries + self._plot_window = {} + self.chi2 = None parameter_dict = None attribute_dict = None @@ -166,18 +168,55 @@ class CrystalFieldMultiSite(object): """Form a definition string for the CrystalFieldSpectrum function @param i: Index of a spectrum. """ - funs = self.function.createEquivalentFunctions() - return str(funs[i]) + if self.NumberOfSpectra == 1: + return str(self.function) + else: + funs = self.function.createEquivalentFunctions() + return str(funs[i]) def update(self, func): """ Update values of the fitting parameters. @param func: A IFunction object containing new parameter values. """ - if self.NumberOfSpectra == 1: - return str(self.function) + self.function = func + + def plot(self, i=0, workspace=None, ws_index=0, name=None): + """Plot a spectrum. Parameters are the same as in getSpectrum(...)""" + from mantidplot import plotSpectrum + from mantid.api import AlgorithmManager + createWS = AlgorithmManager.createUnmanaged('CreateWorkspace') + createWS.initialize() + + xArray, yArray = self.getSpectrum(i, workspace, ws_index) + ws_name = name if name is not None else 'CrystalFieldMultiSite_%s' % self.Ions + + if isinstance(i, int): + if workspace is None: + if i > 0: + ws_name += '_%s' % i + createWS.setProperty('DataX', xArray) + createWS.setProperty('DataY', yArray) + createWS.setProperty('OutputWorkspace', ws_name) + createWS.execute() + plot_window = self._plot_window[i] if i in self._plot_window else None + self._plot_window[i] = plotSpectrum(ws_name, 0, window=plot_window, clearWindow=True) + else: + ws_name += '_%s' % workspace + if i > 0: + ws_name += '_%s' % i + createWS.setProperty('DataX', xArray) + createWS.setProperty('DataY', yArray) + createWS.setProperty('OutputWorkspace', ws_name) + createWS.execute() + plotSpectrum(ws_name, 0) else: - self.function = func + ws_name += '_%s' % i + createWS.setProperty('DataX', xArray) + createWS.setProperty('DataY', yArray) + createWS.setProperty('OutputWorkspace', ws_name) + createWS.execute() + plotSpectrum(ws_name, 0) @property def Ions(self): @@ -284,3 +323,39 @@ class CrystalFieldMultiSite(object): def NPeaks(self, value): self.function.setAttributeValue('NPeaks', value) + def fix(self, *args): + for a in args: + self.function.fixParameter(a) + + def __getitem__(self, item): + if self.function.hasAttribute(item): + return self.function.getAttributeValue(item) + else: + return self.function.getParameterValue(item) + + + def setBackground(self, *args, peak=None, other=None): + + if len(args) > 0: + bg = FunctionFactory.createFunction(args[0]) + if isComposite(bg): + f0 = bg[0] + if isPeak(f0): + peak = f0 + return + + self._background = Function(self.function, prefix='bg.') + if peak and other: + self._background.peak = Function(self.function, prefix='bg.f0.') + self._background.background = Function(self.function, prefix='bg.f1.') + self.function.setAttributeValue('Background', '%s;%s' % (peak, other)) + elif peak: + self.function.setAttributeValue('Background', '%s' % peak) + elif other: + self.function.setAttributeValue('Background', '%s' % other) + else: + raise RuntimeError('!!!') + + @property + def background(self): + return self._background \ No newline at end of file diff --git a/scripts/Inelastic/CrystalField/fitting.py b/scripts/Inelastic/CrystalField/fitting.py index 89262a88cbaa81da0a11df8113ca2b03f9c66d4e..dfb66e9828ee70311fce61612239e67bfdce5ae9 100644 --- a/scripts/Inelastic/CrystalField/fitting.py +++ b/scripts/Inelastic/CrystalField/fitting.py @@ -1443,7 +1443,11 @@ class CrystalFieldFit(object): Fit when the model has multiple spectra. """ from mantid.api import AlgorithmManager - fun = self.model.makeMultiSpectrumFunction() + from CrystalField.CrystalFieldMultiSite import CrystalFieldMultiSite + if isinstance(self.model, CrystalFieldMultiSite): + fun = str(self.model.function) + else: + fun = self.model.makeMultiSpectrumFunction() if 'CrystalFieldMultiSpectrum' in fun: fun = re.sub(r'(name=.*?,)(.*?)(PhysicalProperties=\(.*?\),)',r'\1\3\2', fun) alg = AlgorithmManager.createUnmanaged('Fit') diff --git a/scripts/reduction_workflow/instruments/sans/sns_command_interface.py b/scripts/reduction_workflow/instruments/sans/sns_command_interface.py index 5af57ec224172740e5d2d05781241ba7f22123b1..8c8ba289f485695cc12f9ae6adec877430fc7f90 100644 --- a/scripts/reduction_workflow/instruments/sans/sns_command_interface.py +++ b/scripts/reduction_workflow/instruments/sans/sns_command_interface.py @@ -125,3 +125,11 @@ def Resolution(sample_aperture_diameter=10.0): def IndependentBinning(independent_binning=True): ReductionSingleton().reduction_properties["IQIndependentBinning"]=independent_binning + + +def SetDetectorOffset(distance): + ReductionSingleton().reduction_properties["DetectorOffset"] = distance + + +def SetSampleOffset(distance): + ReductionSingleton().reduction_properties["SampleOffset"] = distance diff --git a/scripts/test/CrystalFieldMultiSiteTest.py b/scripts/test/CrystalFieldMultiSiteTest.py index 6be9d3ff2a9ea446cb6434ce8d44c041ed73533f..cffc8c7de5426bea3e638aad728a9ada7ee62557 100644 --- a/scripts/test/CrystalFieldMultiSiteTest.py +++ b/scripts/test/CrystalFieldMultiSiteTest.py @@ -13,7 +13,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertEqual(cfms.Temperatures, [20, 52]) self.assertEqual(cfms.FWHMs, [1.0, 1.0]) - def test_init_multiple_ions(self): + def test_init_multi_ions(self): cfms = CrystalFieldMultiSite(Ions=('Pm', 'Eu'), Symmetries=('D2', 'C3v'), Temperatures=[20, 52], FWHMs=[1.0, 1.0]) self.assertEqual(cfms.Ions, ['Pm', 'Eu']) @@ -51,7 +51,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertEqual(cfms.function.getParameterValue('BmolX'), 1.0) self.assertEqual(cfms.function.getParameterValue('B40'), -0.02) - def test_init_parameters_multiple_ions(self): + def test_init_parameters_multi_ions(self): cfms = CrystalFieldMultiSite(Ions=('Pm', 'Eu'), Symmetries=('D2', 'C3v'), Temperatures=[20, 52], FWHMs=[1.0, 1.0], parameters={'ion0.B40': -0.02, 'ion0.B42': -0.11, 'ion1.B42': -0.12}) @@ -73,7 +73,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertAlmostEqual(cfms.function.getParameterValue('pk0.Sigma'), 0.42, 2) self.assertEqual(cfms.function.getParameterValue('pk0.PeakCentre'), 0) - def test_peak_values_multiple_ions(self): + def test_peak_values_multi_ions(self): cfms = CrystalFieldMultiSite(Ions=('Pr', 'Nd'), Symmetries=('D2', 'C3v'), Temperatures=[20], FWHMs=[1.5], parameters={'ion0.B60': -0.02, 'ion1.B62': -0.12}) self.assertEqual(int(cfms.function.getParameterValue('ion0.pk0.Amplitude')), 278) @@ -83,7 +83,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertEqual(cfms.function.getParameterValue('ion1.pk0.FWHM'), 1.5) self.assertAlmostEqual(cfms.function.getParameterValue('ion1.pk1.PeakCentre'), 1749.981919, 6) - def test_peak_values_multiple_ions_and_spectra(self): + def test_peak_values_multi_ions_and_spectra(self): cfms = CrystalFieldMultiSite(Ions=('Pm', 'Ce'), Symmetries=('D2', 'C3v'), Temperatures=[20, 52], FWHMs=[1.0, 1.0], parameters={'ion0.B40': -0.02, 'ion1.B42': -0.12}) self.assertEqual(int(cfms.function.getParameterValue('ion0.sp0.pk0.Amplitude')), 308) @@ -93,7 +93,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertEqual(cfms.function.getParameterValue('ion1.sp1.pk0.FWHM'), 1.0) self.assertAlmostEqual(cfms.function.getParameterValue('ion1.sp0.pk1.PeakCentre'), 8.519155, 6) - def test_peak_values_multiple_gaussian(self): + def test_peak_values_multi_gaussian(self): cfms = CrystalFieldMultiSite(Ions=('Pm', 'Dy'), Symmetries=('D2', 'C3v'), Temperatures=[20, 52], FWHMs=[1.0, 1.5], parameters={'ion0.B40': -0.02, 'ion1.B42': -0.12}, PeakShape='Gaussian') @@ -111,7 +111,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): r = [0.0, 1.45, 2.4, 3.0, 3.85] x, y = cfms.getSpectrum(r) y = y / c_mbsr - expected_y = [13.94816, 0.016566, 0.006051, 0.003873, 0.002352] + expected_y = [13.950363, 0.02298, 0.031946, 0.189161, 0.392888] np.testing.assert_equal(x, r) np.testing.assert_almost_equal(y, expected_y, 6) @@ -126,24 +126,24 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): ws = CreateWorkspace(x, y, e) x, y = cfms.getSpectrum(0, ws) y = y / c_mbsr - self.assertAlmostEqual(y[0], 12.471600, 6) - self.assertAlmostEqual(y[1], 4.296852, 6) - self.assertAlmostEqual(y[2], 1.448504, 6) - self.assertAlmostEqual(y[3], 0.688184, 6) - self.assertAlmostEqual(y[4], 0.396680, 6) - self.assertAlmostEqual(y[15], 0.029067, 6) - self.assertAlmostEqual(y[16], 0.025555, 6) + self.assertAlmostEqual(y[0], 12.474955, 6) + self.assertAlmostEqual(y[1], 4.300416, 6) + self.assertAlmostEqual(y[2], 1.452309, 6) + self.assertAlmostEqual(y[3], 0.692266, 6) + self.assertAlmostEqual(y[4], 0.401079, 6) + self.assertAlmostEqual(y[15], 0.050130, 6) + self.assertAlmostEqual(y[16], 0.054428, 6) x, y = cfms.getSpectrum(ws) y = y / c_mbsr - self.assertAlmostEqual(y[0], 12.471600, 6) - self.assertAlmostEqual(y[1], 4.296852, 6) + self.assertAlmostEqual(y[0], 12.474955, 6) + self.assertAlmostEqual(y[1], 4.300416, 6) ws = CreateWorkspace(x, y, e, 2) x, y = cfms.getSpectrum(ws, 1) y = y / c_mbsr - self.assertAlmostEqual(y[0], 0.029067, 6) - self.assertAlmostEqual(y[1], 0.025555, 6) + self.assertAlmostEqual(y[0], 0.050130, 6) + self.assertAlmostEqual(y[1], 0.054428, 6) - def test_get_spectrum_from_list_multiple_spectra(self): + def test_get_spectrum_from_list_multi_spectra(self): cfms = CrystalFieldMultiSite(Ions=['Ce'], Symmetries=['C2v'], Temperatures=[4.0, 50.0], FWHMs=[0.1, 0.2], B20=0.035, B40=-0.012, B43=-0.027, B60=-0.00012, B63=0.0025, B66=0.0068) r = [0.0, 1.45, 2.4, 3.0, 3.85] @@ -159,7 +159,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): np.testing.assert_equal(x, r) np.testing.assert_almost_equal(y, expected_y, 6) - def test_get_spectrum_ws_multiple_spectra(self): + def test_get_spectrum_ws_multi_spectra(self): from mantid.simpleapi import CreateWorkspace cfms = CrystalFieldMultiSite(['Ce'], ['C2v'], B20=0.035, B40=-0.012, B43=-0.027, B60=-0.00012, B63=0.0025, B66=0.0068, Temperatures=[4.0, 50.0], FWHMs=[0.1, 0.2]) @@ -194,7 +194,26 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): self.assertAlmostEqual(y[0], 0.050129858433581413, 6) self.assertAlmostEqual(y[1], 0.054427788297191478, 6) - def test_multi_ion_single_spectrum_fit(self): + def test_get_spectrum_list_multi_ion_and_spectra(self): + params = {'ion0.B20': 0.37737, 'ion0.B22': 3.9770, 'ion0.B40': -0.031787, 'ion0.B42': -0.11611, + 'ion0.B44': -0.12544, 'ion1.B20': 0.37737, 'ion1.B22': 3.9770, 'ion1.B40': -0.031787, + 'ion1.B42': -0.11611, 'ion1.B44': -0.12544} + cfms = CrystalFieldMultiSite(Ions=['Ce', 'Pr'], Symmetries=['C2v', 'C2v'], Temperatures=[44.0, 50.0], + FWHMs=[1.1, 1.2], parameters=params) + r = [0.0, 1.45, 2.4, 3.0, 3.85] + x, y = cfms.getSpectrum(0, r) + y = y / c_mbsr + expected_y = [3.904037, 0.744519, 0.274897, 0.175713, 0.106540] + np.testing.assert_equal(x, r) + np.testing.assert_almost_equal(y, expected_y, 6) + + x, y = cfms.getSpectrum(1, r) + y = y / c_mbsr + expected_y = [3.704726, 0.785600, 0.296255, 0.190176, 0.115650] + np.testing.assert_equal(x, r) + np.testing.assert_almost_equal(y, expected_y, 6) + + def test_fit_multi_ion_single_spectrum(self): from CrystalField.fitting import makeWorkspace from CrystalField import CrystalField, CrystalFieldFit @@ -209,15 +228,67 @@ class CrystalFieldMultiSiteTests(unittest.TestCase): ws = makeWorkspace(x, y) params = {'ion0.B20': 0.37737, 'ion0.B22': 3.9770, 'ion0.B40': -0.031787, 'ion0.B42': -0.11611, - 'ion0.B44': -0.12544, 'ion1.B20': 0.37737, 'ion1.B22': 3.9770, 'ion1.B40': -0.031787, 'ion1.B42': -0.11611, - 'ion1.B44': -0.12544} + 'ion0.B44': -0.12544, 'ion1.B20': 0.37737, 'ion1.B22': 3.9770, 'ion1.B40': -0.031787, + 'ion1.B42': -0.11611, 'ion1.B44': -0.12544} cf = CrystalFieldMultiSite(Ions=['Ce', 'Pr'], Symmetries=['C2v', 'C2v'], Temperatures=[44.0], FWHMs=[1.1], - ToleranceIntensity=6.0, ToleranceEnergy=1.0, parameters=params) + ToleranceIntensity=6.0, ToleranceEnergy=1.0, FixAllPeaks=True, parameters=params) + + cf.fix('ion0.BmolX', 'ion0.BmolY', 'ion0.BmolZ', 'ion0.BextX', 'ion0.BextY', 'ion0.BextZ', 'ion0.B40', + 'ion0.B42', 'ion0.B44', 'ion0.B60', 'ion0.B62', 'ion0.B64', 'ion0.B66', 'ion0.IntensityScaling', + 'ion1.BmolX', 'ion1.BmolY', 'ion1.BmolZ', 'ion1.BextX', 'ion1.BextY', 'ion1.BextZ', 'ion1.B40', + 'ion1.B42', 'ion1.B44', 'ion1.B60', 'ion1.B62', 'ion1.B64', 'ion1.B66', 'ion1.IntensityScaling') chi2 = CalculateChiSquared(cf.makeSpectrumFunction(), InputWorkspace=ws)[1] fit = CrystalFieldFit(Model=cf, InputWorkspace=ws, MaxIterations=10) fit.fit() + f = cf.function + for i in range(f.nParams()): + if not f.isFixed(i): + print i, f.parameterName(i), f.getParameterValue(i) + + self.assertFalse(True) + + self.assertTrue(cf.chi2 > 0.0) + self.assertTrue(cf.chi2 < chi2) + + def test_fit_multi_ion_and_spectra(self): + from CrystalField.fitting import makeWorkspace + from CrystalField import CrystalField, CrystalFieldFit + from mantid.simpleapi import CalculateChiSquared + + params = {'B20': 0.37737, 'B22': 3.9770, 'B40': -0.031787, 'B42': -0.11611, 'B44': -0.12544, + 'Temperature': [44.0, 50.0], 'FWHM': [1.1, 0.9]} + cf1 = CrystalField('Ce', 'C2v', **params) + cf2 = CrystalField('Pr', 'C2v', **params) + cf = cf1 + cf2 + ws1 = makeWorkspace(*cf.getSpectrum(0)) + ws2 = makeWorkspace(*cf.getSpectrum(1)) + + params = {'ion0.B20': 0.37737, 'ion0.B22': 3.9770, 'ion0.B40': -0.031787, 'ion0.B42': -0.11611, + 'ion0.B44': -0.12544, 'ion1.B20': 0.37737, 'ion1.B22': 3.9770, 'ion1.B40': -0.031787, + 'ion1.B42': -0.11611, 'ion1.B44': -0.12544} + cf = CrystalFieldMultiSite(Ions=['Ce', 'Pr'], Symmetries=['C2v', 'C2v'], Temperatures=[44.0, 50.0], + FWHMs=[1.0, 1.0], ToleranceIntensity=6.0, ToleranceEnergy=1.0, FixAllPeaks=True, + parameters=params) + + cf.fix('ion0.BmolX', 'ion0.BmolY', 'ion0.BmolZ', 'ion0.BextX', 'ion0.BextY', 'ion0.BextZ', 'ion0.B40', + 'ion0.B42', 'ion0.B44', 'ion0.B60', 'ion0.B62', 'ion0.B64', 'ion0.B66', 'ion0.IntensityScaling', + 'ion1.BmolX', 'ion1.BmolY', 'ion1.BmolZ', 'ion1.BextX', 'ion1.BextY', 'ion1.BextZ', 'ion1.B40', + 'ion1.B42', 'ion1.B44', 'ion1.B60', 'ion1.B62', 'ion1.B64', 'ion1.B66', 'ion1.IntensityScaling', + 'sp0.IntensityScaling', 'sp1.IntensityScaling') + + chi2 = CalculateChiSquared(str(cf.function), InputWorkspace=ws1, InputWorkspace_1=ws2)[1] + + fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws1, ws2], MaxIterations=10) + fit.fit() + + f = cf.function + for i in range(f.nParams()): + if not f.isFixed(i): + print i, f.parameterName(i), f.getParameterValue(i) + self.assertTrue(cf.chi2 > 0.0) - self.assertTrue(cf.chi2 < chi2) \ No newline at end of file + self.assertTrue(cf.chi2 < chi2) + self.assertFalse(True) \ No newline at end of file