24. GDA Use Cases

24.1. Use Case: ‘Old’ style scanning

Name

Running an ‘old style’ scan on the p45 beamline

Description

This use case describes the actions taken by the GDA server when a scan command is issued from the GDA client Jython console to scan a ScannableMotor (stage_x), operating on the p45 beamline. The command issue is: scan stage_x 0 10 2 which will scan stage_x from 0 to 10 with an steps of 2. This represents the ‘old’ style of scanning (also known as the ‘spec’ style) using scan classes contained in the gda-core repo.

Goal

The GDA server will manage all of the scannable devices involved in the scan to perform the scan and save the resulting data.

Actors

Beamline user, GDA client

Preconditions

ActiveMQ has been started and is running on the local host. The GDA server has been started in dummy mode for the p45 beamline and so is running on the local host. The p45 GDA client has been started and is running.

Frequency

Scanning is a key process for beamline operation therefore it is a common task to be carried out.

Basic Course

  1. The user submits a scan command through the GDA client Jython console using the command: scan stage_x 0 10 2 (i.e. scan <scannable> <start> <end> <interval>).

  2. The client makes an Remote Procedure Call (RPC) to the Jython server.

  3. The server uses the GDAJythonInterpreter to interpret the Jython command which is then compiled and run in the InteractiveInterpreter as a Python command.

  4. The Python script, concurrentScanWrapper is called which issues commands to prepare for the scan.

  5. A new Java ConcurrentScan (extension of ConcurrentScanChild -> ScanBase) object is constructed to create the scan by constructing a map of ScanObject (i.e. the Scannables involved in the scan - stage_x). Checks are also performed here to make sure that the scan parameters are feasible.

  6. Once the scan has been created, the python script calls to runScan() from the ScanBase class.

  7. More preparation is carried out before the collection. The two most important are the set-up of the DataWriter (NexusDataWriter), which outputs NeXus files) and the MultithreadedScanDataPointPipeline (extensions of ScanDataPointPipeline) to compute ScanDataPoint (for which there will be one per scan position) and manage threads to broadcast them.

  8. Once ready, the doCollection() method is called from the ConcurrentScan class (view Sequence Diagram) which begins the collection of data and scanning. It iterates over the scan positions which in this case is 6 (0,2,4,6,8,10).
    1. ConcurrentScan.doCollection(): The acquirePoint() method is called from the ConcurrentScanChild to move to the next step in the scan. This calls moveStep() on a scannable device and in this case acts on the ScannableMotor to the DummyMotor. If the device is a detector then collectData() is called on the Detector which tells the detector to begin to collect a set of data.

    2. ConcurrentScan.doCollection(): readDevicesAndPublishScanDataPoint() is called next to create a ScanDataPoint containing information about the position of all scannables, If a detector is present then it will also call readout() on the Detector to return the latest data collected and add this to the ScanDataPoint. The ScanDataPoint is then added to a pipeline ready to be published. A ScanDataPointPublisher is created and instructed to publish the ScanDataPoint. This adds data to the NexusDataWriter about the point, which will create a new NeXus file (/gda_data_non_live/p45-1.nxs) in HDF5 format (as this is the first scan position) and write the data to file. The first scan position is complete.

  9. ConcurrentScan.doCollection(): Continues the iteration to the next position (i.e. 2) and the same process described in 8a and 8b is followed except that the NeXus file has already been created by the NexusDataWriter so the data is written to p45-1.nxs.

  10. On completion of all scan positions, ConcurrentScan returns to ScanBase which calls to endScan(). This begins the shut-down of the key components including the MultithreadedScanDataPointPipeline, ScanDataPointPublisher and the NexusDataWriter. Finally the Jython Server is notified that the scan is now complete.

  11. On receipt that the scan is complete and data has been written, post-processing begins by calling the python scripts ScanDataProcessor and ScanDataProcessorResults to process the data and get the results.

  12. Results of the scan are relayed through RMI to the client and output on the Jython Console in the client. This ends the scan.

Post Conditions

None

Notes

If a detector is also defined in the scan command entered in the Jython console.

24.1.1. Class diagram

_images/OldScanning_ClassDiagram.png

24.2. Use Case: ‘New’ style/ Solstice

The new style scanning, (also known as Mapping or Solstice) can be found in bundles statrting with org.eclipse.scanning in the - gda-core.git. New style scanning allows interaction with Malcolm for hardware triggered scanning. It also in general assumes (at least) 2D scanning. It also only handles NeXus format. New style scanning can easily accommodate ‘layered’ scanning, with an inner and outer scan as well as a ‘standard’ scan involving GDA-8 scannables. Throughout, the term ‘GDA-8’ will be used to reference ‘old’ style scanning which was the only type of scanning available in GDA-8. If a Malcolm detector is used the it will run all detectors connected to it. In a ‘layered’ scan, Malcolm is responsible for running the inner scan (see here for more details on the use of the MalcolmDevice in scanning).

24.2.1. Generic process

The use case below will document the steps and processes involved in ‘new’ style scanning in detail. It will demonstrate the generic procedure which covers running standard 2D scans, ‘layered’ scans (with an inner and an outer scan) and use of Malcolm within scanning. For a specific use case using a Malcolm detector see here, or for an example of a standard scan with GDA-8 scannables see here.

Name

Running a ‘new style’/ mapping scan on the p45 beamline.

Description

This use case describes the actions taken by the GDA server when a mapping scan is submitted from the Mapping Experiment Setup panel on the client. It will describe the generic procedure carried out by the server, independent of the scan parameters.

Goal

The GDA server will manage all of the devices involved in the scan to perform the scan and save the resulting data. .

Actors

Beamline user, GDA client

Preconditions

ActiveMQ has been started and is running on the local host. The GDA server has been started in dummy mode for the p45 beamline and so is running on the local host. The p45 GDA client has been started and is running.

