Skip to content

Sequence

Sequences

Existing sequences

All tomo sequences share following parameters:

mrtomo_config.config_pars

    "start_pos": 0,                 # start position of rotation axis 
    "range": 360,                   # tomo range
    "flat_n": 21,                   # number of flat images
    "dark_n": 20,                   # number of dark images
    "tomo_n": 999,                  # number of projection images
    "energy": 0.0,                  # energy value in keV
    "exposure_time": 0.5,           # exposure time in sec for one image
    "comment": "",                  # string to specify what you want concerning acquisition
    "latency_time": 1e-5,           # extra time in sec to be added to camera time (exposure + readout) in case of continuous scan

Besides projections all tomo sequences can acquire extra images before and/or after: - dark images at start/end - flat images at start/end - static images on return (i.e when rotation goes back to start position)

Static images are taken every 90 degrees by default but you can choose to take then at same angle as flat images.

It is also possible to take flat images every N projections.

If your sample is bigger than field of view, you can activate half acquisition option. Activate it gives you access to dedicated menu to help you to calculated lateral axis displacement.

Finally, if you want to protect your scans from refill or beam lost, you can activate: - beam_check: detect beam lost during tomo and redo it - wait_for_beam: check that frontend is open before running tomo otherwise wait until the opening - refill_check: check for next refill before running tomo and pause it if refill is imminent

These options are not shared between sequences but exist for all of them:

mrfull_tomo.basic_pars

    "return_images_aligned_to_flats": False,        #take static images at same angle as flat images
    "save_flag": True,
    "display_flag": True,
    "return_to_start_pos": True,
    "projection_groups": False,                     #set it to True if you want to take flat images in between projections
    "flat_on": 500,                                 #number of projections after which you want to take flat images
    "dark_at_start": False,                         #take dark images before projections
    "flat_at_start": True,                          #take flat images before projections
    "dark_at_end": False,                           #take dark images after projections
    "flat_at_end": False,                           #take flat images after projections
    "images_on_return": True,                       #take static images after projections
    "scan_type": ScanType.CONTINUOUS,               #type of projections scan
    "half_acquisition": False,                      #activate half acquisition
    "full_frame_position": 0.0,                     #lateral axis position in full frame acquisition
    "acquisition_position": 0.0,                    #lateral axis position in half acquisition
    "shift_in_fov_factor": 0.0,                     #lateral axis displacement express in field-of-view factor
    "shift_in_mm": 0.0,                             #lateral axis displacement express in millimeters
    "shift_in_pixels": 0,                           #lateral axis displacement express in pixels
    "shift_type": "Field-of-view factor",           #type of lateral axis displacement chosen
    "return_to_full_frame_position": False,         #set it to True if you want to put back lateral axis in full field position after acquisition
    "move_to_acquisition_position": False,          #set it to True if you want to move lateral axis to half acquition position in the menu
    "beam_check": False,                            #activate beam check safety
    "wait_for_beam": False,                         #activate wait for beam safety
    "refill_check": False,                          #activate refill check safety

FullFieldTomo

- name: mrfull_tomo
  plugin: bliss
  class: FullFieldTomo
  package: tomo.fulltomo

  tomo_config: $mrtomo_config

This sequence uses all single motor scans of fscan library. You can then run: - continuous scan (fscan) - interlaced scan (finterlaced) - sweep scan (fsweep)

You can also do step scans.

Three useful commands exist:

mrfull_tomo.full_turn_scan()        # 360 tomo range
mrfull_tomo.half_turn_scan()        # 180 tomo range
mrfull_tomo.basic_turn_scan()       # free tomo range based on tomo_range parameter

ZSeries

- name: mrz_series
  plugin: bliss
  class: ZSeries
  package: tomo.zseries

  tomo_config: $mrtomo_config
  tomo: $mrfull_tomo                # full field tomo sequence on which you want to loop
  z_axis: $mrsz

This sequence is just a loop on fullfield sequence with displacement of z axis in between.

Specific parameters exist for this sequence:

mrz_series.sequence_pars

    "nb_digits": 3,                 # digits number used in saving directory name
    "step_start_pos": 0.0,          # start position for z axis 
    "start_nb": 1,                  # stage index from which sequence will start 
    "delta_pos": 1,                 # displacement value of z axis between each tomo
    "sleep": 0.0,                   # sleep time in sec after moving z axis
    "one_collection_per_z": True,   # option to be set to True if you want to create one collection per tomo
    "one_dataset_per_z": False,     # option to be set to True if you want to create one dataset per tomo

Same useful commands as for fullfield tomo exist:

mrz_series.full_turn_scan(delta_pos,nb_scans)       # 360 tomo range
mrz_series.half_turn_scan(delta_pos,nb_scans)       # 180 tomo range
mrz_series.basic_turn_scan(delta_pos,nb_scans)      # free tomo range based on tomo_range parameter

For all these commands you can give collection_name argument if you want to activate one_collection_per_z option or dataset_name argument if you want to activate one_dataset_per_z option:

mrz_series.full_turn_scan(delta_pos,nb_scans,collection_name='mycollectionname')
mrz_series.full_turn_scan(delta_pos,nb_scans,dataset_name='mydatasetname')

TopoTomo

