/** * Set the absolute detector position of a detector * @param instrument :: The instrument that contains the defined detector * @param detID :: Detector ID * @param pos :: new position of Dectector * @param sameParent :: true if detector has same parent as previous detector set here. */ void ApplyCalibration::setDetectorPosition(const Geometry::Instrument_const_sptr & instrument, int detID, V3D pos, bool /*sameParent*/ ) { Geometry::IDetector_const_sptr det = instrument->getDetector(detID); // Then find the corresponding relative position boost::shared_ptr<const Geometry::IComponent> parent = det->getParent(); if (parent) { pos -= parent->getPos(); Quat rot = parent->getRelativeRot(); rot.inverse(); rot.rotate(pos); } boost::shared_ptr<const Geometry::IComponent>grandparent = parent->getParent(); if (grandparent) { Quat rot = grandparent->getRelativeRot(); rot.inverse(); rot.rotate(pos); boost::shared_ptr<const Geometry::IComponent>greatgrandparent = grandparent->getParent(); if (greatgrandparent) { Quat rot2 = greatgrandparent->getRelativeRot(); rot2.inverse(); rot2.rotate(pos); } } // Add a parameter for the new position m_pmap->addV3D(det.get(), "pos", pos); }
void CalculateDIFC::calculate(API::Progress &progress, API::MatrixWorkspace_sptr &outputWs, DataObjects::OffsetsWorkspace_sptr &offsetsWS, double l1, double beamlineNorm, Kernel::V3D &beamline, Kernel::V3D &samplePos, detid2det_map &allDetectors) { SpecialWorkspace2D_sptr localWS = boost::dynamic_pointer_cast<SpecialWorkspace2D>(outputWs); // Now go through all detid2det_map::const_iterator it = allDetectors.begin(); for (; it != allDetectors.end(); ++it) { Geometry::IDetector_const_sptr det = it->second; if ((!det->isMasked()) && (!det->isMonitor())) { const detid_t detID = it->first; double offset = 0.; if (offsetsWS) offset = offsetsWS->getValue(detID, 0.); double difc = Geometry::Instrument::calcConversion( l1, beamline, beamlineNorm, samplePos, det, offset); difc = 1. / difc; // calcConversion gives 1/DIFC localWS->setValue(detID, difc); } progress.report("Calculate DIFC"); } }
/** Method calculates averaged polar coordinates of the detector's group (which may consist of one detector) *@param spDet -- shared pointer to the Mantid Detector *@param Observer -- sample position or the centre of the polar system of coordinates to calculate detector's parameters. *@param Detector -- return Detector class containing averaged polar coordinates of the detector or detector's group in spherical coordinate system with centre at Observer */ void FindDetectorsPar::calcDetPar(const Geometry::IDetector_const_sptr &spDet, const Kernel::V3D &Observer, DetParameters &Detector) { // get number of basic detectors within the composit detector size_t nDetectors = spDet->nDets(); // define summator AvrgDetector detSum; // do we want spherical or linear box sizes? detSum.setUseSpherical(!m_SizesAreLinear); if (nDetectors == 1) { detSum.addDetInfo(spDet, Observer); } else { // access contributing detectors; Geometry::DetectorGroup_const_sptr spDetGroup = boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(spDet); if (!spDetGroup) { g_log.error() << "calc_cylDetPar: can not downcast IDetector_sptr to " "detector group for det->ID: " << spDet->getID() << std::endl; throw(std::bad_cast()); } auto detectors = spDetGroup->getDetectors(); auto it = detectors.begin(); auto it_end = detectors.end(); for (; it != it_end; it++) { detSum.addDetInfo(*it, Observer); } } // calculate averages and return the detector parameters detSum.returnAvrgDetPar(Detector); }
/** Retrieves the detector postion for a given spectrum * @param index :: The workspace index of the spectrum * @param l1 :: Returns the source-sample distance * @param l2 :: Returns the sample-detector distance * @param twoTheta :: Returns the detector's scattering angle */ void RemoveBins::calculateDetectorPosition(const int& index, double& l1, double& l2, double& twoTheta) { // Get a pointer to the instrument contained in the workspace Geometry::Instrument_const_sptr instrument = m_inputWorkspace->getInstrument(); // Get the distance between the source and the sample (assume in metres) Geometry::IObjComponent_const_sptr sample = instrument->getSample(); // Check for valid instrument if (sample == NULL) { throw Exception::InstrumentDefinitionError("Instrument not sufficiently defined: failed to get sample"); } l1 = instrument->getSource()->getDistance(*sample); Geometry::IDetector_const_sptr det = m_inputWorkspace->getDetector(index); // Get the sample-detector distance for this detector (in metres) if ( ! det->isMonitor() ) { l2 = det->getDistance(*sample); // The scattering angle for this detector (in radians). twoTheta = m_inputWorkspace->detectorTwoTheta(det); } else // If this is a monitor then make l1+l2 = source-detector distance and twoTheta=0 { l2 = det->getDistance(*(instrument->getSource())); l2 = l2 - l1; twoTheta = 0.0; } g_log.debug() << "Detector for index " << index << " has L1+L2=" << l1+l2 << " & 2theta= " << twoTheta << std::endl; return; }
void CalculateDIFC::calculate() { Instrument_const_sptr instrument = m_inputWS->getInstrument(); SpecialWorkspace2D_sptr localWS = boost::dynamic_pointer_cast<SpecialWorkspace2D>(m_outputWS); double l1; Kernel::V3D beamline, samplePos; double beamline_norm; instrument->getInstrumentParameters(l1, beamline, beamline_norm, samplePos); // To get all the detector ID's detid2det_map allDetectors; instrument->getDetectors(allDetectors); // Now go through all detid2det_map::const_iterator it = allDetectors.begin(); for (; it != allDetectors.end(); ++it) { Geometry::IDetector_const_sptr det = it->second; if ((!det->isMasked()) && (!det->isMonitor())) { const detid_t detID = it->first; double offset = 0.; if (m_offsetsWS) offset = m_offsetsWS->getValue(detID, 0.); double difc = Geometry::Instrument::calcConversion( l1, beamline, beamline_norm, samplePos, det, offset); difc = 1. / difc; // calcConversion gives 1/DIFC localWS->setValue(detID, difc); } } }
void FindDetectorsPar::populate_values_from_file( const API::MatrixWorkspace_sptr &inputWS) { size_t nHist = inputWS->getNumberHistograms(); if (this->current_ASCII_file.Type == PAR_type) { // in this case data in azimuthal width and polar width are in fact real // sizes in meters; have to transform it in into angular values for (size_t i = 0; i < nHist; i++) { azimuthalWidth[i] = atan2(azimuthalWidth[i], secondaryFlightpath[i]) * rad2deg; polarWidth[i] = atan2(polarWidth[i], secondaryFlightpath[i]) * rad2deg; } m_SizesAreLinear = false; } else { Geometry::IComponent_const_sptr sample = inputWS->getInstrument()->getSample(); secondaryFlightpath.resize(nHist); // Loop over the spectra for (size_t i = 0; i < nHist; i++) { Geometry::IDetector_const_sptr spDet; try { spDet = inputWS->getDetector(i); } catch (Kernel::Exception::NotFoundError &) { continue; } // Check that we aren't writing a monitor... if (spDet->isMonitor()) continue; /// this is the only value, which is not defined in phx file, so we /// calculate it secondaryFlightpath[i] = spDet->getDistance(*sample); } } }
/** Makes sure that the input properties are set correctly * @param inputWorkspace The input workspace * @throw std::runtime_error If the properties are invalid */ void NormaliseToMonitor::checkProperties(API::MatrixWorkspace_sptr inputWorkspace) { // Check where the monitor spectrum should come from Property* monSpec = getProperty("MonitorSpectrum"); Property* monWS = getProperty("MonitorWorkspace"); Property* monID = getProperty("MonitorID"); // Is the monitor spectrum within the main input workspace const bool inWS = !monSpec->isDefault(); // Or is it in a separate workspace bool sepWS = !monWS->isDefault(); // or monitor ID bool monIDs = !monID->isDefault(); // something has to be set if ( !inWS && !sepWS && !monIDs) { const std::string mess("Neither the MonitorSpectrum, nor the MonitorID or the MonitorWorkspace property has been set"); g_log.error()<<mess<<std::endl; throw std::runtime_error(mess); } // One and only one of these properties should have been set // input from separate workspace is owerwritten by monitor spectrum if ( inWS && sepWS ){ g_log.information("Both input workspace MonitorSpectrum number and monitor workspace are specified. Ignoring Monitor Workspace"); sepWS = false; } // input from detector ID is rejected in favour of monitor sp if ( inWS && monIDs ){ g_log.information("Both input workspace MonitorSpectrum number and detector ID are specified. Ignoring Detector ID"); monIDs = false; } // separate ws takes over detectorID (this logic is dublicated within getInWSMonitorSpectrum) if ( sepWS && monIDs ){ g_log.information("Both input MonitorWorkspace and detector ID are specified. Ignoring Detector ID"); } // Do a check for common binning and store m_commonBins = API::WorkspaceHelpers::commonBoundaries(inputWorkspace); int spec_num(-1); // Check the monitor spectrum or workspace and extract into new workspace m_monitor = sepWS ? this->getMonitorWorkspace(inputWorkspace,spec_num) : this->getInWSMonitorSpectrum(inputWorkspace,spec_num) ; // Check that the 'monitor' spectrum actually relates to a monitor - warn if not try { Geometry::IDetector_const_sptr mon = m_monitor->getDetector(0); if ( !mon->isMonitor() ) { g_log.warning()<<"The spectrum N: "<<spec_num<<" in MonitorWorkspace does not refer to a monitor.\n" <<"Continuing with normalisation regardless."; } } catch (Kernel::Exception::NotFoundError &) { g_log.warning("Unable to check if the spectrum provided relates to a monitor - " "the instrument is not fully specified.\n" "Continuing with normalisation regardless."); } }
/** Calculates the total flightpath for the given detector. * This is L1+L2 normally, but is the source-detector distance for a monitor. * @param spectrum :: The workspace index * @param L1 :: The primary flightpath * @param isMonitor :: Output: true is this detector is a monitor * @return The flightpath (Ld) for the detector linked to spectrum * @throw Kernel::Exception::InstrumentDefinitionError if the detector position * can't be obtained */ double UnwrapMonitor::calculateFlightpath(const int &spectrum, const double &L1, bool &isMonitor) const { double Ld = -1.0; try { // Get the detector object for this histogram Geometry::IDetector_const_sptr det = m_inputWS->getDetector(spectrum); // Get the sample-detector distance for this detector (or source-detector if // a monitor) // This is the total flightpath isMonitor = det->isMonitor(); // Get the L2 distance if this detector is not a monitor if (!isMonitor) { double L2 = det->getDistance(*(m_inputWS->getInstrument()->getSample())); Ld = L1 + L2; } // If it is a monitor, then the flightpath is the distance to the source else { Ld = det->getDistance(*(m_inputWS->getInstrument()->getSource())); } } catch (Exception::NotFoundError &) { // If the detector information is missing, return a negative number } return Ld; }
/** * Corrects a spectra for the detector efficiency calculated from detector * information. Gets the detector information and uses this to calculate its * efficiency * @param spectraIndex :: 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 He3TubeEfficiency::correctForEfficiency(std::size_t spectraIndex) { Geometry::IDetector_const_sptr det = this->inputWS->getDetector(spectraIndex); if( det->isMonitor() || det->isMasked() ) { return; } const double exp_constant = this->calculateExponential(spectraIndex, det); const double scale = this->getProperty("ScaleFactor"); Mantid::MantidVec &yout = this->outputWS->dataY(spectraIndex); Mantid::MantidVec &eout = this->outputWS->dataE(spectraIndex); // Need the original values so this is not a reference const Mantid::MantidVec yValues = this->inputWS->readY(spectraIndex); const Mantid::MantidVec eValues = this->inputWS->readE(spectraIndex); std::vector<double>::const_iterator yinItr = yValues.begin(); std::vector<double>::const_iterator einItr = eValues.begin(); Mantid::MantidVec::const_iterator xItr = this->inputWS->readX(spectraIndex).begin(); Mantid::MantidVec::iterator youtItr = yout.begin(); Mantid::MantidVec::iterator eoutItr = eout.begin(); for( ; youtItr != yout.end(); ++youtItr, ++eoutItr) { const double wavelength = (*xItr + *(xItr + 1)) / 2.0; const double effcorr = this->detectorEfficiency(exp_constant * wavelength, scale); *youtItr = (*yinItr) * effcorr; *eoutItr = (*einItr) * effcorr; ++yinItr; ++einItr; ++xItr; } return; }
/** Purpose: Process mask workspace * Requirement: m_maskWS is not None * Guarantees: an array will be set up for masked detectors * @brief IntegratePeaksCWSD::processMaskWorkspace * @param maskws */ std::vector<detid_t> IntegratePeaksCWSD::processMaskWorkspace( DataObjects::MaskWorkspace_const_sptr maskws) { std::vector<detid_t> vecMaskedDetID; // Add the detector IDs of all masked detector to a vector size_t numspec = maskws->getNumberHistograms(); for (size_t iws = 0; iws < numspec; ++iws) { Geometry::IDetector_const_sptr detector = maskws->getDetector(iws); const MantidVec &vecY = maskws->readY(iws); if (vecY[0] > 0.1) { // vecY[] > 0 is masked. det->isMasked() may not be reliable. detid_t detid = detector->getID(); vecMaskedDetID.push_back(detid); } } // Sort the vector for future lookup if (vecMaskedDetID.size() > 1) std::sort(vecMaskedDetID.begin(), vecMaskedDetID.end()); g_log.warning() << "[DB] There are " << vecMaskedDetID.size() << " detectors masked." << "\n"; return vecMaskedDetID; }
int LoadIsawPeaks::findPixelID(Instrument_const_sptr inst, std::string bankName, int col, int row) { boost::shared_ptr<const IComponent> parent = inst->getComponentByName(bankName); if (parent->type().compare("RectangularDetector") == 0) { boost::shared_ptr<const RectangularDetector> RDet = boost::dynamic_pointer_cast< const RectangularDetector>(parent); boost::shared_ptr<Detector> pixel = RDet->getAtXY(col, row); return pixel->getID(); } else { std::vector<Geometry::IComponent_const_sptr> children; boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent); asmb->getChildren(children, false); int col0 = (col%2==0 ? col/2+75 : (col-1)/2); boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[col0]); std::vector<Geometry::IComponent_const_sptr> grandchildren; asmb2->getChildren(grandchildren,false); Geometry::IComponent_const_sptr first = grandchildren[row-1]; Geometry::IDetector_const_sptr det = boost::dynamic_pointer_cast<const Geometry::IDetector>(first); return det->getID(); } }
/** Extract a component's detectors and return it within detectors array * It is a generalized version of bankToDetectors() * * @param componentnames -- vector of component names to process * @param detectors -- vector of detector ids, which belongs to components *provided as input. */ void LoadMask::componentToDetectors( const std::vector<std::string> &componentnames, std::vector<detid_t> &detectors) { Geometry::Instrument_const_sptr minstrument = m_maskWS->getInstrument(); for (auto &componentname : componentnames) { g_log.debug() << "Component name = " << componentname << '\n'; // a) get component Geometry::IComponent_const_sptr component = minstrument->getComponentByName(componentname); if (component) g_log.debug() << "Component ID = " << component->getComponentID() << '\n'; else { // A non-exiting component. Ignore g_log.warning() << "Component " << componentname << " does not exist!\n"; continue; } // b) component -> component assembly --> children (more than detectors) boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(component); std::vector<Geometry::IComponent_const_sptr> children; asmb->getChildren(children, true); g_log.debug() << "Number of Children = " << children.size() << '\n'; size_t numdets(0); detid_t id_min(std::numeric_limits<Mantid::detid_t>::max()); detid_t id_max(0); for (const auto &child : children) { // c) convert component to detector Geometry::IDetector_const_sptr det = boost::dynamic_pointer_cast<const Geometry::IDetector>(child); if (det) { detid_t detid = det->getID(); detectors.push_back(detid); numdets++; if (detid < id_min) id_min = detid; if (detid > id_max) id_max = detid; } } g_log.debug() << "Number of Detectors in Children = " << numdets << " Range = " << id_min << ", " << id_max << '\n'; } // for component }
/** Update the shape cache if necessary * @param det :: a pointer to the detector to query * @param detRadius :: An output parameter that contains the detector radius * @param detAxis :: An output parameter that contains the detector axis vector */ void DetectorEfficiencyCor::getDetectorGeometry(const Geometry::IDetector_const_sptr & det, double & detRadius, V3D & detAxis) { boost::shared_ptr<const Object> shape_sptr = det->shape(); if(!shape_sptr->hasValidShape()) { throw Exception::NotFoundError("Shape", "Detector has no shape"); } std::map<const Geometry::Object *, std::pair<double, Kernel::V3D> >::const_iterator it = m_shapeCache.find(shape_sptr.get()); if( it == m_shapeCache.end() ) { double xDist = distToSurface( V3D(DIST_TO_UNIVERSE_EDGE, 0, 0), shape_sptr.get() ); double zDist = distToSurface( V3D(0, 0, DIST_TO_UNIVERSE_EDGE), shape_sptr.get() ); if ( std::abs(zDist - xDist) < 1e-8 ) { detRadius = zDist/2.0; detAxis = V3D(0,1,0); // assume radi in z and x and the axis is in the y PARALLEL_CRITICAL(deteff_shapecachea) { m_shapeCache.insert(std::pair<const Object *,std::pair<double, V3D> >(shape_sptr.get(), std::pair<double, V3D>(detRadius, detAxis))); } return; }
/** * Update the shape cache if necessary * @param det :: a pointer to the detector to query * @param detRadius :: An output parameter that contains the detector radius * @param detAxis :: An output parameter that contains the detector axis vector */ void He3TubeEfficiency::getDetectorGeometry(\ Geometry::IDetector_const_sptr det, double & detRadius, Kernel::V3D & detAxis) { boost::shared_ptr<const Geometry::Object> shape_sptr = det->shape(); std::map<const Geometry::Object *, std::pair<double, Kernel::V3D> >::const_iterator it = this->shapeCache.find(shape_sptr.get()); if( it == this->shapeCache.end() ) { double xDist = distToSurface( Kernel::V3D(DIST_TO_UNIVERSE_EDGE, 0, 0), shape_sptr.get() ); double zDist = distToSurface( Kernel::V3D(0, 0, DIST_TO_UNIVERSE_EDGE), shape_sptr.get() ); if ( std::abs(zDist - xDist) < 1e-8 ) { detRadius = zDist / 2.0; detAxis = Kernel::V3D(0, 1, 0); // assume radii in z and x and the axis is in the y PARALLEL_CRITICAL(deteff_shapecachea) { this->shapeCache.insert(std::pair<const Geometry::Object *, std::pair<double, Kernel::V3D> >(shape_sptr.get(), std::pair<double, Kernel::V3D>(detRadius, detAxis))); } return; }
/// helper function to preprocess the detectors directions void ConvertToQ3DdE::process_detectors_positions(const DataObjects::Workspace2D_const_sptr inputWS) { const size_t nHist = inputWS->getNumberHistograms(); det_loc.det_dir.resize(nHist); det_loc.det_id.resize(nHist); // Loop over the spectra size_t ic(0); for (size_t i = 0; i < nHist; i++){ Geometry::IDetector_const_sptr spDet; try{ spDet= inputWS->getDetector(i); }catch(Kernel::Exception::NotFoundError &){ continue; } // Check that we aren't dealing with monitor... if (spDet->isMonitor())continue; det_loc.det_id[ic] = spDet->getID(); // dist = spDet->getDistance(*sample); double polar = inputWS->detectorTwoTheta(spDet); double azim = spDet->getPhi(); double sPhi=sin(polar); double ez = cos(polar); double ex = sPhi*cos(azim); double ey = sPhi*sin(azim); det_loc.det_dir[ic].setX(ex); det_loc.det_dir[ic].setY(ey); det_loc.det_dir[ic].setZ(ez); ic++; } // if(ic<nHist){ det_loc.det_dir.resize(ic); det_loc.det_id.resize(ic); } }
/** * Set the new detector position given the r,theta and phi. * @param det :: A pointer to the detector * @param l2 :: A single l2 * @param theta :: A single theta * @param phi :: A single phi */ void UpdateInstrumentFromFile::setDetectorPosition(const Geometry::IDetector_const_sptr & det, const float l2, const float theta, const float phi) { if( m_ignoreMonitors && det->isMonitor() ) return; Geometry::ParameterMap & pmap = m_workspace->instrumentParameters(); Kernel::V3D pos; if (!m_ignorePhi) { pos.spherical(l2, theta, phi); } else { double r,t,p; det->getPos().getSpherical(r,t,p); pos.spherical(l2, theta, p); } Geometry::ComponentHelper::moveComponent(*det, pmap, pos, Geometry::ComponentHelper::Absolute); }
std::pair<double, double> LoadILLSANS::calculateQMaxQMin() { double min = std::numeric_limits<double>::max(), max = std::numeric_limits<double>::min(); g_log.debug("Calculating Qmin Qmax..."); std::size_t nHist = m_localWorkspace->getNumberHistograms(); for (std::size_t i = 0; i < nHist; ++i) { Geometry::IDetector_const_sptr det = m_localWorkspace->getDetector(i); if (!det->isMonitor()) { const MantidVec &lambdaBinning = m_localWorkspace->readX(i); Kernel::V3D detPos = det->getPos(); double r, theta, phi; detPos.getSpherical(r, theta, phi); double v1 = calculateQ(*(lambdaBinning.begin()), theta); double v2 = calculateQ(*(lambdaBinning.end() - 1), theta); // std::cout << "i=" << i << " theta="<<theta << " lambda_i=" << // *(lambdaBinning.begin()) << " lambda_f=" << *(lambdaBinning.end()-1) << // " v1=" << v1 << " v2=" << v2 << '\n'; if (i == 0) { min = v1; max = v1; } if (v1 < min) { min = v1; } if (v2 < min) { min = v2; } if (v1 > max) { max = v1; } if (v2 > max) { max = v2; } } else g_log.debug() << "Detector " << i << " is a Monitor : " << det->getID() << '\n'; } g_log.debug() << "Calculating Qmin Qmax. Done : [" << min << "," << max << "]\n"; return std::pair<double, double>(min, max); }
/** * * @param pmap A reference to the ParameterMap instance to update * @param det A pointer to the detector whose parameters should be updated * @param l2 The new l2 value * @param theta The new theta value * @param phi The new phi value * @param delay The new delay time * @param pressure The new pressure value * @param thickness The new thickness value */ void LoadDetectorInfo::updateParameterMap(Geometry::ParameterMap & pmap, const Geometry::IDetector_const_sptr & det, const double l2, const double theta, const double phi, const double delay, const double pressure, const double thickness) const { // store detector params that are different to instrument level if(fabs(delay - m_instDelta) > 1e-06) pmap.addDouble(det->getComponentID(), DELAY_PARAM, delay); if(fabs(pressure - m_instPressure) > 1e-06) pmap.addDouble(det->getComponentID(), PRESSURE_PARAM, pressure); if(fabs(thickness - m_instThickness) > 1e-06) pmap.addDouble(det->getComponentID(), THICKNESS_PARAM, thickness); // move if(m_moveDets) { V3D newPos; newPos.spherical(l2, theta, phi); // The sample position may not be at 0,0,0 newPos += m_samplePos; ComponentHelper::moveComponent(*det, pmap, newPos, ComponentHelper::Absolute); } }
/** * This function calculates the exponential contribution to the He3 tube * efficiency. * @param spectraIndex :: the current index to calculate * @param idet :: the current detector pointer * @throw out_of_range if twice tube thickness is greater than tube diameter * @return the exponential contribution for the given detector */ double He3TubeEfficiency::calculateExponential(std::size_t spectraIndex, Geometry::IDetector_const_sptr idet) { // Get the parameters for the current associated tube double pressure = this->getParameter("TubePressure", spectraIndex, "tube_pressure", idet); double tubethickness = this->getParameter("TubeThickness", spectraIndex, "tube_thickness", idet); double temperature = this->getParameter("TubeTemperature", spectraIndex, "tube_temperature", idet); double detRadius(0.0); Kernel::V3D detAxis; this->getDetectorGeometry(idet, detRadius, detAxis); double detDiameter = 2.0 * detRadius; double twiceTubeThickness = 2.0 * tubethickness; // 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 center Kernel::V3D vectorFromSample = idet->getPos() - this->samplePos; vectorFromSample.normalize(); Kernel::Quat rot = idet->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); const double straight_path = detDiameter - twiceTubeThickness; if (std::fabs(straight_path - 0.0) < TOL) { throw std::out_of_range("Twice tube thickness cannot be greater than "\ "or equal to the tube diameter"); } const double pathlength = straight_path / sinTheta; return EXP_SCALAR_CONST * (pressure / temperature) * pathlength; }
/** Method updates the column, which describes if current detector/spectra is masked It is used if one tries to process multiple workspaces obtained from a series of experiments where the masked detectors can change */ void PreprocessDetectorsToMD::updateMasksState( const API::MatrixWorkspace_const_sptr &inputWS, DataObjects::TableWorkspace_sptr &targWS) { int *pMasksArray = targWS->getColDataArray<int>("detMask"); if (!pMasksArray) throw std::invalid_argument( "target workspace " + targWS->getName() + " does not have defined masks column to update"); size_t nHist = targWS->rowCount(); const size_t nRows = inputWS->getNumberHistograms(); if (nHist != nRows) throw std::invalid_argument( " source workspace " + inputWS->getName() + " and target workspace " + targWS->getName() + " are inconsistent as have different numner of detectors"); uint32_t liveDetectorsCount(0); for (size_t i = 0; i < nHist; i++) { // get detector or detector group which corresponds to the spectra i Geometry::IDetector_const_sptr spDet; try { spDet = inputWS->getDetector(i); } catch (Kernel::Exception::NotFoundError &) { continue; } // Check that we aren't dealing with monitor... if (spDet->isMonitor()) continue; // if masked detectors state is not used, masked detectors just ignored; bool maskDetector = spDet->isMasked(); *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0; liveDetectorsCount++; } }
/** * If the InstrumentParameter property is set then it attempts to retrieve the parameter * from the component, else it returns the value of the Factor property * @param inputWS A pointer to the input workspace * @param index The current index to inspect * @return Value for the scale factor */ double ScaleX::getScaleFactor(const API::MatrixWorkspace_const_sptr & inputWS, const size_t index) { if(m_parname.empty()) return m_algFactor; // Try and get factor from component. If we see a DetectorGroup use this will use the first component Geometry::IDetector_const_sptr det; auto inst = inputWS->getInstrument(); auto *spec = inputWS->getSpectrum(index); const auto & ids = spec->getDetectorIDs(); const size_t ndets(ids.size()); if(ndets > 0) { try { det = inst->getDetector(*ids.begin()); } catch(Exception::NotFoundError&) { return 0.0; } } else return 0.0; const auto & pmap = inputWS->constInstrumentParameters(); auto par = pmap.getRecursive(det->getComponentID(), m_parname); if(par) { if(!m_combine) return par->value<double>(); else return m_binOp(m_algFactor,par->value<double>()); } else { std::ostringstream os; os << "Spectrum at index '" << index << "' has no parameter named '" << m_parname << "'\n"; throw std::runtime_error(os.str()); } }
/**Calculates the distance a neutron coming from the sample will have deviated * from a * straight tragetory before hitting a detector. If calling this function many * times * for the same detector you can call this function once, with waveLength=1, and * use * the fact drop is proportional to wave length squared .This function has no * knowledge * of which axis is vertical for a given instrument * @param ws :: workspace * @param det :: the detector that the neutron entered * @param waveLength :: the neutrons wave length in meters * @param extraLength :: additional length * @return the deviation in meters */ double GravitySANSHelper::gravitationalDrop(API::MatrixWorkspace_const_sptr ws, Geometry::IDetector_const_sptr det, const double waveLength, const double extraLength) const { using namespace PhysicalConstants; /// Pre-factor in gravity calculation: gm^2/2h^2 static const double gm2_OVER_2h2 = g * NeutronMass * NeutronMass / (2.0 * h * h); const V3D samplePos = ws->getInstrument()->getSample()->getPos(); const double pathLength = det->getPos().distance(samplePos) + extraLength; // Want L2 (sample-pixel distance) squared, times the prefactor g^2/h^2 const double L2 = gm2_OVER_2h2 * std::pow(pathLength, 2); return waveLength * waveLength * L2; }
/** * Return the efixed for this detector * @param det :: A pointer to a detector object * @return The value of efixed */ double SofQW3::getEFixed(Geometry::IDetector_const_sptr det) const { double efixed(0.0); if( m_emode == 1 ) //Direct { efixed = m_efixed; } else // Indirect { if( m_efixedGiven ) efixed = m_efixed; // user provided a value else { std::vector<double> param = det->getNumberParameter("EFixed"); if( param.empty() ) throw std::runtime_error("Cannot find EFixed parameter for component \"" + det->getName() + "\". This is required in indirect mode. Please check the IDF contains these values."); efixed = param[0]; } } return efixed; }
/**Calculates the distance a neutron coming from the sample will have deviated * from a * straight tragetory before hitting a detector. If calling this function many * times * for the same detector you can call this function once, with waveLength=1, and * use * the fact drop is proportional to wave length squared .This function has no * knowledge * of which axis is vertical for a given instrument * @param ws :: workspace * @param det :: the detector that the neutron entered * @param waveLength :: the neutrons wave length in meters * @param extraLength :: additional length * @return the deviation in meters */ double GravitySANSHelper::gravitationalDrop(API::MatrixWorkspace_const_sptr ws, Geometry::IDetector_const_sptr det, const double waveLength, const double extraLength) const { using namespace PhysicalConstants; /// Pre-factor in gravity calculation: gm^2/2h^2 static const double gm2_OVER_2h2 = g * NeutronMass * NeutronMass / (2.0 * h * h); const V3D samplePos = ws->getInstrument()->getSample()->getPos(); // Perform a path length correction if an Lextra is specified. // The correction is Lcorr^2 = (L + Lextra)^2 -(LExtra)^2 const auto pathLengthWithExtraLength = det->getPos().distance(samplePos) + extraLength; const auto pathLengthSquared = std::pow(pathLengthWithExtraLength, 2) - std::pow(extraLength, 2); // Want L2 (sample-pixel distance) squared, times the prefactor g^2/h^2 const double L2 = gm2_OVER_2h2 * pathLengthSquared; return waveLength * waveLength * L2; }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroupsEvent( DataObjects::EventWorkspace_const_sptr inputWS, DataObjects::EventWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum EventList & outEL = outputWS->getEventList(outIndex); // The spectrum number of the group is the key outEL.setSpectrumNo(it->first); // Start fresh with no detector IDs outEL.clearDetectorIDs(); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; const EventList & fromEL=inputWS->getEventList(originalWI); //Add the event lists with the operator outEL += fromEL; // detectors to add to the output spectrum outEL.addDetectorIDs(fromEL.getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->doneAddingEventLists(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroups( API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum ISpectrum * outSpec = outputWS->getSpectrum(outIndex); // The spectrum number of the group is the key outSpec->setSpectrumNo(it->first); // Start fresh with no detector IDs outSpec->clearDetectorIDs(); // Copy over X data from first spectrum, the bin boundaries for all spectra are assumed to be the same here outSpec->dataX() = inputWS->readX(0); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; // detectors to add to firstSpecNum const ISpectrum * fromSpectrum = inputWS->getSpectrum(originalWI); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = outSpec->dataY(); MantidVec::iterator fYit; MantidVec::iterator fEit = outSpec->dataE().begin(); MantidVec::const_iterator Yit = fromSpectrum->dataY().begin(); MantidVec::const_iterator Eit = fromSpectrum->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = std::sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // detectors to add to the output spectrum outSpec->addDetectorIDs(fromSpectrum->getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** method to cacluate the detectors parameters and add them to the detectors *averages *@param spDet -- shared pointer to the Mantid Detector *@param Observer -- sample position or the centre of the polar system of *coordinates to calculate detector's parameters. */ void AvrgDetector::addDetInfo(const Geometry::IDetector_const_sptr &spDet, const Kernel::V3D &Observer) { m_nComponents++; Kernel::V3D detPos = spDet->getPos(); Kernel::V3D toDet = (detPos - Observer); double dist2Det, Polar, Azimut, ringPolar, ringAzim; // identify the detector' position in the beam coordinate system: toDet.getSpherical(dist2Det, Polar, Azimut); if (m_nComponents <= 1) { m_FlightPathSum = dist2Det; m_PolarSum = Polar; m_AzimutSum = Azimut; m_AzimBase = Polar; m_PolarBase = Azimut; ringPolar = Polar; ringAzim = Azimut; } else { ringPolar = nearAngle(m_AzimBase, Polar); ringAzim = nearAngle(m_PolarBase, Azimut); m_FlightPathSum += dist2Det; m_PolarSum += ringPolar; m_AzimutSum += ringAzim; } // centre of the azimuthal ring (the ring detectors form around the beam) Kernel::V3D ringCentre(0, 0, toDet.Z()); // Get the bounding box Geometry::BoundingBox bbox; std::vector<Kernel::V3D> coord(3); Kernel::V3D er(0, 1, 0), e_th, ez(0, 0, 1); // ez along beamline, which is always oz; if (dist2Det) er = toDet / dist2Det; // direction to the detector Kernel::V3D e_tg = er.cross_prod(ez); // tangential to the ring and anticloakwise; e_tg.normalize(); // make orthogonal -- projections are calculated in this coordinate system ez = e_tg.cross_prod(er); coord[0] = er; // new X coord[1] = ez; // new y coord[2] = e_tg; // new z bbox.setBoxAlignment(ringCentre, coord); spDet->getBoundingBox(bbox); // linear extensions of the bounding box orientied tangentially to the equal // scattering angle circle double azimMin = bbox.zMin(); double azimMax = bbox.zMax(); double polarMin = bbox.yMin(); // bounding box has been rotated according to // coord above, so z is along e_tg double polarMax = bbox.yMax(); if (m_useSphericalSizes) { if (dist2Det == 0) dist2Det = 1; // convert to angular units double polarHalfSize = rad2deg * atan2(0.5 * (polarMax - polarMin), dist2Det); double azimHalfSize = rad2deg * atan2(0.5 * (azimMax - azimMin), dist2Det); polarMin = ringPolar - polarHalfSize; polarMax = ringPolar + polarHalfSize; azimMin = ringAzim - azimHalfSize; azimMax = ringAzim + azimHalfSize; } if (m_AzimMin > azimMin) m_AzimMin = azimMin; if (m_AzimMax < azimMax) m_AzimMax = azimMax; if (m_PolarMin > polarMin) m_PolarMin = polarMin; if (m_PolarMax < polarMax) m_PolarMax = polarMax; }
/** Executes the algorithm *@param localworkspace :: the input workspace *@param indices :: set of indices to sum up */ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace, std::set<int> &indices) { // Make a brand new EventWorkspace EventWorkspace_sptr outputWorkspace = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", 1, 2, 1)); // Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent(localworkspace, outputWorkspace, true); Progress progress(this, 0, 1, indices.size()); // Get the pointer to the output event list EventList &outEL = outputWorkspace->getEventList(0); outEL.setSpectrumNo(m_outSpecId); outEL.clearDetectorIDs(); // Loop over spectra std::set<int>::iterator it; size_t numSpectra(0); size_t numMasked(0); size_t numZeros(0); // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = indices.begin(); it != indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Add the event lists with the operator const EventList &tOutEL = localworkspace->getEventList(i); if (tOutEL.empty()) { ++numZeros; } outEL += tOutEL; progress.report(); } // Set all X bins on the output cow_ptr<MantidVec> XValues; XValues.access() = localworkspace->readX(0); outputWorkspace->setAllX(XValues); outputWorkspace->mutableRun().addProperty("NumAllSpectra", int(numSpectra), "", true); outputWorkspace->mutableRun().addProperty("NumMaskSpectra", int(numMasked), "", true); outputWorkspace->mutableRun().addProperty("NumZeroSpectra", int(numZeros), "", true); // Assign it to the output workspace property setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(outputWorkspace)); }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors ISpectrum *outSpec = outputWorkspace->getSpectrum(0); MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec &FracSum = outWS->dataF(0); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = m_indices.begin(); it != m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); const MantidVec &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }
/** * This function deals with the logic necessary for summing a Workspace2D. * @param localworkspace The input workspace for summing. * @param outSpec The spectrum for the summed output. * @param progress The progress indicator. * @param numSpectra The number of spectra contributed to the sum. * @param numMasked The spectra dropped from the summations because they are * masked. * @param numZeros The number of zero bins in histogram workspace or empty * spectra for event workspace. */ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, ISpectrum *outSpec, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get references to the output workspaces's data vectors MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = this->m_indices.begin(); it != this->m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= this->m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] / errsq; } else { nZeros[k]++; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k]; YError[k] += YErrors[k] * YErrors[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } }