/** * Construct an "empty" output workspace in virtual-lambda for summation in Q. * The workspace will have the same x values as the input workspace but the y * values will all be zero. * * @return : a 1D workspace where y values are all zero */ MatrixWorkspace_sptr ReflectometryReductionOne2::constructIvsLamWS(MatrixWorkspace_sptr detectorWS) { // There is one output spectrum for each detector group const size_t numGroups = detectorGroups().size(); // Calculate the number of bins based on the min/max wavelength, using // the same bin width as the input workspace const double binWidth = (detectorWS->x(0).back() - detectorWS->x(0).front()) / static_cast<double>(detectorWS->blocksize()); const int numBins = static_cast<int>( std::ceil((wavelengthMax() - wavelengthMin()) / binWidth)); // Construct the histogram with these X values. Y and E values are zero. const BinEdges xValues(numBins, LinearGenerator(wavelengthMin(), binWidth)); // Create the output workspace MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create( detectorWS, numGroups, numBins, numBins - 1); // Loop through each detector group in the input for (size_t groupIdx = 0; groupIdx < numGroups; ++groupIdx) { // Get the detectors in this group auto &detectors = detectorGroups()[groupIdx]; // Set the x values for this spectrum outputWS->setBinEdges(groupIdx, xValues); // Set the detector ID from the twoThetaR detector. const size_t twoThetaRIdx = twoThetaRDetectorIdx(detectors); auto &outSpec = outputWS->getSpectrum(groupIdx); const detid_t twoThetaRDetID = m_spectrumInfo->detector(twoThetaRIdx).getID(); outSpec.clearDetectorIDs(); outSpec.addDetectorID(twoThetaRDetID); // Set the spectrum number from the twoThetaR detector SpectrumNumber specNum = detectorWS->indexInfo().spectrumNumber(twoThetaRIdx); auto indexInf = outputWS->indexInfo(); indexInf.setSpectrumNumbers(specNum, specNum); outputWS->setIndexInfo(indexInf); } return outputWS; }
/** Execute the algorithm. */ void EditInstrumentGeometry::exec() { // Lots of things have to do with the input workspace MatrixWorkspace_sptr workspace = getProperty("Workspace"); Geometry::Instrument_const_sptr originstrument = workspace->getInstrument(); // Get and check the primary flight path double l1 = this->getProperty("PrimaryFlightPath"); if (isEmpty(l1)) { // Use the original L1 if (!originstrument) { std::string errmsg( "It is not supported that L1 is not given, ", "while there is no instrument associated to input workspace."); g_log.error(errmsg); throw std::runtime_error(errmsg); } Geometry::IComponent_const_sptr source = originstrument->getSource(); Geometry::IComponent_const_sptr sample = originstrument->getSample(); l1 = source->getDistance(*sample); g_log.information() << "Retrieve L1 from input data workspace. \n"; } g_log.information() << "Using L1 = " << l1 << "\n"; // Get spectra number in case they are in a funny order std::vector<int32_t> specids = this->getProperty("SpectrumIDs"); if (specids.empty()) // they are using the order of the input workspace { size_t numHist = workspace->getNumberHistograms(); for (size_t i = 0; i < numHist; ++i) { specids.push_back(workspace->getSpectrum(i).getSpectrumNo()); g_log.information() << "Add spectrum " << workspace->getSpectrum(i).getSpectrumNo() << ".\n"; } } // Get the detector ids - empsy means ignore it const vector<int> vec_detids = getProperty("DetectorIDs"); const bool renameDetID(!vec_detids.empty()); // Get individual detector geometries ordered by input spectrum Numbers const std::vector<double> l2s = this->getProperty("L2"); const std::vector<double> tths = this->getProperty("Polar"); std::vector<double> phis = this->getProperty("Azimuthal"); // empty list of L2 and 2-theta is not allowed if (l2s.empty()) { throw std::runtime_error("User must specify L2 for all spectra. "); } if (tths.empty()) { throw std::runtime_error("User must specify 2theta for all spectra."); } // empty list of phi means that they are all zero if (phis.empty()) { phis.assign(l2s.size(), 0.); } // Validate for (size_t ib = 0; ib < l2s.size(); ib++) { g_log.information() << "Detector " << specids[ib] << " L2 = " << l2s[ib] << " 2Theta = " << tths[ib] << '\n'; if (specids[ib] < 0) { // Invalid spectrum Number : less than 0. stringstream errmsgss; errmsgss << "Detector ID = " << specids[ib] << " cannot be less than 0."; throw std::invalid_argument(errmsgss.str()); } if (l2s[ib] <= 0.0) { throw std::invalid_argument("L2 cannot be less or equal to 0"); } } // Keep original instrument and set the new instrument, if necessary const auto spec2indexmap = workspace->getSpectrumToWorkspaceIndexMap(); // ??? Condition: spectrum has 1 and only 1 detector size_t nspec = workspace->getNumberHistograms(); // Initialize another set of L2/2-theta/Phi/DetectorIDs vector ordered by // workspace index std::vector<double> storL2s(nspec, 0.); std::vector<double> stor2Thetas(nspec, 0.); std::vector<double> storPhis(nspec, 0.); vector<int> storDetIDs(nspec, 0); // Map the properties from spectrum Number to workspace index for (size_t i = 0; i < specids.size(); i++) { // Find spectrum's workspace index auto it = spec2indexmap.find(specids[i]); if (it == spec2indexmap.end()) { stringstream errss; errss << "Spectrum Number " << specids[i] << " is not found. " << "Instrument won't be edited for this spectrum. \n"; g_log.error(errss.str()); throw std::runtime_error(errss.str()); } // Store and set value size_t workspaceindex = it->second; storL2s[workspaceindex] = l2s[i]; stor2Thetas[workspaceindex] = tths[i]; storPhis[workspaceindex] = phis[i]; if (renameDetID) storDetIDs[workspaceindex] = vec_detids[i]; g_log.debug() << "workspace index = " << workspaceindex << " is for Spectrum " << specids[i] << '\n'; } // Generate a new instrument // Name of the new instrument std::string name = std::string(getProperty("InstrumentName")); if (name.empty()) { // Use the original L1 if (!originstrument) { std::string errmsg( "It is not supported that InstrumentName is not given, ", "while there is no instrument associated to input workspace."); g_log.error(errmsg); throw std::runtime_error(errmsg); } name = originstrument->getName(); } // Create a new instrument from scratch any way. auto instrument = boost::make_shared<Geometry::Instrument>(name); if (!bool(instrument)) { stringstream errss; errss << "Trying to use a Parametrized Instrument as an Instrument."; g_log.error(errss.str()); throw std::runtime_error(errss.str()); } // Set up source and sample information Geometry::ObjComponent *samplepos = new Geometry::ObjComponent("Sample", instrument.get()); instrument->add(samplepos); instrument->markAsSamplePos(samplepos); samplepos->setPos(0.0, 0.0, 0.0); Geometry::ObjComponent *source = new Geometry::ObjComponent("Source", instrument.get()); instrument->add(source); instrument->markAsSource(source); source->setPos(0.0, 0.0, -1.0 * l1); // Add/copy detector information auto indexInfo = workspace->indexInfo(); std::vector<detid_t> detIDs; for (size_t i = 0; i < workspace->getNumberHistograms(); i++) { // Create a new detector. // (Instrument will take ownership of pointer so no need to delete.) detid_t newdetid; if (renameDetID) newdetid = storDetIDs[i]; else newdetid = detid_t(i) + 100; Geometry::Detector *detector = new Geometry::Detector("det", newdetid, samplepos); // Set up new detector parameters related to new instrument double l2 = storL2s[i]; double tth = stor2Thetas[i]; double phi = storPhis[i]; Kernel::V3D pos; pos.spherical(l2, tth, phi); detector->setPos(pos); // Add new detector to spectrum and instrument // Good and do some debug output g_log.debug() << "Orignal spectrum " << indexInfo.spectrumNumber(i) << "has " << indexInfo.detectorIDs(i).size() << " detectors. \n"; detIDs.push_back(newdetid); instrument->add(detector); instrument->markAsDetector(detector); } // ENDFOR workspace index indexInfo.setDetectorIDs(std::move(detIDs)); workspace->setIndexInfo(indexInfo); // Add the new instrument workspace->setInstrument(instrument); }
/// Execute the algorithm in case of a histogrammed data. void ExtractSpectra::execHistogram() { // Retrieve and validate the input properties this->checkProperties(); // Create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( m_inputWorkspace, m_workspaceIndexList.size(), m_maxX - m_minX, m_maxX - m_minX - m_histogram); outputWorkspace->setIndexInfo( Indexing::extract(m_inputWorkspace->indexInfo(), m_workspaceIndexList)); // If this is a Workspace2D, get the spectra axes for copying in the spectraNo // later Axis *inAxis1(nullptr); TextAxis *outTxtAxis(nullptr); NumericAxis *outNumAxis(nullptr); if (m_inputWorkspace->axes() > 1) { inAxis1 = m_inputWorkspace->getAxis(1); auto outAxis1 = outputWorkspace->getAxis(1); outTxtAxis = dynamic_cast<TextAxis *>(outAxis1); if (!outTxtAxis) outNumAxis = dynamic_cast<NumericAxis *>(outAxis1); } cow_ptr<HistogramData::HistogramX> newX(nullptr); if (m_commonBoundaries) { auto &oldX = m_inputWorkspace->x(m_workspaceIndexList.front()); newX = make_cow<HistogramData::HistogramX>(oldX.begin() + m_minX, oldX.begin() + m_maxX); } bool doCrop = ((m_minX != 0) || (m_maxX != m_inputWorkspace->x(0).size())); Progress prog(this, 0.0, 1.0, (m_workspaceIndexList.size())); // Loop over the required workspace indices, copying in the desired bins for (int j = 0; j < static_cast<int>(m_workspaceIndexList.size()); ++j) { auto i = m_workspaceIndexList[j]; bool hasDx = m_inputWorkspace->hasDx(i); // Preserve/restore sharing if X vectors are the same if (m_commonBoundaries) { outputWorkspace->setSharedX(j, newX); if (hasDx) { auto &oldDx = m_inputWorkspace->dx(i); outputWorkspace->setSharedDx( j, make_cow<HistogramData::HistogramDx>( oldDx.begin() + m_minX, oldDx.begin() + m_maxX - m_histogram)); } } else { // Safe to just copy whole vector 'cos can't be cropping in X if not // common outputWorkspace->setSharedX(j, m_inputWorkspace->sharedX(i)); outputWorkspace->setSharedDx(j, m_inputWorkspace->sharedDx(i)); } if (doCrop) { auto &oldY = m_inputWorkspace->y(i); outputWorkspace->mutableY(j) .assign(oldY.begin() + m_minX, oldY.begin() + (m_maxX - m_histogram)); auto &oldE = m_inputWorkspace->e(i); outputWorkspace->mutableE(j) .assign(oldE.begin() + m_minX, oldE.begin() + (m_maxX - m_histogram)); } else { outputWorkspace->setSharedY(j, m_inputWorkspace->sharedY(i)); outputWorkspace->setSharedE(j, m_inputWorkspace->sharedE(i)); } // copy over the axis entry for each spectrum, regardless of the type of // axes present if (inAxis1) { if (outTxtAxis) { outTxtAxis->setLabel(j, inAxis1->label(i)); } else if (outNumAxis) { outNumAxis->setValue(j, inAxis1->operator()(i)); } // spectra axis is implicit in workspace creation } if (!m_commonBoundaries) this->cropRagged(outputWorkspace, static_cast<int>(i), j); // Propagate bin masking if there is any if (m_inputWorkspace->hasMaskedBins(i)) { const MatrixWorkspace::MaskList &inputMasks = m_inputWorkspace->maskedBins(i); MatrixWorkspace::MaskList::const_iterator it; for (it = inputMasks.begin(); it != inputMasks.end(); ++it) { const size_t maskIndex = (*it).first; if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram) outputWorkspace->flagMasked(j, maskIndex - m_minX, (*it).second); } } prog.report(); } setProperty("OutputWorkspace", outputWorkspace); }