/** * Execute the algorithm */ void LoadRKH::exec() { using namespace Mantid::Kernel; using namespace Mantid::API; //Retrieve filename and try to open the file std::string filename = getPropertyValue("Filename"); m_fileIn.open(filename.c_str()); if( ! m_fileIn ) { g_log.error("Unable to open file " + filename); throw Exception::FileError("Unable to open File: ", filename); } g_log.information() << "Opened file \""<<filename<<"\" for reading\n"; std::string line; //The first line contains human readable information about the original workspace that we don't need getline(m_fileIn, line); getline(m_fileIn, line); //Use one line of the file to diagnose if it is 1D or 2D, this line contains some data required by the 2D data reader MatrixWorkspace_sptr result = is2D(line) ? read2D(line) : read1D(); // all RKH files contain distribution data result->isDistribution(true); //Set the output workspace setProperty("OutputWorkspace", result); }
/** * Computes the square root of the errors and if the input was a distribution * this divides by the new bin-width * @param outputWS The workspace containing the output data * @param inputWS The input workspace used for testing distribution state */ void Rebin2D::normaliseOutput(MatrixWorkspace_sptr outputWS, MatrixWorkspace_const_sptr inputWS) { //PARALLEL_FOR1(outputWS) for(int64_t i = 0; i < static_cast<int64_t>(outputWS->getNumberHistograms()); ++i) { PARALLEL_START_INTERUPT_REGION MantidVec & outputY = outputWS->dataY(i); MantidVec & outputE = outputWS->dataE(i); for(size_t j = 0; j < outputWS->blocksize(); ++j) { m_progress->report("Calculating errors"); const double binWidth = (outputWS->readX(i)[j+1] - outputWS->readX(i)[j]); double eValue = std::sqrt(outputE[j]); // Don't do this for a RebinnedOutput workspace. The fractions // take care of such things. if( inputWS->isDistribution() && inputWS->id() != "RebinnedOutput") { outputY[j] /= binWidth; eValue /= binWidth; } outputE[j] = eValue; } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION outputWS->isDistribution(inputWS->isDistribution()); }
/** * This function gets the input workspace. In the case for a RebinnedOutput * workspace, it must be cleaned before proceeding. Other workspaces are * untouched. * @return the input workspace, cleaned if necessary */ MatrixWorkspace_sptr Integration::getInputWorkspace() { MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); if (temp->id() == "RebinnedOutput") { // Clean the input workspace in the RebinnedOutput case for nan's and // inf's in order to treat the data correctly later. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); temp = alg->getProperty("OutputWorkspace"); } // To integrate point data it will be converted to histograms if (!temp->isHistogramData()) { auto alg = this->createChildAlgorithm("ConvertToHistogram"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_histogram"; alg->setProperty("OutputWorkspace", outName); alg->executeAsChildAlg(); temp = alg->getProperty("OutputWorkspace"); temp->isDistribution(true); } return temp; }
void SphericalAbsorption::exec() { // Retrieve the input workspace m_inputWS = getProperty("InputWorkspace"); // Get the input parameters retrieveBaseProperties(); // Create the output workspace MatrixWorkspace_sptr correctionFactors = WorkspaceFactory::Instance().create(m_inputWS); correctionFactors->isDistribution(true); // The output of this is a distribution correctionFactors->setYUnit(""); // Need to explicitly set YUnit to nothing correctionFactors->setYUnitLabel("Attenuation factor"); double m_sphRadius = getProperty("SphericalSampleRadius"); // in cm IAlgorithm_sptr anvred = createSubAlgorithm("AnvredCorrection"); anvred->setProperty<MatrixWorkspace_sptr>("InputWorkspace", m_inputWS); anvred->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", correctionFactors); anvred->setProperty("PreserveEvents", true); anvred->setProperty("ReturnTransmissionOnly", true); anvred->setProperty("LinearScatteringCoef", m_refAtten); anvred->setProperty("LinearAbsorptionCoef", m_scattering); anvred->setProperty("Radius", m_sphRadius); anvred->executeAsSubAlg(); // Get back the result correctionFactors = anvred->getProperty("OutputWorkspace"); setProperty("OutputWorkspace", correctionFactors); }
/** Initialise a workspace from its parent * This sets values such as title, instrument, units, sample, spectramap. * This does NOT copy any data. * * @param parent :: the parent workspace * @param child :: the child workspace * @param differentSize :: A flag to indicate if the two workspace will be different sizes */ void WorkspaceFactoryImpl::initializeFromParent(const MatrixWorkspace_const_sptr parent, const MatrixWorkspace_sptr child, const bool differentSize) const { child->setTitle(parent->getTitle()); child->setComment(parent->getComment()); child->setInstrument(parent->getInstrument()); // This call also copies the SHARED POINTER to the parameter map // This call will (should) perform a COPY of the parameter map. child->instrumentParameters(); child->m_sample = parent->m_sample; child->m_run = parent->m_run; child->setYUnit(parent->m_YUnit); child->setYUnitLabel(parent->m_YUnitLabel); child->isDistribution(parent->isDistribution()); // Only copy the axes over if new sizes are not given if ( !differentSize ) { // Only copy mask map if same size for now. Later will need to check continued validity. child->m_masks = parent->m_masks; } // Same number of histograms = copy over the spectra data if (parent->getNumberHistograms() == child->getNumberHistograms()) { for (size_t wi=0; wi<parent->getNumberHistograms(); wi++) { ISpectrum * childSpec = child->getSpectrum(wi); const ISpectrum * parentSpec = parent->getSpectrum(wi); // Copy spectrum number and detector IDs childSpec->copyInfoFrom(*parentSpec); } } // deal with axis for (size_t i = 0; i < parent->m_axes.size(); ++i) { const size_t newAxisLength = child->getAxis(i)->length(); const size_t oldAxisLength = parent->getAxis(i)->length(); if ( !differentSize || newAxisLength == oldAxisLength ) { // Need to delete the existing axis created in init above delete child->m_axes[i]; // Now set to a copy of the parent workspace's axis child->m_axes[i] = parent->m_axes[i]->clone(child.get()); } else { if (! parent->getAxis(i)->isSpectra()) // WHY??? { delete child->m_axes[i]; // Call the 'different length' clone variant child->m_axes[i] = parent->m_axes[i]->clone(newAxisLength,child.get()); } } } return; }
/** Checks that the input workspace all exist, that they are the same size, have * the same units * and the same instrument name. Will throw if they don't. * @param inputWorkspaces The names of the input workspaces * @return A list of pointers to the input workspace, ordered by increasing * frame starting point * @throw Exception::NotFoundError If an input workspace doesn't exist * @throw std::invalid_argument If the input workspaces are not compatible */ std::list<API::MatrixWorkspace_sptr> MergeRuns::validateInputs(const std::vector<std::string> &inputWorkspaces) { std::list<MatrixWorkspace_sptr> inWS; std::string xUnitID; std::string YUnit; bool dist(false); // Going to check that name of instrument matches - think that's the best // possible at the moment // because if instrument is created from raw file it'll be a different // object std::string instrument; for (size_t i = 0; i < inputWorkspaces.size(); ++i) { MatrixWorkspace_sptr ws; // Fetch the next input workspace - throw an error if it's not there try { ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( inputWorkspaces[i]); if (!ws) { g_log.error() << "Input workspace " << inputWorkspaces[i] << " not found.\n"; throw Kernel::Exception::NotFoundError("Data Object", inputWorkspaces[i]); } inWS.push_back(ws); } catch (Exception::NotFoundError &) { g_log.error() << "Input workspace " << inputWorkspaces[i] << " not found.\n"; throw; } // Check that it has common binning if (!WorkspaceHelpers::commonBoundaries(inWS.back())) { g_log.error("Input workspaces must have common binning for all spectra"); throw std::invalid_argument( "Input workspaces must have common binning for all spectra"); } // Check a few things are the same for all input workspaces if (i == 0) { xUnitID = ws->getAxis(0)->unit()->unitID(); YUnit = ws->YUnit(); dist = ws->isDistribution(); instrument = ws->getInstrument()->getName(); } else { testCompatibility(ws, xUnitID, YUnit, dist, instrument); } } // Order the workspaces by ascending frame (X) starting point inWS.sort(compare); return inWS; }
/** Creates the output workspace, its size, units, etc. * @param binParams the bin boundary specification using the same same syntax as param the Rebin algorithm * @return A pointer to the newly-created workspace */ API::MatrixWorkspace_sptr Q1D2::setUpOutputWorkspace(const std::vector<double> & binParams) const { // Calculate the output binning MantidVecPtr XOut; size_t sizeOut = static_cast<size_t>( VectorHelper::createAxisFromRebinParams(binParams, XOut.access())); // Now create the output workspace MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(m_dataWS,1,sizeOut,sizeOut-1); outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer"); outputWS->setYUnitLabel("1/cm"); // Set the X vector for the output workspace outputWS->setX(0, XOut); outputWS->isDistribution(true); outputWS->getSpectrum(0)->clearDetectorIDs(); outputWS->getSpectrum(0)->setSpectrumNo(1); return outputWS; }
void SANSSolidAngleCorrection::exec() { // Reduction property manager const std::string reductionManagerName = getProperty("ReductionProperties"); boost::shared_ptr<PropertyManager> reductionManager; if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) { reductionManager = PropertyManagerDataService::Instance().retrieve(reductionManagerName); } else { reductionManager = boost::make_shared<PropertyManager>(); PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, reductionManager); } // If the solid angle algorithm isn't in the reduction properties, add it if (!reductionManager->existsProperty("SolidAngleAlgorithm")) { AlgorithmProperty *algProp = new AlgorithmProperty("SolidAngleAlgorithm"); algProp->setValue(toString()); reductionManager->declareProperty(algProp); } MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); DataObjects::EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS) return execEvent(); // Now create the output workspace MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if (outputWS != inputWS) { outputWS = WorkspaceFactory::Instance().create(inputWS); outputWS->isDistribution(true); outputWS->setYUnit(""); outputWS->setYUnitLabel("Steradian"); setProperty("OutputWorkspace", outputWS); } const int numHists = static_cast<int>(inputWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numHists); // Number of X bins const int xLength = static_cast<int>(inputWS->readY(0).size()); PARALLEL_FOR2(outputWS, inputWS) for (int i = 0; i < numHists; ++i) { PARALLEL_START_INTERUPT_REGION outputWS->dataX(i) = inputWS->readX(i); IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test // placed // outside here because Mac Intel compiler doesn't like 'continue' in a // catch // in an openmp block. } // If no detector found, skip onto the next spectrum if (!det) continue; // Skip if we have a monitor or if the detector is masked. if (det->isMonitor() || det->isMasked()) continue; const MantidVec &YIn = inputWS->readY(i); const MantidVec &EIn = inputWS->readE(i); MantidVec &YOut = outputWS->dataY(i); MantidVec &EOut = outputWS->dataE(i); // Compute solid angle correction factor const bool is_tube = getProperty("DetectorTubes"); const double tanTheta = tan(inputWS->detectorTwoTheta(det)); const double theta_term = sqrt(tanTheta * tanTheta + 1.0); double corr; if (is_tube) { const double tanAlpha = tan(getYTubeAngle(det, inputWS)); const double alpha_term = sqrt(tanAlpha * tanAlpha + 1.0); corr = alpha_term * theta_term * theta_term; } else { corr = theta_term * theta_term * theta_term; } // Correct data for all X bins for (int j = 0; j < xLength; j++) { YOut[j] = YIn[j] * corr; EOut[j] = fabs(EIn[j] * corr); } progress.report("Solid Angle Correction"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION setProperty("OutputMessage", "Solid angle correction applied"); }
/** Executes the rebin algorithm * * @throw runtime_error Thrown if the bin range does not intersect the range of *the input workspace */ void Rebin::exec() { // Get the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // Are we preserving event workspace-iness? bool PreserveEvents = getProperty("PreserveEvents"); // Rebinning in-place bool inPlace = (inputWS == outputWS); std::vector<double> rbParams = rebinParamsFromInput(getProperty("Params"), *inputWS, g_log); const bool dist = inputWS->isDistribution(); const bool isHist = inputWS->isHistogramData(); // workspace independent determination of length const int histnumber = static_cast<int>(inputWS->getNumberHistograms()); //------------------------------------------------------- bool fullBinsOnly = getProperty("FullBinsOnly"); MantidVecPtr XValues_new; // create new output X axis const int ntcnew = VectorHelper::createAxisFromRebinParams( rbParams, XValues_new.access(), true, fullBinsOnly); //--------------------------------------------------------------------------------- // Now, determine if the input workspace is actually an EventWorkspace EventWorkspace_const_sptr eventInputWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventInputWS != NULL) { //------- EventWorkspace as input ------------------------------------- EventWorkspace_sptr eventOutputWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (inPlace && PreserveEvents) { // -------------Rebin in-place, preserving events // ---------------------------------------------- // This only sets the X axis. Actual rebinning will be done upon data // access. eventOutputWS->setAllX(XValues_new); this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(eventOutputWS)); } else if (!inPlace && PreserveEvents) { // -------- NOT in-place, but you want to keep events for some reason. // ---------------------- // Must copy the event workspace to a new EventWorkspace (and bin that). // Make a brand new EventWorkspace eventOutputWS = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create( "EventWorkspace", inputWS->getNumberHistograms(), 2, 1)); // Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( inputWS, eventOutputWS, false); // You need to copy over the data as well. eventOutputWS->copyDataFrom((*eventInputWS)); // This only sets the X axis. Actual rebinning will be done upon data // access. eventOutputWS->setAllX(XValues_new); // Cast to the matrixOutputWS and save it this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(eventOutputWS)); } else { //--------- Different output, OR you're inplace but not preserving Events //--- create a Workspace2D ------- g_log.information() << "Creating a Workspace2D from the EventWorkspace " << eventInputWS->getName() << ".\n"; // Create a Workspace2D // This creates a new Workspace2D through a torturous route using the // WorkspaceFactory. // The Workspace2D is created with an EMPTY CONSTRUCTOR outputWS = WorkspaceFactory::Instance().create("Workspace2D", histnumber, ntcnew, ntcnew - 1); WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, true); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, histnumber); // Go through all the histograms and set the data PARALLEL_FOR3(inputWS, eventInputWS, outputWS) for (int i = 0; i < histnumber; ++i) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram outputWS->setX(i, XValues_new); // Get a const event list reference. eventInputWS->dataY() doesn't work. const EventList &el = eventInputWS->getEventList(i); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(*XValues_new, y_data, e_data); // Copy the data over. outputWS->dataY(i).assign(y_data.begin(), y_data.end()); outputWS->dataE(i).assign(e_data.begin(), e_data.end()); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); outputWS->setYUnit(eventInputWS->YUnit()); outputWS->setYUnitLabel(eventInputWS->YUnitLabel()); // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); } } // END ---- EventWorkspace
/** Load an individual "<SASentry>" element into a new workspace. It extends the *LoadCanSAS1D * in the direction of loading the SAStransmission_spectrum as well. (which was *introduced in version 1.1) * * @param[in] workspaceData points to a "<SASentry>" element * @param[out] runName the name this workspace should take * @return dataWS this workspace will be filled with data * @throw NotFoundError if any expected elements couldn't be read * @throw NotImplementedError if the entry doesn't contain exactly one run */ MatrixWorkspace_sptr LoadCanSAS1D2::loadEntry(Poco::XML::Node *const workspaceData, std::string &runName) { MatrixWorkspace_sptr main_out = LoadCanSAS1D::loadEntry(workspaceData, runName); bool loadTrans = getProperty("LoadTransmission"); if (!loadTrans) return main_out; // all done. It is not to load the transmission, nor check // if it exists. Element *workspaceElem = dynamic_cast<Element *>(workspaceData); // check(workspaceElem, "<SASentry>"); // already done at // LoadCanSAS1D::loadEntry Poco::AutoPtr<NodeList> sasTransList = workspaceElem->getElementsByTagName("SAStransmission_spectrum"); if (!sasTransList->length()) { g_log.warning() << "There is no transmission data for this file " << getPropertyValue("Filename") << std::endl; return main_out; } for (unsigned short trans_index = 0; trans_index < sasTransList->length(); trans_index++) { // foreach SAStransmission_spectrum Node *idataElem = sasTransList->item(trans_index); Element *sasTrasElem = dynamic_cast<Element *>(idataElem); if (!sasTrasElem) continue; std::vector<API::MatrixWorkspace_sptr> &group = (sasTrasElem->getAttribute("name") == "sample") ? trans_gp : trans_can_gp; // getting number of Tdata elements in the xml file Poco::AutoPtr<NodeList> tdataElemList = sasTrasElem->getElementsByTagName("Tdata"); size_t nBins = tdataElemList->length(); MatrixWorkspace_sptr dataWS = WorkspaceFactory::Instance().create("Workspace2D", 1, nBins, nBins); createLogs(workspaceElem, dataWS); std::string title = main_out->getTitle(); title += ":trans"; title += sasTrasElem->getAttribute("name"); dataWS->setTitle(title); dataWS->isDistribution(true); dataWS->setYUnit(""); // load workspace data MantidVec &X = dataWS->dataX(0); MantidVec &Y = dataWS->dataY(0); MantidVec &E = dataWS->dataE(0); int vecindex = 0; // iterate through each Tdata element and get the values of "Lambda", //"T" and "Tdev" text nodes and fill X,Y,E vectors for (unsigned long index = 0; index < nBins; ++index) { Node *idataElem = tdataElemList->item(index); Element *elem = dynamic_cast<Element *>(idataElem); if (elem) { // setting X vector std::string nodeVal; Element *qElem = elem->getChildElement("Lambda"); check(qElem, "Lambda"); nodeVal = qElem->innerText(); std::stringstream x(nodeVal); double d; x >> d; X[vecindex] = d; // setting Y vector Element *iElem = elem->getChildElement("T"); check(qElem, "T"); nodeVal = iElem->innerText(); std::stringstream y(nodeVal); y >> d; Y[vecindex] = d; // setting the error vector Element *idevElem = elem->getChildElement("Tdev"); check(qElem, "Tdev"); nodeVal = idevElem->innerText(); std::stringstream e(nodeVal); e >> d; E[vecindex] = d; ++vecindex; } } runLoadInstrument(main_out->getInstrument()->getName(), dataWS); dataWS->getAxis(0)->setUnit("Wavelength"); // add to group group.push_back(dataWS); } return main_out; }
/** Execute the algorithm. */ void ResampleX::exec() { // generically having access to the input workspace is a good idea MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); m_numBins = getProperty("NumberBins"); m_preserveEvents = getProperty("PreserveEvents"); // determine the xmin/xmax for the workspace vector<double> xmins = getProperty("XMin"); vector<double> xmaxs = getProperty("XMax"); string error = determineXMinMax(inputWS, xmins, xmaxs); if (!error.empty()) throw std::runtime_error(error); bool common_limits = true; { double xmin_common = xmins[0]; double xmax_common = xmaxs[0]; for (size_t i = 1; i < xmins.size(); ++i) { if (xmins[i] != xmin_common) { common_limits = false; break; } if (xmaxs[i] != xmax_common) { common_limits = false; break; } } } if (common_limits) { g_log.debug() << "Common limits between all spectra\n"; } else { g_log.debug() << "Does not have common limits between all spectra\n"; } // start doing actual work EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS != NULL) { if (m_preserveEvents) { EventWorkspace_sptr outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (inPlace) { g_log.debug() << "Rebinning event workspace in place\n"; } else { g_log.debug() << "Rebinning event workspace out of place\n"; // copy the event workspace to a new EventWorkspace outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create( "EventWorkspace", inputWS->getNumberHistograms(), 2, 1)); // copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( inputEventWS, outputEventWS, false); // copy over the data as well. outputEventWS->copyDataFrom((*inputEventWS)); } if (common_limits) { // get the delta from the first since they are all the same MantidVecPtr xValues; double delta = this->determineBinning(xValues.access(), xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { // initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // do the rebinning PARALLEL_FOR2(inputEventWS, outputWS) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION MantidVec xValues; double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] << " xmax=" << xmaxs[wkspIndex] << "\n"; outputEventWS->getSpectrum(wkspIndex)->setX(xValues); prog.report(name()); // Report progress PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(outputEventWS)); } // end if (m_preserveEvents) else // event workspace -> matrix workspace { //--------- Different output, OR you're inplace but not preserving Events //--- create a Workspace2D ------- g_log.information() << "Creating a Workspace2D from the EventWorkspace " << inputEventWS->getName() << ".\n"; // Create a Workspace2D // This creates a new Workspace2D through a torturous route using the // WorkspaceFactory. // The Workspace2D is created with an EMPTY CONSTRUCTOR outputWS = WorkspaceFactory::Instance().create("Workspace2D", numSpectra, m_numBins, m_numBins - 1); WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, true); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // Go through all the histograms and set the data PARALLEL_FOR2(inputEventWS, outputWS) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram MantidVec xValues; double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; outputWS->setX(wkspIndex, xValues); // Get a const event list reference. inputEventWS->dataY() doesn't work. const EventList &el = inputEventWS->getEventList(wkspIndex); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(xValues, y_data, e_data); // Copy the data over. outputWS->dataY(wkspIndex).assign(y_data.begin(), y_data.end()); outputWS->dataE(wkspIndex).assign(e_data.begin(), e_data.end()); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); outputWS->setYUnit(inputEventWS->YUnit()); outputWS->setYUnitLabel(inputEventWS->YUnitLabel()); // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); } return; } else // (inputeventWS != NULL)
/// Exec function void CreateWorkspace::exec() { // Contortions to get at the vector in the property without copying it const Property * const dataXprop = getProperty("DataX"); const Property * const dataYprop = getProperty("DataY"); const Property * const dataEprop = getProperty("DataE"); const std::vector<double>& dataX = *dynamic_cast<const ArrayProperty<double>*>(dataXprop); const std::vector<double>& dataY = *dynamic_cast<const ArrayProperty<double>*>(dataYprop); const std::vector<double>& dataE = *dynamic_cast<const ArrayProperty<double>*>(dataEprop); const int nSpec = getProperty("NSpec"); const std::string xUnit = getProperty("UnitX"); const std::string vUnit = getProperty("VerticalAxisUnit"); const std::vector<std::string> vAxis = getProperty("VerticalAxisValues"); std::string parentWorkspace = getPropertyValue("ParentWorkspace"); if ( ( vUnit != "SpectraNumber" ) && ( static_cast<int>(vAxis.size()) != nSpec ) ) { throw std::invalid_argument("Number of y-axis labels must match number of histograms."); } // Verify length of vectors makes sense with NSpec if ( ( dataY.size() % nSpec ) != 0 ) { throw std::invalid_argument("Length of DataY must be divisible by NSpec"); } const std::size_t ySize = dataY.size() / nSpec; // Check whether the X values provided are to be re-used for (are common to) every spectrum const bool commonX( dataX.size() == ySize || dataX.size() == ySize+1 ); std::size_t xSize; MantidVecPtr XValues; if ( commonX ) { xSize = dataX.size(); XValues.access() = dataX; } else { if ( dataX.size() % nSpec != 0 ) { throw std::invalid_argument("Length of DataX must be divisible by NSpec"); } xSize = static_cast<int>(dataX.size()) / nSpec; if ( xSize < ySize || xSize > ySize + 1 ) { throw std::runtime_error("DataX width must be as DataY or +1"); } } const bool dataE_provided = !dataE.empty(); if ( dataE_provided && dataY.size() != dataE.size() ) { throw std::runtime_error("DataE (if provided) must be the same size as DataY"); } MatrixWorkspace_sptr parentWS; if (!parentWorkspace.empty()) { try { parentWS = boost::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieve(parentWorkspace) ); } catch(...) { g_log.warning("Parent workspace not found"); // ignore parent workspace } } // Create the OutputWorkspace MatrixWorkspace_sptr outputWS; if (parentWS) { // if parent is defined use it to initialise the workspace outputWS = WorkspaceFactory::Instance().create(parentWS, nSpec, xSize, ySize); } else { // otherwise create a blank workspace outputWS = WorkspaceFactory::Instance().create("Workspace2D", nSpec, xSize, ySize); } Progress progress(this,0,1,nSpec); PARALLEL_FOR1(outputWS) for ( int i = 0; i < nSpec; i++ ) { PARALLEL_START_INTERUPT_REGION const std::vector<double>::difference_type xStart = i*xSize; const std::vector<double>::difference_type xEnd = xStart + xSize; const std::vector<double>::difference_type yStart = i*ySize; const std::vector<double>::difference_type yEnd = yStart + ySize; // Just set the pointer if common X bins. Otherwise, copy in the right chunk (as we do for Y). if ( commonX ) { outputWS->setX(i,XValues); } else { outputWS->dataX(i).assign(dataX.begin()+xStart,dataX.begin()+xEnd); } outputWS->dataY(i).assign(dataY.begin()+yStart,dataY.begin()+yEnd); if ( dataE_provided) outputWS->dataE(i).assign(dataE.begin()+yStart,dataE.begin()+yEnd); progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Set the Unit of the X Axis try { outputWS->getAxis(0)->unit() = UnitFactory::Instance().create(xUnit); } catch ( Exception::NotFoundError & ) { outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("Label"); Unit_sptr unit = outputWS->getAxis(0)->unit(); boost::shared_ptr<Units::Label> label = boost::dynamic_pointer_cast<Units::Label>(unit); label->setLabel(xUnit, xUnit); } // Populate the VerticalAxis. A spectra one is there by default with a 1->N mapping if ( vUnit != "SpectraNumber" ) { if ( vUnit == "Text" ) { TextAxis* const newAxis = new TextAxis(vAxis.size()); outputWS->replaceAxis(1, newAxis); for ( size_t i = 0; i < vAxis.size(); i++ ) { newAxis->setLabel(i, vAxis[i]); } } else { NumericAxis* const newAxis = new NumericAxis(vAxis.size()); newAxis->unit() = UnitFactory::Instance().create(vUnit); outputWS->replaceAxis(1, newAxis); for ( size_t i = 0; i < vAxis.size(); i++ ) { try { newAxis->setValue(i, boost::lexical_cast<double, std::string>(vAxis[i]) ); } catch ( boost::bad_lexical_cast & ) { throw std::invalid_argument("CreateWorkspace - YAxisValues property could not be converted to a double."); } } } } // Set distribution flag outputWS->isDistribution(getProperty("Distribution")); // Set Y Unit label if (!parentWS || !getPropertyValue("YUnitLabel").empty()) { outputWS->setYUnitLabel(getProperty("YUnitLabel")); } // Set Workspace Title if (!parentWS || !getPropertyValue("WorkspaceTitle").empty()) { outputWS->setTitle(getProperty("WorkspaceTitle")); } // Set OutputWorkspace property setProperty("OutputWorkspace", outputWS); }
/** Execute the algorithm. */ void ResampleX::exec() { // generically having access to the input workspace is a good idea MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); const int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); m_numBins = getProperty("NumberBins"); m_preserveEvents = getProperty("PreserveEvents"); // determine the xmin/xmax for the workspace vector<double> xmins = getProperty("XMin"); vector<double> xmaxs = getProperty("XMax"); string error = determineXMinMax(inputWS, xmins, xmaxs); if (!error.empty()) throw std::runtime_error(error); bool common_limits = true; { double xmin_common = xmins[0]; double xmax_common = xmaxs[0]; for (size_t i = 1; i < xmins.size(); ++i) { if (xmins[i] != xmin_common) { common_limits = false; break; } if (xmaxs[i] != xmax_common) { common_limits = false; break; } } } if (common_limits) { g_log.debug() << "Common limits between all spectra\n"; } else { g_log.debug() << "Does not have common limits between all spectra\n"; } // start doing actual work EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS != nullptr) { if (m_preserveEvents) { if (inPlace) { g_log.debug() << "Rebinning event workspace in place\n"; } else { g_log.debug() << "Rebinning event workspace out of place\n"; outputWS = inputWS->clone(); } auto outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (common_limits) { // get the delta from the first since they are all the same BinEdges xValues(0); const double delta = this->determineBinning(xValues.mutableRawData(), xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { // initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // do the rebinning PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION BinEdges xValues(0); const double delta = this->determineBinning( xValues.mutableRawData(), xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] << " xmax=" << xmaxs[wkspIndex] << "\n"; outputEventWS->setHistogram(wkspIndex, xValues); prog.report(name()); // Report progress PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } } // end if (m_preserveEvents) else // event workspace -> matrix workspace { //--------- Different output, OR you're inplace but not preserving Events g_log.information() << "Creating a Workspace2D from the EventWorkspace " << inputEventWS->getName() << ".\n"; outputWS = create<DataObjects::Workspace2D>( *inputWS, numSpectra, HistogramData::BinEdges(m_numBins + 1)); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // Go through all the histograms and set the data PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram MantidVec xValues; const double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; outputWS->setBinEdges(wkspIndex, xValues); // Get a const event list reference. inputEventWS->dataY() doesn't work. const EventList &el = inputEventWS->getSpectrum(wkspIndex); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(xValues, y_data, e_data); // Copy the data over. outputWS->mutableY(wkspIndex) = std::move(y_data); outputWS->mutableE(wkspIndex) = std::move(e_data); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) { outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } outputWS->setYUnit(inputEventWS->YUnit()); outputWS->setYUnitLabel(inputEventWS->YUnitLabel()); } // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); return; } else // (inputeventWS != NULL)
void Qxy::exec() { MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); const bool doGravity = getProperty("AccountForGravity"); const bool doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(inputWorkspace, waveAdj, pixelAdj); g_log.debug() << "All input workspaces were found to be valid\n"; // Create the output Qx-Qy grid MatrixWorkspace_sptr outputWorkspace = this->setUpOutputWorkspace(inputWorkspace); // Will also need an identically-sized workspace to hold the solid angle/time bin masked weight MatrixWorkspace_sptr weights = WorkspaceFactory::Instance().create(outputWorkspace); // Copy the X values from the output workspace to the solidAngles one cow_ptr<MantidVec> axis; axis.access() = outputWorkspace->readX(0); for ( size_t i = 0; i < weights->getNumberHistograms(); ++i ) weights->setX(i,axis); const size_t numSpec = inputWorkspace->getNumberHistograms(); const size_t numBins = inputWorkspace->blocksize(); // the samplePos is often not (0, 0, 0) because the instruments components are moved to account for the beam centre const V3D samplePos = inputWorkspace->getInstrument()->getSample()->getPos(); // Set the progress bar (1 update for every one percent increase in progress) Progress prog(this, 0.05, 1.0, numSpec); // PARALLEL_FOR2(inputWorkspace,outputWorkspace) for (int64_t i = 0; i < int64_t(numSpec); ++i) { // PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = inputWorkspace->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found or if it's masked or a monitor, skip onto the next spectrum if ( !det || det->isMonitor() || det->isMasked() ) continue; //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for const size_t wavStart = helper.waveLengthCutOff(inputWorkspace, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= inputWorkspace->readY(i).size()) { // all the spectra in this detector are out of range continue; } V3D detPos = det->getPos()-samplePos; // these will be re-calculated if gravity is on but without gravity there is no need double phi = atan2(detPos.Y(),detPos.X()); double a = cos(phi); double b = sin(phi); double sinTheta = sin( inputWorkspace->detectorTwoTheta(det)/2.0 ); // Get references to the data for this spectrum const MantidVec& X = inputWorkspace->readX(i); const MantidVec& Y = inputWorkspace->readY(i); const MantidVec& E = inputWorkspace->readE(i); const MantidVec& axis = outputWorkspace->readX(0); // the solid angle of the detector as seen by the sample is used for normalisation later on double angle = det->solidAngle(samplePos); // some bins are masked completely or partially, the following vector will contain the fractions MantidVec maskFractions; if ( inputWorkspace->hasMaskedBins(i) ) { // go through the set and convert it to a vector const MatrixWorkspace::MaskList& mask = inputWorkspace->maskedBins(i); maskFractions.resize(numBins, 1.0); MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end()); for (it = mask.begin(); it != itEnd; ++it) { // The weight for this masked bin is 1 minus the degree to which this bin is masked maskFractions[it->first] -= it->second; } } double maskFraction(1); // this object is not used if gravity correction is off, but it is only constructed once per spectrum GravitySANSHelper grav; if (doGravity) { grav = GravitySANSHelper(inputWorkspace, det); } for (int j = static_cast<int>(numBins)-1; j >= static_cast<int>(wavStart); --j) { if( j < 0 ) break; // Be careful with counting down. Need a better fix but this will work for now const double binWidth = X[j+1]-X[j]; // Calculate the wavelength at the mid-point of this bin const double wavLength = X[j]+(binWidth)/2.0; if (doGravity) { // SANS instruments must have their y-axis pointing up, show the detector position as where the neutron would be without gravity sinTheta = grav.calcComponents(wavLength, a, b); } // Calculate |Q| for this bin const double Q = 4.0*M_PI*sinTheta/wavLength; // Now get the x & y components of Q. const double Qx = a*Q; // Test whether they're in range, if not go to next spectrum. if ( Qx < axis.front() || Qx >= axis.back() ) break; const double Qy = b*Q; if ( Qy < axis.front() || Qy >= axis.back() ) break; // Find the indices pointing to the place in the 2D array where this bin's contents should go const MantidVec::difference_type xIndex = std::upper_bound(axis.begin(),axis.end(),Qx) - axis.begin() - 1; const int yIndex = static_cast<int>( std::upper_bound(axis.begin(),axis.end(),Qy) - axis.begin() - 1); // PARALLEL_CRITICAL(qxy) /* Write to shared memory - must protect */ { // the data will be copied to this bin in the output array double & outputBinY = outputWorkspace->dataY(yIndex)[xIndex]; double & outputBinE = outputWorkspace->dataE(yIndex)[xIndex]; if ( boost::math::isnan(outputBinY)) { outputBinY = outputBinE = 0; } // Add the contents of the current bin to the 2D array. outputBinY += Y[j]; // add the errors in quadranture outputBinE = std::sqrt( (outputBinE*outputBinE) + (E[j]*E[j]) ); // account for masked bins if ( ! maskFractions.empty() ) { maskFraction = maskFractions[j]; } // add the total weight for this bin in the weights workspace, // in an equivalent bin to where the data was stored // first take into account the product of contributions to the weight which have // no errors double weight = 0.0; if(doSolidAngle) weight = maskFraction*angle; else weight = maskFraction; // then the product of contributions which have errors, i.e. optional // pixelAdj and waveAdj contributions if (pixelAdj && waveAdj) { weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]*waveAdj->readY(0)[j]; const double pixelYSq = pixelAdj->readY(i)[0]*pixelAdj->readY(i)[0]; const double pixelESq = pixelAdj->readE(i)[0]*pixelAdj->readE(i)[0]; const double waveYSq = waveAdj->readY(0)[j]*waveAdj->readY(0)[j]; const double waveESq = waveAdj->readE(0)[j]*waveAdj->readE(0)[j]; // add product of errors from pixelAdj and waveAdj (note no error on weight is assumed) weights->dataE(yIndex)[xIndex] += weight*weight*(waveESq*pixelYSq + pixelESq*waveYSq); } else if (pixelAdj) { weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]; const double pixelE = weight*pixelAdj->readE(i)[0]; // add error from pixelAdj weights->dataE(yIndex)[xIndex] += pixelE*pixelE; } else if(waveAdj) { weights->dataY(yIndex)[xIndex] += weight*waveAdj->readY(0)[j]; const double waveE = weight*waveAdj->readE(0)[j]; // add error from waveAdj weights->dataE(yIndex)[xIndex] += waveE*waveE; } else weights->dataY(yIndex)[xIndex] += weight; } } // loop over single spectrum prog.report("Calculating Q"); // PARALLEL_END_INTERUPT_REGION } // loop over all spectra // PARALLEL_CHECK_INTERUPT_REGION // take sqrt of error weight values // left to be executed here for computational efficiency size_t numHist = weights->getNumberHistograms(); for (size_t i = 0; i < numHist; i++) { for (size_t j = 0; j < weights->dataE(i).size(); j++) { weights->dataE(i)[j] = sqrt(weights->dataE(i)[j]); } } bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { // copy outputworkspace before it gets further modified MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWorkspace); for (size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++) { ws_sumOfCounts->dataX(i) = outputWorkspace->dataX(i); ws_sumOfCounts->dataY(i) = outputWorkspace->dataY(i); ws_sumOfCounts->dataE(i) = outputWorkspace->dataE(i); } helper.outputParts(this, ws_sumOfCounts, weights); } // Divide the output data by the solid angles outputWorkspace /= weights; outputWorkspace->isDistribution(true); // Count of the number of empty cells MatrixWorkspace::const_iterator wsIt(*outputWorkspace); int emptyBins = 0; for (;wsIt != wsIt.end(); ++wsIt) { if (wsIt->Y() < 1.0e-12) ++emptyBins; } // Log the number of empty bins g_log.notice() << "There are a total of " << emptyBins << " (" << (100*emptyBins)/(outputWorkspace->size()) << "%) empty Q bins.\n"; }
/** Executes the algorithm * * @throw Exception::FileError If the grouping file cannot be opened or read successfully * @throw runtime_error If unable to run one of the sub-algorithms successfully */ void DiffractionFocussing::exec() { // retrieve the properties std::string groupingFileName=getProperty("GroupingFileName"); // Get the input workspace MatrixWorkspace_sptr inputW = getProperty("InputWorkspace"); bool dist = inputW->isDistribution(); //do this first to check that a valid file is available before doing any work std::multimap<int64_t,int64_t> detectorGroups;// <group, UDET> if (!readGroupingFile(groupingFileName, detectorGroups)) { throw Exception::FileError("Error reading .cal file",groupingFileName); } //Convert to d-spacing units API::MatrixWorkspace_sptr tmpW = convertUnitsToDSpacing(inputW); //Rebin to a common set of bins RebinWorkspace(tmpW); std::set<int64_t> groupNumbers; for(std::multimap<int64_t,int64_t>::const_iterator d = detectorGroups.begin();d!=detectorGroups.end();d++) { if (groupNumbers.find(d->first) == groupNumbers.end()) { groupNumbers.insert(d->first); } } int iprogress = 0; int iprogress_count = static_cast<int>(groupNumbers.size()); int iprogress_step = iprogress_count / 100; if (iprogress_step == 0) iprogress_step = 1; std::vector<int64_t> resultIndeces; for(std::set<int64_t>::const_iterator g = groupNumbers.begin();g!=groupNumbers.end();g++) { if (iprogress++ % iprogress_step == 0) { progress(0.68 + double(iprogress)/iprogress_count/3); } std::multimap<int64_t,int64_t>::const_iterator from = detectorGroups.lower_bound(*g); std::multimap<int64_t,int64_t>::const_iterator to = detectorGroups.upper_bound(*g); std::vector<detid_t> detectorList; for(std::multimap<int64_t,int64_t>::const_iterator d = from;d!=to;d++) detectorList.push_back(static_cast<detid_t>(d->second)); // Want version 1 of GroupDetectors here API::IAlgorithm_sptr childAlg = createSubAlgorithm("GroupDetectors",-1.0,-1.0,true,1); childAlg->setProperty("Workspace", tmpW); childAlg->setProperty< std::vector<detid_t> >("DetectorList",detectorList); childAlg->executeAsSubAlg(); try { // get the index of the combined spectrum int ri = childAlg->getProperty("ResultIndex"); if (ri >= 0) { resultIndeces.push_back(ri); } } catch(...) { throw std::runtime_error("Unable to get Properties from GroupDetectors sub-algorithm"); } } // Discard left-over spectra, but print warning message giving number discarded int discarded = 0; const int64_t oldHistNumber = tmpW->getNumberHistograms(); API::Axis *spectraAxis = tmpW->getAxis(1); for(int64_t i=0; i < oldHistNumber; i++) if ( spectraAxis->spectraNo(i) >= 0 && find(resultIndeces.begin(),resultIndeces.end(),i) == resultIndeces.end()) { ++discarded; } g_log.warning() << "Discarded " << discarded << " spectra that were not assigned to any group" << std::endl; // Running GroupDetectors leads to a load of redundant spectra // Create a new workspace that's the right size for the meaningful spectra and copy them in int64_t newSize = tmpW->blocksize(); API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(tmpW,resultIndeces.size(),newSize+1,newSize); // Copy units outputW->getAxis(0)->unit() = tmpW->getAxis(0)->unit(); outputW->getAxis(1)->unit() = tmpW->getAxis(1)->unit(); API::Axis *spectraAxisNew = outputW->getAxis(1); for(int64_t hist=0; hist < static_cast<int64_t>(resultIndeces.size()); hist++) { int64_t i = resultIndeces[hist]; double spNo = static_cast<double>(spectraAxis->spectraNo(i)); MantidVec &tmpE = tmpW->dataE(i); MantidVec &outE = outputW->dataE(hist); MantidVec &tmpY = tmpW->dataY(i); MantidVec &outY = outputW->dataY(hist); MantidVec &tmpX = tmpW->dataX(i); MantidVec &outX = outputW->dataX(hist); outE.assign(tmpE.begin(),tmpE.end()); outY.assign(tmpY.begin(),tmpY.end()); outX.assign(tmpX.begin(),tmpX.end()); spectraAxisNew->setValue(hist,spNo); spectraAxis->setValue(i,-1); } progress(1.); outputW->isDistribution(dist); // Assign it to the output workspace property setProperty("OutputWorkspace",outputW); return; }