Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactors events page and updates resampling page #20

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 131 additions & 32 deletions source/advanced/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,148 @@
===================================
Handling Events During Calculations
===================================
Sometimes it is useful to be able to monitor the progress / success of a fit in real time for long simulations. For Simplex and DE fits, RAT sends out 'events', which send out data concerning the
reflectivity, SLD's and so on as the fit progresses. By writing functions that 'listen' to these events, you can use this information to build various kinds of graphical updates to suit your needs.
In this section, we'll use this capability to build a live, updating plot of reflectivity and SLD, similar to that of the main RasCAL GUI.
Sometimes, it is useful to be able to monitor the progress or success of a fit in real time for long simulations. RAT can send out 'events', which contain different data about the
calculation. By writing functions that 'listen' to these events, you can use this information to build various kinds of updates.

.. note::
The code in this section already exists in the repo (utilities/plotting), and you can activate the full updating plot at any time by just typing 'useLivePlot()' at the MATLAB command window. But we detail it here to illustrate how to interact with events.

**Registering Listeners**
***************************
Registering Event Listeners
***************************
When an event is triggered, the event data will be passed to any function that is registered for that specific event type. The event listener function (also called an event handler) should recieve a single argument which will be different depending on the event type.
The example below registers a function to listen for the ``Plot`` event:

On the MATLAB side, the interaction with RAT event is via the 'eventManager' class. To register a listener, we use the 'register' method to associate a function with the event.

.. code-block:: MATLAB
.. tab-set-code::
.. code-block:: Matlab

eventManager.register(eventTypes.Plot, 'updatePlot');

.. code-block:: Python

In this line, we've done two things: we've registered a 'listener' for 'Plot' events, and defined the function 'updatePlot' as the function that runs when the event is triggered (known as a 'handler')
We need to define the handler function:

.. code-block:: MATLAB
import RATapi as RAT
RAT.events.register(RAT.events.EventTypes.Plot, update_plot)

function updatePlot(varargin)
The event listener function is also shown below, it uses one of the plot functions provided by RAT to display the event data. The plot event data contains the current state of the reflectivity and SLD's, along with a number of other items which is detailed below.

h = figure(1000); % Select / open the figure
.. tab-set-code::
.. code-block:: Matlab

subplot(1,2,1); cla % Reflectivity plot panel
subplot(1,2,2); cla % SLD plot panel
plotRefSLDHelper(varargin{:}); % Use the standard RAT reflectivity plot
drawnow limitrate % Make sure it updates

end
function updatePlot(eventData)

h = figure(1000); % Select / open the figure

We can put a breakpoint in our function to examine the contents of varargin
subplot(1,2,1); cla % Reflectivity plot panel
subplot(1,2,2); cla % SLD plot panel
plotRefSLDHelper(eventData); % Use the standard RAT reflectivity plot
drawnow limitrate % Make sure it updates

.. image:: ../images/misc/updateBreakPoint.png
:width: 300
:alt: breakpoint in update function
end

We see that it is a struct containing everything needed to make our custom plot:
.. code-block:: Python

.. image:: ../images/misc/eventContents.png
:width: 300
:alt: contents of events
import matplotlib.pyplot as plt

def update_plot(event_data):
figure = plt.figure(num=1)

# Use the standard RAT reflectivity plot
RAT.plotting.plot_ref_sld_helper(event_data, figure)

In other words, RAT has packaged the current state of the reflectivity and SLD's, along with a number of other items that you can use to make a plot however you like.
For these purposes, we just make use of the existing RAT plot routine to make our plot. The result is the updating plot routine bundled with RAT.
.. note::
A utility function already exists to do live plotting, see :ref:`livePlot` for more information. This section is illustrative for users that want to write more advanced handlers for events.

***********
Event Types
***********
There are a few event types that are emitted by RAT and each type provides different data as its argument to the listener function. The following events are emitted by RAT:

1. :ref:`message_event`
2. :ref:`plot_event`
3. :ref:`progress_event`

Register a function as an event listener by providing the event type and the listener function to the ``register`` function, as shown below.

.. tab-set-code::
.. code-block:: Matlab

