/** Convert a SPICE 2D Det MatrixWorkspace to MDEvents and append to an * MDEventWorkspace * It is optional to use a virtual instrument or copy from input data workspace * @brief ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents * @param dataws :: data matrix workspace * @param usevirtual :: boolean flag to use virtual instrument * @param startdetid :: starting detid for detectors from this workspace mapping * to virtual instrument in MDEventWorkspace * @param scannumber :: scan number * @param runnumber :: run number for all MDEvents created from this matrix * @param measuretime :: duration (time) to measure this point * @param monitor_counts :: monitor counts; add to ExpInfo * workspace */ void ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents( MatrixWorkspace_sptr dataws, bool usevirtual, const detid_t &startdetid, const int scannumber, const int runnumber, double measuretime, int monitor_counts) { // Create transformation matrix from which the transformation is Kernel::DblMatrix rotationMatrix; setupTransferMatrix(dataws, rotationMatrix); g_log.information() << "Before insert new event, output workspace has " << m_outputWS->getNEvents() << "Events.\n"; // Creates a new instance of the MDEventInserte to output workspace MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 = boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(m_outputWS); MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3); // Calcualte k_i: it is assumed that all k_i are same for one Pt. // number, i.e., one 2D XML file Kernel::V3D sourcePos = dataws->getInstrument()->getSource()->getPos(); Kernel::V3D samplePos = dataws->getInstrument()->getSample()->getPos(); if (dataws->readX(0).size() != 2) throw std::runtime_error( "Input matrix workspace has wrong dimension in X-axis."); double momentum = 0.5 * (dataws->readX(0)[0] + dataws->readX(0)[1]); Kernel::V3D ki = (samplePos - sourcePos) * (momentum / sourcePos.norm()); g_log.debug() << "Source at " << sourcePos.toString() << ", Norm = " << sourcePos.norm() << ", momentum = " << momentum << "\n" << "k_i = " << ki.toString() << "\n"; // Go though each spectrum to conver to MDEvent size_t numspec = dataws->getNumberHistograms(); double maxsignal = 0; size_t nummdevents = 0; for (size_t iws = 0; iws < numspec; ++iws) { // Get detector positions and signal double signal = dataws->readY(iws)[0]; // Skip event with 0 signal if (fabs(signal) < 0.001) continue; double error = sqrt(fabs(signal)); Kernel::V3D detpos = dataws->getDetector(iws)->getPos(); std::vector<Mantid::coord_t> q_sample(3); // Calculate Q-sample and new detector ID in virtual instrument. Kernel::V3D qlab = convertToQSample(samplePos, ki, detpos, momentum, q_sample, rotationMatrix); detid_t native_detid = dataws->getDetector(iws)->getID(); detid_t detid = native_detid + startdetid; // Insert inserter.insertMDEvent( static_cast<float>(signal), static_cast<float>(error * error), static_cast<uint16_t>(runnumber), detid, q_sample.data()); updateQRange(q_sample); g_log.debug() << "Q-lab = " << qlab.toString() << "\n"; g_log.debug() << "Insert DetID " << detid << ", signal = " << signal << ", with q_sample = " << q_sample[0] << ", " << q_sample[1] << ", " << q_sample[2] << "\n"; // Update some statistical inforamtion if (signal > maxsignal) maxsignal = signal; ++nummdevents; } g_log.information() << "Imported Matrixworkspace of run number " << runnumber << ": Max. Signal = " << maxsignal << ", Add " << nummdevents << " MDEvents " << "\n"; // Add experiment info including instrument, goniometer and run number ExperimentInfo_sptr expinfo = boost::make_shared<ExperimentInfo>(); if (usevirtual) expinfo->setInstrument(m_virtualInstrument); else { Geometry::Instrument_const_sptr tmp_inst = dataws->getInstrument(); expinfo->setInstrument(tmp_inst); } expinfo->mutableRun().setGoniometer(dataws->run().getGoniometer(), false); int scan_run_number = scannumber * 1000 + runnumber; expinfo->mutableRun().addProperty("run_number", scan_run_number); expinfo->mutableRun().addProperty("duration", measuretime); expinfo->mutableRun().addProperty("monitor", monitor_counts); // Add all the other propertys from original data workspace const std::vector<Kernel::Property *> vec_property = dataws->run().getProperties(); for (auto property : vec_property) { expinfo->mutableRun().addProperty(property->clone()); } m_outputWS->addExperimentInfo(expinfo); }
/** * Copy over the metadata from the input matrix workspace to output *MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace where metadata are copied to. *The source of the metadata is the input matrix workspace * */ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const { // found detector which is not a monitor to get proper bin boundaries. size_t spectra_index(0); bool dector_found(false); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { try { auto det = m_InWS2D->getDetector(i); if (!det->isMonitor()) { spectra_index = i; dector_found = true; g_log.debug() << "Using spectra N " << i << " as the source of the bin " "boundaries for the " "resolution corrections \n"; break; } } catch (...) { } } if (!dector_found) g_log.warning() << "No detectors in the workspace are associated with " "spectra. Using spectrum 0 trying to retrieve the bin " "boundaries \n"; // retrieve representative bin boundaries MantidVec binBoundaries = m_InWS2D->readX(spectra_index); // check if the boundaries transformation is necessary if (m_Convertor->getUnitConversionHelper().isUnitConverted()) { if (!dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) { g_log.information() << " ConvertToMD converts input workspace units, but " "the bin boundaries are copied from the first " "workspace spectra. The resolution estimates can " "be incorrect if unit conversion depends on " "spectra number.\n"; UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper(); unitConv.updateConversion(spectra_index); for (double &binBoundarie : binBoundaries) { binBoundarie = unitConv.convertUnits(binBoundarie); } } // sort bin boundaries in case if unit transformation have swapped them. if (binBoundaries[0] > binBoundaries.back()) { g_log.information() << "Bin boundaries are not arranged monotonously. " "Sorting performed\n"; std::sort(binBoundaries.begin(), binBoundaries.end()); } } // Replacement for SpectraDetectorMap::createIDGroupsMap using the ISpectrum // objects instead auto mapping = boost::make_shared<det2group_map>(); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { const auto &dets = m_InWS2D->getSpectrum(i).getDetectorIDs(); if (!dets.empty()) { mapping->emplace(*dets.begin(), std::vector<detid_t>(dets.begin(), dets.end())); } } // The last experiment info should always be the one that refers // to latest converting workspace. All others should have had this // information set already uint16_t nexpts = mdEventWS->getNumExperimentInfo(); if (nexpts > 0) { ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(static_cast<uint16_t>(nexpts - 1)); expt->mutableRun().storeHistogramBinBoundaries(binBoundaries); expt->cacheDetectorGroupings(*mapping); } }
void LoadFlexiNexus::addMetaData(NeXus::File *fin, Workspace_sptr ws, ExperimentInfo_sptr info) { std::map<std::string, std::string>::const_iterator it; // assign a title if ((it = dictionary.find("title")) == dictionary.end()) { const std::string title("No title found"); ws->setTitle(title); } else { if (it->second.find('/') == it->second.npos) { const std::string title(it->second); ws->setTitle(title); } else { if (safeOpenpath(fin, it->second)) { const std::string title = fin->getStrData(); ws->setTitle(title); } } } // assign a sample name std::string sample; if ((it = dictionary.find("sample")) == dictionary.end()) { sample = "No sample found"; } else { if (it->second.find('/') == it->second.npos) { sample = it->second; } else { if (safeOpenpath(fin, it->second)) { sample = fin->getStrData(); } else { sample = "Sampe plath not found"; } } } info->mutableSample().setName(sample); /** * load all the extras into the Run information */ Run &r = info->mutableRun(); auto specialMap = populateSpecialMap(); for (it = dictionary.begin(); it != dictionary.end(); ++it) { if (specialMap.find(it->first) == specialMap.end()) { // not in specials! if (it->second.find('/') == it->second.npos) { r.addProperty(it->first, it->second, true); } else { if (safeOpenpath(fin, it->second)) { NeXus::Info inf = fin->getInfo(); if (inf.type == ::NeXus::CHAR) { std::string data = fin->getStrData(); r.addProperty(it->first, data, true); } else if (inf.type == ::NeXus::FLOAT32 || inf.type == ::NeXus::FLOAT64) { std::vector<double> data; fin->getDataCoerce(data); r.addProperty(it->first, data, true); } else { std::vector<int> data; fin->getDataCoerce(data); r.addProperty(it->first, data, true); } } } } } }
/** Execute the algorithm. */ void LoadDNSSCD::exec() { MultipleFileProperty *multiFileProp = dynamic_cast<MultipleFileProperty *>(getPointerToProperty("Filenames")); if (!multiFileProp) { throw std::logic_error( "Filenames property must have MultipleFileProperty type."); } std::vector<std::string> filenames = VectorHelper::flattenVector(multiFileProp->operator()()); if (filenames.empty()) throw std::invalid_argument("Must specify at least one filename."); // set type of normalization std::string normtype = getProperty("Normalization"); if (normtype == "monitor") { m_normtype = "Monitor"; m_normfactor = 1.0; } else { m_normtype = "Timer"; m_normfactor = 0.0; // error for time should be 0 } g_log.notice() << "The normalization workspace will contain " << m_normtype << ".\n"; ExperimentInfo_sptr expinfo = boost::make_shared<ExperimentInfo>(); API::Run &run = expinfo->mutableRun(); for (auto fname : filenames) { std::map<std::string, std::string> str_metadata; std::map<std::string, double> num_metadata; try { read_data(fname, str_metadata, num_metadata); // if no stop_time, take file_save_time std::string time(str_metadata["stop_time"]); if (time.empty()) { g_log.warning() << "stop_time is empty! File save time will be used instead." << std::endl; time = str_metadata["file_save_time"]; } updateProperties<std::string>(run, str_metadata, time); updateProperties<double>(run, num_metadata, time); } catch (...) { g_log.warning() << "Failed to read file " << fname; g_log.warning() << ". This file will be ignored. " << std::endl; g_log.debug() << boost::current_exception_diagnostic_information() << std::endl; } } if (m_data.empty()) throw std::runtime_error( "No valid DNS files have been provided. Nothing to load."); m_OutWS = MDEventFactory::CreateMDWorkspace(m_nDims, "MDEvent"); m_OutWS->addExperimentInfo(expinfo); // load huber angles from a table workspace if given ITableWorkspace_sptr huberWS = getProperty("LoadHuberFrom"); if (huberWS) { g_log.notice() << "Huber angles will be loaded from " << huberWS->getName() << std::endl; loadHuber(huberWS); } // get wavelength TimeSeriesProperty<double> *wlprop = dynamic_cast<TimeSeriesProperty<double> *>( expinfo->run().getProperty("Lambda")); // assume, that lambda is in nm double wavelength = wlprop->minValue() * 10.0; // needed to estimate extents => minValue run.addProperty("wavelength", wavelength); run.getProperty("wavelength")->setUnits("Angstrom"); fillOutputWorkspace(wavelength); std::string saveHuberTableWS = getProperty("SaveHuberTo"); if (!saveHuberTableWS.empty()) { Mantid::API::ITableWorkspace_sptr huber_table = saveHuber(); setProperty("SaveHuberTo", huber_table); } setProperty("OutputWorkspace", m_OutWS); }