/** Calculates the rebin parameters in the case where the bins of the two * workspaces intersect. * 'Intersect' is used in the sense of two intersecting sets. * @param X1 :: The bin boundaries from the first workspace * @param i :: Indicates the index in X1 immediately before the overlap * region starts * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::intersectionParams(const MantidVec &X1, int64_t &i, const MantidVec &X2, std::vector<double> ¶ms) const { // First calculate the number of bins in each workspace that are in the // overlap region int64_t overlapbins1, overlapbins2; overlapbins1 = X1.size() - i; for (overlapbins2 = 0; X2[overlapbins2] < X1.back(); ++overlapbins2) { } // We want to use whichever one has the larger bins (on average) if (overlapbins1 < overlapbins2) { // In this case we want the rest of the bins from the first workspace..... for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - X1[i - 1]); params.push_back(X1[i]); } // Now remove the last bin & boundary params.pop_back(); params.pop_back(); // ....and then the non-overlap ones from the second workspace for (size_t j = overlapbins2; j < X2.size(); ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } } else { // In this case we just have to add all the bins from the second workspace for (size_t j = 1; j < X2.size(); ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } } }
/** Deals with the (rare) case where the flightpath is longer than the reference * Note that in this case both T1 & T2 will be greater than Tmax */ std::pair<int, int> UnwrapMonitor::handleFrameOverlapped(const MantidVec &xdata, const double &Ld, std::vector<double> &tempX) { // Calculate the interval to exclude const double Dt = (m_Tmax - m_Tmin) * (1 - (m_LRef / Ld)); // This gives us new minimum & maximum tof values const double minT = m_Tmin + Dt; const double maxT = m_Tmax - Dt; // Can have situation where Ld is so much larger than Lref that everything // would be excluded. // This is an invalid input - warn and leave spectrum unwrapped if (minT > maxT) { g_log.warning() << "Invalid input, Ld (" << Ld << ") >> Lref (" << m_LRef << "). Current spectrum will not be unwrapped.\n"; return std::make_pair(0, static_cast<int>(xdata.size() - 1)); } int min = 0, max = static_cast<int>(xdata.size()); for (unsigned int j = 0; j < m_XSize; ++j) { const double T = xdata[j]; if (T < minT) { min = j + 1; tempX.erase(tempX.begin()); } else if (T > maxT) { tempX.erase(tempX.end() - (max - j), tempX.end()); max = j - 1; break; } } return std::make_pair(min, max); }
/** * Find the overlap of the inputWS with the given polygon * @param oldAxis1 :: Axis 1 bin boundaries from the input grid * @param oldAxis2 :: Axis 2 bin boundaries from the input grid * @param newPoly :: The new polygon to test * @returns A list of intersection locations with weights of the overlap */ std::vector<Rebin2D::BinWithWeight> Rebin2D::findIntersections(const MantidVec & oldAxis1, const MantidVec & oldAxis2, const Geometry::ConvexPolygon & newPoly) const { std::vector<BinWithWeight> overlaps; overlaps.reserve(5); // Have a guess at a posible limit const size_t nxpoints(oldAxis1.size()-1), nypoints(oldAxis2.size()-1); const double yn_lo(newPoly[0].Y()), yn_hi(newPoly[1].Y()); const double xn_lo(newPoly[0].X()), xn_hi(newPoly[2].X()); for(size_t i = 0; i < nypoints; ++i) { const double yo_lo(oldAxis2[i]), yo_hi(oldAxis2[i+1]); // Check if there is a possibility of overlap if( yo_hi < yn_lo || yo_lo > yn_hi ) continue; for(size_t j = 0; j < nxpoints; ++j) { const double xo_lo(oldAxis1[j]), xo_hi(oldAxis1[j+1]); // Check if there is a possibility of overlap if( xo_hi < xn_lo || xo_lo > xn_hi ) continue; ConvexPolygon oldPoly(xo_lo, xo_hi, yo_lo, yo_hi); try { ConvexPolygon overlap = intersectionByLaszlo(newPoly, oldPoly); overlaps.push_back(BinWithWeight(i,j,overlap.area()/oldPoly.area())); } catch(Geometry::NoIntersectionException &) {} } } return overlaps; }
int UnwrapSNS::unwrapX(const MantidVec &datain, MantidVec &dataout, const double &Ld) { MantidVec tempX_L; // lower half - to be frame wrapped tempX_L.reserve(m_XSize); tempX_L.clear(); MantidVec tempX_U; // upper half - to not be frame wrapped tempX_U.reserve(m_XSize); tempX_U.clear(); double filterVal = m_Tmin * Ld / m_LRef; dataout.clear(); int specialBin = 0; for (int bin = 0; bin < m_XSize; ++bin) { // This is the time-of-flight value under consideration in the current // iteration of the loop const double tof = datain[bin]; if (tof < filterVal) { tempX_L.push_back(tof + m_frameWidth); // Record the bins that fall in this range for copying over the data & // errors if (specialBin < bin) specialBin = bin; } else { tempX_U.push_back(tof); } } // loop over X values // now put it back into the vector supplied dataout.clear(); dataout.insert(dataout.begin(), tempX_U.begin(), tempX_U.end()); dataout.insert(dataout.end(), tempX_L.begin(), tempX_L.end()); assert(datain.size() == dataout.size()); return specialBin; }
/** Calculates the rebin parameters in the case where the range of the second * workspace is * entirely within that of the first workspace. * 'Inclusion' is used in the sense of a set being included in anothre. * @param X1 :: The bin boundaries from the first workspace * @param i :: Indicates the index in X1 immediately before the overlap * region starts * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::inclusionParams(const MantidVec &X1, int64_t &i, const MantidVec &X2, std::vector<double> ¶ms) const { // First calculate the number of bins in each workspace that are in the // overlap region int64_t overlapbins1, overlapbins2; for (overlapbins1 = 1; X1[i + overlapbins1] < X2.back(); ++overlapbins1) { } //++overlapbins1; overlapbins2 = X2.size() - 1; // In the overlap region, we want to use whichever one has the larger bins (on // average) if (overlapbins1 + 1 <= overlapbins2) { // In the case where the first workspace has larger bins it's easy // - just add the rest of X1's bins for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - X1[i - 1]); params.push_back(X1[i]); } } else { // In this case we want all of X2's bins first (without the first and last // boundaries) for (size_t j = 1; j < X2.size() - 1; ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } // And now those from X1 that lie above the overlap region i += overlapbins1; for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - params.back()); params.push_back(X1[i]); } } }
/** * Create workspace to store the structure factor. * First spectrum is the real part, second spectrum is the imaginary part * X values are the modulus of the Q-vectors * @param h5file file identifier * @param gws pointer to WorkspaceGroup being filled * @param setName string name of dataset * @param qvmod vector of Q-vectors' moduli * @param sorting_indexes permutation of qvmod indexes to render it in increasing order of momemtum transfer */ void LoadSassena::loadFQ(const hid_t& h5file, API::WorkspaceGroup_sptr gws, const std::string setName, const MantidVec &qvmod, const std::vector<int> &sorting_indexes) { const std::string gwsName = this->getPropertyValue("OutputWorkspace"); int nq = static_cast<int>( qvmod.size() ); //number of q-vectors DataObjects::Workspace2D_sptr ws = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(API::WorkspaceFactory::Instance().create("Workspace2D", 2, nq, nq)); const std::string wsName = gwsName + std::string("_") + setName; ws->setTitle(wsName); double* buf = new double[nq*2]; this->dataSetDouble(h5file,setName,buf); MantidVec& re = ws->dataY(0); // store the real part ws->dataX(0) = qvmod; //X-axis values are the modulus of the q vector MantidVec& im = ws->dataY(1); // store the imaginary part ws->dataX(1) = qvmod; double *curr = buf; for(int iq=0; iq<nq; iq++){ const int index=sorting_indexes[iq]; re[index]=curr[0]; im[index]=curr[1]; curr+=2; } delete[] buf; // Set the Units ws->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("MomentumTransfer"); this->registerWorkspace(gws,wsName,ws, "X-axis: Q-vector modulus; Y-axis: intermediate structure factor"); }
void Divide::performBinaryOperation(const MantidVec &lhsX, const MantidVec &lhsY, const MantidVec &lhsE, const double rhsY, const double rhsE, MantidVec &YOut, MantidVec &EOut) { (void)lhsX; // Avoid compiler warning if (rhsY == 0 && m_warnOnZeroDivide) g_log.warning() << "Division by zero: the RHS is a single-valued vector " "with value zero." << "\n"; // Do the right-hand part of the error calculation just once const double rhsFactor = pow(rhsE / rhsY, 2); const int bins = static_cast<int>(lhsE.size()); for (int j = 0; j < bins; ++j) { // Get reference to input Y const double leftY = lhsY[j]; // see comment in the function above for the error formula EOut[j] = sqrt(pow(lhsE[j], 2) + pow(leftY, 2) * rhsFactor) / fabs(rhsY); // Copy the result last in case one of the input workspaces is also any // output YOut[j] = leftY / rhsY; } }
/** * @param xValues The X data for the fitted spectrum */ void ComptonScatteringCountRate::createPositivityCM(const MantidVec &xValues) { // -- Constraint matrix for J(y) > 0 -- // The first N columns are filled with J(y) for each mass + N_h for the first // mass hermite // terms included + (n+1) for each termn the background of order n // The background columns are filled with x^j/error where j=(1,n+1) const size_t nrows(xValues.size()); size_t nColsCMatrix(m_fixedParamIndices.size()); m_cmatrix = Kernel::DblMatrix(nrows, nColsCMatrix); // Fill background values as they don't change at all if (m_bkgdPolyN > 0) { size_t polyStartCol = nColsCMatrix - m_bkgdPolyN - 1; for (size_t i = 0; i < nrows; ++i) // rows { double *row = m_cmatrix[i]; const double &xi = xValues[i]; const double &erri = m_errors[i]; size_t polyN = m_bkgdPolyN; for (size_t j = polyStartCol; j < nColsCMatrix; ++j) // cols { row[j] = std::pow(xi, static_cast<double>(polyN)) / erri; --polyN; } } } }
void WeightedMean::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE, const double rhsY, const double rhsE, MantidVec& YOut, MantidVec& EOut) { UNUSED_ARG(lhsX); assert( lhsX.size() == 1 ); // If we get here we've got two single column workspaces so it's easy. if (lhsE[0] > 0.0 && rhsE > 0.0) { const double err1 = lhsE[0]*lhsE[0]; const double err2 = rhsE*rhsE; YOut[0] = (lhsY[0]/err1)+(rhsY/err2); EOut[0] = (err1*err2)/(err1+err2); YOut[0] *= EOut[0]; EOut[0] = sqrt(EOut[0]); } else if (lhsE[0] > 0.0 && rhsE <= 0.0) { YOut[0] = lhsY[0]; EOut[0] = lhsE[0]; } else if (lhsE[0] <= 0.0 && rhsE > 0.0) { YOut[0] = rhsY; EOut[0] = rhsE; } else { YOut[0] = 0.0; EOut[0] = 0.0; } }
/// Retrieve and check the Start/EndX parameters, if set void Linear::setRange(const MantidVec& X, const MantidVec& Y) { //read in the values that the user selected double startX = getProperty("StartX"); double endX = getProperty("EndX"); //If the user didn't a start default to the start of the data if ( isEmpty(startX) ) startX = X.front(); //the default for the end is the end of the data if ( isEmpty(endX) ) endX = X.back(); // Check the validity of startX if ( startX < X.front() ) { g_log.warning("StartX out of range! Set to start of frame."); startX = X.front(); } // Now get the corresponding bin boundary that comes before (or coincides with) this value for (m_minX = 0; X[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 >= X.back() || endX < startX ) { if ( endX != X.back() ) { g_log.warning("EndX out of range! Set to end of frame"); endX = X.back(); } m_maxX = static_cast<int>(Y.size()); } else { for (m_maxX = m_minX; X[m_maxX] < endX; ++m_maxX) {} } }
void Divide::performBinaryOperation(const MantidVec &lhsX, const MantidVec &lhsY, const MantidVec &lhsE, const MantidVec &rhsY, const MantidVec &rhsE, MantidVec &YOut, MantidVec &EOut) { (void)lhsX; // Avoid compiler warning const int bins = static_cast<int>(lhsE.size()); for (int j = 0; j < bins; ++j) { // Get references to the input Y's const double leftY = lhsY[j]; const double rightY = rhsY[j]; // error dividing two uncorrelated numbers, re-arrange so that you don't // get infinity if leftY==0 (when rightY=0 the Y value and the result will // both be infinity) // (Sa/a)2 + (Sb/b)2 = (Sc/c)2 // (Sa c/a)2 + (Sb c/b)2 = (Sc)2 // = (Sa 1/b)2 + (Sb (a/b2))2 // (Sc)2 = (1/b)2( (Sa)2 + (Sb a/b)2 ) EOut[j] = sqrt(pow(lhsE[j], 2) + pow(leftY * rhsE[j] / rightY, 2)) / fabs(rightY); // Copy the result last in case one of the input workspaces is also any // output YOut[j] = leftY / rightY; ; } }
MantidVec operator()(const MantidVec &_Left, const MantidVec &_Right) const { // apply operator+ to operands MantidVec v(_Left.size()); std::transform(_Left.begin(), _Left.end(), _Right.begin(), v.begin(), SumGaussError<double>()); return (v); }
/** Calculates the rebin paramters in the case where the two input workspaces do * not overlap at all. * @param X1 :: The bin boundaries from the first workspace * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::noOverlapParams(const MantidVec &X1, const MantidVec &X2, std::vector<double> ¶ms) const { // Add all the bins from the first workspace for (size_t i = 1; i < X1.size(); ++i) { params.push_back(X1[i - 1]); params.push_back(X1[i] - X1[i - 1]); } // Put a single bin in the 'gap' (but check first the 'gap' isn't zero) if (X1.back() < X2.front()) { params.push_back(X1.back()); params.push_back(X2.front() - X1.back()); } // Now add all the bins from the second workspace for (size_t j = 1; j < X2.size(); ++j) { params.push_back(X2[j - 1]); params.push_back(X2[j] - X2[j - 1]); } params.push_back(X2.back()); }
/// Returns vector with x-values of spectrum if MatrixWorkspace does not contain /// histogram data. MantidVec FunctionDomain1DSpectrumCreator::getVectorNonHistogram() const { const MantidVec wsXData = m_matrixWorkspace->readX(m_workspaceIndex); size_t wsXSize = wsXData.size(); if (wsXSize < 1) { throw std::invalid_argument( "Workspace2D with less than one x-value cannot be processed."); } return MantidVec(wsXData); }
/** * Returns the phase shift to apply * If "AutoShift" is set, calculates this automatically as -X[N/2] * Otherwise, returns user-supplied "Shift" (or zero if none set) * @param xValues :: [input] Reference to X values of input workspace * @returns :: Phase shift */ double FFT::getPhaseShift(const MantidVec &xValues) { double shift = 0.0; const bool autoshift = getProperty("AutoShift"); if (autoshift) { const size_t mid = xValues.size() / 2; shift = -xValues[mid]; } else { shift = getProperty("Shift"); } shift *= 2 * M_PI; return shift; }
void PoissonErrors::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE, const double rhsY, const double rhsE, MantidVec& YOut, MantidVec& EOut) { (void) lhsE; (void) lhsX; //Avoid compiler warning assert( lhsX.size() == 1 ); // If we get here we've got two single column workspaces so it's easy. YOut[0] = lhsY[0]; const double fractional = rhsY ? rhsE/rhsY : 0.0; EOut[0] = fractional*lhsY[0]; }
/** Zeroes data (Y/E) at the end of a spectrum * @param start :: The index to start zeroing at * @param end :: The index to end zeroing at * @param Y :: The data vector * @param E :: The error vector */ void RemoveBins::RemoveFromEnds(int start, int end, MantidVec& Y, MantidVec& E) { if ( start ) --start; int size = static_cast<int>(Y.size()); if ( end > size ) end = size; for (int j = start; j < end; ++j) { Y[j] = 0.0; E[j] = 0.0; } return; }
/** Divides the number of counts in each output Q bin by the wrighting ("number that would expected to arrive") * The errors are propogated using the uncorrolated error estimate for multiplication/division * @param[in] normSum the weighting for each bin * @param[in] normError2 square of the error on the normalization * @param[in, out] counts counts in each bin * @param[in, out] errors input the _square_ of the error on each bin, output the total error (unsquared) */ void Q1D2::normalize(const MantidVec & normSum, const MantidVec & normError2, MantidVec & counts, MantidVec & errors) const { for (size_t k = 0; k < counts.size(); ++k) { // the normalisation is a = b/c where b = counts c =normalistion term const double c = normSum[k]; const double a = counts[k] /= c; // when a = b/c, the formula for Da, the error on a, in terms of Db, etc. is (Da/a)^2 = (Db/b)^2 + (Dc/c)^2 //(Da)^2 = ((Db/b)^2 + (Dc/c)^2)*(b^2/c^2) = ((Db/c)^2 + (b*Dc/c^2)^2) = (Db^2 + (b*Dc/c)^2)/c^2 = (Db^2 + (Dc*a)^2)/c^2 //this will work as long as c>0, but then the above formula above can't deal with 0 either const double aOverc = a/c; errors[k] = std::sqrt(errors[k]/(c*c) + normError2[k]*aOverc*aOverc); } }
/** * Get the start and end of the x-interval. * @param X :: The x-vector of a spectrum. * @param isHistogram :: Is the x-vector comming form a histogram? If it's true * the bin * centres are used. * @return :: A pair of start x and end x. */ std::pair<double, double> WienerSmooth::getStartEnd(const MantidVec &X, bool isHistogram) const { const size_t n = X.size(); if (n < 3) { // 3 is the smallest number for this method to work without breaking throw std::runtime_error( "Number of bins/data points cannot be smaller than 3."); } if (isHistogram) { return std::make_pair((X[0] + X[1]) / 2, (X[n - 1] + X[n - 2]) / 2); } // else return std::make_pair(X.front(), X.back()); }
/** Execute the algorithm. */ void WeightedMeanOfWorkspace::exec() { MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace"); // Check if it is an event workspace EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventW != NULL) { throw std::runtime_error("WeightedMeanOfWorkspace cannot handle EventWorkspaces!"); } // Create the output workspace MatrixWorkspace_sptr singleValued = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1); // Calculate weighted mean std::size_t numHists = inputWS->getNumberHistograms(); double averageValue = 0.0; double weightSum = 0.0; for (std::size_t i = 0; i < numHists; ++i) { try { IDetector_const_sptr det = inputWS->getDetector(i); if( det->isMonitor() || det->isMasked() ) { continue; } } catch (...) { // Swallow these if no instrument is found ; } MantidVec y = inputWS->dataY(i); MantidVec e = inputWS->dataE(i); double weight = 0.0; for (std::size_t j = 0; j < y.size(); ++j) { if (!boost::math::isnan(y[j]) && !boost::math::isinf(y[j]) && !boost::math::isnan(e[j]) && !boost::math::isinf(e[j])) { weight = 1.0 / (e[j] * e[j]); averageValue += (y[j] * weight); weightSum += weight; } } } singleValued->dataX(0)[0] = 0.0; singleValued->dataY(0)[0] = averageValue / weightSum; singleValued->dataE(0)[0] = std::sqrt(weightSum); this->setProperty("OutputWorkspace", singleValued); }
/** Returns the number of background points * * Given a list of peaks and a vector with spectrum count data, this method returns the number of background points * contained in this spectrum. It is used for extraction of the background in order to allocate the correct vector * size before filling it. * * @param peakPositions :: Peak positions. * @param correlationCounts :: Data vector the peak positions refer to. * @return Number of background points. */ size_t PoldiPeakSearch::getNumberOfBackgroundPoints(std::list<MantidVec::const_iterator> peakPositions, const MantidVec &correlationCounts) const { /* subtracting 2, to match original algorithm, where * the first and the last point of the spectrum are not * considered in this calculation. */ size_t totalDataPoints = correlationCounts.size() - 2; size_t occupiedByPeaks = peakPositions.size() * (m_doubleMinimumDistance + 1); if(occupiedByPeaks > totalDataPoints) { throw(std::runtime_error("More data points occupied by peaks than existing data points - not possible.")); } return totalDataPoints - occupiedByPeaks; }
void SaveGSS::writeRALFdata(const int bank, const bool MultiplyByBinWidth, std::stringstream &out, const MantidVec &X, const MantidVec &Y, const MantidVec &E) const { const size_t datasize = Y.size(); double bc1 = X[0] * 32; double bc2 = (X[1] - X[0]) * 32; // Logarithmic step double bc4 = (X[1] - X[0]) / X[0]; if (boost::math::isnan(fabs(bc4)) || boost::math::isinf(bc4)) bc4 = 0; // If X is zero for BANK // Write out the data header writeBankLine(out, "RALF", bank, datasize); out << std::fixed << " " << std::setprecision(0) << std::setw(8) << bc1 << std::fixed << " " << std::setprecision(0) << std::setw(8) << bc2 << std::fixed << " " << std::setprecision(0) << std::setw(8) << bc1 << std::fixed << " " << std::setprecision(5) << std::setw(7) << bc4 << " FXYE" << std::endl; // Do each Y entry for (size_t j = 0; j < datasize; j++) { // Calculate the error double Epos; if (MultiplyByBinWidth) Epos = E[j] * (X[j + 1] - X[j]); // E[j]*X[j]*bc4; else Epos = E[j]; Epos = fixErrorValue(Epos); // The center of the X bin. out << std::fixed << std::setprecision(5) << std::setw(15) << 0.5 * (X[j] + X[j + 1]); // The Y value if (MultiplyByBinWidth) out << std::fixed << std::setprecision(8) << std::setw(18) << Y[j] * (X[j + 1] - X[j]); else out << std::fixed << std::setprecision(8) << std::setw(18) << Y[j]; // The error out << std::fixed << std::setprecision(8) << std::setw(18) << Epos << "\n"; } return; }
void Multiply::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE, const double rhsY, const double rhsE, MantidVec& YOut, MantidVec& EOut) { UNUSED_ARG(lhsX); const size_t bins = lhsE.size(); for (size_t j=0; j<bins; ++j) { // Get reference to input Y const double leftY = lhsY[j]; // see comment in the function above for the error formula EOut[j] = sqrt(pow(lhsE[j]*rhsY, 2) + pow(rhsE*leftY, 2)); // Copy the result last in case one of the input workspaces is also any output YOut[j] = leftY*rhsY; } }
/// Returns vector with x-values of spectrum if MatrixWorkspace contains /// histogram data. MantidVec FunctionDomain1DSpectrumCreator::getVectorHistogram() const { const MantidVec wsXData = m_matrixWorkspace->readX(m_workspaceIndex); size_t wsXSize = wsXData.size(); if (wsXSize < 2) { throw std::invalid_argument("Histogram Workspace2D with less than two " "x-values cannot be processed."); } MantidVec x(wsXSize - 1); for (size_t i = 0; i < x.size(); ++i) { x[i] = (wsXData[i] + wsXData[i + 1]) / 2.0; } return x; }
void Divide::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE, const double rhsY, const double rhsE, MantidVec& YOut, MantidVec& EOut) { (void) lhsX; //Avoid compiler warning // Do the right-hand part of the error calculation just once const double rhsFactor = pow(rhsE/rhsY,2); const int bins = static_cast<int>(lhsE.size()); for (int j=0; j<bins; ++j) { // Get reference to input Y const double leftY = lhsY[j]; // see comment in the function above for the error formula EOut[j] = sqrt( pow(lhsE[j], 2)+pow( leftY, 2)*rhsFactor )/rhsY; // Copy the result last in case one of the input workspaces is also any output YOut[j] = leftY/rhsY; } }
/** Write data in SLOG format */ void SaveGSS::writeSLOGdata(const int bank, const bool MultiplyByBinWidth, std::stringstream &out, const MantidVec &X, const MantidVec &Y, const MantidVec &E) const { const size_t datasize = Y.size(); double bc1 = X.front(); // minimum TOF in microseconds if (bc1 <= 0.) { throw std::runtime_error( "Cannot write out logarithmic data starting at zero"); } double bc2 = 0.5 * (*(X.rbegin()) + *(X.rbegin() + 1)); // maximum TOF (in microseconds?) double bc3 = (*(X.begin() + 1) - bc1) / bc1; // deltaT/T g_log.debug() << "SaveGSS(): Min TOF = " << bc1 << std::endl; writeBankLine(out, "SLOG", bank, datasize); out << std::fixed << " " << std::setprecision(0) << std::setw(10) << bc1 << std::fixed << " " << std::setprecision(0) << std::setw(10) << bc2 << std::fixed << " " << std::setprecision(7) << std::setw(10) << bc3 << std::fixed << " 0 FXYE" << std::endl; for (size_t i = 0; i < datasize; i++) { double y = Y[i]; double e = E[i]; if (MultiplyByBinWidth) { // Multiple by bin width as double delta = X[i + 1] - X[i]; y *= delta; e *= delta; } e = fixErrorValue(e); out << " " << std::fixed << std::setprecision(9) << std::setw(20) << 0.5 * (X[i] + X[i + 1]) << " " << std::fixed << std::setprecision(9) << std::setw(20) << y << " " << std::fixed << std::setprecision(9) << std::setw(20) << e << std::setw(12) << " " << "\n"; // let it flush its own buffer } out << std::flush; return; }
/** * Calculate detector efficiency given a formula, the efficiency at the elastic line, * and a vector with energies. * Efficiency = f(Ei-DeltaE) / f(Ei) * Hope all compilers supports the NRVO (otherwise will copy the output vector) * @param eff0 :: calculated eff0 * @param formula :: formula to calculate efficiency (parsed from IDF) * @param xIn :: Energy bins vector (X axis) * @return a vector with the efficiencies */ MantidVec DetectorEfficiencyCorUser::calculateEfficiency(double eff0, const std::string& formula, const MantidVec& xIn) { MantidVec effOut(xIn.size() - 1); // x are bins and have more one value than y try { double e; mu::Parser p; p.DefineVar("e", &e); p.SetExpr(formula); // copied from Jaques Ollivier Code bool conditionForEnergy = std::min( std::abs( *std::min_element(xIn.begin(), xIn.end()) ) , m_Ei) < m_Ei; MantidVec::const_iterator xIn_it = xIn.begin(); // DeltaE MantidVec::iterator effOut_it = effOut.begin(); for (; effOut_it != effOut.end(); ++xIn_it, ++effOut_it) { if (conditionForEnergy ) { // cppcheck cannot see that this is used by reference by muparser e = std::fabs(m_Ei + *xIn_it); } else { // cppcheck cannot see that this is used by reference by muparser // cppcheck-suppress unreadVariable e = std::fabs(m_Ei - *xIn_it); } double eff = p.Eval(); *effOut_it = eff / eff0; } return effOut; } catch (mu::Parser::exception_type &e) { throw Kernel::Exception::InstrumentDefinitionError( "Error calculating formula from string. Muparser error message is: " + e.GetMsg()); } }
/** * Copy over the metadata from the input matrix workspace to output MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace where metadata are copied to. The source of the metadata is the input matrix workspace * */ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const { // found detector which is not a monitor to get proper bin boundaries. size_t spectra_index(0); bool dector_found(false); for(size_t i=0;i<m_InWS2D->getNumberHistograms(); ++i) { try { auto det=m_InWS2D->getDetector(i); if (!det->isMonitor()) { spectra_index=i; dector_found = true; g_log.debug()<<"Using spectra N "<<i<< " as the source of the bin boundaries for the resolution corrections \n"; break; } } catch(...) {} } if (!dector_found) g_log.warning()<<"No detectors in the workspace are associated with spectra. Using spectrum 0 trying to retrieve the bin boundaries \n"; // retrieve representative bin boundaries MantidVec binBoundaries = m_InWS2D->readX(spectra_index); // check if the boundaries transformation is necessary if (m_Convertor->getUnitConversionHelper().isUnitConverted()) { if( !dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) { g_log.information()<<" ConvertToMD converts input workspace units, but the bin boundaries are copied from the first workspace spectra. The resolution estimates can be incorrect if unit conversion depends on spectra number.\n"; UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper(); unitConv.updateConversion(spectra_index); for(size_t i=0;i<binBoundaries.size();i++) { binBoundaries[i] =unitConv.convertUnits(binBoundaries[i]); } } // sort bin boundaries in case if unit transformation have swapped them. if (binBoundaries[0]>binBoundaries[binBoundaries.size()-1]) { g_log.information()<<"Bin boundaries are not arranged monotonously. Sorting performed\n"; std::sort(binBoundaries.begin(),binBoundaries.end()); } } // Replacement for SpectraDetectorMap::createIDGroupsMap using the ISpectrum objects instead auto mapping = boost::make_shared<det2group_map>(); for ( size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i ) { const auto& dets = m_InWS2D->getSpectrum(i)->getDetectorIDs(); if(!dets.empty()) { std::vector<detid_t> id_vector; std::copy(dets.begin(), dets.end(), std::back_inserter(id_vector)); mapping->insert(std::make_pair(id_vector.front(), id_vector)); } } uint16_t nexpts = mdEventWS->getNumExperimentInfo(); for(uint16_t i = 0; i < nexpts; ++i) { ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(i); expt->mutableRun().storeHistogramBinBoundaries(binBoundaries); expt->cacheDetectorGroupings(*mapping); } }
/** Corrects a spectra for the detector efficiency calculated from detector information Gets the detector information and uses this to calculate its efficiency * @param spectraIn :: index of the spectrum to get the efficiency for * @throw invalid_argument if the shape of a detector is isn't a cylinder aligned along one axis * @throw runtime_error if the SpectraDetectorMap has not been filled * @throw NotFoundError if the detector or its gas pressure or wall thickness were not found */ void DetectorEfficiencyCor::correctForEfficiency(int64_t spectraIn) { IDetector_const_sptr det = m_inputWS->getDetector(spectraIn); if( det->isMonitor() || det->isMasked() ) { return; } MantidVec & yout = m_outputWS->dataY(spectraIn); MantidVec & eout = m_outputWS->dataE(spectraIn); // Need the original values so this is not a reference const MantidVec yValues = m_inputWS->readY(spectraIn); const MantidVec eValues = m_inputWS->readE(spectraIn); // get a pointer to the detectors that created the spectrum const std::set<detid_t> dets = m_inputWS->getSpectrum(spectraIn)->getDetectorIDs(); std::set<detid_t>::const_iterator it = dets.begin(); std::set<detid_t>::const_iterator iend = dets.end(); if ( it == iend ) { throw Exception::NotFoundError("No detectors found", spectraIn); } // Storage for the reciprocal wave vectors that are calculated as the //correction proceeds std::vector<double> oneOverWaveVectors(yValues.size()); for( ; it != iend ; ++it ) { IDetector_const_sptr det_member = m_inputWS->getInstrument()->getDetector(*it); Parameter_sptr par = m_paraMap->get(det_member.get(),"3He(atm)"); if ( !par ) { throw Exception::NotFoundError("3He(atm)", spectraIn); } const double atms = par->value<double>(); par = m_paraMap->get(det_member.get(),"wallT(m)"); if ( !par ) { throw Exception::NotFoundError("wallT(m)", spectraIn); } const double wallThickness = par->value<double>(); double detRadius(0.0); V3D detAxis; getDetectorGeometry(det_member, detRadius, detAxis); // now get the sin of the angle, it's the magnitude of the cross product of unit vector along the detector tube axis and a unit vector directed from the sample to the detector centre V3D vectorFromSample = det_member->getPos() - m_samplePos; vectorFromSample.normalize(); Quat rot = det_member->getRotation(); // rotate the original cylinder object axis to get the detector axis in the actual instrument rot.rotate(detAxis); detAxis.normalize(); // Scalar product is quicker than cross product double cosTheta = detAxis.scalar_prod(vectorFromSample); double sinTheta = std::sqrt(1.0 - cosTheta*cosTheta); // Detector constant const double det_const = g_helium_prefactor*(detRadius - wallThickness)*atms/sinTheta; MantidVec::const_iterator yinItr = yValues.begin(); MantidVec::const_iterator einItr = eValues.begin(); MantidVec::iterator youtItr = yout.begin(); MantidVec::iterator eoutItr = eout.begin(); MantidVec::const_iterator xItr = m_inputWS->readX(spectraIn).begin(); std::vector<double>::iterator wavItr = oneOverWaveVectors.begin(); for( ; youtItr != yout.end(); ++youtItr, ++eoutItr) { if( it == dets.begin() ) { *youtItr = 0.0; *eoutItr = 0.0; *wavItr = calculateOneOverK(*xItr, *(xItr + 1 )); } const double oneOverWave = *wavItr; const double factor = 1.0/detectorEfficiency(det_const*oneOverWave); *youtItr += (*yinItr)*factor; *eoutItr += (*einItr)*factor; ++yinItr; ++einItr; ++xItr; ++wavItr; } } }
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"); } }