Commit 914c0ed3 authored by bliss administrator's avatar bliss administrator
Browse files

Merge branch 'id11'

Conflicts:
	tomo/Tomo.py
	tomo/TomoSequence.py
parents 5134eeb4 18a80c00
Pipeline #45655 passed with stages
in 3 minutes and 58 seconds
......@@ -947,14 +947,14 @@ class Tomo(TomoParameters):
# add shutter preset
shutter_preset = FastShutterPreset(self.shutter)
ret_scan.add_preset(shutter_preset)
if setup_globals.machinfo.check == True:
ret_scan_time = self.tomo_tools.estimate_return_scan_duration(
motor
)
refill_preset = WaitForRefillPreset(
setup_globals.machinfo, checktime=ret_scan_time
)
try:
machinfo_check = setup_globals.machinfo.check
except:
machinfo_check = False
if machinfo_check == True:
ret_scan_time = self.tomo_tools.estimate_return_scan_duration(motor)
refill_preset = WaitForRefillPreset(setup_globals.machinfo,checktime=ret_scan_time)
ret_scan.acq_chain.add_preset(refill_preset)
# add to scan sequence when requested
......@@ -1055,8 +1055,12 @@ class Tomo(TomoParameters):
# add dark shutter preset
dark_scan.add_preset(shutter_preset)
if setup_globals.machinfo.check == True:
try:
machinfo_check = setup_globals.machinfo.check
except:
machinfo_check = False
if machinfo_check == True:
dark_scan_time = self.tomo_tools.estimate_dark_scan_duration()
refill_preset = WaitForRefillPreset(
setup_globals.machinfo, checktime=dark_scan_time
......@@ -1161,14 +1165,14 @@ class Tomo(TomoParameters):
# add reference preset
ref_mot_preset = ReferenceMotorPreset(self.reference)
ref_scan.add_preset(ref_mot_preset)
if setup_globals.machinfo.check == True:
ref_scan_time = self.tomo_tools.estimate_ref_scan_duration(
motor
)
refill_preset = WaitForRefillPreset(
setup_globals.machinfo, checktime=ref_scan_time
)
try:
machinfo_check = setup_globals.machinfo.check
except:
machinfo_check = False
if machinfo_check == True:
ref_scan_time = self.tomo_tools.estimate_ref_scan_duration(motor)
refill_preset = WaitForRefillPreset(setup_globals.machinfo,checktime=ref_scan_time)
ref_scan.acq_chain.add_preset(refill_preset)
# add to scan sequence when requested
......
......@@ -641,6 +641,14 @@ class TomoCcd(TomoParameters):
else:
readout_time = self.detector.camera.readout_time
print(f"Frelon readout time = {readout_time} sec")
# Marana detectors
elif ccd_type.startswith("Marana"):
self.take_image(expo_time, 1)
readout_time = self.detector.camera.readout_time
frame_rate = self.detector.camera.frame_rate
print(f"Marana frame rate = {frame_rate} Hz")
print(f"Marana readout time = {readout_time} sec")
else:
raise ValueError(
"No readout time calibration method defined for the detector %s"
......
......@@ -75,6 +75,7 @@ class TomoScan:
extra_time = 0.0
shutter_time = 0.0
self.tomo.shutter.init()
if self.tomo.shutter.shutter_used == ShutterType.CCD:
shutter_time = self.tomo.shutter.fast_shutter_closing_time()
......
......@@ -322,7 +322,11 @@ class FastTomo:
shutter_preset = FastShutterPreset(self.tomo.shutter)
proj_scan.add_preset(shutter_preset)
if setup_globals.machinfo.check == True:
try:
machinfo_check = setup_globals.machinfo.check
except:
machinfo_check = False
if machinfo_check == True:
if self.tomo.parameters.scan_type == ScanType.STEP:
proj_scan_time = self.tomo.tomo_tools.step_scan_time(
self.tomo.rotation_axis, start_pos, nb_points
......
from bliss.common.shutter import BaseShutterState
class FastShutter(object):
def __init__(self, name, config):
......@@ -13,3 +14,11 @@ class FastShutter(object):
@property
def closing_time(self):
return self.fsh.shutter_time
@property
def state(self):
state = self.fsh.state
if state == "CLOSE":
return BaseShutterState.CLOSED
else:
return BaseShutterState.OPEN
......@@ -7,7 +7,16 @@ class OpiomPreset(TomoSequencePreset):
"""
Class to handle opiom setting
"""
CAM2MUX = {
"frelon1" : ("CAM1", "CAM1"),
"frelon2" : ("CAM2", "CAM2"),
"frelon3" : ("CAM3", "CAM3"),
"marana" : ("MARANA", None),
"frelon16" : ("CAM1", "CAM1"),
}
def __init__(self, name, config):
"""
Parameters
......@@ -32,27 +41,34 @@ class OpiomPreset(TomoSequencePreset):
super().__init__(name, config)
def prepare(self, tomo):
frelon2mux = {"frelon1": "CAM1", "frelon2": "CAM2", "frelon3": "CAM3"}
det_name = tomo.tomo_ccd.detector.name.lower()
self.cam_name = frelon2mux.get(det_name, None)
if self.cam_name is None:
limadev = tomo.tomo_ccd.detector
self.cam_name = limadev.name.lower()
if self.cam_name not in self.CAM2MUX:
raise ValueError(f"Unkown camera name [{det_name}] in tomo.OpiomPreset")
if tomo.parameters.scan_type == ScanType.SWEEP:
self.use_gate = True
else:
self.use_gate = False
if self.cam_name.startswith("frelon"):
if limadev.camera.image_mode == "FRAME TRANSFER":
limadev.shutter.mode = "MANUAL"
limadev.shutter.close_time = 0.0
def start(self):
"""
Switches multiplexer outputs according to desired mode
"""
self.mux.switch("SHUTTER", self.cam_name)
self.mux.switch(self.cam_name, "ON")
(cam_mux, shut_mux) = self.CAM2MUX[self.cam_name]
self.mux.switch("TRIGGER_MODE", "MUSST")
self.mux.switch(cam_mux, "ON")
if self.use_gate:
self.mux.switch("MUSST", "BTRIG")
else:
self.mux.switch("MUSST", "ATRIG")
self.mux.switch("TRIGGER_MODE", "MUSST")
if shut_mux is not None:
self.mux.switch("SHUTTER", shut_mux)
def stop(self):
"""
......
......@@ -127,7 +127,7 @@ class PeterOptic(TomoOptic):
self._objective_state()
return self.magnifications[self.current_objective] * self.eyepiece_magnification
def setup(self):
def setup(self, tomo_ccd):
objvals = list()
for (idx, val) in enumerate(self.magnifications):
objvals.append((idx + 1, f"X{val:d}"))
......@@ -174,7 +174,10 @@ class PeterOptic(TomoOptic):
if value not in (1, 2, 3):
raise ValueError("Only the objectives 1, 2 and 3 can be chosen!")
currobj = self.objective
try:
currobj = self.objective
except:
currobj = 1
if (currobj+1)%3 == value:
# --- move positive
log_debug(self, "move positive")
......
import sys
import gevent
import numpy as np
import time
import click
from bliss.setup_globals import *
from bliss.common import scans
from bliss.common.scans import ascan, pointscan
from bliss.common.cleanup import error_cleanup, cleanup, capture_exceptions, axis as cleanup_axis
from bliss.scanning.scan_tools import peak, goto_peak
from bliss.controllers.lima.roi import Roi
from bliss.shell.standard import umv, mv, umvr, mvr, plotselect
from bliss.config.static import get_config
from nabu.preproc.alignment import CenterOfRotation
from nabu.preproc.alignment import DetectorTranslationAlongBeam
from nabu.preproc.alignment import CameraFocus
from nabu.preproc.alignment import CameraTilt
from bliss.common.plot import plot_image
class TomoAlign():
def __init__(self, name, config):
self.__name = name
self.__config = config
self.tomo = config["tomo"]
#self.paper = config["paper_motor"]
self.paper = config["paper"]
#self.__slits_vg = config["slits_vgap"]
#self.__slits_hg = config["slits_hgap"]
#self.__det_vtilt = config["detector_vtilt"]
#self.__det_htilt = config["detector_htilt"]
self.__slits_vg = None
self.__slits_hg = None
self.__det_vtilt = None
self.__det_htilt = None
@property
def name(self):
"""
A unique name for the Bliss object
"""
return self.__name
@property
def config(self):
"""
The configuration for Tomo alignment
"""
return self.__config
def __info__(self):
info_str = f"{self.name} info:\n"
if self.tomo != None:
info_str += f" tomo = {self.tomo.name} \n"
info_str += f" detector = {self.tomo.tomo_ccd.detector.name}\n"
info_str += f" optic = {self.tomo.optic.description}\n"
info_str += f" pixel size = {self._pixel_size()} \n"
info_str += f" exposure time = {self.tomo.parameters.exposure_time} \n\n"
if self.paper != None:
info_str += f" alignment paper= {self.paper.name} \n"
if self.__slits_vg != None:
info_str += f" slits vgap = {self.__slits_vg.name} \n"
if self.__slits_hg != None:
info_str += f" slits hgap = {self.__slits_hg.name} \n"
if self.__det_vtilt != None:
info_str += f" detector htilt = {self.__det_vtilt.name} \n"
if self.__det_htilt != None:
info_str += f" detector htilt = {self.__det_htilt.name} \n"
return info_str
def _pixel_size(self):
# pixel size returned by tomo is in um
self.tomo.tomo_ccd.calculate_image_pixel_size(self.tomo.optic)
pixel_size = self.tomo.optic.image_pixel_size
print ("pixel_size in um = %g" % pixel_size)
# pixel size for Nabu caluculations must be in mm
# The Frelon camera returns the pixel size in m.
# The Pco cameras return the pixel size in um.
# The fix is implemented in the new tomo version.
# This one works only with the Frlon camera!!!!!!
pixel_size = pixel_size / 1000.0
#pixel_size = pixel_size * 1000
print ("pixel size in mm = %g" % pixel_size)
return pixel_size
def _get_images(self, scan, detector):
# read back the scan images aquired
scan_images=[]
lima_data = scan.get_data()[detector.image]
npoints = lima_data.last_index
if npoints < lima_data.buffer_max_number:
for i in range(npoints):
scan_images.append(lima_data.get_image(i))
return scan_images
else:
ValueError("Cannot read images! Not enough images in the Lima image buffer")
#
# Detector focus alignment
#
def focus(self, save=False):
# prepare the focus scan parameters
scan_pars = self.tomo.optic.focus_scan_parameters()
scan_range = scan_pars["focus_scan_range"]
scan_steps = scan_pars["focus_scan_steps"]
focus_type = scan_pars["focus_type"]
focus_motor = self.tomo.optic.focus_motor()
if focus_type == "Rotation" and self.tomo.optic.magnification < 0.7:
scan_range /= 2
scan_steps *= 2
start = focus_motor.position - scan_range
stop = focus_motor.position + scan_range
#pixel size in mm
pixel_size = self._pixel_size()
# move in paper
print ("Move in paper")
self.paper.IN()
# Do the focus scan
focus_scan = self.focus_scan(focus_motor, start, stop, scan_steps,
self.tomo.parameters.exposure_time ,
self.tomo.tomo_ccd.detector, save=save)
if focus_scan != None:
self.focus_calc(focus_scan, focus_motor, self.tomo.tomo_ccd.detector, pixel_size)
ct(self.tomo.parameters.exposure_time)
print (f"Focus motor position = {focus_motor.position}")
# Move out paper
if click.confirm("Move out paper?", default=True):
self.paper.OUT()
def focus_scan(self, focus_motor, start, stop, steps, expo_time, detector, save=False):
# prepare roi counters for statistics
#code for new Bliss version
#focus_roi = Roi(0,0, detector.image.roi[2], detector.image.roi[3])
# code for old Bliss version
focus_roi = Roi(0,0, detector.image.roi.width, detector.image.roi.height)
det_rois = detector.roi_counters
det_rois["focus_roi"] = focus_roi
std = detector.roi_counters.get_single_roi_counters("focus_roi").std
counters = (std, detector.image)
# clean-up: move back focus motor, delete roi counters, move out paper
restore_list = (cleanup_axis.POS,)
with cleanup(*[focus_motor, ], restore_list=restore_list):
with capture_exceptions(raise_index=0) as capture:
with capture():
# execute focus scan
scan = ascan(focus_motor, start, stop, steps, expo_time, counters, title="focus scan", save=save)
# get the position on the maximum of the standard deviation
pos_std_max = peak()
# delete roi counters
del det_rois["focus_roi"]
return scan
# test if an error has occured
if len(capture.failed) > 0:
# delete roi counters
del det_rois["focus_roi"]
return None
def focus_calc(self, focus_scan, focus_motor, detector, pixel_size):
if focus_scan != None:
# read back the aquired images
foc_images = self._get_images(focus_scan, detector)
#convert to numpy array
foc_array= np.array(foc_images)
# read back the aquired positions
foc_pos = focus_scan.get_data()[focus_motor.name]
focus_calc = CameraFocus()
# enable calculation results plotting
focus_calc.verbose = True
focus_pos, focus_ind, tilts_vh = focus_calc.find_scintillator_tilt(foc_array, foc_pos)
#print (focus_pos, focus_ind, tilts_vh)
tilts_corr_vh_deg = - np.rad2deg(np.arctan(tilts_vh / pixel_size))
#tilts_corr_vh_rad = - tilts_vh / pixel_size
print (f"\nBest focus position: {focus_pos}")
print (f"Tilts vert. and hor. in deg: {tilts_corr_vh_deg}\n")
if click.confirm("Move to the best focus position?", default=True):
# Always move to the best focus from the bottom
mv(focus_motor, foc_pos[0])
# move focus motor to maximum
mv(focus_motor, focus_pos)
#
# Lateral alignment and camera tilt
#
def align(self, save=False):
# move rotation axis to 0
umv (self.tomo.rotation_axis, 0)
# take dark image
dark_n = 1
dark_scan = self.tomo.dark_scan(dark_n, self.tomo.parameters.exposure_time, save=save)
# read back the aquired images
dark_images = self._get_images(dark_scan, self.tomo.tomo_ccd.detector)
dark_image = dark_images[0]
# update reference motor position to current values
# self.tomo.update_reference_positions()
# take reference image
ref_n = 1
ref_scan = self.tomo.ref_scan(ref_n, self.tomo.parameters.exposure_time, save=save)
# read back the aquired images
ref_images = self._get_images(ref_scan, self.tomo.tomo_ccd.detector)
ref_image = ref_images[0]
#pixel size in mm
pixel_size = self._pixel_size()
# do alignment scan
al_scan = self.align_scan(self.tomo.rotation_axis,
self.tomo.parameters.exposure_time,
self.tomo.tomo_ccd.detector, save=save)
# works only with on motor today!
lateral_motor = self.tomo.reference.ref_motors[0]
rotc = self.tomo.optic.rotc_motor()
self.align_calc(al_scan, lateral_motor, rotc,
self.tomo.tomo_ccd.detector, pixel_size,
self.tomo.parameters.source_sample_distance,
self.tomo.parameters.sample_detector_distance,
dark_image, ref_image)
#update reference motor position to current values
#self.tomo.update_reference_positions()
ct(self.tomo.parameters.exposure_time)
print (f"Lateral alignment motor position = {lateral_motor.position}")
print (f"Camera tilt position {rotc.name} = {rotc.position}")
def align_calc(self, align_scan, lateral_motor, rotc_motor,
detector, pixel_size,
source_sample_distance,
sample_detector_distance,
dark_image, ref_image):
# read back the aquired images
al_images = self._get_images(align_scan, detector)
# prepare the images
radio0 = (al_images[0].astype(float) - dark_image.astype(float)) / (ref_image.astype(float)- dark_image.astype(float))
radio180 = (al_images[1].astype(float) - dark_image.astype(float)) / (ref_image.astype(float)- dark_image.astype(float))
# flip the radio180 for the calculation
radio180_flip = np.fliplr(radio180.copy())
#plot_image(radio0)
#plot_image(radio180_flip)
# calculate the lateral correction for the rotation axis
# and the camera tilt with line by line correlation
tilt_calc = CameraTilt()
# enable calculation results plotting
tilt_calc.verbose=True
pixel_cor, camera_tilt = tilt_calc.compute_angle(radio0, radio180_flip)
print("CameraTilt: pixel_cor = %f" % pixel_cor)
#distance from source to sample = L1(mm)
#distance from source to detector = L2(mm)
#size of the image pixel = s(mm/pixel)
#dmot(mm) = L1/L2*s*pixel_cor
cor_factor = source_sample_distance / \
(source_sample_distance + sample_detector_distance) * \
pixel_size
pos_cor = cor_factor * pixel_cor
print (f"\nLateral alignment position correction in pixel: {pixel_cor}")
print (f"Lateral alignment position correction in mm: {pos_cor}")
print (f"Camera tilt in deg: {camera_tilt}\n")
# apply lateral correction
if click.confirm("Apply the lateral position correction?", default=True):
umvr (lateral_motor, pos_cor)
# apply tilt correction
if click.confirm("Apply the camera tilt?", default=True):
umvr (rotc_motor, -1.0*camera_tilt)
def align_scan(self, rotation_motor, expo_time, detector, save=False):
# clean-up: move back rot
restore_list = (cleanup_axis.POS,)
with cleanup(rotation_motor, restore_list=restore_list):
# scan rot
rot_pos_list=[0.0, 180.0]
scan = pointscan(rotation_motor, rot_pos_list, expo_time, detector.image, title="align scan", save=save)
return scan
#
# Camera stage tilt alignment
#
def alignxc(self, start=100, stop=800, steps=10, save=False):
#pixel size in mm
pixel_size = self._pixel_size()
# slit gap to use
if pixel_size < 0.003: #3um
slit_gap = 0.2
else:
slit_gap = 1.0
self.alignxc_scan(tomo.detector_axis, start, stop, steps,
tomo.parameters.exposure_time,
tomo.tomo_ccd.detector,
self.__slits_vg, self.__slits_hg, slit_gap,
save=False)
#calculation to be added!!!!!!!!!
def alignxc_scan(self, xc, start, stop, steps, expo_time, detector,
svg, shg, slit_gap, save=False):
# save current slit positions
vg_pos = svg.position
hg_pos = shg.position
print (f"Current slit gap positions: vertical={vg_pos}, horizontal={hg_pos}")
print (f"Current xc positions: xc={xc.position}")
# clean-up: move back xc motor, open_slits
restore_list = (cleanup_axis.POS,)
with error_cleanup(*[xc, svg, shg], restore_list=restore_list):
# close the slits
umv(svg, slit_gap, shg, slit_gap)
# scan xc
scan = ascan(xc, start, stop, steps, expo_time, detector.image, title="align xc scan", save=save)
# open the slits
umv(svg, vg_pos, shg, hg_pos)
# return images
return scan
from .OpiomPreset import OpiomPreset
from .PeterOptic import PeterOptic
from .FastShutter import FastShutter
from .TomoAlign import TomoAlign
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment