diff --git a/Framework/Algorithms/inc/MantidAlgorithms/FilterEvents.h b/Framework/Algorithms/inc/MantidAlgorithms/FilterEvents.h index 076a14b38039..8ffdd7161b96 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/FilterEvents.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/FilterEvents.h @@ -90,6 +90,9 @@ class DLLExport FilterEvents : public API::Algorithm { /// process splitters given by a MatrixWorkspace void processMatrixSplitterWorkspace(); + /// create event workspace + boost::shared_ptr createEventWorkspaceNoLog(); + /// create output workspaces if the splitters are given in SplittersWorkspace void createOutputWorkspaces(); /// create output workspaces in the case of using TableWorlspace for splitters void createOutputWorkspacesTableSplitterCase(); @@ -127,6 +130,43 @@ class DLLExport FilterEvents : public API::Algorithm { /// (itarget) void convertSplittersWorkspaceToVectors(); + void splitTimeSeriesLogs( + const std::vector *> &int_tsp_vector, + const std::vector *> &dbl_tsp_vector, + const std::vector *> &bool_tsp_vector); + + /// get the names of all the time series properties in the input workspace's + /// Run object + std::vector getTimeSeriesLogNames(); + + void generateSplitterTSP( + std::vector *> &split_tsp_vec); + + void generateSplitterTSPalpha( + std::vector *> &split_tsp_vec); + + /// Add time series property 'Splitter' to each child workspace + void mapSplitterTSPtoWorkspaces( + const std::vector *> &split_tsp_vec); + + void copyNoneSplitLogs( + std::vector *> &int_tsp_name_vector, + std::vector *> &dbl_tsp_name_vector, + std::vector *> &bool_tsp_name_vector); + + template + void + splitTimeSeriesProperty(Kernel::TimeSeriesProperty *tsp, + std::vector &split_datetime_vec, + const int max_target_index); + + void splitDoubleTimeSeriesLogs( + const std::vector *> &dbl_tsp_vector, + std::vector &split_datetime_vec, + const int max_target_index); + + void groupOutputWorkspace(); + DataObjects::EventWorkspace_sptr m_eventWS; DataObjects::SplittersWorkspace_sptr m_splittersWorkspace; DataObjects::TableWorkspace_sptr m_splitterTableWorkspace; @@ -153,24 +193,6 @@ class DLLExport FilterEvents : public API::Algorithm { double m_progress; - /// DOC! TODO - std::vector getTimeSeriesLogNames(); - - Kernel::TimeSplitterType generateSplitters(int wsindex); - - void generateSplitterTSP( - std::vector *> &split_tsp_vec); - - void generateSplitterTSPalpha( - std::vector *> &split_tsp_vec); - - /// - void mapSplitterTSPtoWorkspaces( - const std::vector *> &split_tsp_vec); - - void splitLog(DataObjects::EventWorkspace_sptr eventws, std::string logname, - Kernel::TimeSplitterType &splitters); - /// Base of output workspace's name std::string m_outputWSNameBase; diff --git a/Framework/Algorithms/src/FilterEvents.cpp b/Framework/Algorithms/src/FilterEvents.cpp index 53407693eb89..9f6b05f04ff7 100644 --- a/Framework/Algorithms/src/FilterEvents.cpp +++ b/Framework/Algorithms/src/FilterEvents.cpp @@ -1,10 +1,11 @@ #include "MantidAlgorithms/FilterEvents.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/FileProperty.h" -#include "MantidAPI/TableRow.h" -#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/Run.h" +#include "MantidAPI/SpectrumInfo.h" +#include "MantidAPI/TableRow.h" #include "MantidAPI/WorkspaceFactory.h" +#include "MantidAPI/WorkspaceGroup.h" #include "MantidAPI/WorkspaceProperty.h" #include "MantidAlgorithms/TimeAtSampleStrategyDirect.h" #include "MantidAlgorithms/TimeAtSampleStrategyElastic.h" @@ -13,13 +14,16 @@ #include "MantidDataObjects/TableWorkspace.h" #include "MantidDataObjects/WorkspaceCreation.h" #include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/ArrayProperty.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/ListValidator.h" #include "MantidKernel/LogFilter.h" #include "MantidKernel/PhysicalConstants.h" +#include "MantidKernel/Strings.h" #include "MantidKernel/System.h" #include "MantidKernel/TimeSeriesProperty.h" #include "MantidKernel/VisibleWhenProperty.h" + #include #include @@ -152,6 +156,19 @@ void FilterEvents::init() { declareProperty( "FilterStartTime", "", "Start time for splitters that can be parsed to DateAndTime."); + + declareProperty( + Kernel::make_unique>("TimeSeriesPropertyLogs"), + "List of name of sample logs of TimeSeriesProperty format. " + "They will be either excluded from splitting if ExcludedSpecifiedLogs is " + "specified as True. Or " + "They will be the only TimeSeriesProperty sample logs that will be split " + "to child workspaces."); + + declareProperty("ExcludeSpecifiedLogs", true, + "If true, all the TimeSeriesProperty logs listed will be " + "excluded from duplicating. " + "Otherwise, only those specified logs will be split."); } /** Execution body @@ -183,6 +200,12 @@ void FilterEvents::exec() { else createOutputWorkspacesMatrixCase(); + // clone the properties but TimeSeriesProperty + std::vector *> int_tsp_vector; + std::vector *> dbl_tsp_vector; + std::vector *> bool_tsp_vector; + copyNoneSplitLogs(int_tsp_vector, dbl_tsp_vector, bool_tsp_vector); + // Optionall import corrections m_progress = 0.20; progress(m_progress, "Importing TOF corrections. "); @@ -209,32 +232,15 @@ void FilterEvents::exec() { // assign split_tsp_vector to all the output workspaces! mapSplitterTSPtoWorkspaces(split_tsp_vector); + // split times series property: new way to split events + splitTimeSeriesLogs(int_tsp_vector, dbl_tsp_vector, bool_tsp_vector); + // Optional to group detector - // TODO:FIXME - move this part to a method - if (m_toGroupWS) { - m_progress = 0.9; - progress(m_progress, "Group workspaces"); - - std::string groupname = m_outputWSNameBase; - API::IAlgorithm_sptr groupws = - createChildAlgorithm("GroupWorkspaces", 0.99, 1.00, true); - // groupws->initialize(); - groupws->setAlwaysStoreInADS(true); - groupws->setProperty("InputWorkspaces", m_wsNames); - groupws->setProperty("OutputWorkspace", groupname); - groupws->execute(); - if (!groupws->isExecuted()) { - g_log.error() << "Grouping all output workspaces fails.\n"; - } - } + groupOutputWorkspace(); - // TODO:FIXME - move this part to a method // Form the names of output workspaces std::vector outputwsnames; std::map::iterator miter; - // for (miter = m_outputWorkspacesMap.begin(); - // miter != m_outputWorkspacesMap.end(); ++miter) { - // outputwsnames.push_back(miter->second->name()); for (miter = m_outputWorkspacesMap.begin(); miter != m_outputWorkspacesMap.end(); ++miter) { outputwsnames.push_back(miter->second->getName()); @@ -245,6 +251,72 @@ void FilterEvents::exec() { progress(m_progress, "Completed"); } +//---------------------------------------------------------------------------------------------- +/** Examine whether any spectrum does not have detector + * Warning message will be written out + * @brief FilterEvents::examineEventWS + */ +void FilterEvents::examineAndSortEventWS() { + // get event workspace information + size_t numhist = m_eventWS->getNumberHistograms(); + m_vecSkip.resize(numhist, false); + + // check whether any detector is skipped + if (m_specSkipType == EventFilterSkipNoDetTOFCorr && + m_tofCorrType == NoneCorrect) { + // No TOF correction and skip spectrum only if TOF correction is required + g_log.warning( + "By user's choice, No spectrum will be skipped even if it has " + "no detector."); + } else { + // check detectors whether there is any of them that will be skipped + stringstream msgss; + size_t numskipspec = 0; + size_t numeventsskip = 0; + + const auto &spectrumInfo = m_eventWS->spectrumInfo(); + for (size_t i = 0; i < numhist; ++i) { + if (!spectrumInfo.hasDetectors(i)) { + m_vecSkip[i] = true; + + ++numskipspec; + const EventList &elist = m_eventWS->getSpectrum(i); + numeventsskip += elist.getNumberEvents(); + msgss << i; + if (numskipspec % 10 == 0) + msgss << "\n"; + else + msgss << ","; + } + } // ENDFOR + + if (numskipspec > 0) { + g_log.warning() + << "There are " << numskipspec + << " spectra that do not have detectors. " + << "They will be skipped during filtering. There are total " + << numeventsskip + << " events in those spectra. \nList of these specta is as below:\n" + << msgss.str() << "\n"; + } else { + g_log.notice("There is no spectrum that does not have detectors."); + } + + } // END-IF-ELSE + + // sort events + DataObjects::EventSortType sortType = DataObjects::TOF_SORT; + if (m_filterByPulseTime) + sortType = DataObjects::PULSETIME_SORT; + else + sortType = DataObjects::PULSETIMETOF_SORT; + + // This runs the SortEvents algorithm in parallel + m_eventWS->sortAll(sortType, nullptr); + + return; +} + //---------------------------------------------------------------------------------------------- /** Process input properties */ @@ -290,6 +362,14 @@ void FilterEvents::processAlgorithmProperties() { m_toGroupWS = this->getProperty("GroupWorkspaces"); + if (m_toGroupWS && m_outputWSNameBase.compare(m_eventWS->getName()) == 0) { + std::stringstream errss; + errss << "It is not allowed to group output workspaces into the same name " + "(i..e, OutputWorkspaceBaseName = " << m_outputWSNameBase + << ") as the input workspace to filter events from."; + throw std::invalid_argument(errss.str()); + } + //------------------------------------------------------------------------- // TOF detector/sample correction //------------------------------------------------------------------------- @@ -367,67 +447,267 @@ void FilterEvents::processAlgorithmProperties() { } //---------------------------------------------------------------------------------------------- -/** Examine whether any spectrum does not have detector - * Warning message will be written out - * @brief FilterEvents::examineEventWS +/** group output workspaces + * @brief FilterEvents::groupOutputWorkspace */ -void FilterEvents::examineAndSortEventWS() { - // get event workspace information - size_t numhist = m_eventWS->getNumberHistograms(); - m_vecSkip.resize(numhist, false); +void FilterEvents::groupOutputWorkspace() { + // return if there is no such need + if (!m_toGroupWS) + return; - // check whether any detector is skipped - if (m_specSkipType == EventFilterSkipNoDetTOFCorr && - m_tofCorrType == NoneCorrect) { - // No TOF correction and skip spectrum only if TOF correction is required - g_log.warning( - "By user's choice, No spectrum will be skipped even if it has " - "no detector."); - } else { - // check detectors whether there is any of them that will be skipped - stringstream msgss; - size_t numskipspec = 0; - size_t numeventsskip = 0; + // set progress + m_progress = 0.95; + progress(m_progress, "Group workspaces"); + + std::string groupname = m_outputWSNameBase; + API::IAlgorithm_sptr groupws = + createChildAlgorithm("GroupWorkspaces", 0.95, 1.00, true); + // groupws->initialize(); + groupws->setAlwaysStoreInADS(true); + groupws->setProperty("InputWorkspaces", m_wsNames); + groupws->setProperty("OutputWorkspace", groupname); + groupws->execute(); + if (!groupws->isExecuted()) { + g_log.error("Grouping all output workspaces fails."); + return; + } - const auto &spectrumInfo = m_eventWS->spectrumInfo(); - for (size_t i = 0; i < numhist; ++i) { - if (!spectrumInfo.hasDetectors(i)) { - m_vecSkip[i] = true; + // set the group workspace as output workspace + declareProperty( + make_unique>( + "OutputWorkspace", groupname, Direction::Output), + "Name of the workspace to be created as the output of grouping "); + + AnalysisDataServiceImpl &ads = AnalysisDataService::Instance(); + API::WorkspaceGroup_sptr workspace_group = + boost::dynamic_pointer_cast(ads.retrieve(groupname)); + if (!workspace_group) { + g_log.error( + "Unable to retrieve output workspace from algorithm GroupWorkspaces"); + return; + } + setProperty("OutputWorkspace", workspace_group); - ++numskipspec; - const EventList &elist = m_eventWS->getSpectrum(i); - numeventsskip += elist.getNumberEvents(); - msgss << i; - if (numskipspec % 10 == 0) - msgss << "\n"; + return; +} + +//---------------------------------------------------------------------------------------------- +/** Clone the sample logs that will not be split, including single-value and add + * all the + * TimeSeriesProperty sample logs + * to vectors by their type + * @brief FilterEvents::copyNoneSplitLogs + * @param int_tsp_name_vector :: output + * @param dbl_tsp_name_vector :: output + * @param bool_tsp_name_vector :: output + */ +void FilterEvents::copyNoneSplitLogs( + std::vector *> &int_tsp_name_vector, + std::vector *> &dbl_tsp_name_vector, + std::vector *> &bool_tsp_name_vector) { + // get the user input information + bool exclude_listed_logs = getProperty("ExcludeSpecifiedLogs"); + std::vector tsp_logs = getProperty("TimeSeriesPropertyLogs"); + // convert to set + std::set tsp_logs_set; + for (auto iter = tsp_logs.begin(); iter != tsp_logs.end(); ++iter) + tsp_logs_set.insert(*iter); + + std::set::iterator set_iter; + // initialize + int_tsp_name_vector.clear(); + dbl_tsp_name_vector.clear(); + bool_tsp_name_vector.clear(); + + std::vector prop_vector = m_eventWS->run().getProperties(); + for (size_t i = 0; i < prop_vector.size(); ++i) { + // get property + Property *prop_i = prop_vector[i]; + std::string name_i = prop_i->name(); + + // cast to different type of TimeSeriesProperties + TimeSeriesProperty *dbl_prop = + dynamic_cast *>(prop_i); + TimeSeriesProperty *int_prop = + dynamic_cast *>(prop_i); + TimeSeriesProperty *bool_prop = + dynamic_cast *>(prop_i); + + // check for time series properties + if (dbl_prop || int_prop || bool_prop) { + // check whether the log is there + set_iter = tsp_logs_set.find(name_i); + if (exclude_listed_logs && set_iter != tsp_logs_set.end()) { + // exclude all the listed tsp logs and this log name is in the set + // skip + g_log.warning() << "Skip splitting sample log " << name_i << "\n"; + continue; + } else if (!exclude_listed_logs && set_iter == tsp_logs_set.end()) { + // include all the listed tsp logs to split but this log name is NOT in + // the set + // skip + g_log.warning() << "Skip splitting sample log " << name_i << "\n"; + continue; + } + + // insert the time series property to proper target vector + if (dbl_prop) { + // is double time series property + dbl_tsp_name_vector.push_back(dbl_prop); + } else if (int_prop) { + // is integer time series property + int_tsp_name_vector.push_back(int_prop); + } else if (bool_prop) { + // is integer time series property + bool_tsp_name_vector.push_back(bool_prop); + continue; + } + + } else { + // non time series properties + // single value property: copy to the new workspace + std::map::iterator ws_iter; + for (ws_iter = m_outputWorkspacesMap.begin(); + ws_iter != m_outputWorkspacesMap.end(); ++ws_iter) { + + std::string value_i = prop_i->value(); + double double_v; + int int_v; + if (Strings::convert(value_i, double_v) != 0) // double value + ws_iter->second->mutableRun().addProperty(name_i, double_v, true); + else if (Strings::convert(value_i, int_v) != 0) + ws_iter->second->mutableRun().addProperty(name_i, int_v, true); else - msgss << ","; + ws_iter->second->mutableRun().addProperty(name_i, value_i, true); } - } // ENDFOR + } + } // end for - if (numskipspec > 0) { - g_log.warning() - << "There are " << numskipspec - << " spectra that do not have detectors. " - << "They will be skipped during filtering. There are total " - << numeventsskip - << " events in those spectra. \nList of these specta is as below:\n" - << msgss.str() << "\n"; + return; +} + +//---------------------------------------------------------------------------------------------- +/** Split all the TimeSeriesProperty sample logs to all the output workspace + * @brief FilterEvents::splitTimeSeriesLogs + * @param int_tsp_vector + * @param dbl_tsp_vector + * @param bool_tsp_vector + */ +void FilterEvents::splitTimeSeriesLogs( + const std::vector *> &int_tsp_vector, + const std::vector *> &dbl_tsp_vector, + const std::vector *> &bool_tsp_vector) { + // get split times by converting vector of int64 to Time + std::vector split_datetime_vec; + + // convert splitters workspace to vectors used by TableWorkspace and + // MatrixWorkspace splitters + if (m_useSplittersWorkspace) { + convertSplittersWorkspaceToVectors(); + } + + // convert splitter time vector to DateAndTime format + split_datetime_vec.resize(m_vecSplitterTime.size()); + for (size_t i = 0; i < m_vecSplitterTime.size(); ++i) { + DateAndTime split_time(m_vecSplitterTime[i]); + split_datetime_vec[i] = split_time; + } + + // find the maximum index of the outputs' index + std::set::iterator target_iter; + int max_target_index = 0; + for (target_iter = m_targetWorkspaceIndexSet.begin(); + target_iter != m_targetWorkspaceIndexSet.end(); ++target_iter) { + if (*target_iter > max_target_index) + max_target_index = *target_iter; + } + g_log.information() << "Maximum target index = " << max_target_index << "\n"; + + // splitters workspace need to have 1 more for left-over events + if (m_useSplittersWorkspace) + ++max_target_index; + + // deal with integer time series property + for (size_t i = 0; i < int_tsp_vector.size(); ++i) { + splitTimeSeriesProperty(int_tsp_vector[i], split_datetime_vec, + max_target_index); + } + + // split double time series property + for (size_t i = 0; i < dbl_tsp_vector.size(); ++i) { + splitTimeSeriesProperty(dbl_tsp_vector[i], split_datetime_vec, + max_target_index); + } + + // deal with bool time series property + for (size_t i_bool = 0; i_bool < bool_tsp_vector.size(); ++i_bool) { + splitTimeSeriesProperty(bool_tsp_vector[i_bool], split_datetime_vec, + max_target_index); + } + + // integrate proton charge + for (int tindex = 0; tindex <= max_target_index; ++tindex) { + // find output workspace + std::map::iterator wsiter; + wsiter = m_outputWorkspacesMap.find(tindex); + if (wsiter == m_outputWorkspacesMap.end()) { + g_log.information() << "Workspace target (indexed as " << tindex + << ") does not have workspace associated.\n"; } else { - g_log.notice("There is no spectrum that does not have detectors."); + DataObjects::EventWorkspace_sptr ws_i = wsiter->second; + ws_i->mutableRun().integrateProtonCharge(); } + } - } // END-IF-ELSE + return; +} - // sort events - DataObjects::EventSortType sortType = DataObjects::TOF_SORT; - if (m_filterByPulseTime) - sortType = DataObjects::PULSETIME_SORT; - else - sortType = DataObjects::PULSETIMETOF_SORT; +//---------------------------------------------------------------------------------------------- +template +void FilterEvents::splitTimeSeriesProperty( + Kernel::TimeSeriesProperty *tsp, + std::vector &split_datetime_vec, + const int max_target_index) { + // skip the sample logs if they are specified + // get property name and etc + std::string property_name = tsp->name(); + // generate new propertys for the source to split to + std::vector *> output_vector; + for (int tindex = 0; tindex <= max_target_index; ++tindex) { + TimeSeriesProperty *new_property = + new TimeSeriesProperty(property_name); + new_property->setUnits(tsp->units()); + output_vector.push_back(new_property); + } - // This runs the SortEvents algorithm in parallel - m_eventWS->sortAll(sortType, nullptr); + // duplicate the time series property if the size is just one + if (tsp->size() == 1) { + // duplicate + for (size_t i_out = 0; i_out < output_vector.size(); ++i_out) { + output_vector[i_out]->addValue(tsp->firstTime(), tsp->firstValue()); + } + } else { + // split log + tsp->splitByTimeVector(split_datetime_vec, m_vecSplitterGroup, + output_vector); + } + + // assign to output workspaces + for (int tindex = 0; tindex <= max_target_index; ++tindex) { + // find output workspace + std::map::iterator wsiter; + wsiter = m_outputWorkspacesMap.find(tindex); + if (wsiter == m_outputWorkspacesMap.end()) { + // unable to find workspace associated with target index + g_log.information() << "Workspace target (" << tindex + << ") does not have workspace associated." + << "\n"; + } else { + // add property to the associated workspace + DataObjects::EventWorkspace_sptr ws_i = wsiter->second; + ws_i->mutableRun().addProperty(output_vector[tindex], true); + } + } return; } @@ -499,72 +779,45 @@ void FilterEvents::convertSplittersWorkspaceToVectors() { m_vecSplitterGroup.clear(); m_vecSplitterTime.clear(); + // define filter-left target index + int no_filter_index = m_maxTargetIndex + 1; + // convert SplittersWorkspace to a set of pairs which can be sorted - size_t num_rows = this->m_splittersWorkspace->rowCount(); - for (size_t irow = 0; irow < num_rows; ++irow) { - Kernel::SplittingInterval splitter = - m_splittersWorkspace->getSplitter(irow); - if (m_vecSplitterTime.size() == 0 || - splitter.start() > m_vecSplitterTime.back() + TOLERANCE) { - m_vecSplitterTime.push_back(splitter.start().totalNanoseconds()); - m_vecSplitterTime.push_back(splitter.stop().totalNanoseconds()); - // 0 stands for not defined - m_vecSplitterGroup.push_back(0); + size_t num_splitters = m_splitters.size(); + int64_t last_entry_time(0); + + // it is assumed that m_splitters is sorted by time + for (size_t i_splitter = 0; i_splitter < num_splitters; ++i_splitter) { + // get splitter + Kernel::SplittingInterval splitter = m_splitters[i_splitter]; + int64_t start_time_i64 = splitter.start().totalNanoseconds(); + int64_t stop_time_i64 = splitter.stop().totalNanoseconds(); + if (m_vecSplitterTime.size() == 0) { + // first entry: add + m_vecSplitterTime.push_back(start_time_i64); + m_vecSplitterTime.push_back(stop_time_i64); + m_vecSplitterGroup.push_back(splitter.index()); + } else if (abs(last_entry_time - start_time_i64) < TOLERANCE) { + // start time is SAME as last entry + m_vecSplitterTime.push_back(stop_time_i64); m_vecSplitterGroup.push_back(splitter.index()); - } else if (splitter.start() < m_vecSplitterTime.back() - TOLERANCE) { - // almost same: then add the spliters.stop() only - m_vecSplitterTime.push_back(splitter.stop().totalNanoseconds()); + } else if (start_time_i64 > last_entry_time + TOLERANCE) { + // start time is way behind. then add an empty one + m_vecSplitterTime.push_back(start_time_i64); + m_vecSplitterTime.push_back(stop_time_i64); + m_vecSplitterGroup.push_back(no_filter_index); m_vecSplitterGroup.push_back(splitter.index()); } else { - // have to insert the somewhere - std::vector::iterator finditer = - std::lower_bound(m_vecSplitterTime.begin(), m_vecSplitterTime.end(), - splitter.start().totalNanoseconds()); - // get the index - size_t split_index = - static_cast(finditer - m_vecSplitterTime.begin()); - if (*finditer - splitter.start().totalNanoseconds() > TOLERANCE) { - // the start time is before one splitter indicated by *finditer: insert - // both - // check - if (m_vecSplitterGroup[split_index] != UNDEFINED_SPLITTING_TARGET) { - std::stringstream errss; - errss << "Tried to insert splitter [" << splitter.start() << ", " - << splitter.stop() << "] but there is " - << "already a time entry with target " - << m_vecSplitterGroup[split_index] << " inside it."; - throw std::runtime_error(errss.str()); - } - // inset the full set - m_vecSplitterTime.insert(finditer, splitter.stop().totalNanoseconds()); - m_vecSplitterTime.insert(finditer, splitter.start().totalNanoseconds()); - // insert the target - m_vecSplitterGroup.insert(m_vecSplitterGroup.begin() + split_index, - static_cast(UNDEFINED_SPLITTING_TARGET)); - m_vecSplitterGroup.insert(m_vecSplitterGroup.begin() + split_index, - static_cast(splitter.index())); - } else if (*finditer - splitter.start().totalNanoseconds() > -TOLERANCE) { - // the start time is an existing entry - // check - if (m_vecSplitterGroup[split_index] != UNDEFINED_SPLITTING_TARGET) { - std::stringstream errss; - errss << "Tried to insert splitter [" << splitter.start() << ", " - << splitter.stop() << "] but there is " - << "already a time entry with target " - << m_vecSplitterGroup[split_index] << " inside it."; - throw std::runtime_error(errss.str()); - } - // inset the stop time - m_vecSplitterTime.insert(finditer + 1, - splitter.stop().totalNanoseconds()); - // insert the target - m_vecSplitterGroup.insert(m_vecSplitterGroup.begin() + split_index + 1, - splitter.index()); - } else { - throw std::runtime_error("This is not a possible situation!"); - } - } // IF-ELSE to add a new entry - } // END-FOR (add all splitters) + // some impossible situation + std::stringstream errorss; + errorss << "New start time " << start_time_i64 + << " is before last entry's time " << last_entry_time; + throw std::runtime_error(errorss.str()); + } + + // update + last_entry_time = m_vecSplitterTime.back(); + } // END-FOR (add all splitters) return; } @@ -807,7 +1060,7 @@ void FilterEvents::createOutputWorkspaces() { } boost::shared_ptr optws = - create(*m_eventWS); + createWithoutLogs(*m_eventWS); m_outputWorkspacesMap.emplace(wsgroup, optws); // Add information, including title and comment, to output workspace @@ -843,16 +1096,19 @@ void FilterEvents::createOutputWorkspaces() { m_wsNames.push_back(wsname.str()); // Set (property) to output workspace and set to ADS - declareProperty( - Kernel::make_unique< - API::WorkspaceProperty>( - propertynamess.str(), wsname.str(), Direction::Output), - "Output"); - setProperty(propertynamess.str(), optws); AnalysisDataService::Instance().addOrReplace(wsname.str(), optws); - ++numoutputws; + // create these output properties + if (!this->m_toGroupWS) { + declareProperty( + Kernel::make_unique< + API::WorkspaceProperty>( + propertynamess.str(), wsname.str(), Direction::Output), + "Output"); + setProperty(propertynamess.str(), optws); + } + ++numoutputws; g_log.debug() << "Created output Workspace of group = " << wsgroup << " Property Name = " << propertynamess.str() << " Workspace name = " << wsname.str() @@ -914,9 +1170,12 @@ void FilterEvents::createOutputWorkspacesMatrixCase() { // create new workspace from input EventWorkspace and all the sample logs // are copied to the new one boost::shared_ptr optws = - create(*m_eventWS); + createWithoutLogs(*m_eventWS); m_outputWorkspacesMap.emplace(wsgroup, optws); + // TODO/ISSUE/NOW - How about comment and info similar to + // createOutputWorkspaces()? + // add to output workspace property std::stringstream propertynamess; if (wsgroup == 0) { @@ -927,21 +1186,27 @@ void FilterEvents::createOutputWorkspacesMatrixCase() { // Inserted this pair to map m_wsNames.push_back(wsname.str()); - - // Set (property) to output workspace and set to ADS - declareProperty(Kernel::make_unique< - API::WorkspaceProperty>( - propertynamess.str(), wsname.str(), Direction::Output), - "Output"); - setProperty(propertynamess.str(), optws); AnalysisDataService::Instance().addOrReplace(wsname.str(), optws); g_log.debug() << "Created output Workspace of group = " << wsgroup - << " Property Name = " << propertynamess.str() << " Workspace name = " << wsname.str() << " with Number of events = " << optws->getNumberEvents() << "\n"; + // Set (property) to output workspace and set to ADS + if (m_toGroupWS) { + declareProperty( + Kernel::make_unique< + API::WorkspaceProperty>( + propertynamess.str(), wsname.str(), Direction::Output), + "Output"); + setProperty(propertynamess.str(), optws); + + g_log.debug() << " Property Name = " << propertynamess.str() << "\n"; + } else { + g_log.debug() << "\n"; + } + // Update progress report m_progress = 0.1 + @@ -995,34 +1260,43 @@ void FilterEvents::createOutputWorkspacesTableSplitterCase() { // create new workspace boost::shared_ptr optws = - create(*m_eventWS); + createWithoutLogs(*m_eventWS); m_outputWorkspacesMap.emplace(wsgroup, optws); + // TODO/NOW/ISSUE -- How about comment and info? + // add to output workspace property - std::stringstream propertynamess; - if (wsgroup < 0) { - propertynamess << "OutputWorkspace_unfiltered"; - } else { - propertynamess << "OutputWorkspace_" << wsgroup; - } // Inserted this pair to map m_wsNames.push_back(wsname.str()); // Set (property) to output workspace and set to ADS - declareProperty(Kernel::make_unique< - API::WorkspaceProperty>( - propertynamess.str(), wsname.str(), Direction::Output), - "Output"); - setProperty(propertynamess.str(), optws); AnalysisDataService::Instance().addOrReplace(wsname.str(), optws); g_log.debug() << "Created output Workspace of group = " << wsgroup - << " Property Name = " << propertynamess.str() << " Workspace name = " << wsname.str() << " with Number of events = " << optws->getNumberEvents() << "\n"; + if (this->m_toGroupWS) { + std::stringstream propertynamess; + if (wsgroup < 0) { + propertynamess << "OutputWorkspace_unfiltered"; + } else { + propertynamess << "OutputWorkspace_" << wsgroup; + } + declareProperty( + Kernel::make_unique< + API::WorkspaceProperty>( + propertynamess.str(), wsname.str(), Direction::Output), + "Output"); + setProperty(propertynamess.str(), optws); + + g_log.debug() << " Property Name = " << propertynamess.str() << "\n"; + } else { + g_log.debug() << "\n"; + } + // Update progress report m_progress = 0.1 + @@ -1310,52 +1584,7 @@ void FilterEvents::filterEventsBySplitters(double progressamount) { // Split the sample logs in each target workspace. progress(0.1 + progressamount, "Splitting logs"); - if (!m_splitSampleLogs) { - // Skip if choice is no - g_log.notice("Sample logs are not split by user's choice."); - return; - } - - auto lognames = this->getTimeSeriesLogNames(); - g_log.debug() << "[FilterEvents D1214]: Number of TimeSeries Logs = " - << lognames.size() << " to " << m_outputWorkspacesMap.size() - << " outptu workspaces. \n"; - - double numws = static_cast(m_outputWorkspacesMap.size()); - double outwsindex = 0.; - - // split sample logs from original workspace to new one - for (auto &ws : m_outputWorkspacesMap) { - int wsindex = ws.first; - DataObjects::EventWorkspace_sptr opws = ws.second; - - // Generate a list of splitters for current output workspace - Kernel::TimeSplitterType splitters = generateSplitters(wsindex); - - g_log.debug() << "[FilterEvents D1215]: Output workspace Index " << wsindex - << ": Name = " << opws->getName() - << "; Number of splitters = " << splitters.size() << ".\n"; - - // Skip output workspace has ZERO splitters - if (splitters.empty()) { - g_log.warning() << "[FilterEvents] Workspace " << opws->getName() - << " Indexed @ " << wsindex - << " won't have logs splitted due to zero splitter size. " - << ".\n"; - continue; - } - - // Split log - // FIXME-TODO: SHALL WE MOVE THIS PART OUTSIDE OF THIS METHOD? - size_t numlogs = lognames.size(); - for (size_t ilog = 0; ilog < numlogs; ++ilog) { - this->splitLog(opws, lognames[ilog], splitters); - } - opws->mutableRun().integrateProtonCharge(); - - progress(0.1 + progressamount + outwsindex / numws * 0.2, "Splitting logs"); - outwsindex += 1.; - } + return; } /** Split events by splitters represented by vector @@ -1370,24 +1599,24 @@ void FilterEvents::filterEventsByVectorSplitters(double progressamount) { "input/source EventWorkspace = " << numberOfSpectra << ".\n"; + // check for option FilterByTime if (m_filterByPulseTime) { size_t num_proton_charges = m_eventWS->run().getProperty("proton_charge")->size(); - if (num_proton_charges < m_vecSplitterTime.size()) - throw runtime_error("It is not a good practice to split fast event by " - "pulse time when there are more splitters than pulse " - "times."); - else + if (num_proton_charges < m_vecSplitterTime.size()) { + // throw an exception if there more splitters than proton charges + std::stringstream errmsg; + errmsg << "It is not proper to split fast event 'By PulseTime'', when " + "there are " + "more splitters (" << m_vecSplitterTime.size() + << ") than pulse time " + "log entries (" << num_proton_charges << ")"; + throw runtime_error(errmsg.str()); + } else g_log.warning("User should understand the inaccurancy to filter events " "by pulse time."); } - /* - for (size_t i = 0; i < m_vecSplitterGroup.size(); ++i) - std::cout << "splitter " << i << ": " << m_vecSplitterTime[i] << ", " - << m_vecSplitterGroup[i] << "\n"; - */ - PARALLEL_FOR_NO_WSP_CHECK() for (int64_t iws = 0; iws < int64_t(numberOfSpectra); ++iws) { PARALLEL_START_INTERUPT_REGION @@ -1449,152 +1678,9 @@ void FilterEvents::filterEventsByVectorSplitters(double progressamount) { max_target_index = *target_iter; } - // convert vector of int64 to Time - std::vector split_datetime_vec(m_vecSplitterTime.size()); - for (size_t i = 0; i < m_vecSplitterTime.size(); ++i) { - DateAndTime split_time(m_vecSplitterTime[i]); - split_datetime_vec[i] = split_time; - } - - for (auto property : m_eventWS->run().getProperties()) { - // insert 0 even if it is empty for contructing a vector - g_log.debug() << "Process sample log" << property->name() << "\n"; - TimeSeriesProperty *dbl_prop = - dynamic_cast *>(property); - TimeSeriesProperty *int_prop = - dynamic_cast *>(property); - if (dbl_prop) { - std::vector *> output_vector; - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - TimeSeriesProperty *new_property = - new TimeSeriesProperty(dbl_prop->name()); - new_property->setUnits(dbl_prop->units()); - output_vector.push_back(new_property); - } - - // split - dbl_prop->splitByTimeVector(split_datetime_vec, m_vecSplitterGroup, - output_vector); - - // set to output workspace - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - // find output workspace - std::map::iterator wsiter; - wsiter = m_outputWorkspacesMap.find(tindex); - if (wsiter == m_outputWorkspacesMap.end()) { - ; - // g_log.error() << "Workspace target (" << tindex - // << ") does not have workspace associated." - // << "\n"; - } else { - DataObjects::EventWorkspace_sptr ws_i = wsiter->second; - ws_i->mutableRun().addProperty(output_vector[tindex], true); - } - } - - } else if (int_prop) { - // integer log - std::vector *> output_vector; - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - TimeSeriesProperty *new_property = - new TimeSeriesProperty(int_prop->name()); - new_property->setUnits(int_prop->units()); - output_vector.push_back(new_property); - } - - // split - int_prop->splitByTimeVector(split_datetime_vec, m_vecSplitterGroup, - output_vector); - - // set to output workspace - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - // find output workspace - std::map::iterator wsiter; - wsiter = m_outputWorkspacesMap.find(tindex); - if (wsiter == m_outputWorkspacesMap.end()) { - g_log.error() << "Workspace target (" << tindex - << ") does not have workspace associated." - << "\n"; - } else { - DataObjects::EventWorkspace_sptr ws_i = wsiter->second; - ws_i->mutableRun().addProperty(output_vector[tindex], true); - } - } - } else { - // TODO:FIXME - Copy the prperty! - // set to output workspace ??? -- may not be needed! as the way how output - // workspace is created - } - } - - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - // set to output workspace - for (int tindex = 0; tindex <= max_target_index; ++tindex) { - // find output workspace - std::map::iterator wsiter; - wsiter = m_outputWorkspacesMap.find(tindex); - if (wsiter == m_outputWorkspacesMap.end()) { - g_log.error() << "Workspace target (" << tindex - << ") does not have workspace associated." - << "\n"; - } else { - DataObjects::EventWorkspace_sptr ws_i = wsiter->second; - ws_i->mutableRun().integrateProtonCharge(); - } - } - } - return; } -/** Generate splitters for specified workspace index as a subset of - * m_splitters - */ -Kernel::TimeSplitterType FilterEvents::generateSplitters(int wsindex) { - Kernel::TimeSplitterType splitters; - for (const auto &splitter : m_splitters) { - int index = splitter.index(); - if (index == wsindex) { - splitters.push_back(splitter); - } - } - return splitters; -} - -/** Split a log by splitters - */ -void FilterEvents::splitLog(EventWorkspace_sptr eventws, std::string logname, - TimeSplitterType &splitters) { - // cast property to both double TimeSeriesProperty and IntSeriesProperty - Kernel::TimeSeriesProperty *dbl_prop = - dynamic_cast *>( - eventws->mutableRun().getProperty(logname)); - Kernel::TimeSeriesProperty *int_prop = - dynamic_cast *>( - eventws->mutableRun().getProperty(logname)); - - if (!dbl_prop && !int_prop) { - std::stringstream errmsg; - errmsg << "Log " << logname - << " is not TimeSeriesProperty or TimeSeriesProperty. " - << "Unable to split."; - throw std::runtime_error(errmsg.str()); - } else { - for (const auto &split : splitters) { - g_log.debug() << "Workspace " << eventws->getName() << ": " - << "log name = " << logname - << ", duration = " << split.duration() << " from " - << split.start() << " to " << split.stop() << ".\n"; - } - - // split log - if (dbl_prop) - dbl_prop->filterByTimes(splitters); - else - int_prop->filterByTimes(splitters); - } -} - //---------------------------------------------------------------------------------------------- /** Generate a vector of integer time series property for each splitter * corresponding to each target (in integer) @@ -1664,9 +1750,6 @@ void FilterEvents::generateSplitterTSP( // add run stop time as a new entry DateAndTime stop_time(m_vecSplitterTime[igrp + 1]); curr_tsp->addValue(stop_time, 0); - - // g_log.warning() << "Add " << "i_group " << igrp << " to i_target " << - // itarget << "\n"; } return; @@ -1774,9 +1857,11 @@ std::vector FilterEvents::getTimeSeriesLogNames() { dynamic_cast *>(ip); Kernel::TimeSeriesProperty *inttimeprop = dynamic_cast *>(ip); + Kernel::TimeSeriesProperty *booltimeprop = + dynamic_cast *>(ip); // append to vector if it is either double TimeSeries or int TimeSeries - if (dbltimeprop || inttimeprop) { + if (dbltimeprop || inttimeprop || booltimeprop) { std::string pname = ip->name(); lognames.push_back(pname); } diff --git a/Framework/Algorithms/src/GenerateEventsFilter.cpp b/Framework/Algorithms/src/GenerateEventsFilter.cpp index cc2ff8a30b3a..806801bedc03 100644 --- a/Framework/Algorithms/src/GenerateEventsFilter.cpp +++ b/Framework/Algorithms/src/GenerateEventsFilter.cpp @@ -386,8 +386,7 @@ void GenerateEventsFilter::setFilterByTimeOnly() { // Default and thus just one interval std::stringstream ss; - ss << "Time Interval From " << m_startTime << " to " << m_stopTime; - + ss << "Time.Interval.From." << m_startTime << ".To." << m_stopTime; addNewTimeFilterSplitter(m_startTime, m_stopTime, wsindex, ss.str()); } else if (vec_timeintervals.size() == 1) { double timeinterval = vec_timeintervals[0]; @@ -409,7 +408,7 @@ void GenerateEventsFilter::setFilterByTimeOnly() { Kernel::DateAndTime t0(curtime_ns); Kernel::DateAndTime tf(nexttime_ns); std::stringstream ss; - ss << "Time Interval From " << t0 << " to " << tf; + ss << "Time.Interval.From." << t0 << ".to." << tf; addNewTimeFilterSplitter(t0, tf, wsindex, ss.str()); @@ -462,7 +461,7 @@ void GenerateEventsFilter::setFilterByTimeOnly() { Kernel::DateAndTime t0(curtime_ns); Kernel::DateAndTime tf(nexttime_ns); std::stringstream ss; - ss << "Time Interval From " << t0 << " to " << tf; + ss << "Time.Interval.From." << t0 << ".to." << tf; addNewTimeFilterSplitter(t0, tf, wsindex, ss.str()); @@ -661,14 +660,14 @@ void GenerateEventsFilter::processSingleValueFilter(double minvalue, API::TableRow row = m_filterInfoWS->appendRow(); std::stringstream ss; - ss << "Log " << m_dblLog->name() << " From " << minvalue << " To " << maxvalue - << " Value-change-direction "; + ss << "Log." << m_dblLog->name() << ".From." << minvalue << ".To." << maxvalue + << ".Value-change-direction:"; if (filterincrease && filterdecrease) { - ss << " both "; + ss << ".both "; } else if (filterincrease) { - ss << " increase"; + ss << ".increase"; } else { - ss << " decrease"; + ss << ".decrease"; } row << 0 << ss.str(); } @@ -718,14 +717,14 @@ void GenerateEventsFilter::processMultipleValueFilters(double minvalue, // Workgroup information std::stringstream ss; - ss << "Log " << m_dblLog->name() << " From " << lowbound << " To " - << upbound << " Value-change-direction "; + ss << "Log." << m_dblLog->name() << ".From." << lowbound << ".To." + << upbound << ".Value-change-direction:"; if (filterincrease && filterdecrease) { - ss << " both "; + ss << "both"; } else if (filterincrease) { - ss << " increase"; + ss << "increase"; } else { - ss << " decrease"; + ss << "decrease"; }; API::TableRow newrow = m_filterInfoWS->appendRow(); newrow << wsindex << ss.str(); @@ -825,15 +824,12 @@ void GenerateEventsFilter::makeFilterBySingleValue( // Initialize control parameters bool lastGood = false; bool isGood = false; - ; time_duration tol = DateAndTime::durationFromSeconds(TimeTolerance); int numgood = 0; DateAndTime lastTime, currT; DateAndTime start, stop; size_t progslot = 0; - string info; - for (int i = 0; i < m_dblLog->size(); i++) { lastTime = currT; // The new entry @@ -862,7 +858,8 @@ void GenerateEventsFilter::makeFilterBySingleValue( stop = currT; } - addNewTimeFilterSplitter(start, stop, wsindex, info); + std::string empty(""); + addNewTimeFilterSplitter(start, stop, wsindex, empty); // Reset the number of good ones, for next time numgood = 0; @@ -887,9 +884,12 @@ void GenerateEventsFilter::makeFilterBySingleValue( stop = currT - tol; else stop = currT; - addNewTimeFilterSplitter(start, stop, wsindex, info); - numgood = 0; + + std::string empty(""); + addNewTimeFilterSplitter(start, stop, wsindex, empty); } + + return; } //---------------------------------------------------------------------------------------------- @@ -1540,18 +1540,18 @@ void GenerateEventsFilter::processIntegerValueFilter(int minvalue, int maxvalue, while (logvalue <= maxvalue) { stringstream message; if (logvalue + delta - 1 > logvalue) - message << m_intLog->name() << " = [" << logvalue << ", " + message << m_intLog->name() << "=[" << logvalue << "," << logvalue + delta - 1 << "]"; else - message << m_intLog->name() << " = " << logvalue; + message << m_intLog->name() << "=" << logvalue; - message << ". Value change direction: "; + message << ".Value change direction:"; if (filterIncrease && filterDecrease) - message << "Both."; + message << "Both"; else if (filterIncrease) - message << "Increasing. "; + message << "Increasing"; else if (filterDecrease) - message << "Decreasing. "; + message << "Decreasing"; TableRow newrow = m_filterInfoWS->appendRow(); newrow << wsindex << message.str(); diff --git a/Framework/Algorithms/test/FilterEventsTest.h b/Framework/Algorithms/test/FilterEventsTest.h index fbd88b7189bb..fb4fcba64c99 100644 --- a/Framework/Algorithms/test/FilterEventsTest.h +++ b/Framework/Algorithms/test/FilterEventsTest.h @@ -27,6 +27,18 @@ using namespace Mantid::Geometry; using namespace std; +/* TODO LIST + * 1. Remove all Ptest + * 2. Add a new unit test for grouping workspaces in the end + * 3. Add a new unit test for throwing grouping workspaces if name is not vaid + * 4. Add a new unit test for excluding sample logs + * 5. Parallelizing spliting logs? + * 6. Speed test + * 6.1 with or without splitting logs; + * 6.2 different types of splitters workspaces; + * 6.3 old vs new + */ + class FilterEventsTest : public CxxTest::TestSuite { public: // This pair of boilerplate methods prevent the suite being created statically @@ -140,7 +152,7 @@ class FilterEventsTest : public CxxTest::TestSuite { TS_ASSERT(filteredws0); TS_ASSERT_EQUALS(filteredws0->getNumberHistograms(), 10); TS_ASSERT_EQUALS(filteredws0->getSpectrum(0).getNumberEvents(), 4); - TS_ASSERT_EQUALS(filteredws0->run().getProtonCharge(), 10); + TS_ASSERT_EQUALS(filteredws0->run().getProtonCharge(), 2); // check splitter log TS_ASSERT(filteredws0->run().hasProperty("splitter")); @@ -160,7 +172,7 @@ class FilterEventsTest : public CxxTest::TestSuite { AnalysisDataService::Instance().retrieve("FilteredWS01_1")); TS_ASSERT(filteredws1); TS_ASSERT_EQUALS(filteredws1->getSpectrum(1).getNumberEvents(), 16); - TS_ASSERT_EQUALS(filteredws1->run().getProtonCharge(), 11); + TS_ASSERT_EQUALS(filteredws1->run().getProtonCharge(), 3); // check splitter log TS_ASSERT(filteredws0->run().hasProperty("splitter")); @@ -182,7 +194,7 @@ class FilterEventsTest : public CxxTest::TestSuite { AnalysisDataService::Instance().retrieve("FilteredWS01_2")); TS_ASSERT(filteredws2); TS_ASSERT_EQUALS(filteredws2->getSpectrum(1).getNumberEvents(), 21); - TS_ASSERT_EQUALS(filteredws2->run().getProtonCharge(), 21); + TS_ASSERT_EQUALS(filteredws2->run().getProtonCharge(), 3); EventList elist3 = filteredws2->getSpectrum(3); elist3.sortPulseTimeTOF(); @@ -326,6 +338,7 @@ class FilterEventsTest : public CxxTest::TestSuite { std::vector outputwsnames = filter.getProperty("OutputWorkspaceNames"); for (size_t i = 0; i < outputwsnames.size(); ++i) { + std::cout << "Delete output workspace name: " << outputwsnames[i] << "\n"; AnalysisDataService::Instance().remove(outputwsnames[i]); } @@ -925,8 +938,6 @@ class FilterEventsTest : public CxxTest::TestSuite { runstart_i64); TS_ASSERT_EQUALS(splitter2->nthValue(2), 0); - // TODO - Find out the correct value of the splitter log 2 - // Check spectrum 3 of workspace 2 EventList elist3 = filteredws2->getSpectrum(3); elist3.sortPulseTimeTOF(); @@ -954,6 +965,162 @@ class FilterEventsTest : public CxxTest::TestSuite { return; } + /** Test the feature to exclude some sample logs to be split and add to child + * workspaces + * @brief Utest_excludeSampleLogs + */ + void test_excludeSampleLogs() { + // Create EventWorkspace and SplittersWorkspace + int64_t runstart_i64 = 20000000000; + int64_t pulsedt = 100 * 1000 * 1000; + int64_t tofdt = 10 * 1000 * 1000; + size_t numpulses = 5; + + EventWorkspace_sptr inpWS = + createEventWorkspace(runstart_i64, pulsedt, tofdt, numpulses); + AnalysisDataService::Instance().addOrReplace("Test12", inpWS); + + DataObjects::TableWorkspace_sptr splws = + createTableSplitters(0, pulsedt, tofdt); + AnalysisDataService::Instance().addOrReplace("TableSplitter2", splws); + + FilterEvents filter; + filter.initialize(); + + // Set properties + filter.setProperty("InputWorkspace", "Test12"); + filter.setProperty("OutputWorkspaceBaseName", "FilteredFromTable"); + filter.setProperty("SplitterWorkspace", "TableSplitter2"); + filter.setProperty("RelativeTime", true); + filter.setProperty("OutputWorkspaceIndexedFrom1", true); + filter.setProperty("RelativeTime", true); + + std::vector prop_vec; + prop_vec.push_back("LogB"); + prop_vec.push_back("slow_int_log"); + filter.setProperty("TimeSeriesPropertyLogs", prop_vec); + filter.setProperty("ExcludeSpecifiedLogs", true); + + // Execute + TS_ASSERT_THROWS_NOTHING(filter.execute()); + TS_ASSERT(filter.isExecuted()); + + // Get 3 output workspaces + int numsplittedws = filter.getProperty("NumberOutputWS"); + TS_ASSERT_EQUALS(numsplittedws, 3); + + // check number of sample logs + size_t num_original_logs = inpWS->run().getProperties().size(); + + std::vector outputwsnames = + filter.getProperty("OutputWorkspaceNames"); + for (size_t i = 0; i < outputwsnames.size(); ++i) { + EventWorkspace_sptr childworkspace = + boost::dynamic_pointer_cast( + AnalysisDataService::Instance().retrieve(outputwsnames[i])); + TS_ASSERT(childworkspace); + // there is 1 sample logs that is excluded from propagating to the child + // workspaces. LogB is not TSP, so it won't be excluded even if it is + // listed + // a new TSP splitter is added by FilterEvents. So there will be exactly + // same number, but some different, sample logs in the input and output + // workspaces + TS_ASSERT_EQUALS(num_original_logs, + childworkspace->run().getProperties().size()); + } + + // clean workspaces + AnalysisDataService::Instance().remove("Test12"); + AnalysisDataService::Instance().remove("TableSplitter2"); + for (size_t i = 0; i < outputwsnames.size(); ++i) { + AnalysisDataService::Instance().remove(outputwsnames[i]); + } + + return; + } + + /** test for the case that the input workspace name is same as output base + * workspace name + * @brief test_ThrowSameName + */ + void test_ThrowSameName() { + // Create EventWorkspace and SplittersWorkspace + int64_t runstart_i64 = 20000000000; + int64_t pulsedt = 100 * 1000 * 1000; + int64_t tofdt = 10 * 1000 * 1000; + size_t numpulses = 5; + + EventWorkspace_sptr inpWS = + createEventWorkspace(runstart_i64, pulsedt, tofdt, numpulses); + AnalysisDataService::Instance().addOrReplace("Test13", inpWS); + + DataObjects::TableWorkspace_sptr splws = + createTableSplitters(0, pulsedt, tofdt); + AnalysisDataService::Instance().addOrReplace("TableSplitter2", splws); + + FilterEvents filter; + filter.initialize(); + + // Set properties + filter.setProperty("InputWorkspace", "Test13"); + filter.setProperty("OutputWorkspaceBaseName", "Test13"); + filter.setProperty("SplitterWorkspace", "TableSplitter2"); + filter.setProperty("RelativeTime", true); + filter.setProperty("OutputWorkspaceIndexedFrom1", true); + filter.setProperty("RelativeTime", true); + filter.setProperty("GroupWorkspaces", true); + + // Execute + TS_ASSERT(!filter.execute()); + + // clean workspaces + AnalysisDataService::Instance().remove("Test13"); + AnalysisDataService::Instance().remove("TableSplitter2"); + + return; + } + + /** test for the case that the input workspace name is same as output base + * workspace name + * @brief test_ThrowSameName + */ + void test_groupWorkspaces() { + // Create EventWorkspace and SplittersWorkspace + int64_t runstart_i64 = 20000000000; + int64_t pulsedt = 100 * 1000 * 1000; + int64_t tofdt = 10 * 1000 * 1000; + size_t numpulses = 5; + + EventWorkspace_sptr inpWS = + createEventWorkspace(runstart_i64, pulsedt, tofdt, numpulses); + AnalysisDataService::Instance().addOrReplace("Test13", inpWS); + + DataObjects::TableWorkspace_sptr splws = + createTableSplitters(0, pulsedt, tofdt); + AnalysisDataService::Instance().addOrReplace("TableSplitter2", splws); + + FilterEvents filter; + filter.initialize(); + + // Set properties + filter.setProperty("InputWorkspace", "Test13"); + filter.setProperty("OutputWorkspaceBaseName", "13"); + filter.setProperty("SplitterWorkspace", "TableSplitter2"); + filter.setProperty("RelativeTime", true); + filter.setProperty("OutputWorkspaceIndexedFrom1", true); + filter.setProperty("RelativeTime", true); + filter.setProperty("GroupWorkspaces", true); + + // Execute + TS_ASSERT(filter.execute()); + + // clean workspaces + AnalysisDataService::Instance().remove("Test13"); + AnalysisDataService::Instance().remove("TableSplitter2"); + + return; + } + //---------------------------------------------------------------------------------------------- /** Create an EventWorkspace. This workspace has * @param runstart_i64 : absolute run start time in int64_t format with unit @@ -966,14 +1133,13 @@ class FilterEventsTest : public CxxTest::TestSuite { EventWorkspace_sptr createEventWorkspace(int64_t runstart_i64, int64_t pulsedt, int64_t tofdt, size_t numpulses) { - // 1. Create an EventWorkspace with 10 detectors + // Create an EventWorkspace with 10 detectors EventWorkspace_sptr eventWS = WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(10, 1, true); Kernel::DateAndTime runstart(runstart_i64); - // 2. Set run_start time eventWS->mutableRun().addProperty("run_start", runstart.toISO8601String(), true); @@ -987,7 +1153,14 @@ class FilterEventsTest : public CxxTest::TestSuite { for (int64_t pid = 0; pid < static_cast(numpulses); pid++) { int64_t pulsetime_i64 = pid * pulsedt + runstart.totalNanoseconds(); Kernel::DateAndTime pulsetime(pulsetime_i64); - pchargeLog->addValue(pulsetime, 1.); + + // add pulse time to proton charge log once and only once + if (i == 0) { + pchargeLog->addValue(pulsetime, 1.); + std::cout << "Add proton charge log " << pulsetime.totalNanoseconds() + << "\n"; + } + for (size_t e = 0; e < 10; e++) { double tof = static_cast(e * tofdt / 1000); TofEvent event(tof, pulsetime); @@ -1069,6 +1242,8 @@ class FilterEventsTest : public CxxTest::TestSuite { } // FOR each pulse } // For each bank + eventWS->mutableRun().integrateProtonCharge(); + // double constshift = l1 / sqrt(ei * 2. * PhysicalConstants::meV / // PhysicalConstants::NeutronMass); diff --git a/Framework/Kernel/src/TimeSeriesProperty.cpp b/Framework/Kernel/src/TimeSeriesProperty.cpp index ae861726ee8d..20b2b119f85b 100644 --- a/Framework/Kernel/src/TimeSeriesProperty.cpp +++ b/Framework/Kernel/src/TimeSeriesProperty.cpp @@ -530,9 +530,14 @@ void TimeSeriesProperty::splitByTimeVector( std::vector &splitter_time_vec, std::vector &target_vec, std::vector outputs) { // check inputs - if (splitter_time_vec.size() != target_vec.size() + 1) - throw std::runtime_error("Input time vector's size does not match taget " - "workspace index vector's size."); + if (splitter_time_vec.size() != target_vec.size() + 1) { + std::stringstream errss; + errss << "Try to split TSP " << this->m_name + << ": Input time vector's size " << splitter_time_vec.size() + << " does not match (one more larger than) taget " + "workspace index vector's size " << target_vec.size() << "\n"; + throw std::runtime_error(errss.str()); + } // return if the output vector TimeSeriesProperties is not defined if (outputs.empty()) return; @@ -596,28 +601,20 @@ void TimeSeriesProperty::splitByTimeVector( } } - g_log.debug() << "TSP entry: " << index_tsp_time - << ", Splitter index = " << index_splitter << "\n"; - // now it is the time to put TSP's entries to corresponding continue_search = !no_entry_in_range; while (continue_search) { - // get the first entry index - if (index_tsp_time > 0) - --index_tsp_time; - + // get next target int target = target_vec[index_splitter]; - g_log.debug() << "Target = " << target - << " with splitter index = " << index_splitter << "\n" - << "\t" - << "Time index = " << index_tsp_time << "\n\n"; + // get the first entry index (overlap) + if (index_tsp_time > 0) + --index_tsp_time; + // add the continous entries to same target time series property bool continue_add = true; while (continue_add) { // add current entry - g_log.debug() << "Add entry " << index_tsp_time << " to target " << target - << "\n"; if (outputs[target]->size() == 0 || outputs[target]->lastTime() < tsp_time) { // avoid to add duplicate entry @@ -628,9 +625,6 @@ void TimeSeriesProperty::splitByTimeVector( // advance to next entry ++index_tsp_time; - g_log.debug() << "\tEntry time " << tsp_time_vec[index_tsp_time] - << ", stop time " << split_stop_time << "\n"; - if (index_tsp_time == tsp_time_vec.size()) { // last entry. quit all loops continue_add = false; diff --git a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py index 70dcb22f2bb7..f1544cfbcc5e 100644 --- a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py +++ b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py @@ -723,7 +723,7 @@ def _loadAndSum(self, filename_list, outName): # Normalize by current with new name if self._normalisebycurrent is True: - self.log().warning('[SPECIAL DB] Normalize current to workspace %s' % sample_ws_name) + self.log().information('Normalize current to workspace %s' % sample_ws_name) # temp_ws = self.get_workspace(sample_ws_name) if not (is_event_workspace(sample_ws_name) and get_workspace(sample_ws_name).getNumberEvents() == 0): api.NormaliseByCurrent(InputWorkspace=sample_ws_name, @@ -891,9 +891,6 @@ def _focusChunks(self, filename, filter_wall=(0.,0.), # noqa ReductionProperties="__snspowderreduction", **self._focusPos) # logging (ignorable) - #for iws in range(out_ws_c_s.getNumberHistograms()): - # spec = out_ws_c_s.getSpectrum(iws) - # self.log().debug("[DBx131] ws %d: spectrum No = %d. " % (iws, spec.getSpectrumNo())) if is_event_workspace(out_ws_name_chunk_split): self.log().information('After being aligned and focused, workspace %s: Number of events = %d ' 'of chunk %d ' % (out_ws_name_chunk_split, @@ -1447,7 +1444,7 @@ def _split_workspace(self, raw_ws_name, split_ws_name): self.log().information("SplitterWorkspace = %s, Information Workspace = %s. " % ( split_ws_name, str(self._splitinfotablews))) - base_name = raw_ws_name + base_name = raw_ws_name + '_split' # find out whether the splitters are relative time or epoch time split_ws = AnalysisDataService.retrieve(split_ws_name) diff --git a/Testing/SystemTests/tests/analysis/reference/HYSPECReduction_TIBasEvents.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/HYSPECReduction_TIBasEvents.nxs.md5 index fd70306a58e1..a074d5ffb625 100644 --- a/Testing/SystemTests/tests/analysis/reference/HYSPECReduction_TIBasEvents.nxs.md5 +++ b/Testing/SystemTests/tests/analysis/reference/HYSPECReduction_TIBasEvents.nxs.md5 @@ -1 +1 @@ -846f32a2e87499c798ec56418bc5c5ee \ No newline at end of file +0e32c13270b30d346e70002af2fbf9a5 diff --git a/docs/source/release/v3.11.0/framework.rst b/docs/source/release/v3.11.0/framework.rst index 5cab814fd28d..9f8cae742d98 100644 --- a/docs/source/release/v3.11.0/framework.rst +++ b/docs/source/release/v3.11.0/framework.rst @@ -24,7 +24,7 @@ Improved - :ref:`LoadBBY ` is now better at handling sample information. - :ref:`GroupDetectors ` now supports workspaces with detector scans. - :ref:`algm-MonteCarloAbsorption` now supports approximating the input instrument with a sparse grid of detectors enabling quick simulation of huge pixel arrays. - +- :ref:`FilterEvents ` has refactored on splitting sample logs. - :ref:`FilterEvents ` now copies units for the logs in the filtered workspaces Deprecated