From ecc19e4db44585d369991f4455cc17a06a994477 Mon Sep 17 00:00:00 2001 From: Pete Peterson <petersonpf@ornl.gov> Date: Fri, 14 Dec 2018 13:28:17 -0500 Subject: [PATCH] Rework event filtering documentation --- .../source/algorithms/FilterByLogValue-v1.rst | 15 +- docs/source/algorithms/FilterEvents-v1.rst | 237 ++++++++---------- docs/source/concepts/EventFiltering.rst | 185 ++++++++------ docs/source/release/v3.14.0/framework.rst | 1 + 4 files changed, 224 insertions(+), 214 deletions(-) diff --git a/docs/source/algorithms/FilterByLogValue-v1.rst b/docs/source/algorithms/FilterByLogValue-v1.rst index 6579b1d95d5..8e5a6508db1 100644 --- a/docs/source/algorithms/FilterByLogValue-v1.rst +++ b/docs/source/algorithms/FilterByLogValue-v1.rst @@ -38,6 +38,11 @@ will be included also. If a log has a single point in time, then that log value is assumed to be constant for all time and if it falls within the range, then all events will be kept. +.. warning:: + + :ref:`FilterByLogValue <algm-FilterByLogValue>` is not suitable for + fast log filtering. + PulseFilter (e.g. for Veto Pulses) ################################## @@ -63,7 +68,7 @@ rejected. For example, this call will filter out veto pulses: .. testsetup:: VetoPulseTime ws=CreateSampleWorkspace("Event") - AddTimeSeriesLog(ws, Name="veto_pulse_time", Time="2010-01-01T00:00:00", Value=1) + AddTimeSeriesLog(ws, Name="veto_pulse_time", Time="2010-01-01T00:00:00", Value=1) AddTimeSeriesLog(ws, Name="veto_pulse_time", Time="2010-01-01T00:10:00", Value=0) AddTimeSeriesLog(ws, Name="veto_pulse_time", Time="2010-01-01T00:20:00", Value=1) AddTimeSeriesLog(ws, Name="veto_pulse_time", Time="2010-01-01T00:30:00", Value=0) @@ -77,20 +82,20 @@ rejected. For example, this call will filter out veto pulses: Comparing with other event filtering algorithms ############################################### -Wiki page :ref:`EventFiltering` has a detailed -introduction on event filtering in MantidPlot. +The :ref:`EventFiltering` page has a detailed introduction on event +filtering in mantid. Usage ----- -**Example - Filtering by a simple time series Log** +**Example - Filtering by a simple time series Log** .. testcode:: FilterByLogValue ws = CreateSampleWorkspace("Event",BankPixelWidth=1) - AddTimeSeriesLog(ws, Name="proton_charge", Time="2010-01-01T00:00:00", Value=100) + AddTimeSeriesLog(ws, Name="proton_charge", Time="2010-01-01T00:00:00", Value=100) AddTimeSeriesLog(ws, Name="proton_charge", Time="2010-01-01T00:10:00", Value=100) AddTimeSeriesLog(ws, Name="proton_charge", Time="2010-01-01T00:20:00", Value=100) AddTimeSeriesLog(ws, Name="proton_charge", Time="2010-01-01T00:30:00", Value=100) diff --git a/docs/source/algorithms/FilterEvents-v1.rst b/docs/source/algorithms/FilterEvents-v1.rst index b45de531098..7063dcb65b0 100644 --- a/docs/source/algorithms/FilterEvents-v1.rst +++ b/docs/source/algorithms/FilterEvents-v1.rst @@ -9,147 +9,120 @@ Description ----------- -This algorithm filters events from an :ref:`EventWorkspace` to one or -multiple :ref:`EventWorkspaces <EventWorkspace>` according to an input -:ref:`SplittersWorkspace` containing a series of splitters (i.e., -:ref:`splitting intervals <SplittingInterval>`). - -Inputs -###### - -FilterEvents takes 2 mandatory input Workspaces and 1 optional -Workspace. One of mandatory workspace is the :ref:`EventWorkspace` -where the events are filtered from. The other mandatory workspace is -workspace containing splitters. It can be a MatrixWorkspace, a TableWorkspace or -a :ref:`SplittersWorkspace <SplittersWorkspace>`. - -The optional workspace is a :ref:`TableWorkspace <Table Workspaces>` -for information of splitters. - -Workspace containing splitters -============================== - -This algorithm accepts three types of workspace that contains event splitters. -- TableWorkspace: a general TableWorkspace with at three columns -- MatrixWorkspace: a 1-spectrum MatrixWorkspace -- SplittersWorkspace: an extended TableWorkspace with restrict definition on start and stop time. - -Event splitter -++++++++++++++ - -An event splitter contains three items, start time, stop time and splitting target (index). -All the events belonged to the same splitting target will be saved to a same output EventWorkspace. - -Unit of input splitters -+++++++++++++++++++++++ - -- MatrixWorkspace: the unit must be second. -- TableWorkspace: the unit must be second. -- SplittersWorkspace: by the definition of SplittersWorkspace, the unit has to be nanosecond. - - -How to generate input workspace containing splitters -++++++++++++++++++++++++++++++++++++++++++++++++++++ - -There are two ways to generate - -Algorithm :ref:`GenerateEventsFilter <algm-GenerateEventsFilter>` -creates both the :ref:`SplittersWorkspace <SplittersWorkspace>` and -splitter information workspace. - - -Splitters in relative time or absolute time -+++++++++++++++++++++++++++++++++++++++++++ - -As the SplittersWorkspace is in format of :ref:`MatrixWorkspace -<MatrixWorkspace>`, its time, i.e., the value in X vector, can be -relative time. - -Property ``RelativeTime`` flags that the splitters' time is relative. -Property ``FilterStartTime`` specifies the starting time of the filter. -Or the shift of time of the splitters. -If it is not specified, then the algorithm will search for sample log ``run_start``. - -Outputs -####### - -The output will be one or multiple workspaces according to the number of -index in splitters. The output workspace name is the combination of -parameter OutputWorkspaceBaseName and the index in splitter. - -Calibration File -################ - -The calibration, or say correction, from the detector to sample must be -consider in fast log. Thus a calibration file is required. The math is - -``TOF_calibrated = TOF_raw * correction(detector ID).`` - -The calibration is in column data format. - -A reasonable approximation of the correction is - -``correction(detector_ID) = L1/(L1+L2(detector_ID))`` +This algorithm filters events from a single :ref:`EventWorkspace` to +one or multiple :ref:`EventWorkspaces <EventWorkspace>` according to +the ``SplittersWorkspace`` property. The :ref:`EventFiltering` concept +page has a detailed introduction to event filtering. + +Specifying the splitting strategy +--------------------------------- + +The ``SplittersWorkspace`` describes much of the information for +splitting the ``InputWorkspace`` into the various output +workspaces. It can have one of three types + ++--------------------------------------------------------------+-------------+----------+ +| workspace class | units | rel/abs | ++==============================================================+=============+==========+ +| :ref:`MatrixWorkspace <MatrixWorkspace>` | seconds | either | ++--------------------------------------------------------------+-------------+----------+ +| :class:`SplittersWorkspace <mantid.api.ISplittersWorkspace>` | nanoseconds | absolute | ++--------------------------------------------------------------+-------------+----------+ +| :ref:`TableWorkspace <Table Workspaces>` | seconds | either | ++--------------------------------------------------------------+-------------+----------+ + +Whether the values in :ref:`MatrixWorkspace <MatrixWorkspace>` and +:ref:`TableWorkspace <Table Workspaces>` is treated as relative or +absolute time is dependent on the value of ``RelativeTime``. In the +case of ``RelativeTime=True``, the time is relative to the start of +the run (in the ``ws.run()['run_start']``) or, if specified, the +``FilterStartTime``. In the case of ``RelativeTime=False``, the times +are relative to the :class:`GPS epoch <mantid.kernel.DateAndTime>`. + +Both :ref:`TableWorkspace <Table Workspaces>` and +:class:`SplittersWorkspace <mantid.api.ISplittersWorkspace>` have 3 +colums, ``start``, ``stop``, and ``target`` which should be a float, +float, and string. The :ref:`event filtering <EventFiltering>` concept +page has details on creating the :ref:`TableWorkspace <Table +Workspaces>` by hand. + +If the ``SplittersWorkspace`` is a :ref:`MatrixWorkspace +<MatrixWorkspace>`, it must have a single spectrum with the x-value is +the time boundaries and the y-value is the workspace group index. + +The optional ``InformationWorkspace`` is a :ref:`TableWorkspace <Table +Workspaces>` for information of splitters. Unfiltered Events -################# +----------------- Some events are not inside any splitters. They are put to a workspace -name ended with '\_unfiltered'. - -If input property 'OutputWorkspaceIndexedFrom1' is set to True, then -this workspace shall not be outputted. +name ended with ``_unfiltered``. If +``OutputWorkspaceIndexedFrom1=True``, then this workspace will not be +created. Using FilterEvents with fast-changing logs -########################################## +------------------------------------------ + +There are a few parameters to consider when the log filtering is +expected to produce a large splitter table. An example of such a case +would be a data file for which the events need to be split according +to a log with two or more states changing in the kHz range. To reduce +the filtering time, one may do the following: + +- Make sure the ``SplitterWorkspace`` input is a :ref:`MatrixWorkspace + <MatrixWorkspace>`. Such a workspace can be produced by using the + ``FastLog = True`` option when calling :ref:`GenerateEventsFilter + <algm-GenerateEventsFilter>`. +- Choose the logs to split. Filtering the logs can take a substantial + amount of time. To save time, you may want to split only the logs + you will need for analysis. To do so, set ``ExcludeSpecifiedLogs = + False`` and list the logs you need in + ``TimeSeriesPropertyLogs``. For example, if we only need to know the + accumulated proton charge for each filtered workspace, we would set + ``TimeSeriesPropertyLogs = proton_charge``. + +Correcting time neutron was at the sample +######################################### + +When filtering fast logs, the time to filter by is the time that the +neutron was at the sample. This can be specified using the +``CorrectionToSample`` parameter. Either the user specifies the +correction parameter for every pixel, or one is calculated. The +correction parameters are applied as + +.. math:: + + TOF_{sample} = TOF_{detector} * scale[detectorID] + shift[detectorID] + +and stored in the ``OutputTOFCorrectionWorkspace``. + +* ``CorrectionToSample="None"`` applies no correction +* ``CorrectionToSample="Elastic"`` applies :math:`shift = 0` with + :math:`scale = L1/(L1+L2)` for detectors and :math:`scale = L1/L_{monitor}` + for monitors +* ``CorrectionToSample="Direct"`` applies :math:`scale = 0` and + :math:`shift = L1 / \sqrt{2 E_{fix} / m_n}`. The value supplied in + ``IncidentEnergy`` will override the value found in the workspace's + value of ``Ei``. +* ``CorrectionToSample="Indirect"`` applies :math:`scale = 1` and + :math:`shift = -1 * L2 / \sqrt{2 E_{fix} / m_n}` for detectors. For + monitors, uses the same corrections as ``Elastic``. + +* ``CorrectionToSample="Customized"`` applies the correction supplied + in the ``DetectorTOFCorrectionWorkspace``. -There are a few parameters to consider when the log filtering is expected to produce a large -splitter table. An example of such a case would be a data file for which the events need to be split -according to a log with two or more states changing in the kHz range. To reduce the filtering time, -one may do the following: - -- Make sure the ``SplitterWorkspace`` input is a :ref:`MatrixWorkspace <MatrixWorkspace>`. Such a workspace can be produced by using the ``FastLog = True`` option when calling :ref:`GenerateEventsFilter <algm-GenerateEventsFilter>`. -- Choose the logs to split. Filtering the logs can take a substantial amount of time. To save time, you may want to split only the logs you will need for analysis. To do so, set ``ExcludeSpecifiedLogs = False`` and list the logs you need in ``TimeSeriesPropertyLogs``. For example, if we only need to know the accumulated proton charge for each filtered workspace, we would set ``TimeSeriesPropertyLogs = proton_charge``. Difference from FilterByLogValue -################################ - -In FilterByLogValue(), EventList.splitByTime() is used. - -In FilterEvents, if FilterByPulse is selected true, -EventList.SplitByTime is called; otherwise, EventList.SplitByFullTime() -is called instead. - -The difference between splitByTime and splitByFullTime is that -splitByTime filters events by pulse time, and splitByFullTime considers -both pulse time and TOF. - -Therefore, FilterByLogValue is not suitable for fast log filtering. - -Comparing with other event filtering algorithms -############################################### - -Wiki page :ref:`EventFiltering` has a detailed introduction on event -filtering in MantidPlot. - - -Developer's Note ----------------- - -Splitters given by TableWorkspace -################################# - -- The ``start/stop time`` is converted to ``m_vecSplitterTime``. -- The splitting target (in string) is mapped to a set of continuous integers that are stored in ``m_vecSplitterGroup``. - - The mapping will be recorded in ``m_targetIndexMap`` and ``m_wsGroupIndexTargetMap``. - - Class variable ``m_maxTargetIndex`` is set up to record the highest target group/index,i.e., the max value of ``m_vecSplitterGroup``. - - -Undefined splitting target -########################## - -Indexed as ``0`` in m_vecSplitterGroup. - +-------------------------------- + +In :ref:`FilterByLogValue <algm-FilterByLogValue>`, +``EventList.splitByTime()`` is used. In FilterEvents, it only uses +this when ``FilterByPulse=True``. Otherwise, +``EventList.splitByFullTime()`` is used. The difference between +``splitByTime`` and ``splitByFullTime`` is that ``splitByTime`` +filters events by pulse time, and ``splitByFullTime`` considers both +pulse time and TOF. Usage ----- diff --git a/docs/source/concepts/EventFiltering.rst b/docs/source/concepts/EventFiltering.rst index d86f072e1db..c77137bbefa 100644 --- a/docs/source/concepts/EventFiltering.rst +++ b/docs/source/concepts/EventFiltering.rst @@ -7,86 +7,117 @@ Event Filtering .. contents:: :local: -In MantidPlot, there are a few algorithms working with event -filtering. These algorithms are :ref:`algm-FilterByTime`, -:ref:`algm-FilterByLogValue`, :ref:`algm-FilterEvents`, and -:ref:`algm-GenerateEventsFilter`. +In mantid, there are a variety of ways to filter events that are in an +:ref:`EventWorkspace`. They are :ref:`FilterByTime +<algm-FilterByTime>` and :ref:`FilterByLogValue +<algm-FilterByLogValue>` which will create a filter and apply it in a +single step. The other way to filter events is to use +:ref:`FilterEvents <algm-FilterEvents>` which allows for a variety of +workspaces to specify how an :ref:`EventWorkspace` is split. This +document focuses on how the create these workspaces and will largely +ignore :ref:`FilterByTime <algm-FilterByTime>` and +:ref:`FilterByLogValue <algm-FilterByLogValue>`. How to generate event filters ============================= -Generating filters explicitly ------------------------------ - -:ref:`algm-FilterEvents` reads and parses a -:class:`mantid.api.ISplittersWorkspace` object to generate a list of -:ref:`SplittingIntervals <SplittingInterval>`, which are used to split -neutron events to specified output workspaces according to the times -that they arrive detectors. - -There can be two approaches to create a -:class:`mantid.api.ISplittersWorkspace`. - -* :ref:`algm-GenerateEventsFilter` generate event filters by either by - time or log value. The output filters are stored in a - :ref:`SplittersWorkspace`, which is taken as an input property of - :ref:`algm-FilterEvents`. - -* Users can create a :class:`mantid.api.ISplittersWorkspace` from scrach from Python - script, because :class:`mantid.api.ISplittersWorkspace` inherits from - :ref:`TableWorkspace <Table Workspaces>`. - -Generating inexplicit filters ------------------------------ - -:ref:`algm-FilterByTime` and :ref:`algm-FilterByLogValue` generate event filters during execution. - -* :ref:`algm-FilterByTime` generates a set of :ref:`SplittingInterval` - according to user-specified setup for time splicing; - -* :ref:`algm-FilterByLogValue` generates a set of - :ref:`SplittingInterval` according to the value of a specific sample - log. - -:ref:`algm-GenerateEventsFilter` and :ref:`algm-FilterEvents` vs :ref:`algm-FilterByTime` and :ref:`algm-FilterByLogValue` --------------------------------------------------------------------------------------------------------------------------- - -* If :ref:`algm-GenerateEventsFilter` and :ref:`algm-FilterEvents` are - set up correctly, they can have the same functionality as - :ref:`algm-FilterByTime` and :ref:`algm-FilterByLogValue`. - -* :ref:`algm-FilterEvents` is able to filter neutron events by either - their pulse times or their absolute times. An neutron event's - absolute time is the summation of its pulse time and TOF. - -* :ref:`algm-FilterByLogValue` and :ref:`algm-FilterByTime` can only - split neutron events by their pulse time. - -Types of events filters -======================= - -Filtering by :ref:`SplittingInterval` -------------------------------------- - -:ref:`SplittingInterval` is an individual class to indicate an -independent time splitter. Any event can be filtered by a -:ref:`SplittingInterval` object. - -:ref:`SplittersWorkspace` is a :ref:`TableWorkspace <Table -Workspaces>` that stors a set of :ref:`SplittingInterval`. - -Filtering by duplicate entries/booleans ---------------------------------------- - -Duplicate entries in a :ref:`TimeSeriesProperty` and boolean type of -:ref:`TimeSeriesProperty` are used in MantidPlot too to serve as time -splitters. - -These two are applied in the MantidPlot log viewing functionality and -unfortunately intrudes into :ref:`TimeSeriesProperty`. - -As time splitters are better to be isolated from logs, which are -recorded in :ref:`TimeSeriesProperty`, it is not -recommended to set up event filters by this approach. +Implicit filters +---------------- + +:ref:`algm-FilterByTime` and :ref:`algm-FilterByLogValue` internally +generate event filters during execution that are not exposed to the +user. These algorithms can only split the neutron events by pulse +time and do not provide the equivalent of a ``FastLog=True`` option. + +Explicit filters +---------------- + +:ref:`algm-FilterEvents` takes either a :class:`SplittersWorkspace +<mantid.api.ISplittersWorkspace>`, :ref:`TableWorkspace <Table +Workspaces>`, or :ref:`MatrixWorkspace <MatrixWorkspace>` as the +``SplittersWorkspace``. The events are split into output workspaces +according to the times that they arrive detectors. + +:ref:`GenerateEventsFilter <algm-GenerateEventsFilter>` will create a +:class:`SplittersWorkspace <mantid.api.ISplittersWorkspace>` based on +its various options. This result can be supplied as the +``SplittersWorkspace`` input property of ref:`algm-FilterEvents`. It +will also generate an ``InformationWorkspace`` which can be passed +along to :ref:`GenerateEventsFilter <algm-GenerateEventsFilter>`. +Depending on the parameters in :ref:`GenerateEventsFilter +<algm-GenerateEventsFilter>`, the events will be filtered based on +their pulse times or their absolute times. An neutron event's +absolute time is the summation of its pulse time and TOF. + +Custom event filters +==================== + +Sometimes one wants to filter events based on arbitrary conditions. In +this case, one needs to go beyond what existing algorithms can do. For +this, one must generate their own splitters workspace. The workspace +is generally 3 columns, with the first two being start and stop times +and the third being the workspace index to put the events into. For +filtering with time relative to the start of the run, the first two +columns are ``float``. To specify the times as absolute, in the case +of filtering files that will be summed together, the first two columns +should be ``int64``. For both of the examples below, the filter +workspaces are created using the following function: + +.. code-block:: python + + def create_table_workspace(table_ws_name, column_def_list): + CreateEmptyTableWorkspace(OutputWorkspace=table_ws_name) + table_ws = mtd[table_ws_name] + for col_tup in column_def_list: + data_type = col_tup[0] + col_name = col_tup[1] + table_ws.addColumn(data_type, col_name) + + return table_ws + +Relative time +------------- + +The easiest way to generate a custom event filter is to make one +relative to the start time of the run or relative to a specified +epoch. As the times in the table are seconds, a table can be created +and used + +.. code-block:: python + + filter_rel = create_table_workspace('custom_relative', [('float', 'start'), ('float', 'stop'), ('str', 'target')]) + filter_rel.addRow((0,9500, '0')) + filter_rel.addRow((9500,19000, '1')) + FilterEvents(InputWorkspace='ws', SplitterWorkspace=filter_rel, + GroupWorkspaces=True, OutputWorkspaceBaseName='relative', RelativeTime=True) + +This will generate an event filter relative to the start of the +run. Specifying the ``FilterStartTime`` in :ref:`FilterEvents +<algm-FilterEvents>`, one can specify a different time that filtering +will be relative to. + +Absolute time +------------- + +If instead a custom filter is to be created with absolute time, the +time must be processed somewhat to go into the table workspace. Much of the + +.. code-block:: python + + abs_times = [datetime64('2014-12-12T09:11:22.538096666'), datetime64('2014-12-12T11:45:00'), datetime64('2014-12-12T14:14:00')] + # convert to time relative to GPS epoch + abs_times = [time - datetime64('1990-01-01T00:00') for time in abs_times] + # convert to number of seconds + abs_times = [float(time / timedelta64(1, 's')) for time in abs_times] + + filter_abs = create_table_workspace('custom_absolute', [('float', 'start'), ('float', 'stop'), ('str', 'target')]) + filter_abs.addRow((abs_times[0], abs_times[1], '0')) + filter_abs.addRow((abs_times[1], abs_times[2], '1')) + FilterEvents(InputWorkspace='PG3_21638', SplitterWorkspace=filter_abs, + GroupWorkspaces=True, OutputWorkspaceBaseName='absolute', RelativeTime=False) + +Be warned that specifying ``RelativeTime=True`` with a table full of +absolute times will almost certainly generate output workspaces +without any events in them. .. categories:: Concepts diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst index ee2aa821060..2b64364dc70 100644 --- a/docs/source/release/v3.14.0/framework.rst +++ b/docs/source/release/v3.14.0/framework.rst @@ -84,6 +84,7 @@ Improvements - :ref:`GroupDetectors <algm-GroupDetectors>` now takes masked bins correctly into account when processing histogram workspaces. - :ref:`SaveNexusProcessed <algm-SaveNexusProcessed>` and :ref:`LoadNexusProcessed <algm-LoadNexusProcessed>` can now save and load a ``MaskWorkspace``. - :ref:`FitPeaks <algm-FitPeaks>` can output parameters' uncertainty (fitting error) in an optional workspace. +- The documentation in :ref:`EventFiltering` and :ref:`FilterEvents <algm-FilterEvents>` have been extensively rewritten to aid in understanding what the code does. Bugfixes ######## -- GitLab