/** * @brief InstrumentVisitor::registerDetector * @param detector : IDetector being visited * @return Component index of this component */ size_t InstrumentVisitor::registerDetector(const IDetector &detector) { auto detectorIndex = m_detectorIdToIndexMap->at(detector.getID()); /* Already allocated we just need to index into the inital front-detector * part of the collection. * 1. Guarantee on grouping detectors by type such that the first n * components * are detectors. * 2. Guarantee on ordering such that the * detectorIndex == componentIndex for all detectors. */ // Record the ID -> component index mapping (*m_componentIdToIndexMap)[detector.getComponentID()] = detectorIndex; (*m_componentIds)[detectorIndex] = detector.getComponentID(); m_assemblySortedDetectorIndices->push_back(detectorIndex); (*m_detectorPositions)[detectorIndex] = Kernel::toVector3d(detector.getPos()); (*m_detectorRotations)[detectorIndex] = Kernel::toQuaterniond(detector.getRotation()); (*m_shapes)[detectorIndex] = detector.shape(); (*m_scaleFactors)[detectorIndex] = Kernel::toVector3d(detector.getScaleFactor()); if (m_instrument->isMonitorViaIndex(detectorIndex)) { m_monitorIndices->push_back(detectorIndex); } (*m_names)[detectorIndex] = detector.getName(); clearLegacyParameters(m_pmap, detector); /* Note that positions and rotations for detectors are currently NOT stored! These go into DetectorInfo at present. push_back works for other Component types because Detectors are always come first in the resultant component list forming a contiguous block. */ markAsSourceOrSample(detector.getComponentID(), detectorIndex); // TODO. Optimisation. Cannot have a // detector that is either source or // sample. So delete this. return detectorIndex; }
/** Loads the instrument into a workspace. */ void VesuvioL1ThetaResolution::calculateDetector( const IDetector &detector, std::function<double()> &flatRandomVariateGen, std::vector<double> &l1Values, std::vector<double> &thetaValues) { const int numEvents = getProperty("NumEvents"); l1Values.reserve(numEvents); thetaValues.reserve(numEvents); double sampleWidth = getProperty("SampleWidth"); // If the sample is large fix the width to the approximate beam width if (sampleWidth > 4.0) sampleWidth = 4.0; // Get detector dimensions Geometry::IObject_const_sptr pixelShape = detector.shape(); if (!pixelShape || !pixelShape->hasValidShape()) { throw std::invalid_argument("Detector pixel has no defined shape!"); } Geometry::BoundingBox detBounds = pixelShape->getBoundingBox(); V3D detBoxWidth = detBounds.width(); const double detWidth = detBoxWidth.X() * 100; const double detHeight = detBoxWidth.Y() * 100; g_log.debug() << "detWidth=" << detWidth << "\ndetHeight=" << detHeight << '\n'; // Scattering angle in rad const double theta = m_instWorkspace->detectorTwoTheta(detector); if (theta == 0.0) return; // Final flight path in cm const double l1av = detector.getDistance(*m_sample) * 100.0; const double x0 = l1av * sin(theta); const double y0 = l1av * cos(theta); // Get as many events as defined by NumEvents // This loop is not iteration limited but highly unlikely to ever become // infinate while (l1Values.size() < static_cast<size_t>(numEvents)) { const double xs = -sampleWidth / 2 + sampleWidth * flatRandomVariateGen(); const double ys = 0.0; const double zs = -sampleWidth / 2 + sampleWidth * flatRandomVariateGen(); const double rs = sqrt(pow(xs, 2) + pow(zs, 2)); if (rs <= sampleWidth / 2) { const double a = -detWidth / 2 + detWidth * flatRandomVariateGen(); const double xd = x0 - a * cos(theta); const double yd = y0 + a * sin(theta); const double zd = -detHeight / 2 + detHeight * flatRandomVariateGen(); const double l1 = sqrt(pow(xd - xs, 2) + pow(yd - ys, 2) + pow(zd - zs, 2)); double angle = acos(yd / l1); if (xd < 0.0) angle *= -1; // Convert angle to degrees angle *= 180.0 / M_PI; l1Values.push_back(l1); thetaValues.push_back(angle); } interruption_point(); } }