Basic Course

  1. The user enters values from the Mapping Experiment Setup panel to describe a desired scan. The user clicks Queue Scan. A ScanRequest is generated (which is wrapped in a ScanBean) and despatched over the Event Service (JSON+JMS) to a queue on the server. The ScanRequest contains all the information needed to run a scan. The points which the scan will run are generated using a CompoundModel which contains all the data for generating the scan points.

  2. A ScanServlet (servlet to process a queue) creates a process for each ScanRequest from the queue.

  3. The ScanProcess object is instantiated. It is this that is in charge of running the scan and has overall responsibility for the scan. This object implements the IConsumerProcess which is the process run when a consumer starts a job. The consumer is provided by the IEventService.

  4. The ScanProcess.execute() (view Sequence Diagram) method is called which begins to execute the ScanBean/ScanRequest.
    1. Firstly the method createPointGenerator() in ScanProcess.prepareScan() creates a Point Generator (IPointGenerator) according to the CompoundModel contained in the ScanRequest. The CompoundModel encapsulates all the information required to provide all the scan point locations (with regions) of any n-dimension scan. The IPointGenerator comprises of a nested or compound generator created from a list of these models.

    2. A ScanModel is created from the IPointGenerator. It converts the ScanBean to a ScanModel and contains the ‘real’ objects involved in the scan (not just those referenced in the bean). It also contains the IPointGenerator. The ScanModel is returned from the ScanProcess.prepareScan() method.

  5. ScanProcess.execute(): Following the setup, runScan() is called to begin running the scan.
    1. Firstly ‘runnable devices’ are created:
      1. If the ScanModel indicates the presence of a detector, then the detectors are configured. An AnnotationManger is created for each detector. The AnnotationManger parses annotations and allows methods to be efficiently called during a scan to notify the scan of the progress. The detectors are added as a device to the manager according to their ILevel. The ILevel is used to order the moving of the devices. For example, all level 1 devices will be moved first and when they complete, all level 2 devices will move etc. The invoke() method is called on the AnnotationManger to notify the methods with an annotation that ‘PreConfigure’ should happened. Any method in the detector class that has the annotation ‘@PreConfigure’ will run. The detector is then cast as an IRunnableDevice and configured by calling .configure(model) on it. Following this a ‘PostConfigure’ annotation is invoked. Detectors have now been configured.

      2. A DeviceController is created from the IDeviceWatchdog. The IDeviceController takes input from several clients and ensures that each of their preferences about pausing the device that is being controlled is taken into account (see javadocs link for an example of usage). The clients are ScanProcess and AcquisitionDevice. It also manages the watchdogs which run with the devices. These implement the annotation scheme and provide a way for monitoring a scan by calling their annotations at different points in the scan. The DeviceController can interrupt the scan when a particular external event occurs.

    2. Next the other devices including the AcquistionDevice (with name ‘solstice_scan’) are configured. This calls AcquisitionDevice.configure() (view Sequence Diagram). The AquisitionDevice does a standard GDA scan at each point in the model.
      1. During the configure() it will check if the declared devices in the scan are INexusDevices and set up these by creating the Nexus file manager (NexusScanFileManager) and then configuring it.

      2. The scannables in the scan model are set and an IPositioner is created. The IPositioner wraps the scannables and is used to move them each to a desired position. The scannables are moved in order of their levels (as mentioned above) in separate threads.

      3. If configuring the NexusScanFileManager (in the case of an INexusDevice) a solstice scan monitor is created (SolsticescanMonitor) which uses ILazyWriteableDataset to write the unique key and scan points dataset in a NeXus file. More details of NeXus can be found here [TODO].

      4. ‘Runners’ are also created, which runs any collection of objects by reading their levels. It will run all devices on each level and wait for them to finish. If the devices are detectors then the runner will be a DeviceRunner (which extends LevelRunner), otherwise it will be a LevelRunner. The DeviceRunner runs detectors in a task and is essentially equivalent to the GDA-8 collectData() call.

      5. ‘Writers’ are also created which calls the write() method. Again, if the device is a detector then a DeviceWriter is used, otherwise it is a LevelWriter.

  6. ScanProcess.runScan(): continues to set file paths and validate the scan.

  7. ScanProcess.runScan(): Any detectors (including Malcolm) and the AcquisitionDevice have now been created and configured and are managed by the DeviceController. The final call in the ScanProcess.runScan() method is to runScanBlocking() (normal case) or runScanNonBlocking(). This calls run() on the AcquisitionDevice which will run the scan until complete by iterating through the scan positions. AcquisitionDevice.run() (view Sequence Diagram):
    1. First it checks that the devices are armed.

    2. If a Malcolm device is present then it adds Malcolm listeners to monitor the progress on the inner Malcolm scan.

    3. It begins to iterate over the collection of IPositions using the Iterator<E>. The call of ‘iterable’ on the Iterator class creates a Jython compound generator (compoundgenerator.py). This goes through the list of generators and creates objects using jython_spg_interface.py to create a specific generator (e.g. JLineGenerator1D) and wrap the points into a Java object (ScanPointInterator) through JavaIteratorWrapper(...). The ScanPointInterator implements Iterable<IPosition>.
      1. For each position it first checks to see whether ‘pause’ or ‘abort’ has been called. It then uses the AnnotationManager to invoke ‘PointStart’. Next it calls setPosition which is equivalent to moveTo() in old style scanning. For GDA-8 scannables, the setPosition() call implements that from the ScannableNexusWrapper which wraps the GDA-8 scannables and will write any GDA-8 scannable to NeXus.

      2. At each position the queue job is updated which is reflected on the client’s Queue panel.

      3. It waits for any previous write out to return (as writing is a non-blocking process) and invokes ‘WriteComplete’ on the AnnotationManager.

      4. The run() method is then called on the ‘runners’ and ‘writers’. For GDA-8 scannables this is equivalent to collectData() and for Malcolm this means run(). As described already, the LevelRunner/DeviceRunner will run the devices according to their respected levels and wait for each to complete before running the devices on the next level. Writing is ‘non-blocking’ however and it should move to the next position (where is will wait in step 7.c.iii). If the scan involves an inner and outer scan then the outer scannable will be moved first by the runner (with higher priority). Following that the inner scan will be run. If a Malcolm device is present then it will run the inner scan. The AcquistionDevice will just consider it as one scan position. Once the inner scan completes and the AcquisitionDevice receives news from its listeners that the Malcolm scan has completed.

      5. The AnnotationManager is invoked with ‘PointEnd’ and the ScanBean is updated with the scan progress.

    4. It will move on to the next position. Again, if it is a layered scan then it will move to the next position for the outer scan before again running the inner scan. So it continues.

    5. When all scan positions have been completed, the run() method calls close() which closes down the Writer and Runner, and calls scanFinished() on the SolsticeScanMonitor which records that the scan as finished.

    6. Once the NeXus file is closed the bean is updated that the scan is complete and is published.

    7. Finally, the AnnotationManager is used to invoke @ScanFinally which will invoke any methods with this annotation.

  8. The AcquisitionDevice.run() returns to ScanProcess.runScan() -> ScanProcess.execute() and finishes.

  9. Client Queue panel shows Status Complete and 100% complete.

