/** * Main work portion of algorithm. Calculates mean of standard deviation, * ignoring * the detectors marked as "bad", then determines if any of the detectors are * "bad". * @param progress :: progress indicator * @param valid :: eventual output workspace, holding 0 for bad and 1 for good * @param values :: stddeviations of each spectra (I think) */ void IdentifyNoisyDetectors::getStdDev(API::Progress &progress, MatrixWorkspace_sptr valid, MatrixWorkspace_sptr values) { const int nhist = static_cast<int>(valid->getNumberHistograms()); int count = 0; double mean = 0.0; double mean2 = 0.0; for (int i = 0; i < nhist; i++) { if (valid->readY(i)[0] > 0) { mean += values->readY(i)[0]; mean2 += std::pow(values->readY(i)[0], 2); count++; } progress.report(); } if (0 == count) { // all values are zero, no need to loop return; } mean = mean / count; double stddev = sqrt((mean2 / count) - std::pow(mean, 2)); double upper = mean + 3 * stddev; double lower = mean - 3 * stddev; double min = mean * 0.0001; for (int i = 0; i < nhist; i++) { double value = values->readY(i)[0]; if (value > upper) { valid->dataY(i)[0] = 0.0; } else if (value < lower) { valid->dataY(i)[0] = 0.0; } else if (value < min) { valid->dataY(i)[0] = 0.0; } progress.report("Calculating StdDev..."); } }
void SumRowColumn::exec() { // First task is to integrate the input workspace MatrixWorkspace_const_sptr integratedWS = integrateWorkspace(); const size_t numSpec = integratedWS->getNumberHistograms(); // Check number of spectra is 128*128 or 192*192. Print warning if not. if (numSpec != 16384 && numSpec != 36864) { g_log.warning() << "The input workspace has " << numSpec << " spectra." << "This is not 128*128 or 192*192 - did you make a mistake?\n"; } // This is the dimension if all rows/columns are included const int dim = static_cast<int>( std::sqrt(static_cast<double>(numSpec)) ); // Check the column range properties int start = getProperty("HOverVMin"); int end = getProperty("HOverVMax"); if ( isEmpty(start) ) start = 0; if ( isEmpty(end) || end > dim-1 ) end = dim-1; if ( start > end ) { g_log.error("H/V_Min must be less than H/V_Max"); throw std::out_of_range("H/V_Min must be less than H/V_Max"); } MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(integratedWS,1,dim,dim); // Remove the unit outputWS->getAxis(0)->unit().reset(); // Get references to the vectors for the results MantidVec& X = outputWS->dataX(0); MantidVec& Y = outputWS->dataY(0); // Get the orientation const std::string orientation = getProperty("Orientation"); const bool horizontal = ( orientation=="D_H" ? 1 : 0 ); Progress progress(this,0,1,dim); for (int i = 0; i < dim; ++i) { // Copy X values X[i] = i; // Now loop over calculating Y's for (int j = start; j <= end; ++j) { const int index = ( horizontal ? ( i + j*dim) : ( i*dim + j) ); Y[i] += integratedWS->readY(index)[0]; } } setProperty("OutputWorkspace",outputWS); }
/** 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 NumericAxis(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; }
/// Get the counting time from a workspace /// @param inputWS :: workspace to read the counting time from double HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS) { // First, look whether we have the information in the log if (inputWS->run().hasProperty("timer")) { return inputWS->run().getPropertyValueAsType<double>("timer"); } else { // If we don't have the information in the log, use the default timer // spectrum MantidVec &timer = inputWS->dataY(DEFAULT_TIMER_ID); return timer[0]; } }
/** Populate output workspace with results * @param outWS :: [input/output] Output workspace to populate * @param nplots :: [input] Number of histograms */ void PlotAsymmetryByLogValue::populateOutputWorkspace( MatrixWorkspace_sptr &outWS, int nplots) { auto tAxis = new TextAxis(nplots); if (nplots == 1) { size_t i = 0; for (auto &value : m_logValue) { outWS->dataX(0)[i] = value.second; outWS->dataY(0)[i] = m_redY[value.first]; outWS->dataE(0)[i] = m_redE[value.first]; i++; } tAxis->setLabel(0, "Asymmetry"); } else { size_t i = 0; for (auto &value : m_logValue) { outWS->dataX(0)[i] = value.second; outWS->dataY(0)[i] = m_diffY[value.first]; outWS->dataE(0)[i] = m_diffE[value.first]; outWS->dataX(1)[i] = value.second; outWS->dataY(1)[i] = m_redY[value.first]; outWS->dataE(1)[i] = m_redE[value.first]; outWS->dataX(2)[i] = value.second; outWS->dataY(2)[i] = m_greenY[value.first]; outWS->dataE(2)[i] = m_greenE[value.first]; outWS->dataX(3)[i] = value.second; outWS->dataY(3)[i] = m_sumY[value.first]; outWS->dataE(3)[i] = m_sumE[value.first]; i++; } tAxis->setLabel(0, "Red-Green"); tAxis->setLabel(1, "Red"); tAxis->setLabel(2, "Green"); tAxis->setLabel(3, "Red+Green"); } outWS->replaceAxis(1, tAxis); outWS->getAxis(0)->title() = m_logName; outWS->setYUnitLabel("Asymmetry"); }
/** Populate output workspace with results * @param outWS :: [input/output] Output workspace to populate * @param nplots :: [input] Number of histograms */ void PlotAsymmetryByLogValue::saveResultsToADS(MatrixWorkspace_sptr &outWS, int nplots) { if (nplots == 2) { size_t i = 0; for (auto &value : m_logValue) { size_t run = value.first; outWS->dataX(0)[i] = static_cast<double>(run); // run number outWS->dataY(0)[i] = value.second; // log value outWS->dataY(1)[i] = m_redY[run]; // redY outWS->dataE(1)[i] = m_redE[run]; // redE i++; } } else { size_t i = 0; for (auto &value : m_logValue) { size_t run = value.first; outWS->dataX(0)[i] = static_cast<double>(run); // run number outWS->dataY(0)[i] = value.second; // log value outWS->dataY(1)[i] = m_diffY[run]; // diffY outWS->dataE(1)[i] = m_diffE[run]; // diffE outWS->dataY(2)[i] = m_redY[run]; // redY outWS->dataE(2)[i] = m_redE[run]; // redE outWS->dataY(3)[i] = m_greenY[run]; // greenY outWS->dataE(3)[i] = m_greenE[run]; // greenE outWS->dataY(4)[i] = m_sumY[run]; // sumY outWS->dataE(4)[i] = m_sumE[run]; // sumE i++; } } // Set the title! outWS->setTitle(m_allProperties); // Save results to ADS // We can't set an output property to store the results as this algorithm // is executed as a child algorithm in the Muon ALC interface // If current results were saved as a property we couln't used // the functionality to re-use previous results in ALC AnalysisDataService::Instance().addOrReplace(m_currResName, outWS); }
/** * Share the given input counts into the output array bins proportionally * according to how much the bins overlap the given lambda range. * outputX.size() must equal outputY.size() + 1 * * @param inputCounts [in] :: the input counts to share out * @param inputErr [in] :: the input errors to share out * @param bLambda [in] :: the bin width in lambda * @param lambdaMin [in] :: the start of the range to share counts to * @param lambdaMax [in] :: the end of the range to share counts to * @param outSpecIdx [in] :: the spectrum index to be updated in the output * workspace * @param IvsLam [in,out] :: the output workspace * @param outputE [in,out] :: the projected E values */ void ReflectometryReductionOne2::sumInQShareCounts( const double inputCounts, const double inputErr, const double bLambda, const double lambdaMin, const double lambdaMax, const size_t outSpecIdx, MatrixWorkspace_sptr IvsLam, std::vector<double> &outputE) { // Check that we have histogram data const auto &outputX = IvsLam->dataX(outSpecIdx); auto &outputY = IvsLam->dataY(outSpecIdx); if (outputX.size() != outputY.size() + 1) { throw std::runtime_error( "Expected output array to be histogram data (got X len=" + std::to_string(outputX.size()) + ", Y len=" + std::to_string(outputY.size()) + ")"); } const double totalWidth = lambdaMax - lambdaMin; // Get the first bin edge in the output X array that is within range. // There will probably be some overlap, so start from the bin edge before // this (unless we're already at the first bin edge). auto startIter = std::lower_bound(outputX.begin(), outputX.end(), lambdaMin); if (startIter != outputX.begin()) { --startIter; } // Loop through all overlapping output bins. Convert the iterator to an // index because we need to index both the X and Y arrays. const int xSize = static_cast<int>(outputX.size()); for (auto outIdx = startIter - outputX.begin(); outIdx < xSize - 1; ++outIdx) { const double binStart = outputX[outIdx]; const double binEnd = outputX[outIdx + 1]; if (binStart > lambdaMax) { // No longer in the overlap region so we're finished break; } // Add a share of the input counts to this bin based on the proportion of // overlap. if (totalWidth > Tolerance) { // Share counts out proportionally based on the overlap of this range const double overlapWidth = std::min({bLambda, lambdaMax - binStart, binEnd - lambdaMin}); const double fraction = overlapWidth / totalWidth; outputY[outIdx] += inputCounts * fraction; outputE[outIdx] += inputErr * fraction; } else { // Projection to a single value. Put all counts in the overlapping output // bin. outputY[outIdx] += inputCounts; outputE[outIdx] += inputCounts; } } }
/// Get the counting time from a workspace /// @param inputWS :: workspace to read the counting time from double HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS) { // First, look whether we have the information in the log if (inputWS->run().hasProperty("timer")) { Mantid::Kernel::Property* prop = inputWS->run().getProperty("timer"); Mantid::Kernel::PropertyWithValue<double>* dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double>* >(prop); return *dp; } else { // If we don't have the information in the log, use the default timer spectrum MantidVec& timer = inputWS->dataY(DEFAULT_TIMER_ID); return timer[0]; } }
/** * Rebin the input quadrilateral to the output grid * @param inputQ The input polygon * @param inputWS The input workspace containing the input intensity values * @param i The index in the vertical axis direction that inputQ references * @param j The index in the horizontal axis direction that inputQ references * @param outputWS A pointer to the output workspace that accumulates the data * @param verticalAxis A vector containing the output vertical axis bin boundaries */ void Rebin2D::rebinToOutput(const Geometry::Quadrilateral & inputQ, MatrixWorkspace_const_sptr inputWS, const size_t i, const size_t j, MatrixWorkspace_sptr outputWS, const std::vector<double> & verticalAxis) { const MantidVec & X = outputWS->readX(0); size_t qstart(0), qend(verticalAxis.size()-1), en_start(0), en_end(X.size() - 1); if( !getIntersectionRegion(outputWS, verticalAxis, inputQ, qstart, qend, en_start, en_end)) return; for( size_t qi = qstart; qi < qend; ++qi ) { const double vlo = verticalAxis[qi]; const double vhi = verticalAxis[qi+1]; for( size_t ei = en_start; ei < en_end; ++ei ) { const V2D ll(X[ei], vlo); const V2D lr(X[ei+1], vlo); const V2D ur(X[ei+1], vhi); const V2D ul(X[ei], vhi); const Quadrilateral outputQ(ll, lr, ur, ul); double yValue = inputWS->readY(i)[j]; if (boost::math::isnan(yValue)) { continue; } try { ConvexPolygon overlap = intersectionByLaszlo(outputQ, inputQ); const double weight = overlap.area()/inputQ.area(); yValue *= weight; double eValue = inputWS->readE(i)[j] * weight; const double overlapWidth = overlap.largestX() - overlap.smallestX(); if(inputWS->isDistribution()) { yValue *= overlapWidth; eValue *= overlapWidth; } eValue = eValue*eValue; PARALLEL_CRITICAL(overlap) { outputWS->dataY(qi)[ei] += yValue; outputWS->dataE(qi)[ei] += eValue; } } catch(Geometry::NoIntersectionException &) {} } } }
/** * Handles completion of the preview algorithm. * * @param error If the algorithm failed */ void IndirectSymmetrise::previewAlgDone(bool error) { if (error) return; QString workspaceName = m_uiForm.dsInput->getCurrentDataName(); int spectrumNumber = static_cast<int>(m_dblManager->value(m_properties["PreviewSpec"])); MatrixWorkspace_sptr sampleWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( workspaceName.toStdString()); ITableWorkspace_sptr propsTable = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>( "__SymmetriseProps_temp"); MatrixWorkspace_sptr symmWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( "__Symmetrise_temp"); // Get the index of XCut on each side of zero int negativeIndex = propsTable->getColumn("NegativeXMinIndex")->cell<int>(0); int positiveIndex = propsTable->getColumn("PositiveXMinIndex")->cell<int>(0); // Get the Y values for each XCut and the difference between them double negativeY = sampleWS->dataY(0)[negativeIndex]; double positiveY = sampleWS->dataY(0)[positiveIndex]; double deltaY = fabs(negativeY - positiveY); // Show values in property tree m_dblManager->setValue(m_properties["NegativeYValue"], negativeY); m_dblManager->setValue(m_properties["PositiveYValue"], positiveY); m_dblManager->setValue(m_properties["DeltaY"], deltaY); // Set indicator positions m_uiForm.ppRawPlot->getRangeSelector("NegativeEMinYPos") ->setMinimum(negativeY); m_uiForm.ppRawPlot->getRangeSelector("PositiveEMinYPos") ->setMinimum(positiveY); // Plot preview plot size_t spectrumIndex = symmWS->getIndexFromSpectrumNumber(spectrumNumber); m_uiForm.ppPreviewPlot->clear(); m_uiForm.ppPreviewPlot->addSpectrum("Symmetrised", "__Symmetrise_temp", spectrumIndex); // Don't want this to trigger when the algorithm is run for all spectra disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(previewAlgDone(bool))); }
void ExtractFFTSpectrum::exec() { MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr inputImagWS = getProperty("InputImagWorkspace"); const int fftPart = getProperty("FFTPart"); const int numHists = static_cast<int>(inputWS->getNumberHistograms()); MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS); Progress prog(this, 0.0, 1.0, numHists); PARALLEL_FOR1(outputWS) for ( int i = 0; i < numHists; i++ ) { PARALLEL_START_INTERUPT_REGION IAlgorithm_sptr childFFT = createChildAlgorithm("FFT"); childFFT->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWS); childFFT->setProperty<int>("Real", i); if( inputImagWS ) { childFFT->setProperty<MatrixWorkspace_sptr>("InputImagWorkspace", inputImagWS); childFFT->setProperty<int>("Imaginary", i); } childFFT->execute(); MatrixWorkspace_const_sptr fftTemp = childFFT->getProperty("OutputWorkspace"); outputWS->dataE(i) = fftTemp->readE(fftPart); outputWS->dataY(i) = fftTemp->readY(fftPart); outputWS->dataX(i) = fftTemp->readX(fftPart); prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION boost::shared_ptr<Kernel::Units::Label> lblUnit = boost::dynamic_pointer_cast<Kernel::Units::Label>(UnitFactory::Instance().create("Label")); lblUnit->setLabel("Time", "ns"); outputWS->getAxis(0)->unit() = lblUnit; setProperty("OutputWorkspace", outputWS); }
/** Set up neutron event's TOF correction. * It can be (1) parsed from TOF-correction table workspace to vectors, * (2) created according to detector's position in instrument; * (3) or no correction,i.e., correction value is equal to 1. * Offset should be as F*TOF + B */ void FilterEvents::setupDetectorTOFCalibration() { // Set output correction workspace and set to output const size_t numhist = m_eventWS->getNumberHistograms(); MatrixWorkspace_sptr corrws = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", numhist, 2, 2)); setProperty("OutputTOFCorrectionWorkspace", corrws); // Set up the size of correction and output correction workspace m_detTofOffsets.resize(numhist, 0.0); // unit of TOF m_detTofFactors.resize(numhist, 1.0); // multiplication factor // Set up detector values std::unique_ptr<TimeAtSampleStrategy> strategy; if (m_tofCorrType == CustomizedCorrect) { setupCustomizedTOFCorrection(); } else if (m_tofCorrType == ElasticCorrect) { // Generate TOF correction from instrument's set up strategy.reset(setupElasticTOFCorrection()); } else if (m_tofCorrType == DirectCorrect) { // Generate TOF correction for direct inelastic instrument strategy.reset(setupDirectTOFCorrection()); } else if (m_tofCorrType == IndirectCorrect) { // Generate TOF correction for indirect elastic instrument strategy.reset(setupIndirectTOFCorrection()); } if (strategy) { for (size_t i = 0; i < numhist; ++i) { if (!m_vecSkip[i]) { Correction correction = strategy->calculate(i); m_detTofOffsets[i] = correction.offset; m_detTofFactors[i] = correction.factor; corrws->dataY(i)[0] = correction.factor; corrws->dataY(i)[1] = correction.offset; } } } return; }
/** Create output workspace * @brief GetSpiceDataRawCountsFromMD::createOutputWorkspace * @param vecX * @param vecY * @param xlabel :: only 'Degrees' can be applied to x-axis * @param ylabel * @return */ MatrixWorkspace_sptr GetSpiceDataRawCountsFromMD::createOutputWorkspace( const std::vector<double> &vecX, const std::vector<double> &vecY, const std::string &xlabel, const std::string &ylabel) { // Create MatrixWorkspace size_t sizex = vecX.size(); size_t sizey = vecY.size(); if (sizex != sizey || sizex == 0) throw std::runtime_error("Unable to create output matrix workspace."); MatrixWorkspace_sptr outws = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", 1, sizex, sizey)); if (!outws) throw std::runtime_error("Failed to create output matrix workspace."); // Set data MantidVec &dataX = outws->dataX(0); MantidVec &dataY = outws->dataY(0); MantidVec &dataE = outws->dataE(0); for (size_t i = 0; i < sizex; ++i) { dataX[i] = vecX[i]; dataY[i] = vecY[i]; if (dataY[i] > 1.) dataE[i] = sqrt(dataY[i]); else dataE[i] = 1.; } // Set label outws->setYUnitLabel(ylabel); if (xlabel.size() != 0) { try { outws->getAxis(0)->setUnit(xlabel); } catch (...) { g_log.information() << "Label " << xlabel << " for X-axis is not a unit " "registered." << "\n"; } } return outws; }
void ConvertTableToMatrixWorkspace::exec() { ITableWorkspace_sptr inputWorkspace = getProperty("InputWorkspace"); std::string columnX = getProperty("ColumnX"); std::string columnY = getProperty("ColumnY"); std::string columnE = getProperty("ColumnE"); size_t nrows = inputWorkspace->rowCount(); std::vector<double> X(nrows); std::vector<double> Y(nrows); std::vector<double> E(nrows); inputWorkspace->getColumn(columnX)->numeric_fill(X); inputWorkspace->getColumn(columnY)->numeric_fill(Y); if (!columnE.empty()) { inputWorkspace->getColumn(columnE)->numeric_fill(E); } else { E.assign(X.size(),1.0); } MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create("Workspace2D",1,X.size(),X.size()); outputWorkspace->dataX(0).assign(X.begin(),X.end()); outputWorkspace->dataY(0).assign(Y.begin(),Y.end()); outputWorkspace->dataE(0).assign(E.begin(),E.end()); outputWorkspace->generateSpectraMap(); boost::shared_ptr<Kernel::Units::Label> labelX = boost::dynamic_pointer_cast<Kernel::Units::Label>( Kernel::UnitFactory::Instance().create("Label") ); labelX->setLabel(columnX); outputWorkspace->getAxis(0)->unit() = labelX; outputWorkspace->setYUnitLabel(columnY); setProperty("OutputWorkspace", outputWorkspace); }
/** Uses 'Linear' as a subalgorithm to fit the log of the exponential curve expected for the transmission. * @param WS :: The single-spectrum workspace to fit * @return A workspace containing the fit */ API::MatrixWorkspace_sptr CalculateTransmissionBeamSpreader::fitToData(API::MatrixWorkspace_sptr WS) { g_log.information("Fitting the experimental transmission curve"); Algorithm_sptr childAlg = createSubAlgorithm("Linear",0.6,1.0); childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", WS); const double lambdaMin = getProperty("MinWavelength"); const double lambdaMax = getProperty("MaxWavelength"); childAlg->setProperty<double>("StartX",lambdaMin); childAlg->setProperty<double>("EndX",lambdaMax); childAlg->executeAsSubAlg(); std::string fitStatus = childAlg->getProperty("FitStatus"); if ( fitStatus != "success" ) { g_log.error("Unable to successfully fit the data: " + fitStatus); throw std::runtime_error("Unable to successfully fit the data"); } // Only get to here if successful MatrixWorkspace_sptr result = childAlg->getProperty("OutputWorkspace"); if (logFit) { // Need to transform back to 'unlogged' double b = childAlg->getProperty("FitIntercept"); double m = childAlg->getProperty("FitSlope"); b = std::pow(10,b); m = std::pow(10,m); const MantidVec & X = result->readX(0); MantidVec & Y = result->dataY(0); MantidVec & E = result->dataE(0); for (size_t i = 0; i < Y.size(); ++i) { Y[i] = b*(std::pow(m,0.5*(X[i]+X[i+1]))); E[i] = std::abs(E[i]*Y[i]); } } return result; }
void FlatBackground::exec() { // Retrieve the input workspace MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); // Copy over all the data const int numHists = static_cast<int>(inputWS->getNumberHistograms()); const int blocksize = static_cast<int>(inputWS->blocksize()); // Get the required X range double startX,endX; this->checkRange(startX,endX); std::vector<int> specInds = getProperty("WorkspaceIndexList"); // check if the user passed an empty list, if so all of spec will be processed this->getSpecInds(specInds, numHists); // Are we removing the background? const bool removeBackground = std::string(getProperty("outputMode")) == "Subtract Background"; // Initialise the progress reporting object m_progress = new Progress(this,0.0,0.2,numHists); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // If input and output workspaces are not the same, create a new workspace for the output if (outputWS != inputWS ) { outputWS = WorkspaceFactory::Instance().create(inputWS); PARALLEL_FOR2(inputWS,outputWS) for (int i = 0; i < numHists; ++i) { PARALLEL_START_INTERUPT_REGION outputWS->dataX(i) = inputWS->readX(i); outputWS->dataY(i) = inputWS->readY(i); outputWS->dataE(i) = inputWS->readE(i); m_progress->report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** * Add -1.*minValue on each spectra. * * @param minWS A workspace of minimum values for each spectra. This is calculated in * the @see exec portion of the algorithm. * @param wksp The workspace to modify. * @param prog The progress. */ void ResetNegatives::pushMinimum(MatrixWorkspace_const_sptr minWS, MatrixWorkspace_sptr wksp, Progress &prog) { int64_t nHist = minWS->getNumberHistograms(); PARALLEL_FOR2(wksp, minWS) for (int64_t i = 0; i < nHist; i++) { PARALLEL_START_INTERUPT_REGION double minValue = minWS->readY(i)[0]; if (minValue <= 0) { minValue *= -1.; MantidVec & y = wksp->dataY(i); for (MantidVec::iterator it = y.begin(); it != y.end(); ++it) { *it = fixZero(*it + minValue); } } prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** 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 (MantidVec::iterator it = YOut.begin(), end=YOut.end(); it != end; ++it) { m_fileIn >> *it; } 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 (MantidVec::iterator it = EOut.begin(), end=EOut.end(); it != end; ++it) { m_fileIn >> *it; } prog.report("Loading error estimates"); }// loop on to the next spectrum return outWrksp; }
/** * 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); } } }
/** * Groups the workspace according to grouping provided. * * @param ws :: Workspace to group * @param g :: The grouping information * @return Sptr to created grouped workspace */ MatrixWorkspace_sptr groupWorkspace(MatrixWorkspace_const_sptr ws, const Grouping& g) { // As I couldn't specify multiple groups for GroupDetectors, I am going down quite a complicated // route - for every group distinct grouped workspace is created using GroupDetectors. These // workspaces are then merged into the output workspace. // Create output workspace MatrixWorkspace_sptr outWs = WorkspaceFactory::Instance().create(ws, g.groups.size(), ws->readX(0).size(), ws->blocksize()); for(size_t gi = 0; gi < g.groups.size(); gi++) { Mantid::API::IAlgorithm_sptr alg = AlgorithmManager::Instance().create("GroupDetectors"); alg->setChild(true); // So Output workspace is not added to the ADS alg->initialize(); alg->setProperty("InputWorkspace", boost::const_pointer_cast<MatrixWorkspace>(ws)); alg->setPropertyValue("SpectraList", g.groups[gi]); alg->setPropertyValue("OutputWorkspace", "grouped"); // Is not actually used, just to make validators happy alg->execute(); MatrixWorkspace_sptr grouped = alg->getProperty("OutputWorkspace"); // Copy the spectrum *(outWs->getSpectrum(gi)) = *(grouped->getSpectrum(0)); // Update spectrum number outWs->getSpectrum(gi)->setSpectrumNo(static_cast<specid_t>(gi)); // Copy to the output workspace outWs->dataY(gi) = grouped->readY(0); outWs->dataX(gi) = grouped->readX(0); outWs->dataE(gi) = grouped->readE(0); } return outWs; }
/** Execute the ghost correction on all events in the input workspace **/ void GhostCorrection::exec() { // Get the input workspace this->inputW = getProperty("InputWorkspace"); //Load the grouping GroupingWorkspace_sptr groupWS = getProperty("GroupingWorkspace"); groupWS->makeDetectorIDToGroupMap(detId_to_group, nGroups); if (this->nGroups <= 0) throw std::runtime_error("The # of groups found in the Grouping file is 0."); // Now the offsets OffsetsWorkspace_sptr offsetsWS = getProperty("OffsetsWorkspace"); //Make the X axis to bin to. MantidVecPtr XValues_new; const int64_t numbins = VectorHelper::createAxisFromRebinParams(getProperty("BinParams"), XValues_new.access()); //Prepare the binfinder class BinFinder binner( getProperty("BinParams") ); if (binner.lastBinIndex() != static_cast<int>(XValues_new.access().size()-1)) { std::stringstream msg; msg << "GhostCorrection: The binner found " << binner.lastBinIndex()+1 << " bins, but the X axis has " << XValues_new.access().size() << ". Try different binning parameters."; throw std::runtime_error(msg.str()); } //Create an output Workspace2D with group # of output spectra MatrixWorkspace_sptr outputW = WorkspaceFactory::Instance().create("Workspace2D", this->nGroups-1, numbins, numbins-1); WorkspaceFactory::Instance().initializeFromParent(inputW, outputW, true); //Set the X bins in the output WS. Workspace2D_sptr outputWS2D = boost::dynamic_pointer_cast<Workspace2D>(outputW); for (std::size_t i=0; i < outputWS2D->getNumberHistograms(); i++) outputWS2D->setX(i, XValues_new); //Prepare the maps you need input_detectorIDToWorkspaceIndexMap = inputW->getDetectorIDToWorkspaceIndexMap(true); //Load the ghostmapping file this->loadGhostMap( getProperty("GhostCorrectionFilename") ); //Initialize progress reporting. int64_t numsteps = 0; //count how many steps for (int64_t gr=1; gr < this->nGroups; ++gr) numsteps += this->groupedGhostMaps[gr]->size(); Progress prog(this, 0.0, 1.0, numsteps); //Set up the tof-to-d_spacing map for all pixel ids. this->tof_to_d = Mantid::Algorithms::AlignDetectors::calcTofToD_ConversionMap(inputW, offsetsWS); // Set the final unit that our output workspace will have outputW->getAxis(0)->unit() = UnitFactory::Instance().create("dSpacing"); //Go through the groups, starting at #1! PARALLEL_FOR2(inputW, outputW) for (int64_t gr=1; gr < this->nGroups; ++gr) { PARALLEL_START_INTERUPT_REGION //TODO: Convert between group # and workspace index. Sigh. //Groups normally start at 1 and so the workspace index will be one below that. int64_t outputWorkspaceIndex = gr-1; //Start by making sure the Y and E values are 0. MantidVec& Y = outputW->dataY(outputWorkspaceIndex); MantidVec& E = outputW->dataE(outputWorkspaceIndex); Y.assign(Y.size(), 0.0); E.assign(E.size(), 0.0); //Perform the GhostCorrection //Ok, this map has as keys the source workspace indices GhostSourcesMap * thisGroupsGhostMap = this->groupedGhostMaps[gr]; GhostSourcesMap::iterator it; for (it = thisGroupsGhostMap->begin(); it != thisGroupsGhostMap->end(); ++it) { //This workspace index is causing 16 ghosts in this group. int64_t inputWorkspaceIndex = it->first; int64_t inputDetectorID = it->second; //This is the events in the pixel CAUSING the ghost. const EventList & sourceEventList = inputW->getEventList(inputWorkspaceIndex); //Now get the actual vector of tofevents const std::vector<TofEvent>& events = sourceEventList.getEvents(); size_t numEvents = events.size(); //Go through all events. for (size_t i=0; i < numEvents; i++) { const TofEvent& event = events[i]; for (int64_t g=0; g < NUM_GHOSTS; g++) { //Find the ghost correction int64_t fileIndex = inputDetectorID * NUM_GHOSTS + g; GhostDestinationValue ghostVal = (*rawGhostMap)[fileIndex]; //Convert to d-spacing using the factor of the GHOST pixel id double d_spacing = event.tof() * (*tof_to_d)[ghostVal.pixelId]; //Find the bin for this d-spacing int64_t binIndex = binner.bin(d_spacing); if (binIndex >= 0) { //Slap it in the Y array for this group; use the weight. Y[binIndex] += ghostVal.weight; } } //for each ghost } //for each event //Report progress prog.report(); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Assign the workspace to the output workspace property setProperty("OutputWorkspace", outputW); }
/** @ throw invalid_argument if the workspaces are not mututially compatible */ void Q1D2::exec() { m_dataWS = getProperty("DetBankWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj"); const bool doGravity = getProperty("AccountForGravity"); m_doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(m_dataWS, waveAdj, pixelAdj); // FIXME: how to examine the wavePixelAdj? g_log.debug() << "All input workspaces were found to be valid\n"; // normalization as a function of wavelength (i.e. centers of x-value bins) double const * const binNorms = waveAdj ? &(waveAdj->readY(0)[0]) : NULL; // error on the wavelength normalization double const * const binNormEs = waveAdj ? &(waveAdj->readE(0)[0]) : NULL; //define the (large number of) data objects that are going to be used in all iterations of the loop below // this will become the output workspace from this algorithm MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning")); const MantidVec & QOut = outputWS->readX(0); MantidVec & YOut = outputWS->dataY(0); MantidVec & EOutTo2 = outputWS->dataE(0); // normalisation that is applied to counts in each Q bin MantidVec normSum(YOut.size(), 0.0); // the error on the normalisation MantidVec normError2(YOut.size(), 0.0); const int numSpec = static_cast<int>(m_dataWS->getNumberHistograms()); Progress progress(this, 0.05, 1.0, numSpec+1); PARALLEL_FOR3(m_dataWS, outputWS, pixelAdj) for (int i = 0; i < numSpec; ++i) { PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = m_dataWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i)->getSpectrumNo() << ") 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 detector is masked shouldn't be included 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 = waveLengthCutOff(i); const size_t wavStart = helper.waveLengthCutOff(m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= m_dataWS->readY(i).size()) { // all the spectra in this detector are out of range continue; } const size_t numWavbins = m_dataWS->readY(i).size()-wavStart; // make just one call to new to reduce CPU overhead on each thread, access to these // three "arrays" is via iterators MantidVec _noDirectUseStorage_(3*numWavbins); //normalization term MantidVec::iterator norms = _noDirectUseStorage_.begin(); // the error on these weights, it contributes to the error calculation on the output workspace MantidVec::iterator normETo2s = norms + numWavbins; // the Q values calculated from input wavelength workspace MantidVec::iterator QIn = normETo2s + numWavbins; // the weighting for this input spectrum that is added to the normalization calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s); // now read the data from the input workspace, calculate Q for each bin convertWavetoQ(i, doGravity, wavStart, QIn); // Pointers to the counts data and it's error MantidVec::const_iterator YIn = m_dataWS->readY(i).begin()+wavStart; MantidVec::const_iterator EIn = m_dataWS->readE(i).begin()+wavStart; //when finding the output Q bin remember that the input Q bins (from the convert to wavelength) start high and reduce MantidVec::const_iterator loc = QOut.end(); // sum the Q contributions from each individual spectrum into the output array const MantidVec::const_iterator end = m_dataWS->readY(i).end(); for( ; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) { //find the output bin that each input y-value will fall into, remembering there is one more bin boundary than bins getQBinPlus1(QOut, *QIn, loc); // ignore counts that are out of the output range if ( (loc != QOut.begin()) && (loc != QOut.end()) ) { // the actual Q-bin to add something to const size_t bin = loc - QOut.begin() - 1; PARALLEL_CRITICAL(q1d_counts_sum) { YOut[bin] += *YIn; normSum[bin] += *norms; //these are the errors squared which will be summed and square rooted at the end EOutTo2[bin] += (*EIn)*(*EIn); normError2[bin] += *normETo2s; } } } PARALLEL_CRITICAL(q1d_spectra_map) { progress.report("Computing I(Q)"); // Add up the detector IDs in the output spectrum at workspace index 0 const ISpectrum * inSpec = m_dataWS->getSpectrum(i); ISpectrum * outSpec = outputWS->getSpectrum(0); outSpec->addDetectorIDs( inSpec->getDetectorIDs() ); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS); ws_sumOfCounts->dataX(0) = outputWS->dataX(0); ws_sumOfCounts->dataY(0) = outputWS->dataY(0); for (size_t i = 0; i < outputWS->dataE(0).size(); i++) { ws_sumOfCounts->dataE(0)[i] = sqrt(outputWS->dataE(0)[i]); } MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS); ws_sumOfNormFactors->dataX(0) = outputWS->dataX(0); for (size_t i = 0; i < ws_sumOfNormFactors->dataY(0).size(); i++) { ws_sumOfNormFactors->dataY(0)[i] = normSum[i]; ws_sumOfNormFactors->dataE(0)[i] = sqrt(normError2[i]); } helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors); } progress.report("Normalizing I(Q)"); //finally divide the number of counts in each output Q bin by its weighting normalize(normSum, normError2, YOut, EOutTo2); outputWS->updateSpectraUsingMap(); setProperty("OutputWorkspace",outputWS); }
/** Execute the algorithm. */ void LoadNXSPE::exec() { std::string filename = getProperty("Filename"); // quicly check if it's really nxspe try { ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openData("definition"); if (identiferConfidence(file.getStrData()) < 1) { throw std::invalid_argument("Not NXSPE"); } file.close(); } catch (...) { throw std::invalid_argument("Not NeXus or not NXSPE"); } // Load the data ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openGroup("NXSPE_info", "NXcollection"); std::map<std::string, std::string> entries = file.getEntries(); std::vector<double> temporary; double fixed_energy, psi = 0.; if (!entries.count("fixed_energy")) { throw std::invalid_argument("fixed_energy field was not found"); } file.openData("fixed_energy"); file.getData(temporary); fixed_energy = temporary.at(0); file.closeData(); if (entries.count("psi")) { file.openData("psi"); file.getData(temporary); psi = temporary.at(0); file.closeData(); } int kikfscaling = 0; if (entries.count("ki_over_kf_scaling")) { file.openData("ki_over_kf_scaling"); std::vector<int> temporaryint; file.getData(temporaryint); kikfscaling = temporaryint.at(0); file.closeData(); } file.closeGroup(); // NXSPE_Info file.openGroup("data", "NXdata"); entries = file.getEntries(); if (!entries.count("data")) { throw std::invalid_argument("data field was not found"); } file.openData("data"); ::NeXus::Info info = file.getInfo(); std::size_t numSpectra = static_cast<std::size_t>(info.dims.at(0)); std::size_t numBins = static_cast<std::size_t>(info.dims.at(1)); std::vector<double> data; file.getData(data); file.closeData(); if (!entries.count("error")) { throw std::invalid_argument("error field was not found"); } file.openData("error"); std::vector<double> error; file.getData(error); file.closeData(); if (!entries.count("energy")) { throw std::invalid_argument("energy field was not found"); } file.openData("energy"); std::vector<double> energies; file.getData(energies); file.closeData(); if (!entries.count("azimuthal")) { throw std::invalid_argument("azimuthal field was not found"); } file.openData("azimuthal"); std::vector<double> azimuthal; file.getData(azimuthal); file.closeData(); if (!entries.count("azimuthal_width")) { throw std::invalid_argument("azimuthal_width field was not found"); } file.openData("azimuthal_width"); std::vector<double> azimuthal_width; file.getData(azimuthal_width); file.closeData(); if (!entries.count("polar")) { throw std::invalid_argument("polar field was not found"); } file.openData("polar"); std::vector<double> polar; file.getData(polar); file.closeData(); if (!entries.count("polar_width")) { throw std::invalid_argument("polar_width field was not found"); } file.openData("polar_width"); std::vector<double> polar_width; file.getData(polar_width); file.closeData(); // distance might not have been saved in all NXSPE files std::vector<double> distance; if (entries.count("distance")) { file.openData("distance"); file.getData(distance); file.closeData(); } file.closeGroup(); // data group file.closeGroup(); // Main entry file.close(); // check if dimensions of the vectors are correct if ((error.size() != data.size()) || (azimuthal.size() != numSpectra) || (azimuthal_width.size() != numSpectra) || (polar.size() != numSpectra) || (polar_width.size() != numSpectra) || ((energies.size() != numBins) && (energies.size() != numBins + 1))) { throw std::invalid_argument( "incompatible sizes of fields in the NXSPE file"); } MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", numSpectra, energies.size(), numBins)); // Need to get hold of the parameter map outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE"); outputWS->setYUnit("SpectraNumber"); // add logs outputWS->mutableRun().addLogData( new PropertyWithValue<double>("Ei", fixed_energy)); outputWS->mutableRun().addLogData(new PropertyWithValue<double>("psi", psi)); outputWS->mutableRun().addLogData(new PropertyWithValue<std::string>( "ki_over_kf_scaling", kikfscaling == 1 ? "true" : "false")); // Set Goniometer Geometry::Goniometer gm; gm.pushAxis("psi", 0, 1, 0, psi); outputWS->mutableRun().setGoniometer(gm, true); // generate instrument Geometry::Instrument_sptr instrument(new Geometry::Instrument("NXSPE")); outputWS->setInstrument(instrument); Geometry::ObjComponent *source = new Geometry::ObjComponent("source"); source->setPos(0.0, 0.0, -10.0); instrument->add(source); instrument->markAsSource(source); Geometry::ObjComponent *sample = new Geometry::ObjComponent("sample"); instrument->add(sample); instrument->markAsSamplePos(sample); Geometry::Object_const_sptr cuboid( createCuboid(0.1, 0.1, 0.1)); // FIXME: memory hog on rendering. Also, // make each detector separate size for (std::size_t i = 0; i < numSpectra; ++i) { double r = 1.0; if (!distance.empty()) { r = distance.at(i); } Kernel::V3D pos; pos.spherical(r, polar.at(i), azimuthal.at(i)); Geometry::Detector *det = new Geometry::Detector("pixel", static_cast<int>(i + 1), sample); det->setPos(pos); det->setShape(cuboid); instrument->add(det); instrument->markAsDetector(det); } Geometry::ParameterMap &pmap = outputWS->instrumentParameters(); std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(), itdataend, iterrorend; API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra); for (std::size_t i = 0; i < numSpectra; ++i) { itdataend = itdata + numBins; iterrorend = iterror + numBins; outputWS->dataX(i) = energies; if ((!boost::math::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin { outputWS->dataY(i) = std::vector<double>(numBins, 0); outputWS->dataE(i) = std::vector<double>(numBins, 0); pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true); } else { outputWS->dataY(i) = std::vector<double>(itdata, itdataend); outputWS->dataE(i) = std::vector<double>(iterror, iterrorend); } itdata = (itdataend); iterror = (iterrorend); prog.report(); } setProperty("OutputWorkspace", outputWS); }
/** Executes the algorithm * * @throw runtime_error Thrown if algorithm cannot execute */ void MaxMin::exec() { // Try and retrieve the optional properties m_MinRange = getProperty("RangeLower"); m_MaxRange = getProperty("RangeUpper"); m_MinSpec = getProperty("StartWorkspaceIndex"); m_MaxSpec = getProperty("EndWorkspaceIndex"); showMin = getProperty("ShowMin"); // Get the input workspace MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace"); const int numberOfSpectra = static_cast<int>(localworkspace->getNumberHistograms()); // Check 'StartSpectrum' is in range 0-numberOfSpectra if ( m_MinSpec > numberOfSpectra ) { g_log.warning("StartSpectrum out of range! Set to 0."); m_MinSpec = 0; } if ( isEmpty(m_MaxSpec) ) m_MaxSpec = numberOfSpectra-1; if ( m_MaxSpec > numberOfSpectra-1 || m_MaxSpec < m_MinSpec ) { g_log.warning("EndSpectrum out of range! Set to max detector number"); m_MaxSpec = numberOfSpectra; } if ( m_MinRange > m_MaxRange ) { g_log.warning("Range_upper is less than Range_lower. Will integrate up to frame maximum."); m_MaxRange = 0.0; } // Create the 1D workspace for the output MatrixWorkspace_sptr outputWorkspace = API::WorkspaceFactory::Instance().create(localworkspace,m_MaxSpec-m_MinSpec+1,2,1); Progress progress(this,0,1,(m_MaxSpec-m_MinSpec+1)); PARALLEL_FOR2(localworkspace,outputWorkspace) // Loop over spectra for (int i = m_MinSpec; i <= m_MaxSpec; ++i) { PARALLEL_START_INTERUPT_REGION int newindex=i-m_MinSpec; // Copy over spectrum and detector number info outputWorkspace->getSpectrum(newindex)->copyInfoFrom(*localworkspace->getSpectrum(i)); // Retrieve the spectrum into a vector const MantidVec& X = localworkspace->readX(i); const MantidVec& Y = localworkspace->readY(i); // Find the range [min,max] MantidVec::const_iterator lowit, highit; if (m_MinRange == EMPTY_DBL()) lowit=X.begin(); else lowit=std::lower_bound(X.begin(),X.end(),m_MinRange); if (m_MaxRange == EMPTY_DBL()) highit=X.end(); else highit=std::find_if(lowit,X.end(),std::bind2nd(std::greater<double>(),m_MaxRange)); // If range specified doesn't overlap with this spectrum then bail out if ( lowit == X.end() || highit == X.begin() ) continue; --highit; // Upper limit is the bin before, i.e. the last value smaller than MaxRange MantidVec::difference_type distmin=std::distance(X.begin(),lowit); MantidVec::difference_type distmax=std::distance(X.begin(),highit); MantidVec::const_iterator maxY; // Find the max/min element if (showMin==true) { maxY=std::min_element(Y.begin()+distmin,Y.begin()+distmax); } else { maxY=std::max_element(Y.begin()+distmin,Y.begin()+distmax); } MantidVec::difference_type d=std::distance(Y.begin(),maxY); // X boundaries for the max/min element outputWorkspace->dataX(newindex)[0]=*(X.begin()+d); outputWorkspace->dataX(newindex)[1]=*(X.begin()+d+1); //This is safe since X is of dimension Y+1 outputWorkspace->dataY(newindex)[0]=*maxY; progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Assign it to the output workspace property setProperty("OutputWorkspace",outputWorkspace); return; }
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]; } } }
/** Read a data file that contains only one spectrum into a workspace * @return the new workspace */ const API::MatrixWorkspace_sptr LoadRKH::read1D() { g_log.information() << "file appears to contain 1D information, reading in 1D data mode\n"; //The 3rd line contains information regarding the number of points in the file and // start and end reading points int totalPoints(0), readStart(0), readEnd(0), buried(0); std::string fileline; getline(m_fileIn, fileline); std::istringstream is(fileline); //Get data information for( int counter = 1; counter < 8; ++counter ) { switch( counter ) { case 1: is >> totalPoints; break; case 5: is >> readStart; break; case 6: is >> readEnd; break; default: is >> buried; break; } } g_log.information() << "Total number of data points declared to be in the data file: " << totalPoints << "\n"; //What are we reading? std::string firstColVal = getProperty("FirstColumnValue"); bool colIsUnit(true); if( m_RKHKeys.find( firstColVal ) != m_RKHKeys.end() ) { colIsUnit = false; readStart = 1; readEnd = totalPoints; } if( readStart < 1 || readEnd < 1 || readEnd < readStart || readStart > totalPoints || readEnd > totalPoints ) { g_log.error("Invalid data range specfied."); m_fileIn.close(); throw std::invalid_argument("Invalid data range specfied."); } g_log.information() << "Reading started on data line: " << readStart << "\n"; g_log.information() << "Reading finished on data line: " << readEnd << "\n"; //The 4th and 5th line do not contain useful information either skipLines(m_fileIn, 2); int pointsToRead = readEnd - readStart + 1; //Now stream sits at the first line of data fileline = ""; std::vector<double> columnOne, ydata, errdata; columnOne.reserve(readEnd); ydata.reserve(readEnd); errdata.reserve(readEnd); Progress prog(this,0.0,1.0,readEnd); for( int index = 1; index <= readEnd; ++index ) { getline(m_fileIn, fileline); if( index < readStart ) continue; double x(0.), y(0.), yerr(0.); std::istringstream datastr(fileline); datastr >> x >> y >> yerr; columnOne.push_back(x); ydata.push_back(y); errdata.push_back(yerr); prog.report(); } m_fileIn.close(); assert( pointsToRead == static_cast<int>(columnOne.size()) ); assert( pointsToRead == static_cast<int>(ydata.size()) ); assert( pointsToRead == static_cast<int>(errdata.size()) ); if( colIsUnit ) { MatrixWorkspace_sptr localworkspace = WorkspaceFactory::Instance().create("Workspace2D", 1, pointsToRead, pointsToRead); localworkspace->getAxis(0)->unit() = UnitFactory::Instance().create(firstColVal); localworkspace->dataX(0) = columnOne; localworkspace->dataY(0) = ydata; localworkspace->dataE(0) = errdata; return localworkspace; } else { MatrixWorkspace_sptr localworkspace = WorkspaceFactory::Instance().create("Workspace2D", pointsToRead, 1, 1); //Set the appropriate values for( int index = 0; index < pointsToRead; ++index ) { localworkspace->getAxis(1)->setValue(index, static_cast<int>(columnOne[index])); localworkspace->dataY(index)[0] = ydata[index]; localworkspace->dataE(index)[0] = errdata[index]; } return localworkspace; } }
void Linear::exec() { // Get the input workspace MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); // Get the spectrum to fit const int histNumber = getProperty("WorkspaceIndex"); // Check validity if ( histNumber >= static_cast<int>(inputWorkspace->getNumberHistograms()) ) { g_log.error() << "WorkspaceIndex set to an invalid value of " << histNumber << std::endl; throw Exception::IndexError(histNumber,inputWorkspace->getNumberHistograms(),"Linear WorkspaceIndex property"); } // Get references to the data in the chosen spectrum const MantidVec& X = inputWorkspace->dataX(histNumber); const MantidVec& Y = inputWorkspace->dataY(histNumber); const MantidVec& E = inputWorkspace->dataE(histNumber); // Check if this spectrum has errors double errorsCount = 0.0; // Retrieve the Start/EndX properties, if set this->setRange(X,Y); const bool isHistogram = inputWorkspace->isHistogramData(); // If the spectrum to be fitted has masked bins, we want to exclude them (even if only partially masked) const MatrixWorkspace::MaskList * const maskedBins = ( inputWorkspace->hasMaskedBins(histNumber) ? &(inputWorkspace->maskedBins(histNumber)) : NULL ); // Put indices of masked bins into a set for easy searching later std::set<size_t> maskedIndices; if (maskedBins) { MatrixWorkspace::MaskList::const_iterator it; for (it = maskedBins->begin(); it != maskedBins->end(); ++it) maskedIndices.insert(it->first); } progress(0); // Declare temporary vectors and reserve enough space if they're going to be used std::vector<double> XCen, unmaskedY, weights; int numPoints = m_maxX - m_minX; if (isHistogram) XCen.reserve(numPoints); if (maskedBins) unmaskedY.reserve(numPoints); weights.reserve(numPoints); for (int i = 0; i < numPoints; ++i) { // If the current bin is masked, skip it if ( maskedBins && maskedIndices.count(m_minX+i) ) continue; // Need to adjust X to centre of bin, if a histogram if (isHistogram) XCen.push_back( 0.5*(X[m_minX+i]+X[m_minX+i+1]) ); // If there are masked bins present, we need to copy the unmasked Y values if (maskedBins) unmaskedY.push_back(Y[m_minX+i]); // GSL wants the errors as weights, i.e. 1/sigma^2 // We need to be careful if E is zero because that would naively lead to an infinite weight on the point. // Solution taken here is to zero weight if error is zero, which typically means Y is zero // (so it is effectively excluded from the fit). const double& currentE = E[m_minX+i]; weights.push_back( currentE ? 1.0/(currentE*currentE) : 0.0 ); // However, if the spectrum given has all errors of zero, then we should use the gsl function that // doesn't take account of the errors. if ( currentE ) ++errorsCount; } progress(0.3); // If masked bins present, need to recalculate numPoints here if (maskedBins) numPoints = static_cast<int>(unmaskedY.size()); // If no points left for any reason, bail out if (numPoints == 0) { g_log.error("No points in this range to fit"); throw std::runtime_error("No points in this range to fit"); } // Set up pointer variables to pass to gsl, pointing them to the right place const double * const xVals = ( isHistogram ? &XCen[0] : &X[m_minX] ); const double * const yVals = ( maskedBins ? &unmaskedY[0] : &Y[m_minX] ); // Call the gsl fitting function // The stride value of 1 reflects that fact that we want every element of our input vectors const int stride = 1; double *c0(new double),*c1(new double),*cov00(new double),*cov01(new double),*cov11(new double),*chisq(new double); int status; // Unless our spectrum has error values for vast majority of points, // call the gsl function that doesn't use errors if ( errorsCount/numPoints < 0.9 ) { g_log.debug("Calling gsl_fit_linear (doesn't use errors in fit)"); status = gsl_fit_linear(xVals,stride,yVals,stride,numPoints,c0,c1,cov00,cov01,cov11,chisq); } // Otherwise, call the one that does account for errors on the data points else { g_log.debug("Calling gsl_fit_wlinear (uses errors in fit)"); status = gsl_fit_wlinear(xVals,stride,&weights[0],stride,yVals,stride,numPoints,c0,c1,cov00,cov01,cov11,chisq); } progress(0.8); // Check that the fit succeeded std::string fitStatus = gsl_strerror(status); // For some reason, a fit where c0,c1 & chisq are all infinity doesn't report as a // failure, so check explicitly. if ( !gsl_finite(*chisq) || !gsl_finite(*c0) || !gsl_finite(*c1) ) fitStatus = "Fit gives infinities"; if (fitStatus != "success") g_log.error() << "The fit failed: " << fitStatus << "\n"; else g_log.information() << "The fit succeeded, giving y = " << *c0 << " + " << *c1 << "*x, with a Chi^2 of " << *chisq << "\n"; // Set the fit result output properties setProperty("FitStatus",fitStatus); setProperty("FitIntercept",*c0); setProperty("FitSlope",*c1); setProperty("Cov00",*cov00); setProperty("Cov11",*cov11); setProperty("Cov01",*cov01); setProperty("Chi2",*chisq); // Create and fill a workspace2D with the same bins as the fitted spectrum and the value of the fit for the centre of each bin const size_t YSize = Y.size(); MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace,1,X.size(),YSize); // Copy over the X bins outputWorkspace->dataX(0).assign(X.begin(),X.end()); // Now loop over the spectrum and use gsl function to calculate the Y & E values for the function for (size_t i = 0; i < YSize; ++i) { const double x = ( isHistogram ? 0.5*(X[i]+X[i+1]) : X[i] ); const int err = gsl_fit_linear_est(x,*c0,*c1,*cov00,*cov01,*cov11,&(outputWorkspace->dataY(0)[i]),&(outputWorkspace->dataE(0)[i])); if (err) g_log.warning() << "Problem in filling the output workspace: " << gsl_strerror(err) << std::endl; } setProperty("OutputWorkspace",outputWorkspace); progress(1); // Clean up delete c0; delete c1; delete cov00; delete cov01; delete cov11; delete chisq; }
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"); }
/** Filter non-background data points out and create a background workspace */ Workspace2D_sptr ProcessBackground::filterForBackground(BackgroundFunction_sptr bkgdfunction) { double posnoisetolerance = getProperty("NoiseTolerance"); double negnoisetolerance = getProperty("NegativeNoiseTolerance"); if (isEmpty(negnoisetolerance)) negnoisetolerance = posnoisetolerance; // Calcualte theoretical values const std::vector<double> x = m_dataWS->readX(m_wsIndex); API::FunctionDomain1DVector domain(x); API::FunctionValues values(domain); bkgdfunction->function(domain, values); g_log.information() << "Function used to select background points : " << bkgdfunction->asString() << "\n"; // Optional output string userbkgdwsname = getPropertyValue("UserBackgroundWorkspace"); if (userbkgdwsname.size() == 0) throw runtime_error("In mode SelectBackgroundPoints, " "UserBackgroundWorkspace must be given!"); size_t sizex = domain.size(); size_t sizey = values.size(); MatrixWorkspace_sptr visualws = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", 4, sizex, sizey)); for (size_t i = 0; i < sizex; ++i) { for (size_t j = 0; j < 4; ++j) { visualws->dataX(j)[i] = domain[i]; } } for (size_t i = 0; i < sizey; ++i) { visualws->dataY(0)[i] = values[i]; visualws->dataY(1)[i] = m_dataWS->readY(m_wsIndex)[i] - values[i]; visualws->dataY(2)[i] = posnoisetolerance; visualws->dataY(3)[i] = -negnoisetolerance; } setProperty("UserBackgroundWorkspace", visualws); // Filter for background std::vector<double> vecx, vecy, vece; for (size_t i = 0; i < domain.size(); ++i) { // double y = m_dataWS->readY(m_wsIndex)[i]; // double theoryy = values[i]; y-theoryy double purey = visualws->readY(1)[i]; if (purey < posnoisetolerance && purey > -negnoisetolerance) { // Selected double x = domain[i]; double y = m_dataWS->readY(m_wsIndex)[i]; double e = m_dataWS->readE(m_wsIndex)[i]; vecx.push_back(x); vecy.push_back(y); vece.push_back(e); } } g_log.information() << "Found " << vecx.size() << " background points out of " << m_dataWS->readX(m_wsIndex).size() << " total data points. " << "\n"; // Build new workspace for OutputWorkspace size_t nspec = 3; Workspace2D_sptr outws = boost::dynamic_pointer_cast<DataObjects::Workspace2D>( API::WorkspaceFactory::Instance().create("Workspace2D", nspec, vecx.size(), vecy.size())); for (size_t i = 0; i < vecx.size(); ++i) { for (size_t j = 0; j < nspec; ++j) outws->dataX(j)[i] = vecx[i]; outws->dataY(0)[i] = vecy[i]; outws->dataE(0)[i] = vece[i]; } return outws; }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("Workspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getProperty("SigmaModerator"); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0); const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; for (size_t i = 0; i < xInterpolate.size() - 1; ++i) { const double midpoint = xInterpolate[i + 1] - xInterpolate[i]; lookUpTable.addPoint(midpoint, yInterpolate[i]); } } else { for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } } const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; } // 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 scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1 + L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * (3.0 * R1 * R1 / (L1 * L1) + 3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) + (deltaR * deltaR) / (L2 * L2)); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin(theta / 2.0); const MantidVec &xIn = inOutWS->readX(i); MantidVec &yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // wavelenght spread from moderatorm, converted from microseconds to // wavelengths const double sigmaModerator = lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum); // calculate wavelenght resolution from moderator and histogram time bin const double sigmaLambda = std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 + sigmaModerator * sigmaModerator); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl; const double sigmaQ = std::sqrt( dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); } }