- name: mrtopo_tomo
  plugin: bliss
  class: TopoTomo
  package: tomo.topotomo

  tomo_config: $mrtomo_config
  nested_axis: $yrot_eh2

This sequence allows to scan a nested axis at each rotation angle. The nested scan can be: - continuous (based on fscan2d of fscan library, see https://bliss.gitlab-pages.esrf.fr/fscan/usage_fscan2d.html) - step-by-step (based on bliss common amesh scan, see https://bliss.gitlab-pages.esrf.fr/bliss/master/scan_default.html#amesh)

Specific parameters exist for this sequence:

mrtopo_tomo.sequence_pars

    "nested_start_pos": 0.0,        # nested axis start position
    "nested_end_pos": 100.0,        # nested axis stop position
    "nested_npoints": 100           # nested scan number of points

Same useful commands as for fullfield tomo exist:

mrtopo_tomo.full_turn_scan(nested_start_pos, nested_end_pos, nested_npoints)       # 360 tomo range
mrtopo_tomo.half_turn_scan(nested_start_pos, nested_end_pos, nested_npoints)       # 180 tomo range
mrtopo_tomo.basic_turn_scan(nested_start_pos, nested_end_pos, nested_npoints)      # free tomo range based on tomo_range parameter

MultiTurnsTomo

PcoTomo

How to create new sequence

Template:

from fscan.fscantools import FScanParamBase
from tomo.sequencebasic import SequenceBasic, Pars

class MySequencePars(FScanParamBase):
    DEFAULT = {
        "mypar1": False,
        "mypar2": 0,
    }
    LISTVAL = {}
    NOSETTINGS = []

    def __init__(self, name):
        FScanParamBase.__init__(
            self,
            name,
            MySequencePars.DEFAULT,
            value_list=MySequencePars.LISTVAL,
            no_settings=MySequencePars.NOSETTINGS,
        )

class MySequence(SequenceBasic):

    def __init__(self, name, config):
        self.name = name + "_sequence"
        self.sequence_pars = MySequencePars(self.name)
        super().__init__(name, config)

    def create_parameters(self):
        default = {
            **self.basic_pars.DEFAULT,
            **self.config_pars.DEFAULT,
            **self.sequence_pars.DEFAULT,
        }
        listval = {
            **self.basic_pars.LISTVAL,
            **self.config_pars.LISTVAL,
            **self.sequence_pars.LISTVAL,
        }
        nosettings = (
            self.basic_pars.NOSETTINGS
            + self.config_pars.NOSETTINGS
            + self.sequence_pars.NOSETTINGS
        )
        self.pars = Pars(self.name, self, default, listval, nosettings)

    def get_parameters(self):
        """
        Return basic and specific sequence parameters as a dictionary
        """
        self.pars._update_cache()
        return self.pars.to_dict()

    def set_parameter(self, key, value):
        """
        Update key parameter with given value if key exists in basic
        or specific sequence parameters
        """
        if key in self.sequence_pars.to_dict():
            self.sequence_pars.from_dict({key: value})
        else:
            super().set_parameter(key, value)

    def set_parameters(self, dict):
        """
        Update all basic or specific sequence parameters present in the
        given dictionary with corresponding values
        """
        for key, value in dict.items():
            self.set_parameter(key, value)

    def validate(self):
        """
        Need to be implemented if you want to check coherency of specific parameters and estimate sequence duration
        """
        self._inpars.scan_time = my_scan_time

    def add_metadata(self, scan_info):
        """
        Need to be implemented if you want to add some specific informations in scan metadata technique field
        """
        super().add_metadata(scan_info)
        scan_info["technique"]["mynewkey"] = "mynewvalue"

    def projection_scan(
        self, motor, start_pos, end_pos, tomo_n, expo_time, scan_info=None, run=True
    ):
        """
        Need to be implemented to create your projection scan by calling a specific tomo runner
        """
        tomo_scan = MyTomoRunner(
            motor,
            start_pos,
            end_pos,
            tomo_n,
            expo_time,
            scan_info=scan_info,
            run=False,
        )

        self._inpars.proj_time = runner._estimate_scan_duration(self._inpars)

        if run:
            tomo_scan.run()

        return tomo_scan

    def build_sequence(self):
        """
        Need to be implemented to build your scan sequence (add dark, flat, projection and return scans)
        """ 
        if self.pars.dark_at_start:
            self.add_dark()
        if self.pars.flat_at_start:
            self.add_flat()
        if self.pars.projection_groups:
            self.add_projections_group(
                self.pars.start_pos,
                self.pars.start_pos + self.pars.range,
                self.pars.tomo_n,
                self.pars.exposure_time,
                flat_on=self.pars.flat_on,
            )
        else:
            self.add_proj(
                self.pars.start_pos,
                self.pars.start_pos + self.pars.range,
                self.pars.tomo_n,
                self.pars.exposure_time,
            )
        if self.pars.dark_at_end:
            self.add_dark()
        if self.pars.flat_at_end:
            self.add_flat()
        if self.pars.images_on_return:
            self.add_return()

    def _send_icat_metadata(self):
        """
        Need to be implemented because some info are collected differently from one sequence to another
        like TOMO_accelDisp or if you want to overwrite some metadata
        """
        super()._send_icat_metadata()
        scan_saving = current_session.scan_saving
        scan_saving.dataset.write_metadata_field("metadata_field", str(metadata_value))