Introduced nexus data structure (same as Debye)
CI for superxas_bec / test (pull_request) Successful in 34s
CI for superxas_bec / test (push) Successful in 34s

This commit was merged in pull request #15.
This commit is contained in:
x10da
2026-05-05 14:53:49 +02:00
committed by appel_c
parent f70ac8743d
commit d17f3deefa
5 changed files with 921 additions and 99 deletions
+4
View File
@@ -12,7 +12,11 @@ classifiers = [
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering",
]
dependencies = [
"numpy",
"scipy",
"xrt",
"websockets",
]
@@ -0,0 +1,239 @@
"""
X10DA / SuperXAS Beamline Parameters.
This file describes the parameter of each component of the SuperXAS beamline
to be used for raytracing and geometrical calculations.
"""
import os
import numpy as np
from collections import namedtuple
import xrt.backends.raycing.materials as rm
# if os.environ.get("USE_XRT", "True").lower() in ("1", "true", "yes"):
# import xrt.backends.raycing.materials as rm # type: ignore
# else:
# class _DummyClass:
# def __init__(self, *args, **kwargs):
# pass
# class _DummyMaterials:
# Material = _DummyClass
# CrystalSi = _DummyClass
# rm = _DummyMaterials()
# XRT definitions
filterBeryl = rm.Material('Be', rho=1.85, kind='plate')
filterDiamond = rm.Material('C', rho=3.52, kind='plate')
filterGraphite = rm.Material('C', rho=2.266, kind='plate')
stripeSi = rm.Material('Si', rho=2.33)
stripePt = rm.Material('Pt', rho=21.45)
stripeRh = rm.Material('Rh', rho=12.41)
stripeCr = rm.Material('Cr', rho=7.14)
stripePyrex = rm.Material('Si', rho=2.20) # Use Si as bare element and the density of SiO2
si111_1 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # first xtal surface
si311_1 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # first xtal surface
si333_1 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # first xtal surface
si511_1 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # first xtal surface
si111_2 = rm.CrystalSi(hkl=(1, 1, 1), tK=77) # second xtal surface
si311_2 = rm.CrystalSi(hkl=(3, 1, 1), tK=77) # second xtal surface
si333_2 = rm.CrystalSi(hkl=(3, 3, 3), tK=77) # second xtal surface
si511_2 = rm.CrystalSi(hkl=(5, 1, 1), tK=77) # second xtal surface
filterDiamond = rm.Material('C', rho=3.52, kind='plate')
filterBe = rm.Material('Be', rho=1.85, kind='plate')
filterSi3N4 = rm.Material(['Si', 'N'], quantities=[3, 4], rho=3.44, kind='plate')
filterAl = rm.Material('Al', rho=2.69, kind='plate')
filterGraphite = rm.Material('C', rho=2.266, kind='plate')
sourceHeight = 0
#Synchrotron
synchrotron = namedtuple('synchrotron', ['eE', 'eI', 'eEspread',
'eEpsilonX', 'eEpsilonZ', 'betaX', 'betaZ'])
sls1 = synchrotron(
eE = 2.4,
eI = 0.4,
eEspread=0.878e-3,
eEpsilonX=5.63,
eEpsilonZ=0.007,
betaX=0.45,
betaZ=14.4,
)
sls2 = synchrotron(
eE=2.7,
eI=0.4,
eEspread=1.147e-3,
eEpsilonX=0.156,
eEpsilonZ=0.01,
betaX=0.18,
betaZ=4.6,
)
# Source
bendingMagnet = namedtuple('bendingMagnet', ['name', 'center', 'sync', 'B0'])
sls1_29t = bendingMagnet(
name='FE-BM-SLS1-2.9T',
center=(0, 0, 0),
sync=sls1,
B0=2.9,)
sls2_21t = bendingMagnet(
name='FE-BM-SLS2-2.1T',
center=(0, 0, 0),
sync=sls1,
B0=2.1,)
# FE slits
slits = namedtuple('slits', ['name', 'center', 'maxDivH', 'maxDivV'])
feSlits = slits(
name='FE-SLITS',
center=(0, 5290, sourceHeight),
maxDivH=1.8e-3,
maxDivV=0.8e-3,)
# Filters
filt = namedtuple('filt', ['name', 'center', 'pitch', 'limPhysX', 'limPhysY', 'surface', 'material', 'thickness'])
feWindow = filt(
name='FE-WINDOW',
center=(0., 6158, sourceHeight),
pitch=np.pi/2,
limPhysX=(-6, 6),
limPhysY=(-3., 3.),
surface='None',
material=filterDiamond,
thickness=0.1,)
feWindow = feWindow._replace(surface='CVD Diamond window {0:0.0f} $\mu$m'.format(feWindow.thickness*1e3))
feFilt = filt(
name='FE-FI',
center=(0., 6590, sourceHeight),
pitch=np.pi/2,
limPhysX=(-15, 15),
limPhysY=(-10, 10),
surface='None',
material=filterGraphite,
thickness=0.25,)
feFilt = feFilt._replace(surface='Graphite filter {0:0.0f} $\mu$m'.format(feFilt.thickness*1e3))
# Collimating mirror
collimatingMirror = namedtuple('collimatingMirror', ['name',
'center', 'surface', 'material', 'limPhysX', 'limPhysY',
'limOptX', 'limOptY', 'R', 'pitch', 'jack1', 'jack2', 'jack3',
'tx1', 'tx2'])
cm = collimatingMirror(
name='FE-CM',
center=[0, 7618, sourceHeight],
surface=('Rh','Si','Pt'),
material=(stripeRh, stripeSi, stripePt),
limPhysX=(-30, 30),
limPhysY=(-600, 600),
limOptX=((11, -2, -21), (21, 8, -5)),
limOptY=((-500, -500, -500), (500, 500, 500)),
R=[3e6, 15e6],
pitch=[1.4e-3, 4.5e-3],
jack1=[0., 7210., 0.], #Tripod X, Y, Z (global)
jack2=[-210., 8310., 0.],
jack3=[210., 8310., 0.],
tx1=[0.0, -575.5], # X-Stage 1 [x, y] (local)
tx2=[0.0, 575],) # X-Stage 2
apertures = namedtuple('apertures', ['name', 'center', 'opening'])
fePS = apertures(
name='FE-PS',
center=[0, 8760, sourceHeight],
opening=[-39/2, 39/2, -10, 29]) # left, right, bottom, top
opWbBsBlock = apertures(
name='OP-WB-BS-BLOCK',
center=[0., 13606-135, sourceHeight],
opening=[-18., 18., 42, 76]) # left, right, bottom, top
opSlits = apertures(
name='OP-SLITS',
center=[0, 14145-135, sourceHeight],
opening=[-35/2, 35/2, 47.5, 82.5])
# Monochromator
monochromator = namedtuple('monochromator', ['name', 'center',
'xtal', 'material1', 'material2', 'xtalWidth', 'xtalOffsetX',
'xtalLength1', 'xtalLength2', 'xtalGap', 'rotOffset',
'heightOffset', 'braggLim', 'jack1', 'jack2', 'jack3', 'tx'])
mo1 = monochromator(
name='OP-CCM1',
center=[0., 11670-135, sourceHeight],
xtal=('Si311','Si111'),
material1=(si311_1, si111_1),
material2=(si311_2, si111_2),
xtalWidth = (20, 20),
xtalOffsetX=(-19.2, 19.2),
xtalLength1 = (60, 60),
xtalLength2 = (60, 60),
xtalGap = (8, 8),
rotOffset = 6, # not sure what it is
heightOffset = 8.5, # not sure what it is
braggLim = [4, 35],
jack1=[0., 11350., 0.], #Tripod not available!
jack2=[-400., 12350., 0.],
jack3=[400., 12350., 0.],
tx=0.0,) # X-Stage [x]
# Focusing mirror
focusingMirror = namedtuple('focusingMirror', ['name', 'center',
'surfaceToroid', 'materialToroid',
'limPhysXToroid', 'limPhysYToroid',
'limOptXToroid', 'limOptYToroid',
'R', 'pitch', 'r', 'xToroid', 'hToroid', 'jack1', 'jack2', 'jack3',
'tx1', 'tx2'])
fm = focusingMirror(
name='OP-FM',
center=[0., 15580-135, sourceHeight],
surfaceToroid=('Rh', 'Pt'),
materialToroid=(stripeRh, stripePt),
limPhysXToroid=(-54., 54.),
limPhysYToroid=(-565., 565.),
limOptXToroid=((90.25, 41.75), (51.75, 5.75)), # With old VME axis, no absolute value!
limOptYToroid=((-500., -500.), (500., 500.)),
R=[3e6, 15e6],
pitch=[1.4e-3, 4.5e-3],
r=[30, 20],
xToroid=[24.126, -22,874], # offset in local x
hToroid=[7., 11.3], # depth of the cylinder at x = xCylinder1 and x = xCylinder2.
jack1=[0., 14980., 0.],
jack2=[-75., 16180., 0.],
jack3=[75., 16180., 0.],
tx1=[0., -575.], # X-Stage 1 [x, y]
tx2=[0., 575.],) # X-Stage 2 [x, y]
ehWindow = filt(
name='EH-WINDOW',
center=(0., 22225-135, sourceHeight),
pitch=np.pi/2,
limPhysX=(-10., 10.),
limPhysY=(17.5, 92.5),
surface='None',
material=filterBe,
thickness=0.25,)
ehWindow = ehWindow._replace(surface='Beryllium window {0:0.0f} $\mu$m'.format(ehWindow.thickness*1e3))
# Sample
sample = namedtuple('sample', ['name', 'center'])
smpl = sample(
name='OP-SMPL',
center=[0, 24000-135, sourceHeight],)
@@ -0,0 +1,396 @@
###################################
## Monochromator ##
###################################
mo1_try:
readoutPriority: baseline
description: Monochromator Y Translation
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: X10DA-OP1-MO1:TRY
onFailure: retry
enabled: true
softwareTrigger: false
mo1_trx:
readoutPriority: baseline
description: Monochromator X Translation
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: X10DA-OP1-MO1:TRX
onFailure: retry
enabled: true
softwareTrigger: false
###################################
## Optics Slits + Beam Monitor 1 ##
###################################
# sl1_trxr:
# readoutPriority: baseline
# description: Optics slits 1 X-translation Ring-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:TRXR
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_trxw:
# readoutPriority: baseline
# description: Optics slits 1 X-translation Wall-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:TRXW
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_tryb:
# readoutPriority: baseline
# description: Optics slits 1 Y-translation Bottom-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:TRYB
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_tryt:
# readoutPriority: baseline
# description: Optics slits 1 X-translation Top-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:TRYT
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# bm1_try:
# readoutPriority: baseline
# description: Beam Monitor 1 Y-translation
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-BM1:TRY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_centerx:
# readoutPriority: baseline
# description: Optics slits 1 X-center
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:CENTERX
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_gapx:
# readoutPriority: baseline
# description: Optics slits 1 X-gap
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:GAPX
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_centery:
# readoutPriority: baseline
# description: Optics slits 1 Y-center
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:CENTERY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl1_gapy:
# readoutPriority: baseline
# description: Optics slits 1 Y-gap
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL1:GAPY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
###################################
## Focusing Mirror ##
###################################
# fm_trxu:
# readoutPriority: baseline
# description: Focusing Mirror X-translation upstream
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-FM:TRXU
# onFailure: retry
# enabled: true
# softwareTrigger: false
# fm_trxd:
# readoutPriority: baseline
# description: Focusing Mirror X-translation downstream
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-FM:TRXD
# onFailure: retry
# enabled: true
# softwareTrigger: false
# fm_tryd:
# readoutPriority: baseline
# description: Focusing Mirror Y-translation downstream
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-FM:TRYD
# onFailure: retry
# enabled: true
# softwareTrigger: false
# fm_tryur:
# readoutPriority: baseline
# description: Focusing Mirror Y-translation upstream ring
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-FM:TRYUR
# onFailure: retry
# enabled: true
# softwareTrigger: false
# fm_tryuw:
# readoutPriority: baseline
# description: Focusing Mirror Y-translation upstream wall
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-FM:TRYUW
# onFailure: retry
# enabled: true
# softwareTrigger: false
fm_bnd:
readoutPriority: baseline
description: Focusing Mirror bender
deviceClass: ophyd.EpicsMotor
deviceConfig:
prefix: X10DA-OP-MI1:TRB
onFailure: retry
enabled: true
softwareTrigger: false
# fm_bnd_radius:
# readoutPriority: baseline
# description: Focusing Mirror Bending Radius
# deviceClass: ophyd.EpicsSignalRO
# deviceConfig:
# read_pv: X10DA-CPCL-FM:BNDFORCE
# onFailure: retry
# readOnly: true
# enabled: true
# softwareTrigger: false
fm_rotx:
readoutPriority: baseline
description: Focusing Morror Pitch
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
auto_monitor: true
read_pv: X10DA-OP-MI1:pitch
onFailure: retry
enabled: true
softwareTrigger: false
fm_roty:
readoutPriority: baseline
description: Focusing Morror Yaw
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
auto_monitor: true
read_pv: X10DA-OP-MI1:yaw
onFailure: retry
enabled: true
softwareTrigger: false
fm_rotz:
readoutPriority: baseline
description: Focusing Morror Roll
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
auto_monitor: true
read_pv: X10DA-OP-MI1:roll
onFailure: retry
enabled: true
softwareTrigger: false
fm_trx:
readoutPriority: baseline
description: Focusing Morror Center Point X
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
auto_monitor: true
read_pv: X10DA-OP-MI1:trans
onFailure: retry
enabled: true
softwareTrigger: false
fm_try:
readoutPriority: baseline
description: Focusing Morror Center Point Y
deviceClass: ophyd.EpicsSignalRO
deviceConfig:
auto_monitor: true
read_pv: X10DA-OP-MI1:y
onFailure: retry
enabled: true
softwareTrigger: false
###################################
## Optics Slits + Beam Monitor 2 ##
###################################
# sl2_trxr:
# readoutPriority: baseline
# description: Optics slits 2 X-translation Ring-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:TRXR
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_trxw:
# readoutPriority: baseline
# description: Optics slits 2 X-translation Wall-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:TRXW
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_tryb:
# readoutPriority: baseline
# description: Optics slits 2 Y-translation Bottom-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:TRYB
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_tryt:
# readoutPriority: baseline
# description: Optics slits 2 X-translation Top-edge
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:TRYT
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# bm2_try:
# readoutPriority: baseline
# description: Beam Monitor 2 Y-translation
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-BM2:TRY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_centerx:
# readoutPriority: baseline
# description: Optics slits 2 X-center
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:CENTERX
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_gapx:
# readoutPriority: baseline
# description: Optics slits 2 X-gap
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:GAPX
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_centery:
# readoutPriority: baseline
# description: Optics slits 2 Y-center
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:CENTERY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
# sl2_gapy:
# readoutPriority: baseline
# description: Optics slits 2 Y-gap
# deviceClass: ophyd.EpicsMotor
# deviceConfig:
# prefix: X10DA-OP-SL2:GAPY
# onFailure: retry
# enabled: true
# softwareTrigger: false
# deviceTags:
# - optics
# - slits
@@ -52,9 +52,9 @@ mo1_bragg:
# enabled: true
# softwareTrigger: false
## Remaining optics hutch
# optics_config:
# - !include ./x10da_optics.yaml
# Remaining optics hutch
optics_config:
- !include ./x10da_optics.yaml
###################################
## Experimental Hutch ##
@@ -1,5 +1,6 @@
from bec_server.file_writer.default_writer import DefaultFormat
import superxas_bec.bec_widgets.widgets.x10da_parameters as bl
class SuperXASNexusStructure(DefaultFormat):
"""Nexus Structure for SuperXAS"""
@@ -12,102 +13,6 @@ class SuperXASNexusStructure(DefaultFormat):
instrument = entry.create_group(name="instrument")
instrument.attrs["NX_class"] = "NXinstrument"
###################
## mo1_bragg specific information
###################
# Logic if device exist
if "mo1_bragg" in self.device_manager.devices:
monochromator = instrument.create_group(name="monochromator")
monochromator.attrs["NX_class"] = "NXmonochromator"
crystal = monochromator.create_group(name="crystal")
crystal.attrs["NX_class"] = "NXcrystal"
# Create a dataset
chemical_formular = crystal.create_dataset(name="chemical_formular", data="Si")
chemical_formular.attrs["NX_class"] = "NX_CHAR"
# Create a softlink
d_spacing = crystal.create_soft_link(
name="d_spacing",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_d_spacing/value",
)
d_spacing.attrs["NX_class"] = "NX_FLOAT"
offset = crystal.create_soft_link(
name="offset",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_offset/value",
)
offset.attrs["NX_class"] = "NX_FLOAT"
reflection = crystal.create_soft_link(
name="reflection",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_xtal_string/value",
)
reflection.attrs["NX_class"] = "NX_CHAR"
##################
## cm mirror specific information
###################
collimating_mirror = instrument.create_group(name="collimating_mirror")
collimating_mirror.attrs["NX_class"] = "NXmirror"
cm_substrate_material = collimating_mirror.create_dataset(
name="substrate_material", data="Si"
)
cm_substrate_material.attrs["NX_class"] = "NX_CHAR"
cm_bending_radius = collimating_mirror.create_soft_link(
name="sagittal radius",
target="/entry/collection/devices/cm_bnd_radius/cm_bnd_radius/value",
)
cm_bending_radius.attrs["NX_class"] = "NX_FLOAT"
cm_bending_radius.attrs["units"] = "km"
cm_incidence_angle = collimating_mirror.create_soft_link(
name="incidence angle", target="/entry/collection/devices/cm_rotx/cm_rotx/value"
)
cm_incidence_angle.attrs["NX_class"] = "NX_FLOAT"
cm_yaw_angle = collimating_mirror.create_soft_link(
name="incident angle", target="/entry/collection/devices/cm_roty/cm_roty/value"
)
cm_yaw_angle.attrs["NX_class"] = "NX_FLOAT"
##################
## fm mirror specific information
###################
focusing_mirror = instrument.create_group(name="focusing_mirror")
focusing_mirror.attrs["NX_class"] = "NXmirror"
fm_substrate_material = focusing_mirror.create_dataset(name="substrate_material", data="Si")
fm_substrate_material.attrs["NX_class"] = "NX_CHAR"
fm_bending_radius = focusing_mirror.create_soft_link(
name="sagittal radius",
target="/entry/collection/devices/fm_bnd_radius/fm_bnd_radius/value",
)
fm_bending_radius.attrs["NX_class"] = "NX_FLOAT"
fm_incidence_angle = focusing_mirror.create_soft_link(
name="incidence angle",
target="/entry/collection/devices/fm_incidence_angle/fm_incidence_angle/value",
)
fm_incidence_angle.attrs["NX_class"] = "NX_FLOAT"
fm_yaw_angle = focusing_mirror.create_soft_link(
name="yaw angle", target="/entry/collection/devices/fm_roty/fm_roty/value"
)
fm_yaw_angle.attrs["NX_class"] = "NX_FLOAT"
fm_roll_angle = focusing_mirror.create_soft_link(
name="roll angle", target="/entry/collection/devices/fm_rotz/fm_rotz/value"
)
fm_roll_angle.attrs["NX_class"] = "NX_FLOAT"
##################
## source specific information
###################
@@ -123,3 +28,281 @@ class SuperXASNexusStructure(DefaultFormat):
probe = source.create_dataset(name="probe", data="X-ray")
probe.attrs["NX_class"] = "NX_CHAR"
if "curr" in self.device_manager.devices:
ring_current = source.create_soft_link(
name="ring_current",
target="/entry/collection/devices/curr/curr/value",
)
ring_current.attrs["NX_class"] = "NX_FLOAT"
ring_current.attrs["units"] = "mA"
###################
## mo1_bragg specific information
###################
## Logic if device exist
if "mo1_bragg" in self.device_manager.devices:
monochromator = instrument.create_group(name="monochromator")
monochromator.attrs["NX_class"] = "NXmonochromator"
crystal = monochromator.create_group(name="crystal")
crystal.attrs["NX_class"] = "NXcrystal"
# Create a dataset
chemical_formular = crystal.create_dataset(name="chemical_formular", data="Si")
chemical_formular.attrs["NX_class"] = "NX_CHAR"
reflection = crystal.create_soft_link(
name="reflection",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_xtal_string/value",
)
reflection.attrs["NX_class"] = "NX_CHAR"
# Create a softlink
d_spacing = crystal.create_soft_link(
name="d_spacing",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_d_spacing/value",
)
d_spacing.attrs["NX_class"] = "NX_FLOAT"
d_spacing.attrs["units"] = "angstrom"
bragg_offset = crystal.create_soft_link(
name="bragg_offset",
target="/entry/collection/devices/mo1_bragg/mo1_bragg_crystal_current_bragg_off/value",
)
bragg_offset.attrs["NX_class"] = "NX_FLOAT"
bragg_offset.attrs["units"] = "degree"
###################
### cm mirror specific information
####################
collimating_mirror = instrument.create_group(name="collimating_mirror")
collimating_mirror.attrs["NX_class"] = "NXmirror"
cm_substrate_material = collimating_mirror.create_dataset(
name="substrate_material", data="Si"
)
cm_substrate_material.attrs["NX_class"] = "NX_CHAR"
#previous error due to space in name field
if "cm_bnd" in self.device_manager.devices:
cm_bending = collimating_mirror.create_soft_link(
name="sagittal_radius_bender_motor",
target="/entry/collection/devices/cm_bnd/cm_bnd/value",
)
cm_bending.attrs["NX_class"] = "NX_FLOAT"
cm_bending.attrs["units"] = "steps"
if "cm_rotx" in self.device_manager.devices:
cm_incidence_angle = collimating_mirror.create_soft_link(
name="incidence_angle", target="/entry/collection/devices/cm_rotx/cm_rotx/value"
)
cm_incidence_angle.attrs["NX_class"] = "NX_FLOAT"
cm_incidence_angle.attrs["units"] = "mrad"
if "cm_roty" in self.device_manager.devices:
cm_yaw_angle = collimating_mirror.create_soft_link(
name="yaw_angle", target="/entry/collection/devices/cm_roty/cm_roty/value"
)
cm_yaw_angle.attrs["NX_class"] = "NX_FLOAT"
cm_yaw_angle.attrs["units"] = "mrad"
if "cm_rotz" in self.device_manager.devices:
cm_roll_angle = collimating_mirror.create_soft_link(
name="roll_angle", target="/entry/collection/devices/cm_rotz/cm_rotz/value"
)
cm_roll_angle.attrs["NX_class"] = "NX_FLOAT"
cm_roll_angle.attrs["units"] = "mrad"
if 'cm_trx' in self.device_manager.devices:
cm_trx = - self.device_manager.devices.cm_trx.read(cached=True).get('cm_trx').get('value')
stripe = 'Unknown'
for name, low, high in zip(bl.cm.surface, bl.cm.limOptX[0], bl.cm.limOptX[1]):
if low <= cm_trx <= high:
stripe = name
cm_stripe = collimating_mirror.create_dataset(
name="stripe", data=stripe
)
cm_stripe.attrs["NX_class"] = "NX_CHAR"
###################
### fm mirror specific information
####################
focusing_mirror = instrument.create_group(name="focusing_mirror")
focusing_mirror.attrs["NX_class"] = "NXmirror"
fm_substrate_material = focusing_mirror.create_dataset(
name="substrate_material", data="Si"
)
fm_substrate_material.attrs["NX_class"] = "NX_CHAR"
if "fm_bnd" in self.device_manager.devices:
fm_bending = focusing_mirror.create_soft_link(
name="sagittal_radius_bender_motor",
target="/entry/collection/devices/fm_bnd/fm_bnd/value",
)
fm_bending.attrs["NX_class"] = "NX_FLOAT"
fm_bending.attrs["units"] = "steps"
if "fm_rotx" in self.device_manager.devices:
fm_incidence_angle = focusing_mirror.create_soft_link(
name="incidence_angle", target="/entry/collection/devices/fm_rotx/fm_rotx/value"
)
fm_incidence_angle.attrs["NX_class"] = "NX_FLOAT"
fm_incidence_angle.attrs["units"] = "mrad"
if "fm_roty" in self.device_manager.devices:
fm_yaw_angle = focusing_mirror.create_soft_link(
name="yaw_angle", target="/entry/collection/devices/fm_roty/fm_roty/value"
)
fm_yaw_angle.attrs["NX_class"] = "NX_FLOAT"
fm_yaw_angle.attrs["units"] = "mrad"
if "fm_rotz" in self.device_manager.devices:
fm_roll_angle = focusing_mirror.create_soft_link(
name="roll_angle", target="/entry/collection/devices/fm_rotz/fm_rotz/value"
)
fm_roll_angle.attrs["NX_class"] = "NX_FLOAT"
fm_roll_angle.attrs["units"] = "mrad"
if 'fm_trx' in self.device_manager.devices:
fm_trx = - self.device_manager.devices.fm_trx.read(cached=True).get('fm_trx').get('value')
stripe = 'Unknown'
for name, low, high in zip(bl.fm.surfaceToroid, bl.fm.limOptXToroid[1], bl.fm.limOptXToroid[0]):
if low <= fm_trx <= high:
stripe = name + ' (toroid)'
fm_stripe = focusing_mirror.create_dataset(
name="stripe", data=stripe
)
fm_stripe.attrs["NX_class"] = "NX_CHAR"
###################
## nidaq specific information
###################
## Logic if device exist
if "nidaq" in self.device_manager.devices:
#ai_chans_bits = self.device_manager.devices.nidaq.ai_chans.read(cached=True).get("nidaq_ai_chans").get("value")
ai_chans_bits = self.configuration.get("nidaq", {}).get("nidaq_ai_chans", {}).get("value")
ci_chans_bits = self.configuration.get("nidaq", {}).get("nidaq_ci_chans", {}).get("value")
#add_chans_bits = self.device_manager.devices.nidaq.add_chans.read(cached=True).get("nidaq_add_chans").get("value")
add_chans_bits = self.configuration.get("nidaq", {}).get("nidaq_add_chans", {}).get("value")
measurement_mode = entry.create_group(name="mode")
measurement_mode.attrs["NX_class"] = "NX_CHAR"
if (int(ci_chans_bits) & 0x7F) != 0:
# Create a dataset
rayspec_sdd_active = measurement_mode.create_group(name="Multi_Element_Partial_Fluorescence_Yield")
me_sdd = rayspec_sdd_active.create_dataset(name="Detector", data="Rayspec 7 element Silicon Drift Detector")
me_sdd.attrs["NX_class"] = "NX_CHAR"
if (int(ci_chans_bits) & (1<<8)) != 0:
# Create a dataset
ketek_sdd_active = measurement_mode.create_group(name="Single_Element_Partial_Fluorescence_Yield")
se_sdd = ketek_sdd_active.create_dataset(name="Detector", data="Ketex mini single element Silicon Drift Detector")
se_sdd.attrs["NX_class"] = "NX_CHAR"
if ((int(ai_chans_bits) & (1<<6)) != 0):
# Create a dataset
pips_active = measurement_mode.create_group(name="Total_Flourescence_Yield")
tfy = pips_active.create_dataset(name="Detector", data="Mirion Technologies Partially Depeleted PIPS Detector")
tfy.attrs["NX_class"] = "NX_CHAR"
if ((int(ai_chans_bits) & (1<<0)) != 0) & ((int(ai_chans_bits) & (1<<2)) != 0):
# Create a dataset
ai0ai2_active = measurement_mode.create_group(name="Sample_Transmission")
sam_trans = ai0ai2_active.create_dataset(name="Detector", data="Ionitec 15 cm gas filled Ionisation Chambers")
sam_trans.attrs["NX_class"] = "NX_CHAR"
if ((int(ai_chans_bits) & (1<<2)) != 0) & ((int(ai_chans_bits) & (1<<4)) != 0):
# Create a dataset
ai2ai4_active = measurement_mode.create_group(name="Reference_Transmission")
ref_trans = ai2ai4_active.create_dataset(name="Detector", data="Ionitec 15 cm gas filled Ionisation Chambers")
ref_trans.attrs["NX_class"] = "NX_CHAR"
main_data = entry.create_group(name="data")
main_data.attrs["NX_class"] = "NXdata"
##################
## energy, test whether the signal exists. how to check from config?
###################
energy = main_data.create_group(name="energy")
energy.attrs["NX_class"] = "NXdata"
energy.attrs["units"] = "eV"
main_data.create_soft_link(name="energy", target="/entry/collection/readout_groups/async/nidaq/nidaq_energy/value")
##################
## i0
###################
if (int(ai_chans_bits) & (1<<0)) !=0:
i0 = main_data.create_group(name="i0")
i0.attrs["NX_class"] = "NXdata"
i0.attrs["units"] = "V"
main_data.create_soft_link(name="i0", target="/entry/collection/readout_groups/async/nidaq/nidaq_ai0_mean/value")
##################
## i1
###################
if (int(ai_chans_bits) & (1<<2)) !=0:
i1 = main_data.create_group(name="i1")
i1.attrs["NX_class"] = "NXdata"
i1.attrs["units"] = "V"
main_data.create_soft_link(name="i1", target="/entry/collection/readout_groups/async/nidaq/nidaq_ai2_mean/value")
##################
## i2
###################
if (int(ai_chans_bits) & (1<<4)) !=0:
i2 = main_data.create_group(name="i2")
i2.attrs["NX_class"] = "NXdata"
i2.attrs["units"] = "V"
main_data.create_soft_link(name="i2", target="/entry/collection/readout_groups/async/nidaq/nidaq_ai4_mean/value")
##################
## ci sum
###################
if int(ci_chans_bits) > 0:
ci_sum = main_data.create_group(name="Fluorescence_Sum")
ci_sum.attrs["NX_class"] = "NXdata"
ci_sum.attrs["units"] = "counts"
main_data.create_soft_link(name="Fluorescence_Sum", target="/entry/collection/readout_groups/async/nidaq/nidaq_cisum/value")
##################
## mu sample, test whether the signal exists. how to check from config?
###################
if (int(add_chans_bits) & (1<<0)) !=0:
mu_sample = main_data.create_group(name="mu_sample")
mu_sample.attrs["NX_class"] = "NXdata"
main_data.create_soft_link(name="mu_sample", target="/entry/collection/readout_groups/async/nidaq/nidaq_smpl_abs/value")
##################
## mu reference, test whether the signal exists. how to check from config?
###################
if (int(add_chans_bits) & (1<<1)) !=0:
mu_reference = main_data.create_group(name="mu_reference")
mu_reference.attrs["NX_class"] = "NXdata"
main_data.create_soft_link(name="mu_reference", target="/entry/collection/readout_groups/async/nidaq/nidaq_ref_abs/value")