/** Converts an EventWorkspace to an equivalent Workspace2D * @param inputMatrixW :: input event workspace * @return a MatrixWorkspace_sptr */ MatrixWorkspace_sptr EventWorkspaceHelpers::convertEventTo2D(MatrixWorkspace_sptr inputMatrixW) { EventWorkspace_sptr inputW = boost::dynamic_pointer_cast<EventWorkspace>(inputMatrixW); if (!inputW) throw std::invalid_argument("EventWorkspaceHelpers::convertEventTo2D(): " "Input workspace is not an EventWorkspace."); size_t numBins = inputW->blocksize(); // Make a workspace 2D version of it MatrixWorkspace_sptr outputW; outputW = WorkspaceFactory::Instance().create( "Workspace2D", inputW->getNumberHistograms(), numBins + 1, numBins); WorkspaceFactory::Instance().initializeFromParent(inputW, outputW, false); // Now let's set all the X bins and values for (size_t i = 0; i < inputW->getNumberHistograms(); i++) { outputW->getSpectrum(i).copyInfoFrom(inputW->getSpectrum(i)); outputW->setX(i, inputW->refX(i)); MantidVec &Yout = outputW->dataY(i); const MantidVec &Yin = inputW->readY(i); for (size_t j = 0; j < numBins; j++) Yout[j] = Yin[j]; MantidVec &Eout = outputW->dataE(i); const MantidVec &Ein = inputW->readE(i); for (size_t j = 0; j < numBins; j++) Eout[j] = Ein[j]; } return outputW; }
/** Creates the output workspace, setting the axes according to the input * binning parameters * @param[in] inputWorkspace The input workspace * @param[in] binParams The bin parameters from the user * @param[out] newAxis The 'vertical' axis defined by the given * parameters * @return A pointer to the newly-created workspace */ API::MatrixWorkspace_sptr SofQW::setUpOutputWorkspace(API::MatrixWorkspace_const_sptr inputWorkspace, const std::vector<double> &binParams, std::vector<double> &newAxis) { // Create vector to hold the new X axis values MantidVecPtr xAxis; xAxis.access() = inputWorkspace->readX(0); const int xLength = static_cast<int>(xAxis->size()); // Create a vector to temporarily hold the vertical ('y') axis and populate // that const int yLength = static_cast<int>( VectorHelper::createAxisFromRebinParams(binParams, newAxis)); // Create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( inputWorkspace, yLength - 1, xLength, xLength - 1); // Create a numeric axis to replace the default vertical one Axis *const verticalAxis = new BinEdgeAxis(newAxis); outputWorkspace->replaceAxis(1, verticalAxis); // Now set the axis values for (int i = 0; i < yLength - 1; ++i) { outputWorkspace->setX(i, xAxis); } // Set the axis units verticalAxis->unit() = UnitFactory::Instance().create("MomentumTransfer"); verticalAxis->title() = "|Q|"; // Set the X axis title (for conversion to MD) outputWorkspace->getAxis(0)->title() = "Energy transfer"; return outputWorkspace; }
/** Reads from the third line of the input file to the end assuming it contains * 2D data * @param firstLine :: the second line in the file * @return a workspace containing the loaded data * @throw NotFoundError if there is compulsulary data is missing from the file * @throw invalid_argument if there is an inconsistency in the header * information */ const MatrixWorkspace_sptr LoadRKH::read2D(const std::string &firstLine) { g_log.information() << "file appears to contain 2D information, reading in 2D data mode\n"; MatrixWorkspace_sptr outWrksp; MantidVec axis0Data; Progress prog(read2DHeader(firstLine, outWrksp, axis0Data)); const size_t nAxis1Values = outWrksp->getNumberHistograms(); for (size_t i = 0; i < nAxis1Values; ++i) { // set the X-values to the common bin values we read above MantidVecPtr toPass; toPass.access() = axis0Data; outWrksp->setX(i, toPass); // now read in the Y values MantidVec &YOut = outWrksp->dataY(i); for (double &value : YOut) { m_fileIn >> value; } prog.report("Loading Y data"); } // loop on to the next spectrum // the error values form one big block after the Y-values for (size_t i = 0; i < nAxis1Values; ++i) { MantidVec &EOut = outWrksp->dataE(i); for (double &value : EOut) { m_fileIn >> value; } prog.report("Loading error estimates"); } // loop on to the next spectrum return outWrksp; }
/** Executes the algorithm */ void MultiplyRange::exec() { // Get the input workspace and other properties MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); m_startBin = getProperty("StartBin"); m_endBin = getProperty("EndBin"); m_factor = getProperty("Factor"); // A few checks on the input properties const int specSize = static_cast<int>(inputWS->blocksize()); if ( isEmpty(m_endBin) ) m_endBin = specSize - 1; if ( m_endBin >= specSize ) { g_log.error("EndBin out of range!"); throw std::out_of_range("EndBin out of range!"); } if ( m_endBin < m_startBin ) { g_log.error("StartBin must be less than or equal to EndBin"); throw std::out_of_range("StartBin must be less than or equal to EndBin"); } // Only create the output workspace if it's different to the input one MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if ( outputWS != inputWS ) { outputWS = WorkspaceFactory::Instance().create(inputWS); setProperty("OutputWorkspace",outputWS); } // Get the count of histograms in the input workspace const int histogramCount = static_cast<int>(inputWS->getNumberHistograms()); Progress progress(this,0.0,1.0,histogramCount); // Loop over spectra PARALLEL_FOR2(inputWS,outputWS) for (int i = 0; i < histogramCount; ++i) { PARALLEL_START_INTERUPT_REGION // Copy over the bin boundaries outputWS->setX(i,inputWS->refX(i)); // Copy over the data outputWS->dataY(i) = inputWS->readY(i); outputWS->dataE(i) = inputWS->readE(i); MantidVec& newY = outputWS->dataY(i); MantidVec& newE = outputWS->dataE(i); // Now multiply the requested range std::transform(newY.begin()+m_startBin,newY.begin()+m_endBin+1,newY.begin()+m_startBin, std::bind2nd(std::multiplies<double>(),m_factor)); std::transform(newE.begin()+m_startBin,newE.begin()+m_endBin+1,newE.begin()+m_startBin, std::bind2nd(std::multiplies<double>(),m_factor)); progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** Creates the output workspace, setting the X vector to the bins boundaries in * Qx. * @return A pointer to the newly-created workspace */ API::MatrixWorkspace_sptr Qxy::setUpOutputWorkspace(API::MatrixWorkspace_const_sptr inputWorkspace) { const double max = getProperty("MaxQxy"); const double delta = getProperty("DeltaQ"); int bins = static_cast<int>(max / delta); if (bins * delta != max) ++bins; // Stop at first boundary past MaxQxy if max is not a multiple of // delta const double startVal = -1.0 * delta * bins; bins *= 2; // go from -max to +max bins += 1; // Add 1 - this is a histogram // Create an output workspace with the same meta-data as the input MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( inputWorkspace, bins - 1, bins, bins - 1); // ... but clear the masking from the parameter map as we don't want to carry // that over since this is essentially // a 2D rebin ParameterMap &pmap = outputWorkspace->instrumentParameters(); pmap.clearParametersByName("masked"); // Create a numeric axis to replace the vertical one Axis *verticalAxis = new BinEdgeAxis(bins); outputWorkspace->replaceAxis(1, verticalAxis); // Build up the X values Kernel::cow_ptr<MantidVec> axis; MantidVec &horizontalAxisRef = axis.access(); horizontalAxisRef.resize(bins); for (int i = 0; i < bins; ++i) { const double currentVal = startVal + i * delta; // Set the X value horizontalAxisRef[i] = currentVal; // Set the Y value on the axis verticalAxis->setValue(i, currentVal); } // Fill the X vectors in the output workspace for (int i = 0; i < bins - 1; ++i) { outputWorkspace->setX(i, axis); for (int j = 0; j < bins - j; ++j) { outputWorkspace->dataY(i)[j] = std::numeric_limits<double>::quiet_NaN(); outputWorkspace->dataE(i)[j] = std::numeric_limits<double>::quiet_NaN(); } } // Set the axis units outputWorkspace->getAxis(1)->unit() = outputWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer"); // Set the 'Y' unit (gets confusing here...this is probably a Z axis in this // case) outputWorkspace->setYUnitLabel("Cross Section (1/cm)"); setProperty("OutputWorkspace", outputWorkspace); return outputWorkspace; }
MatrixWorkspace_sptr PolarizationCorrection::copyShapeAndFill(MatrixWorkspace_sptr &base, const double &value) { MatrixWorkspace_sptr wsTemplate = WorkspaceFactory::Instance().create(base); // Copy the x-array across to the new workspace. for (size_t i = 0; i < wsTemplate->getNumberHistograms(); ++i) { wsTemplate->setX(i, base->refX(i)); } auto zeroed = this->multiply(wsTemplate, 0); auto filled = this->add(zeroed, value); return filled; }
void IQTransform::exec() { MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); // Print a warning if the input workspace has more than one spectrum if ( inputWS->getNumberHistograms() > 1 ) { g_log.warning("This algorithm is intended for use on single-spectrum workspaces.\n" "Only the first spectrum will be transformed."); } // Do background subtraction from a workspace first because it doesn't like // potential conversion to point data that follows. Requires a temporary workspace. MatrixWorkspace_sptr tmpWS; MatrixWorkspace_sptr backgroundWS = getProperty("BackgroundWorkspace"); if ( backgroundWS ) tmpWS = subtractBackgroundWS(inputWS,backgroundWS); else tmpWS = inputWS; // Create the output workspace const size_t length = tmpWS->blocksize(); MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS,1,length,length); m_label->setLabel(""); outputWS->setYUnit(""); // Copy the data over. Assume single spectrum input (output will be). // Take the mid-point of histogram bins if ( tmpWS->isHistogramData() ) { VectorHelper::convertToBinCentre(tmpWS->readX(0),outputWS->dataX(0)); } else { outputWS->setX(0,tmpWS->refX(0)); } MantidVec& Y = outputWS->dataY(0) = tmpWS->dataY(0); outputWS->dataE(0) = tmpWS->dataE(0); // Subtract a constant background if requested const double background = getProperty("BackgroundValue"); if ( background > 0.0 ) subtractBackgroundValue(Y,background); // Select the desired transformation function and call it TransformFunc f = m_transforms.find(getProperty("TransformType"))->second; (this->*f)(outputWS); // Need the generic label unit on this (unless the unit on the X axis hasn't changed) if ( ! m_label->caption().empty() ) outputWS->getAxis(0)->unit() = m_label; setProperty("OutputWorkspace",outputWS); }
/** 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; }
/** * Sets a new preview spectrum for the mini plot. * * @param value workspace index */ void ResNorm::previewSpecChanged(int value) { m_previewSpec = value; // Update vanadium plot if (m_uiForm.dsVanadium->isValid()) m_uiForm.ppPlot->addSpectrum( "Vanadium", m_uiForm.dsVanadium->getCurrentDataName(), m_previewSpec); // Update fit plot std::string fitWsGroupName(m_pythonExportWsName + "_Fit_Workspaces"); std::string fitParamsName(m_pythonExportWsName + "_Fit"); if (AnalysisDataService::Instance().doesExist(fitWsGroupName)) { WorkspaceGroup_sptr fitWorkspaces = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( fitWsGroupName); ITableWorkspace_sptr fitParams = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>( fitParamsName); if (fitWorkspaces && fitParams) { Column_const_sptr scaleFactors = fitParams->getColumn("Scaling"); std::string fitWsName(fitWorkspaces->getItem(m_previewSpec)->name()); MatrixWorkspace_const_sptr fitWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( fitWsName); MatrixWorkspace_sptr fit = WorkspaceFactory::Instance().create(fitWs, 1); fit->setX(0, fitWs->readX(1)); fit->getSpectrum(0)->setData(fitWs->readY(1), fitWs->readE(1)); for (size_t i = 0; i < fit->blocksize(); i++) fit->dataY(0)[i] /= scaleFactors->cell<double>(m_previewSpec); m_uiForm.ppPlot->addSpectrum("Fit", fit, 0, Qt::red); } } }
/** * Setup the output workspace * @param parent :: A pointer to the input workspace * @param newXBins [out] :: An output vector to be filled with the new X bin boundaries * @param newYBins [out] :: An output vector to be filled with the new Y bin boundaries * @return A pointer to the output workspace */ MatrixWorkspace_sptr Rebin2D::createOutputWorkspace(MatrixWorkspace_const_sptr parent, MantidVec & newXBins, MantidVec & newYBins) const { using Kernel::VectorHelper::createAxisFromRebinParams; // First create the two sets of bin boundaries const int newXSize = createAxisFromRebinParams(getProperty("Axis1Binning"), newXBins); const int newYSize = createAxisFromRebinParams(getProperty("Axis2Binning"), newYBins); // and now the workspace MatrixWorkspace_sptr outputWS; if (!this->useFractionalArea) { outputWS = WorkspaceFactory::Instance().create(parent,newYSize-1,newXSize,newXSize-1); } else { outputWS = WorkspaceFactory::Instance().create("RebinnedOutput", newYSize-1, newXSize, newXSize-1); WorkspaceFactory::Instance().initializeFromParent(parent, outputWS, true); } Axis* const verticalAxis = new NumericAxis(newYSize); // Meta data verticalAxis->unit() = parent->getAxis(1)->unit(); verticalAxis->title() = parent->getAxis(1)->title(); outputWS->replaceAxis(1,verticalAxis); // Now set the axis values for (size_t i=0; i < static_cast<size_t>(newYSize-1); ++i) { outputWS->setX(i,newXBins); verticalAxis->setValue(i,newYBins[i]); } // One more to set on the 'y' axis verticalAxis->setValue(newYSize-1,newYBins[newYSize-1]); return outputWS; }
//---------------------------------------------------------------------------------------------- /// @copydoc Mantid::API::Algorithm::exec() void ResetNegatives::exec() { MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = this->getProperty("OutputWorkspace"); // get the minimum for each spectrum IAlgorithm_sptr alg = this->createChildAlgorithm("Min", 0., .1); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWS); alg->executeAsChildAlg(); MatrixWorkspace_const_sptr minWS = alg->getProperty("OutputWorkspace"); // determine if there is anything to do int64_t nHist = static_cast<int64_t>(minWS->getNumberHistograms()); bool hasNegative = false; for (int64_t i = 0; i < nHist; i++) { if (minWS->readY(i)[0] < 0) { hasNegative = true; } break; } // get out early if there is nothing to do if (!hasNegative) { g_log.information() << "No values are negative. Copying InputWorkspace to OutputWorkspace\n"; if (inputWS != outputWS) { IAlgorithm_sptr alg = this->createChildAlgorithm("CloneWorkspace", .1, 1.); alg->setProperty<Workspace_sptr>("InputWorkspace", inputWS); alg->executeAsChildAlg(); Workspace_sptr temp = alg->getProperty("OutputWorkspace"); setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(temp)); } return; } // sort the event list to make it fast and thread safe DataObjects::EventWorkspace_const_sptr eventWS = boost::dynamic_pointer_cast<const DataObjects::EventWorkspace>( inputWS ); if (eventWS) eventWS->sortAll(DataObjects::TOF_SORT, NULL); Progress prog(this, .1, 1., 2*nHist); // generate output workspace - copy X and dY outputWS = API::WorkspaceFactory::Instance().create(inputWS); PARALLEL_FOR2(inputWS,outputWS) for (int64_t i = 0; i < nHist; i++) { PARALLEL_START_INTERUPT_REGION outputWS->dataY(i) = inputWS->readY(i); outputWS->dataE(i) = inputWS->readE(i); outputWS->setX(i, inputWS->refX(i)); // share the pointer more prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // do the actual work if (this->getProperty("AddMinimum")) { this->pushMinimum(minWS, outputWS, prog); } else { this->changeNegatives(minWS, this->getProperty("ResetValue"), outputWS, prog); } setProperty("OutputWorkspace",outputWS); }
/** * Make 2D MatrixWorkspace */ void ConvertMDHistoToMatrixWorkspace::make2DWorkspace() { // get the input workspace IMDHistoWorkspace_sptr inputWorkspace = getProperty("InputWorkspace"); // find the non-integrated dimensions Mantid::Geometry::VecIMDDimension_const_sptr nonIntegDims = inputWorkspace->getNonIntegratedDimensions(); auto xDim = nonIntegDims[0]; auto yDim = nonIntegDims[1]; size_t nx = xDim->getNBins(); size_t ny = yDim->getNBins(); size_t xDimIndex = inputWorkspace->getDimensionIndexById(xDim->getDimensionId()); size_t xStride = calcStride(*inputWorkspace, xDimIndex); size_t yDimIndex = inputWorkspace->getDimensionIndexById(yDim->getDimensionId()); size_t yStride = calcStride(*inputWorkspace, yDimIndex); // get the normalization of the output std::string normProp = getPropertyValue("Normalization"); Mantid::API::MDNormalization normalization; if (normProp == "NoNormalization") { normalization = NoNormalization; } else if (normProp == "VolumeNormalization") { normalization = VolumeNormalization; } else if (normProp == "NumEventsNormalization") { normalization = NumEventsNormalization; } else { normalization = NoNormalization; } signal_t inverseVolume = static_cast<signal_t>(inputWorkspace->getInverseVolume()); // create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create("Workspace2D", ny, nx + 1, nx); // set the x-values Mantid::MantidVec &X = outputWorkspace->dataX(0); double dx = xDim->getBinWidth(); double x = xDim->getMinimum(); for (auto ix = X.begin(); ix != X.end(); ++ix, x += dx) { *ix = x; } // set the y-values and errors for (size_t i = 0; i < ny; ++i) { if (i > 0) outputWorkspace->setX(i, X); auto &Y = outputWorkspace->dataY(i); auto &E = outputWorkspace->dataE(i); size_t yOffset = i * yStride; for (size_t j = 0; j < nx; ++j) { size_t linearIndex = yOffset + j * xStride; signal_t signal = inputWorkspace->getSignalArray()[linearIndex]; signal_t error = inputWorkspace->getErrorSquaredArray()[linearIndex]; // apply normalization if (normalization != NoNormalization) { if (normalization == VolumeNormalization) { signal *= inverseVolume; error *= inverseVolume; } else // normalization == NumEventsNormalization { signal_t factor = inputWorkspace->getNumEventsArray()[linearIndex]; factor = factor != 0.0 ? 1.0 / factor : 1.0; signal *= factor; error *= factor; } } Y[j] = signal; E[j] = sqrt(error); } } // set the first axis auto labelX = boost::dynamic_pointer_cast<Kernel::Units::Label>( Kernel::UnitFactory::Instance().create("Label")); labelX->setLabel(xDim->getName()); outputWorkspace->getAxis(0)->unit() = labelX; // set the second axis auto yAxis = new NumericAxis(ny); for (size_t i = 0; i < ny; ++i) { yAxis->setValue(i, yDim->getX(i)); } auto labelY = boost::dynamic_pointer_cast<Kernel::Units::Label>( Kernel::UnitFactory::Instance().create("Label")); labelY->setLabel(yDim->getName()); yAxis->unit() = labelY; outputWorkspace->replaceAxis(1, yAxis); // set the "units" for the y values outputWorkspace->setYUnitLabel("Signal"); // done setProperty("OutputWorkspace", outputWorkspace); }
/** 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
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"; }
/// 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 in case of a histogrammed data. void ExtractSpectra::execHistogram() { m_histogram = m_inputWorkspace->isHistogramData(); // Check for common boundaries in input workspace m_commonBoundaries = WorkspaceHelpers::commonBoundaries(m_inputWorkspace); // Retrieve and validate the input properties this->checkProperties(); // Create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( m_inputWorkspace, m_workspaceIndexList.size(), m_maxX - m_minX, m_maxX - m_minX - m_histogram); // If this is a Workspace2D, get the spectra axes for copying in the spectraNo // later Axis *inAxis1(nullptr); TextAxis *outTxtAxis(nullptr); NumericAxis *outNumAxis(nullptr); if (m_inputWorkspace->axes() > 1) { inAxis1 = m_inputWorkspace->getAxis(1); auto outAxis1 = outputWorkspace->getAxis(1); outTxtAxis = dynamic_cast<TextAxis *>(outAxis1); if (!outTxtAxis) outNumAxis = dynamic_cast<NumericAxis *>(outAxis1); } cow_ptr<MantidVec> newX; if (m_commonBoundaries) { const MantidVec &oldX = m_inputWorkspace->readX(m_workspaceIndexList.front()); newX.access().assign(oldX.begin() + m_minX, oldX.begin() + m_maxX); } Progress prog(this, 0.0, 1.0, (m_workspaceIndexList.size())); // Loop over the required workspace indices, copying in the desired bins for (int j = 0; j < static_cast<int>(m_workspaceIndexList.size()); ++j) { auto i = m_workspaceIndexList[j]; bool hasDx = m_inputWorkspace->hasDx(i); // Preserve/restore sharing if X vectors are the same if (m_commonBoundaries) { outputWorkspace->setX(j, newX); if (hasDx) { const MantidVec &oldDx = m_inputWorkspace->readDx(i); outputWorkspace->dataDx(j) .assign(oldDx.begin() + m_minX, oldDx.begin() + m_maxX); } } else { // Safe to just copy whole vector 'cos can't be cropping in X if not // common outputWorkspace->setX(j, m_inputWorkspace->refX(i)); if (hasDx) { outputWorkspace->setDx(j, m_inputWorkspace->refDx(i)); } } const MantidVec &oldY = m_inputWorkspace->readY(i); outputWorkspace->dataY(j) .assign(oldY.begin() + m_minX, oldY.begin() + (m_maxX - m_histogram)); const MantidVec &oldE = m_inputWorkspace->readE(i); outputWorkspace->dataE(j) .assign(oldE.begin() + m_minX, oldE.begin() + (m_maxX - m_histogram)); // copy over the axis entry for each spectrum, regardless of the type of // axes present if (inAxis1) { if (outTxtAxis) { outTxtAxis->setLabel(j, inAxis1->label(i)); } else if (outNumAxis) { outNumAxis->setValue(j, inAxis1->operator()(i)); } // spectra axis is handled by copyInfoFrom line } // Copy spectrum number & detectors outputWorkspace->getSpectrum(j) ->copyInfoFrom(*m_inputWorkspace->getSpectrum(i)); if (!m_commonBoundaries) this->cropRagged(outputWorkspace, static_cast<int>(i), j); // Propagate bin masking if there is any if (m_inputWorkspace->hasMaskedBins(i)) { const MatrixWorkspace::MaskList &inputMasks = m_inputWorkspace->maskedBins(i); MatrixWorkspace::MaskList::const_iterator it; for (it = inputMasks.begin(); it != inputMasks.end(); ++it) { const size_t maskIndex = (*it).first; if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram) outputWorkspace->flagMasked(j, maskIndex - m_minX, (*it).second); } } prog.report(); } setProperty("OutputWorkspace", outputWorkspace); }
void TOFSANSResolution::exec() { Workspace2D_sptr iqWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr reducedWS = getProperty("ReducedWorkspace"); EventWorkspace_sptr reducedEventWS = boost::dynamic_pointer_cast<EventWorkspace>(reducedWS); const double min_wl = getProperty("MinWavelength"); const double max_wl = getProperty("MaxWavelength"); double pixel_size_x = getProperty("PixelSizeX"); double pixel_size_y = getProperty("PixelSizeY"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters pixel_size_x /= 1000.0; pixel_size_y /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; wl_resolution = getProperty("DeltaT"); // Although we want the 'ReducedWorkspace' to be an event workspace for this algorithm to do // anything, we don't want the algorithm to 'fail' if it isn't if (!reducedEventWS) { g_log.warning() << "An Event Workspace is needed to compute dQ. Calculation skipped." << std::endl; return; } // Calculate the output binning const std::vector<double> binParams = getProperty("OutputBinning"); // Count histogram for normalization const int xLength = static_cast<int>(iqWS->readX(0).size()); std::vector<double> XNorm(xLength-1, 0.0); // Create workspaces with each component of the resolution for debugging purposes MatrixWorkspace_sptr thetaWS = WorkspaceFactory::Instance().create(iqWS); declareProperty(new WorkspaceProperty<>("ThetaError","",Direction::Output)); setPropertyValue("ThetaError","__"+iqWS->getName()+"_theta_error"); setProperty("ThetaError",thetaWS); thetaWS->setX(0,iqWS->readX(0)); MantidVec& ThetaY = thetaWS->dataY(0); MatrixWorkspace_sptr tofWS = WorkspaceFactory::Instance().create(iqWS); declareProperty(new WorkspaceProperty<>("TOFError","",Direction::Output)); setPropertyValue("TOFError","__"+iqWS->getName()+"_tof_error"); setProperty("TOFError",tofWS); tofWS->setX(0,iqWS->readX(0)); MantidVec& TOFY = tofWS->dataY(0); // Initialize Dq MantidVec& DxOut = iqWS->dataDx(0); for ( int i = 0; i<xLength-1; i++ ) DxOut[i] = 0.0; const V3D samplePos = reducedWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = reducedWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(reducedWS->getNumberHistograms()); Progress progress(this,0.0,1.0,numberOfSpectra); PARALLEL_FOR2(reducedEventWS, iqWS) for (int i = 0; i < numberOfSpectra; i++) { PARALLEL_START_INTERUPT_REGION IDetector_const_sptr det; try { det = reducedEventWS->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 flight path from the sample to the detector pixel const V3D scattered_flight_path = det->getPos() - samplePos; // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = reducedEventWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin( theta/2.0 ); EventList& el = reducedEventWS->getEventList(i); el.switchTo(WEIGHTED); std::vector<WeightedEvent>::iterator itev; std::vector<WeightedEvent>::iterator itev_end = el.getWeightedEvents().end(); for (itev = el.getWeightedEvents().begin(); itev != itev_end; ++itev) { if ( itev->m_weight != itev->m_weight ) continue; if (std::abs(itev->m_weight) == std::numeric_limits<double>::infinity()) continue; if ( !isEmpty(min_wl) && itev->m_tof < min_wl ) continue; if ( !isEmpty(max_wl) && itev->m_tof > max_wl ) continue; const double q = factor/itev->m_tof; int iq = 0; // Bin assignment depends on whether we have log or linear bins if(binParams[1]>0.0) { iq = (int)floor( (q-binParams[0])/ binParams[1] ); } else { iq = (int)floor(log(q/binParams[0])/log(1.0-binParams[1])); } const double L2 = scattered_flight_path.norm(); const double src_to_pixel = L1+L2; const double dTheta2 = ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*src_to_pixel*src_to_pixel/(L1*L1*L2*L2) + 2.0*(pixel_size_x*pixel_size_x+pixel_size_y*pixel_size_y)/(L2*L2) )/12.0; const double dwl_over_wl = 3.9560*getTOFResolution(itev->m_tof)/(1000.0*(L1+L2)*itev->m_tof); const double dq_over_q = std::sqrt(dTheta2/(theta*theta)+dwl_over_wl*dwl_over_wl); PARALLEL_CRITICAL(iq) /* Write to shared memory - must protect */ if (iq>=0 && iq < xLength-1 && !dq_over_q!=dq_over_q && dq_over_q>0) { DxOut[iq] += q*dq_over_q*itev->m_weight; XNorm[iq] += itev->m_weight; TOFY[iq] += q*std::fabs(dwl_over_wl)*itev->m_weight; ThetaY[iq] += q*std::sqrt(dTheta2)/theta*itev->m_weight; } } progress.report("Computing Q resolution"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Normalize according to the chosen weighting scheme for ( int i = 0; i<xLength-1; i++ ) { if (XNorm[i]>0) { DxOut[i] /= XNorm[i]; TOFY[i] /= XNorm[i]; ThetaY[i] /= XNorm[i]; } } }
/** 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)
void SmoothData::exec() { // Get the input properties MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); int npts = getProperty("NPoints"); // Number of smoothing points must always be an odd number, so add 1 if it isn't. if (!(npts%2)) { g_log.information("Adding 1 to number of smoothing points, since it must always be odd"); ++npts; } // Check that the number of points in the smoothing isn't larger than the spectrum length const int vecSize = static_cast<int>(inputWorkspace->blocksize()); if ( npts >= vecSize ) { g_log.error("The number of averaging points requested is larger than the spectrum length"); throw std::out_of_range("The number of averaging points requested is larger than the spectrum length"); } const int halfWidth = (npts-1)/2; // Create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); Progress progress(this,0.0,1.0,inputWorkspace->getNumberHistograms()); PARALLEL_FOR2(inputWorkspace,outputWorkspace) // Loop over all the spectra in the workspace for (int i = 0; i < static_cast<int>(inputWorkspace->getNumberHistograms()); ++i) { PARALLEL_START_INTERUPT_REGION // Copy the X data over. Preserves data sharing if present in input workspace. outputWorkspace->setX(i,inputWorkspace->refX(i)); // Now get references to the Y & E vectors in the input and output workspaces const MantidVec &Y = inputWorkspace->readY(i); const MantidVec &E = inputWorkspace->readE(i); MantidVec &newY = outputWorkspace->dataY(i); MantidVec &newE = outputWorkspace->dataE(i); // Use total to help hold our moving average double total = 0.0, totalE = 0.0; // First push the values ahead of the current point onto total for (int i = 0; i < halfWidth; ++i) { if ( Y[i] == Y[i] ) total += Y[i]; // Exclude if NaN totalE += E[i]*E[i]; } // Now calculate the smoothed values for the 'end' points, where the number contributing // to the smoothing will be less than NPoints for (int j = 0; j <= halfWidth; ++j) { const int index = j+halfWidth; if ( Y[index] == Y[index] ) total += Y[index]; // Exclude if NaN newY[j] = total/(index+1); totalE += E[index]*E[index]; newE[j] = sqrt(totalE)/(index+1); } // This is the main part, where each data point is the average of NPoints points centred on the // current point. Note that the statistical error will be reduced by sqrt(npts) because more // data is now contributing to each point. for (int k = halfWidth+1; k < vecSize-halfWidth; ++k) { const int kp = k+halfWidth; const int km = k-halfWidth-1; total += (Y[kp]!=Y[kp] ? 0.0 : Y[kp]) - (Y[km]!=Y[km] ? 0.0 : Y[km]); // Exclude if NaN newY[k] = total/npts; totalE += E[kp]*E[kp] - E[km]*E[km]; // Use of a moving average can lead to rounding error where what should be // zero actually comes out as a tiny negative number - bad news for sqrt so protect newE[k] = std::sqrt(std::abs(totalE))/npts; } // This deals with the 'end' at the tail of each spectrum for (int l = vecSize-halfWidth; l < vecSize; ++l) { const int index = l-halfWidth; total -= (Y[index-1]!=Y[index-1] ? 0.0 : Y[index-1]); // Exclude if NaN newY[l] = total/(vecSize-index); totalE -= E[index-1]*E[index-1]; newE[l] = std::sqrt(std::abs(totalE))/(vecSize-index); } progress.report(); PARALLEL_END_INTERUPT_REGION } // Loop over spectra PARALLEL_CHECK_INTERUPT_REGION // Set the output workspace to its property setProperty("OutputWorkspace", outputWorkspace); }
/** * Loads data from a selection of the FITS files into the workspace * @param workspace The workspace to insert data into * @param yVals Reference to a pre-allocated vector to hold data values for the workspace * @param eVals Reference to a pre-allocated vector to hold error values for the workspace * @param bufferAny Pointer to an allocated memory region which will hold a files worth of data * @param x Vector holding the X bin values * @param spectraCount Number of data points in each file * @param bitsPerPixel Number of bits used to represent one data point * @param binChunkStartIndex Index for the first file to be processed in this chunk */ void LoadFITS::loadChunkOfBinsFromFile(MatrixWorkspace_sptr &workspace, vector<vector<double> > &yVals, vector<vector<double> > &eVals, void *&bufferAny, MantidVecPtr &x, size_t spectraCount, int bitsPerPixel, size_t binChunkStartIndex) { size_t binsThisChunk = m_binChunkSize; if((binChunkStartIndex + m_binChunkSize) > m_allHeaderInfo.size()) { // No need to do extra processing if number of bins to process is lower than m_binChunkSize // Also used to prevent out of bounds error where a greater number of elements have been reserved. binsThisChunk = static_cast<size_t>(m_allHeaderInfo.size() - binChunkStartIndex); } uint8_t *buffer8 = NULL; uint16_t *buffer16 = NULL; uint32_t *buffer32 = NULL; // create pointer of correct data type to void pointer of the buffer: buffer8 = static_cast<uint8_t*>(bufferAny); buffer16 = static_cast<uint16_t*>(bufferAny); buffer32 = static_cast<uint32_t*>(bufferAny); for(size_t i=binChunkStartIndex; i < binChunkStartIndex+binsThisChunk ; ++i) { // Read Data bool fileErr = false; FILE * currFile = fopen ( m_allHeaderInfo[i].filePath.c_str(), "rb" ); if (currFile==NULL) fileErr = true; size_t result = 0; if(!fileErr) { fseek (currFile , FIXED_HEADER_SIZE , SEEK_CUR); result = fread(bufferAny, bitsPerPixel/8, spectraCount, currFile); } if (result != spectraCount) fileErr = true; if(fileErr) { throw std::runtime_error("Error reading file; possibly invalid data."); } for(size_t j=0; j<spectraCount;++j) { double val = 0; if(bitsPerPixel == 8) val = static_cast<double>(buffer8[j]); if(bitsPerPixel == 16) val = static_cast<double>(buffer16[j]); if(bitsPerPixel == 32) val = static_cast<double>(buffer32[j]); yVals[j][i-binChunkStartIndex] = val; eVals[j][i-binChunkStartIndex] = sqrt(val); } // Clear memory associated with the file load fclose (currFile); } // Now load chunk into workspace PARALLEL_FOR1(workspace) for (int64_t wi = 0; wi < static_cast<int64_t>(spectraCount); ++wi) { workspace->setX(wi, x); MantidVec *currY = &workspace->dataY(wi); MantidVec *currE = &workspace->dataE(wi); std::copy(yVals[wi].begin(), yVals[wi].end()-(m_binChunkSize-binsThisChunk), currY->begin()+binChunkStartIndex ); std::copy(eVals[wi].begin(), eVals[wi].end()-(m_binChunkSize-binsThisChunk), currE->begin()+binChunkStartIndex ); // I expect this will be wanted once IDF is in a more useful state. //workspace->getSpectrum(wi)->setDetectorID(detid_t(wi)); //workspace->getSpectrum(wi)->setSpectrumNo(specid_t(wi+1)); } }