Post Conditions

None

Notes

  • The scanning does not make a distinction between a Malcolm device, an area detector or a CPU device. They all implement the same runnable device interface and are operated the same way at the level of the scan.

  • If using Malcolm in a layered scan, then the whole PointGenerator is passed to the Malcolm device (including both inner and outer scans) even though it only runs the inner as it needs to calculate the file size.

  • Runners run() method is equivalent to collectData() in old style scanning and the writers call() method is equivalent to readout().

24.2.2. Standard GDA-8 Scan

Please use the above genetic new style scanning as a reference for more details. The use case below will assume general knowledge on how ‘new’ style scanning works and will build on it to demonstrate how a standard (GDA-8) 3x2 scan of stageX and stageY (motors) is run in the ‘new’ style scanning.

Name

Running a ‘new style’/ mapping scan on the p45 beamline with Malcolm

Description

This use case describes the actions taken by the GDA server when a mapping scan is submitted from the Mapping Experiment Setup panel on the client. The scan parameters specify a ‘Rectangle’ shaped scan using the ‘Grid’ path for a 3 x 2 scan (stageX x stageY) giving a total of 6 scan positions.

Goal

The GDA server will manage all of the devices involved in the scan to perform the scan and save the resulting data.

Actors

Beamline user, GDA client

Preconditions

ActiveMQ has been started and is running on the local host. The GDA server has been started in dummy mode for the p45 beamline. The p45 GDA client has been started and is running.

Basic Course

  1. The user enters values from the Mapping Experiment Setup panel to describe a 3x2 grid scan with all other parameters as default. The user clicks Queue Scan. A ScanRequest (see example) is generated (which is wrapped in a ScanBean) and despatched over the Event Service (JSON+JMS) to a queue on the server. The points which the scan will run are generated using a CompoundModel.

  2. A ScanServlet creates a process for each ScanRequest from the queue.

  3. The ScanProcess object is instantiated. This object implements the IConsumerProcess. The consumer is provided by the IEventService.

  4. The ScanProcess.execute() method is called which begins to execute the ScanBean/ScanRequest.
    1. Firstly the method createPointGenerator() in ScanProcess.prepareScan() creates a Point Generator (IPointGenerator) according to the CompoundModel contained in the ScanRequest (again see example to identify this object).

    2. A ScanModel is created from the IPointGenerator. It converts the ScanBean to a ScanModel and contains the ‘real’ objects involved in the scan (not just those referenced in the bean). It also contains the IPointGenerator. The ScanModel is returned from the ScanProcess.prepareScan() method.

  5. ScanProcess.execute(): Following the setup, runScan() is called to begin running the scan.
    1. Firstly ‘runnable devices’ are created:
      1. A DeviceController is created from the IDeviceWatchdog.

    2. Next the AcquistionDevice (with name ‘solstice_scan’) is configured. This calls AcquisitionDevice.configure().
      1. The scannables in the scan model (stageX and stageY) are set and an IPositioner is created. The scannables are moved in order of their levels.

      2. The ‘runners’ are created for the devices. A LevelRunner is used for the stageX and stageY.

  6. ScanProcess.runScan(): continues to set file paths and validate the scan.

  7. ScanProcess.runScan(): The AcquisitionDevice has now been created and configured and managed by the DeviceController. The final call in the ScanProcess.runScan() method is to runScanBlocking(). This calls run() on the AcquisitionDevice which will run the scan until complete by iterating through the scan positions. AcquisitionDevice.run():
    1. First it checks that stageX and stageY are armed.

    2. It begins to iterate over the collection of IPositions using the Iterator<E>.
      1. For each position it first checks to see whether ‘pause’ or ‘abort’ has been called. It then uses the AnnotationManager to invoke ‘PointStart’. Next it calls setPosition. For stageX and stageY (a GDA-8 scannable), the setPosition() call implements that from the ScannableNexusWrapper which wraps the GDA-8 scannables and will write any GDA-8 scannable to NeXus.

      2. At each position the queue job is updated which is reflected on the client’s Queue panel.

      3. It waits for any previous write out to return (as writing is a non-blocking process) and invokes ‘WriteComplete’ on the AnnotationManager.

      4. The run() method is then called on the ‘runners’ and ‘writers’. As described already, the LevelRunner will run the devices according to their respected levels and wait for each to complete before running the devices on the next level. stageX will be moved first and then stageY.

      5. The AnnotationManager is invoked with ‘PointEnd’ and the ScanBean is updated with the scan progress.

    1. It will move on to the next position. It will move stageX to the next position in the sequence (which will be the same) and then move stageY to the next position. The process will continue until all scan positions have been completed.

    2. When all scan positions have been completed, the run() method calls close() which closes down the Writer and Runner, and calls scanFinished() on the SolsticeScanMonitor which records that the scan as finished.

    3. Lastly, once the NeXus file is closed the bean is updated that the scan is complete and is published.

  8. The AcquisitionDevice.run() returns to ScanProcess.runScan() -> ScanProcess.execute() and finishes.

  9. Client Queue panel shows Status Complete and 100% complete.

Post Conditions

None

Notes

  • Runners run() method is equivalent to collectData() in old style scanning and the writers call() method is equivalent to readout().

24.2.3. Layered Malcolm Scanning

Please use the above genetic new style scanning as a reference for more details. The use case below will assume general knowledge on how ‘new’ style scanning works and will build on it to demonstrate how Malcolm is used in a layer scan as the inner scan. Specific details of how the MalcolmDevice responds to commands made during scan can be found here.

Name

Running a ‘new style’/ mapping scan on the p45 beamline with Malcolm

Description

This use case describes the actions taken by the GDA server when a mapping scan is submitted from the Mapping Experiment Setup panel on the client. The scan parameters specify a 3D scan with an inner and outer scan. The outer scan is of the stageZ axis with 11 scan positions. The inner scan is a ‘Rectangle’ shaped scan using the ‘Grid’ path for a 5 x 5 scan (stageX, stageY). This will result in a total of 275 scan positions. The Malcolm Detector is selected and this will manage the inner scan.

Goal

The GDA server will manage all of the devices involved in the scan to perform the scan and save the resulting data. It will also interface with Malcolm devices through a connection service.

Actors

Beamline user, GDA client, Malcolm

Preconditions

ActiveMQ has been started and is running on the local host. The GDA server has been started in live mode for the p45 beamline. The p45 GDA client has been started and is running.

