size_t MaskPeaksWorkspace::getWkspIndex(const detid2index_map &pixel_to_wi, Geometry::IComponent_const_sptr comp, const int x, const int y) { Geometry::RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp); if (det) { if (x >= det->xpixels() || x < 0 || y >= det->ypixels() || y < 0) return EMPTY_INT(); if ((x >= det->xpixels()) || (x < 0) // this check is unnecessary as callers are doing it too || (y >= det->ypixels()) || (y < 0)) // but just to make debugging easier { std::stringstream msg; msg << "Failed to find workspace index for x=" << x << " y=" << y << "(max x=" << det->xpixels() << ", max y=" << det->ypixels() << ")"; throw std::runtime_error(msg.str()); } int pixelID = det->getAtXY(x, y)->getID(); // Find the corresponding workspace index, if any auto wiEntry = pixel_to_wi.find(pixelID); if (wiEntry == pixel_to_wi.end()) { std::stringstream msg; msg << "Failed to find workspace index for x=" << x << " y=" << y; throw std::runtime_error(msg.str()); } return wiEntry->second; } else { std::vector<Geometry::IComponent_const_sptr> children; boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(comp); asmb->getChildren(children, false); boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[0]); std::vector<Geometry::IComponent_const_sptr> grandchildren; asmb2->getChildren(grandchildren, false); int NROWS = static_cast<int>(grandchildren.size()); int NCOLS = static_cast<int>(children.size()); // Wish pixels and tubes start at 1 not 0 if (x - 1 >= NCOLS || x - 1 < 0 || y - 1 >= NROWS || y - 1 < 0) return EMPTY_INT(); std::string bankName = comp->getName(); detid2index_map::const_iterator it = pixel_to_wi.find(findPixelID(bankName, x, y)); if (it == pixel_to_wi.end()) return EMPTY_INT(); return (it->second); } }
/* Set workspace->group ID map by detectors (range) * */ void LoadDetectorsGroupingFile::setByDetectors() { // 0. Check if (!m_instrument && m_groupDetectorsMap.size() > 0) { std::map<int, std::vector<detid_t>>::iterator mapiter; bool norecord = true; for (mapiter = m_groupDetectorsMap.begin(); mapiter != m_groupDetectorsMap.end(); ++mapiter) if (mapiter->second.size() > 0) { norecord = false; g_log.error() << "Instrument is not specified in XML file. " << "But tag 'detid' is used in XML file for Group " << mapiter->first << ". It is not allowed. " << std::endl; break; } if (!norecord) throw std::invalid_argument( "XML definition involving detectors causes error"); } // 1. Prepare const detid2index_map indexmap = m_groupWS->getDetectorIDToWorkspaceIndexMap(true); // 2. Set GroupingWorkspace for (auto &detectorMap : m_groupDetectorsMap) { g_log.debug() << "Group ID = " << detectorMap.first << std::endl; for (auto detid : detectorMap.second) { auto itx = indexmap.find(detid); if (itx != indexmap.end()) { size_t wsindex = itx->second; m_groupWS->dataY(wsindex)[0] = detectorMap.first; } else { g_log.error() << "Pixel w/ ID = " << detid << " Cannot Be Located" << std::endl; } } // ENDFOR detid (in range) } // ENDFOR each group ID return; }
/** Mask detectors or Unmask detectors * @param indexmap: spectraId to spectraNum map used * in masking * @param tomask: true to mask, false to unmask * @param singledetids: list of individual det ids to mask */ void LoadMask::processMaskOnDetectors( const detid2index_map &indexmap, bool tomask, const std::vector<detid_t> &singledetids) { // 1. Get index map // 2. Mask g_log.debug() << "Mask = " << tomask << " Final Single IDs Size = " << singledetids.size() << '\n'; for (auto detid : singledetids) { detid2index_map::const_iterator it; it = indexmap.find(detid); if (it != indexmap.end()) { size_t index = it->second; m_maskWS->mutableY(index)[0] = (tomask) ? 1 : 0; } else { g_log.warning() << "Pixel w/ ID = " << detid << " Cannot Be Located\n"; } } }
/** Calculate (all) detectors' offsets */ void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() { int nspec = static_cast<int>(m_inputWS->getNumberHistograms()); // To get the workspace index from the detector ID const detid2index_map pixel_to_wi = m_maskWS->getDetectorIDToWorkspaceIndexMap(true); // Fit all the spectra with a gaussian Progress prog(this, 0, 1.0, nspec); // cppcheck-suppress syntaxError PRAGMA_OMP(parallel for schedule(dynamic, 1) ) for (int wi = 0; wi < nspec; ++wi) { PARALLEL_START_INTERUPT_REGION std::vector<double> fittedpeakpositions, tofitpeakpositions; FitPeakOffsetResult offsetresult = calculatePeakOffset(wi, fittedpeakpositions, tofitpeakpositions); // Get the list of detectors in this pixel const std::set<detid_t> &dets = m_inputWS->getSpectrum(wi)->getDetectorIDs(); // Most of the exec time is in FitSpectra, so this critical block should // not be a problem. PARALLEL_CRITICAL(GetDetOffsetsMultiPeaks_setValue) { // Use the same offset for all detectors from this pixel (in case of // summing pixels) std::set<detid_t>::iterator it; for (it = dets.begin(); it != dets.end(); ++it) { // Set value to output peak offset workspace m_outputW->setValue(*it, offsetresult.offset, offsetresult.fitSum); // Set value to output peak number workspace m_outputNP->setValue(*it, offsetresult.peakPosFittedSize, offsetresult.chisqSum); // Set value to mask workspace const auto mapEntry = pixel_to_wi.find(*it); if (mapEntry == pixel_to_wi.end()) continue; const size_t workspaceIndex = mapEntry->second; if (offsetresult.mask > 0.9) { // Being masked m_maskWS->maskWorkspaceIndex(workspaceIndex); m_maskWS->dataY(workspaceIndex)[0] = offsetresult.mask; } else { // Using the detector m_maskWS->dataY(workspaceIndex)[0] = offsetresult.mask; // check the average value of delta(d)/d. if it is far off the // theorical value, output // FIXME - This warning should not appear by filtering out peaks // that are too wide or narrow. // TODO - Delete the if statement below if it is never triggered. if (m_hasInputResolution) { double pixelresolution = m_inputResolutionWS->readY(wi)[0]; if (offsetresult.resolution > 10 * pixelresolution || offsetresult.resolution < 0.1 * pixelresolution) g_log.warning() << "Spectrum " << wi << " delta(d)/d = " << offsetresult.resolution << "\n"; } } } // ENDFOR (detectors) // Report offset fitting result/status addInfoToReportWS(wi, offsetresult, tofitpeakpositions, fittedpeakpositions); } // End of critical region prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION return; }
/** Load a single bank into the workspace * * @param nexusfilename :: file to open * @param entry_name :: NXentry name * @param bankName :: NXdata bank name * @param WS :: workspace to modify * @param id_to_wi :: det ID to workspace index mapping */ void LoadTOFRawNexus::loadBank(const std::string &nexusfilename, const std::string &entry_name, const std::string &bankName, API::MatrixWorkspace_sptr WS, const detid2index_map &id_to_wi) { g_log.debug() << "Loading bank " << bankName << std::endl; // To avoid segfaults on RHEL5/6 and Fedora m_fileMutex.lock(); // Navigate to the point in the file auto file = new ::NeXus::File(nexusfilename); file->openGroup(entry_name, "NXentry"); file->openGroup("instrument", "NXinstrument"); file->openGroup(bankName, "NXdetector"); size_t m_numPixels = 0; std::vector<uint32_t> pixel_id; if (!m_assumeOldFile) { // Load the pixel IDs file->readData("pixel_id", pixel_id); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid pixel_id data in " << bankName << std::endl; return; } } else { // Load the x and y pixel offsets std::vector<float> xoffsets; std::vector<float> yoffsets; file->readData("x_pixel_offset", xoffsets); file->readData("y_pixel_offset", yoffsets); m_numPixels = xoffsets.size() * yoffsets.size(); if (0 == m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid (x,y) offsets in " << bankName << std::endl; return; } size_t bankNum = 0; if (bankName.size() > 4) { if (bankName.substr(0, 4) == "bank") { bankNum = boost::lexical_cast<size_t>(bankName.substr(4)); bankNum--; } else { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid bank number for " << bankName << std::endl; return; } } // All good, so construct the pixel ID listing size_t numX = xoffsets.size(); size_t numY = yoffsets.size(); for (size_t i = 0; i < numX; i++) { for (size_t j = 0; j < numY; j++) { pixel_id.push_back( static_cast<uint32_t>(j + numY * (i + numX * bankNum))); } } } size_t iPart = 0; if (m_spec_max != Mantid::EMPTY_INT()) { uint32_t ifirst = pixel_id[0]; range_check out_range(m_spec_min, m_spec_max, id_to_wi); auto newEnd = std::remove_if(pixel_id.begin(), pixel_id.end(), out_range); pixel_id.erase(newEnd, pixel_id.end()); // check if beginning or end of array was erased if (ifirst != pixel_id[0]) iPart = m_numPixels - pixel_id.size(); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "No pixels from " << bankName << std::endl; return; }; } // Load the TOF vector std::vector<float> tof; file->readData(m_axisField, tof); size_t m_numBins = tof.size() - 1; if (tof.size() <= 1) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid " << m_axisField << " data in " << bankName << std::endl; return; } // Make a shared pointer MantidVecPtr Xptr; MantidVec &X = Xptr.access(); X.resize(tof.size(), 0); X.assign(tof.begin(), tof.end()); // Load the data. Coerce ints into double. std::string errorsField = ""; std::vector<double> data; file->openData(m_dataField); file->getDataCoerce(data); if (file->hasAttr("errors")) file->getAttr("errors", errorsField); file->closeData(); // Load the errors bool hasErrors = !errorsField.empty(); std::vector<double> errors; if (hasErrors) { try { file->openData(errorsField); file->getDataCoerce(errors); file->closeData(); } catch (...) { g_log.information() << "Error loading the errors field, '" << errorsField << "' for bank " << bankName << ". Will use sqrt(counts). " << std::endl; hasErrors = false; } } /*if (data.size() != m_numBins * m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << m_dataField << "' data in " << bankName << std::endl; return; } if (hasErrors && (errors.size() != m_numBins * m_numPixels)) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << errorsField << "' errors in " << bankName << std::endl; return; } */ // Have all the data I need m_fileMutex.unlock(); file->close(); for (size_t i = iPart; i < iPart + m_numPixels; i++) { // Find the workspace index for this detector detid_t pixelID = pixel_id[i - iPart]; size_t wi = id_to_wi.find(pixelID)->second; // Set the basic info of that spectrum ISpectrum *spec = WS->getSpectrum(wi); spec->setSpectrumNo(specid_t(wi + 1)); spec->setDetectorID(pixel_id[i - iPart]); // Set the shared X pointer spec->setX(X); // Extract the Y MantidVec &Y = spec->dataY(); Y.assign(data.begin() + i * m_numBins, data.begin() + (i + 1) * m_numBins); MantidVec &E = spec->dataE(); if (hasErrors) { // Copy the errors from the loaded document E.assign(errors.begin() + i * m_numBins, errors.begin() + (i + 1) * m_numBins); } else { // Now take the sqrt(Y) to give E E = Y; std::transform(E.begin(), E.end(), E.begin(), (double (*)(double))sqrt); } } // Done! }
/* * Convert Componenet -> Detector IDs -> Workspace Indices -> set group ID */ void LoadDetectorsGroupingFile::setByComponents() { // 0. Check if (!m_instrument) { std::map<int, std::vector<std::string>>::iterator mapiter; bool norecord = true; for (mapiter = m_groupComponentsMap.begin(); mapiter != m_groupComponentsMap.end(); ++mapiter) { if (mapiter->second.size() > 0) { g_log.error() << "Instrument is not specified in XML file. " << "But tag 'component' is used in XML file for Group " << mapiter->first << " It is not allowed" << std::endl; norecord = false; break; } } if (!norecord) throw std::invalid_argument( "XML definition involving component causes error"); } // 1. Prepare const detid2index_map indexmap = m_groupWS->getDetectorIDToWorkspaceIndexMap(true); // 2. Set for (auto &componentMap : m_groupComponentsMap) { g_log.debug() << "Group ID = " << componentMap.first << " With " << componentMap.second.size() << " Components" << std::endl; for (auto &name : componentMap.second) { // a) get component Geometry::IComponent_const_sptr component = m_instrument->getComponentByName(name); // 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() << "Component Name = " << name << " Component ID = " << component->getComponentID() << "Number of Children = " << children.size() << std::endl; for (auto child : children) { // c) convert component to detector Geometry::IDetector_const_sptr det = boost::dynamic_pointer_cast<const Geometry::IDetector>(child); if (det) { // Component is DETECTOR: int32_t detid = det->getID(); auto itx = indexmap.find(detid); if (itx != indexmap.end()) { size_t wsindex = itx->second; m_groupWS->dataY(wsindex)[0] = componentMap.first; } else { g_log.error() << "Pixel w/ ID = " << detid << " Cannot Be Located" << std::endl; } } // ENDIF Detector } // ENDFOR (children of component) } // ENDFOR (component) } // ENDFOR GroupID return; }
/** * Read Event Data * @param eventEntries map of the file entries that have events * @param nxFile Reads data from inside first top entry * @return Names of workspaces to include in the output group */ std::vector<std::string> LoadMcStas::readEventData( const std::map<std::string, std::string> &eventEntries, ::NeXus::File &nxFile) { // vector to store output workspaces std::vector<std::string> scatteringWSNames; std::string filename = getPropertyValue("Filename"); auto entries = nxFile.getEntries(); const bool errorBarsSetTo1 = getProperty("ErrorBarsSetTo1"); // will assume that each top level entry contain one mcstas // generated IDF and any event data entries within this top level // entry are data collected for that instrument // This code for loading the instrument is for now adjusted code from // ExperimentalInfo. // Close data folder and go back to top level. Then read and close the // Instrument folder. nxFile.closeGroup(); Geometry::Instrument_sptr instrument; // Initialize progress reporting int reports = 2; const double progressFractionInitial = 0.1; Progress progInitial(this, 0.0, progressFractionInitial, reports); std::string instrumentXML; progInitial.report("Loading instrument"); try { nxFile.openGroup("instrument", "NXinstrument"); nxFile.openGroup("instrument_xml", "NXnote"); nxFile.readData("data", instrumentXML); nxFile.closeGroup(); nxFile.closeGroup(); } catch (...) { g_log.warning() << "\nCould not find the instrument description in the Nexus file:" << filename << " Ignore eventdata from the Nexus file\n"; return scatteringWSNames; ; } try { std::string instrumentName = "McStas"; Geometry::InstrumentDefinitionParser parser(filename, instrumentName, instrumentXML); std::string instrumentNameMangled = parser.getMangledName(); // Check whether the instrument is already in the InstrumentDataService if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) { // If it does, just use the one from the one stored there instrument = InstrumentDataService::Instance().retrieve(instrumentNameMangled); } else { // Really create the instrument instrument = parser.parseXML(nullptr); // Add to data service for later retrieval InstrumentDataService::Instance().add(instrumentNameMangled, instrument); } } catch (Exception::InstrumentDefinitionError &e) { g_log.warning() << "When trying to read the instrument description in the Nexus file: " << filename << " the following error is reported: " << e.what() << " Ignore eventdata from the Nexus file\n"; return scatteringWSNames; ; } catch (...) { g_log.warning() << "Could not parse instrument description in the Nexus file: " << filename << " Ignore eventdata from the Nexus file\n"; return scatteringWSNames; ; } // Finished reading Instrument. Then open new data folder again nxFile.openGroup("data", "NXdetector"); // create and prepare an event workspace ready to receive the mcstas events progInitial.report("Set up EventWorkspace"); EventWorkspace_sptr eventWS(new EventWorkspace()); // initialize, where create up front number of eventlists = number of // detectors eventWS->initialize(instrument->getNumberDetectors(), 1, 1); // Set the units eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); eventWS->setYUnit("Counts"); // set the instrument eventWS->setInstrument(instrument); // assign detector ID to eventlists std::vector<detid_t> detIDs = instrument->getDetectorIDs(); for (size_t i = 0; i < instrument->getNumberDetectors(); i++) { eventWS->getSpectrum(i).addDetectorID(detIDs[i]); // spectrum number are treated as equal to detector IDs for McStas data eventWS->getSpectrum(i).setSpectrumNo(detIDs[i]); } // the one is here for the moment for backward compatibility eventWS->rebuildSpectraMapping(true); bool isAnyNeutrons = false; // to store shortest and longest recorded TOF double shortestTOF(0.0); double longestTOF(0.0); // create vector container all the event output workspaces needed const size_t numEventEntries = eventEntries.size(); std::string nameOfGroupWS = getProperty("OutputWorkspace"); const auto eventDataTotalName = "EventData_" + nameOfGroupWS; std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = { {eventWS, eventDataTotalName}}; // if numEventEntries > 1 also create separate event workspaces const bool onlySummedEventWorkspace = getProperty("OutputOnlySummedEventWorkspace"); if (!onlySummedEventWorkspace && numEventEntries > 1) { for (const auto &eventEntry : eventEntries) { const std::string &dataName = eventEntry.first; // create container to hold partial event data // plus the name users will see for it const auto ws_name = dataName + "_" + nameOfGroupWS; allEventWS.emplace_back(eventWS->clone(), ws_name); } } Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2); // Refer to entry in allEventWS. The first non-summed workspace index is 1 auto eventWSIndex = 1u; // Loop over McStas event data components for (const auto &eventEntry : eventEntries) { const std::string &dataName = eventEntry.first; const std::string &dataType = eventEntry.second; // open second level entry nxFile.openGroup(dataName, dataType); std::vector<double> data; nxFile.openData("events"); progEntries.report("read event data from nexus"); // Need to take into account that the nexus readData method reads a // multi-column data entry // into a vector // The number of data column for each neutron is here hardcoded to (p, x, // y, n, id, t) // Thus we have // column 0 : p neutron wight // column 1 : x x coordinate // column 2 : y y coordinate // column 3 : n accumulated number of neutrons // column 4 : id pixel id // column 5 : t time // get info about event data ::NeXus::Info id_info = nxFile.getInfo(); if (id_info.dims.size() != 2) { g_log.error() << "Event data in McStas nexus file not loaded. Expected " "event data block to be two dimensional\n"; return scatteringWSNames; ; } int64_t nNeutrons = id_info.dims[0]; int64_t numberOfDataColumn = id_info.dims[1]; if (nNeutrons && numberOfDataColumn != 6) { g_log.error() << "Event data in McStas nexus file expecting 6 columns\n"; return scatteringWSNames; ; } if (!isAnyNeutrons && nNeutrons > 0) isAnyNeutrons = true; std::vector<int64_t> start(2); std::vector<int64_t> step(2); // read the event data in blocks. 1 million event is 1000000*6*8 doubles // about 50Mb int64_t nNeutronsInBlock = 1000000; int64_t nOfFullBlocks = nNeutrons / nNeutronsInBlock; int64_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock; // sum over number of blocks + 1 to cover the remainder for (int64_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) { if (iBlock == nOfFullBlocks) { // read remaining neutrons start[0] = nOfFullBlocks * nNeutronsInBlock; start[1] = 0; step[0] = nRemainingNeutrons; step[1] = numberOfDataColumn; } else { // read neutrons in a full block start[0] = iBlock * nNeutronsInBlock; start[1] = 0; step[0] = nNeutronsInBlock; step[1] = numberOfDataColumn; } const int64_t nNeutronsForthisBlock = step[0]; // number of neutrons read for this block data.resize(nNeutronsForthisBlock * numberOfDataColumn); // Check that the type is what it is supposed to be if (id_info.type == ::NeXus::FLOAT64) { nxFile.getSlab(&data[0], start, step); } else { g_log.warning() << "Entry event field is not FLOAT64! It will be skipped.\n"; continue; } // populate workspace with McStas events const detid2index_map detIDtoWSindex_map = allEventWS[0].first->getDetectorIDToWorkspaceIndexMap(true); progEntries.report("read event data into workspace"); for (int64_t in = 0; in < nNeutronsForthisBlock; in++) { const int detectorID = static_cast<int>(data[4 + numberOfDataColumn * in]); const double detector_time = data[5 + numberOfDataColumn * in] * 1.0e6; // convert to microseconds if (in == 0 && iBlock == 0) { shortestTOF = detector_time; longestTOF = detector_time; } else { if (detector_time < shortestTOF) shortestTOF = detector_time; if (detector_time > longestTOF) longestTOF = detector_time; } const size_t workspaceIndex = detIDtoWSindex_map.find(detectorID)->second; int64_t pulse_time = 0; auto weightedEvent = WeightedEvent(); if (errorBarsSetTo1) { weightedEvent = WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in], 1.0); } else { weightedEvent = WeightedEvent( detector_time, pulse_time, data[numberOfDataColumn * in], data[numberOfDataColumn * in] * data[numberOfDataColumn * in]); } allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent; if (!onlySummedEventWorkspace && numEventEntries > 1) { allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) += weightedEvent; } } eventWSIndex++; } // end reading over number of blocks of an event dataset nxFile.closeData(); nxFile.closeGroup(); } // end reading over number of event datasets // Create a default TOF-vector for histogramming, for now just 2 bins // 2 bins is the standard. However for McStas simulation data it may make // sense to // increase this number for better initial visual effect auto axis = HistogramData::BinEdges{shortestTOF - 1, longestTOF + 1}; // ensure that specified name is given to workspace (eventWS) when added to // outputGroup for (auto eventWS : allEventWS) { const auto ws = eventWS.first; ws->setAllX(axis); AnalysisDataService::Instance().addOrReplace(eventWS.second, ws); scatteringWSNames.emplace_back(eventWS.second); } return scatteringWSNames; }
/** * Computed the normalization for the input workspace. Results are stored in * m_normWS * @param otherValues * @param affineTrans */ void MDNormSCD::calculateNormalization( const std::vector<coord_t> &otherValues, const Kernel::Matrix<coord_t> &affineTrans) { API::MatrixWorkspace_const_sptr integrFlux = getProperty("FluxWorkspace"); integrFlux->getXMinMax(m_kiMin, m_kiMax); API::MatrixWorkspace_const_sptr solidAngleWS = getProperty("SolidAngleWorkspace"); const auto &exptInfoZero = *(m_inputWS->getExperimentInfo(0)); typedef Kernel::PropertyWithValue<std::vector<double>> VectorDoubleProperty; auto *rubwLog = dynamic_cast<VectorDoubleProperty *>(exptInfoZero.getLog("RUBW_MATRIX")); if (!rubwLog) { throw std::runtime_error( "Wokspace does not contain a log entry for the RUBW matrix." "Cannot continue."); } else { Kernel::DblMatrix rubwValue( (*rubwLog)()); // includes the 2*pi factor but not goniometer for now :) m_rubw = exptInfoZero.run().getGoniometerMatrix() * rubwValue; m_rubw.Invert(); } const double protonCharge = exptInfoZero.run().getProtonCharge(); auto instrument = exptInfoZero.getInstrument(); std::vector<detid_t> detIDs = instrument->getDetectorIDs(true); // Prune out those that are part of a group and simply leave the head of the // group detIDs = removeGroupedIDs(exptInfoZero, detIDs); // Mappings const int64_t ndets = static_cast<int64_t>(detIDs.size()); const detid2index_map fluxDetToIdx = integrFlux->getDetectorIDToWorkspaceIndexMap(); const detid2index_map solidAngDetToIdx = solidAngleWS->getDetectorIDToWorkspaceIndexMap(); auto prog = make_unique<API::Progress>(this, 0.3, 1.0, ndets); PARALLEL_FOR1(integrFlux) for (int64_t i = 0; i < ndets; i++) { PARALLEL_START_INTERUPT_REGION const auto detID = detIDs[i]; double theta(0.0), phi(0.0); bool skip(false); try { auto spectrum = getThetaPhi(detID, exptInfoZero, theta, phi); if (spectrum->isMonitor() || spectrum->isMasked()) continue; } catch ( std::exception &) // detector might not exist or has no been included // in grouping { skip = true; // Intel compiler has a problem with continue inside a catch // inside openmp... } if (skip) continue; // Intersections auto intersections = calculateIntersections(theta, phi); if (intersections.empty()) continue; // get the flux spetrum number size_t wsIdx = fluxDetToIdx.find(detID)->second; // Get solid angle for this contribution double solid = solidAngleWS->readY(solidAngDetToIdx.find(detID)->second)[0] * protonCharge; // -- calculate integrals for the intersection -- // momentum values at intersections auto intersectionsBegin = intersections.begin(); std::vector<double> xValues(intersections.size()), yValues(intersections.size()); { // copy momenta to xValues auto x = xValues.begin(); for (auto it = intersectionsBegin; it != intersections.end(); ++it, ++x) { *x = (*it)[3]; } } // calculate integrals at momenta from xValues by interpolating between // points in spectrum sp // of workspace integrFlux. The result is stored in yValues calcIntegralsForIntersections(xValues, *integrFlux, wsIdx, yValues); // Compute final position in HKL const size_t vmdDims = intersections.front().size(); // pre-allocate for efficiency and copy non-hkl dim values into place std::vector<coord_t> pos(vmdDims + otherValues.size()); std::copy(otherValues.begin(), otherValues.end(), pos.begin() + vmdDims - 1); pos.push_back(1.); for (auto it = intersectionsBegin + 1; it != intersections.end(); ++it) { const auto &curIntSec = *it; const auto &prevIntSec = *(it - 1); // the full vector isn't used so compute only what is necessary double delta = curIntSec[3] - prevIntSec[3]; if (delta < 1e-07) continue; // Assume zero contribution if difference is small // Average between two intersections for final position std::transform(curIntSec.getBareArray(), curIntSec.getBareArray() + vmdDims - 1, prevIntSec.getBareArray(), pos.begin(), VectorHelper::SimpleAverage<coord_t>()); std::vector<coord_t> posNew = affineTrans * pos; size_t linIndex = m_normWS->getLinearIndexAtCoord(posNew.data()); if (linIndex == size_t(-1)) continue; // index of the current intersection size_t k = static_cast<size_t>(std::distance(intersectionsBegin, it)); // signal = integral between two consecutive intersections double signal = (yValues[k] - yValues[k - 1]) * solid; PARALLEL_CRITICAL(updateMD) { signal += m_normWS->getSignalAt(linIndex); m_normWS->setSignalAt(linIndex, signal); } } prog->report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/** * Return the confidence with with this algorithm can load the file * @param eventEntries map of the file entries that have events * @param outputGroup pointer to the workspace group * @param nxFile Reads data from inside first first top entry */ void LoadMcStas::readEventData( const std::map<std::string, std::string> &eventEntries, WorkspaceGroup_sptr &outputGroup, ::NeXus::File &nxFile) { std::string filename = getPropertyValue("Filename"); auto entries = nxFile.getEntries(); // will assume that each top level entry contain one mcstas // generated IDF and any event data entries within this top level // entry are data collected for that instrument // This code for loading the instrument is for now adjusted code from // ExperimentalInfo. // Close data folder and go back to top level. Then read and close the // Instrument folder. nxFile.closeGroup(); Geometry::Instrument_sptr instrument; // Initialize progress reporting int reports = 2; const double progressFractionInitial = 0.1; Progress progInitial(this, 0.0, progressFractionInitial, reports); try { nxFile.openGroup("instrument", "NXinstrument"); std::string instrumentXML; nxFile.openGroup("instrument_xml", "NXnote"); nxFile.readData("data", instrumentXML); nxFile.closeGroup(); nxFile.closeGroup(); progInitial.report("Loading instrument"); Geometry::InstrumentDefinitionParser parser; std::string instrumentName = "McStas"; parser.initialize(filename, instrumentName, instrumentXML); std::string instrumentNameMangled = parser.getMangledName(); // Check whether the instrument is already in the InstrumentDataService if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) { // If it does, just use the one from the one stored there instrument = InstrumentDataService::Instance().retrieve(instrumentNameMangled); } else { // Really create the instrument instrument = parser.parseXML(NULL); // Add to data service for later retrieval InstrumentDataService::Instance().add(instrumentNameMangled, instrument); } } catch (...) { // Loader should not stop if there is no IDF.xml g_log.warning() << "\nCould not find the instrument description in the Nexus file:" << filename << " Ignore evntdata from data file" << std::endl; return; } // Finished reading Instrument. Then open new data folder again nxFile.openGroup("data", "NXdetector"); // create and prepare an event workspace ready to receive the mcstas events progInitial.report("Set up EventWorkspace"); EventWorkspace_sptr eventWS(new EventWorkspace()); // initialize, where create up front number of eventlists = number of // detectors eventWS->initialize(instrument->getNumberDetectors(), 1, 1); // Set the units eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); eventWS->setYUnit("Counts"); // set the instrument eventWS->setInstrument(instrument); // assign detector ID to eventlists std::vector<detid_t> detIDs = instrument->getDetectorIDs(); for (size_t i = 0; i < instrument->getNumberDetectors(); i++) { eventWS->getEventList(i).addDetectorID(detIDs[i]); // spectrum number are treated as equal to detector IDs for McStas data eventWS->getEventList(i).setSpectrumNo(detIDs[i]); } // the one is here for the moment for backward compatibility eventWS->rebuildSpectraMapping(true); bool isAnyNeutrons = false; // to store shortest and longest recorded TOF double shortestTOF(0.0); double longestTOF(0.0); const size_t numEventEntries = eventEntries.size(); Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2); for (auto eit = eventEntries.begin(); eit != eventEntries.end(); ++eit) { std::string dataName = eit->first; std::string dataType = eit->second; // open second level entry nxFile.openGroup(dataName, dataType); std::vector<double> data; nxFile.openData("events"); progEntries.report("read event data from nexus"); // Need to take into account that the nexus readData method reads a // multi-column data entry // into a vector // The number of data column for each neutron is here hardcoded to (p, x, // y, n, id, t) // Thus we have // column 0 : p neutron wight // column 1 : x x coordinate // column 2 : y y coordinate // column 3 : n accumulated number of neutrons // column 4 : id pixel id // column 5 : t time // get info about event data ::NeXus::Info id_info = nxFile.getInfo(); if (id_info.dims.size() != 2) { g_log.error() << "Event data in McStas nexus file not loaded. Expected " "event data block to be two dimensional" << std::endl; return; } int64_t nNeutrons = id_info.dims[0]; int64_t numberOfDataColumn = id_info.dims[1]; if (nNeutrons && numberOfDataColumn != 6) { g_log.error() << "Event data in McStas nexus file expecting 6 columns" << std::endl; return; } if (isAnyNeutrons == false && nNeutrons > 0) isAnyNeutrons = true; std::vector<int64_t> start(2); std::vector<int64_t> step(2); // read the event data in blocks. 1 million event is 1000000*6*8 doubles // about 50Mb int64_t nNeutronsInBlock = 1000000; int64_t nOfFullBlocks = nNeutrons / nNeutronsInBlock; int64_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock; // sum over number of blocks + 1 to cover the remainder for (int64_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) { if (iBlock == nOfFullBlocks) { // read remaining neutrons start[0] = nOfFullBlocks * nNeutronsInBlock; start[1] = 0; step[0] = nRemainingNeutrons; step[1] = numberOfDataColumn; } else { // read neutrons in a full block start[0] = iBlock * nNeutronsInBlock; start[1] = 0; step[0] = nNeutronsInBlock; step[1] = numberOfDataColumn; } const int64_t nNeutronsForthisBlock = step[0]; // number of neutrons read for this block data.resize(nNeutronsForthisBlock * numberOfDataColumn); // Check that the type is what it is supposed to be if (id_info.type == ::NeXus::FLOAT64) { nxFile.getSlab(&data[0], start, step); } else { g_log.warning() << "Entry event field is not FLOAT64! It will be skipped.\n"; continue; } // populate workspace with McStas events const detid2index_map detIDtoWSindex_map = eventWS->getDetectorIDToWorkspaceIndexMap(true); progEntries.report("read event data into workspace"); for (int64_t in = 0; in < nNeutronsForthisBlock; in++) { const int detectorID = static_cast<int>(data[4 + numberOfDataColumn * in]); const double detector_time = data[5 + numberOfDataColumn * in] * 1.0e6; // convert to microseconds if (in == 0 && iBlock == 0) { shortestTOF = detector_time; longestTOF = detector_time; } else { if (detector_time < shortestTOF) shortestTOF = detector_time; if (detector_time > longestTOF) longestTOF = detector_time; } const size_t workspaceIndex = detIDtoWSindex_map.find(detectorID)->second; int64_t pulse_time = 0; // eventWS->getEventList(workspaceIndex) += // TofEvent(detector_time,pulse_time); // eventWS->getEventList(workspaceIndex) += TofEvent(detector_time); eventWS->getEventList(workspaceIndex) += WeightedEvent( detector_time, pulse_time, data[numberOfDataColumn * in], 1.0); } } // end reading over number of blocks of an event dataset // nxFile.getData(data); nxFile.closeData(); nxFile.closeGroup(); } // end reading over number of event datasets // Create a default TOF-vector for histogramming, for now just 2 bins // 2 bins is the standard. However for McStas simulation data it may make // sense to // increase this number for better initial visual effect Kernel::cow_ptr<MantidVec> axis; MantidVec &xRef = axis.access(); xRef.resize(2, 0.0); // if ( nNeutrons > 0) if (isAnyNeutrons) { xRef[0] = shortestTOF - 1; // Just to make sure the bins hold it all xRef[1] = longestTOF + 1; } // Set the binning axis eventWS->setAllX(axis); // ensure that specified name is given to workspace (eventWS) when added to // outputGroup std::string nameOfGroupWS = getProperty("OutputWorkspace"); std::string nameUserSee = std::string("EventData_") + nameOfGroupWS; std::string extraProperty = "Outputworkspace_dummy_" + boost::lexical_cast<std::string>(m_countNumWorkspaceAdded); declareProperty(new WorkspaceProperty<Workspace>(extraProperty, nameUserSee, Direction::Output)); setProperty(extraProperty, boost::static_pointer_cast<Workspace>(eventWS)); m_countNumWorkspaceAdded++; // need to increment to ensure extraProperty are // unique outputGroup->addWorkspace(eventWS); }
int PeakIntegration::fitneighbours(int ipeak, std::string det_name, int x0, int y0, int idet, double qspan, PeaksWorkspace_sptr &Peaks, const detid2index_map &pixel_to_wi) { UNUSED_ARG(ipeak); UNUSED_ARG(det_name); UNUSED_ARG(x0); UNUSED_ARG(y0); Geometry::IPeak &peak = Peaks->getPeak(ipeak); // Number of slices int TOFmax = 0; IAlgorithm_sptr slice_alg = createChildAlgorithm("IntegratePeakTimeSlices"); slice_alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputW); std::ostringstream tab_str; tab_str << "LogTable" << ipeak; slice_alg->setPropertyValue("OutputWorkspace", tab_str.str()); slice_alg->setProperty<PeaksWorkspace_sptr>("Peaks", Peaks); slice_alg->setProperty("PeakIndex", ipeak); slice_alg->setProperty("PeakQspan", qspan); int nPixels = std::max<int>(0, getProperty("NBadEdgePixels")); slice_alg->setProperty("NBadEdgePixels", nPixels); slice_alg->executeAsChildAlg(); Mantid::API::MemoryManager::Instance().releaseFreeMemory(); MantidVec &Xout = outputW->dataX(idet); MantidVec &Yout = outputW->dataY(idet); MantidVec &Eout = outputW->dataE(idet); TableWorkspace_sptr logtable = slice_alg->getProperty("OutputWorkspace"); peak.setIntensity(slice_alg->getProperty("Intensity")); peak.setSigmaIntensity(slice_alg->getProperty("SigmaIntensity")); TOFmax = static_cast<int>(logtable->rowCount()); for (int iTOF = 0; iTOF < TOFmax; iTOF++) { Xout[iTOF] = logtable->getRef<double>(std::string("Time"), iTOF); if (m_IC) // Ikeda-Carpenter fit { Yout[iTOF] = logtable->getRef<double>(std::string("TotIntensity"), iTOF); Eout[iTOF] = logtable->getRef<double>(std::string("TotIntensityError"), iTOF); } else { Yout[iTOF] = logtable->getRef<double>(std::string("ISAWIntensity"), iTOF); Eout[iTOF] = logtable->getRef<double>(std::string("ISAWIntensityError"), iTOF); } } outputW->getSpectrum(idet)->clearDetectorIDs(); // Find the pixel ID at that XY position on the rectangular detector int pixelID = peak.getDetectorID(); // det->getAtXY(x0,y0)->getID(); // Find the corresponding workspace index, if any auto wiEntry = pixel_to_wi.find(pixelID); if (wiEntry != pixel_to_wi.end()) { size_t wi = wiEntry->second; // Set detectorIDs outputW->getSpectrum(idet) ->addDetectorIDs(inputW->getSpectrum(wi)->getDetectorIDs()); } return TOFmax - 1; }