/** Smoothing using Butterworth filter. * @param n :: The cutoff frequency control parameter. * Cutoff frequency = my/n where my is the * number of sample points in the data. * As with the "Zeroing" case, the cutoff * frequency is truncated to an integer value * and set to 1 if the truncated value was zero. * @param order :: The order of the Butterworth filter, 1, 2, etc. * This must be a positive integer. * @param unfilteredWS :: workspace for storing the unfiltered Fourier * transform of the input spectrum * @param filteredWS :: workspace for storing the filtered spectrum */ void FFTSmooth2::Butterworth(int n, int order, API::MatrixWorkspace_sptr &unfilteredWS, API::MatrixWorkspace_sptr &filteredWS) { int mx = static_cast<int>(unfilteredWS->readX(0).size()); int my = static_cast<int>(unfilteredWS->readY(0).size()); int ny = my / n; if (ny == 0) ny = 1; filteredWS = API::WorkspaceFactory::Instance().create(unfilteredWS, 2, mx, my); const Mantid::MantidVec &Yr = unfilteredWS->readY(0); const Mantid::MantidVec &Yi = unfilteredWS->readY(1); const Mantid::MantidVec &X = unfilteredWS->readX(0); Mantid::MantidVec &yr = filteredWS->dataY(0); Mantid::MantidVec &yi = filteredWS->dataY(1); Mantid::MantidVec &xr = filteredWS->dataX(0); Mantid::MantidVec &xi = filteredWS->dataX(1); xr.assign(X.begin(), X.end()); xi.assign(X.begin(), X.end()); yr.assign(Yr.size(), 0); yi.assign(Yr.size(), 0); double cutoff = ny; for (int i = 0; i < my; i++) { double scale = 1.0 / (1.0 + pow(i / cutoff, 2 * order)); yr[i] = scale * Yr[i]; yi[i] = scale * Yi[i]; } }
/** Smoothing by zeroing. * @param n :: The order of truncation * @param unfilteredWS :: workspace for storing the unfiltered Fourier * transform of the input spectrum * @param filteredWS :: workspace for storing the filtered spectrum */ void FFTSmooth2::zero(int n, API::MatrixWorkspace_sptr &unfilteredWS, API::MatrixWorkspace_sptr &filteredWS) { int mx = static_cast<int>(unfilteredWS->readX(0).size()); int my = static_cast<int>(unfilteredWS->readY(0).size()); int ny = my / n; if (ny == 0) ny = 1; filteredWS = API::WorkspaceFactory::Instance().create(unfilteredWS, 2, mx, my); const Mantid::MantidVec &Yr = unfilteredWS->readY(0); const Mantid::MantidVec &Yi = unfilteredWS->readY(1); const Mantid::MantidVec &X = unfilteredWS->readX(0); Mantid::MantidVec &yr = filteredWS->dataY(0); Mantid::MantidVec &yi = filteredWS->dataY(1); Mantid::MantidVec &xr = filteredWS->dataX(0); Mantid::MantidVec &xi = filteredWS->dataX(1); xr.assign(X.begin(), X.end()); xi.assign(X.begin(), X.end()); yr.assign(Yr.size(), 0); yi.assign(Yr.size(), 0); for (int i = 0; i < ny; i++) { yr[i] = Yr[i]; yi[i] = Yi[i]; } }
/** * Validation of the inputs of the RingProfile algorithm. * * Inside this method, the Workspace is considered a 2D Matrix, where each *spectrum is * the rows of the matrix and have the variation in axis0. The columns of the *matrix * is the position of dataX(0) * * The main validation are: * - the centre of the ring is inside the image it self. * - The minimum ring is smaller than the limits of the image to allow * @param inputWS: pointer to the input workspace */ void RingProfile::checkInputsForNumericWorkspace( const API::MatrixWorkspace_sptr inputWS) { g_log.notice() << "CheckingInputs For Numeric Workspace" << std::endl; // The Axis0 is defined by the values of readX inside the spectra of the // workspace. // The limits of this axis will be get by inspection of the readX vector // taking the first // and the last value. // check that centre is inside the range available for the instrument const MantidVec &refX = inputWS->readX(inputWS->getNumberHistograms() / 2); // get the limits of the axis 0 (X) double min_v_x, max_v_x; min_v_x = std::min(refX[0], refX[refX.size() - 1]); max_v_x = std::max(refX[0], refX[refX.size() - 1]); g_log.notice() << "Limits X = " << min_v_x << " " << max_v_x << std::endl; // check centre is inside the X domain if (centre_x < min_v_x || centre_x > max_v_x) { std::stringstream s; s << "The input value for centre (X=" << centre_x << ") is outside the limits of the instrument [" << min_v_x << ", " << max_v_x << "]"; throw std::invalid_argument(s.str()); } // The Axis1 is defined by the spectra inside the workspace. Its limits and // values are given by the // ws->getAxis(1) // get the limits of the axis1 (Y) API::NumericAxis *oldAxis2 = dynamic_cast<API::NumericAxis *>(inputWS->getAxis(1)); // we cannot have the positions in Y direction without a NumericAxis if (!oldAxis2) throw std::invalid_argument("Vertical axis is not a numeric axis. If it is " "a spectra axis try running " "ConvertSpectrumAxis first."); double min_v_y = std::min(oldAxis2->getMin(), oldAxis2->getMax()); double max_v_y = std::max(oldAxis2->getMin(), oldAxis2->getMax()); g_log.notice() << "Limits Y = " << min_v_y << " " << max_v_y << std::endl; // check centre is inside the Y domain if (centre_y < min_v_y || centre_y > max_v_y) { std::stringstream s; s << "The input value for centre (Y=" << centre_y << ") is outside the limits of the instrument [" << min_v_y << ", " << max_v_y << "]"; throw std::invalid_argument(s.str()); } g_log.notice() << "Centre: " << centre_x << " " << centre_y << std::endl; // check minradius is inside the limits of the region of the instrument if (centre_x - min_radius > max_v_x || centre_x + min_radius < min_v_x || centre_y - min_radius > max_v_y || centre_y + min_radius < min_v_y) throw std::invalid_argument( "The minimun radius is outside the region of the instrument"); }
double RadiusSum::getMinBinSizeForNumericImage(API::MatrixWorkspace_sptr inWS) { // The pixel dimensions: // - width: image width/ number of pixels in one row // - height: image height/ number of pixels in one column // The minimum bin size is the smallest value between this two values. std::vector<double> boundaries = getBoundariesOfNumericImage(inWS); const MantidVec &refX = inWS->readX(inputWS->getNumberHistograms() / 2); int nX = static_cast<int>(refX.size()); int nY = static_cast<int>(inWS->getAxis(1)->length()); // remembering boundaries is defined as { xMin, xMax, yMin, yMax} return std::min(((boundaries[1] - boundaries[0]) / nX), ((boundaries[3] - boundaries[2]) / nY)); }
/** Assuming that the input workspace is a Numeric Image where the pixel *positions depend on their * relative position inside the workspace, this function extracts the position *of the first and last * pixel of the image. * * It is important that the input workspace must be a numeric image, and not an *instrument related workspace. * The function will raise exception (std::invalid_argument) if an invalid *input is give. * * @see RadiusSum::inputWorkspaceHasInstrumentAssociated for reference. * * @param inWS reference to the workspace * @return a list of values that defines the limits of the image in this order: *Xmin, Xmax, Ymin, Ymax */ std::vector<double> RadiusSum::getBoundariesOfNumericImage(API::MatrixWorkspace_sptr inWS) { // horizontal axis // get the pixel position in the horizontal axis from the middle of the image. const MantidVec &refX = inWS->readX(inWS->getNumberHistograms() / 2); double min_x, max_x; const double &first_x(refX[0]); const double &last_x(refX[refX.size() - 1]); if (first_x < last_x) { min_x = first_x; max_x = last_x; } else { min_x = last_x; max_x = first_x; } // vertical axis API::NumericAxis *verticalAxis = dynamic_cast<API::NumericAxis *>(inWS->getAxis(1)); if (!verticalAxis) throw std::invalid_argument("Vertical axis is not a numeric axis. Can not " "find the limits of the image."); double min_y, max_y; min_y = verticalAxis->getMin(); max_y = verticalAxis->getMax(); // check the assumption made that verticalAxis will provide the correct // answer. if (min_y > max_y) { throw std::logic_error("Failure to get the boundaries of this image. " "Internal logic error. Please, inform MantidHelp"); } std::vector<double> output(4); // output = {min_x, max_x, min_y, max_y}; not // supported in all compilers output[0] = min_x; output[1] = max_x; output[2] = min_y; output[3] = max_y; return output; }
/** Carries out the bin-by-bin normalisation * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin(API::MatrixWorkspace_sptr inputWorkspace, API::MatrixWorkspace_sptr& outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); EventWorkspace_sptr outputEvent; // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace ) { if (inputEvent) { //Make a brand new EventWorkspace outputEvent = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", inputEvent->getNumberHistograms(), 2, 1)); //Copy geometry and data API::WorkspaceFactory::Instance().initializeFromParent(inputEvent, outputEvent, false); outputEvent->copyDataFrom( (*inputEvent) ); outputWorkspace = boost::dynamic_pointer_cast<MatrixWorkspace>(outputEvent); } else outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); } // Get hold of the monitor spectrum const MantidVec& monX = m_monitor->readX(0); MantidVec& monY = m_monitor->dataY(0); MantidVec& monE = m_monitor->dataE(0); // Calculate the overall normalisation just the once if bins are all matching if (m_commonBins) this->normalisationFactor(m_monitor->readX(0),&monY,&monE); const size_t numHists = inputWorkspace->getNumberHistograms(); MantidVec::size_type specLength = inputWorkspace->blocksize(); Progress prog(this,0.0,1.0,numHists); // Loop over spectra PARALLEL_FOR3(inputWorkspace,outputWorkspace,m_monitor) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const MantidVec& X = inputWorkspace->readX(i); // If not rebinning, just point to our monitor spectra, otherwise create new vectors MantidVec* Y = ( m_commonBins ? &monY : new MantidVec(specLength) ); MantidVec* E = ( m_commonBins ? &monE : new MantidVec(specLength) ); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeroes - skip these, they cause problems if (X.back() == 0.0 && X.front() == 0.0) continue; // Rebin the monitor spectrum to match the binning of the current data spectrum VectorHelper::rebinHistogram(monX,monY,monE,X,*Y,*E,false); // Recalculate the overall normalisation factor this->normalisationFactor(X,Y,E); } if (inputEvent) { // ----------------------------------- EventWorkspace --------------------------------------- EventList & outEL = outputEvent->getEventList(i); outEL.divide(X, *Y, *E); } else { // ----------------------------------- Workspace2D --------------------------------------- const MantidVec& inY = inputWorkspace->readY(i); const MantidVec& inE = inputWorkspace->readE(i); MantidVec& YOut = outputWorkspace->dataY(i); MantidVec& EOut = outputWorkspace->dataE(i); outputWorkspace->dataX(i) = inputWorkspace->readX(i); // The code below comes more or less straight out of Divide.cpp for (MantidVec::size_type k = 0; k < specLength; ++k) { // Get references to the input Y's const double& leftY = inY[k]; const double& rightY = (*Y)[k]; // Calculate result and store in local variable to avoid overwriting original data if // output workspace is same as one of the input ones const double newY = leftY/rightY; if (fabs(rightY)>1.0e-12 && fabs(newY)>1.0e-12) { const double lhsFactor = (inE[k]<1.0e-12|| fabs(leftY)<1.0e-12) ? 0.0 : pow((inE[k]/leftY),2); const double rhsFactor = (*E)[k]<1.0e-12 ? 0.0 : pow(((*E)[k]/rightY),2); EOut[k] = std::abs(newY) * sqrt(lhsFactor+rhsFactor); } // Now store the result YOut[k] = newY; } // end Workspace2D case } // end loop over current spectrum if (!m_commonBins) { delete Y; delete E; } PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION }
/** Executes the algorithm * */ void SplineBackground::exec() { API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); int spec = getProperty("WorkspaceIndex"); if (spec > static_cast<int>(inWS->getNumberHistograms())) throw std::out_of_range("WorkspaceIndex is out of range."); const MantidVec& X = inWS->readX(spec); const MantidVec& Y = inWS->readY(spec); const MantidVec& E = inWS->readE(spec); const bool isHistogram = inWS->isHistogramData(); const int ncoeffs = getProperty("NCoeff"); const int k = 4; // order of the spline + 1 (cubic) const int nbreak = ncoeffs - (k - 2); if (nbreak <= 0) throw std::out_of_range("Too low NCoeff"); gsl_bspline_workspace *bw; gsl_vector *B; gsl_vector *c, *w, *x, *y; gsl_matrix *Z, *cov; gsl_multifit_linear_workspace *mw; double chisq; int n = static_cast<int>(Y.size()); bool isMasked = inWS->hasMaskedBins(spec); std::vector<int> masked(Y.size()); if (isMasked) { for(API::MatrixWorkspace::MaskList::const_iterator it=inWS->maskedBins(spec).begin();it!=inWS->maskedBins(spec).end();++it) masked[it->first] = 1; n -= static_cast<int>(inWS->maskedBins(spec).size()); } if (n < ncoeffs) { g_log.error("Too many basis functions (NCoeff)"); throw std::out_of_range("Too many basis functions (NCoeff)"); } /* allocate a cubic bspline workspace (k = 4) */ bw = gsl_bspline_alloc(k, nbreak); B = gsl_vector_alloc(ncoeffs); x = gsl_vector_alloc(n); y = gsl_vector_alloc(n); Z = gsl_matrix_alloc(n, ncoeffs); c = gsl_vector_alloc(ncoeffs); w = gsl_vector_alloc(n); cov = gsl_matrix_alloc(ncoeffs, ncoeffs); mw = gsl_multifit_linear_alloc(n, ncoeffs); /* this is the data to be fitted */ int j = 0; for (MantidVec::size_type i = 0; i < Y.size(); ++i) { if (isMasked && masked[i]) continue; gsl_vector_set(x, j, (isHistogram ? (0.5*(X[i]+X[i+1])) : X[i])); // Middle of the bins, if a histogram gsl_vector_set(y, j, Y[i]); gsl_vector_set(w, j, E[i]>0.?1./(E[i]*E[i]):0.); ++j; } if (n != j) { gsl_bspline_free(bw); gsl_vector_free(B); gsl_vector_free(x); gsl_vector_free(y); gsl_matrix_free(Z); gsl_vector_free(c); gsl_vector_free(w); gsl_matrix_free(cov); gsl_multifit_linear_free(mw); throw std::runtime_error("Assertion failed: n != j"); } double xStart = X.front(); double xEnd = X.back(); /* use uniform breakpoints */ gsl_bspline_knots_uniform(xStart, xEnd, bw); /* construct the fit matrix X */ for (int i = 0; i < n; ++i) { double xi=gsl_vector_get(x, i); /* compute B_j(xi) for all j */ gsl_bspline_eval(xi, B, bw); /* fill in row i of X */ for (j = 0; j < ncoeffs; ++j) { double Bj = gsl_vector_get(B, j); gsl_matrix_set(Z, i, j, Bj); } } /* do the fit */ gsl_multifit_wlinear(Z, w, y, c, cov, &chisq, mw); /* output the smoothed curve */ API::MatrixWorkspace_sptr outWS = WorkspaceFactory::Instance().create(inWS,1,X.size(),Y.size()); { outWS->getAxis(1)->setValue(0, inWS->getAxis(1)->spectraNo(spec)); double xi, yi, yerr; for (MantidVec::size_type i=0;i<Y.size();i++) { xi = X[i]; gsl_bspline_eval(xi, B, bw); gsl_multifit_linear_est(B, c, cov, &yi, &yerr); outWS->dataY(0)[i] = yi; outWS->dataE(0)[i] = yerr; } outWS->dataX(0) = X; } gsl_bspline_free(bw); gsl_vector_free(B); gsl_vector_free(x); gsl_vector_free(y); gsl_matrix_free(Z); gsl_vector_free(c); gsl_vector_free(w); gsl_matrix_free(cov); gsl_multifit_linear_free(mw); setProperty("OutputWorkspace",outWS); }
/** Executes the algorithm * @throw Exception::FileError If the calibration file cannot be opened and * read successfully * @throw Exception::InstrumentDefinitionError If unable to obtain the * source-sample distance */ void AlignDetectors::exec() { // Get the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); this->getCalibrationWS(inputWS); // Initialise the progress reporting object m_numberOfSpectra = static_cast<int64_t>(inputWS->getNumberHistograms()); // Check if its an event workspace EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventW != nullptr) { this->execEvent(); return; } API::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); setProperty("OutputWorkspace", outputWS); } // Set the final unit that our output workspace will have setXAxisUnits(outputWS); ConversionFactors converter = ConversionFactors(m_calibrationWS); Progress progress(this, 0.0, 1.0, m_numberOfSpectra); // Loop over the histograms (detector spectra) PARALLEL_FOR2(inputWS, outputWS) for (int64_t i = 0; i < m_numberOfSpectra; ++i) { PARALLEL_START_INTERUPT_REGION try { // Get the input spectrum number at this workspace index auto inSpec = inputWS->getSpectrum(size_t(i)); auto toDspacing = converter.getConversionFunc(inSpec->getDetectorIDs()); // Get references to the x data MantidVec &xOut = outputWS->dataX(i); // Make sure reference to input X vector is obtained after output one // because in the case // where the input & output workspaces are the same, it might move if the // vectors were shared. const MantidVec &xIn = inSpec->readX(); std::transform(xIn.begin(), xIn.end(), xOut.begin(), toDspacing); // Copy the Y&E data outputWS->dataY(i) = inSpec->readY(); outputWS->dataE(i) = inSpec->readE(); } catch (Exception::NotFoundError &) { // Zero the data in this case outputWS->dataX(i).assign(outputWS->readX(i).size(), 0.0); outputWS->dataY(i).assign(outputWS->readY(i).size(), 0.0); outputWS->dataE(i).assign(outputWS->readE(i).size(), 0.0); } progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** * Execute smoothing of a single spectrum. * @param inputWS :: A workspace to pick a spectrum from. * @param wsIndex :: An index of a spectrum to smooth. * @return :: A single-spectrum workspace with the smoothed data. */ API::MatrixWorkspace_sptr WienerSmooth::smoothSingleSpectrum(API::MatrixWorkspace_sptr inputWS, size_t wsIndex) { size_t dataSize = inputWS->blocksize(); // it won't work for very small workspaces if (dataSize < 4) { g_log.debug() << "No smoothing, spectrum copied." << std::endl; return copyInput(inputWS, wsIndex); } // Due to the way RealFFT works the input should be even-sized const bool isOddSize = dataSize % 2 != 0; if (isOddSize) { // add a fake value to the end to make size even inputWS = copyInput(inputWS, wsIndex); wsIndex = 0; auto &X = inputWS->dataX(wsIndex); auto &Y = inputWS->dataY(wsIndex); auto &E = inputWS->dataE(wsIndex); double dx = X[dataSize - 1] - X[dataSize - 2]; X.push_back(X.back() + dx); Y.push_back(Y.back()); E.push_back(E.back()); } // the input vectors auto &X = inputWS->readX(wsIndex); auto &Y = inputWS->readY(wsIndex); auto &E = inputWS->readE(wsIndex); // Digital fourier transform works best for data oscillating around 0. // Fit a spline with a small number of break points to the data. // Make sure that the spline passes through the first and the last points // of the data. // The fitted spline will be subtracted from the data and the difference // will be smoothed with the Wiener filter. After that the spline will be // added to the smoothed data to produce the output. // number of spline break points, must be smaller than the data size but // between 2 and 10 size_t nbreak = 10; if (nbreak * 3 > dataSize) nbreak = dataSize / 3; // NB. The spline mustn't fit too well to the data. If it does smoothing // doesn't happen. // TODO: it's possible that the spline is unnecessary and a simple linear // function will // do a better job. g_log.debug() << "Spline break points " << nbreak << std::endl; // define the spline API::IFunction_sptr spline = API::FunctionFactory::Instance().createFunction("BSpline"); auto xInterval = getStartEnd(X, inputWS->isHistogramData()); spline->setAttributeValue("StartX", xInterval.first); spline->setAttributeValue("EndX", xInterval.second); spline->setAttributeValue("NBreak", static_cast<int>(nbreak)); // fix the first and last parameters to the first and last data values spline->setParameter(0, Y.front()); spline->fix(0); size_t lastParamIndex = spline->nParams() - 1; spline->setParameter(lastParamIndex, Y.back()); spline->fix(lastParamIndex); // fit the spline to the data auto fit = createChildAlgorithm("Fit"); fit->initialize(); fit->setProperty("Function", spline); fit->setProperty("InputWorkspace", inputWS); fit->setProperty("WorkspaceIndex", static_cast<int>(wsIndex)); fit->setProperty("CreateOutput", true); fit->execute(); // get the fit output workspace; spectrum 2 contains the difference that is to // be smoothed API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace"); // Fourier transform the difference spectrum auto fourier = createChildAlgorithm("RealFFT"); fourier->initialize(); fourier->setProperty("InputWorkspace", fitOut); fourier->setProperty("WorkspaceIndex", 2); // we don't require bin linearity as we don't need the exact transform fourier->setProperty("IgnoreXBins", true); fourier->execute(); API::MatrixWorkspace_sptr fourierOut = fourier->getProperty("OutputWorkspace"); // spectrum 2 of the transformed workspace has the transform modulus which is // a square // root of the power spectrum auto &powerSpec = fourierOut->dataY(2); // convert the modulus to power spectrum wich is the base of the Wiener filter std::transform(powerSpec.begin(), powerSpec.end(), powerSpec.begin(), PowerSpectrum()); // estimate power spectrum's noise as the average of its high frequency half size_t n2 = powerSpec.size(); double noise = std::accumulate(powerSpec.begin() + n2 / 2, powerSpec.end(), 0.0); noise /= static_cast<double>(n2); // index of the maximum element in powerSpec const size_t imax = static_cast<size_t>(std::distance( powerSpec.begin(), std::max_element(powerSpec.begin(), powerSpec.end()))); if (noise == 0.0) { noise = powerSpec[imax] / guessSignalToNoiseRatio; } g_log.debug() << "Maximum signal " << powerSpec[imax] << std::endl; g_log.debug() << "Noise " << noise << std::endl; // storage for the Wiener filter, initialized with 0.0's std::vector<double> wf(n2); // The filter consists of two parts: // 1) low frequency region, from 0 until the power spectrum falls to the // noise level, filter is calculated // from the power spectrum // 2) high frequency noisy region, filter is a smooth function of frequency // decreasing to 0 // the following code is an adaptation of a fortran routine // noise starting index size_t i0 = 0; // intermediate variables double xx = 0.0; double xy = 0.0; double ym = 0.0; // low frequency filter values: the higher the power spectrum the closer the // filter to 1.0 for (size_t i = 0; i < n2; ++i) { double cd1 = powerSpec[i] / noise; if (cd1 < 1.0 && i > imax) { i0 = i; break; } double cd2 = log(cd1); wf[i] = cd1 / (1.0 + cd1); double j = static_cast<double>(i + 1); xx += j * j; xy += j * cd2; ym += cd2; } // i0 should always be > 0 but in case something goes wrong make a check if (i0 > 0) { g_log.debug() << "Noise start index " << i0 << std::endl; // high frequency filter values: smooth decreasing function double ri0f = static_cast<double>(i0 + 1); double xm = (1.0 + ri0f) / 2; ym /= ri0f; double a1 = (xy - ri0f * xm * ym) / (xx - ri0f * xm * xm); double b1 = ym - a1 * xm; g_log.debug() << "(a1,b1) = (" << a1 << ',' << b1 << ')' << std::endl; const double dblev = -20.0; // cut-off index double ri1 = floor((dblev / 4 - b1) / a1); if (ri1 < static_cast<double>(i0)) { g_log.warning() << "Failed to build Wiener filter: no smoothing." << std::endl; ri1 = static_cast<double>(i0); } size_t i1 = static_cast<size_t>(ri1); if (i1 > n2) i1 = n2; for (size_t i = i0; i < i1; ++i) { double s = exp(a1 * static_cast<double>(i + 1) + b1); wf[i] = s / (1.0 + s); } // wf[i] for i1 <= i < n2 are 0.0 g_log.debug() << "Cut-off index " << i1 << std::endl; } else { g_log.warning() << "Power spectrum has an unexpected shape: no smoothing" << std::endl; return copyInput(inputWS, wsIndex); } // multiply the fourier transform by the filter auto &re = fourierOut->dataY(0); auto &im = fourierOut->dataY(1); std::transform(re.begin(), re.end(), wf.begin(), re.begin(), std::multiplies<double>()); std::transform(im.begin(), im.end(), wf.begin(), im.begin(), std::multiplies<double>()); // inverse fourier transform fourier = createChildAlgorithm("RealFFT"); fourier->initialize(); fourier->setProperty("InputWorkspace", fourierOut); fourier->setProperty("IgnoreXBins", true); fourier->setPropertyValue("Transform", "Backward"); fourier->execute(); API::MatrixWorkspace_sptr out = fourier->getProperty("OutputWorkspace"); auto &background = fitOut->readY(1); auto &y = out->dataY(0); if (y.size() != background.size()) { throw std::logic_error("Logic error: inconsistent arrays"); } // add the spline "background" to the smoothed data std::transform(y.begin(), y.end(), background.begin(), y.begin(), std::plus<double>()); // copy the x-values and errors from the original spectrum // remove the last values for odd-sized inputs if (isOddSize) { out->dataX(0).assign(X.begin(), X.end() - 1); out->dataE(0).assign(E.begin(), E.end() - 1); out->dataY(0).resize(Y.size() - 1); } else { out->setX(0, X); out->dataE(0).assign(E.begin(), E.end()); } return out; }
/** Calculate the integral asymmetry for a workspace (red & green). * The calculation is done by MuonAsymmetryCalc and SimpleIntegration algorithms. * @param ws_red :: The red workspace * @param ws_green :: The green workspace * @param Y :: Reference to a variable receiving the value of asymmetry * @param E :: Reference to a variable receiving the value of the error */ void PlotAsymmetryByLogValue::calcIntAsymmetry(API::MatrixWorkspace_sptr ws_red, API::MatrixWorkspace_sptr ws_green,double& Y, double& E) { if ( !m_autogroup ) { groupDetectors(ws_red,m_backward_list); groupDetectors(ws_red,m_forward_list); groupDetectors(ws_green,m_backward_list); groupDetectors(ws_green,m_forward_list); } Property* startXprop = getProperty("TimeMin"); Property* endXprop = getProperty("TimeMax"); bool setX = !startXprop->isDefault() && !endXprop->isDefault(); double startX(0.0),endX(0.0); if (setX) { startX = getProperty("TimeMin"); endX = getProperty("TimeMax"); } if (!m_int) { // "Differential asymmetry" API::MatrixWorkspace_sptr tmpWS = API::WorkspaceFactory::Instance().create( ws_red,1,ws_red->readX(0).size(),ws_red->readY(0).size()); for(size_t i=0; i<tmpWS->dataY(0).size(); i++) { double FNORM = ws_green->readY(0)[i] + ws_red->readY(0)[i]; FNORM = FNORM != 0.0 ? 1.0 / FNORM : 1.0; double BNORM = ws_green->readY(1)[i] + ws_red->readY(1)[i]; BNORM = BNORM != 0.0 ? 1.0 / BNORM : 1.0; double ZF = ( ws_green->readY(0)[i] - ws_red->readY(0)[i] ) * FNORM; double ZB = ( ws_green->readY(1)[i] - ws_red->readY(1)[i] ) * BNORM; tmpWS->dataY(0)[i] = ZB - ZF; tmpWS->dataE(0)[i] = (1.0+ZF*ZF)*FNORM+(1.0+ZB*ZB)*BNORM; } IAlgorithm_sptr integr = createChildAlgorithm("Integration"); integr->setProperty("InputWorkspace",tmpWS); integr->setPropertyValue("OutputWorkspace","tmp"); if (setX) { integr->setProperty("RangeLower",startX); integr->setProperty("RangeUpper",endX); } integr->execute(); MatrixWorkspace_sptr out = integr->getProperty("OutputWorkspace"); Y = out->readY(0)[0] / static_cast<double>(tmpWS->dataY(0).size()); E = out->readE(0)[0] / static_cast<double>(tmpWS->dataY(0).size()); } else { // "Integral asymmetry" IAlgorithm_sptr integr = createChildAlgorithm("Integration"); integr->setProperty("InputWorkspace", ws_red); integr->setPropertyValue("OutputWorkspace","tmp"); if (setX) { integr->setProperty("RangeLower",startX); integr->setProperty("RangeUpper",endX); } integr->execute(); API::MatrixWorkspace_sptr intWS_red = integr->getProperty("OutputWorkspace"); integr = createChildAlgorithm("Integration"); integr->setProperty("InputWorkspace", ws_green); integr->setPropertyValue("OutputWorkspace","tmp"); if (setX) { integr->setProperty("RangeLower",startX); integr->setProperty("RangeUpper",endX); } integr->execute(); API::MatrixWorkspace_sptr intWS_green = integr->getProperty("OutputWorkspace"); double YIF = ( intWS_green->readY(0)[0] - intWS_red->readY(0)[0] ) / ( intWS_green->readY(0)[0] + intWS_red->readY(0)[0] ); double YIB = ( intWS_green->readY(1)[0] - intWS_red->readY(1)[0] ) / ( intWS_green->readY(1)[0] + intWS_red->readY(1)[0] ); Y = YIB - YIF; double VARIF = (1.0 + YIF*YIF) / ( intWS_green->readY(0)[0] + intWS_red->readY(0)[0] ); double VARIB = (1.0 + YIB*YIB) / ( intWS_green->readY(1)[0] + intWS_red->readY(1)[0] ); E = sqrt( VARIF + VARIB ); } }
/** Executes the algorithm * @throw Exception::FileError If the calibration file cannot be opened and read successfully * @throw Exception::InstrumentDefinitionError If unable to obtain the source-sample distance */ void AlignDetectors::exec() { // Get the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); // Read in the calibration data const std::string calFileName = getProperty("CalibrationFile"); OffsetsWorkspace_sptr offsetsWS = getProperty("OffsetsWorkspace"); progress(0.0,"Reading calibration file"); if (offsetsWS && !calFileName.empty()) throw std::invalid_argument("You must specify either CalibrationFile or OffsetsWorkspace but not both."); if (!offsetsWS && calFileName.empty()) throw std::invalid_argument("You must specify either CalibrationFile or OffsetsWorkspace."); if (!calFileName.empty()) { // Load the .cal file IAlgorithm_sptr alg = createChildAlgorithm("LoadCalFile"); alg->setPropertyValue("CalFilename", calFileName); alg->setProperty("InputWorkspace", inputWS); alg->setProperty<bool>("MakeGroupingWorkspace", false); alg->setProperty<bool>("MakeOffsetsWorkspace", true); alg->setProperty<bool>("MakeMaskWorkspace", false); alg->setPropertyValue("WorkspaceName", "temp"); alg->executeAsChildAlg(); offsetsWS = alg->getProperty("OutputOffsetsWorkspace"); } const int64_t numberOfSpectra = inputWS->getNumberHistograms(); // generate map of the tof->d conversion factors this->tofToDmap = calcTofToD_ConversionMap(inputWS, offsetsWS); //Check if its an event workspace EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventW != NULL) { this->execEvent(); return; } API::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); setProperty("OutputWorkspace",outputWS); } // Set the final unit that our output workspace will have outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("dSpacing"); // Initialise the progress reporting object Progress progress(this,0.0,1.0,numberOfSpectra); // Loop over the histograms (detector spectra) PARALLEL_FOR2(inputWS,outputWS) for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) { PARALLEL_START_INTERUPT_REGION try { // Get the input spectrum number at this workspace index const ISpectrum * inSpec = inputWS->getSpectrum(size_t(i)); const double factor = calcConversionFromMap(this->tofToDmap, inSpec->getDetectorIDs()); // Get references to the x data MantidVec& xOut = outputWS->dataX(i); // Make sure reference to input X vector is obtained after output one because in the case // where the input & output workspaces are the same, it might move if the vectors were shared. const MantidVec& xIn = inSpec->readX(); //std::transform( xIn.begin(), xIn.end(), xOut.begin(), std::bind2nd(std::multiplies<double>(), factor) ); // the above transform creates wrong output in parallel in debug in Visual Studio for(size_t k = 0; k < xOut.size(); ++k) { xOut[k] = xIn[k] * factor; } // Copy the Y&E data outputWS->dataY(i) = inSpec->readY(); outputWS->dataE(i) = inSpec->readE(); } catch (Exception::NotFoundError &) { // Zero the data in this case outputWS->dataX(i).assign(outputWS->readX(i).size(),0.0); outputWS->dataY(i).assign(outputWS->readY(i).size(),0.0); outputWS->dataE(i).assign(outputWS->readE(i).size(),0.0); } progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }