/** Append the peaks from a .peaks file into the workspace * @param outWS :: the workspace in which to place the information * @param filename :: path to the .peaks file */ void LoadIsawPeaks::appendFile( PeaksWorkspace_sptr outWS, std::string filename ) { // Open the file std::ifstream in( filename.c_str() ); // Read the header, load the instrument double T0; std::string s = readHeader( outWS, in , T0); // set T0 in the run parameters API::Run & m_run = outWS->mutableRun(); m_run.addProperty<double>("T0", T0, true); if( !in.good() || s.length() < 1 ) throw std::runtime_error( "End of Peaks file before peaks" ); if( s.compare( std::string( "0" ) ) != 0 ) throw std::logic_error( "No header for Peak segments" ); readToEndOfLine( in , true ); s = getWord( in , false ); int run, bankNum; double chi , phi , omega , monCount; // Build the universal goniometer that will build the rotation matrix. Mantid::Geometry::Goniometer uniGonio; uniGonio.makeUniversalGoniometer(); // TODO: Can we find the number of peaks to get better progress reporting? Progress prog(this, 0.0, 1.0, 100); while( in.good() ) { // Read the header if necessary s = readPeakBlockHeader( s , in , run , bankNum , chi , phi , omega , monCount ); // Build the Rotation matrix using phi,chi,omega uniGonio.setRotationAngle("phi", phi); uniGonio.setRotationAngle("chi", chi); uniGonio.setRotationAngle("omega", omega); //Put goniometer into peaks workspace outWS->mutableRun().setGoniometer(uniGonio, false); std::ostringstream oss; std::string bankString = "bank"; if (outWS->getInstrument()->getName() == "WISH") bankString = "WISHpanel0"; oss << bankString << bankNum; std::string bankName = oss.str(); int seqNum = -1; try { // Read the peak Peak peak = readPeak(outWS, s, in, seqNum, bankName); // Get the calculated goniometer matrix Matrix<double> gonMat = uniGonio.getR(); peak.setGoniometerMatrix(gonMat); peak.setRunNumber(run); peak.setMonitorCount( monCount ); double tof = peak.getTOF(); Kernel::Units::Wavelength wl; wl.initialize(peak.getL1(), peak.getL2(), peak.getScattering(), 0, peak.getInitialEnergy(), 0.0); peak.setWavelength(wl.singleFromTOF( tof)); // Add the peak to workspace outWS->addPeak(peak); } catch (std::runtime_error & e) { g_log.warning() << "Error reading peak SEQN " << seqNum << " : " << e.what() << std::endl; } prog.report(); } }
void FindPeaksMD::findPeaks(typename MDEventWorkspace<MDE, nd>::sptr ws) { if (nd < 3) throw std::invalid_argument("Workspace must have at least 3 dimensions."); progress(0.01, "Refreshing Centroids"); // TODO: This might be slow, progress report? // Make sure all centroids are fresh ws->getBox()->refreshCentroid(); typedef IMDBox<MDE,nd>* boxPtr; if (ws->getNumExperimentInfo() == 0) throw std::runtime_error("No instrument was found in the MDEventWorkspace. Cannot find peaks."); // TODO: Do we need to pick a different instrument info? ExperimentInfo_sptr ei = ws->getExperimentInfo(0); // Instrument associated with workspace Geometry::Instrument_const_sptr inst = ei->getInstrument(); // Find the run number int runNumber = ei->getRunNumber(); // Check that the workspace dimensions are in Q-sample-frame or Q-lab-frame. eDimensionType dimType; std::string dim0 = ws->getDimension(0)->getName(); if (dim0 == "H") { dimType = HKL; throw std::runtime_error("Cannot find peaks in a workspace that is already in HKL space."); } else if (dim0 == "Q_lab_x") { dimType = QLAB; } else if (dim0 == "Q_sample_x") dimType = QSAMPLE; else throw std::runtime_error("Unexpected dimensions: need either Q_lab_x or Q_sample_x."); // Find the goniometer rotation matrix Mantid::Kernel::Matrix<double> goniometer(3,3, true); // Default IDENTITY matrix try { goniometer = ei->mutableRun().getGoniometerMatrix(); } catch (std::exception & e) { g_log.warning() << "Error finding goniometer matrix. It will not be set in the peaks found." << std::endl; g_log.warning() << e.what() << std::endl; } /// Arbitrary scaling factor for density to make more manageable numbers, especially for older file formats. signal_t densityScalingFactor = 1e-6; // Calculate a threshold below which a box is too diffuse to be considered a peak. signal_t thresholdDensity = 0.0; thresholdDensity = ws->getBox()->getSignalNormalized() * DensityThresholdFactor * densityScalingFactor; g_log.notice() << "Threshold signal density: " << thresholdDensity << std::endl; // We will fill this vector with pointers to all the boxes (up to a given depth) typename std::vector<boxPtr> boxes; // Get all the MDboxes progress(0.10, "Getting Boxes"); ws->getBox()->getBoxes(boxes, 1000, true); // TODO: Here keep only the boxes > e.g. 3 * mean. typedef std::pair<double, boxPtr> dens_box; // Map that will sort the boxes by increasing density. The key = density; value = box *. typename std::multimap<double, boxPtr> sortedBoxes; progress(0.20, "Sorting Boxes by Density"); typename std::vector<boxPtr>::iterator it1; typename std::vector<boxPtr>::iterator it1_end = boxes.end(); for (it1 = boxes.begin(); it1 != it1_end; it1++) { boxPtr box = *it1; double density = box->getSignalNormalized() * densityScalingFactor; // Skip any boxes with too small a signal density. if (density > thresholdDensity) sortedBoxes.insert(dens_box(density,box)); } // List of chosen possible peak boxes. std::vector<boxPtr> peakBoxes; prog = new Progress(this, 0.30, 0.95, MaxPeaks); int64_t numBoxesFound = 0; // Now we go (backwards) through the map // e.g. from highest density down to lowest density. typename std::multimap<double, boxPtr>::reverse_iterator it2; typename std::multimap<double, boxPtr>::reverse_iterator it2_end = sortedBoxes.rend(); for (it2 = sortedBoxes.rbegin(); it2 != it2_end; it2++) { signal_t density = it2->first; boxPtr box = it2->second; #ifndef MDBOX_TRACK_CENTROID coord_t boxCenter[nd]; box->calculateCentroid(boxCenter); #else const coord_t * boxCenter = box->getCentroid(); #endif // Compare to all boxes already picked. bool badBox = false; for (typename std::vector<boxPtr>::iterator it3=peakBoxes.begin(); it3 != peakBoxes.end(); it3++) { #ifndef MDBOX_TRACK_CENTROID coord_t otherCenter[nd]; (*it3)->calculateCentroid(otherCenter); #else const coord_t * otherCenter = (*it3)->getCentroid(); #endif // Distance between this box and a box we already put in. coord_t distSquared = 0.0; for (size_t d=0; d<nd; d++) { coord_t dist = otherCenter[d] - boxCenter[d]; distSquared += (dist * dist); } // Reject this box if it is too close to another previously found box. if (distSquared < peakRadiusSquared) { badBox = true; break; } } // The box was not rejected for another reason. if (!badBox) { if (numBoxesFound++ >= MaxPeaks) { g_log.notice() << "Number of peaks found exceeded the limit of " << MaxPeaks << ". Stopping peak finding." << std::endl; break; } peakBoxes.push_back(box); g_log.information() << "Found box at "; for (size_t d=0; d<nd; d++) g_log.information() << (d>0?",":"") << boxCenter[d]; g_log.information() << "; Density = " << density << std::endl; // Report progres for each box found. prog->report("Finding Peaks"); } } prog->resetNumSteps(numBoxesFound, 0.95, 1.0); // Copy the instrument, sample, run to the peaks workspace. peakWS->copyExperimentInfoFrom(ei.get()); // --- Convert the "boxes" to peaks ---- for (typename std::vector<boxPtr>::iterator it3=peakBoxes.begin(); it3 != peakBoxes.end(); it3++) { // The center of the box = Q in the lab frame boxPtr box = *it3; #ifndef MDBOX_TRACK_CENTROID coord_t boxCenter[nd]; box->calculateCentroid(boxCenter); #else const coord_t * boxCenter = box->getCentroid(); #endif V3D Q(boxCenter[0], boxCenter[1], boxCenter[2]); // Create a peak and add it // Empty starting peak. Peak p; try { if (dimType == QLAB) { // Build using the Q-lab-frame constructor p = Peak(inst, Q); // Save gonio matrix for later p.setGoniometerMatrix(goniometer); } else if (dimType == QSAMPLE) { // Build using the Q-sample-frame constructor p = Peak(inst, Q, goniometer); } } catch (std::exception &e) { g_log.notice() << "Error creating peak at " << Q << " because of '" << e.what() << "'. Peak will be skipped." << std::endl; continue; } try { // Look for a detector p.findDetector(); } catch (...) { /* Ignore errors in ray-tracer TODO: Handle for WISH data later */ } // The "bin count" used will be the box density. p.setBinCount( box->getSignalNormalized() * densityScalingFactor); // Save the run number found before. p.setRunNumber(runNumber); peakWS->addPeak(p); // Report progres for each box found. prog->report("Adding Peaks"); } // for each box found }