/** Convert X units from nano-secs to micro-secs and shift to start at m_tMin * @param inputWs :: [input/output] workspace to convert */ void PhaseQuadMuon::convertToMicroSecs (API::MatrixWorkspace_sptr inputWs) { for (size_t h=0; h<inputWs->getNumberHistograms(); h++) { auto spec = inputWs->getSpectrum(h); for (int t=0; t<m_nData+1; t++) { spec->dataX()[t] = spec->dataX()[t]/1000+m_tMin; } } }
/** Loads, checks and passes back the values passed to the algorithm * @param whiteBeam1 :: A white beam vanadium spectrum that will be used to * check detector efficiency variations * @param whiteBeam2 :: The other white beam vanadium spectrum from the same * instrument to use for comparison * @param variation :: The maximum fractional variation above the median that is * allowed for god detectors * @param startWsIndex :: Index number of the first spectrum to use * @param endWsIndex :: Index number of the last spectrum to use * @throw invalid_argument if there is an incapatible property value and so the * algorithm can't continue */ void DetectorEfficiencyVariation::retrieveProperties( API::MatrixWorkspace_sptr &whiteBeam1, API::MatrixWorkspace_sptr &whiteBeam2, double &variation, int &startWsIndex, int &endWsIndex) { whiteBeam1 = getProperty("WhiteBeamBase"); whiteBeam2 = getProperty("WhiteBeamCompare"); if (whiteBeam1->getInstrument()->getName() != whiteBeam2->getInstrument()->getName()) { throw std::invalid_argument("The two input white beam vanadium workspaces " "must be from the same instrument"); } int maxWsIndex = static_cast<int>(whiteBeam1->getNumberHistograms()) - 1; if (maxWsIndex != static_cast<int>(whiteBeam2->getNumberHistograms()) - 1) { // we would get a crash later on if this were not true throw std::invalid_argument("The input white beam vanadium workspaces must " "be have the same number of histograms"); } variation = getProperty("Variation"); startWsIndex = getProperty("StartWorkspaceIndex"); if ((startWsIndex < 0) || (startWsIndex > maxWsIndex)) { g_log.warning("StartWorkspaceIndex out of range, changed to 0"); startWsIndex = 0; } endWsIndex = getProperty("EndWorkspaceIndex"); if (endWsIndex == Mantid::EMPTY_INT()) endWsIndex = maxWsIndex; if ((endWsIndex < 0) || (endWsIndex > maxWsIndex)) { g_log.warning( "EndWorkspaceIndex out of range, changed to max Workspace number"); endWsIndex = maxWsIndex; } if ((endWsIndex < startWsIndex)) { g_log.warning( "EndWorkspaceIndex can not be less than the StartWorkspaceIndex, " "changed to max Workspace number"); endWsIndex = maxWsIndex; } }
std::vector<std::vector<size_t> > DetectorDiagnostic::makeInstrumentMap(API::MatrixWorkspace_sptr countsWS) { std::vector<std::vector<size_t> > mymap; std::vector<size_t> single; for(size_t i=0;i < countsWS->getNumberHistograms();i++) { single.push_back(i); } mymap.push_back(single); return mymap; }
/*** * This will ensure the spectrum numbers do not overlap by starting the second *on at the first + 1 * * @param ws1 The first workspace supplied to the algorithm. * @param ws2 The second workspace supplied to the algorithm. * @param output The workspace that is going to be returned by the algorithm. */ void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2, API::MatrixWorkspace_sptr output) { bool needsFix(false); if (this->getProperty("CheckOverlapping")) { // If CheckOverlapping is required, then either skip fixing spectrum number // or get stopped by an exception if (!m_overlapChecked) checkForOverlap(ws1, ws2, true); needsFix = false; } else { // It will be determined later whether spectrum number needs to be fixed. needsFix = true; } if (!needsFix) return; // is everything possibly ok? specid_t min; specid_t max; getMinMax(output, min, max); if (max - min >= static_cast<specid_t>( output->getNumberHistograms())) // nothing to do then return; // information for remapping the spectra numbers specid_t ws1min; specid_t ws1max; getMinMax(ws1, ws1min, ws1max); // change the axis by adding the maximum existing spectrum number to the // current value for (size_t i = ws1->getNumberHistograms(); i < output->getNumberHistograms(); i++) { specid_t origid; origid = output->getSpectrum(i)->getSpectrumNo(); output->getSpectrum(i)->setSpectrumNo(origid + ws1max); } }
/** Returns a given spectrum as a complex number * @param inWS :: [input] The input workspace containing all the spectra * @param spec :: [input] The spectrum of interest * @param errors :: [input] If true, returns the errors, otherwise returns the * counts * @return : Spectrum 'spec' as a complex vector */ std::vector<double> MaxEnt::toComplex(const API::MatrixWorkspace_sptr &inWS, size_t spec, bool errors) { std::vector<double> result(inWS->blocksize() * 2); if (inWS->getNumberHistograms() % 2) throw std::invalid_argument( "Cannot convert input workspace to complex data"); size_t nspec = inWS->getNumberHistograms() / 2; if (!errors) { for (size_t i = 0; i < inWS->blocksize(); i++) { result[2 * i] = inWS->readY(spec)[i]; result[2 * i + 1] = inWS->readY(spec + nspec)[i]; } } else { for (size_t i = 0; i < inWS->blocksize(); i++) { result[2 * i] = inWS->readE(spec)[i]; result[2 * i + 1] = inWS->readE(spec + nspec)[i]; } } return result; }
/** Divide each bin by the width of its q bin. * @param outputWS :: The output workspace * @param qAxis :: A vector of the q bin boundaries */ void SofQWCentre::makeDistribution(API::MatrixWorkspace_sptr outputWS, const std::vector<double> qAxis) { std::vector<double> widths(qAxis.size()); std::adjacent_difference(qAxis.begin(), qAxis.end(), widths.begin()); const size_t numQBins = outputWS->getNumberHistograms(); for (size_t i = 0; i < numQBins; ++i) { auto &Y = outputWS->mutableY(i); auto &E = outputWS->mutableE(i); std::transform(Y.begin(), Y.end(), Y.begin(), std::bind2nd(std::divides<double>(), widths[i + 1])); std::transform(E.begin(), E.end(), E.begin(), std::bind2nd(std::divides<double>(), widths[i + 1])); } }
void SaveFITS::writeFITSHeaderAxesSizes(const API::MatrixWorkspace_sptr img, std::ofstream &file) { const std::string sizeX = std::to_string(img->blocksize()); const std::string sizeY = std::to_string(img->getNumberHistograms()); const size_t fieldWidth = 20; std::stringstream axis1; axis1 << "NAXIS1 = " << std::setw(fieldWidth) << sizeX << " / length of data axis 1"; writeFITSHeaderEntry(axis1.str(), file); std::stringstream axis2; axis2 << "NAXIS2 = " << std::setw(fieldWidth) << sizeY << " / length of data axis 2"; writeFITSHeaderEntry(axis2.str(), file); }
/** Fits each spectrum in the workspace to f(x) = A * sin( w * x + p) * @param ws :: [input] The workspace to fit * @param freq :: [input] Hint for the frequency (w) * @param groupName :: [input] The name of the output workspace group * @param resTab :: [output] Table workspace storing the asymmetries and phases * @param resGroup :: [output] Workspace group storing the fitting results */ void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws, double freq, std::string groupName, API::ITableWorkspace_sptr &resTab, API::WorkspaceGroup_sptr &resGroup) { int nhist = static_cast<int>(ws->getNumberHistograms()); // Create the fitting function f(x) = A * sin ( w * x + p ) // The same function and initial parameters are used for each fit std::string funcStr = createFittingFunction(freq, true); // Set up results table resTab->addColumn("int", "Spectrum number"); resTab->addColumn("double", "Asymmetry"); resTab->addColumn("double", "Phase"); // Loop through fitting all spectra individually const static std::string success = "success"; for (int wsIndex = 0; wsIndex < nhist; wsIndex++) { reportProgress(wsIndex, nhist); auto fit = createChildAlgorithm("Fit"); fit->initialize(); fit->setPropertyValue("Function", funcStr); fit->setProperty("InputWorkspace", ws); fit->setProperty("WorkspaceIndex", wsIndex); fit->setProperty("CreateOutput", true); fit->setPropertyValue("Output", groupName); fit->execute(); std::string status = fit->getProperty("OutputStatus"); if (!fit->isExecuted() || status != success) { std::ostringstream error; error << "Fit failed for spectrum at workspace index " << wsIndex; error << ": " << status; throw std::runtime_error(error.str()); } API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace"); resGroup->addWorkspace(fitOut); API::ITableWorkspace_sptr tab = fit->getProperty("OutputParameters"); // Now we have our fitting results stored in tab // but we need to extract the relevant information, i.e. // the detector phases (parameter 'p') and asymmetries ('A') const auto &spectrum = ws->getSpectrum(static_cast<size_t>(wsIndex)); extractDetectorInfo(tab, resTab, spectrum.getSpectrumNo()); } }
/** * Validation of the inputs of the RingProfile algorithm. * * Inside this method, the Workspace is considered a 2D Matrix, where each spectrum is * the rows of the matrix and have the variation in axis0. The columns of the matrix * is the position of dataX(0) * * The main validation are: * - the centre of the ring is inside the image it self. * - The minimum ring is smaller than the limits of the image to allow * @param inputWS: pointer to the input workspace */ void RingProfile::checkInputsForNumericWorkspace(const API::MatrixWorkspace_sptr inputWS){ g_log.notice() << "CheckingInputs For Numeric Workspace" << std::endl; // The Axis0 is defined by the values of readX inside the spectra of the workspace. // The limits of this axis will be get by inspection of the readX vector taking the first // and the last value. // check that centre is inside the range available for the instrument const MantidVec & refX = inputWS->readX(inputWS->getNumberHistograms()/2); // get the limits of the axis 0 (X) double min_v_x, max_v_x; min_v_x = std::min(refX[0], refX[refX.size() -1]); max_v_x = std::max(refX[0], refX[refX.size() -1]); g_log.notice() << "Limits X = " << min_v_x << " " << max_v_x << std::endl; // check centre is inside the X domain if ( centre_x < min_v_x || centre_x > max_v_x){ std::stringstream s; s << "The input value for centre (X="<< centre_x << ") is outside the limits of the instrument [" << min_v_x << ", "<< max_v_x << "]" ; throw std::invalid_argument(s.str()); } // The Axis1 is defined by the spectra inside the workspace. Its limits and values are given by the // ws->getAxis(1) // get the limits of the axis1 (Y) API::NumericAxis *oldAxis2 = dynamic_cast<API::NumericAxis*>(inputWS->getAxis(1) ); // we cannot have the positions in Y direction without a NumericAxis if( !oldAxis2 ) throw std::invalid_argument("Vertical axis is not a numeric axis. If it is a spectra axis try running ConvertSpectrumAxis first."); double min_v_y = std::min(oldAxis2->getMin(), oldAxis2->getMax()); double max_v_y = std::max(oldAxis2->getMin(), oldAxis2->getMax()); g_log.notice() << "Limits Y = " << min_v_y << " " << max_v_y << std::endl; // check centre is inside the Y domain if (centre_y < min_v_y || centre_y > max_v_y){ std::stringstream s; s << "The input value for centre (Y=" << centre_y << ") is outside the limits of the instrument [" << min_v_y << ", " << max_v_y << "]" ; throw std::invalid_argument(s.str()); } g_log.notice() << "Centre: " << centre_x << " " << centre_y << std::endl; // check minradius is inside the limits of the region of the instrument if (centre_x - min_radius > max_v_x || centre_x + min_radius < min_v_x || centre_y - min_radius > max_v_y || centre_y + min_radius < min_v_y) throw std::invalid_argument("The minimun radius is outside the region of the instrument"); }
/** This function will check how to group spectra when calculating median * * */ std::vector<std::vector<size_t>> DetectorDiagnostic::makeMap(API::MatrixWorkspace_sptr countsWS) { std::multimap<Mantid::Geometry::ComponentID, size_t> mymap; Geometry::Instrument_const_sptr instrument = countsWS->getInstrument(); if (m_parents == 0) { return makeInstrumentMap(*countsWS); } if (!instrument) { g_log.warning("Workspace has no instrument. LevelsUP is ignored"); return makeInstrumentMap(*countsWS); } // check if not grouped. If grouped, it will throw if (countsWS->hasGroupedDetectors()) { throw std::runtime_error("Median detector test: not able to create " "detector to spectra map. Try with LevelUp=0."); } for (size_t i = 0; i < countsWS->getNumberHistograms(); i++) { detid_t d = (*(countsWS->getSpectrum(i).getDetectorIDs().begin())); auto anc = instrument->getDetector(d)->getAncestors(); if (anc.size() < static_cast<size_t>(m_parents)) { g_log.warning("Too many levels up. Will ignore LevelsUp"); m_parents = 0; return makeInstrumentMap(*countsWS); } mymap.emplace(anc[m_parents - 1]->getComponentID(), i); } std::vector<std::vector<size_t>> speclist; std::multimap<Mantid::Geometry::ComponentID, size_t>::iterator m_it, s_it; for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) { Mantid::Geometry::ComponentID theKey = m_it->first; auto keyRange = mymap.equal_range(theKey); // Iterate over all map elements with key == theKey std::vector<size_t> speclistsingle; for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) { speclistsingle.push_back(s_it->second); } speclist.push_back(std::move(speclistsingle)); } return speclist; }
/** Assuming that the input workspace is a Numeric Image where the pixel *positions depend on their * relative position inside the workspace, this function extracts the position *of the first and last * pixel of the image. * * It is important that the input workspace must be a numeric image, and not an *instrument related workspace. * The function will raise exception (std::invalid_argument) if an invalid *input is give. * * @see RadiusSum::inputWorkspaceHasInstrumentAssociated for reference. * * @param inWS reference to the workspace * @return a list of values that defines the limits of the image in this order: *Xmin, Xmax, Ymin, Ymax */ std::vector<double> RadiusSum::getBoundariesOfNumericImage(API::MatrixWorkspace_sptr inWS) { // horizontal axis // get the pixel position in the horizontal axis from the middle of the image. const MantidVec &refX = inWS->readX(inWS->getNumberHistograms() / 2); double min_x, max_x; const double &first_x(refX[0]); const double &last_x(refX[refX.size() - 1]); if (first_x < last_x) { min_x = first_x; max_x = last_x; } else { min_x = last_x; max_x = first_x; } // vertical axis API::NumericAxis *verticalAxis = dynamic_cast<API::NumericAxis *>(inWS->getAxis(1)); if (!verticalAxis) throw std::invalid_argument("Vertical axis is not a numeric axis. Can not " "find the limits of the image."); double min_y, max_y; min_y = verticalAxis->getMin(); max_y = verticalAxis->getMax(); // check the assumption made that verticalAxis will provide the correct // answer. if (min_y > max_y) { throw std::logic_error("Failure to get the boundaries of this image. " "Internal logic error. Please, inform MantidHelp"); } std::vector<double> output(4); // output = {min_x, max_x, min_y, max_y}; not // supported in all compilers output[0] = min_x; output[1] = max_x; output[2] = min_y; output[3] = max_y; return output; }
/** If there is an overlap in spectrum numbers between ws1 and ws2, * then the spectrum numbers are reset as a simple 1-1 correspondence * with the workspace index. * * @param ws1 The first workspace supplied to the algorithm. * @param ws2 The second workspace supplied to the algorithm. * @param output The workspace that is going to be returned by the algorithm. */ void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2, API::MatrixWorkspace_sptr output) { specid_t ws1min; specid_t ws1max; getMinMax(ws1, ws1min, ws1max); specid_t ws2min; specid_t ws2max; getMinMax(ws2, ws2min, ws2max); // is everything possibly ok? if (ws2min > ws1max) return; // change the axis by adding the maximum existing spectrum number to the current value for (size_t i = 0; i < output->getNumberHistograms(); i++) output->getSpectrum(i)->setSpectrumNo( specid_t(i) ); }
/** * The main method to calculate the ring profile for workspaces based on *instruments. * * It will iterate over all the spectrum inside the workspace. * For each spectrum, it will use the RingProfile::getBinForPixel method to *identify * where, in the output_bins, the sum of all the spectrum values should be *placed in. * * @param inputWS: pointer to the input workspace * @param output_bins: the reference to the vector to be filled with the *integration values */ void RingProfile::processInstrumentRingProfile( const API::MatrixWorkspace_sptr inputWS, std::vector<double> &output_bins) { for (int i = 0; i < static_cast<int>(inputWS->getNumberHistograms()); i++) { m_progress->report("Computing ring bins positions for detectors"); // for the detector based, the positions will be taken from the detector // itself. try { Mantid::Geometry::IDetector_const_sptr det = inputWS->getDetector(i); // skip monitors if (det->isMonitor()) { continue; } // this part will be executed if the instrument is attached to the // workspace // get the bin position int bin_n = getBinForPixel(det); if (bin_n < 0) // -1 is the agreement for an invalid bin, or outside the // ring being integrated continue; g_log.debug() << "Bin for the index " << i << " = " << bin_n << " Pos = " << det->getPos() << std::endl; // get the reference to the spectrum auto spectrum_pt = inputWS->getSpectrum(i); const MantidVec &refY = spectrum_pt->dataY(); // accumulate the values of this spectrum inside this bin for (size_t sp_ind = 0; sp_ind < inputWS->blocksize(); sp_ind++) output_bins[bin_n] += refY[sp_ind]; } catch (Kernel::Exception::NotFoundError &ex) { g_log.information() << "It found that detector for " << i << " is not valid. " << ex.what() << std::endl; continue; } } }
/** 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); }
/** Carries out the bin-by-bin normalization * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin( const API::MatrixWorkspace_sptr &inputWorkspace, API::MatrixWorkspace_sptr &outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace) { if (inputEvent) { outputWorkspace = inputWorkspace->clone(); } else outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); } auto outputEvent = boost::dynamic_pointer_cast<EventWorkspace>(outputWorkspace); // Get hold of the monitor spectrum const auto &monX = m_monitor->binEdges(0); auto monY = m_monitor->counts(0); auto monE = m_monitor->countStandardDeviations(0); // Calculate the overall normalization just the once if bins are all matching if (m_commonBins) this->normalisationFactor(monX, monY, monE); const size_t numHists = inputWorkspace->getNumberHistograms(); auto specLength = inputWorkspace->blocksize(); // Flag set when a division by 0 is found bool hasZeroDivision = false; Progress prog(this, 0.0, 1.0, numHists); // Loop over spectra PARALLEL_FOR_IF( Kernel::threadSafe(*inputWorkspace, *outputWorkspace, *m_monitor)) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const auto &X = inputWorkspace->binEdges(i); // If not rebinning, just point to our monitor spectra, otherwise create new // vectors auto Y = (m_commonBins ? monY : Counts(specLength)); auto E = (m_commonBins ? monE : CountStandardDeviations(specLength)); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeros - 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.rawData(), monY.mutableRawData(), monE.mutableRawData(), X.rawData(), Y.mutableRawData(), E.mutableRawData(), false); // Recalculate the overall normalization factor this->normalisationFactor(X, Y, E); } if (inputEvent) { // ----------------------------------- EventWorkspace // --------------------------------------- EventList &outEL = outputEvent->getSpectrum(i); outEL.divide(X.rawData(), Y.mutableRawData(), E.mutableRawData()); } else { // ----------------------------------- Workspace2D // --------------------------------------- auto &YOut = outputWorkspace->mutableY(i); auto &EOut = outputWorkspace->mutableE(i); const auto &inY = inputWorkspace->y(i); const auto &inE = inputWorkspace->e(i); outputWorkspace->mutableX(i) = inputWorkspace->x(i); // The code below comes more or less straight out of Divide.cpp for (size_t k = 0; k < specLength; ++k) { // Get the input Y's const double leftY = inY[k]; const double rightY = Y[k]; if (rightY == 0.0) { hasZeroDivision = true; } // 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 PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION if (hasZeroDivision) { g_log.warning() << "Division by zero in some of the bins.\n"; } }
std::vector<std::vector<size_t>> DetectorDiagnostic::makeInstrumentMap(API::MatrixWorkspace_sptr countsWS) { return { {boost::counting_iterator<std::size_t>(0), boost::counting_iterator<std::size_t>(countsWS->getNumberHistograms())}}; }
/** Forms the quadrature phase signal (squashogram) * @param ws :: [input] workspace containing the measured spectra * @param phase :: [input] table workspace containing the detector phases * @param n0 :: [input] vector containing the normalization constants * @return :: workspace containing the quadrature phase signal */ API::MatrixWorkspace_sptr PhaseQuadMuon::squash(const API::MatrixWorkspace_sptr &ws, const API::ITableWorkspace_sptr &phase, const std::vector<double> &n0) { // Poisson limit: below this number we consider we don't have enough // statistics // to apply sqrt(N). This is an arbitrary number used in the original code // provided by scientists const double poissonLimit = 30.; // Muon life time in microseconds const double muLife = PhysicalConstants::MuonLifetime * 1e6; const size_t nspec = ws->getNumberHistograms(); if (n0.size() != nspec) { throw std::invalid_argument("Invalid normalization constants"); } auto names = phase->getColumnNames(); for (auto &name : names) { std::transform(name.begin(), name.end(), name.begin(), ::tolower); } auto phaseIndex = findName(phaseNames, names); auto asymmetryIndex = findName(asymmNames, names); // Get the maximum asymmetry double maxAsym = 0.; for (size_t h = 0; h < nspec; h++) { if (phase->Double(h, asymmetryIndex) > maxAsym && phase->Double(h, asymmetryIndex) != ASYMM_ERROR) { maxAsym = phase->Double(h, asymmetryIndex); } } if (maxAsym == 0.0) { throw std::invalid_argument("Invalid detector asymmetries"); } std::vector<bool> emptySpectrum; emptySpectrum.reserve(nspec); std::vector<double> aj, bj; { // Calculate coefficients aj, bj double sxx = 0.; double syy = 0.; double sxy = 0.; for (size_t h = 0; h < nspec; h++) { emptySpectrum.push_back( std::all_of(ws->y(h).begin(), ws->y(h).end(), [](double value) { return value == 0.; })); if (!emptySpectrum[h]) { const double asym = phase->Double(h, asymmetryIndex) / maxAsym; const double phi = phase->Double(h, phaseIndex); const double X = n0[h] * asym * cos(phi); const double Y = n0[h] * asym * sin(phi); sxx += X * X; syy += Y * Y; sxy += X * Y; } } const double lam1 = 2 * syy / (sxx * syy - sxy * sxy); const double mu1 = 2 * sxy / (sxy * sxy - sxx * syy); const double lam2 = 2 * sxy / (sxy * sxy - sxx * syy); const double mu2 = 2 * sxx / (sxx * syy - sxy * sxy); for (size_t h = 0; h < nspec; h++) { if (emptySpectrum[h]) { aj.push_back(0.0); bj.push_back(0.0); } else { const double asym = phase->Double(h, asymmetryIndex) / maxAsym; const double phi = phase->Double(h, phaseIndex); const double X = n0[h] * asym * cos(phi); const double Y = n0[h] * asym * sin(phi); aj.push_back((lam1 * X + mu1 * Y) * 0.5); bj.push_back((lam2 * X + mu2 * Y) * 0.5); } } } const size_t npoints = ws->blocksize(); // Create and populate output workspace API::MatrixWorkspace_sptr ows = API::WorkspaceFactory::Instance().create(ws, 2, npoints + 1, npoints); // X ows->setSharedX(0, ws->sharedX(0)); ows->setSharedX(1, ws->sharedX(0)); // Phase quadrature auto &realY = ows->mutableY(0); auto &imagY = ows->mutableY(1); auto &realE = ows->mutableE(0); auto &imagE = ows->mutableE(1); const auto xPointData = ws->histogram(0).points(); // First X value const double X0 = xPointData.front(); // calculate exponential decay outside of the loop std::vector<double> expDecay = xPointData.rawData(); std::transform(expDecay.begin(), expDecay.end(), expDecay.begin(), [X0, muLife](double x) { return exp(-(x - X0) / muLife); }); for (size_t i = 0; i < npoints; i++) { for (size_t h = 0; h < nspec; h++) { if (!emptySpectrum[h]) { // (X,Y,E) with exponential decay removed const double X = ws->x(h)[i]; const double exponential = n0[h] * exp(-(X - X0) / muLife); const double Y = ws->y(h)[i] - exponential; const double E = (ws->y(h)[i] > poissonLimit) ? ws->e(h)[i] : sqrt(exponential); realY[i] += aj[h] * Y; imagY[i] += bj[h] * Y; realE[i] += aj[h] * aj[h] * E * E; imagE[i] += bj[h] * bj[h] * E * E; } } realE[i] = sqrt(realE[i]); imagE[i] = sqrt(imagE[i]); // Regain exponential decay realY[i] /= expDecay[i]; imagY[i] /= expDecay[i]; realE[i] /= expDecay[i]; imagE[i] /= expDecay[i]; } // New Y axis label ows->setYUnit("Asymmetry"); return ows; }
/** Fits each spectrum in the workspace to f(x) = A * sin( w * x + p) * @param ws :: [input] The workspace to fit * @param freq :: [input] Hint for the frequency (w) * @param groupName :: [input] The name of the output workspace group * @param resTab :: [output] Table workspace storing the asymmetries and phases * @param resGroup :: [output] Workspace group storing the fitting results */ void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws, double freq, std::string groupName, API::ITableWorkspace_sptr resTab, API::WorkspaceGroup_sptr &resGroup) { int nhist = static_cast<int>(ws->getNumberHistograms()); // Create the fitting function f(x) = A * sin ( w * x + p ) // The same function and initial parameters are used for each fit std::string funcStr = createFittingFunction(freq, true); // Set up results table resTab->addColumn("int", "Spectrum number"); resTab->addColumn("double", "Asymmetry"); resTab->addColumn("double", "Phase"); const auto &indexInfo = ws->indexInfo(); // Loop through fitting all spectra individually const static std::string success = "success"; for (int wsIndex = 0; wsIndex < nhist; wsIndex++) { reportProgress(wsIndex, nhist); const auto &yValues = ws->y(wsIndex); auto emptySpectrum = std::all_of(yValues.begin(), yValues.end(), [](double value) { return value == 0.; }); if (emptySpectrum) { g_log.warning("Spectrum " + std::to_string(wsIndex) + " is empty"); TableWorkspace_sptr tab = boost::make_shared<TableWorkspace>(); tab->addColumn("str", "Name"); tab->addColumn("double", "Value"); tab->addColumn("double", "Error"); for (int j = 0; j < 4; j++) { API::TableRow row = tab->appendRow(); if (j == PHASE_ROW) { row << "dummy" << 0.0 << 0.0; } else { row << "dummy" << ASYMM_ERROR << 0.0; } } extractDetectorInfo(*tab, *resTab, indexInfo.spectrumNumber(wsIndex)); } else { auto fit = createChildAlgorithm("Fit"); fit->initialize(); fit->setPropertyValue("Function", funcStr); fit->setProperty("InputWorkspace", ws); fit->setProperty("WorkspaceIndex", wsIndex); fit->setProperty("CreateOutput", true); fit->setPropertyValue("Output", groupName); fit->execute(); std::string status = fit->getProperty("OutputStatus"); if (!fit->isExecuted()) { std::ostringstream error; error << "Fit failed for spectrum at workspace index " << wsIndex; error << ": " << status; throw std::runtime_error(error.str()); } else if (status != success) { g_log.warning("Fit failed for spectrum at workspace index " + std::to_string(wsIndex) + ": " + status); } API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace"); resGroup->addWorkspace(fitOut); API::ITableWorkspace_sptr tab = fit->getProperty("OutputParameters"); // Now we have our fitting results stored in tab // but we need to extract the relevant information, i.e. // the detector phases (parameter 'p') and asymmetries ('A') extractDetectorInfo(*tab, *resTab, indexInfo.spectrumNumber(wsIndex)); } } }
API::MatrixWorkspace_sptr CreateFloodWorkspace::removeBackground(API::MatrixWorkspace_sptr ws) { g_log.information() << "Remove background " << getPropertyValue(Prop::BACKGROUND) << '\n'; auto fitWS = transpose(ws); auto const &x = fitWS->x(0); // Define the fitting interval double startX = getProperty(Prop::START_X); double endX = getProperty(Prop::END_X); std::vector<double> excludeFromFit; if (isDefault(Prop::START_X)) { startX = x.front(); } else { excludeFromFit.push_back(x.front()); excludeFromFit.push_back(startX); } if (isDefault(Prop::END_X)) { endX = x.back(); } else { excludeFromFit.push_back(endX); excludeFromFit.push_back(x.back()); } // Exclude any bad detectors. for (auto i : m_excludedSpectra) { excludeFromFit.push_back(i); excludeFromFit.push_back(i); } std::string const function = getBackgroundFunction(); // Fit the data to determine unwanted background auto alg = createChildAlgorithm("Fit", 0.9, 0.99); alg->setProperty("Function", function); alg->setProperty("InputWorkspace", fitWS); alg->setProperty("WorkspaceIndex", 0); if (!excludeFromFit.empty()) { alg->setProperty("Exclude", excludeFromFit); } alg->setProperty("Output", "fit"); alg->execute(); IFunction_sptr func = alg->getProperty("Function"); g_log.information() << "Background function parameters:\n"; for (size_t i = 0; i < func->nParams(); ++i) { g_log.information() << " " << func->parameterName(i) << ": " << func->getParameter(i) << '\n'; } // Divide the workspace by the fitted curve to remove the background // and scale to values around 1 MatrixWorkspace_sptr bkgWS = alg->getProperty("OutputWorkspace"); auto const &bkg = bkgWS->y(1); auto const nHisto = static_cast<int>(ws->getNumberHistograms()); PARALLEL_FOR_IF(Kernel::threadSafe(*ws, *bkgWS)) for (int i = 0; i < nHisto; ++i) { PARALLEL_START_INTERUPT_REGION auto const xVal = x[i]; if (isExcludedSpectrum(xVal)) { ws->mutableY(i)[0] = VERY_BIG_VALUE; ws->mutableE(i)[0] = 0.0; } else if (xVal >= startX && xVal <= endX) { auto const background = bkg[i]; if (background <= 0.0) { throw std::runtime_error( "Background is expected to be positive, found value " + std::to_string(background) + " at spectrum with workspace index " + std::to_string(i)); } ws->mutableY(i)[0] /= background; ws->mutableE(i)[0] /= background; } else { ws->mutableY(i)[0] = 1.0; ws->mutableE(i)[0] = 0.0; } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Remove the logs ws->setSharedRun(make_cow<Run>()); return ws; }
/** Forms the quadrature phase signal (squashogram) * @param ws :: [input] workspace containing the measured spectra * @param phase :: [input] table workspace containing the detector phases * @param n0 :: [input] vector containing the normalization constants * @return :: workspace containing the quadrature phase signal */ API::MatrixWorkspace_sptr PhaseQuadMuon::squash(const API::MatrixWorkspace_sptr &ws, const API::ITableWorkspace_sptr &phase, const std::vector<double> &n0) { // Poisson limit: below this number we consider we don't have enough // statistics // to apply sqrt(N). This is an arbitrary number used in the original code // provided by scientists double poissonLimit = 30.; size_t nspec = ws->getNumberHistograms(); size_t npoints = ws->blocksize(); // Muon life time in microseconds double muLife = PhysicalConstants::MuonLifetime * 1e6; if (n0.size() != nspec) { throw std::invalid_argument("Invalid normalization constants"); } // Get the maximum asymmetry double maxAsym = 0.; for (size_t h = 0; h < nspec; h++) { if (phase->Double(h, 1) > maxAsym) { maxAsym = phase->Double(h, 1); } } if (maxAsym == 0.0) { throw std::invalid_argument("Invalid detector asymmetries"); } std::vector<double> aj, bj; { // Calculate coefficients aj, bj double sxx = 0; double syy = 0; double sxy = 0; for (size_t h = 0; h < nspec; h++) { double asym = phase->Double(h, 1) / maxAsym; double phi = phase->Double(h, 2); double X = n0[h] * asym * cos(phi); double Y = n0[h] * asym * sin(phi); sxx += X * X; syy += Y * Y; sxy += X * Y; } double lam1 = 2 * syy / (sxx * syy - sxy * sxy); double mu1 = 2 * sxy / (sxy * sxy - sxx * syy); double lam2 = 2 * sxy / (sxy * sxy - sxx * syy); double mu2 = 2 * sxx / (sxx * syy - sxy * sxy); for (size_t h = 0; h < nspec; h++) { double asym = phase->Double(h, 1) / maxAsym; double phi = phase->Double(h, 2); double X = n0[h] * asym * cos(phi); double Y = n0[h] * asym * sin(phi); aj.push_back((lam1 * X + mu1 * Y) * 0.5); bj.push_back((lam2 * X + mu2 * Y) * 0.5); } } // First X value double X0 = ws->x(0).front(); // Create and populate output workspace API::MatrixWorkspace_sptr ows = API::WorkspaceFactory::Instance().create( "Workspace2D", 2, npoints + 1, npoints); // X ows->setSharedX(0, ws->sharedX(0)); ows->setSharedX(1, ws->sharedX(0)); // Phase quadrature auto &realY = ows->mutableY(0); auto &imagY = ows->mutableY(1); auto &realE = ows->mutableE(0); auto &imagE = ows->mutableE(1); for (size_t i = 0; i < npoints; i++) { for (size_t h = 0; h < nspec; h++) { // (X,Y,E) with exponential decay removed const double X = ws->x(h)[i]; const double Y = ws->y(h)[i] - n0[h] * exp(-(X - X0) / muLife); const double E = (ws->y(h)[i] > poissonLimit) ? ws->e(h)[i] : sqrt(n0[h] * exp(-(X - X0) / muLife)); realY[i] += aj[h] * Y; imagY[i] += bj[h] * Y; realE[i] += aj[h] * aj[h] * E * E; imagE[i] += bj[h] * bj[h] * E * E; } realE[i] = sqrt(realE[i]); imagE[i] = sqrt(imagE[i]); // Regain exponential decay const double X = ws->getSpectrum(0).x()[i]; const double e = exp(-(X - X0) / muLife); realY[i] /= e; imagY[i] /= e; realE[i] /= e; imagE[i] /= e; } return ows; }
/** * Validation of the inputs of the RingProfile algorithm. * * Inside this method, the Workspace is considered an instrument based *instrument. Each spectrum * has a detector associated which has a position in the 3D space. * * The main validation are: * - the centre of the ring is inside the image it self. * - The minimum ring is smaller than the limits of the image to allow * * @param inputWS: the input workspace */ void RingProfile::checkInputsForSpectraWorkspace( const API::MatrixWorkspace_sptr inputWS) { try { // finding the limits of the instrument double first_x, first_y, first_z; size_t i = 0; while (true) { i++; if (i >= inputWS->getNumberHistograms()) throw std::invalid_argument( "Did not find any non monitor detector position"); auto det = inputWS->getDetector(i); if (det->isMonitor()) continue; first_x = det->getPos().X(); first_y = det->getPos().Y(); first_z = det->getPos().Z(); break; } double last_x, last_y, last_z; i = inputWS->getNumberHistograms() - 1; while (true) { i--; if (i == 0) throw std::invalid_argument( "There is no region defined for the instrument of this workspace"); auto det = inputWS->getDetector(i); if (det->isMonitor()) continue; last_x = det->getPos().X(); last_y = det->getPos().Y(); last_z = det->getPos().Z(); break; } double xMax, yMax, zMax; double xMin, yMin, zMin; xMax = std::max(first_x, last_x); yMax = std::max(first_y, last_y); zMax = std::max(first_z, last_z); xMin = std::min(first_x, last_x); yMin = std::min(first_y, last_y); zMin = std::min(first_z, last_z); std::stringstream limits_s; limits_s << "([" << xMin << ", " << xMax << "], [" << yMin << ", " << yMax << "], [" << zMin << ", " << zMax << "])"; g_log.debug() << "The limits for the instrument is : " << limits_s.str() << std::endl; int xOutside = 0, yOutside = 0, zOutside = 0; if (centre_x < xMin || centre_x > xMax) xOutside = 1; if (centre_y < yMin || centre_y > yMax) yOutside = 1; if (centre_z < zMin || centre_z > zMax) zOutside = 1; int summed = xOutside + yOutside + zOutside; // if at least 2 are outside, the centre is considered outside the box. if (summed >= 2) { std::stringstream s; s << "The defined centre (" << centre_x << ", " << centre_y << ", " << centre_z << ") is outside the limits of the detectors inside this instrument: " << limits_s.str(); throw std::invalid_argument(s.str()); } xOutside = yOutside = zOutside = 0; if (centre_x - min_radius > xMax || centre_x + min_radius < xMin) xOutside = 1; if (centre_y - min_radius > yMax || centre_y + min_radius < yMin) yOutside = 1; if (centre_z - min_radius > zMax || centre_z + min_radius < zMin) zOutside = 1; summed = xOutside + yOutside + zOutside; if (summed >= 2) { std::stringstream s; s << "The defined minRadius make the inner ring outside the limits of " "the detectors inside this instrument: " << limits_s.str(); throw std::invalid_argument(s.str()); } } catch (Kernel::Exception::NotFoundError &) { throw std::invalid_argument("Invalid input workspace. This workspace does " "not has detectors to get the positions " "from. "); } }
/** Assuming that the workspace has an instrument associated with it from which *the pixel positions has to be taken, * this function extracts the position of the first and last valid pixel *(detector) and return a list of values * giving the boundaries of the instrument. * * @param inWS Input Workspace * @return a list of values that defines the limits of the image in this order: *Xmin, Xmax, Ymin, Ymax, Zmin, Zmax */ std::vector<double> RadiusSum::getBoundariesOfInstrument(API::MatrixWorkspace_sptr inWS) { // This function is implemented based in the following assumption: // - The workspace is composed by spectrum with associated spectrum No which // is associated to one detector or monitor // - The first spectrum No (non monitor) is associated with one detector // while the last spectrum No (non monitor) // is associated with one detector. // - They are in complete oposite direction. // // Consider the following 'image' (where the ID is the number and the // position is where it is displayed) // // 1 2 3 // 4 5 6 // 7 8 9 // 10 11 12 // // In this image, the assumption is true, because, we can derive the // boundaries of the image looking just to the // ids 1 and 12. // // But the following image: // // 1 2 3 6 5 4 // 6 5 4 1 2 3 // 7 8 9 12 11 10 // 12 11 12 7 8 9 // // Although valid 'IDF' instrument, fail the assumption, and will return // wrong values. // Bear in mind these words if you face problems with the return of the // boundaries of one instrument // double first_x, first_y, first_z; size_t i = 0; while (true) { i++; if (i >= inWS->getNumberHistograms()) throw std::invalid_argument("Did not find any non monitor detector. " "Failed to identify the boundaries of this " "instrument."); auto det = inWS->getDetector(i); if (det->isMonitor()) continue; // get the position of the first valid (non-monitor) detector. first_x = det->getPos().X(); first_y = det->getPos().Y(); first_z = det->getPos().Z(); break; } double last_x, last_y, last_z; i = inWS->getNumberHistograms() - 1; while (true) { i--; if (i == 0) throw std::invalid_argument("There is no region defined for the " "instrument of this workspace. Failed to " "identify the boundaries of this instrument"); auto det = inWS->getDetector(i); if (det->isMonitor()) continue; // get the last valid detector position last_x = det->getPos().X(); last_y = det->getPos().Y(); last_z = det->getPos().Z(); break; } // order the values double xMax, yMax, zMax; double xMin, yMin, zMin; xMax = std::max(first_x, last_x); yMax = std::max(first_y, last_y); zMax = std::max(first_z, last_z); xMin = std::min(first_x, last_x); yMin = std::min(first_y, last_y); zMin = std::min(first_z, last_z); std::vector<double> output(6); // output = {xMin, xMax, yMin, yMax, zMin, // zMax }; not supported in all compilers output[0] = xMin; output[1] = xMax; output[2] = yMin; output[3] = yMax; output[4] = zMin; output[5] = zMax; return output; }
/** Carries out the bin-by-bin normalisation * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin(API::MatrixWorkspace_sptr inputWorkspace, API::MatrixWorkspace_sptr& outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); EventWorkspace_sptr outputEvent; // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace ) { if (inputEvent) { //Make a brand new EventWorkspace outputEvent = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", inputEvent->getNumberHistograms(), 2, 1)); //Copy geometry and data API::WorkspaceFactory::Instance().initializeFromParent(inputEvent, outputEvent, false); outputEvent->copyDataFrom( (*inputEvent) ); outputWorkspace = boost::dynamic_pointer_cast<MatrixWorkspace>(outputEvent); } else outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); } // Get hold of the monitor spectrum const MantidVec& monX = m_monitor->readX(0); MantidVec& monY = m_monitor->dataY(0); MantidVec& monE = m_monitor->dataE(0); // Calculate the overall normalisation just the once if bins are all matching if (m_commonBins) this->normalisationFactor(m_monitor->readX(0),&monY,&monE); const size_t numHists = inputWorkspace->getNumberHistograms(); MantidVec::size_type specLength = inputWorkspace->blocksize(); Progress prog(this,0.0,1.0,numHists); // Loop over spectra PARALLEL_FOR3(inputWorkspace,outputWorkspace,m_monitor) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const MantidVec& X = inputWorkspace->readX(i); // If not rebinning, just point to our monitor spectra, otherwise create new vectors MantidVec* Y = ( m_commonBins ? &monY : new MantidVec(specLength) ); MantidVec* E = ( m_commonBins ? &monE : new MantidVec(specLength) ); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeroes - skip these, they cause problems if (X.back() == 0.0 && X.front() == 0.0) continue; // Rebin the monitor spectrum to match the binning of the current data spectrum VectorHelper::rebinHistogram(monX,monY,monE,X,*Y,*E,false); // Recalculate the overall normalisation factor this->normalisationFactor(X,Y,E); } if (inputEvent) { // ----------------------------------- EventWorkspace --------------------------------------- EventList & outEL = outputEvent->getEventList(i); outEL.divide(X, *Y, *E); } else { // ----------------------------------- Workspace2D --------------------------------------- const MantidVec& inY = inputWorkspace->readY(i); const MantidVec& inE = inputWorkspace->readE(i); MantidVec& YOut = outputWorkspace->dataY(i); MantidVec& EOut = outputWorkspace->dataE(i); outputWorkspace->dataX(i) = inputWorkspace->readX(i); // The code below comes more or less straight out of Divide.cpp for (MantidVec::size_type k = 0; k < specLength; ++k) { // Get references to the input Y's const double& leftY = inY[k]; const double& rightY = (*Y)[k]; // Calculate result and store in local variable to avoid overwriting original data if // output workspace is same as one of the input ones const double newY = leftY/rightY; if (fabs(rightY)>1.0e-12 && fabs(newY)>1.0e-12) { const double lhsFactor = (inE[k]<1.0e-12|| fabs(leftY)<1.0e-12) ? 0.0 : pow((inE[k]/leftY),2); const double rhsFactor = (*E)[k]<1.0e-12 ? 0.0 : pow(((*E)[k]/rightY),2); EOut[k] = std::abs(newY) * sqrt(lhsFactor+rhsFactor); } // Now store the result YOut[k] = newY; } // end Workspace2D case } // end loop over current spectrum if (!m_commonBins) { delete Y; delete E; } PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION }
/** Executes the algorithm * * @throw Exception::FileError If the grouping file cannot be opened or read successfully * @throw runtime_error If unable to run one of the sub-algorithms successfully */ void DiffractionFocussing::exec() { // retrieve the properties std::string groupingFileName=getProperty("GroupingFileName"); // Get the input workspace MatrixWorkspace_sptr inputW = getProperty("InputWorkspace"); bool dist = inputW->isDistribution(); //do this first to check that a valid file is available before doing any work std::multimap<int64_t,int64_t> detectorGroups;// <group, UDET> if (!readGroupingFile(groupingFileName, detectorGroups)) { throw Exception::FileError("Error reading .cal file",groupingFileName); } //Convert to d-spacing units API::MatrixWorkspace_sptr tmpW = convertUnitsToDSpacing(inputW); //Rebin to a common set of bins RebinWorkspace(tmpW); std::set<int64_t> groupNumbers; for(std::multimap<int64_t,int64_t>::const_iterator d = detectorGroups.begin();d!=detectorGroups.end();d++) { if (groupNumbers.find(d->first) == groupNumbers.end()) { groupNumbers.insert(d->first); } } int iprogress = 0; int iprogress_count = static_cast<int>(groupNumbers.size()); int iprogress_step = iprogress_count / 100; if (iprogress_step == 0) iprogress_step = 1; std::vector<int64_t> resultIndeces; for(std::set<int64_t>::const_iterator g = groupNumbers.begin();g!=groupNumbers.end();g++) { if (iprogress++ % iprogress_step == 0) { progress(0.68 + double(iprogress)/iprogress_count/3); } std::multimap<int64_t,int64_t>::const_iterator from = detectorGroups.lower_bound(*g); std::multimap<int64_t,int64_t>::const_iterator to = detectorGroups.upper_bound(*g); std::vector<detid_t> detectorList; for(std::multimap<int64_t,int64_t>::const_iterator d = from;d!=to;d++) detectorList.push_back(static_cast<detid_t>(d->second)); // Want version 1 of GroupDetectors here API::IAlgorithm_sptr childAlg = createSubAlgorithm("GroupDetectors",-1.0,-1.0,true,1); childAlg->setProperty("Workspace", tmpW); childAlg->setProperty< std::vector<detid_t> >("DetectorList",detectorList); childAlg->executeAsSubAlg(); try { // get the index of the combined spectrum int ri = childAlg->getProperty("ResultIndex"); if (ri >= 0) { resultIndeces.push_back(ri); } } catch(...) { throw std::runtime_error("Unable to get Properties from GroupDetectors sub-algorithm"); } } // Discard left-over spectra, but print warning message giving number discarded int discarded = 0; const int64_t oldHistNumber = tmpW->getNumberHistograms(); API::Axis *spectraAxis = tmpW->getAxis(1); for(int64_t i=0; i < oldHistNumber; i++) if ( spectraAxis->spectraNo(i) >= 0 && find(resultIndeces.begin(),resultIndeces.end(),i) == resultIndeces.end()) { ++discarded; } g_log.warning() << "Discarded " << discarded << " spectra that were not assigned to any group" << std::endl; // Running GroupDetectors leads to a load of redundant spectra // Create a new workspace that's the right size for the meaningful spectra and copy them in int64_t newSize = tmpW->blocksize(); API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(tmpW,resultIndeces.size(),newSize+1,newSize); // Copy units outputW->getAxis(0)->unit() = tmpW->getAxis(0)->unit(); outputW->getAxis(1)->unit() = tmpW->getAxis(1)->unit(); API::Axis *spectraAxisNew = outputW->getAxis(1); for(int64_t hist=0; hist < static_cast<int64_t>(resultIndeces.size()); hist++) { int64_t i = resultIndeces[hist]; double spNo = static_cast<double>(spectraAxis->spectraNo(i)); MantidVec &tmpE = tmpW->dataE(i); MantidVec &outE = outputW->dataE(hist); MantidVec &tmpY = tmpW->dataY(i); MantidVec &outY = outputW->dataY(hist); MantidVec &tmpX = tmpW->dataX(i); MantidVec &outX = outputW->dataX(hist); outE.assign(tmpE.begin(),tmpE.end()); outY.assign(tmpY.begin(),tmpY.end()); outX.assign(tmpX.begin(),tmpX.end()); spectraAxisNew->setValue(hist,spNo); spectraAxis->setValue(i,-1); } progress(1.); outputW->isDistribution(dist); // Assign it to the output workspace property setProperty("OutputWorkspace",outputW); return; }