/**Convert a binned workspace to point data * * @param workspace :: The input workspace * @return the converted workspace containing point data */ MatrixWorkspace_sptr SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const { if (workspace->isHistogramData()) { const size_t histNo = workspace->getNumberHistograms(); const size_t size = workspace->y(0).size(); // make a new workspace for the point data MatrixWorkspace_sptr pointWorkspace = WorkspaceFactory::Instance().create(workspace, histNo, size, size); // loop over each histogram for (size_t i = 0; i < histNo; ++i) { const auto &xValues = workspace->x(i); pointWorkspace->setSharedY(i, workspace->sharedY(i)); auto &newXValues = pointWorkspace->mutableX(i); // set x values to be average of bin bounds for (size_t j = 0; j < size; ++j) { newXValues[j] = (xValues[j] + xValues[j + 1]) / 2; } } return pointWorkspace; } return workspace; }
/** Populates the output workspaces * @param inWS :: [input] The input workspace * @param spec :: [input] The current spectrum being analyzed * @param nspec :: [input] The total number of histograms in the input workspace * @param result :: [input] The result to be written in the output workspace * @param outWS :: [input] The output workspace to populate */ void MaxEnt::populateDataWS(const MatrixWorkspace_sptr &inWS, size_t spec, size_t nspec, const std::vector<double> &result, MatrixWorkspace_sptr &outWS) { if (result.size() % 2) throw std::invalid_argument("Cannot write results to output workspaces"); int npoints = static_cast<int>(result.size() / 2); int npointsX = inWS->isHistogramData() ? npoints + 1 : npoints; MantidVec X(npointsX); MantidVec YR(npoints); MantidVec YI(npoints); MantidVec E(npoints, 0.); double x0 = inWS->readX(spec)[0]; double dx = inWS->readX(spec)[1] - x0; for (int i = 0; i < npoints; i++) { X[i] = x0 + i * dx; YR[i] = result[2 * i]; YI[i] = result[2 * i + 1]; } if (npointsX == npoints + 1) X[npoints] = x0 + npoints * dx; outWS->dataX(spec).assign(X.begin(), X.end()); outWS->dataY(spec).assign(YR.begin(), YR.end()); outWS->dataE(spec).assign(E.begin(), E.end()); outWS->dataX(nspec + spec).assign(X.begin(), X.end()); outWS->dataY(nspec + spec).assign(YI.begin(), YI.end()); outWS->dataE(nspec + spec).assign(E.begin(), E.end()); }
/** * This function gets the input workspace. In the case for a RebinnedOutput * workspace, it must be cleaned before proceeding. Other workspaces are * untouched. * @return the input workspace, cleaned if necessary */ MatrixWorkspace_sptr Integration::getInputWorkspace() { MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); if (temp->id() == "RebinnedOutput") { // Clean the input workspace in the RebinnedOutput case for nan's and // inf's in order to treat the data correctly later. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); temp = alg->getProperty("OutputWorkspace"); } // To integrate point data it will be converted to histograms if (!temp->isHistogramData()) { auto alg = this->createChildAlgorithm("ConvertToHistogram"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_histogram"; alg->setProperty("OutputWorkspace", outName); alg->executeAsChildAlg(); temp = alg->getProperty("OutputWorkspace"); temp->setDistribution(true); } return temp; }
/** Compares the properties of the input workspace with the reference * @param ws : the testee workspace * @param checkNumberHistograms : whether to check also the number of histograms * @return : empty if compatible, error message otherwises */ std::string RunCombinationHelper::checkCompatibility(MatrixWorkspace_sptr ws, bool checkNumberHistograms) { std::string errors; if (ws->getNumberHistograms() != m_numberSpectra && checkNumberHistograms) errors += "different number of histograms; "; if (ws->getAxis(0)->unit()->unitID() != m_xUnit) errors += "different X units; "; if (ws->getAxis(1)->unit()->unitID() != m_spectrumAxisUnit) errors += "different spectrum axis units; "; if (ws->YUnit() != m_yUnit) errors += "different Y units; "; if (ws->isHistogramData() != m_isHistogramData) errors += "different distribution or histogram type; "; if (ws->detectorInfo().isScanning() != m_isScanning) errors += "a mix of workspaces with and without detector scans; "; if (m_isScanning && ws->detectorInfo().size() != m_numberDetectors) errors += "workspaces with detectors scans have different number of " "detectors; "; if (ws->getInstrument()->getName() != m_instrumentName) errors += "different instrument names; "; if (ws->getNumberHistograms() == m_numberSpectra) { if (!m_hasDx.empty()) { for (unsigned int i = 0; i < m_numberSpectra; ++i) { if (m_hasDx[i] != ws->hasDx(i)) { errors += "spectra must have either Dx values or not; "; break; } } } } return errors; }
/** * Returns true if the algorithm needs to be run. * @param inputWS pointer to input workspace * @returns True if the input workspace needs to be run through this algorithm */ bool ConvertToPointData::isProcessingRequired(const MatrixWorkspace_sptr inputWS) const { if( !inputWS->isHistogramData() ) { g_log.information() << "Input workspace already contains point data. " << "OutputWorkspace set to InputWorkspace value.\n"; return false; } return true; }
/**Convert a binned workspace to point data * * @param workspace :: The input workspace * @return the converted workspace containing point data */ MatrixWorkspace_sptr SplineSmoothing::convertBinnedData(MatrixWorkspace_sptr workspace) { if (workspace->isHistogramData()) { auto alg = createChildAlgorithm("ConvertToPointData"); alg->setProperty("InputWorkspace", workspace); alg->execute(); return alg->getProperty("OutputWorkspace"); } else { return workspace; } }
/** Sets the properties of the reference (usually first) workspace, * to later check the compatibility of the others with the reference * @param ref : the reference workspace */ void RunCombinationHelper::setReferenceProperties(MatrixWorkspace_sptr ref) { m_numberSpectra = ref->getNumberHistograms(); m_numberDetectors = ref->detectorInfo().size(); m_xUnit = ref->getAxis(0)->unit()->unitID(); m_spectrumAxisUnit = ref->getAxis(1)->unit()->unitID(); m_yUnit = ref->YUnit(); m_isHistogramData = ref->isHistogramData(); m_isScanning = ref->detectorInfo().isScanning(); m_instrumentName = ref->getInstrument()->getName(); if (m_numberSpectra) { m_hasDx.reserve(m_numberSpectra); for (unsigned int i = 0; i < m_numberSpectra; ++i) m_hasDx.push_back(ref->hasDx(i)); } }
void IQTransform::exec() { MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); // Print a warning if the input workspace has more than one spectrum if ( inputWS->getNumberHistograms() > 1 ) { g_log.warning("This algorithm is intended for use on single-spectrum workspaces.\n" "Only the first spectrum will be transformed."); } // Do background subtraction from a workspace first because it doesn't like // potential conversion to point data that follows. Requires a temporary workspace. MatrixWorkspace_sptr tmpWS; MatrixWorkspace_sptr backgroundWS = getProperty("BackgroundWorkspace"); if ( backgroundWS ) tmpWS = subtractBackgroundWS(inputWS,backgroundWS); else tmpWS = inputWS; // Create the output workspace const size_t length = tmpWS->blocksize(); MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS,1,length,length); m_label->setLabel(""); outputWS->setYUnit(""); // Copy the data over. Assume single spectrum input (output will be). // Take the mid-point of histogram bins if ( tmpWS->isHistogramData() ) { VectorHelper::convertToBinCentre(tmpWS->readX(0),outputWS->dataX(0)); } else { outputWS->setX(0,tmpWS->refX(0)); } MantidVec& Y = outputWS->dataY(0) = tmpWS->dataY(0); outputWS->dataE(0) = tmpWS->dataE(0); // Subtract a constant background if requested const double background = getProperty("BackgroundValue"); if ( background > 0.0 ) subtractBackgroundValue(Y,background); // Select the desired transformation function and call it TransformFunc f = m_transforms.find(getProperty("TransformType"))->second; (this->*f)(outputWS); // Need the generic label unit on this (unless the unit on the X axis hasn't changed) if ( ! m_label->caption().empty() ) outputWS->getAxis(0)->unit() = m_label; setProperty("OutputWorkspace",outputWS); }
void NormaliseToMonitor::exec() { // Get the input workspace const MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // First check the inputs checkProperties(inputWS); bool isSingleCountWorkspace = false; try { isSingleCountWorkspace = (!inputWS->isHistogramData()) && (inputWS->blocksize() == 1); } catch (std::length_error &) { // inconsistent bin size, not a single count workspace isSingleCountWorkspace = false; } // See if the normalization with integration properties are set. const bool integrate = setIntegrationProps(isSingleCountWorkspace); if (integrate) normaliseByIntegratedCount(inputWS, outputWS, isSingleCountWorkspace); else normaliseBinByBin(inputWS, outputWS); setProperty("OutputWorkspace", outputWS); std::string norm_ws_name = getPropertyValue("NormFactorWS"); if (!norm_ws_name.empty()) { std::string out_name = getPropertyValue("OutputWorkspace"); if (out_name == norm_ws_name) { // if the normalization factor workspace name coincides with output // workspace name, add _normFactor suffix to this name norm_ws_name = norm_ws_name + "_normFactor"; auto pProp = (this->getPointerToProperty("NormFactorWS")); pProp->setValue(norm_ws_name); } if (!integrate) m_monitor = extractMonitorSpectra(m_monitor, m_workspaceIndexes); setProperty("NormFactorWS", m_monitor); } }
void FFTDerivative::execRealFFT() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outWS; size_t n = inWS->getNumberHistograms(); API::Progress progress(this,0,1,n); size_t ny = inWS->readY(0).size(); size_t nx = inWS->readX(0).size(); // Workspace for holding a copy of a spectrum. Each spectrum is symmetrized to minimize // possible edge effects. MatrixWorkspace_sptr copyWS = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace> (Mantid::API::WorkspaceFactory::Instance().create(inWS,1,nx+ny,ny+ny)); bool isHist = (nx != ny); for(size_t spec = 0; spec < n; ++spec) { const Mantid::MantidVec& x0 = inWS->readX(spec); const Mantid::MantidVec& y0 = inWS->readY(spec); Mantid::MantidVec& x1 = copyWS->dataX(0); Mantid::MantidVec& y1 = copyWS->dataY(0); double xx = 2*x0[0]; x1[ny] = x0[0]; y1[ny] = y0[0]; for(size_t i = 1; i < ny; ++i) { size_t j1 = ny - i; size_t j2 = ny + i; x1[j1] = xx - x0[i]; x1[j2] = x0[i]; y1[j1] = y1[j2] = y0[i]; } x1[0] = 2*x1[1] - x1[2]; y1[0] = y0.back(); if (isHist) { x1[y1.size()] = x0[ny]; } // Transform symmetrized spectrum IAlgorithm_sptr fft = createChildAlgorithm("RealFFT"); fft->setProperty("InputWorkspace",copyWS); fft->setProperty("WorkspaceIndex",0); fft->setProperty("Transform","Forward"); fft->execute(); MatrixWorkspace_sptr transWS = fft->getProperty("OutputWorkspace"); Mantid::MantidVec& nu = transWS->dataX(0); Mantid::MantidVec& re = transWS->dataY(0); Mantid::MantidVec& im = transWS->dataY(1); int dn = getProperty("Order"); bool swap_re_im = dn % 2 != 0; int sign_re = 1; int sign_im = -1; switch(dn % 4) { case 1: sign_re = 1; sign_im = -1; break; case 2: sign_re = -1; sign_im = -1; break; case 3: sign_re = -1; sign_im = 1; break; } // Multiply the transform by (2*pi*i*w)**dn for(size_t j=0; j < re.size(); ++j) { double w = 2 * M_PI * nu[j]; double ww = w; for(int k = dn; k > 1; --k) { ww *= w; } double a = sign_re * re[j]*ww; double b = sign_im * im[j]*ww; if (swap_re_im) { re[j] = b; im[j] = a; } else { re[j] = a; im[j] = b; } } // Inverse transform fft = createChildAlgorithm("RealFFT"); fft->setProperty("InputWorkspace",transWS); fft->setProperty("Transform","Backward"); fft->execute(); transWS = fft->getProperty("OutputWorkspace"); size_t m2 = transWS->readY(0).size() / 2; size_t my = m2 + ((transWS->readY(0).size() % 2) ? 1 : 0); size_t mx = my + (transWS->isHistogramData() ? 1 : 0); if (!outWS) { outWS = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace> (Mantid::API::WorkspaceFactory::Instance().create(inWS,n,mx,my)); } // Save the upper half of the inverse transform for output Mantid::MantidVec& x = outWS->dataX(spec); Mantid::MantidVec& y = outWS->dataY(spec); double dx = x1[0]; std::copy(transWS->dataX(0).begin() + m2,transWS->dataX(0).end(),x.begin()); std::transform(x.begin(),x.end(),x.begin(),std::bind2nd(std::plus<double>(),dx)); std::copy(transWS->dataY(0).begin() + m2,transWS->dataY(0).end(),y.begin()); // shift the data to make x and x0 match. using linear interpolation. if (x.size() != x0.size() && false)// TODO: doesn't work at the moment. needs to be working { std::cerr << "(my != x0.size()) " << x0[0] << "!=" << x[0] << std::endl; dx = x0[0] - x[0]; assert(dx > 0.0); double f = (x0[0] - x[0]) / (x0[1] - x0[0]); for(size_t i = 0; i < my - 1; ++i) { y[i] += (y[i+1] - y[i]) * f; x[i] = x0[i]; } x.back() += dx; } progress.report(); } setProperty("OutputWorkspace",outWS); }
/** Execute the algorithm. */ void ResampleX::exec() { // generically having access to the input workspace is a good idea MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); const int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); m_numBins = getProperty("NumberBins"); m_preserveEvents = getProperty("PreserveEvents"); // determine the xmin/xmax for the workspace vector<double> xmins = getProperty("XMin"); vector<double> xmaxs = getProperty("XMax"); string error = determineXMinMax(inputWS, xmins, xmaxs); if (!error.empty()) throw std::runtime_error(error); bool common_limits = true; { double xmin_common = xmins[0]; double xmax_common = xmaxs[0]; for (size_t i = 1; i < xmins.size(); ++i) { if (xmins[i] != xmin_common) { common_limits = false; break; } if (xmaxs[i] != xmax_common) { common_limits = false; break; } } } if (common_limits) { g_log.debug() << "Common limits between all spectra\n"; } else { g_log.debug() << "Does not have common limits between all spectra\n"; } // start doing actual work EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS != nullptr) { if (m_preserveEvents) { if (inPlace) { g_log.debug() << "Rebinning event workspace in place\n"; } else { g_log.debug() << "Rebinning event workspace out of place\n"; outputWS = inputWS->clone(); } auto outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (common_limits) { // get the delta from the first since they are all the same BinEdges xValues(0); const double delta = this->determineBinning(xValues.mutableRawData(), xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { // initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // do the rebinning PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION BinEdges xValues(0); const double delta = this->determineBinning( xValues.mutableRawData(), xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] << " xmax=" << xmaxs[wkspIndex] << "\n"; outputEventWS->setHistogram(wkspIndex, xValues); prog.report(name()); // Report progress PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } } // end if (m_preserveEvents) else // event workspace -> matrix workspace { //--------- Different output, OR you're inplace but not preserving Events g_log.information() << "Creating a Workspace2D from the EventWorkspace " << inputEventWS->getName() << ".\n"; outputWS = create<DataObjects::Workspace2D>( *inputWS, numSpectra, HistogramData::BinEdges(m_numBins + 1)); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // Go through all the histograms and set the data PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram MantidVec xValues; const double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; outputWS->setBinEdges(wkspIndex, xValues); // Get a const event list reference. inputEventWS->dataY() doesn't work. const EventList &el = inputEventWS->getSpectrum(wkspIndex); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(xValues, y_data, e_data); // Copy the data over. outputWS->mutableY(wkspIndex) = std::move(y_data); outputWS->mutableE(wkspIndex) = std::move(e_data); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) { outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } outputWS->setYUnit(inputEventWS->YUnit()); outputWS->setYUnitLabel(inputEventWS->YUnitLabel()); } // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); return; } else // (inputeventWS != NULL)
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("Workspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getProperty("SigmaModerator"); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0); const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; for (size_t i = 0; i < xInterpolate.size() - 1; ++i) { const double midpoint = xInterpolate[i + 1] - xInterpolate[i]; lookUpTable.addPoint(midpoint, yInterpolate[i]); } } else { for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } } const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (!det || det->isMonitor() || det->isMasked()) continue; // Get the flight path from the sample to the detector pixel const V3D scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1 + L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * (3.0 * R1 * R1 / (L1 * L1) + 3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) + (deltaR * deltaR) / (L2 * L2)); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin(theta / 2.0); const MantidVec &xIn = inOutWS->readX(i); MantidVec &yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // wavelenght spread from moderatorm, converted from microseconds to // wavelengths const double sigmaModerator = lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum); // calculate wavelenght resolution from moderator and histogram time bin const double sigmaLambda = std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 + sigmaModerator * sigmaModerator); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl; const double sigmaQ = std::sqrt( dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); } }
/** Execute the algorithm. */ void ResampleX::exec() { // generically having access to the input workspace is a good idea MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); m_numBins = getProperty("NumberBins"); m_preserveEvents = getProperty("PreserveEvents"); // determine the xmin/xmax for the workspace vector<double> xmins = getProperty("XMin"); vector<double> xmaxs = getProperty("XMax"); string error = determineXMinMax(inputWS, xmins, xmaxs); if (!error.empty()) throw std::runtime_error(error); bool common_limits = true; { double xmin_common = xmins[0]; double xmax_common = xmaxs[0]; for (size_t i = 1; i < xmins.size(); ++i) { if (xmins[i] != xmin_common) { common_limits = false; break; } if (xmaxs[i] != xmax_common) { common_limits = false; break; } } } if (common_limits) { g_log.debug() << "Common limits between all spectra\n"; } else { g_log.debug() << "Does not have common limits between all spectra\n"; } // start doing actual work EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS != NULL) { if (m_preserveEvents) { EventWorkspace_sptr outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (inPlace) { g_log.debug() << "Rebinning event workspace in place\n"; } else { g_log.debug() << "Rebinning event workspace out of place\n"; // copy the event workspace to a new EventWorkspace outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create( "EventWorkspace", inputWS->getNumberHistograms(), 2, 1)); // copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( inputEventWS, outputEventWS, false); // copy over the data as well. outputEventWS->copyDataFrom((*inputEventWS)); } if (common_limits) { // get the delta from the first since they are all the same MantidVecPtr xValues; double delta = this->determineBinning(xValues.access(), xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { // initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // do the rebinning PARALLEL_FOR2(inputEventWS, outputWS) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION MantidVec xValues; double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] << " xmax=" << xmaxs[wkspIndex] << "\n"; outputEventWS->getSpectrum(wkspIndex)->setX(xValues); prog.report(name()); // Report progress PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(outputEventWS)); } // end if (m_preserveEvents) else // event workspace -> matrix workspace { //--------- Different output, OR you're inplace but not preserving Events //--- create a Workspace2D ------- g_log.information() << "Creating a Workspace2D from the EventWorkspace " << inputEventWS->getName() << ".\n"; // Create a Workspace2D // This creates a new Workspace2D through a torturous route using the // WorkspaceFactory. // The Workspace2D is created with an EMPTY CONSTRUCTOR outputWS = WorkspaceFactory::Instance().create("Workspace2D", numSpectra, m_numBins, m_numBins - 1); WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, true); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // Go through all the histograms and set the data PARALLEL_FOR2(inputEventWS, outputWS) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram MantidVec xValues; double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; outputWS->setX(wkspIndex, xValues); // Get a const event list reference. inputEventWS->dataY() doesn't work. const EventList &el = inputEventWS->getEventList(wkspIndex); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(xValues, y_data, e_data); // Copy the data over. outputWS->dataY(wkspIndex).assign(y_data.begin(), y_data.end()); outputWS->dataE(wkspIndex).assign(e_data.begin(), e_data.end()); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); outputWS->setYUnit(inputEventWS->YUnit()); outputWS->setYUnitLabel(inputEventWS->YUnitLabel()); // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); } return; } else // (inputeventWS != NULL)
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); const bool doGravity = getProperty("AccountForGravity"); // Check the input checkInput(inWS); // Setup outputworkspace auto outWS = setupOutputWorkspace(inWS); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; // The moderator workspace needs to match the data workspace // in terms of wavelength binning const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getModeratorWorkspace(inWS); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const auto &xInterpolate = sigmaModeratorVSwavelength->points(0); const auto &yInterpolate = sigmaModeratorVSwavelength->y(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; } for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } // Calculate the L1 distance const V3D samplePos = inWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); // Get the collimation length double LCollim = getProperty("CollimationLength"); if (LCollim == 0.0) { auto collimationLengthEstimator = SANSCollimationLengthEstimator(); LCollim = collimationLengthEstimator.provideCollimationLength(inWS); g_log.information() << "No collimation length was specified. A default " "collimation length was estimated to be " << LCollim << '\n'; } else { g_log.information() << "The collimation length is " << LCollim << '\n'; } const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); const auto &spectrumInfo = inWS->spectrumInfo(); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; if (!spectrumInfo.hasDetectors(i)) { g_log.information() << "Workspace index " << i << " has no detector assigned to it - discarding\n"; continue; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) continue; const double L2 = spectrumInfo.l2(i); TOFSANSResolutionByPixelCalculator calculator; const double waveLengthIndependentFactor = calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = spectrumInfo.twoTheta(i); double sinTheta = sin(0.5 * theta); double factor = 4.0 * M_PI * sinTheta; const auto &xIn = inWS->x(i); const size_t xLength = xIn.size(); // Gravity correction std::unique_ptr<GravitySANSHelper> grav; if (doGravity) { grav = Kernel::make_unique<GravitySANSHelper>(spectrumInfo, i, getProperty("ExtraLength")); } // Get handles on the outputWorkspace auto &yOut = outWS->mutableY(i); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit // If we include a gravity correction we need to adjust sinTheta // for each wavelength (in Angstrom) if (doGravity) { double sinThetaGrav = grav->calcSinTheta(wl); factor = 4.0 * M_PI * sinThetaGrav; } const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // Get the uncertainty in Q auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl), waveLengthIndependentFactor, q, wl, sigmaSpreadFromBin, L1, L2); // Insert the Q value and the Q resolution into the outputworkspace yOut[j] = sigmaQ; } progress.report("Computing Q resolution"); } // Set the y axis label outWS->setYUnitLabel("QResolution"); setProperty("OutputWorkspace", outWS); }
/** Populates the output workspaces * @param inWS :: [input] The input workspace * @param spec :: [input] The current spectrum being analyzed * @param nspec :: [input] The total number of histograms in the input workspace * @param result :: [input] The result to be written in the output workspace * @param outWS :: [input] The output workspace to populate * @param autoShift :: [input] Whether or not to correct the phase shift */ void MaxEnt::populateImageWS(const MatrixWorkspace_sptr &inWS, size_t spec, size_t nspec, const std::vector<double> &result, MatrixWorkspace_sptr &outWS, bool autoShift) { if (result.size() % 2) throw std::invalid_argument("Cannot write results to output workspaces"); int npoints = static_cast<int>(result.size() / 2); int npointsX = inWS->isHistogramData() ? npoints + 1 : npoints; MantidVec X(npointsX); MantidVec YR(npoints); MantidVec YI(npoints); MantidVec E(npoints, 0.); double x0 = inWS->readX(spec)[0]; double dx = inWS->readX(spec)[1] - x0; double delta = 1. / dx / npoints; int isOdd = (inWS->blocksize() % 2) ? 1 : 0; double shift = x0 * 2 * M_PI; if (!autoShift) shift = 0; for (int i = 0; i < npoints; i++) { int j = (npoints / 2 + i + isOdd) % npoints; X[i] = delta * (-npoints / 2 + i); double xShift = X[i] * shift; double c = cos(xShift); double s = sin(xShift); YR[i] = result[2 * j] * c - result[2 * j + 1] * s; YI[i] = result[2 * j] * s + result[2 * j + 1] * c; YR[i] *= dx; YI[i] *= dx; } if (npointsX == npoints + 1) X[npoints] = X[npoints - 1] + delta; // Caption & label auto inputUnit = inWS->getAxis(0)->unit(); if (inputUnit) { boost::shared_ptr<Kernel::Units::Label> lblUnit = boost::dynamic_pointer_cast<Kernel::Units::Label>( UnitFactory::Instance().create("Label")); if (lblUnit) { lblUnit->setLabel( inverseCaption[inWS->getAxis(0)->unit()->caption()], inverseLabel[inWS->getAxis(0)->unit()->label().ascii()]); outWS->getAxis(0)->unit() = lblUnit; } } outWS->dataX(spec).assign(X.begin(), X.end()); outWS->dataY(spec).assign(YR.begin(), YR.end()); outWS->dataE(spec).assign(E.begin(), E.end()); outWS->dataX(nspec + spec).assign(X.begin(), X.end()); outWS->dataY(nspec + spec).assign(YI.begin(), YI.end()); outWS->dataE(nspec + spec).assign(E.begin(), E.end()); }
/** Execute the algorithm. */ void MaxEnt::exec() { // MaxEnt parameters // Complex data? bool complex = getProperty("ComplexData"); // Image must be positive? bool positiveImage = getProperty("PositiveImage"); // Autoshift bool autoShift = getProperty("AutoShift"); // Increase the number of points in the image by this factor size_t densityFactor = getProperty("DensityFactor"); // Background (default level, sky background, etc) double background = getProperty("A"); // Chi target double chiTarget = getProperty("ChiTarget"); // Required precision for Chi arget double chiEps = getProperty("ChiEps"); // Maximum degree of non-parallelism between S and C double angle = getProperty("MaxAngle"); // Distance penalty for current image double distEps = getProperty("DistancePenalty"); // Maximum number of iterations size_t niter = getProperty("MaxIterations"); // Maximum number of iterations in alpha chop size_t alphaIter = getProperty("AlphaChopIterations"); // Number of spectra and datapoints // Read input workspace MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); // Number of spectra size_t nspec = inWS->getNumberHistograms(); // Number of data points size_t npoints = inWS->blocksize() * densityFactor; // Number of X bins size_t npointsX = inWS->isHistogramData() ? npoints + 1 : npoints; // The type of entropy we are going to use (depends on the type of image, // positive only, or positive and/or negative) MaxentData_sptr maxentData; if (positiveImage) { maxentData = boost::make_shared<MaxentData>( boost::make_shared<MaxentEntropyPositiveValues>()); } else { maxentData = boost::make_shared<MaxentData>( boost::make_shared<MaxentEntropyNegativeValues>()); } // Output workspaces MatrixWorkspace_sptr outImageWS; MatrixWorkspace_sptr outDataWS; MatrixWorkspace_sptr outEvolChi; MatrixWorkspace_sptr outEvolTest; nspec = complex ? nspec / 2 : nspec; outImageWS = WorkspaceFactory::Instance().create(inWS, 2 * nspec, npointsX, npoints); outDataWS = WorkspaceFactory::Instance().create(inWS, 2 * nspec, npointsX, npoints); outEvolChi = WorkspaceFactory::Instance().create(inWS, nspec, niter, niter); outEvolTest = WorkspaceFactory::Instance().create(inWS, nspec, niter, niter); npoints *= 2; for (size_t s = 0; s < nspec; s++) { // Start distribution (flat background) std::vector<double> image(npoints, background); if (complex) { auto dataRe = inWS->readY(s); auto dataIm = inWS->readY(s + nspec); auto errorsRe = inWS->readE(s); auto errorsIm = inWS->readE(s + nspec); maxentData->loadComplex(dataRe, dataIm, errorsRe, errorsIm, image, background); } else { auto data = inWS->readY(s); auto error = inWS->readE(s); maxentData->loadReal(data, error, image, background); } // To record the algorithm's progress std::vector<double> evolChi(niter, 0.); std::vector<double> evolTest(niter, 0.); // Progress Progress progress(this, 0, 1, niter); // Run maxent algorithm for (size_t it = 0; it < niter; it++) { // Calculate quadratic model coefficients // (SB eq. 21 and 24) maxentData->calculateQuadraticCoefficients(); double currAngle = maxentData->getAngle(); double currChisq = maxentData->getChisq(); auto coeffs = maxentData->getQuadraticCoefficients(); // Calculate delta to construct new image (SB eq. 25) auto delta = move(coeffs, chiTarget / currChisq, chiEps, alphaIter); // Apply distance penalty (SB eq. 33) image = maxentData->getImage(); delta = applyDistancePenalty(delta, coeffs, image, background, distEps); // Update image according to 'delta' and calculate the new Chi-square maxentData->updateImage(delta); currChisq = maxentData->getChisq(); // Record the evolution of Chi-square and angle(S,C) evolChi[it] = currChisq; evolTest[it] = currAngle; // Stop condition, solution found if ((std::abs(currChisq / chiTarget - 1.) < chiEps) && (currAngle < angle)) { break; } // Check for canceling the algorithm if (!(it % 1000)) { interruption_point(); } progress.report(); } // iterations // Get calculated data auto solData = maxentData->getReconstructedData(); auto solImage = maxentData->getImage(); // Populate the output workspaces populateDataWS(inWS, s, nspec, solData, outDataWS); populateImageWS(inWS, s, nspec, solImage, outImageWS, autoShift); // Populate workspaces recording the evolution of Chi and Test // X values for (size_t it = 0; it < niter; it++) { outEvolChi->dataX(s)[it] = static_cast<double>(it); outEvolTest->dataX(s)[it] = static_cast<double>(it); } // Y values outEvolChi->dataY(s).assign(evolChi.begin(), evolChi.end()); outEvolTest->dataY(s).assign(evolTest.begin(), evolTest.end()); // No errors } // Next spectrum setProperty("EvolChi", outEvolChi); setProperty("EvolAngle", outEvolTest); setProperty("ReconstructedImage", outImageWS); setProperty("ReconstructedData", outDataWS); }
/** Executes the rebin algorithm * * @throw runtime_error Thrown if the bin range does not intersect the range of *the input workspace */ void Rebin::exec() { // Get the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // Are we preserving event workspace-iness? bool PreserveEvents = getProperty("PreserveEvents"); // Rebinning in-place bool inPlace = (inputWS == outputWS); std::vector<double> rbParams = rebinParamsFromInput(getProperty("Params"), *inputWS, g_log); const bool dist = inputWS->isDistribution(); const bool isHist = inputWS->isHistogramData(); // workspace independent determination of length const int histnumber = static_cast<int>(inputWS->getNumberHistograms()); //------------------------------------------------------- bool fullBinsOnly = getProperty("FullBinsOnly"); MantidVecPtr XValues_new; // create new output X axis const int ntcnew = VectorHelper::createAxisFromRebinParams( rbParams, XValues_new.access(), true, fullBinsOnly); //--------------------------------------------------------------------------------- // Now, determine if the input workspace is actually an EventWorkspace EventWorkspace_const_sptr eventInputWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventInputWS != NULL) { //------- EventWorkspace as input ------------------------------------- EventWorkspace_sptr eventOutputWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (inPlace && PreserveEvents) { // -------------Rebin in-place, preserving events // ---------------------------------------------- // This only sets the X axis. Actual rebinning will be done upon data // access. eventOutputWS->setAllX(XValues_new); this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(eventOutputWS)); } else if (!inPlace && PreserveEvents) { // -------- NOT in-place, but you want to keep events for some reason. // ---------------------- // Must copy the event workspace to a new EventWorkspace (and bin that). // Make a brand new EventWorkspace eventOutputWS = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create( "EventWorkspace", inputWS->getNumberHistograms(), 2, 1)); // Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( inputWS, eventOutputWS, false); // You need to copy over the data as well. eventOutputWS->copyDataFrom((*eventInputWS)); // This only sets the X axis. Actual rebinning will be done upon data // access. eventOutputWS->setAllX(XValues_new); // Cast to the matrixOutputWS and save it this->setProperty( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(eventOutputWS)); } else { //--------- Different output, OR you're inplace but not preserving Events //--- create a Workspace2D ------- g_log.information() << "Creating a Workspace2D from the EventWorkspace " << eventInputWS->getName() << ".\n"; // Create a Workspace2D // This creates a new Workspace2D through a torturous route using the // WorkspaceFactory. // The Workspace2D is created with an EMPTY CONSTRUCTOR outputWS = WorkspaceFactory::Instance().create("Workspace2D", histnumber, ntcnew, ntcnew - 1); WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, true); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, histnumber); // Go through all the histograms and set the data PARALLEL_FOR3(inputWS, eventInputWS, outputWS) for (int i = 0; i < histnumber; ++i) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram outputWS->setX(i, XValues_new); // Get a const event list reference. eventInputWS->dataY() doesn't work. const EventList &el = eventInputWS->getEventList(i); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(*XValues_new, y_data, e_data); // Copy the data over. outputWS->dataY(i).assign(y_data.begin(), y_data.end()); outputWS->dataE(i).assign(e_data.begin(), e_data.end()); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); outputWS->setYUnit(eventInputWS->YUnit()); outputWS->setYUnitLabel(eventInputWS->YUnitLabel()); // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); } } // END ---- EventWorkspace