bool lineIntersectsSphere(const V3D &line, const V3D &lineStart, const V3D &peakCenter, const double peakRadius) { V3D peakToStart = peakCenter - lineStart; V3D unitLine = line; unitLine.normalize(); double proj = peakToStart.scalar_prod(unitLine); // All we are doing here is // projecting the peak to // segment start vector onto // the segment itself. V3D closestPointOnSegment; if (proj <= 0) // The projection is outside the segment. So use the start // point of the segment. { closestPointOnSegment = lineStart; // Start of line } else if (proj >= line.norm()) // The projection is greater than the segment // length. So use the end point of the // segment. { closestPointOnSegment = lineStart + line; // End of line. } else // The projection falls somewhere between the start and end of the line // segment. { V3D projectionVector = unitLine * proj; closestPointOnSegment = projectionVector + lineStart; } return (peakCenter - closestPointOnSegment).norm() <= peakRadius; }
/** Determines if this,B,C are collinear @param Bv :: Vector to test @param Cv :: Vector to test @return false is no colinear and true if they are (within Ptolerance) */ bool V3D::coLinear(const V3D& Bv,const V3D& Cv) const { const V3D& Av=*this; const V3D Tmp((Bv-Av).cross_prod(Cv-Av)); return (Tmp.norm()>Tolerance) ? false : true; }
/** \brief Initializes the FilterState \ref Base::state_ with the Acceleration-Vector. * * @param fMeasInit - Acceleration-Vector which should be used for initializing the attitude of the IMU. */ void initWithAccelerometer(const V3D& fMeasInit){ V3D unitZ(0,0,1); if(fMeasInit.norm()>1e-6){ state_.qWM().setFromVectors(unitZ,fMeasInit); } else { state_.qWM().setIdentity(); } }
/** Calculates the angle between this and another vector. * * @param v :: The other vector * @return The angle between the vectors in radians (0 < theta < pi) */ double V3D::angle(const V3D &v) const { double ratio = this->scalar_prod(v) / (this->norm() * v.norm()); if (ratio >= 1.0) // NOTE: Due to rounding errors, if v is return 0.0; // is nearly the same as "this" or else if (ratio <= -1.0) // as "-this", ratio can be slightly return M_PI; // more than 1 in absolute value. // That causes acos() to return NaN. return acos(ratio); }
void jacTransform(MXD& J, const mtInput& input) const{ J.setZero(); const int& camID = input.CfP(ID_).camID_; if(camID != outputCamID_){ input.updateMultiCameraExtrinsics(mpMultiCamera_); const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID))); const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD)); const double d_out = DrDP.norm(); const LWF::NormalVectorElement nor_out(DrDP); // TODO: test if Jacobian works, this new setting of vector is dangerous const Eigen::Matrix<double,1,3> J_d_DrDP = nor_out.getVec().transpose(); const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out; const Eigen::Matrix<double,3,3> J_DrDP_qDC = gSM(DrDP); const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix(); const Eigen::Matrix<double,3,3> J_DrDP_CrCD = -MPD(qDC).matrix(); const Eigen::Matrix<double,3,3> J_qDC_qDB = Eigen::Matrix3d::Identity(); const Eigen::Matrix<double,3,3> J_qDC_qCB = -MPD(qDC).matrix(); const Eigen::Matrix<double,3,3> J_CrCD_qCB = gSM(CrCD); const Eigen::Matrix<double,3,3> J_CrCD_BrBC = -MPD(input.qCM(camID)).matrix(); const Eigen::Matrix<double,3,3> J_CrCD_BrBD = MPD(input.qCM(camID)).matrix(); const Eigen::Matrix<double,3,1> J_CrCP_d = input.CfP(ID_).get_nor().getVec()*input.dep(ID_).getDistanceDerivative(); const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM(); J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor; J.template block<2,1>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)+2) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_d; if(!ignoreDistanceOutput_){ J.template block<1,2>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_nor; J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_d; } if(input.aux().doVECalibration_ && camID != outputCamID_){ J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(camID)) = J_nor_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB); J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_nor_DrDP*J_DrDP_qDC*J_qDC_qDB; J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(camID)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBC; J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBD; if(!ignoreDistanceOutput_){ J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(camID)) = J_d_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB); J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_d_DrDP*J_DrDP_qDC*J_qDC_qDB; J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(camID)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBC; J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBD; } } } else { J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = Eigen::Matrix2d::Identity(); J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = Eigen::Matrix<double,1,1>::Identity(); } }
/** * Provide the collimation length which is associated with the instrument * @param workspace: the input workspace * @returns the collimation length */ double SANSCollimationLengthEstimator::provideCollimationLength( Mantid::API::MatrixWorkspace_sptr workspace) { // If the instrument does not have a correction specified then set the length // to 4 const double defaultLColim = 4.0; auto collimationLengthID = "collimation-length-correction"; if (!workspace->getInstrument()->hasParameter(collimationLengthID)) { g_log.error("Error in SANSCollimtionLengthEstimator: The instrument " "parameter file does not contain a collimation length " "correction," "a default of 4 is provided. Please update the instrument " "parameter file."); return defaultLColim; } // Get the L1 length const V3D samplePos = workspace->getInstrument()->getSample()->getPos(); const V3D sourcePos = workspace->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); auto collimationLengthCorrection = workspace->getInstrument()->getNumberParameter(collimationLengthID); if (workspace->getInstrument()->hasParameter( "special-default-collimation-length-method")) { auto specialCollimationMethod = workspace->getInstrument()->getStringParameter( "special-default-collimation-length-method"); if (specialCollimationMethod[0] == "guide") { try { return getCollimationLengthWithGuides(workspace, L1, collimationLengthCorrection[0]); } catch (std::invalid_argument &ex) { g_log.notice() << ex.what(); g_log.notice() << "SANSCollimationLengthEstimator: Not using any guides"; return L1 - collimationLengthCorrection[0]; } } else { throw std::invalid_argument("Error in SANSCollimationLengthEstimator: " "Unknown special collimation method."); } } return L1 - collimationLengthCorrection[0]; }
void evalTransform(mtOutput& output, const mtInput& input) const{ input.updateMultiCameraExtrinsics(mpMultiCamera_); mpMultiCamera_->transformFeature(outputCamID_,input.CfP(ID_),input.dep(ID_),output.c(),output.d()); if(input.CfP(ID_).trackWarping_ && input.CfP(ID_).com_warp_nor()){ const int& camID = input.CfP(ID_).camID_; const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID))); const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD)); const double d_out = DrDP.norm(); const LWF::NormalVectorElement nor_out(DrDP); const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out; const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix(); const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM(); output.c().set_warp_nor(J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor*input.CfP(ID_).get_warp_nor()); } }
/** * Add an event to the appropriate vector of events for the closest h,k,l, * if it is within the required radius of the corresponding peak in the * PeakQMap. * * NOTE: The event passed in may be modified by this method. In particular, * if it corresponds to one of the specified peak_qs, the corresponding peak q * will be subtracted from the event and the event will be added to that * peak's vector in the event_lists map. * * @param event_Q The Q-vector for the event that may be added to the * event_lists map, if it is close enough to some peak */ void Integrate3DEvents::addEvent( V3D event_Q ) { int64_t hkl_key = getHklKey( event_Q ); if ( hkl_key == 0 ) // don't keep events associated with 0,0,0 return; V3D peak_q = peak_qs[hkl_key]; if ( ! peak_q.nullVector() ) { event_Q = event_Q - peak_q; if ( event_Q.norm() < radius ) { event_lists[ hkl_key ].push_back( event_Q ); } } }
/** * Builds a map based on the given number of neighbours * @param noNeighbours :: The number of nearest neighbours to use to build * the graph */ void NearestNeighbours::build(const int noNeighbours) { std::map<specid_t, IDetector_const_sptr> spectraDets = getSpectraDetectors(m_instrument, m_spectraMap); if (spectraDets.empty()) { throw std::runtime_error( "NearestNeighbours::build - Cannot find any spectra"); } const int nspectra = static_cast<int>(spectraDets.size()); // ANN only deals with integers if (noNeighbours >= nspectra) { throw std::invalid_argument( "NearestNeighbours::build - Invalid number of neighbours"); } // Clear current m_graph.clear(); m_specToVertex.clear(); m_noNeighbours = noNeighbours; BoundingBox bbox; // Base the scaling on the first detector, should be adequate but we can look // at this IDetector_const_sptr firstDet = (*spectraDets.begin()).second; firstDet->getBoundingBox(bbox); m_scale.reset(new V3D(bbox.width())); ANNpointArray dataPoints = annAllocPts(nspectra, 3); MapIV pointNoToVertex; std::map<specid_t, IDetector_const_sptr>::const_iterator detIt; int pointNo = 0; for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) { IDetector_const_sptr detector = detIt->second; const specid_t spectrum = detIt->first; V3D pos = detector->getPos() / (*m_scale); dataPoints[pointNo][0] = pos.X(); dataPoints[pointNo][1] = pos.Y(); dataPoints[pointNo][2] = pos.Z(); Vertex vertex = boost::add_vertex(spectrum, m_graph); pointNoToVertex[pointNo] = vertex; m_specToVertex[spectrum] = vertex; ++pointNo; } ANNkd_tree *annTree = new ANNkd_tree(dataPoints, nspectra, 3); pointNo = 0; // Run the nearest neighbour search on each detector, reusing the arrays ANNidxArray nnIndexList = new ANNidx[m_noNeighbours]; ANNdistArray nnDistList = new ANNdist[m_noNeighbours]; for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) { ANNpoint scaledPos = dataPoints[pointNo]; annTree->annkSearch(scaledPos, // Point to search nearest neighbours of m_noNeighbours, // Number of neighbours to find (8) nnIndexList, // Index list of results nnDistList, // List of distances to each of these 0.0 // Error bound (?) is this the radius to search in? ); // The distances that are returned are in our scaled coordinate // system. We store the real space ones. V3D realPos = V3D(scaledPos[0], scaledPos[1], scaledPos[2]) * (*m_scale); for (int i = 0; i < m_noNeighbours; i++) { ANNidx index = nnIndexList[i]; V3D neighbour = V3D(dataPoints[index][0], dataPoints[index][1], dataPoints[index][2]) * (*m_scale); V3D distance = neighbour - realPos; double separation = distance.norm(); boost::add_edge(m_specToVertex[detIt->first], // from pointNoToVertex[index], // to distance, m_graph); if (separation > m_cutoff) { m_cutoff = separation; } } pointNo++; } delete[] nnIndexList; delete[] nnDistList; delete annTree; annDeallocPts(dataPoints); annClose(); pointNoToVertex.clear(); m_vertexID = get(boost::vertex_name, m_graph); m_edgeLength = get(boost::edge_name, m_graph); }
/** Calculates the angle between this and another vector. * * @param v :: The other vector * @return The angle between the vectors in radians (0 < theta < pi) */ double V3D::angle(const V3D& v) const { return acos( this->scalar_prod(v) / (this->norm() * v.norm()) ); }
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"); }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("Workspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getProperty("SigmaModerator"); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0); const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; for (size_t i = 0; i < xInterpolate.size() - 1; ++i) { const double midpoint = xInterpolate[i + 1] - xInterpolate[i]; lookUpTable.addPoint(midpoint, yInterpolate[i]); } } else { for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } } const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; } // 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 scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1 + L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * (3.0 * R1 * R1 / (L1 * L1) + 3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) + (deltaR * deltaR) / (L2 * L2)); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin(theta / 2.0); const MantidVec &xIn = inOutWS->readX(i); MantidVec &yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // wavelenght spread from moderatorm, converted from microseconds to // wavelengths const double sigmaModerator = lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum); // calculate wavelenght resolution from moderator and histogram time bin const double sigmaLambda = std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 + sigmaModerator * sigmaModerator); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl; const double sigmaQ = std::sqrt( dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); } }
/** Execute the algorithm. */ void IntegrateEllipsoids::exec() { // get the input workspace MatrixWorkspace_sptr wksp = getProperty("InputWorkspace"); EventWorkspace_sptr eventWS = boost::dynamic_pointer_cast<EventWorkspace>(wksp); Workspace2D_sptr histoWS = boost::dynamic_pointer_cast<Workspace2D>(wksp); if (!eventWS && !histoWS) { throw std::runtime_error("IntegrateEllipsoids needs either a " "EventWorkspace or Workspace2D as input."); } // error out if there are not events if (eventWS && eventWS->getNumberEvents() <= 0) { throw std::runtime_error( "IntegrateEllipsoids does not work for empty event lists"); } PeaksWorkspace_sptr in_peak_ws = getProperty("PeaksWorkspace"); if (!in_peak_ws) { throw std::runtime_error("Could not read the peaks workspace"); } double radius_m = getProperty("RegionRadius"); double radius_s = getProperty("SatelliteRegionRadius"); int numSigmas = getProperty("NumSigmas"); double cutoffIsigI = getProperty("CutoffIsigI"); bool specify_size = getProperty("SpecifySize"); double peak_radius = getProperty("PeakSize"); double sate_peak_radius = getProperty("SatellitePeakSize"); double back_inner_radius = getProperty("BackgroundInnerSize"); double sate_back_inner_radius = getProperty("SatelliteBackgroundInnerSize"); double back_outer_radius = getProperty("BackgroundOuterSize"); double sate_back_outer_radius = getProperty("SatelliteBackgroundOuterSize"); bool hkl_integ = getProperty("IntegrateInHKL"); bool integrateEdge = getProperty("IntegrateIfOnEdge"); bool adaptiveQBackground = getProperty("AdaptiveQBackground"); double adaptiveQMultiplier = getProperty("AdaptiveQMultiplier"); double adaptiveQBackgroundMultiplier = 0.0; bool useOnePercentBackgroundCorrection = getProperty("UseOnePercentBackgroundCorrection"); if (adaptiveQBackground) adaptiveQBackgroundMultiplier = adaptiveQMultiplier; if (!integrateEdge) { // This only fails in the unit tests which say that MaskBTP is not // registered try { runMaskDetectors(in_peak_ws, "Tube", "edges"); runMaskDetectors(in_peak_ws, "Pixel", "edges"); } catch (...) { g_log.error("Can't execute MaskBTP algorithm for this instrument to set " "edge for IntegrateIfOnEdge option"); } calculateE1(in_peak_ws->detectorInfo()); // fill E1Vec for use in detectorQ } Mantid::DataObjects::PeaksWorkspace_sptr peak_ws = getProperty("OutputWorkspace"); if (peak_ws != in_peak_ws) peak_ws = in_peak_ws->clone(); // get UBinv and the list of // peak Q's for the integrator std::vector<Peak> &peaks = peak_ws->getPeaks(); size_t n_peaks = peak_ws->getNumberPeaks(); size_t indexed_count = 0; std::vector<V3D> peak_q_list; std::vector<std::pair<double, V3D>> qList; std::vector<V3D> hkl_vectors; std::vector<V3D> mnp_vectors; int ModDim = 0; for (size_t i = 0; i < n_peaks; i++) // Note: we skip un-indexed peaks { V3D hkl(peaks[i].getIntHKL()); V3D mnp(peaks[i].getIntMNP()); if (mnp[0] != 0 && ModDim == 0) ModDim = 1; if (mnp[1] != 0 && ModDim == 1) ModDim = 2; if (mnp[2] != 0 && ModDim == 2) ModDim = 3; // use tolerance == 1 to just check for (0,0,0,0,0,0) if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0)) { peak_q_list.emplace_back(peaks[i].getQLabFrame()); qList.emplace_back(1., V3D(peaks[i].getQLabFrame())); hkl_vectors.push_back(hkl); mnp_vectors.push_back(mnp); indexed_count++; } } if (indexed_count < 3) throw std::runtime_error( "At least three linearly independent indexed peaks are needed."); // Get UB using indexed peaks and // lab-Q vectors Matrix<double> UB(3, 3, false); Matrix<double> modUB(3, 3, false); Matrix<double> modHKL(3, 3, false); Geometry::IndexingUtils::Optimize_6dUB(UB, modUB, hkl_vectors, mnp_vectors, ModDim, peak_q_list); int maxOrder = 0; bool CT = false; if (peak_ws->sample().hasOrientedLattice()) { OrientedLattice lattice = peak_ws->mutableSample().getOrientedLattice(); lattice.setUB(UB); lattice.setModUB(modUB); modHKL = lattice.getModHKL(); maxOrder = lattice.getMaxOrder(); CT = lattice.getCrossTerm(); } Matrix<double> UBinv(UB); UBinv.Invert(); UBinv *= (1.0 / (2.0 * M_PI)); std::vector<double> PeakRadiusVector(n_peaks, peak_radius); std::vector<double> BackgroundInnerRadiusVector(n_peaks, back_inner_radius); std::vector<double> BackgroundOuterRadiusVector(n_peaks, back_outer_radius); if (specify_size) { if (back_outer_radius > radius_m) throw std::runtime_error( "BackgroundOuterSize must be less than or equal to the RegionRadius"); if (back_inner_radius >= back_outer_radius) throw std::runtime_error( "BackgroundInnerSize must be less BackgroundOuterSize"); if (peak_radius > back_inner_radius) throw std::runtime_error( "PeakSize must be less than or equal to the BackgroundInnerSize"); } // make the integrator Integrate3DEvents integrator(qList, hkl_vectors, mnp_vectors, UBinv, modHKL, radius_m, radius_s, maxOrder, CT, useOnePercentBackgroundCorrection); // get the events and add // them to the inegrator // set up a descripter of where we are going this->initTargetWSDescr(wksp); // set up the progress bar const size_t numSpectra = wksp->getNumberHistograms(); Progress prog(this, 0.5, 1.0, numSpectra); if (eventWS) { // process as EventWorkspace qListFromEventWS(integrator, prog, eventWS, UBinv, hkl_integ); } else { // process as Workspace2D qListFromHistoWS(integrator, prog, histoWS, UBinv, hkl_integ); } double inti; double sigi; std::vector<double> principalaxis1, principalaxis2, principalaxis3; std::vector<double> sateprincipalaxis1, sateprincipalaxis2, sateprincipalaxis3; for (size_t i = 0; i < n_peaks; i++) { const V3D hkl(peaks[i].getIntHKL()); const V3D mnp(peaks[i].getIntMNP()); if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0) || Geometry::IndexingUtils::ValidIndex(mnp, 1.0)) { const V3D peak_q = peaks[i].getQLabFrame(); // modulus of Q const double lenQpeak = adaptiveQMultiplier != 0.0 ? peak_q.norm() : 0.0; double adaptiveRadius = adaptiveQMultiplier * lenQpeak + peak_radius; if (mnp != V3D(0, 0, 0)) adaptiveRadius = adaptiveQMultiplier * lenQpeak + sate_peak_radius; if (adaptiveRadius <= 0.0) { g_log.error() << "Error: Radius for integration sphere of peak " << i << " is negative = " << adaptiveRadius << '\n'; peaks[i].setIntensity(0.0); peaks[i].setSigmaIntensity(0.0); PeakRadiusVector[i] = 0.0; BackgroundInnerRadiusVector[i] = 0.0; BackgroundOuterRadiusVector[i] = 0.0; continue; } double adaptiveBack_inner_radius; double adaptiveBack_outer_radius; if (mnp == V3D(0, 0, 0)) { adaptiveBack_inner_radius = adaptiveQBackgroundMultiplier * lenQpeak + back_inner_radius; adaptiveBack_outer_radius = adaptiveQBackgroundMultiplier * lenQpeak + back_outer_radius; } else { adaptiveBack_inner_radius = adaptiveQBackgroundMultiplier * lenQpeak + sate_back_inner_radius; adaptiveBack_outer_radius = adaptiveQBackgroundMultiplier * lenQpeak + sate_back_outer_radius; } PeakRadiusVector[i] = adaptiveRadius; BackgroundInnerRadiusVector[i] = adaptiveBack_inner_radius; BackgroundOuterRadiusVector[i] = adaptiveBack_outer_radius; std::vector<double> axes_radii; Mantid::Geometry::PeakShape_const_sptr shape = integrator.ellipseIntegrateModEvents( E1Vec, peak_q, hkl, mnp, specify_size, adaptiveRadius, adaptiveBack_inner_radius, adaptiveBack_outer_radius, axes_radii, inti, sigi); peaks[i].setIntensity(inti); peaks[i].setSigmaIntensity(sigi); peaks[i].setPeakShape(shape); if (axes_radii.size() == 3) { if (inti / sigi > cutoffIsigI || cutoffIsigI == EMPTY_DBL()) { if (mnp == V3D(0, 0, 0)) { principalaxis1.push_back(axes_radii[0]); principalaxis2.push_back(axes_radii[1]); principalaxis3.push_back(axes_radii[2]); } else { sateprincipalaxis1.push_back(axes_radii[0]); sateprincipalaxis2.push_back(axes_radii[1]); sateprincipalaxis3.push_back(axes_radii[2]); } } } } else { peaks[i].setIntensity(0.0); peaks[i].setSigmaIntensity(0.0); } } if (principalaxis1.size() > 1) { Statistics stats1 = getStatistics(principalaxis1); g_log.notice() << "principalaxis1: " << " mean " << stats1.mean << " standard_deviation " << stats1.standard_deviation << " minimum " << stats1.minimum << " maximum " << stats1.maximum << " median " << stats1.median << "\n"; Statistics stats2 = getStatistics(principalaxis2); g_log.notice() << "principalaxis2: " << " mean " << stats2.mean << " standard_deviation " << stats2.standard_deviation << " minimum " << stats2.minimum << " maximum " << stats2.maximum << " median " << stats2.median << "\n"; Statistics stats3 = getStatistics(principalaxis3); g_log.notice() << "principalaxis3: " << " mean " << stats3.mean << " standard_deviation " << stats3.standard_deviation << " minimum " << stats3.minimum << " maximum " << stats3.maximum << " median " << stats3.median << "\n"; if (sateprincipalaxis1.size() > 1) { Statistics satestats1 = getStatistics(sateprincipalaxis1); g_log.notice() << "sateprincipalaxis1: " << " mean " << satestats1.mean << " standard_deviation " << satestats1.standard_deviation << " minimum " << satestats1.minimum << " maximum " << satestats1.maximum << " median " << satestats1.median << "\n"; Statistics satestats2 = getStatistics(sateprincipalaxis2); g_log.notice() << "sateprincipalaxis2: " << " mean " << satestats2.mean << " standard_deviation " << satestats2.standard_deviation << " minimum " << satestats2.minimum << " maximum " << satestats2.maximum << " median " << satestats2.median << "\n"; Statistics satestats3 = getStatistics(sateprincipalaxis3); g_log.notice() << "sateprincipalaxis3: " << " mean " << satestats3.mean << " standard_deviation " << satestats3.standard_deviation << " minimum " << satestats3.minimum << " maximum " << satestats3.maximum << " median " << satestats3.median << "\n"; } constexpr size_t histogramNumber = 3; Workspace_sptr wsProfile = WorkspaceFactory::Instance().create( "Workspace2D", histogramNumber, principalaxis1.size(), principalaxis1.size()); Workspace2D_sptr wsProfile2D = boost::dynamic_pointer_cast<Workspace2D>(wsProfile); AnalysisDataService::Instance().addOrReplace("EllipsoidAxes", wsProfile2D); // set output workspace Points points(principalaxis1.size(), LinearGenerator(0, 1)); wsProfile2D->setHistogram(0, points, Counts(std::move(principalaxis1))); wsProfile2D->setHistogram(1, points, Counts(std::move(principalaxis2))); wsProfile2D->setHistogram(2, points, Counts(std::move(principalaxis3))); if (cutoffIsigI != EMPTY_DBL()) { principalaxis1.clear(); principalaxis2.clear(); principalaxis3.clear(); sateprincipalaxis1.clear(); sateprincipalaxis2.clear(); sateprincipalaxis3.clear(); specify_size = true; peak_radius = std::max(std::max(stats1.mean, stats2.mean), stats3.mean) + numSigmas * std::max(std::max(stats1.standard_deviation, stats2.standard_deviation), stats3.standard_deviation); back_inner_radius = peak_radius; back_outer_radius = peak_radius * 1.25992105; // A factor of 2 ^ (1/3) // will make the background // shell volume equal to the peak region volume. for (size_t i = 0; i < n_peaks; i++) { V3D hkl(peaks[i].getIntHKL()); V3D mnp(peaks[i].getIntMNP()); if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0) || Geometry::IndexingUtils::ValidIndex(mnp, 1.0)) { const V3D peak_q = peaks[i].getQLabFrame(); std::vector<double> axes_radii; integrator.ellipseIntegrateModEvents( E1Vec, peak_q, hkl, mnp, specify_size, peak_radius, back_inner_radius, back_outer_radius, axes_radii, inti, sigi); peaks[i].setIntensity(inti); peaks[i].setSigmaIntensity(sigi); if (axes_radii.size() == 3) { if (mnp == V3D(0, 0, 0)) { principalaxis1.push_back(axes_radii[0]); principalaxis2.push_back(axes_radii[1]); principalaxis3.push_back(axes_radii[2]); } else { sateprincipalaxis1.push_back(axes_radii[0]); sateprincipalaxis2.push_back(axes_radii[1]); sateprincipalaxis3.push_back(axes_radii[2]); } } } else { peaks[i].setIntensity(0.0); peaks[i].setSigmaIntensity(0.0); } } if (principalaxis1.size() > 1) { Workspace_sptr wsProfile2 = WorkspaceFactory::Instance().create( "Workspace2D", histogramNumber, principalaxis1.size(), principalaxis1.size()); Workspace2D_sptr wsProfile2D2 = boost::dynamic_pointer_cast<Workspace2D>(wsProfile2); AnalysisDataService::Instance().addOrReplace("EllipsoidAxes_2ndPass", wsProfile2D2); Points profilePoints(principalaxis1.size(), LinearGenerator(0, 1)); wsProfile2D->setHistogram(0, profilePoints, Counts(std::move(principalaxis1))); wsProfile2D->setHistogram(1, profilePoints, Counts(std::move(principalaxis2))); wsProfile2D->setHistogram(2, profilePoints, Counts(std::move(principalaxis3))); } } } // This flag is used by the PeaksWorkspace to evaluate whether it has been // integrated. peak_ws->mutableRun().addProperty("PeaksIntegrated", 1, true); // These flags are specific to the algorithm. peak_ws->mutableRun().addProperty("PeakRadius", PeakRadiusVector, true); peak_ws->mutableRun().addProperty("BackgroundInnerRadius", BackgroundInnerRadiusVector, true); peak_ws->mutableRun().addProperty("BackgroundOuterRadius", BackgroundOuterRadiusVector, true); setProperty("OutputWorkspace", peak_ws); }
void SANSDirectBeamScaling::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); const double beamRadius = getProperty("BeamRadius"); const double attTrans = getProperty("AttenuatorTransmission"); const double attTransErr = getProperty("AttenuatorTransmissionError"); // Extract the required spectra into separate workspaces std::vector<detid_t> udet; std::vector<size_t> index; udet.push_back(getProperty("BeamMonitor")); // Convert UDETs to workspace indices inputWS->getIndicesFromDetectorIDs(udet,index); if (index.size() < 1) { g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n"; throw std::invalid_argument("Could not find the incident beam monitor spectra\n"); } const int64_t numHists = inputWS->getNumberHistograms(); Progress progress(this,0.0,1.0,numHists); // Number of X bins const int64_t xLength = inputWS->readY(0).size(); // Monitor counts double monitor = 0.0; const MantidVec& MonIn = inputWS->readY(index[0]); for (int64_t j = 0; j < xLength; j++) monitor += MonIn[j]; const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos(); double counts = 0.0; double error = 0.0; int nPixels = 0; // Sample-detector distance for the contributing pixels double sdd = 0.0; for (int64_t i = 0; i < int64_t(numHists); ++i) { IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; continue; } // Skip if we have a monitor or if the detector is masked. if ( det->isMonitor() || det->isMasked() ) continue; const MantidVec& YIn = inputWS->readY(i); const MantidVec& EIn = inputWS->readE(i); // Sum up all the counts V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0); const double pixelDistance = pos.Z(); pos.setZ(0.0); if (pos.norm() <= beamRadius) { // Correct data for all X bins for (int64_t j = 0; j < xLength; j++) { counts += YIn[j]; error += EIn[j]*EIn[j]; } nPixels += 1; sdd += pixelDistance; } progress.report("Absolute Scaling"); } // Get the average SDD for the counted pixels, and transform to mm. sdd = sdd/nPixels*1000.0; error = std::sqrt(error); // Transform from m to mm double sourceAperture = getProperty("SourceApertureRadius"); sourceAperture *= 1000.0; // Transform from m to mm double sampleAperture = getProperty("SampleApertureRadius"); sampleAperture *= 1000.0; //TODO: replace this by some meaningful value const double KCG2FluxPerMon_SUGAR = 1.0; // Solid angle correction scale in 1/(cm^2)/steradian double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture); solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0; // Scaling factor in n/(monitor count)/(cm^2)/steradian double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) ); scale /= attTrans; std::vector<double> output; output.push_back(scale); output.push_back(scaleErr); setProperty("ScaleFactor", output); }
/** Determines if this,B,C are collinear @param Bv :: Vector to test @param Cv :: Vector to test @return false is no colinear and true if they are (within Ptolerance) */ bool V3D::coLinear(const V3D &Bv, const V3D &Cv) const { const V3D &Av = *this; const V3D Tmp((Bv - Av).cross_prod(Cv - Av)); return Tmp.norm() <= Tolerance; }
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"); }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); const bool doGravity = getProperty("AccountForGravity"); // Check the input checkInput(inWS); // Setup outputworkspace auto outWS = setupOutputWorkspace(inWS); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; // The moderator workspace needs to match the data workspace // in terms of wavelength binning const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getModeratorWorkspace(inWS); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const auto &xInterpolate = sigmaModeratorVSwavelength->points(0); const auto &yInterpolate = sigmaModeratorVSwavelength->y(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; } for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } // Calculate the L1 distance const V3D samplePos = inWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); // Get the collimation length double LCollim = getProperty("CollimationLength"); if (LCollim == 0.0) { auto collimationLengthEstimator = SANSCollimationLengthEstimator(); LCollim = collimationLengthEstimator.provideCollimationLength(inWS); g_log.information() << "No collimation length was specified. A default " "collimation length was estimated to be " << LCollim << '\n'; } else { g_log.information() << "The collimation length is " << LCollim << '\n'; } const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); const auto &spectrumInfo = inWS->spectrumInfo(); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; if (!spectrumInfo.hasDetectors(i)) { g_log.information() << "Workspace index " << i << " has no detector assigned to it - discarding\n"; continue; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) continue; const double L2 = spectrumInfo.l2(i); TOFSANSResolutionByPixelCalculator calculator; const double waveLengthIndependentFactor = calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = spectrumInfo.twoTheta(i); double sinTheta = sin(0.5 * theta); double factor = 4.0 * M_PI * sinTheta; const auto &xIn = inWS->x(i); const size_t xLength = xIn.size(); // Gravity correction std::unique_ptr<GravitySANSHelper> grav; if (doGravity) { grav = Kernel::make_unique<GravitySANSHelper>(spectrumInfo, i, getProperty("ExtraLength")); } // Get handles on the outputWorkspace auto &yOut = outWS->mutableY(i); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit // If we include a gravity correction we need to adjust sinTheta // for each wavelength (in Angstrom) if (doGravity) { double sinThetaGrav = grav->calcSinTheta(wl); factor = 4.0 * M_PI * sinThetaGrav; } const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // Get the uncertainty in Q auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl), waveLengthIndependentFactor, q, wl, sigmaSpreadFromBin, L1, L2); // Insert the Q value and the Q resolution into the outputworkspace yOut[j] = sigmaQ; } progress.report("Computing Q resolution"); } // Set the y axis label outWS->setYUnitLabel("QResolution"); setProperty("OutputWorkspace", outWS); }
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]; } } }
void PeakHKLErrors::functionDeriv1D(Jacobian *out, const double *xValues, const size_t nData) { PeaksWorkspace_sptr Peaks = AnalysisDataService::Instance().retrieveWS<PeaksWorkspace>( PeakWorkspaceName); boost::shared_ptr<Geometry::Instrument> instNew = getNewInstrument(Peaks); const DblMatrix &UB = Peaks->sample().getOrientedLattice().getUB(); DblMatrix UBinv(UB); UBinv.Invert(); UBinv /= 2 * M_PI; double GonRotx = getParameter("GonRotx"); double GonRoty = getParameter("GonRoty"); double GonRotz = getParameter("GonRotz"); Matrix<double> InvGonRotxMat = RotationMatrixAboutRegAxis(GonRotx, 'x'); Matrix<double> InvGonRotyMat = RotationMatrixAboutRegAxis(GonRoty, 'y'); Matrix<double> InvGonRotzMat = RotationMatrixAboutRegAxis(GonRotz, 'z'); Matrix<double> GonRot = InvGonRotxMat * InvGonRotyMat * InvGonRotzMat; InvGonRotxMat.Invert(); InvGonRotyMat.Invert(); InvGonRotzMat.Invert(); std::map<int, Kernel::Matrix<double>> RunNums2GonMatrix; getRun2MatMap(Peaks, OptRuns, RunNums2GonMatrix); g_log.debug() << "----------------------------Derivative------------------------\n"; V3D samplePosition = instNew->getSample()->getPos(); IPeak &ppeak = Peaks->getPeak(0); double L0 = ppeak.getL1(); double velocity = (L0 + ppeak.getL2()) / ppeak.getTOF(); double K = 2 * M_PI / ppeak.getWavelength() / velocity; // 2pi/lambda = K* velocity V3D beamDir = instNew->getBeamDirection(); size_t paramNums[] = {parameterIndex(std::string("SampleXOffset")), parameterIndex(std::string("SampleYOffset")), parameterIndex(std::string("SampleZOffset"))}; for (size_t i = 0; i < nData; i += 3) { int peakNum = boost::math::iround(xValues[i]); IPeak &peak_old = Peaks->getPeak(peakNum); Peak peak = createNewPeak(peak_old, instNew, 0, peak_old.getL1()); int runNum = peak_old.getRunNumber(); std::string runNumStr = std::to_string(runNum); for (int kk = 0; kk < static_cast<int>(nParams()); kk++) { out->set(i, kk, 0.0); out->set(i + 1, kk, 0.0); out->set(i + 2, kk, 0.0); } double chi, phi, omega; size_t chiParamNum, phiParamNum, omegaParamNum; size_t N = OptRuns.find("/" + runNumStr); if (N < OptRuns.size()) { chi = getParameter("chi" + (runNumStr)); phi = getParameter("phi" + (runNumStr)); omega = getParameter("omega" + (runNumStr)); peak.setGoniometerMatrix(GonRot * RunNums2GonMatrix[runNum]); chiParamNum = parameterIndex("chi" + (runNumStr)); phiParamNum = parameterIndex("phi" + (runNumStr)); omegaParamNum = parameterIndex("omega" + (runNumStr)); } else { Geometry::Goniometer Gon(peak.getGoniometerMatrix()); std::vector<double> phichiOmega = Gon.getEulerAngles("YZY"); chi = phichiOmega[1]; phi = phichiOmega[2]; omega = phichiOmega[0]; // peak.setGoniometerMatrix( GonRot*Gon.getR()); chiParamNum = phiParamNum = omegaParamNum = nParams() + 10; peak.setGoniometerMatrix(GonRot * peak.getGoniometerMatrix()); } V3D sampOffsets(getParameter("SampleXOffset"), getParameter("SampleYOffset"), getParameter("SampleZOffset")); peak.setSamplePos(peak.getSamplePos() + sampOffsets); // NOTE:Use getQLabFrame except for below. // For parameters the getGoniometerMatrix should remove GonRot, for derivs // wrt GonRot*, wrt chi*,phi*,etc. // Deriv wrt chi phi and omega if (phiParamNum < nParams()) { Matrix<double> chiMatrix = RotationMatrixAboutRegAxis(chi, 'z'); Matrix<double> phiMatrix = RotationMatrixAboutRegAxis(phi, 'y'); Matrix<double> omegaMatrix = RotationMatrixAboutRegAxis(omega, 'y'); Matrix<double> dchiMatrix = DerivRotationMatrixAboutRegAxis(chi, 'z'); Matrix<double> dphiMatrix = DerivRotationMatrixAboutRegAxis(phi, 'y'); Matrix<double> domegaMatrix = DerivRotationMatrixAboutRegAxis(omega, 'y'); Matrix<double> InvG = omegaMatrix * chiMatrix * phiMatrix; InvG.Invert(); // Calculate Derivatives wrt chi(phi,omega) in degrees Matrix<double> R = omegaMatrix * chiMatrix * dphiMatrix; Matrix<double> InvR = InvG * R * InvG * -1; V3D lab = peak.getQLabFrame(); V3D Dhkl0 = UBinv * InvR * lab; R = omegaMatrix * dchiMatrix * phiMatrix; InvR = InvG * R * InvG * -1; V3D Dhkl1 = UBinv * InvR * peak.getQLabFrame(); R = domegaMatrix * chiMatrix * phiMatrix; InvR = InvG * R * InvG * -1; V3D Dhkl2 = UBinv * InvR * peak.getQLabFrame(); // R.transpose should be R inverse out->set(i, chiParamNum, Dhkl1[0]); out->set(i + 1, chiParamNum, Dhkl1[1]); out->set(i + 2, chiParamNum, Dhkl1[2]); out->set(i, phiParamNum, Dhkl0[0]); out->set(i + 1, phiParamNum, Dhkl0[1]); out->set(i + 2, phiParamNum, Dhkl0[2]); out->set(i, omegaParamNum, Dhkl2[0]); out->set(i + 1, omegaParamNum, Dhkl2[1]); out->set(i + 2, omegaParamNum, Dhkl2[2]); } // if optimize for chi phi and omega on this peak //------------------------Goniometer Rotation Derivatives //----------------------- Matrix<double> InvGonRot(GonRot); InvGonRot.Invert(); Matrix<double> InvGon = InvGonRot * peak.getGoniometerMatrix(); InvGon.Invert(); V3D DGonx = (UBinv * InvGon * InvGonRotzMat * InvGonRotyMat * DerivRotationMatrixAboutRegAxis( -GonRotx, 'x') * // - gives inverse of GonRot peak.getQLabFrame()) * -1; V3D DGony = (UBinv * InvGon * InvGonRotzMat * DerivRotationMatrixAboutRegAxis(-GonRoty, 'y') * InvGonRotxMat * peak.getQLabFrame()) * -1; V3D DGonz = (UBinv * InvGon * DerivRotationMatrixAboutRegAxis(-GonRotz, 'z') * InvGonRotyMat * InvGonRotxMat * peak.getQLabFrame()) * -1; size_t paramnum = parameterIndex("GonRotx"); out->set(i, paramnum, DGonx[0]); out->set(i + 1, paramnum, DGonx[1]); out->set(i + 2, paramnum, DGonx[2]); out->set(i, parameterIndex("GonRoty"), DGony[0]); out->set(i + 1, parameterIndex("GonRoty"), DGony[1]); out->set(i + 2, parameterIndex("GonRoty"), DGony[2]); out->set(i, parameterIndex("GonRotz"), DGonz[0]); out->set(i + 1, parameterIndex("GonRotz"), DGonz[1]); out->set(i + 2, parameterIndex("GonRotz"), DGonz[2]); //-------------------- Sample Orientation derivatives //---------------------------------- // Qlab = -KV + k|V|*beamdir // D = pos-sampPos //|V|= vmag=(L0 + D )/tof // t1= tof - L0/|V| {time from sample to pixel} // V = D/t1 V3D D = peak.getDetPos() - samplePosition; double vmag = (L0 + D.norm()) / peak.getTOF(); double t1 = peak.getTOF() - L0 / vmag; // Derivs wrt sample x, y, z // Ddsx =( - 1, 0, 0), d|D|^2/dsx -> 2|D|d|D|/dsx =d(tranp(D)* D)/dsx =2 // Ddsx* tranp(D) //|D| also called Dmag V3D Dmagdsxsysz(D); Dmagdsxsysz *= (-1 / D.norm()); V3D vmagdsxsysz = Dmagdsxsysz / peak.getTOF(); V3D t1dsxsysz = vmagdsxsysz * (L0 / vmag / vmag); Matrix<double> Gon = peak.getGoniometerMatrix(); Gon.Invert(); // x=0 is deriv wrt SampleXoffset, x=1 is deriv wrt SampleYoffset, etc. for (int x = 0; x < 3; x++) { V3D pp; pp[x] = 1; V3D dQlab1 = pp / -t1 - D * (t1dsxsysz[x] / t1 / t1); V3D dQlab2 = beamDir * vmagdsxsysz[x]; V3D dQlab = dQlab2 - dQlab1; dQlab *= K; V3D dQSamp = Gon * dQlab; V3D dhkl = UBinv * dQSamp; out->set(i, paramNums[x], dhkl[0]); out->set(i + 1, paramNums[x], dhkl[1]); out->set(i + 2, paramNums[x], dhkl[2]); } } }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const double sigmaModeratorMicroSec = getProperty("SigmaModerator"); const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this,0.0,1.0,numberOfSpectra); //PARALLEL_FOR1(inOutWS) for (int i = 0; i < numberOfSpectra; i++) { //PARALLEL_START_INTERUPT_REGION IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.information() << "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 scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1+L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*Lsum*Lsum/(L1*L1*L2*L2) + (deltaR*deltaR)/(L2*L2) ); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin( theta/2.0 ); const MantidVec& xIn = inOutWS->readX(i); MantidVec& yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); for ( size_t j = 0; j < xLength-1; j++) { // Calculate q. Alternatively q could be calculated using ConvertUnit const double wl = (xIn[j+1]+xIn[j])/2.0; const double q = factor/wl; // calculate wavelenght resolution from moderator and histogram time bin width and // convert to from unit of micro-seconds to Aangstrom const double sigmaLambda = sigmaModeratorMicroSec*3.9560/(1000.0*Lsum); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q*sigmaLambda/wl; const double sigmaQ = std::sqrt(dTheta2/(wl*wl)+sigmaOverLambdaTimesQ*sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); //PARALLEL_END_INTERUPT_REGION } }
void AnvredCorrection::execEvent() { const int64_t numHists = static_cast<int64_t>(m_inputWS->getNumberHistograms()); std::string unitStr = m_inputWS->getAxis(0)->unit()->unitID(); //Create a new outputworkspace with not much in it DataObjects::EventWorkspace_sptr correctionFactors; correctionFactors = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace",numHists,2,1) ); correctionFactors->sortAll(TOF_SORT, NULL); //Copy required stuff from it API::WorkspaceFactory::Instance().initializeFromParent(m_inputWS, correctionFactors, true); bool inPlace = (this->getPropertyValue("InputWorkspace") == this->getPropertyValue("OutputWorkspace")); if (inPlace) g_log.debug("Correcting EventWorkspace in-place."); // If sample not at origin, shift cached positions. const V3D samplePos = m_inputWS->getInstrument()->getSample()->getPos(); const V3D pos = m_inputWS->getInstrument()->getSource()->getPos()-samplePos; double L1 = pos.norm(); Progress prog(this,0.0,1.0,numHists); // Loop over the spectra PARALLEL_FOR2(eventW,correctionFactors) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION // Copy over bin boundaries const MantidVec& X = eventW->readX(i); correctionFactors->dataX(i) = X; // Get detector position IDetector_const_sptr det; try { det = eventW->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 ) continue; // This is the scattered beam direction Instrument_const_sptr inst = eventW->getInstrument(); V3D dir = det->getPos() - samplePos; double L2 = dir.norm(); // Two-theta = polar angle = scattering angle = between +Z vector and the scattered beam double scattering = dir.angle( V3D(0.0, 0.0, 1.0) ); EventList el = eventW->getEventList(i); el.switchTo(WEIGHTED_NOTIME); std::vector<WeightedEventNoTime> events = el.getWeightedEventsNoTime(); std::vector<WeightedEventNoTime>::iterator itev; std::vector<WeightedEventNoTime>::iterator itev_end = events.end(); Mantid::Kernel::Units::Wavelength wl; std::vector<double> timeflight; // multiplying an event list by a scalar value for (itev = events.begin(); itev != itev_end; itev++) { timeflight.push_back(itev->tof()); if (unitStr.compare("TOF") == 0) wl.fromTOF(timeflight, timeflight, L1, L2, scattering, 0, 0, 0); double value = this->getEventWeight(timeflight[0], scattering); timeflight.clear(); itev->m_errorSquared = static_cast<float>(itev->m_errorSquared * value*value); itev->m_weight *= static_cast<float>(value); } correctionFactors->getOrAddEventList(i) +=events; std::set<detid_t>& dets = eventW->getEventList(i).getDetectorIDs(); std::set<detid_t>::iterator j; for (j = dets.begin(); j != dets.end(); ++j) correctionFactors->getOrAddEventList(i).addDetectorID(*j); // When focussing in place, you can clear out old memory from the input one! if (inPlace) { eventW->getEventList(i).clear(); Mantid::API::MemoryManager::Instance().releaseFreeMemory(); } prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION correctionFactors->doneAddingEventLists(); setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(correctionFactors)); // Now do some cleaning-up since destructor may not be called immediately this->cleanup(); }
void EQSANSTofStructure::execEvent( Mantid::DataObjects::EventWorkspace_sptr inputWS, double threshold, double frame_offset, double tof_frame_width, double tmp_frame_width, bool frame_skipping) { const size_t numHists = inputWS->getNumberHistograms(); Progress progress(this, 0.0, 1.0, numHists); // Get the nominal sample-to-detector distance (in mm) Mantid::Kernel::Property *prop = inputWS->run().getProperty("sample_detector_distance"); auto dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop); if (!dp) { throw std::runtime_error("sample_detector_distance log not found."); } const double SDD = *dp / 1000.0; // Loop through the spectra and apply correction PARALLEL_FOR1(inputWS) for (int64_t ispec = 0; ispec < int64_t(numHists); ++ispec) { IDetector_const_sptr det; try { det = inputWS->getDetector(ispec); } catch (Exception::NotFoundError &) { g_log.warning() << "Workspace index " << ispec << " has no detector assigned to it - discarding\n"; // 'continue' statement moved outside catch block because Mac Intel // compiler has a problem with it being here in an openmp block. } if (!det) continue; // Get the flight path from the sample to the detector pixel const V3D samplePos = inputWS->getInstrument()->getSample()->getPos(); const V3D scattered_flight_path = det->getPos() - samplePos; // Sample-to-source distance const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; double tof_factor = (SSD.norm() + scattered_flight_path.norm()) / (SSD.norm() + SDD); PARALLEL_START_INTERUPT_REGION // Get the pointer to the output event list std::vector<TofEvent> &events = inputWS->getSpectrum(ispec).getEvents(); std::vector<TofEvent>::iterator it; std::vector<TofEvent> clean_events; for (it = events.begin(); it < events.end(); ++it) { double newtof = it->tof(); newtof += frame_offset; // Correct for the scattered neutron flight path if (flight_path_correction) newtof /= tof_factor; while (newtof < threshold) newtof += tmp_frame_width; // Remove events that don't fall within the accepted time window double rel_tof = newtof - frame_tof0; double x = (static_cast<int>(floor(rel_tof * 10)) % static_cast<int>(floor(tof_frame_width * 10))) * 0.1; if (x < low_tof_cut || x > tof_frame_width - high_tof_cut) { continue; } // At this point the events in the second frame are still off by a frame if (frame_skipping && rel_tof > tof_frame_width) newtof += tof_frame_width; clean_events.emplace_back(newtof, it->pulseTime()); } events.clear(); events.reserve(clean_events.size()); for (it = clean_events.begin(); it < clean_events.end(); ++it) { events.push_back(*it); } progress.report("TOF structure"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** * Change UB to a new matrix corresponding to a unit cell with the first * two sides approximately equal in magnitude. This is used to arrange * the UB matrix for a tetragonal cell into a standard order. * * @param UB on input this should correspond to a tetragonal cell. * On output, it will correspond to a tetragonal cell with the * first two sides, a and b, set to the two sides that are most * nearly equal in length. */ void ConventionalCell::StandardizeTetragonal( Kernel::DblMatrix & UB ) { V3D a; V3D b; V3D c; IndexingUtils::GetABC( UB, a, b, c ); double a_b_diff = fabs( a.norm() - b.norm() ) / std::min( a.norm(), b.norm() ); double a_c_diff = fabs( a.norm() - c.norm() ) / std::min( a.norm(), c.norm() ); double b_c_diff = fabs( b.norm() - c.norm() ) / std::min( b.norm(), c.norm() ); // if needed, change UB to have the two most nearly // equal sides first. if ( a_c_diff <= a_b_diff && a_c_diff <= b_c_diff ) { IndexingUtils::GetUB( UB, c, a, b ); } else if ( b_c_diff <= a_b_diff && b_c_diff <= a_c_diff ) { IndexingUtils::GetUB( UB, b, c, a ); } }
bool NiggliCell::MakeNiggliUB(const DblMatrix &UB, DblMatrix &newUB) { V3D a; V3D b; V3D c; if (!OrientedLattice::GetABC(UB, a, b, c)) { return false; } V3D v1; V3D v2; V3D v3; // first make a list of linear combinations // of vectors a,b,c with coefficients up to 5 std::vector<V3D> directions; int N_coeff = 5; for (int i = -N_coeff; i <= N_coeff; i++) { for (int j = -N_coeff; j <= N_coeff; j++) { for (int k = -N_coeff; k <= N_coeff; k++) { if (i != 0 || j != 0 || k != 0) { v1 = a * i; v2 = b * j; v3 = c * k; V3D sum(v1); sum += v2; sum += v3; directions.push_back(sum); } } } } // next sort the list of linear combinations // in order of increasing length std::sort(directions.begin(), directions.end(), V3D::CompareMagnitude); // next form a list of possible UB matrices // using sides from the list of linear // combinations, using shorter directions first. // Keep trying more until 25 UBs are found. // Only keep UBs corresponding to cells with // at least a minimum cell volume std::vector<DblMatrix> UB_list; size_t num_needed = 25; size_t max_to_try = 5; while (UB_list.size() < num_needed && max_to_try < directions.size()) { max_to_try *= 2; size_t num_to_try = std::min(max_to_try, directions.size()); V3D acrossb; double vol = 0; double min_vol = .1f; // what should this be? 0.1 works OK, but...? for (size_t i = 0; i < num_to_try - 2; i++) { a = directions[i]; for (size_t j = i + 1; j < num_to_try - 1; j++) { b = directions[j]; acrossb = a.cross_prod(b); for (size_t k = j + 1; k < num_to_try; k++) { c = directions[k]; vol = acrossb.scalar_prod(c); if (vol > min_vol && HasNiggliAngles(a, b, c, 0.01)) { Matrix<double> new_tran(3, 3, false); OrientedLattice::GetUB(new_tran, a, b, c); UB_list.push_back(new_tran); } } } } } // if no valid UBs could be formed, return // false and the original UB if (UB_list.empty()) { newUB = UB; return false; } // now sort the UB's in order of increasing // total side length |a|+|b|+|c| std::sort(UB_list.begin(), UB_list.end(), CompareABCsum); // keep only those UB's with total side length // within .1% of the first one. This can't // be much larger or "bad" UBs are made for // some tests with 5% noise double length_tol = 0.001; double total_length; std::vector<DblMatrix> short_list; short_list.push_back(UB_list[0]); OrientedLattice::GetABC(short_list[0], a, b, c); total_length = a.norm() + b.norm() + c.norm(); bool got_short_list = false; size_t i = 1; while (i < UB_list.size() && !got_short_list) { OrientedLattice::GetABC(UB_list[i], v1, v2, v3); double next_length = v1.norm() + v2.norm() + v3.norm(); if (fabs(next_length - total_length) / total_length < length_tol) short_list.push_back(UB_list[i]); else got_short_list = true; i++; } // now sort on the basis of difference of cell // angles from 90 degrees and return the one // with angles most different from 90 std::sort(short_list.begin(), short_list.end(), CompareDiffFrom90); newUB = short_list[0]; return true; }