Basic Course

  1. The user enters values from the Mapping Experiment Setup panel to describe an outer scan of the stageZ with 11 positions and an inner 5x5 grid scan of the stageX and stageY. The Malcolm Dummy Detector is selected. All other parameters remain as default. The user clicks Queue Scan. A ScanRequest (see example) is generated (which is wrapped in a ScanBean) and despatched over the Event Service (JSON+JMS) to a queue on the server. The points which the scan will run are generated using a CompoundModel.

  2. A ScanServlet creates a process for each ScanRequest from the queue.

  3. The ScanProcess object is instantiated. This object implements the IConsumerProcess. The consumer is provided by the IEventService.

  4. The ScanProcess.execute() method is called which begins to execute the ScanBean/ScanRequest.
    1. Firstly the method createPointGenerator() in ScanProcess.prepareScan() creates a Point Generator (IPointGenerator) according to the CompoundModel contained in the ScanRequest (again see example to identify this object).

    2. A ScanModel is created from the IPointGenerator. It converts the ScanBean to a ScanModel and contains the ‘real’ objects involved in the scan (not just those referenced in the bean). It also contains the IPointGenerator. The ScanModel is returned from the ScanProcess.prepareScan() method.

  5. ScanProcess.execute(): Following the setup, runScan() is called to begin running the scan.
    1. Firstly ‘runnable devices’ are created:
      1. The Malcolm detector is configured. An AnnotationManger is created and the Malcolm detector is added as a device to the manager. The invoke() method is called on the AnnotationManger to notify the methods with an annotation that ‘PreConfigure’ should happened. Any method in the detector class that has the annotation @PreConfigure will run, which includes the AbstractMaloclmDevice.configureScan() method. The detector is then cast as an IRunnableDevice and configured by calling .configure(model) on the MalcolmDevice.

      2. A DeviceController is created from the IDeviceWatchdog.

    2. Next the AcquistionDevice (with name ‘solstice_scan’) is configured. This calls AcquisitionDevice.configure().
      1. During the configure() it will set up the Nexus writing by creating the Nexus file manager (NexusScanFileManager) and then configuring it.

      2. The scannables in the scan model (stageZ and Malcolm) are set and an IPositioner is created. The scannables are moved in order of their levels.

      3. When configuring the NexusScanFileManager a solstice scan monitor is created (SolsticescanMonitor) which uses ILazyWriteableDataset to write the unique key and scan points dataset in a NeXus file. More details of NeXus can be found here [TODO].

      4. The ‘runners’ are created for the devices. A LevelRunner is used for the stageZ scannable while a DeviceRunner is used for the Malcolm device

      5. The ‘writers’ are also created in the scan pattern as the ‘runners’.

  6. ScanProcess.runScan(): continues to set file paths and validate the scan.

  7. ScanProcess.runScan(): The Malcolm device and the AcquisitionDevice have now been created and configured and are managed by the DeviceController. The final call in the ScanProcess.runScan() method is to runScanBlocking(). This calls run() on the AcquisitionDevice which will run the scan until complete by iterating through the scan positions. AcquisitionDevice.run():
    1. First it checks that the Malcolm device and stageZ are armed.

    2. It adds Malcolm listeners to monitor the progress on the inner Malcolm scan.

    3. It begins to iterate over the collection of IPositions using the Iterator<E>.
      1. For each position it first checks to see whether ‘pause’ or ‘abort’ has been called. It then uses the AnnotationManager to invoke ‘PointStart’. Next it calls setPosition. For stageZ (a GDA-8 scannable), the setPosition() call implements that from the ScannableNexusWrapper which wraps the GDA-8 scannables and will write any GDA-8 scannable to NeXus.

      2. At each position the queue job is updated which is reflected on the client’s Queue panel.

      3. It waits for any previous write out to return (as writing is a non-blocking process) and invokes ‘WriteComplete’ on the AnnotationManager.

      4. The run() method is then called on the ‘runners’ and ‘writers’. As described already, the LevelRunner/DeviceRunner will run the devices according to their respected levels and wait for each to complete before running the devices on the next level. The first move will be on the outer scannable (stageZ) to its first position. Following that the inner scan will be run. The DeviceRunner will call run() on the MalcolmDvice and it will run the inner scan. The AcquistionDevice will just consider the inner scan of stageX and stageY as one scan position even though there will be 25 scan positions within it. This is because Malcolm is managing this. Once the inner scan completes and the AcquisitionDevice receives news from its Malcolm listener that the Malcolm scan has completed.

      5. The AnnotationManager is invoked with ‘PointEnd’ and the ScanBean is updated with the scan progress.

    4. It will move on to the next position. It will move stageZ to the next position in the sequence and once complete, it will call on the DeviceRunner to once again run the MalcolmDevice. So it continues until all 11x5x5 scans have been completed.

    5. When all scan positions have been completed, the run() method calls close() which closes down the Writer and Runner, and calls scanFinished() on the SolsticeScanMonitor which records that the scan as finished.

    6. Once the NeXus file is closed the bean is updated that the scan is complete and is published.

    7. Finally, the AnnotationManager is used to invoke @ScanFinally which will invoke the MalcolmDevice method reset() to reset Malcolm and return it to a ‘ready’ state.

  8. The AcquisitionDevice.run() returns to ScanProcess.runScan() -> ScanProcess.execute() and finishes.

  9. Client Queue panel shows Status Complete and 100% complete.

Post Conditions

None

Notes

  • The scanning does not make a distinction between a Malcolm device, an area detector or a CPU device. They all implement the same runnable device interface and are operated the same way at the level of the scan.

  • If using Malcolm in a layered scan, then the whole PointGenerator is passed to the Malcolm device (including both inner and outer scans) even though it only runs the inner as it needs to calculate the file size.

  • Runners run() method is equivalent to collectData() in old style scanning and the writers call() method is equivalent to readout().

24.2.4. Class diagram

_images/NewScanning_ClassDiagram.png

24.3. Use Case: MX Data Collection

See the MX Data Collections page of this document for more details on classes and methods involved.

Name

Performing a data collection on the MX beamline.

Description

This use case describes the actions taken by the GDA client and server when a scan is submitted from the Data Collection screen in the GDA client on the i03 beamline (used in dummy mode). A single sample is used for the scan. After submitting from the client, the server will control all the devices involved and run the scan through to completion. This beamline uses Zebra triggering and a Pilatus detector.

Goal

The GDA server will manage and configure all of the devices involved in the scan to perform the data collection and save the resulting data.

