/** loadData * Load the counts data from an NXInt into a workspace */ void LoadMuonNexus2::loadData(const Mantid::NeXus::NXInt &counts, const std::vector<double> &timeBins, int wsIndex, int period, int spec, API::MatrixWorkspace_sptr localWorkspace) { MantidVec &X = localWorkspace->dataX(wsIndex); MantidVec &Y = localWorkspace->dataY(wsIndex); MantidVec &E = localWorkspace->dataE(wsIndex); X.assign(timeBins.begin(), timeBins.end()); int nBins = 0; int *data = nullptr; if (counts.rank() == 3) { nBins = counts.dim2(); data = &counts(period, spec, 0); } else if (counts.rank() == 2) { nBins = counts.dim1(); data = &counts(spec, 0); } else { throw std::runtime_error("Data have unsupported dimansionality"); } assert(nBins + 1 == static_cast<int>(timeBins.size())); Y.assign(data, data + nBins); typedef double (*uf)(double); uf dblSqrt = std::sqrt; std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt); }
void RadiusSum::setUpOutputWorkspace(std::vector<double> &values) { g_log.debug() << "Output calculated, setting up the output workspace\n"; API::MatrixWorkspace_sptr outputWS = API::WorkspaceFactory::Instance().create( inputWS, 1, values.size() + 1, values.size()); g_log.debug() << "Set the data\n"; MantidVec &refY = outputWS->dataY(0); std::copy(values.begin(), values.end(), refY.begin()); g_log.debug() << "Set the bins limits\n"; MantidVec &refX = outputWS->dataX(0); double bin_size = (max_radius - min_radius) / num_bins; for (int i = 0; i < (static_cast<int>(refX.size())) - 1; i++) refX[i] = min_radius + i * bin_size; refX.back() = max_radius; // configure the axis: // for numeric images, the axis are the same as the input workspace, and are // copied in the creation. // for instrument related, the axis Y (1) continues to be the same. // it is necessary to change only the axis X. We have to change it to radius. if (inputWorkspaceHasInstrumentAssociated(inputWS)) { API::Axis *const horizontal = new API::NumericAxis(refX.size()); auto labelX = UnitFactory::Instance().create("Label"); boost::dynamic_pointer_cast<Units::Label>(labelX)->setLabel("Radius"); horizontal->unit() = labelX; outputWS->replaceAxis(0, horizontal); } setProperty("OutputWorkspace", outputWS); }
/** * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. The xbins are read along with * each call to the data/error loading * @param data :: The NXDataSet object of y values * @param errors :: The NXDataSet object of error values * @param xbins :: The xbin NXDataSet * @param blocksize :: The blocksize to use * @param nchannels :: The number of channels for the block * @param hist :: The workspace index to start reading into * @param wsIndex :: The workspace index to save data into * @param local_workspace :: A pointer to the workspace */ void LoadNexusProcessed::loadBlock(NXDataSetTyped<double> & data, NXDataSetTyped<double> & errors, NXDouble & xbins, int64_t blocksize, int64_t nchannels, int64_t &hist, int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) { data.load(static_cast<int>(blocksize),static_cast<int>(hist)); double *data_start = data(); double *data_end = data_start + nchannels; errors.load(static_cast<int>(blocksize),static_cast<int>(hist)); double *err_start = errors(); double *err_end = err_start + nchannels; xbins.load(static_cast<int>(blocksize),static_cast<int>(hist)); const int64_t nxbins(nchannels + 1); double *xbin_start = xbins(); double *xbin_end = xbin_start + nxbins; int64_t final(hist + blocksize); while( hist < final ) { MantidVec& Y = local_workspace->dataY(wsIndex); Y.assign(data_start, data_end); data_start += nchannels; data_end += nchannels; MantidVec& E = local_workspace->dataE(wsIndex); E.assign(err_start, err_end); err_start += nchannels; err_end += nchannels; MantidVec& X = local_workspace->dataX(wsIndex); X.assign(xbin_start, xbin_end); xbin_start += nxbins; xbin_end += nxbins; ++hist; ++wsIndex; } }
/** 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]; } }
/** Execute the algorithm. */ void DampSq::exec() { // TODO Auto-generated execute stub // 1. Generate new workspace API::MatrixWorkspace_const_sptr isqspace = getProperty("InputWorkspace"); API::MatrixWorkspace_sptr osqspace = WorkspaceFactory::Instance().create(isqspace, 1, isqspace->size(), isqspace->size()); int mode = getProperty("Mode"); double qmax = getProperty("QMax"); if (mode < 1 || mode > 4) { g_log.error("Damp mode can only be 1, 2, 3, or 4"); return; } // 2. Get access to all const MantidVec& iQVec = isqspace->dataX(0); const MantidVec& iSVec = isqspace->dataY(0); const MantidVec& iEVec = isqspace->dataE(0); MantidVec& oQVec = osqspace->dataX(0); MantidVec& oSVec = osqspace->dataY(0); MantidVec& oEVec = osqspace->dataE(0); // 3. Calculation double dqmax = qmax - iQVec[0]; double damp; for (unsigned int i = 0; i < iQVec.size(); i ++) { // a) calculate damp coefficient switch (mode) { case 1: damp = dampcoeff1(iQVec[i], qmax, dqmax); break; case 2: damp = dampcoeff2(iQVec[i], qmax, dqmax);; break; case 3: damp = dampcoeff3(iQVec[i], qmax, dqmax);; break; case 4: damp = dampcoeff4(iQVec[i], qmax, dqmax);; break; default: damp = 0; break; } // b) calculate new S(q) oQVec[i] = iQVec[i]; oSVec[i] = 1 + damp*(iSVec[i]-1); oEVec[i] = damp*iEVec[i]; } // i // 4. Over setProperty("OutputWorkspace", osqspace); return; }
/** Performs the Holtzer transformation: IQ v Q * @param ws The workspace to be transformed */ void IQTransform::holtzer(API::MatrixWorkspace_sptr ws) { MantidVec& X = ws->dataX(0); MantidVec& Y = ws->dataY(0); MantidVec& E = ws->dataE(0); std::transform(Y.begin(),Y.end(),X.begin(),Y.begin(),std::multiplies<double>()); std::transform(E.begin(),E.end(),X.begin(),E.begin(),std::multiplies<double>()); ws->setYUnitLabel("I x Q"); }
/** Performs the Porod transformation: IQ^4 v Q * @param ws The workspace to be transformed */ void IQTransform::porod(API::MatrixWorkspace_sptr ws) { MantidVec& X = ws->dataX(0); MantidVec& Y = ws->dataY(0); MantidVec& E = ws->dataE(0); MantidVec Q4(X.size()); std::transform(X.begin(),X.end(),X.begin(),Q4.begin(),VectorHelper::TimesSquares<double>()); std::transform(Y.begin(),Y.end(),Q4.begin(),Y.begin(),std::multiplies<double>()); std::transform(E.begin(),E.end(),Q4.begin(),E.begin(),std::multiplies<double>()); ws->setYUnitLabel("I x Q^4"); }
/** Performs a log-log transformation: Ln(I) v Ln(Q) * @param ws The workspace to be transformed * @throw std::range_error if an attempt is made to take log of a negative number */ void IQTransform::logLog(API::MatrixWorkspace_sptr ws) { MantidVec& X = ws->dataX(0); MantidVec& Y = ws->dataY(0); MantidVec& E = ws->dataE(0); std::transform(X.begin(),X.end(),X.begin(),VectorHelper::Log<double>()); std::transform(E.begin(),E.end(),Y.begin(),E.begin(),std::divides<double>()); std::transform(Y.begin(),Y.end(),Y.begin(),VectorHelper::LogNoThrow<double>()); ws->setYUnitLabel("Ln(I)"); m_label->setLabel("Ln(Q)"); }
/** Performs the Guinier (sheets) transformation: Ln(IQ^2) v Q^2 * @param ws The workspace to be transformed * @throw std::range_error if an attempt is made to take log of a negative number */ void IQTransform::guinierSheets(API::MatrixWorkspace_sptr ws) { MantidVec& X = ws->dataX(0); MantidVec& Y = ws->dataY(0); MantidVec& E = ws->dataE(0); std::transform(E.begin(),E.end(),Y.begin(),E.begin(),std::divides<double>()); std::transform(X.begin(),X.end(),X.begin(),VectorHelper::Squares<double>()); std::transform(Y.begin(),Y.end(),X.begin(),Y.begin(),std::multiplies<double>()); std::transform(Y.begin(),Y.end(),Y.begin(),VectorHelper::LogNoThrow<double>()); ws->setYUnitLabel("Ln(I x Q^2)"); m_label->setLabel("Q^2"); }
/** Convert the workspace units according to a simple output = a * (input^b) relationship * @param outputWS :: the output workspace * @param factor :: the conversion factor a to apply * @param power :: the Power b to apply to the conversion */ void ConvertUnits::convertQuickly(API::MatrixWorkspace_sptr outputWS, const double& factor, const double& power) { Progress prog(this,0.2,1.0,m_numberOfSpectra); int64_t numberOfSpectra_i = static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy // See if the workspace has common bins - if so the X vector can be common // First a quick check using the validator CommonBinsValidator sameBins; bool commonBoundaries = false; if ( sameBins.isValid(outputWS) == "" ) { commonBoundaries = WorkspaceHelpers::commonBoundaries(outputWS); // Only do the full check if the quick one passes if (commonBoundaries) { // Calculate the new (common) X values MantidVec::iterator iter; for (iter = outputWS->dataX(0).begin(); iter != outputWS->dataX(0).end(); ++iter) { *iter = factor * std::pow(*iter,power); } MantidVecPtr xVals; xVals.access() = outputWS->dataX(0); PARALLEL_FOR1(outputWS) for (int64_t j = 1; j < numberOfSpectra_i; ++j) { PARALLEL_START_INTERUPT_REGION outputWS->setX(j,xVals); prog.report("Convert to " + m_outputUnit->unitID()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION if (!m_inputEvents) // if in event mode the work is done return; } }
/** Performs a transformation of the form: Q^A x I^B x Ln(Q^C x I^D x E) v Q^F x * I^G x Ln(Q^H x I^I x J). * Uses the 'GeneralFunctionConstants' property where A-J are the 10 (ordered) * input constants. * @param ws The workspace to be transformed * @throw std::range_error if an attempt is made to take log of a negative * number */ void IQTransform::general(API::MatrixWorkspace_sptr ws) { MantidVec &X = ws->dataX(0); MantidVec &Y = ws->dataY(0); MantidVec &E = ws->dataE(0); const std::vector<double> C = getProperty("GeneralFunctionConstants"); // Check for the correct number of elements if (C.size() != 10) { std::string mess( "The General transformation requires 10 values to be provided."); g_log.error(mess); throw std::invalid_argument(mess); } for (size_t i = 0; i < Y.size(); ++i) { double tmpX = std::pow(X[i], C[7]) * std::pow(Y[i], C[8]) * C[9]; if (tmpX <= 0.0) throw std::range_error( "Attempt to take log of a zero or negative number."); tmpX = std::pow(X[i], C[5]) * std::pow(Y[i], C[6]) * std::log(tmpX); const double tmpY = std::pow(X[i], C[2]) * std::pow(Y[i], C[3]) * C[4]; if (tmpY <= 0.0) throw std::range_error( "Attempt to take log of a zero or negative number."); const double newY = std::pow(X[i], C[0]) * std::pow(Y[i], C[1]) * std::log(tmpY); E[i] *= std::pow(X[i], C[0]) * (C[1] * std::pow(Y[i], C[1] - 1) * std::log(tmpY) + ((std::pow(Y[i], C[1]) * std::pow(X[i], C[2]) * C[4] * C[3] * std::pow(Y[i], C[3] - 1)) / tmpY)); X[i] = tmpX; Y[i] = newY; } std::stringstream ylabel; ylabel << "Q^" << C[0] << " x I^" << C[1] << " x Ln( Q^" << C[2] << " x I^" << C[3] << " x " << C[4] << ")"; ws->setYUnitLabel(ylabel.str()); std::stringstream xlabel; xlabel << "Q^" << C[5] << " x I^" << C[6] << " x Ln( Q^" << C[7] << " x I^" << C[8] << " x " << C[9] << ")"; m_label->setLabel(xlabel.str()); }
/** * Here is the main logic to perform the transformation, to calculate the bin *position in degree for each spectrum. * * The first part of the method is to check if the pixel position is inside the *ring defined as minRadio and maxRadio. * * To do this, it deducts the pixel position. This deduction follows the *followin assumption: * * - the spectrum_index == row number * - the position in the 'Y' direction is given by getAxis(1)[spectrum_index] * - the position in the 'X' direction is the central point of the bin *(dataX[column] + dataX[column+1])/2 * * Having the position of the pixel, as defined above, if the distance is *outside the ring defined by minRadio, maxRadio, * it defines the bin position as -1. * * If the pixel is inside the ring, it calculates the angle of the pixel and *calls fromAngleToBin to define the bin * position. * @param ws: pointer to the workspace * @param spectrum_index: index of the spectrum * @param bins_pos: bin positions (for each column inside the spectrum, the *correspondent bin_pos) */ void RingProfile::getBinForPixel(const API::MatrixWorkspace_sptr ws, int spectrum_index, std::vector<int> &bins_pos) { if (bins_pos.size() != ws->dataY(spectrum_index).size()) throw std::runtime_error("Invalid bin positions vector"); API::NumericAxis *oldAxis2 = dynamic_cast<API::NumericAxis *>(ws->getAxis(1)); // assumption y position is the ws->getAxis(1)(spectrum_index) if (!oldAxis2) { throw std::logic_error("Failed to cast workspace axis to NumericAxis"); } // calculate ypos, the difference of y - centre and the square of this // difference double ypos = (*oldAxis2)(spectrum_index); double diffy = ypos - centre_y; double diffy_quad = pow(diffy, 2.0); // the reference to X bins (the limits for each pixel in the horizontal // direction) auto xvec = ws->dataX(spectrum_index); // for each pixel inside this row for (size_t i = 0; i < xvec.size() - 1; i++) { double xpos = (xvec[i] + xvec[i + 1]) / 2.0; // the x position is the centre of the bins boundaries double diffx = xpos - centre_x; // calculate the distance => norm of pixel position - centre double distance = sqrt(pow(diffx, 2.0) + diffy_quad); // check if the distance is inside the ring if (distance < min_radius || distance > max_radius || distance == 0) { bins_pos[i] = -1; continue; } double angle = atan2(diffy, diffx); // call fromAngleToBin (radians) bins_pos[i] = fromAngleToBin(angle, false); } }
/** Performs the Debye-Bueche transformation: 1/sqrt(I) v Q^2 * The output is set to zero for negative input Y values * @param ws The workspace to be transformed */ void IQTransform::debyeBueche(API::MatrixWorkspace_sptr ws) { MantidVec &X = ws->dataX(0); MantidVec &Y = ws->dataY(0); MantidVec &E = ws->dataE(0); std::transform(X.begin(), X.end(), X.begin(), VectorHelper::Squares<double>()); for (size_t i = 0; i < Y.size(); ++i) { if (Y[i] > 0.0) { Y[i] = 1.0 / std::sqrt(Y[i]); E[i] *= std::pow(Y[i], 3); } else { Y[i] = 0.0; E[i] = 0.0; } } ws->setYUnitLabel("1/sqrt(I)"); m_label->setLabel("Q^2"); }
/** Create output workspace */ API::MatrixWorkspace_sptr GeneratePeaks::createOutputWorkspace() { // Reference workspace and output workspace API::MatrixWorkspace_sptr outputWS; m_newWSFromParent = true; if (!inputWS && binParameters.empty()) { // Error! Neither bin parameters or reference workspace is given. std::string errmsg("Must define either InputWorkspace or BinningParameters."); g_log.error(errmsg); throw std::invalid_argument(errmsg); } else if (inputWS) { // Generate Workspace2D from input workspace if (!binParameters.empty()) g_log.notice() << "Both binning parameters and input workspace are given. " << "Using input worksapce to generate output workspace!\n"; outputWS = API::WorkspaceFactory::Instance().create(inputWS, inputWS->getNumberHistograms(), inputWS->dataX(0).size(), inputWS->dataY(0).size()); std::set<specid_t>::iterator siter; // Only copy the X-values from spectra with peaks specified in the table workspace. for (siter = m_spectraSet.begin(); siter != m_spectraSet.end(); ++siter) { specid_t iws = *siter; std::copy(inputWS->dataX(iws).begin(), inputWS->dataX(iws).end(), outputWS->dataX(iws).begin()); } m_newWSFromParent = true; } else { // Generate a one-spectrum Workspace2D from binning outputWS = createDataWorkspace(binParameters); m_newWSFromParent = false; } return outputWS; }
/** Unwraps an X array, converting the units to wavelength along the way. * @param tempWS :: A pointer to the temporary workspace in which the results * are being stored * @param spectrum :: The workspace index * @param Ld :: The flightpath for the detector related to this spectrum * @return A 3-element vector containing the bins at which the upper and lower * ranges start & end */ const std::vector<int> UnwrapMonitor::unwrapX(const API::MatrixWorkspace_sptr &tempWS, const int &spectrum, const double &Ld) { // Create and initalise the vector that will store the bin ranges, and will be // returned // Elements are: 0 - Lower range start, 1 - Lower range end, 2 - Upper range // start std::vector<int> binRange(3, -1); // Calculate cut-off times const double T1 = m_Tmax - (m_Tmin * (1 - (Ld / m_LRef))); const double T2 = m_Tmax * (Ld / m_LRef); // Create a temporary vector to store the lower range of the unwrapped // histograms std::vector<double> tempX_L; tempX_L.reserve( m_XSize); // Doing this possible gives a small efficiency increase // Create a vector for the upper range. Make it a reference to the output // histogram to save an assignment later MantidVec &tempX_U = tempWS->dataX(spectrum); tempX_U.clear(); tempX_U.reserve(m_XSize); // Get a reference to the input x data const MantidVec &xdata = m_inputWS->readX(spectrum); // Loop over histogram, selecting bins in appropriate ranges. // At the moment, the data in the bin in which a cut-off sits is excluded. for (unsigned 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 = xdata[bin]; // First deal with bins where m_Tmin < tof < T2 if (tof < T2) { const double wavelength = (m_conversionConstant * tof) / Ld; tempX_L.push_back(wavelength); // Record the bins that fall in this range for copying over the data & // errors if (binRange[0] == -1) binRange[0] = bin; binRange[1] = bin; } // Now do the bins where T1 < tof < m_Tmax else if (tof > T1) { const double velocity = Ld / (tof - m_Tmax + m_Tmin); const double wavelength = m_conversionConstant / velocity; tempX_U.push_back(wavelength); // Remove the duplicate boundary bin if (tof == m_Tmax && std::abs(wavelength - tempX_L.front()) < 1.0e-5) tempX_U.pop_back(); // Record the bins that fall in this range for copying over the data & // errors if (binRange[2] == -1) binRange[2] = bin; } } // loop over X values // Deal with the (rare) case that a detector (e.g. downstream monitor) is at a // longer flightpath than m_LRef if (Ld > m_LRef) { std::pair<int, int> binLimits = this->handleFrameOverlapped(xdata, Ld, tempX_L); binRange[0] = binLimits.first; binRange[1] = binLimits.second; } // Record the point at which the unwrapped sections are joined, first time // through only Property *join = getProperty("JoinWavelength"); if (join->isDefault()) { g_log.information() << "Joining wavelength: " << tempX_L.front() << " Angstrom\n"; setProperty("JoinWavelength", tempX_L.front()); } // Append first vector to back of second tempX_U.insert(tempX_U.end(), tempX_L.begin(), tempX_L.end()); return binRange; }
/** * Splits multiperiod histogram data into seperate workspaces and puts them in * a group * * @param numPeriods :: number of periods **/ void LoadNexusMonitors2::splitMutiPeriodHistrogramData( const size_t numPeriods) { // protection - we should not have entered the routine if these are not true // More than 1 period if (numPeriods < 2) { g_log.warning() << "Attempted to split multiperiod histogram workspace with " << numPeriods << "periods, aborted." << std::endl; return; } // Y array should be divisible by the number of periods if (m_workspace->blocksize() % numPeriods != 0) { g_log.warning() << "Attempted to split multiperiod histogram workspace with " << m_workspace->blocksize() << "data entries, into " << numPeriods << "periods." " Aborted." << std::endl; return; } WorkspaceGroup_sptr wsGroup(new WorkspaceGroup); size_t yLength = m_workspace->blocksize() / numPeriods; size_t xLength = yLength + 1; size_t numSpectra = m_workspace->getNumberHistograms(); ISISRunLogs monLogCreator(m_workspace->run(), static_cast<int>(numPeriods)); for (size_t i = 0; i < numPeriods; i++) { // create the period workspace API::MatrixWorkspace_sptr wsPeriod = API::WorkspaceFactory::Instance().create(m_workspace, numSpectra, xLength, yLength); // assign x values - restart at start for all periods for (size_t specIndex = 0; specIndex < numSpectra; specIndex++) { MantidVec &outputVec = wsPeriod->dataX(specIndex); const MantidVec &inputVec = m_workspace->readX(specIndex); for (size_t index = 0; index < xLength; index++) { outputVec[index] = inputVec[index]; } } // assign y values - use the values offset by the period number for (size_t specIndex = 0; specIndex < numSpectra; specIndex++) { MantidVec &outputVec = wsPeriod->dataY(specIndex); const MantidVec &inputVec = m_workspace->readY(specIndex); for (size_t index = 0; index < yLength; index++) { outputVec[index] = inputVec[(yLength * i) + index]; } } // assign E values for (size_t specIndex = 0; specIndex < numSpectra; specIndex++) { MantidVec &outputVec = wsPeriod->dataE(specIndex); const MantidVec &inputVec = m_workspace->readE(specIndex); for (size_t index = 0; index < yLength; index++) { outputVec[index] = inputVec[(yLength * i) + index]; } } // add period logs monLogCreator.addPeriodLogs(static_cast<int>(i + 1), wsPeriod->mutableRun()); // add to workspace group wsGroup->addWorkspace(wsPeriod); } // set the output workspace this->setProperty("OutputWorkspace", wsGroup); }
/** 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 }
/** * 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; }
/** * Executes the algorithm */ void ScaleX::exec() { //Get input workspace and offset const MatrixWorkspace_sptr inputW = getProperty("InputWorkspace"); m_algFactor = getProperty("Factor"); m_parname = getPropertyValue("InstrumentParameter"); m_combine = getProperty("Combine"); if(m_combine && m_parname.empty()) { throw std::invalid_argument("Combine behaviour requested but the InstrumentParameter argument is blank."); } const std::string op = getPropertyValue("Operation"); API::MatrixWorkspace_sptr outputW = createOutputWS(inputW); //Get number of histograms int histnumber = static_cast<int>(inputW->getNumberHistograms()); m_progress = new API::Progress(this, 0.0, 1.0, histnumber+1); m_progress->report("Scaling X"); m_wi_min = 0; m_wi_max = histnumber-1; //check if workspace indexes have been set int tempwi_min = getProperty("IndexMin"); int tempwi_max = getProperty("IndexMax"); if ( tempwi_max != Mantid::EMPTY_INT() ) { if ((m_wi_min <= tempwi_min) && (tempwi_min <= tempwi_max) && (tempwi_max <= m_wi_max)) { m_wi_min = tempwi_min; m_wi_max = tempwi_max; } else { g_log.error("Invalid Workspace Index min/max properties"); throw std::invalid_argument("Inconsistent properties defined"); } } // Setup appropriate binary function const bool multiply = (op=="Multiply"); if(multiply) m_binOp = std::multiplies<double>(); else m_binOp = std::plus<double>(); //Check if its an event workspace EventWorkspace_const_sptr eventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputW); if (eventWS != NULL) { this->execEvent(); return; } // do the shift in X PARALLEL_FOR2(inputW, outputW) for (int i = 0; i < histnumber; ++i) { PARALLEL_START_INTERUPT_REGION //Copy y and e data auto & outY = outputW->dataY(i); outY = inputW->dataY(i); auto & outE = outputW->dataE(i); outE = inputW->dataE(i); auto & outX = outputW->dataX(i); const auto & inX = inputW->readX(i); //Change bin value by offset if ((i >= m_wi_min) && (i <= m_wi_max)) { double factor = getScaleFactor(inputW, i); // Do the offsetting std::transform(inX.begin(), inX.end(), outX.begin(), std::bind2nd(m_binOp, factor)); // reverse the vector if multiplicative factor was negative if(multiply && factor < 0.0) { std::reverse( outX.begin(), outX.end() ); std::reverse( outY.begin(), outY.end() ); std::reverse( outE.begin(), outE.end() ); } } else { outX = inX; //copy } m_progress->report("Scaling X"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // 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); }
/** Generate peaks in the given output workspace * @param functionmap :: map to contain the list of functions with key as their spectra * @param dataWS :: output matrix workspace */ void GeneratePeaks::generatePeaks(const std::map<specid_t, std::vector<std::pair<double, API::IFunction_sptr> > >& functionmap, API::MatrixWorkspace_sptr dataWS) { // Calcualte function std::map<specid_t, std::vector<std::pair<double, API::IFunction_sptr> > >::const_iterator mapiter; for (mapiter = functionmap.begin(); mapiter != functionmap.end(); ++mapiter) { // Get spec id and translated to wsindex in the output workspace specid_t specid = mapiter->first; specid_t wsindex; if (m_newWSFromParent) wsindex = specid; else wsindex = m_SpectrumMap[specid]; const std::vector<std::pair<double, API::IFunction_sptr> >& vec_centrefunc = mapiter->second; size_t numpeaksinspec = mapiter->second.size(); for (size_t ipeak = 0; ipeak < numpeaksinspec; ++ipeak) { const std::pair<double, API::IFunction_sptr>& centrefunc = vec_centrefunc[ipeak]; // Determine boundary API::IPeakFunction_sptr thispeak = getPeakFunction(centrefunc.second); double centre = centrefunc.first; double fwhm = thispeak->fwhm(); // const MantidVec& X = dataWS->dataX(wsindex); double leftbound = centre - m_numPeakWidth*fwhm; if (ipeak > 0) { // Not left most peak. API::IPeakFunction_sptr leftPeak = getPeakFunction(vec_centrefunc[ipeak-1].second); double middle = 0.5*(centre + leftPeak->centre()); if (leftbound < middle) leftbound = middle; } std::vector<double>::const_iterator left = std::lower_bound(X.begin(), X.end(), leftbound); if (left == X.end()) left = X.begin(); double rightbound = centre + m_numPeakWidth*fwhm; if (ipeak != numpeaksinspec-1) { // Not the rightmost peak IPeakFunction_sptr rightPeak = getPeakFunction(vec_centrefunc[ipeak+1].second); double middle = 0.5*(centre + rightPeak->centre()); if (rightbound > middle) rightbound = middle; } std::vector<double>::const_iterator right = std::lower_bound(left + 1, X.end(), rightbound); // Build domain & function API::FunctionDomain1DVector domain(left, right); //dataWS->dataX(wsindex)); // Evaluate the function API::FunctionValues values(domain); centrefunc.second->function(domain, values); // Put to output std::size_t offset = (left-X.begin()); std::size_t numY = values.size(); for (std::size_t i = 0; i < numY; i ++) { dataWS->dataY(wsindex)[i + offset] += values[i]; } } // ENDFOR(ipeak) } return; }
/** 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; }
/** 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 }
void LoadDaveGrp::exec() { const std::string filename = this->getProperty("Filename"); int yLength = 0; MantidVec *xAxis = new MantidVec(); MantidVec *yAxis = new MantidVec(); std::vector<MantidVec *> data; std::vector<MantidVec *> errors; this->ifile.open(filename.c_str()); if (this->ifile.is_open()) { // Size of x axis this->getAxisLength(this->xLength); // Size of y axis this->getAxisLength(yLength); // This is also the number of groups (spectra) this->nGroups = yLength; // Read in the x axis values this->getAxisValues(xAxis, static_cast<std::size_t>(this->xLength)); // Read in the y axis values this->getAxisValues(yAxis, static_cast<std::size_t>(yLength)); // Read in the data this->getData(data, errors); } this->ifile.close(); // Scale the x-axis if it is in micro-eV to get it to meV const bool isUeV = this->getProperty("IsMicroEV"); if (isUeV) { MantidVec::iterator iter; for (iter = xAxis->begin(); iter != xAxis->end(); ++iter) { *iter /= 1000.0; } } // Create workspace API::MatrixWorkspace_sptr outputWorkspace = \ boost::dynamic_pointer_cast<API::MatrixWorkspace>\ (API::WorkspaceFactory::Instance().create("Workspace2D", this->nGroups, this->xLength, yLength)); // Force the workspace to be a distribution outputWorkspace->isDistribution(true); // Set the x-axis units outputWorkspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(this->getProperty("XAxisUnits")); API::Axis* const verticalAxis = new API::NumericAxis(yLength); // Set the y-axis units verticalAxis->unit() = Kernel::UnitFactory::Instance().create(this->getProperty("YAxisUnits")); outputWorkspace->replaceAxis(1, verticalAxis); for(int i = 0; i < this->nGroups; i++) { outputWorkspace->dataX(i) = *xAxis; outputWorkspace->dataY(i) = *data[i]; outputWorkspace->dataE(i) = *errors[i]; verticalAxis->setValue(i, yAxis->at(i)); delete data[i]; delete errors[i]; } delete xAxis; delete yAxis; outputWorkspace->mutableRun().addProperty("Filename",filename); this->setProperty("OutputWorkspace", outputWorkspace); }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroups( API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum ISpectrum * outSpec = outputWS->getSpectrum(outIndex); // The spectrum number of the group is the key outSpec->setSpectrumNo(it->first); // Start fresh with no detector IDs outSpec->clearDetectorIDs(); // Copy over X data from first spectrum, the bin boundaries for all spectra are assumed to be the same here outSpec->dataX() = inputWS->readX(0); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; // detectors to add to firstSpecNum const ISpectrum * fromSpectrum = inputWS->getSpectrum(originalWI); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = outSpec->dataY(); MantidVec::iterator fYit; MantidVec::iterator fEit = outSpec->dataE().begin(); MantidVec::const_iterator Yit = fromSpectrum->dataY().begin(); MantidVec::const_iterator Eit = fromSpectrum->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = std::sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // detectors to add to the output spectrum outSpec->addDetectorIDs(fromSpectrum->getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** 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); }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroupsEvent( DataObjects::EventWorkspace_const_sptr inputWS, DataObjects::EventWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum EventList & outEL = outputWS->getEventList(outIndex); // The spectrum number of the group is the key outEL.setSpectrumNo(it->first); // Start fresh with no detector IDs outEL.clearDetectorIDs(); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; const EventList & fromEL=inputWS->getEventList(originalWI); //Add the event lists with the operator outEL += fromEL; // detectors to add to the output spectrum outEL.addDetectorIDs(fromEL.getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->doneAddingEventLists(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** Convert the workspace units using TOF as an intermediate step in the * conversion * @param fromUnit :: The unit of the input workspace * @param outputWS :: The output workspace */ void ConvertUnitsUsingDetectorTable::convertViaTOF( Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_sptr outputWS) { using namespace Geometry; // Let's see if we are using a TableWorkspace to override parameters TableWorkspace_sptr paramWS = getProperty("DetectorParameters"); // See if we have supplied a DetectorParameters Workspace // TODO: Check if paramWS is NULL and if so throw an exception // const std::string l1ColumnLabel("l1"); // Let's check all the columns exist and are readable try { auto spectraColumnTmp = paramWS->getColumn("spectra"); auto l1ColumnTmp = paramWS->getColumn("l1"); auto l2ColumnTmp = paramWS->getColumn("l2"); auto twoThetaColumnTmp = paramWS->getColumn("twotheta"); auto efixedColumnTmp = paramWS->getColumn("efixed"); auto emodeColumnTmp = paramWS->getColumn("emode"); } catch (...) { throw Exception::InstrumentDefinitionError( "DetectorParameter TableWorkspace is not defined correctly."); } // Now let's read them into some vectors. auto l1Column = paramWS->getColVector<double>("l1"); auto l2Column = paramWS->getColVector<double>("l2"); auto twoThetaColumn = paramWS->getColVector<double>("twotheta"); auto efixedColumn = paramWS->getColVector<double>("efixed"); auto emodeColumn = paramWS->getColVector<int>("emode"); auto spectraColumn = paramWS->getColVector<int>("spectra"); EventWorkspace_sptr eventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check Progress prog(this, 0.2, 1.0, m_numberOfSpectra); int64_t numberOfSpectra_i = static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy // Get the unit object for each workspace Kernel::Unit_const_sptr outputUnit = outputWS->getAxis(0)->unit(); std::vector<double> emptyVec; int failedDetectorCount = 0; // ConstColumnVector<int> spectraNumber = paramWS->getVector("spectra"); // TODO: Check why this parallel stuff breaks // Loop over the histograms (detector spectra) // PARALLEL_FOR1(outputWS) for (int64_t i = 0; i < numberOfSpectra_i; ++i) { // Lets find what row this spectrum ID appears in our detector table. // PARALLEL_START_INTERUPT_REGION std::size_t wsid = i; try { double deg2rad = M_PI / 180.; auto det = outputWS->getDetector(i); int specid = det->getID(); // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i)); // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber); g_log.debug() << "###### Spectra #" << specid << " ==> Workspace ID:" << wsid << std::endl; // Now we need to find the row that contains this spectrum std::vector<int>::iterator specIter; specIter = std::find(spectraColumn.begin(), spectraColumn.end(), specid); if (specIter != spectraColumn.end()) { size_t detectorRow = std::distance(spectraColumn.begin(), specIter); double l1 = l1Column[detectorRow]; double l2 = l2Column[detectorRow]; double twoTheta = twoThetaColumn[detectorRow] * deg2rad; double efixed = efixedColumn[detectorRow]; int emode = emodeColumn[detectorRow]; g_log.debug() << "specId from detector table = " << spectraColumn[detectorRow] << std::endl; // l1 = l1Column->toDouble(detectorRow); // l2 = l2Column->toDouble(detectorRow); // twoTheta = deg2rad * twoThetaColumn->toDouble(detectorRow); // efixed = efixedColumn->toDouble(detectorRow); // emode = static_cast<int>(emodeColumn->toDouble(detectorRow)); g_log.debug() << "###### Spectra #" << specid << " ==> Det Table Row:" << detectorRow << std::endl; g_log.debug() << "\tL1=" << l1 << ",L2=" << l2 << ",TT=" << twoTheta << ",EF=" << efixed << ",EM=" << emode << std::endl; // Make local copies of the units. This allows running the loop in // parallel Unit *localFromUnit = fromUnit->clone(); Unit *localOutputUnit = outputUnit->clone(); /// @todo Don't yet consider hold-off (delta) const double delta = 0.0; // Convert the input unit to time-of-flight localFromUnit->toTOF(outputWS->dataX(wsid), emptyVec, l1, l2, twoTheta, emode, efixed, delta); // Convert from time-of-flight to the desired unit localOutputUnit->fromTOF(outputWS->dataX(wsid), emptyVec, l1, l2, twoTheta, emode, efixed, delta); // EventWorkspace part, modifying the EventLists. if (m_inputEvents) { eventWS->getEventList(wsid) .convertUnitsViaTof(localFromUnit, localOutputUnit); } // Clear unit memory delete localFromUnit; delete localOutputUnit; } else { // Not found g_log.debug() << "Spectrum " << specid << " not found!" << std::endl; failedDetectorCount++; outputWS->maskWorkspaceIndex(wsid); } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector failedDetectorCount++; // Since you usually (always?) get to here when there's no attached // detectors, this call is // the same as just zeroing out the data (calling clearData on the // spectrum) outputWS->maskWorkspaceIndex(i); } prog.report("Convert to " + m_outputUnit->unitID()); // PARALLEL_END_INTERUPT_REGION } // loop over spectra // PARALLEL_CHECK_INTERUPT_REGION if (failedDetectorCount != 0) { g_log.information() << "Something went wrong for " << failedDetectorCount << " spectra. Masking spectrum." << std::endl; } if (m_inputEvents) eventWS->clearMRU(); }
/** 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 ScaleX::exec() { //Get input workspace and offset const MatrixWorkspace_sptr inputW = getProperty("InputWorkspace"); factor = getProperty("Factor"); API::MatrixWorkspace_sptr outputW = createOutputWS(inputW); //Get number of histograms int histnumber = static_cast<int>(inputW->getNumberHistograms()); m_progress = new API::Progress(this, 0.0, 1.0, histnumber+1); m_progress->report("Scaling X"); wi_min = 0; wi_max = histnumber-1; //check if workspace indexes have been set int tempwi_min = getProperty("IndexMin"); int tempwi_max = getProperty("IndexMax"); if ( tempwi_max != Mantid::EMPTY_INT() ) { if ((wi_min <= tempwi_min) && (tempwi_min <= tempwi_max) && (tempwi_max <= wi_max)) { wi_min = tempwi_min; wi_max = tempwi_max; } else { g_log.error("Invalid Workspace Index min/max properties"); throw std::invalid_argument("Inconsistent properties defined"); } } //Check if its an event workspace EventWorkspace_const_sptr eventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputW); if (eventWS != NULL) { this->execEvent(); return; } // do the shift in X PARALLEL_FOR2(inputW, outputW) for (int i=0; i < histnumber; ++i) { PARALLEL_START_INTERUPT_REGION //Do the offsetting for (int j=0; j < static_cast<int>(inputW->readX(i).size()); ++j) { //Change bin value by offset if ((i >= wi_min) && (i <= wi_max)) outputW->dataX(i)[j] = inputW->readX(i)[j] * factor; else outputW->dataX(i)[j] = inputW->readX(i)[j]; } //Copy y and e data outputW->dataY(i) = inputW->dataY(i); outputW->dataE(i) = inputW->dataE(i); if( (i >= wi_min) && (i <= wi_max) && factor<0 ) { std::reverse( outputW->dataX(i).begin(), outputW->dataX(i).end() ); std::reverse( outputW->dataY(i).begin(), outputW->dataY(i).end() ); std::reverse( outputW->dataE(i).begin(), outputW->dataE(i).end() ); } m_progress->report("Scaling X"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // 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); }