eventManager.register(eventTypes.Message, handleEvent); % Message Event
eventManager.register(eventTypes.Plot, handleEvent); % Plot Event
eventManager.register(eventTypes.Progress, handleEvent); % Progress Event

.. code-block:: Python

import RATapi as RAT

RAT.events.register(RAT.events.EventTypes.Message, handle_event) # Message Event
RAT.events.register(RAT.events.EventTypes.Plot, handle_event) # Plot Event
RAT.events.register(RAT.events.EventTypes.Progress, handle_event) # Progress Event

.. _message_event:

Message Event
=============
The message event contains text output from the calculation, which can inform the users about the current step or convergence of the calculation. This event is supported by all algorithms. The event data is a simple string.

.. _plot_event:

Plot Event
==========
The plot event contains intermediate results from the calculation. As shown in the example above, a good use case for this data is live plotting while the simulation is running. The frequency of the plot events can be controlled from the controls class, see :ref:`frequencyLivePlot` from more information.
This event is supported by the Simplex and DE algorithms. The event data is a structure with the fields described below:

Fields in plot event
********************

.. list-table::
:header-rows: 1

* - Field
- Type
- Description
* - reflectivity
- array of double arrays
- The calculated reflectivities
* - shiftedData
- array of double arrays
- The data corrected with the scalefactor
* - sldProfiles
- array of double arrays
- The calculated SLD profiles
* - resampledLayers
- array of double arrays
- The resampled layers
* - subRoughs
- array of doubles
- The substrate roughness
* - dataPresent
- array of boolean/logical values
- flags indicating which contrast contains data
* - resample
- array of boolean/logical values
- flags indicating which contrast was resampled
* - modelType
- string
- The model type used for the calculation
* - contrastNames
- array of strings
- The name for each contrast which can be used to add a plot legend

.. _progress_event:

Progress Event
==============
The progress event gives the percentage completion for the calculation, and a title text for the event. This event is only supported by the DREAM algorithm. The event data is a structure with the fields described below:

Fields in progress event
************************

.. list-table::
:header-rows: 1

* - Field
- Type
- Description
* - message
- string
- The title text for the event
* - percent
- float
- The percentage of the calculation completed
40 changes: 28 additions & 12 deletions source/advanced/resampling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ is circumvented:
However, this kind of 'dumb microslicing' causes the creation of a large number of layers, which may not all be necessary and will significantly slow down the calculation.

This problem of finding the lowest number of individual points that will completely describe a waveform is a common problem in signal processing. RAT uses a technique
borrowed from SP called Adaptive Resampling (AR).
borrowed from signal processing called Adaptive Resampling (AR).

AR is an interactive process which aims to find the lowest number of points that will best describe a curve. It does this by adding points where the angle between neighbouring
points becomes greater than a threshold value. So, it adds more points where the signal is changing most strongly (in order to capture all details of the curvature). So, for a
points becomes smaller than a threshold value. So, it adds more points where the signal is changing most strongly (in order to capture all details of the curvature). So, for a
cosine wave, the resampled points cluster at the regions of the largest curvature:

.. image:: ../images/advanced/adaptiveSpPic.png
:width: 700
:alt: adaptive cosine

So, for the continuous cosine curve show in blue, the AR algorithm has chosen the red points as being most representative. In other words, if the red points were
For the continuous cosine curve show in blue, the AR algorithm has chosen the red points as being most representative. In other words, if the red points were
joined with straight lines, the resulting curve would be very similar to the original signal. The salient point is that more points are required where the gradient
of the signal is changing quickly, and those where the gradient is constant can be represented by fewer points.

Expand All @@ -37,14 +37,16 @@ distance between neighbouring points. So, for an SLD profile of a floating bilay
:width: 700
:alt: sld and dots...

..which are then converted into a set of zero roughness layers:
which are then converted into a set of zero roughness layers:

.. image:: ../images/advanced/layersPic.png
:width: 700
:alt: sld and dots...

**Using Resampling in RAT**
Using resampling on a contrast in RAT is very simple. For any contrast that you want to reample, then simply set the 'resample' flag for that contrast to 'true'
***********************
Using Resampling in RAT
***********************
Using resampling on a contrast in RAT is very simple. For any contrast that you want to resample, simply set the ``resample`` flag for that contrast as shown below:

