/** 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 }
/** * 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::rebinToFractionalOutput(const Geometry::Quadrilateral & inputQ, MatrixWorkspace_const_sptr inputWS, const size_t i, const size_t j, RebinnedOutput_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(); // Don't do the overlap removal if already RebinnedOutput. // This wreaks havoc on the data. if(inputWS->isDistribution() && inputWS->id() != "RebinnedOutput") { yValue *= overlapWidth; eValue *= overlapWidth; } eValue *= eValue; PARALLEL_CRITICAL(overlap) { outputWS->dataY(qi)[ei] += yValue; outputWS->dataE(qi)[ei] += eValue; outputWS->dataF(qi)[ei] += weight; } } catch(Geometry::NoIntersectionException &) {} } } }
/* Execute the transformtion. Generates an output IMDEventWorkspace. @return the constructed IMDEventWorkspace following the transformation. @param ws: Input MatrixWorkspace const shared pointer */ IMDEventWorkspace_sptr ReflectometryTransformQxQz::execute(MatrixWorkspace_const_sptr inputWs) const { const size_t nbinsx = 10; const size_t nbinsz = 10; auto ws = boost::make_shared<MDEventWorkspace<MDLeanEvent<2>,2> >(); MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(new MDHistoDimension("Qx","qx","(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin), static_cast<Mantid::coord_t>(m_qxMax), nbinsx)); MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(new MDHistoDimension("Qz","qz","(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin), static_cast<Mantid::coord_t>(m_qzMax), nbinsz)); ws->addDimension(qxDim); ws->addDimension(qzDim); // Set some reasonable values for the box controller BoxController_sptr bc = ws->getBoxController(); bc->setSplitInto(2); bc->setSplitThreshold(10); // Initialize the workspace. ws->initialize(); // Start with a MDGridBox. ws->splitBox(); auto spectraAxis = inputWs->getAxis(1); for(size_t index = 0; index < inputWs->getNumberHistograms(); ++index) { auto counts = inputWs->readY(index); auto wavelengths = inputWs->readX(index); auto errors = inputWs->readE(index); const size_t nInputBins = wavelengths.size() -1; const double theta_final = spectraAxis->getValue(index); m_QxCalculation.setThetaFinal(theta_final); m_QzCalculation.setThetaFinal(theta_final); //Loop over all bins in spectra for(size_t binIndex = 0; binIndex < nInputBins; ++binIndex) { const double& wavelength = 0.5*(wavelengths[binIndex] + wavelengths[binIndex+1]); double _qx = m_QxCalculation.execute(wavelength); double _qz = m_QzCalculation.execute(wavelength); double centers[2] = {_qx, _qz}; ws->addEvent(MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex]*errors[binIndex]), centers)); } ws->splitAllIfNeeded(NULL); } return ws; }
void SaveNISTDAT::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); std::string filename = getPropertyValue("Filename"); // prepare to save to file std::ofstream out_File(filename.c_str()); if (!out_File) { g_log.error("Failed to open file:" + filename); throw Exception::FileError("Failed to open file:" , filename); } out_File << "Data columns Qx - Qy - I(Qx,Qy) - err(I)\r\n"; out_File << "ASCII data\r\n"; // Set up the progress reporting object Progress progress(this,0.0,1.0,2); progress.report("Save I(Qx,Qy)"); if ( inputWS->axes() > 1 && inputWS->getAxis(1)->isNumeric() ) { const Axis& axis = *inputWS->getAxis(1); for (size_t i = 0; i < axis.length()-1; i++) { const double qy = (axis(i)+axis(i+1))/2.0; const MantidVec& XIn = inputWS->readX(i); const MantidVec& YIn = inputWS->readY(i); const MantidVec& EIn = inputWS->readE(i); for ( size_t j = 0; j < XIn.size()-1; j++) { // Exclude NaNs if (YIn[j]==YIn[j]) { out_File << (XIn[j]+XIn[j+1])/2.0; out_File << " " << qy; out_File << " " << YIn[j]; out_File << " " << EIn[j] << "\r\n"; } } } } out_File.close(); progress.report("Save I(Qx,Qy)"); }
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); }
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 }
IMDHistoWorkspace_sptr ReflectometryTransform::executeMDNormPoly( MatrixWorkspace_const_sptr inputWs) const { auto input_x_dim = inputWs->getXDimension(); MDHistoDimension_sptr dim0 = MDHistoDimension_sptr(new MDHistoDimension( input_x_dim->getName(), input_x_dim->getDimensionId(), input_x_dim->getMDFrame(), static_cast<Mantid::coord_t>(input_x_dim->getMinimum()), static_cast<Mantid::coord_t>(input_x_dim->getMaximum()), input_x_dim->getNBins())); auto input_y_dim = inputWs->getYDimension(); MDHistoDimension_sptr dim1 = MDHistoDimension_sptr(new MDHistoDimension( input_y_dim->getName(), input_y_dim->getDimensionId(), input_y_dim->getMDFrame(), static_cast<Mantid::coord_t>(input_y_dim->getMinimum()), static_cast<Mantid::coord_t>(input_y_dim->getMaximum()), input_y_dim->getNBins())); auto outWs = boost::make_shared<MDHistoWorkspace>(dim0, dim1); for (size_t nHistoIndex = 0; nHistoIndex < inputWs->getNumberHistograms(); ++nHistoIndex) { const MantidVec X = inputWs->readX(nHistoIndex); const MantidVec Y = inputWs->readY(nHistoIndex); const MantidVec E = inputWs->readE(nHistoIndex); for (size_t nBinIndex = 0; nBinIndex < inputWs->blocksize(); ++nBinIndex) { auto value_index = outWs->getLinearIndex(nBinIndex, nHistoIndex); outWs->setSignalAt(value_index, Y[nBinIndex]); outWs->setErrorSquaredAt(value_index, E[nBinIndex] * E[nBinIndex]); } } return outWs; }
/** * 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); } } }
/** @ 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); }
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"); }
/** * Enable points that were disabled for fit * @param destWs :: Workspace to enable points in * @param sourceWs :: Workspace with original errors */ void ALCBaselineModellingModel::enableDisabledPoints (MatrixWorkspace_sptr destWs, MatrixWorkspace_const_sptr sourceWs) { // Unwanted points were disabled by setting their errors to very high values. // We recover here the original errors stored in sourceWs destWs->dataE(0) = sourceWs->readE(0); }
/** Executes the algorithm * * @throw runtime_error Thrown if algorithm cannot execute */ void Fit1D::exec() { // Custom initialization prepare(); // check if derivative defined in derived class bool isDerivDefined = true; gsl_matrix *M = NULL; try { const std::vector<double> inTest(m_parameterNames.size(), 1.0); std::vector<double> outTest(m_parameterNames.size()); const double xValuesTest = 0; JacobianImpl J; M = gsl_matrix_alloc(m_parameterNames.size(), 1); J.setJ(M); // note nData set to zero (last argument) hence this should avoid further // memory problems functionDeriv(&(inTest.front()), &J, &xValuesTest, 0); } catch (Exception::NotImplementedError &) { isDerivDefined = false; } gsl_matrix_free(M); // Try to retrieve optional properties int histNumber = getProperty("WorkspaceIndex"); const int maxInterations = getProperty("MaxIterations"); // Get the input workspace MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace"); // number of histogram is equal to the number of spectra const size_t numberOfSpectra = localworkspace->getNumberHistograms(); // Check that the index given is valid if (histNumber >= static_cast<int>(numberOfSpectra)) { g_log.warning("Invalid Workspace index given, using first Workspace"); histNumber = 0; } // Retrieve the spectrum into a vector const MantidVec &XValues = localworkspace->readX(histNumber); const MantidVec &YValues = localworkspace->readY(histNumber); const MantidVec &YErrors = localworkspace->readE(histNumber); // Read in the fitting range data that we were sent double startX = getProperty("StartX"); double endX = getProperty("EndX"); // check if the values had been set, otherwise use defaults if (isEmpty(startX)) { startX = XValues.front(); modifyStartOfRange(startX); // does nothing by default but derived class may // provide a more intelligent value } if (isEmpty(endX)) { endX = XValues.back(); modifyEndOfRange(endX); // does nothing by default but derived class may // previde a more intelligent value } int m_minX; int m_maxX; // Check the validity of startX if (startX < XValues.front()) { g_log.warning("StartX out of range! Set to start of frame."); startX = XValues.front(); } // Get the corresponding bin boundary that comes before (or coincides with) // this value for (m_minX = 0; XValues[m_minX + 1] < startX; ++m_minX) { } // Check the validity of endX and get the bin boundary that come after (or // coincides with) it if (endX >= XValues.back() || endX < startX) { g_log.warning("EndX out of range! Set to end of frame"); endX = XValues.back(); m_maxX = static_cast<int>(YValues.size()); } else { for (m_maxX = m_minX; XValues[m_maxX] < endX; ++m_maxX) { } } afterDataRangedDetermined(m_minX, m_maxX); // create and populate GSL data container warn user if l_data.n < l_data.p // since as a rule of thumb this is required as a minimum to obtained // 'accurate' // fitting parameter values. FitData l_data(this, getProperty("Fix")); l_data.n = m_maxX - m_minX; // m_minX and m_maxX are array index markers. I.e. e.g. 0 & 19. if (l_data.n == 0) { g_log.error("The data set is empty."); throw std::runtime_error("The data set is empty."); } if (l_data.n < l_data.p) { g_log.error( "Number of data points less than number of parameters to be fitted."); throw std::runtime_error( "Number of data points less than number of parameters to be fitted."); } l_data.X = new double[l_data.n]; l_data.sigmaData = new double[l_data.n]; l_data.forSimplexLSwrap = new double[l_data.n]; l_data.parameters = new double[nParams()]; // check if histogram data in which case use mid points of histogram bins const bool isHistogram = localworkspace->isHistogramData(); for (unsigned int i = 0; i < l_data.n; ++i) { if (isHistogram) l_data.X[i] = 0.5 * (XValues[m_minX + i] + XValues[m_minX + i + 1]); // take mid-point if histogram bin else l_data.X[i] = XValues[m_minX + i]; } l_data.Y = &YValues[m_minX]; // check that no error is negative or zero for (unsigned int i = 0; i < l_data.n; ++i) { if (YErrors[m_minX + i] <= 0.0) { l_data.sigmaData[i] = 1.0; } else l_data.sigmaData[i] = YErrors[m_minX + i]; } // create array of fitted parameter. Take these to those input by the user. // However, for doing the // underlying fitting it might be more efficient to actually perform the // fitting on some of other // form of the fitted parameters. For instance, take the Gaussian sigma // parameter. In practice it // in fact more efficient to perform the fitting not on sigma but 1/sigma^2. // The methods // modifyInitialFittedParameters() and modifyFinalFittedParameters() are used // to allow for this; // by default these function do nothing. m_fittedParameter.clear(); for (size_t i = 0; i < nParams(); i++) { m_fittedParameter.push_back(getProperty(m_parameterNames[i])); } modifyInitialFittedParameters( m_fittedParameter); // does nothing except if overwritten by derived class for (size_t i = 0; i < nParams(); i++) { l_data.parameters[i] = m_fittedParameter[i]; } // set-up initial guess for fit parameters gsl_vector *initFuncArg; initFuncArg = gsl_vector_alloc(l_data.p); for (size_t i = 0, j = 0; i < nParams(); i++) { if (l_data.active[i]) gsl_vector_set(initFuncArg, j++, m_fittedParameter[i]); } // set-up GSL container to be used with GSL simplex algorithm gsl_multimin_function gslSimplexContainer; gslSimplexContainer.n = l_data.p; // n here refers to number of parameters gslSimplexContainer.f = &gsl_costFunction; gslSimplexContainer.params = &l_data; // set-up GSL least squares container gsl_multifit_function_fdf f; f.f = &gsl_f; f.df = &gsl_df; f.fdf = &gsl_fdf; f.n = l_data.n; f.p = l_data.p; f.params = &l_data; // set-up remaining GSL machinery for least squared const gsl_multifit_fdfsolver_type *T = gsl_multifit_fdfsolver_lmsder; gsl_multifit_fdfsolver *s = NULL; if (isDerivDefined) { s = gsl_multifit_fdfsolver_alloc(T, l_data.n, l_data.p); gsl_multifit_fdfsolver_set(s, &f, initFuncArg); } // set-up remaining GSL machinery to use simplex algorithm const gsl_multimin_fminimizer_type *simplexType = gsl_multimin_fminimizer_nmsimplex; gsl_multimin_fminimizer *simplexMinimizer = NULL; gsl_vector *simplexStepSize = NULL; if (!isDerivDefined) { simplexMinimizer = gsl_multimin_fminimizer_alloc(simplexType, l_data.p); simplexStepSize = gsl_vector_alloc(l_data.p); gsl_vector_set_all(simplexStepSize, 1.0); // is this always a sensible starting step size? gsl_multimin_fminimizer_set(simplexMinimizer, &gslSimplexContainer, initFuncArg, simplexStepSize); } // finally do the fitting int iter = 0; int status; double finalCostFuncVal; double dof = static_cast<double>( l_data.n - l_data.p); // dof stands for degrees of freedom // Standard least-squares used if derivative function defined otherwise // simplex Progress prog(this, 0.0, 1.0, maxInterations); if (isDerivDefined) { do { iter++; status = gsl_multifit_fdfsolver_iterate(s); if (status) // break if error break; status = gsl_multifit_test_delta(s->dx, s->x, 1e-4, 1e-4); prog.report(); } while (status == GSL_CONTINUE && iter < maxInterations); double chi = gsl_blas_dnrm2(s->f); finalCostFuncVal = chi * chi / dof; // put final converged fitting values back into m_fittedParameter for (size_t i = 0, j = 0; i < nParams(); i++) if (l_data.active[i]) m_fittedParameter[i] = gsl_vector_get(s->x, j++); } else { do { iter++; status = gsl_multimin_fminimizer_iterate(simplexMinimizer); if (status) // break if error break; double size = gsl_multimin_fminimizer_size(simplexMinimizer); status = gsl_multimin_test_size(size, 1e-2); prog.report(); } while (status == GSL_CONTINUE && iter < maxInterations); finalCostFuncVal = simplexMinimizer->fval / dof; // put final converged fitting values back into m_fittedParameter for (unsigned int i = 0, j = 0; i < m_fittedParameter.size(); i++) if (l_data.active[i]) m_fittedParameter[i] = gsl_vector_get(simplexMinimizer->x, j++); } modifyFinalFittedParameters( m_fittedParameter); // do nothing except if overwritten by derived class // Output summary to log file std::string reportOfFit = gsl_strerror(status); g_log.information() << "Iteration = " << iter << "\n" << "Status = " << reportOfFit << "\n" << "Chi^2/DoF = " << finalCostFuncVal << "\n"; for (size_t i = 0; i < m_fittedParameter.size(); i++) g_log.information() << m_parameterNames[i] << " = " << m_fittedParameter[i] << " \n"; // also output summary to properties setProperty("OutputStatus", reportOfFit); setProperty("OutputChi2overDoF", finalCostFuncVal); for (size_t i = 0; i < m_fittedParameter.size(); i++) setProperty(m_parameterNames[i], m_fittedParameter[i]); std::string output = getProperty("Output"); if (!output.empty()) { // calculate covariance matrix if derivatives available gsl_matrix *covar(NULL); std::vector<double> standardDeviations; std::vector<double> sdExtended; if (isDerivDefined) { covar = gsl_matrix_alloc(l_data.p, l_data.p); gsl_multifit_covar(s->J, 0.0, covar); int iPNotFixed = 0; for (size_t i = 0; i < nParams(); i++) { sdExtended.push_back(1.0); if (l_data.active[i]) { sdExtended[i] = sqrt(gsl_matrix_get(covar, iPNotFixed, iPNotFixed)); iPNotFixed++; } } modifyFinalFittedParameters(sdExtended); for (size_t i = 0; i < nParams(); i++) if (l_data.active[i]) standardDeviations.push_back(sdExtended[i]); declareProperty( new WorkspaceProperty<API::ITableWorkspace>( "OutputNormalisedCovarianceMatrix", "", Direction::Output), "The name of the TableWorkspace in which to store the final " "covariance matrix"); setPropertyValue("OutputNormalisedCovarianceMatrix", output + "_NormalisedCovarianceMatrix"); Mantid::API::ITableWorkspace_sptr m_covariance = Mantid::API::WorkspaceFactory::Instance().createTable( "TableWorkspace"); m_covariance->addColumn("str", "Name"); std::vector<std::string> paramThatAreFitted; // used for populating 1st "name" column for (size_t i = 0; i < nParams(); i++) { if (l_data.active[i]) { m_covariance->addColumn("double", m_parameterNames[i]); paramThatAreFitted.push_back(m_parameterNames[i]); } } for (size_t i = 0; i < l_data.p; i++) { Mantid::API::TableRow row = m_covariance->appendRow(); row << paramThatAreFitted[i]; for (size_t j = 0; j < l_data.p; j++) { if (j == i) row << 1.0; else { row << 100.0 * gsl_matrix_get(covar, i, j) / sqrt(gsl_matrix_get(covar, i, i) * gsl_matrix_get(covar, j, j)); } } } setProperty("OutputNormalisedCovarianceMatrix", m_covariance); } declareProperty(new WorkspaceProperty<API::ITableWorkspace>( "OutputParameters", "", Direction::Output), "The name of the TableWorkspace in which to store the " "final fit parameters"); declareProperty( new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace", "", Direction::Output), "Name of the output Workspace holding resulting simlated spectrum"); setPropertyValue("OutputParameters", output + "_Parameters"); setPropertyValue("OutputWorkspace", output + "_Workspace"); // Save the final fit parameters in the output table workspace Mantid::API::ITableWorkspace_sptr m_result = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); m_result->addColumn("str", "Name"); m_result->addColumn("double", "Value"); if (isDerivDefined) m_result->addColumn("double", "Error"); Mantid::API::TableRow row = m_result->appendRow(); row << "Chi^2/DoF" << finalCostFuncVal; for (size_t i = 0; i < nParams(); i++) { Mantid::API::TableRow row = m_result->appendRow(); row << m_parameterNames[i] << m_fittedParameter[i]; if (isDerivDefined && l_data.active[i]) { // perhaps want to scale standard deviations with sqrt(finalCostFuncVal) row << sdExtended[i]; } } setProperty("OutputParameters", m_result); // Save the fitted and simulated spectra in the output workspace MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); int iSpec = getProperty("WorkspaceIndex"); const MantidVec &inputX = inputWorkspace->readX(iSpec); const MantidVec &inputY = inputWorkspace->readY(iSpec); int histN = isHistogram ? 1 : 0; Mantid::DataObjects::Workspace2D_sptr ws = boost::dynamic_pointer_cast<Mantid::DataObjects::Workspace2D>( Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 3, l_data.n + histN, l_data.n)); ws->setTitle(""); ws->getAxis(0)->unit() = inputWorkspace->getAxis(0) ->unit(); // UnitFactory::Instance().create("TOF"); for (int i = 0; i < 3; i++) ws->dataX(i) .assign(inputX.begin() + m_minX, inputX.begin() + m_maxX + histN); ws->dataY(0).assign(inputY.begin() + m_minX, inputY.begin() + m_maxX); MantidVec &Y = ws->dataY(1); MantidVec &E = ws->dataY(2); double *lOut = new double[l_data.n]; // to capture output from call to function() modifyInitialFittedParameters(m_fittedParameter); // does nothing except if // overwritten by derived // class function(&m_fittedParameter[0], lOut, l_data.X, l_data.n); modifyInitialFittedParameters(m_fittedParameter); // reverse the effect of // modifyInitialFittedParameters - if any for (unsigned int i = 0; i < l_data.n; i++) { Y[i] = lOut[i]; E[i] = l_data.Y[i] - Y[i]; } delete[] lOut; setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(ws)); if (isDerivDefined) gsl_matrix_free(covar); } // clean up dynamically allocated gsl stuff if (isDerivDefined) gsl_multifit_fdfsolver_free(s); else { gsl_vector_free(simplexStepSize); gsl_multimin_fminimizer_free(simplexMinimizer); } delete[] l_data.X; delete[] l_data.sigmaData; delete[] l_data.forSimplexLSwrap; delete[] l_data.parameters; gsl_vector_free(initFuncArg); return; }
/** * This function deals with the logic necessary for summing a Workspace2D. * @param localworkspace The input workspace for summing. * @param outSpec The spectrum for the summed output. * @param progress The progress indicator. * @param numSpectra The number of spectra contributed to the sum. * @param numMasked The spectra dropped from the summations because they are * masked. * @param numZeros The number of zero bins in histogram workspace or empty * spectra for event workspace. */ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, ISpectrum *outSpec, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get references to the output workspaces's data vectors MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = this->m_indices.begin(); it != this->m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= this->m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] / errsq; } else { nZeros[k]++; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k]; YError[k] += YErrors[k] * YErrors[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } }
void SANSDirectBeamScaling::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); const double beamRadius = getProperty("BeamRadius"); const double attTrans = getProperty("AttenuatorTransmission"); const double attTransErr = getProperty("AttenuatorTransmissionError"); // Extract the required spectra into separate workspaces std::vector<detid_t> udet; std::vector<size_t> index; udet.push_back(getProperty("BeamMonitor")); // Convert UDETs to workspace indices inputWS->getIndicesFromDetectorIDs(udet,index); if (index.size() < 1) { g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n"; throw std::invalid_argument("Could not find the incident beam monitor spectra\n"); } const int64_t numHists = inputWS->getNumberHistograms(); Progress progress(this,0.0,1.0,numHists); // Number of X bins const int64_t xLength = inputWS->readY(0).size(); // Monitor counts double monitor = 0.0; const MantidVec& MonIn = inputWS->readY(index[0]); for (int64_t j = 0; j < xLength; j++) monitor += MonIn[j]; const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos(); double counts = 0.0; double error = 0.0; int nPixels = 0; // Sample-detector distance for the contributing pixels double sdd = 0.0; for (int64_t i = 0; i < int64_t(numHists); ++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; 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); // Sum up all the counts V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0); const double pixelDistance = pos.Z(); pos.setZ(0.0); if (pos.norm() <= beamRadius) { // Correct data for all X bins for (int64_t j = 0; j < xLength; j++) { counts += YIn[j]; error += EIn[j]*EIn[j]; } nPixels += 1; sdd += pixelDistance; } progress.report("Absolute Scaling"); } // Get the average SDD for the counted pixels, and transform to mm. sdd = sdd/nPixels*1000.0; error = std::sqrt(error); // Transform from m to mm double sourceAperture = getProperty("SourceApertureRadius"); sourceAperture *= 1000.0; // Transform from m to mm double sampleAperture = getProperty("SampleApertureRadius"); sampleAperture *= 1000.0; //TODO: replace this by some meaningful value const double KCG2FluxPerMon_SUGAR = 1.0; // Solid angle correction scale in 1/(cm^2)/steradian double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture); solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0; // Scaling factor in n/(monitor count)/(cm^2)/steradian double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) ); scale /= attTrans; std::vector<double> output; output.push_back(scale); output.push_back(scaleErr); setProperty("ScaleFactor", output); }
/** Executes the rebin algorithm * * @throw runtime_error Thrown if */ void Rebunch::exec() { // retrieve the properties int n_bunch=getProperty("NBunch"); // Get the input workspace MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace"); bool dist = inputW->isDistribution(); // workspace independent determination of length int histnumber = static_cast<int>(inputW->size()/inputW->blocksize()); /* const std::vector<double>& Xold = inputW->readX(0); const std::vector<double>& Yold = inputW->readY(0); int size_x=Xold.size(); int size_y=Yold.size(); */ int size_x = static_cast<int>(inputW->readX(0).size()); int size_y = static_cast<int>(inputW->readY(0).size()); //signal is the same length for histogram and point data int ny=(size_y/n_bunch); if(size_y%n_bunch >0)ny+=1; // default is for hist int nx=ny+1; bool point=false; if (size_x==size_y) { point=true; nx=ny; } // make output Workspace the same type is the input, but with new length of signal array API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(inputW,histnumber,nx,ny); int progress_step = histnumber / 100; if (progress_step == 0) progress_step = 1; PARALLEL_FOR2(inputW,outputW) for (int hist=0; hist < histnumber;hist++) { PARALLEL_START_INTERUPT_REGION // Ensure that axis information are copied to the output workspace if the axis exists try { outputW->getAxis(1)->spectraNo(hist)=inputW->getAxis(1)->spectraNo(hist); } catch( Exception::IndexError& ) { // Not a Workspace2D } // get const references to input Workspace arrays (no copying) const MantidVec& XValues = inputW->readX(hist); const MantidVec& YValues = inputW->readY(hist); const MantidVec& YErrors = inputW->readE(hist); //get references to output workspace data (no copying) MantidVec& XValues_new=outputW->dataX(hist); MantidVec& YValues_new=outputW->dataY(hist); MantidVec& YErrors_new=outputW->dataE(hist); // output data arrays are implicitly filled by function if(point) { rebunch_point(XValues,YValues,YErrors,XValues_new,YValues_new,YErrors_new,n_bunch); } else { rebunch_hist(XValues,YValues,YErrors,XValues_new,YValues_new,YErrors_new,n_bunch, dist); } if (hist % progress_step == 0) { progress(double(hist)/histnumber); interruption_point(); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION outputW->isDistribution(dist); // Copy units if (outputW->getAxis(0)->unit().get()) outputW->getAxis(0)->unit() = inputW->getAxis(0)->unit(); try { if (inputW->getAxis(1)->unit().get()) outputW->getAxis(1)->unit() = inputW->getAxis(1)->unit(); } catch(Exception::IndexError&) { // OK, so this isn't a Workspace2D } // Assign it to the output workspace property setProperty("OutputWorkspace",outputW); return; }
void SofQWCentre::exec() { using namespace Geometry; MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); // Do the full check for common binning if (!WorkspaceHelpers::commonBoundaries(inputWorkspace)) { g_log.error( "The input workspace must have common binning across all spectra"); throw std::invalid_argument( "The input workspace must have common binning across all spectra"); } std::vector<double> verticalAxis; MatrixWorkspace_sptr outputWorkspace = setUpOutputWorkspace( inputWorkspace, getProperty("QAxisBinning"), verticalAxis); setProperty("OutputWorkspace", outputWorkspace); // Holds the spectrum-detector mapping std::vector<specnum_t> specNumberMapping; std::vector<detid_t> detIDMapping; m_EmodeProperties.initCachedValues(*inputWorkspace, this); int emode = m_EmodeProperties.m_emode; // Get a pointer to the instrument contained in the workspace Instrument_const_sptr instrument = inputWorkspace->getInstrument(); // Get the distance between the source and the sample (assume in metres) IComponent_const_sptr source = instrument->getSource(); IComponent_const_sptr sample = instrument->getSample(); V3D beamDir = sample->getPos() - source->getPos(); beamDir.normalize(); try { double l1 = source->getDistance(*sample); g_log.debug() << "Source-sample distance: " << l1 << '\n'; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate source-sample distance"); throw Exception::InstrumentDefinitionError( "Unable to calculate source-sample distance", inputWorkspace->getTitle()); } // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV)) const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 / (PhysicalConstants::h * PhysicalConstants::h); // Loop over input workspace bins, reassigning data to correct bin in output // qw workspace const size_t numHists = inputWorkspace->getNumberHistograms(); const size_t numBins = inputWorkspace->blocksize(); Progress prog(this, 0.0, 1.0, numHists); for (int64_t i = 0; i < int64_t(numHists); ++i) { try { // Now get the detector object for this histogram IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i); if (spectrumDet->isMonitor()) continue; const double efixed = m_EmodeProperties.getEFixed(*spectrumDet); // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda // does not hold. In order to // be completely general we must calculate the momentum transfer by // calculating the incident and final // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)] DetectorGroup_const_sptr detGroup = boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet); std::vector<IDetector_const_sptr> detectors; if (detGroup) { detectors = detGroup->getDetectors(); } else { detectors.push_back(spectrumDet); } const size_t numDets = detectors.size(); const double numDets_d = static_cast<double>( numDets); // cache to reduce number of static casts const MantidVec &Y = inputWorkspace->readY(i); const MantidVec &E = inputWorkspace->readE(i); const MantidVec &X = inputWorkspace->readX(i); // Loop over the detectors and for each bin calculate Q for (size_t idet = 0; idet < numDets; ++idet) { IDetector_const_sptr det = detectors[idet]; // Calculate kf vector direction and then Q for each energy bin V3D scatterDir = (det->getPos() - sample->getPos()); scatterDir.normalize(); for (size_t j = 0; j < numBins; ++j) { const double deltaE = 0.5 * (X[j] + X[j + 1]); // Compute ki and kf wave vectors and therefore q = ki - kf double ei(0.0), ef(0.0); if (emode == 1) { ei = efixed; ef = efixed - deltaE; if (ef < 0) { std::string mess = "Energy transfer requested in Direct mode exceeds incident " "energy.\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with Ei=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } else { ei = efixed + deltaE; ef = efixed; if (ef < 0) { std::string mess = "Incident energy of a neutron is negative. Are you trying to " "process Direct data in Indirect mode?\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with efied=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } if (ei < 0) throw std::runtime_error( "Negative incident energy. Check binning."); const V3D ki = beamDir * sqrt(energyToK * ei); const V3D kf = scatterDir * (sqrt(energyToK * (ef))); const double q = (ki - kf).norm(); // Test whether it's in range of the Q axis if (q < verticalAxis.front() || q > verticalAxis.back()) continue; // Find which q bin this point lies in const MantidVec::difference_type qIndex = std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) - verticalAxis.begin() - 1; // Add this spectra-detector pair to the mapping specNumberMapping.push_back( outputWorkspace->getSpectrum(qIndex).getSpectrumNo()); detIDMapping.push_back(det->getID()); // And add the data and it's error to that bin, taking into account // the number of detectors contributing to this bin outputWorkspace->dataY(qIndex)[j] += Y[j] / numDets_d; // Standard error on the average outputWorkspace->dataE(qIndex)[j] = sqrt((pow(outputWorkspace->readE(qIndex)[j], 2) + pow(E[j], 2)) / numDets_d); } } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector // Presumably, if we get to here the spectrum will be all zeroes anyway // (from conversion to E) continue; } prog.report(); } // If the input workspace was a distribution, need to divide by q bin width if (inputWorkspace->isDistribution()) this->makeDistribution(outputWorkspace, verticalAxis); // Set the output spectrum-detector mapping SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping); outputWorkspace->updateSpectraUsing(outputDetectorMap); }
void EQSANSMonitorTOF::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); // Now create the output workspace MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if ( outputWS != inputWS ) { outputWS = WorkspaceFactory::Instance().create(inputWS); setProperty("OutputWorkspace",outputWS); } // Get the nominal sample-to-detector distance (in mm) // const double MD = MONITORPOS/1000.0; // Get the monitor const std::vector<detid_t> monitor_list = inputWS->getInstrument()->getMonitors(); if (monitor_list.size() != 1) { g_log.error() << "EQSANS workspace does not have exactly ones monitor! This should not happen" << std::endl; } IDetector_const_sptr mon; try { mon = inputWS->getInstrument()->getDetector(monitor_list[0]); } catch (Exception::NotFoundError&) { g_log.error() << "Spectrum index " << monitor_list[0] << " has no detector assigned to it - discarding" << std::endl; return; } // Get the source to monitor distance in mm double source_z = inputWS->getInstrument()->getSource()->getPos().Z(); double monitor_z = mon->getPos().Z(); double source_to_monitor = (monitor_z - source_z)*1000.0; // Calculate the frame width double frequency = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("frequency"))->getStatistics().mean; double tof_frame_width = 1.0e6/frequency; // Determine whether we need frame skipping or not by checking the chopper speed bool frame_skipping = false; const double chopper_speed = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("Speed1"))->getStatistics().mean; if (std::fabs(chopper_speed-frequency/2.0)<1.0) frame_skipping = true; // Get TOF offset // this is the call to the chopper code to say where // the start of the data frame is relative to the native facility frame double frame_tof0 = getTofOffset(inputWS, frame_skipping, source_to_monitor); // Calculate the frame width // none of this changes in response to just looking at the monitor double tmp_frame_width = frame_skipping ? tof_frame_width * 2.0 : tof_frame_width; double frame_offset=0.0; if (frame_tof0 >= tmp_frame_width) frame_offset = tmp_frame_width * ( (int)( frame_tof0/tmp_frame_width ) ); // Find the new binning first const MantidVec XIn = inputWS->readX(0); // Copy here to avoid holding on to reference for too long (problem with managed workspaces) // Since we are swapping the low-TOF and high-TOF regions around the cutoff value, // there is the potential for having an overlap between the two regions. We exclude // the region beyond a single frame by considering only the first 1/60 sec of the // TOF histogram. (Bins 1 to 1666, as opposed to 1 to 2000) const int nTOF = static_cast<int>(XIn.size()); // Loop through each bin to find the cutoff where the TOF distribution wraps around int cutoff = 0; double threshold = frame_tof0-frame_offset; int tof_bin_range = 0; double frame = 1000000.0/frequency; for (int i=0; i<nTOF; i++) { if (XIn[i] < threshold) cutoff = i; if (XIn[i] < frame) tof_bin_range = i; } g_log.information() << "Cutoff=" << cutoff << "; Threshold=" << threshold << std::endl; g_log.information() << "Low TOFs: old = [" << (cutoff+1) << ", " << (tof_bin_range-2) << "] -> new = [0, " << (tof_bin_range-3-cutoff) << "]" << std::endl; g_log.information() << "High bin boundary of the Low TOFs: old = " << tof_bin_range-1 << "; new = " << (tof_bin_range-2-cutoff) << std::endl; g_log.information() << "High TOFs: old = [0, " << (cutoff-1) << "] -> new = [" << (tof_bin_range-1-cutoff) << ", " << (tof_bin_range-2) << "]" << std::endl; g_log.information() << "Overlap: new = [" << (tof_bin_range-1) << ", " << (nTOF-2) << "]" << std::endl; // Keep a copy of the input data since we may end up overwriting it // if the input workspace is equal to the output workspace. // This is necessary since we are shuffling around the TOF bins. MantidVec YCopy = MantidVec(inputWS->readY(0)); MantidVec& YIn = YCopy; MantidVec ECopy = MantidVec(inputWS->readE(0)); MantidVec& EIn = ECopy; MantidVec& XOut = outputWS->dataX(0); MantidVec& YOut = outputWS->dataY(0); MantidVec& EOut = outputWS->dataE(0); // Here we modify the TOF according to the offset we calculated. // Since this correction will change the order of the TOF bins, // we do it in sequence so that we obtain a valid distribution // as our result (with increasing TOF values). // Move up the low TOFs for (int i=0; i<cutoff; i++) { XOut[i+tof_bin_range-1-cutoff] = XIn[i] + frame_offset + tmp_frame_width; YOut[i+tof_bin_range-1-cutoff] = YIn[i]; EOut[i+tof_bin_range-1-cutoff] = EIn[i]; } // Get rid of extra bins for (int i=tof_bin_range-1; i<nTOF-1; i++) { XOut[i] = XOut[i-1]+10.0; YOut[i] = 0.0; EOut[i] = 0.0; } XOut[nTOF-1] = XOut[nTOF-2]+10.0; // Move down the high TOFs for (int i=cutoff+1; i<tof_bin_range-1; i++) { XOut[i-cutoff-1] = XIn[i] + frame_offset; YOut[i-cutoff-1] = YIn[i]; EOut[i-cutoff-1] = EIn[i]; } // Don't forget the low boundary XOut[tof_bin_range-2-cutoff] = XIn[tof_bin_range] + frame_offset; // Zero out the cutoff bin, which no longer makes sense because // len(x) = len(y)+1 YOut[tof_bin_range-2-cutoff] = 0.0; EOut[tof_bin_range-2-cutoff] = 0.0; setProperty("OutputWorkspace",outputWS); }
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); }
/** Executes the regroup algorithm * * @throw runtime_error Thrown if */ void Regroup::exec() { // retrieve the properties std::vector<double> rb_params=getProperty("Params"); // Get the input workspace MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace"); // can work only if all histograms have the same boundaries if (!API::WorkspaceHelpers::commonBoundaries(inputW)) { g_log.error("Histograms with different boundaries"); throw std::runtime_error("Histograms with different boundaries"); } bool dist = inputW->isDistribution(); int histnumber = static_cast<int>(inputW->getNumberHistograms()); MantidVecPtr XValues_new; const MantidVec & XValues_old = inputW->readX(0); std::vector<int> xoldIndex;// indeces of new x in XValues_old // create new output X axis int ntcnew = newAxis(rb_params,XValues_old,XValues_new.access(),xoldIndex); // make output Workspace the same type is the input, but with new length of signal array API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(inputW,histnumber,ntcnew,ntcnew-1); int progress_step = histnumber / 100; if (progress_step == 0) progress_step = 1; for (int hist=0; hist < histnumber;hist++) { // get const references to input Workspace arrays (no copying) const MantidVec& XValues = inputW->readX(hist); const MantidVec& YValues = inputW->readY(hist); const MantidVec& YErrors = inputW->readE(hist); //get references to output workspace data (no copying) MantidVec& YValues_new=outputW->dataY(hist); MantidVec& YErrors_new=outputW->dataE(hist); // output data arrays are implicitly filled by function rebin(XValues,YValues,YErrors,xoldIndex,YValues_new,YErrors_new, dist); outputW->setX(hist,XValues_new); if (hist % progress_step == 0) { progress(double(hist)/histnumber); interruption_point(); } } outputW->isDistribution(dist); // Copy units if (outputW->getAxis(0)->unit().get()) outputW->getAxis(0)->unit() = inputW->getAxis(0)->unit(); try { if (inputW->getAxis(1)->unit().get()) outputW->getAxis(1)->unit() = inputW->getAxis(1)->unit(); } catch(Exception::IndexError) { // OK, so this isn't a Workspace2D } // Assign it to the output workspace property setProperty("OutputWorkspace",outputW); return; }
/** * Execution path for NormalisedPolygon Rebinning * @param inputWS : Workspace to be rebinned * @param vertexes : TableWorkspace for debugging purposes * @param dumpVertexes : determines whether vertexes will be written to for * debugging purposes or not * @param outputDimensions : used for the column headings for Dump Vertexes */ MatrixWorkspace_sptr ReflectometryTransform::executeNormPoly( MatrixWorkspace_const_sptr inputWS, boost::shared_ptr<Mantid::DataObjects::TableWorkspace> &vertexes, bool dumpVertexes, std::string outputDimensions) const { MatrixWorkspace_sptr temp = WorkspaceFactory::Instance().create( "RebinnedOutput", m_d1NumBins, m_d0NumBins, m_d0NumBins); RebinnedOutput_sptr outWS = boost::static_pointer_cast<RebinnedOutput>(temp); const double widthD0 = (m_d0Max - m_d0Min) / double(m_d0NumBins); const double widthD1 = (m_d1Max - m_d1Min) / double(m_d1NumBins); std::vector<double> xBinsVec; std::vector<double> zBinsVec; VectorHelper::createAxisFromRebinParams({m_d1Min, widthD1, m_d1Max}, zBinsVec); VectorHelper::createAxisFromRebinParams({m_d0Min, widthD0, m_d0Max}, xBinsVec); // Put the correct bin boundaries into the workspace auto verticalAxis = new BinEdgeAxis(zBinsVec); outWS->replaceAxis(1, verticalAxis); for (size_t i = 0; i < zBinsVec.size() - 1; ++i) outWS->setX(i, xBinsVec); verticalAxis->title() = m_d1Label; // Prepare the required theta values DetectorAngularCache cache = initAngularCaches(inputWS.get()); m_theta = cache.thetas; m_thetaWidths = cache.thetaWidths; const size_t nHistos = inputWS->getNumberHistograms(); const size_t nBins = inputWS->blocksize(); // Holds the spectrum-detector mapping std::vector<specnum_t> specNumberMapping; std::vector<detid_t> detIDMapping; // Create a table for the output if we want to debug vertex positioning addColumnHeadings(vertexes, outputDimensions); for (size_t i = 0; i < nHistos; ++i) { IDetector_const_sptr detector = inputWS->getDetector(i); if (!detector || detector->isMasked() || detector->isMonitor()) { continue; } // Compute polygon points const double theta = m_theta[i]; const double thetaWidth = m_thetaWidths[i]; const double thetaHalfWidth = 0.5 * thetaWidth; const double thetaLower = theta - thetaHalfWidth; const double thetaUpper = theta + thetaHalfWidth; const MantidVec &X = inputWS->readX(i); const MantidVec &Y = inputWS->readY(i); const MantidVec &E = inputWS->readE(i); for (size_t j = 0; j < nBins; ++j) { const double lamLower = X[j]; const double lamUpper = X[j + 1]; const double signal = Y[j]; const double error = E[j]; auto inputQ = m_calculator->createQuad(lamUpper, lamLower, thetaUpper, thetaLower); FractionalRebinning::rebinToFractionalOutput(inputQ, inputWS, i, j, outWS, zBinsVec); // Find which qy bin this point lies in const auto qIndex = std::upper_bound(zBinsVec.begin(), zBinsVec.end(), inputQ[0].Y()) - zBinsVec.begin(); if (qIndex != 0 && qIndex < static_cast<int>(zBinsVec.size())) { // Add this spectra-detector pair to the mapping specNumberMapping.push_back( outWS->getSpectrum(qIndex - 1).getSpectrumNo()); detIDMapping.push_back(detector->getID()); } // Debugging if (dumpVertexes) { writeRow(vertexes, inputQ[0], i, j, signal, error); writeRow(vertexes, inputQ[1], i, j, signal, error); writeRow(vertexes, inputQ[2], i, j, signal, error); writeRow(vertexes, inputQ[3], i, j, signal, error); } } } outWS->finalize(); FractionalRebinning::normaliseOutput(outWS, inputWS); // Set the output spectrum-detector mapping SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping); outWS->updateSpectraUsing(outputDetectorMap); outWS->getAxis(0)->title() = m_d0Label; outWS->setYUnit(""); outWS->setYUnitLabel("Intensity"); return outWS; }
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"; }