Actors

Beamline user, GDA client.

Preconditions

ActiveMQ has been started and is running on the local host. The GDA server has been started in dummy mode for the i03 beamline and so is also running on the local host. The i03 GDA client has been started and is running. The Data Collection option is has been selected and this page is showing in the client.

Frequency

Data collection in MX is equivalent to the concept of a scan in non-MX beamlines. It is a key process for beamline operation and commonly used.

Basic Course

  1. Set up the parameters for the scan from the Data Collection page in the client. Click on the button under ‘Sample’ and select the sample in position 1. Scroll down to the bottom and for the Sample position set 0, 0, 0.

  2. Run the scan by clicking Run Scan. This will add the scan to the queue and as the queue is empty, it will run immediately.

  3. From the client the DataCollectionScanManager is in-charge of collecting the scan parameters, validating and issuing instructions to the server to run. It contains the DataCollectionModel with the ExptTableModel which is an object used to store all the parameters that have been set by the user in the client to describe the scan.

  4. The DataCollectionScanManager converts the ExptTableModel to an ExtendedCollectRequest (ECR) object. This is saved as a .xml file and again contains all the parameters that describe the scan and can be accessed by the server.

  5. The final step on the client side is for the DataCollectionScanManager to create a Python command to pass to the server which will be issued by the JythonServer. This command calls the data_collection.py script on the server side and includes the location of the ECR xml file.

  6. Once submitted, the client checks the status of the CommandServer which returns as ‘running’. The client GUI shows a yellow box with the words ‘running’.

  7. The server picks up the process from the queue and issues the Python command. The `data_collection.py script Start() method is instigated using the ECR xml file.

  8. The data_collection.Start() calls on the datacollection.factory.create to create a CollectRequestHandler (CRH) from the HandleCollectRequest class (see this section for further details). This assesses the ECR passed to it determining that this ECR only has 1 row with 1 oscillation_sequence.

  9. HandleCollectRequest: The parameters defined the CRH object are set to those read in from the ECR file (e.g. detector, camera, attenuator).

  10. HandleCollectRequest: It loops over the collect_requests (members of the ECR), which is just 1 in this case and gets the ISPyB data collection group with ID. Following this it loads the sample on the container.

  11. Once initial set up is complete, the execute() method in HandleCollectiRequests class is called on the CRH object and this begins to run the scan. It starts a loop to iterate through each ECR (just 1 in this case). For each ECR:
    1. First checks are made on the status of the devices involved and then they are moved to initial positions. For example: the activateHutch script is run, the detector shutter is opened and the backlight is moved in.

    2. The sample is moved into position using the SmarGonController which controls the x,y and z positions.

    3. A snapshot is taken of the sample and saved.

    4. The backlight is moved out.

    5. The wavelength in changed and beamline energy is set.

  12. HandleCollectiRequests.doSample() is called next. This populates the ISPyB database with information on the data collection.
    1. The transmission is set to 100%.

    2. The detector is configured using EPICS. This uses the DummyAreaDetectorPilatus device (as this scan is run in dummy mode) which extends AreaDetectorPilatusBase.

  13. For each oscillation_sequence contained in this ECR, doOscillations() is called. Only 1 oscillation_sequence is contained in this ECR and so it only loops around once.
    1. doOscillation() calls to takeImageExZebra() as i03 uses the Zebra for triggering.

    2. The Zebra box is triggered.

    3. AreaDetectorPilatusBase starts the acquisition and returns that it is armed, ready for a trigger.

    4. HandleCollectRequests starts the exposure and the detector is triggered. It monitors the response from the detector until it is complete.

  14. On completion the Zebra is disarmed and HandleCollectRequests checks the number of files saved to see that it matches what is expected. With success of this, this current oscillation_sequence is deemed to be complete.

  15. As there are no more oscillation_sequences to run or collect_requests, the total data collection is now complete. The backlight is moved in and the detector shutter is closed.

  16. The JythonServerStatusHolder returns the Command Server status as IDLE and the Command Queue issues that the queued process is complete.

  17. Back in the client, the yellow ‘running’ status turns to green ‘Queue - waiting’ indicating that the data collection has completed and the queue is ready for another scan to be submitted.

Post Conditions

None

Notes

None

24.3.1. Class diagram

A class diagrams for the client side java classes can be found here.

invisible invisible invisible invisible