/// calculate distance from source to sample or detector double ModeratorTzero::CalculateL1(Mantid::API::MatrixWorkspace_sptr inputWS, size_t i){ double L1(0); // Get detector position IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError&) { return 0; } if( det->isMonitor() ) { L1=m_instrument->getSource()->getDistance(*det); } else { IComponent_const_sptr sample = m_instrument->getSample(); try { L1 = m_instrument->getSource()->getDistance(*sample); } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate source-sample distance"); throw Exception::InstrumentDefinitionError("Unable to calculate source-sample distance", inputWS->getTitle()); } } return L1; }
/* * Sum up all the unmasked detector pixels. * * @param rebinnedWS: workspace where all the wavelength bins have been grouped together * @param sum: sum of all the unmasked detector pixels (counts) * @param error: error on sum (counts) * @param nPixels: number of unmasked detector pixels that contributed to sum */ void CalculateEfficiency::sumUnmaskedDetectors(MatrixWorkspace_sptr rebinnedWS, double& sum, double& error, int& nPixels) { // Number of spectra const int numberOfSpectra = static_cast<int>(rebinnedWS->getNumberHistograms()); sum = 0.0; error = 0.0; nPixels = 0; for (int i = 0; i < numberOfSpectra; i++) { progress(0.2+0.2*i/numberOfSpectra, "Computing sensitivity"); // Get the detector object for this spectrum IDetector_const_sptr det = rebinnedWS->getDetector(i); // If this detector is masked, skip to the next one if ( det->isMasked() ) continue; // If this detector is a monitor, skip to the next one if ( det->isMonitor() ) continue; // Retrieve the spectrum into a vector const MantidVec& YValues = rebinnedWS->readY(i); const MantidVec& YErrors = rebinnedWS->readE(i); sum += YValues[0]; error += YErrors[0]*YErrors[0]; nPixels++; } error = std::sqrt(error); }
/** Get instrument geometry setup including L2 for each detector and L1 */ void CreateLogTimeCorrection::getInstrumentSetup() { // 1. Get sample position and source position IComponent_const_sptr sample = m_instrument->getSample(); if (!sample) { throw runtime_error("No sample has been set."); } V3D samplepos = sample->getPos(); IComponent_const_sptr source = m_instrument->getSource(); if (!source) { throw runtime_error("No source has been set."); } V3D sourcepos = source->getPos(); m_L1 = sourcepos.distance(samplepos); // 2. Get detector IDs std::vector<detid_t> detids = m_instrument->getDetectorIDs(true); for (auto &detid : detids) { IDetector_const_sptr detector = m_instrument->getDetector(detid); V3D detpos = detector->getPos(); double l2 = detpos.distance(samplepos); m_l2map.emplace(detid, l2); } // 3. Output information g_log.information() << "Sample position = " << samplepos << "; " << "Source position = " << sourcepos << ", L1 = " << m_L1 << "; " << "Number of detector/pixels = " << detids.size() << ".\n"; }
/** Extract mask information from a workspace containing instrument * @return vector of detector IDs of detectors that are masked */ std::vector<detid_t> ExtractMaskToTable::extractMaskFromMatrixWorkspace() { // Clear input std::vector<detid_t> maskeddetids; // Get on hold of instrument Instrument_const_sptr instrument = m_dataWS->getInstrument(); if (!instrument) throw runtime_error("There is no instrument in input workspace."); // Extract size_t numdets = instrument->getNumberDetectors(); vector<detid_t> detids = instrument->getDetectorIDs(); for (size_t i = 0; i < numdets; ++i) { detid_t tmpdetid = detids[i]; IDetector_const_sptr tmpdetector = instrument->getDetector(tmpdetid); bool masked = tmpdetector->isMasked(); if (masked) { maskeddetids.push_back(tmpdetid); } g_log.debug() << "[DB] Detector No. " << i << ": ID = " << tmpdetid << ", Masked = " << masked << ".\n"; } g_log.notice() << "Extract mask: There are " << maskeddetids.size() << " detectors that" " are masked." << ".\n"; return maskeddetids; }
/** * Execute the algorithm */ void ExtractMasking::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); const int nHist = static_cast<int>(inputWS->getNumberHistograms()); const int xLength(1), yLength(1); // Create a new workspace for the results, copy from the input to ensure that we copy over the instrument and current masking MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS, nHist, xLength, yLength); Progress prog(this,0.0,1.0,nHist); MantidVecPtr xValues; xValues.access() = MantidVec(1, 0.0); PARALLEL_FOR2(inputWS, outputWS) for( int i = 0; i < nHist; ++i ) { PARALLEL_START_INTERUPT_REGION // Spectrum in the output workspace ISpectrum * outSpec = outputWS->getSpectrum(i); // Spectrum in the input workspace const ISpectrum * inSpec = inputWS->getSpectrum(i); // Copy X, spectrum number and detector IDs outSpec->setX(xValues); outSpec->copyInfoFrom(*inSpec); IDetector_const_sptr inputDet; bool inputIsMasked(false); try { inputDet = inputWS->getDetector(i); if( inputDet->isMasked() ) { inputIsMasked = true; } } catch(Kernel::Exception::NotFoundError &) { inputIsMasked = false; } if( inputIsMasked ) { outSpec->dataY()[0] = 0.0; outSpec->dataE()[0] = 0.0; } else { outSpec->dataY()[0] = 1.0; outSpec->dataE()[0] = 1.0; } prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION setProperty("OutputWorkspace", outputWS); }
void SANSSolidAngleCorrection::execEvent() { MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); // generate the output workspace pointer MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if (outputWS != inputWS) { outputWS = inputWS->clone(); setProperty("OutputWorkspace", outputWS); } auto outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); const int numberOfSpectra = static_cast<int>(outputEventWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); progress.report("Solid Angle Correction"); PARALLEL_FOR1(outputEventWS) for (int i = 0; i < numberOfSpectra; i++) { PARALLEL_START_INTERUPT_REGION IDetector_const_sptr det; try { det = outputEventWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.warning() << "Workspace index " << i << " has no detector assigned to it - discarding\n"; // Catch if no detector. Next line tests whether this happened - test // placed // outside here because Mac Intel compiler doesn't like 'continue' in a // catch // in an openmp block. } if (!det) continue; // Skip if we have a monitor or if the detector is masked. if (det->isMonitor() || det->isMasked()) continue; // Compute solid angle correction factor const bool is_tube = getProperty("DetectorTubes"); const double tanTheta = tan(outputEventWS->detectorTwoTheta(*det)); const double theta_term = sqrt(tanTheta * tanTheta + 1.0); double corr; if (is_tube) { const double tanAlpha = tan(getYTubeAngle(det, inputWS)); const double alpha_term = sqrt(tanAlpha * tanAlpha + 1.0); corr = alpha_term * theta_term * theta_term; } else { corr = theta_term * theta_term * theta_term; } EventList &el = outputEventWS->getSpectrum(i); el *= corr; progress.report("Solid Angle Correction"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION setProperty("OutputMessage", "Solid angle correction applied"); }
/** * * @param filename filename A full path to the input RAW file */ void LoadDetectorInfo::loadFromIsisNXS(const std::string &filename) { ::NeXus::File nxsFile(filename, NXACC_READ); // will throw if file can't be opened // two types of file: // - new type entry per detector // - old libisis with single pressure, thickness entry for whole file // hold data read from file DetectorInfo detInfo; std::map<std::string, std::string> entries; nxsFile.getEntries(entries); if (entries.find("full_reference_detector") != entries.end()) { nxsFile.openGroup("full_reference_detector", "NXIXTdetector"); readLibisisNxs(nxsFile, detInfo); nxsFile.closeGroup(); } else if (entries.find("detectors.dat") != entries.end()) { nxsFile.openGroup("detectors.dat", "NXEntry"); readNXSDotDat(nxsFile, detInfo); nxsFile.closeGroup(); } else { throw std::invalid_argument("Unknown NeXus file type"); } nxsFile.close(); // Start loop over detectors auto &pmap = m_workspace->instrumentParameters(); int numDets = static_cast<int>(detInfo.ids.size()); for (int i = 0; i < numDets; ++i) { detid_t detID = detInfo.ids[i]; int code = detInfo.codes[i]; IDetector_const_sptr det; try { det = m_baseInstrument->getDetector(detID); } catch (Exception::NotFoundError &) { continue; } if (det->isMonitor() || code == 1) continue; // Positions double l2 = detInfo.l2[i]; double theta = detInfo.theta[i]; double phi = detInfo.phi[i]; // Parameters double delta = detInfo.delays[i]; // offset value is be subtracted so store negative delta *= -1.0; // pressure, wall thickness double pressure = detInfo.pressures[i]; double thickness = detInfo.thicknesses[i]; updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness); } }
/** * A map detector ID and Q ranges * This method looks unnecessary as it could be calculated on the fly but * the parallelization means that lazy instantation slows it down due to the * necessary CRITICAL sections required to update the cache. The Q range * values are required very frequently so the total time is more than * offset by this precaching step */ void SofQW2::initThetaCache(API::MatrixWorkspace_const_sptr workspace) { const size_t nhist = workspace->getNumberHistograms(); m_thetaPts = std::vector<double>(nhist); size_t ndets(0); double minTheta(DBL_MAX), maxTheta(-DBL_MAX); for(int64_t i = 0 ; i < (int64_t)nhist; ++i) //signed for OpenMP { m_progress->report("Calculating detector angles"); IDetector_const_sptr det; try { det = workspace->getDetector(i); // Check to see if there is an EFixed, if not skip it try { m_EmodeProperties.getEFixed(det); } catch(std::runtime_error&) { det.reset(); } } catch(Kernel::Exception::NotFoundError&) { // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found, skip onto the next spectrum if( !det || det->isMonitor() ) { m_thetaPts[i] = -1.0; // Indicates a detector to skip } else { ++ndets; const double theta = workspace->detectorTwoTheta(det); m_thetaPts[i] = theta; if( theta < minTheta ) { minTheta = theta; } else if( theta > maxTheta ) { maxTheta = theta; } } } m_thetaWidth = (maxTheta - minTheta)/static_cast<double>(ndets); g_log.information() << "Calculated detector width in theta=" << (m_thetaWidth*180.0/M_PI) << " degrees.\n"; }
/** * @param filename A full path to the input RAW file */ void LoadDetectorInfo::loadFromRAW(const std::string &filename) { ISISRAW2 iraw; if (iraw.readFromFile(filename.c_str(), false) != 0) { throw Exception::FileError("Unable to access raw file:", filename); } const int numDets = iraw.i_det; const int numUserTables = iraw.i_use; int pressureTabNum(0), thicknessTabNum(0); if (numUserTables == 10) { pressureTabNum = 7; thicknessTabNum = 8; } else if (numUserTables == 14) { pressureTabNum = 11; thicknessTabNum = 12; } else { throw std::invalid_argument( "RAW file contains unexpected number of user tables=" + std::to_string(numUserTables) + ". Expected 10 or 14."); } // Is ut01 (=phi) present? Sometimes an array is present but has wrong values // e.g.all 1.0 or all 2.0 bool phiPresent = (iraw.ut[0] != 1.0 && iraw.ut[0] != 2.0); // Start loop over detectors auto &pmap = m_workspace->instrumentParameters(); for (int i = 0; i < numDets; ++i) { detid_t detID = static_cast<detid_t>(iraw.udet[i]); int code = iraw.code[i]; IDetector_const_sptr det; try { det = m_baseInstrument->getDetector(detID); } catch (Exception::NotFoundError &) { continue; } if (det->isMonitor() || code == 1) continue; // Positions float l2 = iraw.len2[i]; float theta = iraw.tthe[i]; float phi = (phiPresent ? iraw.ut[i] : 0.0f); // Parameters float delta = iraw.delt[i]; // offset value is be subtracted so store negative delta *= -1.0f; // pressure, wall thickness float pressure = iraw.ut[i + pressureTabNum * numDets]; float thickness = iraw.ut[i + thicknessTabNum * numDets]; updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness); } }
/** If needed, cache the detector positions for all detectors. * Call this BEFORE getDetPos(). * Does nothing if the positions have already been cached. */ void InstrumentActor::cacheDetPos() const { if (m_detPos.size() != m_detIDs.size()) { m_detPos.clear(); for (size_t i=0; i<m_detIDs.size(); i++) { IDetector_const_sptr det = this->getDetector(i); m_detPos.push_back( det->getPos() ); } } }
/// Calculate the distances traversed by the neutrons within the sample /// @param detector :: The detector we are working on /// @param L2s :: A vector of the sample-detector distance for each segment of /// the sample void AbsorptionCorrection::calculateDistances( const IDetector_const_sptr &detector, std::vector<double> &L2s) const { V3D detectorPos(detector->getPos()); if (detector->nDets() > 1) { // We need to make sure this is right for grouped detectors - should use // average theta & phi detectorPos.spherical(detectorPos.norm(), detector->getTwoTheta(V3D(), V3D(0, 0, 1)) * 180.0 / M_PI, detector->getPhi() * 180.0 / M_PI); } for (size_t i = 0; i < m_numVolumeElements; ++i) { // Create track for distance in cylinder between scattering point and // detector V3D direction = detectorPos - m_elementPositions[i]; direction.normalize(); Track outgoing(m_elementPositions[i], direction); int temp = m_sampleObject->interceptSurface(outgoing); /* Most of the time, the number of hits is 1. Sometime, we have more than * one intersection due to * arithmetic imprecision. If it is the case, then selecting the first * intersection is valid. * In principle, one could check the consistency of all distances if hits is * larger than one by doing: * Mantid::Geometry::Track::LType::const_iterator it=outgoing.begin(); * and looping until outgoing.end() checking the distances with it->Dist */ // Not hitting the cylinder from inside, usually means detector is badly // defined, // i.e, position is (0,0,0). if (temp < 1) { // FOR NOW AT LEAST, JUST IGNORE THIS ERROR AND USE A ZERO PATH LENGTH, // WHICH I RECKON WILL MAKE A // NEGLIGIBLE DIFFERENCE ANYWAY (ALWAYS SEEMS TO HAPPEN WITH ELEMENT RIGHT // AT EDGE OF SAMPLE) L2s[i] = 0.0; // std::ostringstream message; // message << "Problem with detector at " << detectorPos << " ID:" << // detector->getID() << std::endl; // message << "This usually means that this detector is defined inside the // sample cylinder"; // g_log.error(message.str()); // throw std::runtime_error("Problem in // AbsorptionCorrection::calculateDistances"); } else // The normal situation { L2s[i] = outgoing.begin()->distFromStart; } } }
// calculate time from sample to detector void ModeratorTzeroLinear::calculateTfLi(MatrixWorkspace_const_sptr inputWS, size_t i, double &t_f, double &L_i) { static const double convFact = 1.0e-6 * sqrt(2 * PhysicalConstants::meV / PhysicalConstants::NeutronMass); static const double TfError = -1.0; // signal error when calculating final // time // Get detector position IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError &) { t_f = TfError; return; } if (det->isMonitor()) { L_i = m_instrument->getSource()->getDistance(*det); t_f = 0.0; // t_f=0.0 since there is no sample to detector path } else { IComponent_const_sptr sample = m_instrument->getSample(); try { L_i = m_instrument->getSource()->getDistance(*sample); } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate source-sample distance"); throw Exception::InstrumentDefinitionError( "Unable to calculate source-sample distance", inputWS->getTitle()); } // Get final energy E_f, final velocity v_f std::vector<double> wsProp = det->getNumberParameter("Efixed"); if (!wsProp.empty()) { double E_f = wsProp.at(0); //[E_f]=meV double v_f = convFact * sqrt(E_f); //[v_f]=meter/microsec try { // obtain L_f, calculate t_f double L_f = det->getDistance(*sample); t_f = L_f / v_f; // g_log.debug() << "detector: " << i << " L_f=" << L_f << " t_f=" << // t_f << '\n'; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate detector-sample distance"); throw Exception::InstrumentDefinitionError( "Unable to calculate detector-sample distance", inputWS->getTitle()); } } else { g_log.debug() << "Efixed not found for detector " << i << '\n'; t_f = TfError; } } } // end of CalculateTf(const MatrixWorkspace_sptr inputWS, size_t i)
/** Gets the distances between the source and detectors whose IDs you pass to it * @param WS :: the input workspace * @param mon0Spec :: Spectrum number of the output from the first monitor * @param mon1Spec :: Spectrum number of the output from the second monitor * @param monitor0Dist :: the calculated distance to the detector whose ID was * passed to this function first * @param monitor1Dist :: calculated distance to the detector whose ID was * passed to this function second * @throw NotFoundError if no detector is found for the detector ID given */ void GetEi::getGeometry(API::MatrixWorkspace_const_sptr WS, specid_t mon0Spec, specid_t mon1Spec, double &monitor0Dist, double &monitor1Dist) const { const IComponent_const_sptr source = WS->getInstrument()->getSource(); // retrieve a pointer to the first detector and get its distance size_t monWI = 0; try { monWI = WS->getIndexFromSpectrumNumber(mon0Spec); } catch (std::runtime_error &) { g_log.error() << "Could not find the workspace index for the monitor at spectrum " << mon0Spec << "\n"; g_log.error() << "Error retrieving data for the first monitor" << std::endl; throw std::bad_cast(); } const std::set<detid_t> &dets = WS->getSpectrum(monWI)->getDetectorIDs(); if (dets.size() != 1) { g_log.error() << "The detector for spectrum number " << mon0Spec << " was either not found or is a group, grouped monitors " "are not supported by this algorithm\n"; g_log.error() << "Error retrieving data for the first monitor" << std::endl; throw std::bad_cast(); } IDetector_const_sptr det = WS->getInstrument()->getDetector(*dets.begin()); monitor0Dist = det->getDistance(*(source.get())); // repeat for the second detector try { monWI = WS->getIndexFromSpectrumNumber(mon0Spec); } catch (std::runtime_error &) { g_log.error() << "Could not find the workspace index for the monitor at spectrum " << mon0Spec << "\n"; g_log.error() << "Error retrieving data for the second monitor\n"; throw std::bad_cast(); } const std::set<detid_t> &dets2 = WS->getSpectrum(monWI)->getDetectorIDs(); if (dets2.size() != 1) { g_log.error() << "The detector for spectrum number " << mon1Spec << " was either not found or is a group, grouped monitors " "are not supported by this algorithm\n"; g_log.error() << "Error retrieving data for the second monitor\n"; throw std::bad_cast(); } det = WS->getInstrument()->getDetector(*dets2.begin()); monitor1Dist = det->getDistance(*(source.get())); }
double ConvertSpectrumAxis::getEfixed(const Mantid::Geometry::IDetector &detector, MatrixWorkspace_const_sptr inputWS, int emode) const { double efixed(0); double efixedProp = getProperty("Efixed"); if (efixedProp != EMPTY_DBL()) { efixed = efixedProp; g_log.debug() << "Detector: " << detector.getID() << " Efixed: " << efixed << "\n"; } else { if (emode == 1) { if (inputWS->run().hasProperty("Ei")) { Kernel::Property *p = inputWS->run().getProperty("Ei"); Kernel::PropertyWithValue<double> *doublep = dynamic_cast<Kernel::PropertyWithValue<double> *>(p); if (doublep) { efixed = (*doublep)(); } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } else if (emode == 2) { std::vector<double> efixedVec = detector.getNumberParameter("Efixed"); if (efixedVec.empty()) { int detid = detector.getID(); IDetector_const_sptr detectorSingle = inputWS->getInstrument()->getDetector(detid); efixedVec = detectorSingle->getNumberParameter("Efixed"); } if (!efixedVec.empty()) { efixed = efixedVec.at(0); g_log.debug() << "Detector: " << detector.getID() << " EFixed: " << efixed << "\n"; } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } } return efixed; }
/** Execute the algorithm. */ void WeightedMeanOfWorkspace::exec() { MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace"); // Check if it is an event workspace EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventW != NULL) { throw std::runtime_error("WeightedMeanOfWorkspace cannot handle EventWorkspaces!"); } // Create the output workspace MatrixWorkspace_sptr singleValued = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1); // Calculate weighted mean std::size_t numHists = inputWS->getNumberHistograms(); double averageValue = 0.0; double weightSum = 0.0; for (std::size_t i = 0; i < numHists; ++i) { try { IDetector_const_sptr det = inputWS->getDetector(i); if( det->isMonitor() || det->isMasked() ) { continue; } } catch (...) { // Swallow these if no instrument is found ; } MantidVec y = inputWS->dataY(i); MantidVec e = inputWS->dataE(i); double weight = 0.0; for (std::size_t j = 0; j < y.size(); ++j) { if (!boost::math::isnan(y[j]) && !boost::math::isinf(y[j]) && !boost::math::isnan(e[j]) && !boost::math::isinf(e[j])) { weight = 1.0 / (e[j] * e[j]); averageValue += (y[j] * weight); weightSum += weight; } } } singleValued->dataX(0)[0] = 0.0; singleValued->dataY(0)[0] = averageValue / weightSum; singleValued->dataE(0)[0] = std::sqrt(weightSum); this->setProperty("OutputWorkspace", singleValued); }
/** * Full format is defined in doc text * @param filename A full path to the input DAT file */ void LoadDetectorInfo::loadFromDAT(const std::string & filename) { std::ifstream datFile(filename.c_str()); if(!datFile) { throw Exception::FileError("Unable to access dat file", filename); } std::string line; // skip 3 lines of header info for(int i = 0; i < 3; ++i) getline(datFile, line); // start loop over file auto & pmap = m_workspace->instrumentParameters(); while(getline(datFile, line)) { if(line.empty() || line[0] == '#') continue; std::istringstream is(line); detid_t detID(0); int code(0); float droppedFloat(0.0f); float delta(0.0f), l2(0.0f), theta(0.0f), phi(0.0f); is >> detID >> delta >> l2 >> code >> theta >> phi; // offset value is be subtracted so store negative delta *= -1.0f; IDetector_const_sptr det; try { det = m_baseInstrument->getDetector(detID); } catch(Exception::NotFoundError&) { continue; } if(det->isMonitor() || code == 1) continue; // drop 10 float columns for(int i = 0; i < 10; ++i) is >> droppedFloat; // pressure, wall thickness float pressure(0.0), thickness(0.0); is >> pressure >> thickness; updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness); } }
//calculate time from sample to detector double ModeratorTzero::CalculateT2(MatrixWorkspace_sptr inputWS, size_t i) { static const double convFact = 1.0e-6*sqrt(2*PhysicalConstants::meV/PhysicalConstants::NeutronMass); double t2(-1.0); // negative initialization signals error // Get detector position IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError&) { return t2; } if( det->isMonitor() ) { t2 = 0.0; //t2=0.0 since there is no sample to detector path } else { IComponent_const_sptr sample = m_instrument->getSample(); // Get final energy E_f, final velocity v_f std::vector< double > wsProp=det->getNumberParameter("Efixed"); if ( !wsProp.empty() ) { double E2 = wsProp.at(0); //[E2]=meV double v2 = convFact * sqrt(E2); //[v2]=meter/microsec try { double L2 = det->getDistance(*sample); t2 = L2 / v2; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate detector-sample distance"); throw Exception::InstrumentDefinitionError("Unable to calculate detector-sample distance", inputWS->getTitle()); } } else { g_log.debug() <<"Efixed not found for detector "<< i << std::endl; } } return t2; } // end of CalculateT2(const MatrixWorkspace_sptr inputWS, size_t i)
/** Gets the results of the trace, then returns the first detector * (that is NOT a monitor) found in the results. * @return sptr to IDetector, or an invalid sptr if not found */ IDetector_const_sptr InstrumentRayTracer::getDetectorResult() const { Links results = this->getResults(); // Go through all results Links::const_iterator resultItr = results.begin(); for (; resultItr != results.end(); ++resultItr) { IComponent_const_sptr component = m_instrument->getComponentByID(resultItr->componentID); IDetector_const_sptr det = boost::dynamic_pointer_cast<const IDetector>(component); if (det) { if (!det->isMonitor()) { return det; } } // (is a detector) } // each ray tracer result return IDetector_const_sptr(); }
/** * Get the list of detectors associated with a spectra * @param instrument :: A pointer to the instrument * @param spectraMap :: A reference to the spectra map * @returns A map of spectra number to detector pointer */ std::map<specid_t, IDetector_const_sptr> NearestNeighbours::getSpectraDetectors( boost::shared_ptr<const Instrument> instrument, const ISpectrumDetectorMapping &spectraMap) { std::map<specid_t, IDetector_const_sptr> spectra; if (spectraMap.empty()) return spectra; ISpectrumDetectorMapping::const_iterator cend = spectraMap.cend(); for (ISpectrumDetectorMapping::const_iterator citr = spectraMap.cbegin(); citr != cend; ++citr) { const std::vector<detid_t> detIDs(citr->second.begin(), citr->second.end()); IDetector_const_sptr det = instrument->getDetectorG(detIDs); // Always ignore monitors and ignore masked detectors if requested. bool heedMasking = !m_bIgnoreMaskedDetectors && det->isMasked(); if (!det->isMonitor() && !heedMasking) { spectra.insert(std::make_pair(citr->first, det)); } } return spectra; }
Correction TimeAtSampleStrategyIndirect::calculate(const size_t &workspace_index) const { // A constant among all spectra double twomev_d_mass = 2. * PhysicalConstants::meV / PhysicalConstants::NeutronMass; V3D samplepos = m_ws->getInstrument()->getSample()->getPos(); // Get the parameter map const ParameterMap &pmap = m_ws->constInstrumentParameters(); double shift; IDetector_const_sptr det = m_ws->getDetector(workspace_index); if (!det->isMonitor()) { // Get E_fix double efix = 0.; try { Parameter_sptr par = pmap.getRecursive(det.get(), "Efixed"); if (par) { efix = par->value<double>(); } } catch (std::runtime_error &) { // Throws if a DetectorGroup, use single provided value std::stringstream errmsg; errmsg << "Inelastic instrument detector " << det->getID() << " of spectrum " << workspace_index << " does not have EFixed "; throw std::runtime_error(errmsg.str()); } // Get L2 double l2 = det->getPos().distance(samplepos); // Calculate shift shift = -1. * l2 / sqrt(efix * twomev_d_mass); } else { std::stringstream errormsg; errormsg << "Workspace index " << workspace_index << " is a monitor. "; throw std::invalid_argument(errormsg.str()); } return Correction(1.0, shift); }
void AnvredCorrection::scale_init(IDetector_const_sptr det, Instrument_const_sptr inst, int& bank, double& L2, double& depth, double& pathlength, std::string bankName) { bankName = det->getParent()->getParent()->getName(); std::string bankNameStr = bankName; // Take out the "bank" part of the bank name and convert to an int bankNameStr.erase(remove_if(bankNameStr.begin(), bankNameStr.end(), not1(std::ptr_fun (::isdigit))), bankNameStr.end()); Strings::convert(bankNameStr, bank); IComponent_const_sptr sample = inst->getSample(); double cosA = inst->getComponentByName(bankName)->getDistance(*sample) / L2; pathlength = depth / cosA; }
/** Convert X axis to Elastic Q representation * @param progress :: Progress indicator * @param targetUnit :: Target conversion unit * @param inputWS :: Input workspace * @param nHist :: Stores the number of histograms */ void ConvertSpectrumAxis2::createElasticQMap(API::Progress &progress, const std::string &targetUnit, API::MatrixWorkspace_sptr &inputWS, size_t nHist) { IComponent_const_sptr source = inputWS->getInstrument()->getSource(); IComponent_const_sptr sample = inputWS->getInstrument()->getSample(); const std::string emodeStr = getProperty("EMode"); int emode = 0; if (emodeStr == "Direct") emode = 1; else if (emodeStr == "Indirect") emode = 2; for (size_t i = 0; i < nHist; i++) { IDetector_const_sptr detector = inputWS->getDetector(i); double twoTheta(0.0), efixed(0.0); if (!detector->isMonitor()) { twoTheta = 0.5 * inputWS->detectorTwoTheta(*detector); efixed = getEfixed(detector, inputWS, emode); // get efixed } else { twoTheta = 0.0; efixed = DBL_MIN; } // Convert to MomentumTransfer double elasticQInAngstroms = Kernel::UnitConversion::run(twoTheta, efixed); if (targetUnit == "ElasticQ") { m_indexMap.emplace(elasticQInAngstroms, i); } else if (targetUnit == "ElasticQSquared") { // The QSquared value. double elasticQSquaredInAngstroms = elasticQInAngstroms * elasticQInAngstroms; m_indexMap.emplace(elasticQSquaredInAngstroms, i); } progress.report("Converting to Elastic Q..."); } }
double ConvertSpectrumAxis2::getEfixed(IDetector_const_sptr detector, MatrixWorkspace_const_sptr inputWS, int emode) const { double efixed(0); double efixedProp = getProperty("Efixed"); if (efixedProp != EMPTY_DBL()) { efixed = efixedProp; g_log.debug() << "Detector: " << detector->getID() << " Efixed: " << efixed << "\n"; } else { if (emode == 1) { if (inputWS->run().hasProperty("Ei")) { efixed = inputWS->run().getLogAsSingleValue("Ei"); } else { throw std::invalid_argument("Could not retrieve Efixed from the " "workspace. Please provide a value."); } } else if (emode == 2) { std::vector<double> efixedVec = detector->getNumberParameter("Efixed"); if (efixedVec.empty()) { int detid = detector->getID(); IDetector_const_sptr detectorSingle = inputWS->getInstrument()->getDetector(detid); efixedVec = detectorSingle->getNumberParameter("Efixed"); } if (!efixedVec.empty()) { efixed = efixedVec.at(0); g_log.debug() << "Detector: " << detector->getID() << " EFixed: " << efixed << "\n"; } else { g_log.warning() << "Efixed could not be found for detector " << detector->getID() << ", please provide a value\n"; throw std::invalid_argument("Could not retrieve Efixed from the " "detector. Please provide a value."); } } } return efixed; }
/** * Execution path for NormalisedPolygon Rebinning * @param inputWS : Workspace to be rebinned * @param vertexes : TableWorkspace for debugging purposes * @param dumpVertexes : determines whether vertexes will be written to for * debugging purposes or not * @param outputDimensions : used for the column headings for Dump Vertexes */ MatrixWorkspace_sptr ReflectometryTransform::executeNormPoly( MatrixWorkspace_const_sptr inputWS, boost::shared_ptr<Mantid::DataObjects::TableWorkspace> &vertexes, bool dumpVertexes, std::string outputDimensions) const { MatrixWorkspace_sptr temp = WorkspaceFactory::Instance().create( "RebinnedOutput", m_d1NumBins, m_d0NumBins, m_d0NumBins); RebinnedOutput_sptr outWS = boost::static_pointer_cast<RebinnedOutput>(temp); const double widthD0 = (m_d0Max - m_d0Min) / double(m_d0NumBins); const double widthD1 = (m_d1Max - m_d1Min) / double(m_d1NumBins); std::vector<double> xBinsVec; std::vector<double> zBinsVec; VectorHelper::createAxisFromRebinParams({m_d1Min, widthD1, m_d1Max}, zBinsVec); VectorHelper::createAxisFromRebinParams({m_d0Min, widthD0, m_d0Max}, xBinsVec); // Put the correct bin boundaries into the workspace auto verticalAxis = new BinEdgeAxis(zBinsVec); outWS->replaceAxis(1, verticalAxis); for (size_t i = 0; i < zBinsVec.size() - 1; ++i) outWS->setX(i, xBinsVec); verticalAxis->title() = m_d1Label; // Prepare the required theta values DetectorAngularCache cache = initAngularCaches(inputWS.get()); m_theta = cache.thetas; m_thetaWidths = cache.thetaWidths; const size_t nHistos = inputWS->getNumberHistograms(); const size_t nBins = inputWS->blocksize(); // Holds the spectrum-detector mapping std::vector<specnum_t> specNumberMapping; std::vector<detid_t> detIDMapping; // Create a table for the output if we want to debug vertex positioning addColumnHeadings(vertexes, outputDimensions); for (size_t i = 0; i < nHistos; ++i) { IDetector_const_sptr detector = inputWS->getDetector(i); if (!detector || detector->isMasked() || detector->isMonitor()) { continue; } // Compute polygon points const double theta = m_theta[i]; const double thetaWidth = m_thetaWidths[i]; const double thetaHalfWidth = 0.5 * thetaWidth; const double thetaLower = theta - thetaHalfWidth; const double thetaUpper = theta + thetaHalfWidth; const MantidVec &X = inputWS->readX(i); const MantidVec &Y = inputWS->readY(i); const MantidVec &E = inputWS->readE(i); for (size_t j = 0; j < nBins; ++j) { const double lamLower = X[j]; const double lamUpper = X[j + 1]; const double signal = Y[j]; const double error = E[j]; auto inputQ = m_calculator->createQuad(lamUpper, lamLower, thetaUpper, thetaLower); FractionalRebinning::rebinToFractionalOutput(inputQ, inputWS, i, j, outWS, zBinsVec); // Find which qy bin this point lies in const auto qIndex = std::upper_bound(zBinsVec.begin(), zBinsVec.end(), inputQ[0].Y()) - zBinsVec.begin(); if (qIndex != 0 && qIndex < static_cast<int>(zBinsVec.size())) { // Add this spectra-detector pair to the mapping specNumberMapping.push_back( outWS->getSpectrum(qIndex - 1).getSpectrumNo()); detIDMapping.push_back(detector->getID()); } // Debugging if (dumpVertexes) { writeRow(vertexes, inputQ[0], i, j, signal, error); writeRow(vertexes, inputQ[1], i, j, signal, error); writeRow(vertexes, inputQ[2], i, j, signal, error); writeRow(vertexes, inputQ[3], i, j, signal, error); } } } outWS->finalize(); FractionalRebinning::normaliseOutput(outWS, inputWS); // Set the output spectrum-detector mapping SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping); outWS->updateSpectraUsing(outputDetectorMap); outWS->getAxis(0)->title() = m_d0Label; outWS->setYUnit(""); outWS->setYUnitLabel("Intensity"); return outWS; }
/** * A map detector ID and Q ranges * This method looks unnecessary as it could be calculated on the fly but * the parallelization means that lazy instantation slows it down due to the * necessary CRITICAL sections required to update the cache. The Q range * values are required very frequently so the total time is more than * offset by this precaching step */ DetectorAngularCache initAngularCaches(const MatrixWorkspace *const workspace) { const size_t nhist = workspace->getNumberHistograms(); std::vector<double> thetas(nhist); std::vector<double> thetaWidths(nhist); std::vector<double> detectorHeights(nhist); auto inst = workspace->getInstrument(); const auto samplePos = inst->getSample()->getPos(); const V3D upDirVec = inst->getReferenceFrame()->vecPointingUp(); for (size_t i = 0; i < nhist; ++i) // signed for OpenMP { IDetector_const_sptr det; try { det = workspace->getDetector(i); } catch (Exception::NotFoundError &) { // Catch if no detector. Next line tests whether this happened - test // placed // outside here because Mac Intel compiler doesn't like 'continue' in a // catch // in an openmp block. } // If no detector found, skip onto the next spectrum if (!det || det->isMonitor()) { thetas[i] = -1.0; // Indicates a detector to skip thetaWidths[i] = -1.0; continue; } // We have to convert theta from radians to degrees const double theta = workspace->detectorSignedTwoTheta(*det) * rad2deg; thetas[i] = theta; /** * Determine width from shape geometry. A group is assumed to contain * detectors with the same shape & r, theta value, i.e. a ring mapped-group * The shape is retrieved and rotated to match the rotation of the detector. * The angular width is computed using the l2 distance from the sample */ if (auto group = boost::dynamic_pointer_cast<const DetectorGroup>(det)) { // assume they all have same shape and same r,theta auto dets = group->getDetectors(); det = dets[0]; } const auto pos = det->getPos() - samplePos; double l2(0.0), t(0.0), p(0.0); pos.getSpherical(l2, t, p); // Get the shape auto shape = det->shape(); // Defined in its own reference frame with centre at 0,0,0 BoundingBox bbox = shape->getBoundingBox(); auto maxPoint(bbox.maxPoint()); auto minPoint(bbox.minPoint()); auto span = maxPoint - minPoint; detectorHeights[i] = span.scalar_prod(upDirVec); thetaWidths[i] = 2.0 * std::fabs(std::atan((detectorHeights[i] / 2) / l2)) * 180.0 / M_PI; } DetectorAngularCache cache; cache.thetas = thetas; cache.thetaWidths = thetaWidths; cache.detectorHeights = detectorHeights; return cache; }
/** @ throw invalid_argument if the workspaces are not mututially compatible */ void Q1D2::exec() { m_dataWS = getProperty("DetBankWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj"); const bool doGravity = getProperty("AccountForGravity"); m_doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(m_dataWS, waveAdj, pixelAdj); // FIXME: how to examine the wavePixelAdj? g_log.debug() << "All input workspaces were found to be valid\n"; // normalization as a function of wavelength (i.e. centers of x-value bins) double const * const binNorms = waveAdj ? &(waveAdj->readY(0)[0]) : NULL; // error on the wavelength normalization double const * const binNormEs = waveAdj ? &(waveAdj->readE(0)[0]) : NULL; //define the (large number of) data objects that are going to be used in all iterations of the loop below // this will become the output workspace from this algorithm MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning")); const MantidVec & QOut = outputWS->readX(0); MantidVec & YOut = outputWS->dataY(0); MantidVec & EOutTo2 = outputWS->dataE(0); // normalisation that is applied to counts in each Q bin MantidVec normSum(YOut.size(), 0.0); // the error on the normalisation MantidVec normError2(YOut.size(), 0.0); const int numSpec = static_cast<int>(m_dataWS->getNumberHistograms()); Progress progress(this, 0.05, 1.0, numSpec+1); PARALLEL_FOR3(m_dataWS, outputWS, pixelAdj) for (int i = 0; i < numSpec; ++i) { PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = m_dataWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i)->getSpectrumNo() << ") has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found or if detector is masked shouldn't be included skip onto the next spectrum if ( !det || det->isMonitor() || det->isMasked() ) { continue; } //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for //const size_t wavStart = waveLengthCutOff(i); const size_t wavStart = helper.waveLengthCutOff(m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= m_dataWS->readY(i).size()) { // all the spectra in this detector are out of range continue; } const size_t numWavbins = m_dataWS->readY(i).size()-wavStart; // make just one call to new to reduce CPU overhead on each thread, access to these // three "arrays" is via iterators MantidVec _noDirectUseStorage_(3*numWavbins); //normalization term MantidVec::iterator norms = _noDirectUseStorage_.begin(); // the error on these weights, it contributes to the error calculation on the output workspace MantidVec::iterator normETo2s = norms + numWavbins; // the Q values calculated from input wavelength workspace MantidVec::iterator QIn = normETo2s + numWavbins; // the weighting for this input spectrum that is added to the normalization calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s); // now read the data from the input workspace, calculate Q for each bin convertWavetoQ(i, doGravity, wavStart, QIn); // Pointers to the counts data and it's error MantidVec::const_iterator YIn = m_dataWS->readY(i).begin()+wavStart; MantidVec::const_iterator EIn = m_dataWS->readE(i).begin()+wavStart; //when finding the output Q bin remember that the input Q bins (from the convert to wavelength) start high and reduce MantidVec::const_iterator loc = QOut.end(); // sum the Q contributions from each individual spectrum into the output array const MantidVec::const_iterator end = m_dataWS->readY(i).end(); for( ; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) { //find the output bin that each input y-value will fall into, remembering there is one more bin boundary than bins getQBinPlus1(QOut, *QIn, loc); // ignore counts that are out of the output range if ( (loc != QOut.begin()) && (loc != QOut.end()) ) { // the actual Q-bin to add something to const size_t bin = loc - QOut.begin() - 1; PARALLEL_CRITICAL(q1d_counts_sum) { YOut[bin] += *YIn; normSum[bin] += *norms; //these are the errors squared which will be summed and square rooted at the end EOutTo2[bin] += (*EIn)*(*EIn); normError2[bin] += *normETo2s; } } } PARALLEL_CRITICAL(q1d_spectra_map) { progress.report("Computing I(Q)"); // Add up the detector IDs in the output spectrum at workspace index 0 const ISpectrum * inSpec = m_dataWS->getSpectrum(i); ISpectrum * outSpec = outputWS->getSpectrum(0); outSpec->addDetectorIDs( inSpec->getDetectorIDs() ); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS); ws_sumOfCounts->dataX(0) = outputWS->dataX(0); ws_sumOfCounts->dataY(0) = outputWS->dataY(0); for (size_t i = 0; i < outputWS->dataE(0).size(); i++) { ws_sumOfCounts->dataE(0)[i] = sqrt(outputWS->dataE(0)[i]); } MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS); ws_sumOfNormFactors->dataX(0) = outputWS->dataX(0); for (size_t i = 0; i < ws_sumOfNormFactors->dataY(0).size(); i++) { ws_sumOfNormFactors->dataY(0)[i] = normSum[i]; ws_sumOfNormFactors->dataE(0)[i] = sqrt(normError2[i]); } helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors); } progress.report("Normalizing I(Q)"); //finally divide the number of counts in each output Q bin by its weighting normalize(normSum, normError2, YOut, EOutTo2); outputWS->updateSpectraUsingMap(); setProperty("OutputWorkspace",outputWS); }
void TOFSANSResolution::exec() { Workspace2D_sptr iqWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr reducedWS = getProperty("ReducedWorkspace"); EventWorkspace_sptr reducedEventWS = boost::dynamic_pointer_cast<EventWorkspace>(reducedWS); const double min_wl = getProperty("MinWavelength"); const double max_wl = getProperty("MaxWavelength"); double pixel_size_x = getProperty("PixelSizeX"); double pixel_size_y = getProperty("PixelSizeY"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters pixel_size_x /= 1000.0; pixel_size_y /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; wl_resolution = getProperty("DeltaT"); // Although we want the 'ReducedWorkspace' to be an event workspace for this algorithm to do // anything, we don't want the algorithm to 'fail' if it isn't if (!reducedEventWS) { g_log.warning() << "An Event Workspace is needed to compute dQ. Calculation skipped." << std::endl; return; } // Calculate the output binning const std::vector<double> binParams = getProperty("OutputBinning"); // Count histogram for normalization const int xLength = static_cast<int>(iqWS->readX(0).size()); std::vector<double> XNorm(xLength-1, 0.0); // Create workspaces with each component of the resolution for debugging purposes MatrixWorkspace_sptr thetaWS = WorkspaceFactory::Instance().create(iqWS); declareProperty(new WorkspaceProperty<>("ThetaError","",Direction::Output)); setPropertyValue("ThetaError","__"+iqWS->getName()+"_theta_error"); setProperty("ThetaError",thetaWS); thetaWS->setX(0,iqWS->readX(0)); MantidVec& ThetaY = thetaWS->dataY(0); MatrixWorkspace_sptr tofWS = WorkspaceFactory::Instance().create(iqWS); declareProperty(new WorkspaceProperty<>("TOFError","",Direction::Output)); setPropertyValue("TOFError","__"+iqWS->getName()+"_tof_error"); setProperty("TOFError",tofWS); tofWS->setX(0,iqWS->readX(0)); MantidVec& TOFY = tofWS->dataY(0); // Initialize Dq MantidVec& DxOut = iqWS->dataDx(0); for ( int i = 0; i<xLength-1; i++ ) DxOut[i] = 0.0; const V3D samplePos = reducedWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = reducedWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(reducedWS->getNumberHistograms()); Progress progress(this,0.0,1.0,numberOfSpectra); PARALLEL_FOR2(reducedEventWS, iqWS) for (int i = 0; i < numberOfSpectra; i++) { PARALLEL_START_INTERUPT_REGION IDetector_const_sptr det; try { det = reducedEventWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // 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 scattered_flight_path = det->getPos() - samplePos; // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = reducedEventWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin( theta/2.0 ); EventList& el = reducedEventWS->getEventList(i); el.switchTo(WEIGHTED); std::vector<WeightedEvent>::iterator itev; std::vector<WeightedEvent>::iterator itev_end = el.getWeightedEvents().end(); for (itev = el.getWeightedEvents().begin(); itev != itev_end; ++itev) { if ( itev->m_weight != itev->m_weight ) continue; if (std::abs(itev->m_weight) == std::numeric_limits<double>::infinity()) continue; if ( !isEmpty(min_wl) && itev->m_tof < min_wl ) continue; if ( !isEmpty(max_wl) && itev->m_tof > max_wl ) continue; const double q = factor/itev->m_tof; int iq = 0; // Bin assignment depends on whether we have log or linear bins if(binParams[1]>0.0) { iq = (int)floor( (q-binParams[0])/ binParams[1] ); } else { iq = (int)floor(log(q/binParams[0])/log(1.0-binParams[1])); } const double L2 = scattered_flight_path.norm(); const double src_to_pixel = L1+L2; const double dTheta2 = ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*src_to_pixel*src_to_pixel/(L1*L1*L2*L2) + 2.0*(pixel_size_x*pixel_size_x+pixel_size_y*pixel_size_y)/(L2*L2) )/12.0; const double dwl_over_wl = 3.9560*getTOFResolution(itev->m_tof)/(1000.0*(L1+L2)*itev->m_tof); const double dq_over_q = std::sqrt(dTheta2/(theta*theta)+dwl_over_wl*dwl_over_wl); PARALLEL_CRITICAL(iq) /* Write to shared memory - must protect */ if (iq>=0 && iq < xLength-1 && !dq_over_q!=dq_over_q && dq_over_q>0) { DxOut[iq] += q*dq_over_q*itev->m_weight; XNorm[iq] += itev->m_weight; TOFY[iq] += q*std::fabs(dwl_over_wl)*itev->m_weight; ThetaY[iq] += q*std::sqrt(dTheta2)/theta*itev->m_weight; } } progress.report("Computing Q resolution"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Normalize according to the chosen weighting scheme for ( int i = 0; i<xLength-1; i++ ) { if (XNorm[i]>0) { DxOut[i] /= XNorm[i]; TOFY[i] /= XNorm[i]; ThetaY[i] /= XNorm[i]; } } }
/** * Execute the algorithm */ void ExtractMask::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); Geometry::Instrument_const_sptr instr = inputWS->getInstrument(); // convert input to a mask workspace DataObjects::MaskWorkspace_const_sptr inputMaskWS = boost::dynamic_pointer_cast<const DataObjects::MaskWorkspace>(inputWS); bool inputWSIsSpecial = bool(inputMaskWS); if (inputWSIsSpecial) { g_log.notice() << "Input workspace is a MaskWorkspace.\n"; } DataObjects::MaskWorkspace_sptr maskWS; // List masked of detector IDs std::vector<detid_t> detectorList; if (instr) { const int nHist = static_cast<int>(inputWS->getNumberHistograms()); // Create a new workspace for the results, copy from the input to ensure that we copy over the instrument and current masking maskWS = DataObjects::MaskWorkspace_sptr(new DataObjects::MaskWorkspace(inputWS)); maskWS->setTitle(inputWS->getTitle()); Progress prog(this,0.0,1.0,nHist); MantidVecPtr xValues; xValues.access() = MantidVec(1, 0.0); PARALLEL_FOR2(inputWS, maskWS) for( int i = 0; i < nHist; ++i ) { PARALLEL_START_INTERUPT_REGION bool inputIsMasked(false); IDetector_const_sptr inputDet; try { inputDet = inputWS->getDetector(i); if (inputWSIsSpecial) { inputIsMasked = inputMaskWS->isMaskedIndex(i); } // special workspaces can mysteriously have the mask bit set // but only check if we haven't already decided to mask the spectrum if( !inputIsMasked && inputDet->isMasked() ) { inputIsMasked = true; } if (inputIsMasked) { detid_t id = inputDet->getID(); PARALLEL_CRITICAL(name) { detectorList.push_back(id); } } } catch(Kernel::Exception::NotFoundError &) { inputIsMasked = false; } maskWS->setMaskedIndex(i, inputIsMasked); prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Clear all the "masked" bits on the output masked workspace Geometry::ParameterMap & pmap = maskWS->instrumentParameters(); pmap.clearParametersByName("masked"); } else // no instrument { // TODO should fill this in throw std::runtime_error("No instrument");
/** Corrects a spectra for the detector efficiency calculated from detector information Gets the detector information and uses this to calculate its efficiency * @param spectraIn :: index of the spectrum to get the efficiency for * @throw invalid_argument if the shape of a detector is isn't a cylinder aligned along one axis * @throw runtime_error if the SpectraDetectorMap has not been filled * @throw NotFoundError if the detector or its gas pressure or wall thickness were not found */ void DetectorEfficiencyCor::correctForEfficiency(int64_t spectraIn) { IDetector_const_sptr det = m_inputWS->getDetector(spectraIn); if( det->isMonitor() || det->isMasked() ) { return; } MantidVec & yout = m_outputWS->dataY(spectraIn); MantidVec & eout = m_outputWS->dataE(spectraIn); // Need the original values so this is not a reference const MantidVec yValues = m_inputWS->readY(spectraIn); const MantidVec eValues = m_inputWS->readE(spectraIn); // get a pointer to the detectors that created the spectrum const std::set<detid_t> dets = m_inputWS->getSpectrum(spectraIn)->getDetectorIDs(); std::set<detid_t>::const_iterator it = dets.begin(); std::set<detid_t>::const_iterator iend = dets.end(); if ( it == iend ) { throw Exception::NotFoundError("No detectors found", spectraIn); } // Storage for the reciprocal wave vectors that are calculated as the //correction proceeds std::vector<double> oneOverWaveVectors(yValues.size()); for( ; it != iend ; ++it ) { IDetector_const_sptr det_member = m_inputWS->getInstrument()->getDetector(*it); Parameter_sptr par = m_paraMap->get(det_member.get(),"3He(atm)"); if ( !par ) { throw Exception::NotFoundError("3He(atm)", spectraIn); } const double atms = par->value<double>(); par = m_paraMap->get(det_member.get(),"wallT(m)"); if ( !par ) { throw Exception::NotFoundError("wallT(m)", spectraIn); } const double wallThickness = par->value<double>(); double detRadius(0.0); V3D detAxis; getDetectorGeometry(det_member, detRadius, detAxis); // now get the sin of the angle, it's the magnitude of the cross product of unit vector along the detector tube axis and a unit vector directed from the sample to the detector centre V3D vectorFromSample = det_member->getPos() - m_samplePos; vectorFromSample.normalize(); Quat rot = det_member->getRotation(); // rotate the original cylinder object axis to get the detector axis in the actual instrument rot.rotate(detAxis); detAxis.normalize(); // Scalar product is quicker than cross product double cosTheta = detAxis.scalar_prod(vectorFromSample); double sinTheta = std::sqrt(1.0 - cosTheta*cosTheta); // Detector constant const double det_const = g_helium_prefactor*(detRadius - wallThickness)*atms/sinTheta; MantidVec::const_iterator yinItr = yValues.begin(); MantidVec::const_iterator einItr = eValues.begin(); MantidVec::iterator youtItr = yout.begin(); MantidVec::iterator eoutItr = eout.begin(); MantidVec::const_iterator xItr = m_inputWS->readX(spectraIn).begin(); std::vector<double>::iterator wavItr = oneOverWaveVectors.begin(); for( ; youtItr != yout.end(); ++youtItr, ++eoutItr) { if( it == dets.begin() ) { *youtItr = 0.0; *eoutItr = 0.0; *wavItr = calculateOneOverK(*xItr, *(xItr + 1 )); } const double oneOverWave = *wavItr; const double factor = 1.0/detectorEfficiency(det_const*oneOverWave); *youtItr += (*yinItr)*factor; *eoutItr += (*einItr)*factor; ++yinItr; ++einItr; ++xItr; ++wavItr; } } }
void ConvertToDiffractionMDWorkspace::convertEventList(int workspaceIndex, EventList &el) { size_t numEvents = el.getNumberEvents(); DataObjects::MDBoxBase<DataObjects::MDLeanEvent<3>, 3> *box = ws->getBox(); // Get the position of the detector there. const std::set<detid_t> &detectors = el.getDetectorIDs(); if (!detectors.empty()) { // Get the detector (might be a detectorGroup for multiple detectors) // or might return an exception if the detector is not in the instrument // definition IDetector_const_sptr det; try { det = m_inWS->getDetector(workspaceIndex); } catch (Exception::NotFoundError &) { this->failedDetectorLookupCount++; return; } // Vector between the sample and the detector V3D detPos = det->getPos() - samplePos; // Neutron's total travelled distance double distance = detPos.norm() + l1; // Detector direction normalized to 1 V3D detDir = detPos / detPos.norm(); // The direction of momentum transfer in the inelastic convention ki-kf // = input beam direction (normalized to 1) - output beam direction // (normalized to 1) V3D Q_dir_lab_frame = beamDir - detDir; double qSign = -1.0; std::string convention = ConfigService::Instance().getString("Q.convention"); if (convention == "Crystallography") qSign = 1.0; Q_dir_lab_frame *= qSign; // Multiply by the rotation matrix to convert to Q in the sample frame (take // out goniometer rotation) // (or to HKL, if that's what the matrix is) V3D Q_dir = mat * Q_dir_lab_frame; // For speed we extract the components. coord_t Q_dir_x = coord_t(Q_dir.X()); coord_t Q_dir_y = coord_t(Q_dir.Y()); coord_t Q_dir_z = coord_t(Q_dir.Z()); // For lorentz correction, calculate sin(theta))^2 double sin_theta_squared = 0; if (LorentzCorrection) { // Scattering angle = 2 theta = angle between neutron beam direction and // the detector (scattering) direction // The formula for Lorentz Correction is sin(theta), i.e. sin(half the // scattering angle) double theta = detDir.angle(beamDir) / 2.0; sin_theta_squared = sin(theta); sin_theta_squared = sin_theta_squared * sin_theta_squared; // square it } /** Constant that you divide by tof (in usec) to get wavenumber in ang^-1 : * Wavenumber (in ang^-1) = (PhysicalConstants::NeutronMass * distance) / * ((tof (in usec) * 1e-6) * PhysicalConstants::h_bar) * 1e-10; */ const double wavenumber_in_angstrom_times_tof_in_microsec = (PhysicalConstants::NeutronMass * distance * 1e-10) / (1e-6 * PhysicalConstants::h_bar); // PARALLEL_CRITICAL( convert_tester_output ) { std::cout << "Spectrum " << // el.getSpectrumNo() << " beamDir = " << beamDir << " detDir = " << detDir // << " Q_dir = " << Q_dir << " conversion factor " << // wavenumber_in_angstrom_times_tof_in_microsec << std::endl; } // g_log.information() << wi << " : " << el.getNumberEvents() << " events. // Pos is " << detPos << std::endl; // g_log.information() << Q_dir.norm() << " Qdir norm" << std::endl; // This little dance makes the getting vector of events more general (since // you can't overload by return type). typename std::vector<T> *events_ptr; getEventsFrom(el, events_ptr); typename std::vector<T> &events = *events_ptr; // Iterators to start/end auto it = events.begin(); auto it_end = events.end(); for (; it != it_end; it++) { // Get the wavenumber in ang^-1 using the previously calculated constant. coord_t wavenumber = coord_t(wavenumber_in_angstrom_times_tof_in_microsec / it->tof()); // Q vector = K_final - K_initial = wavenumber * (output_direction - // input_direction) coord_t center[3] = {Q_dir_x * wavenumber, Q_dir_y * wavenumber, Q_dir_z * wavenumber}; // Check that the event is within bounds if (center[0] < m_extentsMin[0] || center[0] >= m_extentsMax[0]) continue; if (center[1] < m_extentsMin[1] || center[1] >= m_extentsMax[1]) continue; if (center[2] < m_extentsMin[2] || center[2] >= m_extentsMax[2]) continue; if (LorentzCorrection) { // double lambda = 1.0/wavenumber; // (sin(theta))^2 / wavelength^4 float correct = float(sin_theta_squared * wavenumber * wavenumber * wavenumber * wavenumber); // Push the MDLeanEvent but correct the weight. box->addEvent(MDE(float(it->weight() * correct), float(it->errorSquared() * correct * correct), center)); } else { // Push the MDLeanEvent with the same weight box->addEvent( MDE(float(it->weight()), float(it->errorSquared()), center)); } } // Clear out the EventList to save memory if (ClearInputWorkspace) { // Track how much memory you cleared size_t memoryCleared = el.getMemorySize(); // Clear it now el.clear(); // For Linux with tcmalloc, make sure memory goes back, if you've cleared // 200 Megs MemoryManager::Instance().releaseFreeMemoryIfAccumulated( memoryCleared, static_cast<size_t>(2e8)); } } prog->reportIncrement(numEvents, "Adding Events"); }