.. tab-set-code::
.. code-block:: Matlab
Expand Down Expand Up @@ -84,7 +86,7 @@ Using resampling on a contrast in RAT is very simple. For any contrast that you
print(problem.contrasts)


The resampling itself is controlled by the 'resamPars' field in the controls block:
The resampling operation is controlled by the parameters ``resampleMinAngle`` and ``resampleNPoints`` in the controls object:

.. tab-set::
:class: tab-label-hidden
Expand All @@ -106,12 +108,26 @@ The resampling itself is controlled by the 'resamPars' field in the controls blo
controls = RAT.Controls()
print(controls)

The resampPars field has two parameters in it, corresponding to the minimum angle and minimum points (resamPars = [minAngle minPoints]) which to use to resample the profiles.
These have the following effects:
* ``resampleMinAngle``: For each data point, the algorithm draws two lines from that data point to its neighbouring points on either side.
If the angle between those lines is smaller than ``resampleMinAngle``, then the algorithm will refine over that point.

* **minAngle**: The algorithm refines near the points which form, together with their left and right neighbours, a triangle with central angle smaller than the given value. So, a larger value of minAngle results in a finer resampling. minAngle is defined as a multiple of pi (i.e. minAngle = 0.9 refines where the adjacent points form an angle greater than 0.9 * pi)
In practice, this means that resampling happens for points which are significantly higher or lower than their neighbours
(i.e. the gradient of the function has changed rapidly)
and ``resampleMinAngle`` controls the sensitivity of this.

``resampleMinAngle`` is defined in the units of 'radians divided by pi', i.e. ``resampleMinAngle = 0.9`` refines where the adjacent points form an angle smaller than :math:`0.9 \pi` radians.

* **nPoints**: The initial number of domain points (layers). The algorithm will start from this number of layers, and refine until all the *minAngle* criteria are satisfied.
* ``resampleNPoints``: The initial number of domain points (layers) sampled by the algorithm at the start.

.. note::
Generally, *minAngle* has a larger effect on the eventual resampling than *nPoints*.
Generally, ``resampleMinAngle`` has a larger effect on the eventual resampling than ``resampleNPoints``.

.. figure:: ../images/advanced/resample_angles.png
:width: 700

A simple example of how resampling calculates angles, with ``resampleNPoints`` = 5.
If ``resampleMinAngle`` were set to its default value of 0.9,
then resampling would occur around :math:`x_1` and :math:`x_3`, but not :math:`x_2`.



Binary file added source/images/advanced/resample_angles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed source/images/misc/eventContents.png
Binary file not shown.
Binary file removed source/images/misc/updateBreakPoint.png
Binary file not shown.
4 changes: 0 additions & 4 deletions source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ RAT contains a number of improvements over legacy RasCAL, including:
* :ref:`Plotting routines<simplePlotting>` for easy visualisation of data and fits
* and more!

.. As well as this documentation, there are extensive examples in the RAT/examples folder
TODO Add a link to the examples in the grid when the example pages are created.


.. grid:: 1 1 3 3

.. grid-item-card::
Expand Down
2 changes: 1 addition & 1 deletion source/tutorial/chapter2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ containing the simulated reflectivities, SLD's and so on from whatever procedure

controls = controlsClass;
controls.display = 'off';
[~, ~, results] = evalc('RAT(problem, controls);');
[~, ~, results] = evalc('RAT(load("source/tutorial/data/monolayerExample.mat").problem, controls);');
disp(results)

.. tab-item:: Python
Expand Down
6 changes: 5 additions & 1 deletion source/utilities/livePlot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ reflectivity, SLD's and more as the fit progresses. To visualize the plot event
When the snippet above is run, a plot figure willed be opened and the plot will be updated every time a plot event is received.


**Frequency of events**
.. _frequencyLivePlot:

************************
Frequency of Plot Events
************************

To control how often the plot event is triggered, change the plot frequency parameter in the controls block as shown below. The default frequency is 20 which means the
plot event is triggered after every 20 iterations.
Expand Down