/** * Return the reference 2theta angle and the corresponding horizon angle. * * @param spectrumInfo [in] :: a spectrum info of the input workspace. * @return :: the reference angle struct */ ReflectometrySumInQ::Angles ReflectometrySumInQ::referenceAngles(const API::SpectrumInfo &spectrumInfo) { Angles a; const double beamCentre = getProperty(Prop::BEAM_CENTRE); const bool isFlat = getProperty(Prop::IS_FLAT_SAMPLE); if (isFlat) { a.horizon = centreTwoTheta(beamCentre, spectrumInfo) / 2.; } else { a.horizon = 0.; } a.referenceWSIndex = static_cast<size_t>(beamCentre); a.twoTheta = spectrumInfo.twoTheta(a.referenceWSIndex); a.delta = a.twoTheta - a.horizon; return a; }
void ConvertToDiffractionMDWorkspace::convertEventList( int workspaceIndex, const API::SpectrumInfo &specInfo, EventList &el) { size_t numEvents = el.getNumberEvents(); DataObjects::MDBoxBase<DataObjects::MDLeanEvent<3>, 3> *box = ws->getBox(); // Get the position of the detector there. const auto &detectors = el.getDetectorIDs(); if (!detectors.empty()) { // Check if a detector is located at this workspace index, returns // immediately if one is not found. if (!specInfo.hasDetectors(workspaceIndex)) { this->failedDetectorLookupCount++; return; } // Neutron's total travelled distance double distance = l1 + specInfo.l2(workspaceIndex); // Vector between the sample and the detector const V3D detPos = specInfo.position(workspaceIndex); // Detector direction normalized to 1 const 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) const 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 = specInfo.twoTheta(workspaceIndex) / 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); // 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) el.clear(); } prog->reportIncrement(numEvents, "Adding Events"); }