Compare commits

..

6 Commits

Author SHA1 Message Date
x12sa
36548544fb removed linear progress bar
All checks were successful
CI for csaxs_bec / test (push) Successful in 1m54s
2026-03-28 12:42:12 +01:00
x12sa
556afec35d http error message cooldown to 10 mins
All checks were successful
CI for csaxs_bec / test (push) Successful in 2m0s
2026-03-28 12:20:01 +01:00
x12sa
4b312f72c7 error message cooldown
All checks were successful
CI for csaxs_bec / test (push) Successful in 1m55s
2026-03-28 10:51:54 +01:00
x12sa
e003f6cf03 change url and fix in https certificate ignore
Some checks failed
CI for csaxs_bec / test (push) Has been cancelled
2026-03-28 10:50:36 +01:00
x12sa
5e57042e9c https without certificate possible 2026-03-28 10:35:31 +01:00
x12sa
187964078e mod audio gen 2026-03-28 10:31:23 +01:00
4 changed files with 496 additions and 530 deletions

View File

@@ -1317,7 +1317,8 @@ class Flomni(
self._webpage_gen = FlomniWebpageGenerator(
bec_client=client,
output_dir="~/data/raw/webpage/",
upload_url="http://s1090968537.online.de/upload.php", # optional
#upload_url="http://s1090968537.online.de/upload.php", # optional
upload_url="https://v1p0zyg2w9n2k9c1.myfritz.net/upload.php",
)
self._webpage_gen.start()

View File

@@ -235,6 +235,16 @@ class HttpUploader:
self._uploaded: dict[str, float] = {} # abs path -> mtime at last upload
self._lock = threading.Lock()
self._busy = False # True while an upload thread is running
self._warn_at: dict[str, float] = {} # key -> epoch of last warning
_WARN_COOLDOWN_S = 600 # only repeat the same warning once per minute
def _warn(self, key: str, msg: str) -> None:
"""Log a warning at most once per _WARN_COOLDOWN_S for a given key."""
now = _epoch()
if now - self._warn_at.get(key, 0) >= self._WARN_COOLDOWN_S:
self._warn_at[key] = now
logger.warning(msg)
# ── Public API ──────────────────────────────────────────────────────────
@@ -294,8 +304,10 @@ class HttpUploader:
def _upload_files(self, files: list, force: bool = False) -> None:
try:
import requests as _requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
except ImportError:
logger.warning("HttpUploader: 'requests' library not installed")
self._warn("no_requests", "HttpUploader: 'requests' library not installed")
return
for path in files:
@@ -312,21 +324,26 @@ class HttpUploader:
self._url,
files={"file": (path.name, f)},
timeout=self._timeout,
verify=False, # accept self-signed / untrusted certs
)
if r.status_code == 200:
self._uploaded[str(path)] = mtime
self._warn_at.pop(f"upload_{path.name}", None) # clear on success
logger.debug(f"HttpUploader: OK {path.name}")
else:
logger.warning(
self._warn(
f"upload_{path.name}",
f"HttpUploader: {path.name} -> HTTP {r.status_code}: "
f"{r.text[:120]}"
)
except Exception as exc:
logger.warning(f"HttpUploader: {path.name} failed: {exc}")
self._warn(f"upload_{path.name}", f"HttpUploader: {path.name} failed: {exc}")
def _do_cleanup(self) -> None:
try:
import requests as _requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
except ImportError:
return
try:
@@ -334,15 +351,17 @@ class HttpUploader:
self._url,
data={"action": "cleanup"},
timeout=self._timeout,
verify=False, # accept self-signed / untrusted certs
)
logger.info(f"HttpUploader cleanup: {r.text[:120]}")
self._warn_at.pop("cleanup", None) # clear on success
# Forget mtime records for ptycho files so they get re-uploaded
with self._lock:
to_remove = [k for k in self._uploaded if "/S" in k or "\\S" in k]
for k in to_remove:
self._uploaded.pop(k, None)
except Exception as exc:
logger.warning(f"HttpUploader cleanup failed: {exc}")
self._warn("cleanup", f"HttpUploader cleanup failed: {exc}")
# ---------------------------------------------------------------------------
@@ -1245,21 +1264,6 @@ def _render_html(phone_numbers: list) -> str:
}}
.info-item .value {{ font-size: 0.9rem; font-weight: 600; color: var(--text); }}
.bar-wrap {{ grid-column: 1 / -1; display: flex; flex-direction: column; gap: 0.35rem; }}
.bar-label {{
display: flex; justify-content: space-between;
font-family: var(--mono); font-size: 0.6rem; color: var(--text-dim);
letter-spacing: 0.06em; text-transform: uppercase;
}}
.bar-track {{ height: 5px; background: var(--surface2); border-radius: 99px; overflow: hidden; }}
.bar-fill {{
height: 100%;
background: var(--ring-blend);
background: color-mix(in srgb, var(--status-color) 65%, var(--surface2));
border-radius: 99px;
transition: width 0.8s cubic-bezier(.4,0,.2,1), background 0.6s;
}}
/* ── Recon card ── */
.recon-stats {{ display: flex; gap: 2rem; flex-wrap: wrap; }}
.recon-stat {{ display: flex; flex-direction: column; gap: 0.15rem; }}
@@ -1502,10 +1506,7 @@ def _render_html(phone_numbers: list) -> str:
<div class="info-item"><span class="label">ETA</span><span class="value" id="pi-eta">-</span></div>
<div class="info-item"><span class="label">Started</span><span class="value" id="pi-start">-</span></div>
</div>
<div class="bar-wrap">
<div class="bar-label"><span>Sub-tomo progress</span><span id="bar-sub-label">-</span></div>
<div class="bar-track"><div class="bar-fill" id="bar-sub-fill" style="width:0%"></div></div>
</div>
</div>
@@ -1667,90 +1668,80 @@ function initDrag() {{
}}
initDrag();
// ── Audio ─────────────────────────────────────────────────────────────────
// iOS (all browsers on iPhone use WebKit) requires:
// 1. AudioContext created inside a user gesture.
// 2. A real (even silent) BufferSource started synchronously in the gesture.
// 3. ctx.resume() awaited before scheduling audible nodes.
// We combine all three: silent unlock buffer + resume promise + .then(beeps).
// iOS (all browsers on iPhone use WebKit) strict rules:
// 1. AudioContext must be created inside a user gesture handler.
// 2. A real BufferSource must be started SYNCHRONOUSLY in the gesture
// .then() / microtasks run outside the gesture and are rejected.
// 3. ctx.resume() is called fire-and-forget; beeps are delayed 80ms by
// setTimeout so the engine has time to start before nodes are scheduled.
//
// unlockAudio() handles all of this and must be called at the TOP of any
// onclick handler that wants audio — before any other logic.
let audioCtx = null, audioEnabled = false;
let audioArmed = false, warningActive = false, warningTimer = null, lastStatus = null;
let staleActive = false, staleTimer = null, staleConfirmed = false;
let audioCtx=null, audioEnabled=false;
let audioArmed=false, warningActive=false, warningTimer=null, lastStatus=null;
let staleActive=false, staleTimer=null, staleConfirmed=false;
function getCtx() {{
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function getCtx(){{
if(!audioCtx) audioCtx=new(window.AudioContext||window.webkitAudioContext)();
return audioCtx;
}}
function unlockAudio() {{
// Must be called synchronously inside a user gesture handler.
// Plays a 1-sample silent buffer — the most reliable iOS unlock method.
const ctx = getCtx();
const buf = ctx.createBuffer(1, 1, ctx.sampleRate);
const src = ctx.createBufferSource();
src.buffer = buf;
src.connect(ctx.destination);
src.start(0);
// resume() is async; return the promise so callers can chain.
return ctx.state === 'suspended' ? ctx.resume() : Promise.resolve();
function unlockAudio(){{
// Synchronous silent 1-sample buffer — the only reliable iOS unlock.
// Must be called synchronously at the start of a user gesture handler.
const ctx=getCtx();
const buf=ctx.createBuffer(1,1,ctx.sampleRate);
const src=ctx.createBufferSource();
src.buffer=buf; src.connect(ctx.destination); src.start(0);
if(ctx.state==='suspended') ctx.resume(); // fire-and-forget
}}
function beep(freq, dur, vol) {{
try {{
const ctx = getCtx();
const o = ctx.createOscillator();
const g = ctx.createGain();
function beep(freq,dur,vol){{
try{{
const ctx=getCtx(),o=ctx.createOscillator(),g=ctx.createGain();
o.connect(g); g.connect(ctx.destination);
o.type = 'sine';
o.frequency.setValueAtTime(freq, ctx.currentTime);
g.gain.setValueAtTime(vol, ctx.currentTime);
g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + dur);
o.start(); o.stop(ctx.currentTime + dur);
}} catch(e) {{ console.warn('Audio beep:', e); }}
o.type='sine'; o.frequency.setValueAtTime(freq,ctx.currentTime);
g.gain.setValueAtTime(vol,ctx.currentTime);
g.gain.exponentialRampToValueAtTime(0.001,ctx.currentTime+dur);
o.start(); o.stop(ctx.currentTime+dur);
}}catch(e){{console.warn('Audio:',e);}}
}}
function warningChime() {{
beep(660, 0.3, 0.4);
setTimeout(() => beep(440, 0.5, 0.4), 350);
function warningChime(){{
beep(660,0.3,0.4); setTimeout(()=>beep(440,0.5,0.4),350);
}}
function staleChime(){{
beep(1200,0.12,0.35);
setTimeout(()=>beep(1200,0.12,0.35),180);
setTimeout(()=>beep(1200,0.25,0.35),360);
}}
function staleChime() {{
beep(1200, 0.12, 0.35);
setTimeout(() => beep(1200, 0.12, 0.35), 180);
setTimeout(() => beep(1200, 0.25, 0.35), 360);
function testSound(){{
// Gesture handler — unlock first, then delay beeps 80ms for resume().
unlockAudio();
setTimeout(()=>beep(880, 0.15,0.4), 80);
setTimeout(()=>beep(1100,0.15,0.4),260);
setTimeout(()=>beep(880, 0.3, 0.4),440);
}}
function testSound() {{
// Called directly from onclick — gesture is active here.
unlockAudio().then(() => {{
beep(880, 0.15, 0.4);
setTimeout(() => beep(1100, 0.15, 0.4), 180);
setTimeout(() => beep(880, 0.3, 0.4), 360);
}});
function toggleAudio(){{
// Gesture handler — unlock first (synchronous), then do logic.
unlockAudio();
audioEnabled=!audioEnabled;
localStorage.setItem('audioEnabled',audioEnabled);
if(!audioEnabled){{
stopWarning(); audioArmed=false; warningActive=false;
document.getElementById('btn-confirm').style.display='none';
stopStaleWarning(); staleActive=false; staleConfirmed=false;
document.getElementById('btn-confirm-stale').style.display='none';
}} else {{
if(lastStatus==='scanning' && !audioArmed) audioArmed=true;
}}
updateAudioUI();
}}
function toggleAudio() {{
// Called directly from onclick — gesture is active here.
unlockAudio().then(() => {{
audioEnabled = !audioEnabled;
localStorage.setItem('audioEnabled', audioEnabled);
if (!audioEnabled) {{
stopWarning();
audioArmed = false; warningActive = false;
document.getElementById('btn-confirm').style.display = 'none';
stopStaleWarning();
staleActive = false; staleConfirmed = false;
document.getElementById('btn-confirm-stale').style.display = 'none';
}} else {{
if (lastStatus === 'scanning' && !audioArmed) audioArmed = true;
}}
updateAudioUI();
}});
}}
function confirmWarning(){{
stopWarning();
warningActive=false;
@@ -1759,9 +1750,10 @@ function confirmWarning(){{
}}
function startWarning(){{
// Not a gesture handler — context already unlocked by Enable button click.
if(warningActive) return;
warningActive=true;
if(audioEnabled) warningChime(); // returns promise; chime plays after unlock
if(audioEnabled) warningChime();
warningTimer=setInterval(()=>{{ if(audioEnabled) warningChime(); }},30000);
document.getElementById('btn-confirm').style.display='inline-block';
updateAudioUI();
@@ -1780,9 +1772,10 @@ function confirmStale(){{
}}
function startStaleWarning(){{
// Not a gesture handler — context already unlocked by Enable button click.
if(staleActive || staleConfirmed) return;
staleActive=true;
if(audioEnabled) staleChime(); // returns promise; chime plays after unlock
if(audioEnabled) staleChime();
staleTimer=setInterval(()=>{{ if(audioEnabled) staleChime(); }},30000);
document.getElementById('btn-confirm-stale').style.display='inline-block';
updateAudioUI();
@@ -1964,8 +1957,7 @@ function render(d){{
document.getElementById('pi-type').textContent=p.tomo_type||'-';
document.getElementById('pi-eta').textContent=p.estimated_remaining_human||'-';
document.getElementById('pi-start').textContent=fmtTime(p.tomo_start_time);
document.getElementById('bar-sub-label').textContent=(p.subtomo_projection||0)+' / '+(p.subtomo_total_projections||0);
document.getElementById('bar-sub-fill').style.width=(sPct*100).toFixed(1)+'%';
if(d.recon){{
document.getElementById('recon-waiting').textContent=d.recon.waiting;
const fv=document.getElementById('recon-failed');
@@ -2011,4 +2003,4 @@ poll();
</script>
</body>
</html>
"""
"""

View File

@@ -1 +1 @@
from .csaxs_nexus import cSAXSNeXusFormat
from .csaxs_nexus import NeXus_format as cSAXS_NeXus_format

View File

@@ -1,472 +1,445 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import numpy as np
from bec_server.file_writer.default_writer import DefaultFormat
if TYPE_CHECKING:
from bec_lib.devicemanager import DeviceManagerBase
from bec_server.file_writer.file_writer import HDF5Storage
class cSAXSNeXusFormat(DefaultFormat):
def get_entry(data: dict, name: str, default=None) -> Any:
"""
NeXus file format for cSAXS beamline. This format is based on the default NeXus format, but with some additional entries specific to the cSAXS beamline. The structure of the file is based on the NeXus standard, but with some additional groups and datasets specific to the cSAXS beamline.
Get an entry from the scan data assuming a <device>.<device>.value structure.
Args:
data (dict): Scan data
name (str): Entry name
default (Any, optional): Default value. Defaults to None.
"""
if isinstance(data.get(name), list) and isinstance(data.get(name)[0], dict):
return [sub_data.get(name, {}).get("value", default) for sub_data in data.get(name)]
def format(self) -> None:
"""
Prepare the NeXus file format.
Override this method in file writer plugins to customize the HDF5 file format.
return data.get(name, {}).get(name, {}).get("value", default)
The class provides access to the following attributes:
- self.storage: The HDF5Storage object.
- self.data: The data dictionary.
- self.file_references: The file references dictionary, which has the link to external data.
- self.device_manager: The DeviceManagerBase object.
- self.get_entry(name, default=None): Helper method to get an entry from the data dictionary.
See also: :class:`bec_server.file_writer.file_writer.HDF5Storage`.
def NeXus_format(
storage: HDF5Storage, data: dict, file_references: dict, device_manager: DeviceManagerBase
) -> HDF5Storage:
"""
Prepare the NeXus file format.
"""
Args:
storage (HDF5Storage): HDF5 storage. Pseudo hdf5 file container that will be written to disk later.
data (dict): scan data
file_references (dict): File references. Can be used to add external files to the HDF5 file. The path is given relative to the HDF5 file.
device_manager (DeviceManagerBase): Device manager. Can be used to check if devices are available.
# entry = self.storage.create_group("entry")
Returns:
HDF5Storage: Updated HDF5 storage
"""
# /entry
entry = storage.create_group("entry")
entry.attrs["NX_class"] = "NXentry"
entry.attrs["definition"] = "NXsas"
entry.attrs["start_time"] = data.get("start_time")
entry.attrs["end_time"] = data.get("end_time")
entry.attrs["version"] = 1.0
# # /entry/control
# control = entry.create_group("control")
# control.attrs["NX_class"] = "NXmonitor"
# control.create_dataset(name="mode", data="monitor")
# /entry/collection
collection = entry.create_group("collection")
collection.attrs["NX_class"] = "NXcollection"
bec_collection = collection.create_group("bec")
# #########
# # EXAMPLE for soft link
# #########
# # /entry/data
# if "eiger_4" in self.device_manager.devices:
# entry.create_soft_link(name="data", target="/entry/instrument/eiger_4")
# /entry/control
control = entry.create_group("control")
control.attrs["NX_class"] = "NXmonitor"
control.create_dataset(name="mode", data="monitor")
control.create_dataset(name="integral", data=get_entry(data, "bpm4i"))
# ########
# # EXAMPLE for external link
# ########
# # control = entry.create_group("sample")
# # control.create_ext_link("data", self.file_references["eiger9m"]["path"], "EG9M/data")
# /entry/data
main_data = entry.create_group("data")
main_data.attrs["NX_class"] = "NXdata"
if "eiger_4" in device_manager.devices:
main_data.create_soft_link(name="data", target="/entry/instrument/eiger_4/data")
elif "eiger9m" in device_manager.devices:
main_data.create_soft_link(name="data", target="/entry/instrument/eiger9m/data")
elif "pilatus_2" in device_manager.devices:
main_data.create_soft_link(name="data", target="/entry/instrument/pilatus_2/data")
# # /entry/sample
# control = entry.create_group("sample")
# control.attrs["NX_class"] = "NXsample"
# control.create_dataset(name="name", data=self.data.get("samplename"))
# control.create_dataset(name="description", data=self.data.get("sample_description"))
# /entry/sample
control = entry.create_group("sample")
control.attrs["NX_class"] = "NXsample"
control.create_dataset(name="name", data=get_entry(data, "samplename"))
control.create_dataset(name="description", data=data.get("sample_description"))
x_translation = control.create_dataset(name="x_translation", data=get_entry(data, "samx"))
x_translation.attrs["units"] = "mm"
y_translation = control.create_dataset(name="y_translation", data=get_entry(data, "samy"))
y_translation.attrs["units"] = "mm"
temperature_log = control.create_dataset(name="temperature_log", data=get_entry(data, "temp"))
temperature_log.attrs["units"] = "K"
# # /entry/instrument
# instrument = entry.create_group("instrument")
# instrument.attrs["NX_class"] = "NXinstrument"
# /entry/instrument
instrument = entry.create_group("instrument")
instrument.attrs["NX_class"] = "NXinstrument"
instrument.create_dataset(name="name", data="cSAXS beamline")
# source = instrument.create_group("source")
# source.attrs["NX_class"] = "NXsource"
# source.create_dataset(name="type", data="Synchrotron X-ray Source")
# source.create_dataset(name="name", data="Swiss Light Source")
# source.create_dataset(name="probe", data="x-ray")
source = instrument.create_group("source")
source.attrs["NX_class"] = "NXsource"
source.create_dataset(name="type", data="Synchrotron X-ray Source")
source.create_dataset(name="name", data="Swiss Light Source")
source.create_dataset(name="probe", data="x-ray")
distance = source.create_dataset(
name="distance", data=-33800 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
sigma_x = source.create_dataset(name="sigma_x", data=0.202)
sigma_x.attrs["units"] = "mm"
sigma_y = source.create_dataset(name="sigma_y", data=0.018)
sigma_y.attrs["units"] = "mm"
divergence_x = source.create_dataset(name="divergence_x", data=0.000135)
divergence_x.attrs["units"] = "radians"
divergence_y = source.create_dataset(name="divergence_y", data=0.000025)
divergence_y.attrs["units"] = "radians"
current = source.create_dataset(name="current", data=get_entry(data, "curr"))
current.attrs["units"] = "mA"
# # /entry
# entry = self.storage.create_group("entry")
# entry.attrs["NX_class"] = "NXentry"
# entry.attrs["definition"] = "NXsas"
# entry.attrs["start_time"] = self.data.get("start_time")
# entry.attrs["end_time"] = self.data.get("end_time")
# entry.attrs["version"] = 1.0
insertion_device = instrument.create_group("insertion_device")
insertion_device.attrs["NX_class"] = "NXinsertion_device"
source.create_dataset(name="type", data="undulator")
gap = source.create_dataset(name="gap", data=get_entry(data, "idgap"))
gap.attrs["units"] = "mm"
k = source.create_dataset(name="k", data=2.46)
k.attrs["units"] = "NX_DIMENSIONLESS"
length = source.create_dataset(name="length", data=1820)
length.attrs["units"] = "mm"
# # /entry/control
# control = entry.create_group("control")
# control.attrs["NX_class"] = "NXmonitor"
# control.create_dataset(name="mode", data="monitor")
# control.create_dataset(name="integral", data=self.get_entry("bpm4i"))
slit_0 = instrument.create_group("slit_0")
slit_0.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="OFHC Cu")
source.create_dataset(name="description", data="Horizontal secondary source slit")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl0wh"))
x_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl0ch"))
x_translation.attrs["units"] = "mm"
distance = source.create_dataset(
name="distance", data=-21700 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
# # /entry/data
# main_data = entry.create_group("data")
# main_data.attrs["NX_class"] = "NXdata"
# if "eiger_4" in self.device_manager.devices:
# main_data.create_soft_link(name="data", target="/entry/instrument/eiger_4/data")
# elif "eiger9m" in self.device_manager.devices:
# main_data.create_soft_link(name="data", target="/entry/instrument/eiger9m/data")
# elif "pilatus_2" in self.device_manager.devices:
# main_data.create_soft_link(name="data", target="/entry/instrument/pilatus_2/data")
slit_1 = instrument.create_group("slit_1")
slit_1.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="OFHC Cu")
source.create_dataset(name="description", data="Horizontal secondary source slit")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl1wh"))
x_gap.attrs["units"] = "mm"
y_gap = source.create_dataset(name="y_gap", data=get_entry(data, "sl1wv"))
y_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl1ch"))
x_translation.attrs["units"] = "mm"
height = source.create_dataset(name="x_translation", data=get_entry(data, "sl1ch"))
height.attrs["units"] = "mm"
distance = source.create_dataset(
name="distance", data=-7800 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
# # /entry/sample
# control = entry.create_group("sample")
# control.attrs["NX_class"] = "NXsample"
# control.create_dataset(name="name", data=self.get_entry("samplename"))
# control.create_dataset(name="description", data=self.data.get("sample_description"))
# x_translation = control.create_dataset(name="x_translation", data=self.get_entry("samx"))
# x_translation.attrs["units"] = "mm"
# y_translation = control.create_dataset(name="y_translation", data=self.get_entry("samy"))
# y_translation.attrs["units"] = "mm"
# temperature_log = control.create_dataset(
# name="temperature_log", data=self.get_entry("temp")
# )
# temperature_log.attrs["units"] = "K"
mono = instrument.create_group("monochromator")
mono.attrs["NX_class"] = "NXmonochromator"
mokev = data.get("mokev", {})
if mokev:
if isinstance(mokev, list):
mokev = mokev[0]
wavelength = mono.create_dataset(
name="wavelength", data=12.3984193 / (mokev.get("mokev").get("value") + 1e-9)
)
wavelength.attrs["units"] = "Angstrom"
energy = mono.create_dataset(name="energy", data=mokev.get("mokev").get("value"))
energy.attrs["units"] = "keV"
mono.create_dataset(name="type", data="Double crystal fixed exit monochromator.")
distance = mono.create_dataset(
name="distance", data=-5220 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
# # /entry/instrument
# instrument = entry.create_group("instrument")
# instrument.attrs["NX_class"] = "NXinstrument"
# instrument.create_dataset(name="name", data="cSAXS beamline")
crystal_1 = mono.create_group("crystal_1")
crystal_1.attrs["NX_class"] = "NXcrystal"
crystal_1.create_dataset(name="usage", data="Bragg")
crystal_1.create_dataset(name="order_no", data="1")
crystal_1.create_dataset(name="reflection", data="[1 1 1]")
bragg_angle = crystal_1.create_dataset(name="bragg_angle", data=get_entry(data, "moth1"))
bragg_angle.attrs["units"] = "degrees"
# source = instrument.create_group("source")
# source.attrs["NX_class"] = "NXsource"
# source.create_dataset(name="type", data="Synchrotron X-ray Source")
# source.create_dataset(name="name", data="Swiss Light Source")
# source.create_dataset(name="probe", data="x-ray")
# distance = source.create_dataset(
# name="distance", data=-33800 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
# sigma_x = source.create_dataset(name="sigma_x", data=0.202)
# sigma_x.attrs["units"] = "mm"
# sigma_y = source.create_dataset(name="sigma_y", data=0.018)
# sigma_y.attrs["units"] = "mm"
# divergence_x = source.create_dataset(name="divergence_x", data=0.000135)
# divergence_x.attrs["units"] = "radians"
# divergence_y = source.create_dataset(name="divergence_y", data=0.000025)
# divergence_y.attrs["units"] = "radians"
# current = source.create_dataset(name="current", data=self.get_entry("curr"))
# current.attrs["units"] = "mA"
crystal_2 = mono.create_group("crystal_2")
crystal_2.attrs["NX_class"] = "NXcrystal"
crystal_2.create_dataset(name="usage", data="Bragg")
crystal_2.create_dataset(name="order_no", data="2")
crystal_2.create_dataset(name="reflection", data="[1 1 1]")
bragg_angle = crystal_2.create_dataset(name="bragg_angle", data=get_entry(data, "moth1"))
bragg_angle.attrs["units"] = "degrees"
bend_x = crystal_2.create_dataset(name="bend_x", data=get_entry(data, "mobd"))
bend_x.attrs["units"] = "degrees"
# insertion_device = instrument.create_group("insertion_device")
# insertion_device.attrs["NX_class"] = "NXinsertion_device"
# source.create_dataset(name="type", data="undulator")
# gap = source.create_dataset(name="gap", data=self.get_entry("idgap"))
# gap.attrs["units"] = "mm"
# k = source.create_dataset(name="k", data=2.46)
# k.attrs["units"] = "NX_DIMENSIONLESS"
# length = source.create_dataset(name="length", data=1820)
# length.attrs["units"] = "mm"
xbpm4 = instrument.create_group("XBPM4")
xbpm4.attrs["NX_class"] = "NXdetector"
xbpm4_sum = xbpm4.create_group("XBPM4_sum")
xbpm4_sum_data = xbpm4_sum.create_dataset(name="data", data=get_entry(data, "bpm4s"))
xbpm4_sum_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm4_sum.create_dataset(name="description", data="Sum of counts for the four quadrants.")
xbpm4_x = xbpm4.create_group("XBPM4_x")
xbpm4_x_data = xbpm4_x.create_dataset(name="data", data=get_entry(data, "bpm4x"))
xbpm4_x_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm4_x.create_dataset(
name="description", data="Normalized difference of counts between left and right quadrants."
)
xbpm4_y = xbpm4.create_group("XBPM4_y")
xbpm4_y_data = xbpm4_y.create_dataset(name="data", data=get_entry(data, "bpm4y"))
xbpm4_y_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm4_y.create_dataset(
name="description", data="Normalized difference of counts between high and low quadrants."
)
xbpm4_skew = xbpm4.create_group("XBPM4_skew")
xbpm4_skew_data = xbpm4_skew.create_dataset(name="data", data=get_entry(data, "bpm4z"))
xbpm4_skew_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm4_skew.create_dataset(
name="description", data="Normalized difference of counts between diagonal quadrants."
)
# slit_0 = instrument.create_group("slit_0")
# slit_0.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="OFHC Cu")
# source.create_dataset(name="description", data="Horizontal secondary source slit")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl0wh"))
# x_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl0ch"))
# x_translation.attrs["units"] = "mm"
# distance = source.create_dataset(
# name="distance", data=-21700 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
mirror = instrument.create_group("mirror")
mirror.attrs["NX_class"] = "NXmirror"
mirror.create_dataset(name="type", data="single")
mirror.create_dataset(
name="description",
data="Grazing incidence mirror to reject high-harmonic wavelengths from the monochromator. There are three coating options available that are used depending on the X-ray energy, no coating (SiO2), rhodium (Rh) or platinum (Pt).",
)
incident_angle = mirror.create_dataset(name="incident_angle", data=get_entry(data, "mith"))
incident_angle.attrs["units"] = "degrees"
substrate_material = mirror.create_dataset(name="substrate_material", data="SiO2")
substrate_material.attrs["units"] = "NX_CHAR"
coating_material = mirror.create_dataset(name="coating_material", data="SiO2")
coating_material.attrs["units"] = "NX_CHAR"
bend_y = mirror.create_dataset(name="bend_y", data="mibd")
bend_y.attrs["units"] = "NX_DIMENSIONLESS"
distance = mirror.create_dataset(
name="distance", data=-4370 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
# slit_1 = instrument.create_group("slit_1")
# slit_1.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="OFHC Cu")
# source.create_dataset(name="description", data="Horizontal secondary source slit")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl1wh"))
# x_gap.attrs["units"] = "mm"
# y_gap = source.create_dataset(name="y_gap", data=self.get_entry("sl1wv"))
# y_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl1ch"))
# x_translation.attrs["units"] = "mm"
# height = source.create_dataset(name="x_translation", data=self.get_entry("sl1ch"))
# height.attrs["units"] = "mm"
# distance = source.create_dataset(
# name="distance", data=-7800 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
xbpm5 = instrument.create_group("XBPM5")
xbpm5.attrs["NX_class"] = "NXdetector"
xbpm5_sum = xbpm5.create_group("XBPM5_sum")
xbpm5_sum_data = xbpm5_sum.create_dataset(name="data", data=get_entry(data, "bpm5s"))
xbpm5_sum_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm5_sum.create_dataset(name="description", data="Sum of counts for the four quadrants.")
xbpm5_x = xbpm5.create_group("XBPM5_x")
xbpm5_x_data = xbpm5_x.create_dataset(name="data", data=get_entry(data, "bpm5x"))
xbpm5_x_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm5_x.create_dataset(
name="description", data="Normalized difference of counts between left and right quadrants."
)
xbpm5_y = xbpm5.create_group("XBPM5_y")
xbpm5_y_data = xbpm5_y.create_dataset(name="data", data=get_entry(data, "bpm5y"))
xbpm5_y_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm5_y.create_dataset(
name="description", data="Normalized difference of counts between high and low quadrants."
)
xbpm5_skew = xbpm5.create_group("XBPM5_skew")
xbpm5_skew_data = xbpm5_skew.create_dataset(name="data", data=get_entry(data, "bpm5z"))
xbpm5_skew_data.attrs["units"] = "NX_DIMENSIONLESS"
xbpm5_skew.create_dataset(
name="description", data="Normalized difference of counts between diagonal quadrants."
)
# mono = instrument.create_group("monochromator")
# mono.attrs["NX_class"] = "NXmonochromator"
# mokev = self.data.get("mokev", {})
# if mokev:
# if isinstance(mokev, list):
# mokev = mokev[0]
# wavelength = mono.create_dataset(
# name="wavelength", data=12.3984193 / (mokev.get("mokev").get("value") + 1e-9)
# )
# wavelength.attrs["units"] = "Angstrom"
# energy = mono.create_dataset(name="energy", data=mokev.get("mokev").get("value"))
# energy.attrs["units"] = "keV"
# mono.create_dataset(name="type", data="Double crystal fixed exit monochromator.")
# distance = mono.create_dataset(
# name="distance", data=-5220 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
slit_2 = instrument.create_group("slit_2")
slit_2.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="Ag")
source.create_dataset(name="description", data="Slit 2, optics hutch")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl2wh"))
x_gap.attrs["units"] = "mm"
y_gap = source.create_dataset(name="y_gap", data=get_entry(data, "sl2wv"))
y_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl2ch"))
x_translation.attrs["units"] = "mm"
height = source.create_dataset(name="x_translation", data=get_entry(data, "sl2cv"))
height.attrs["units"] = "mm"
distance = source.create_dataset(
name="distance", data=-3140 - np.asarray(get_entry(data, "samz", 0))
)
distance.attrs["units"] = "mm"
# crystal_1 = mono.create_group("crystal_1")
# crystal_1.attrs["NX_class"] = "NXcrystal"
# crystal_1.create_dataset(name="usage", data="Bragg")
# crystal_1.create_dataset(name="order_no", data="1")
# crystal_1.create_dataset(name="reflection", data="[1 1 1]")
# bragg_angle = crystal_1.create_dataset(name="bragg_angle", data=self.get_entry("moth1"))
# bragg_angle.attrs["units"] = "degrees"
slit_3 = instrument.create_group("slit_3")
slit_3.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="Si")
source.create_dataset(name="description", data="Slit 3, experimental hutch, exposure box")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl3wh"))
x_gap.attrs["units"] = "mm"
y_gap = source.create_dataset(name="y_gap", data=get_entry(data, "sl3wv"))
y_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl3ch"))
x_translation.attrs["units"] = "mm"
height = source.create_dataset(name="x_translation", data=get_entry(data, "sl3cv"))
height.attrs["units"] = "mm"
# distance = source.create_dataset(name="distance", data=-3140 - get_entry(data, "samz", 0))
# distance.attrs["units"] = "mm"
# crystal_2 = mono.create_group("crystal_2")
# crystal_2.attrs["NX_class"] = "NXcrystal"
# crystal_2.create_dataset(name="usage", data="Bragg")
# crystal_2.create_dataset(name="order_no", data="2")
# crystal_2.create_dataset(name="reflection", data="[1 1 1]")
# bragg_angle = crystal_2.create_dataset(name="bragg_angle", data=self.get_entry("moth1"))
# bragg_angle.attrs["units"] = "degrees"
# bend_x = crystal_2.create_dataset(name="bend_x", data=self.get_entry("mobd"))
# bend_x.attrs["units"] = "degrees"
filter_set = instrument.create_group("filter_set")
filter_set.attrs["NX_class"] = "NXattenuator"
filter_set.create_dataset(name="material", data="Si")
filter_set.create_dataset(
name="description",
data="The filter set consists of 4 linear stages, each with five filter positions. Additionally, each one allows for an out position to allow 'no filtering'.",
)
attenuator_transmission = filter_set.create_dataset(
name="attenuator_transmission", data=10 ** get_entry(data, "ftrans", 0)
)
attenuator_transmission.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm4 = instrument.create_group("XBPM4")
# xbpm4.attrs["NX_class"] = "NXdetector"
# xbpm4_sum = xbpm4.create_group("XBPM4_sum")
# xbpm4_sum_data = xbpm4_sum.create_dataset(name="data", data=self.get_entry("bpm4s"))
# xbpm4_sum_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm4_sum.create_dataset(name="description", data="Sum of counts for the four quadrants.")
# xbpm4_x = xbpm4.create_group("XBPM4_x")
# xbpm4_x_data = xbpm4_x.create_dataset(name="data", data=self.get_entry("bpm4x"))
# xbpm4_x_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm4_x.create_dataset(
# name="description",
# data="Normalized difference of counts between left and right quadrants.",
# )
# xbpm4_y = xbpm4.create_group("XBPM4_y")
# xbpm4_y_data = xbpm4_y.create_dataset(name="data", data=self.get_entry("bpm4y"))
# xbpm4_y_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm4_y.create_dataset(
# name="description",
# data="Normalized difference of counts between high and low quadrants.",
# )
# xbpm4_skew = xbpm4.create_group("XBPM4_skew")
# xbpm4_skew_data = xbpm4_skew.create_dataset(name="data", data=self.get_entry("bpm4z"))
# xbpm4_skew_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm4_skew.create_dataset(
# name="description", data="Normalized difference of counts between diagonal quadrants."
# )
slit_4 = instrument.create_group("slit_4")
slit_4.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="Si")
source.create_dataset(name="description", data="Slit 4, experimental hutch, exposure box")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl4wh"))
x_gap.attrs["units"] = "mm"
y_gap = source.create_dataset(name="y_gap", data=get_entry(data, "sl4wv"))
y_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl4ch"))
x_translation.attrs["units"] = "mm"
height = source.create_dataset(name="x_translation", data=get_entry(data, "sl4cv"))
height.attrs["units"] = "mm"
# distance = source.create_dataset(name="distance", data=-3140 - get_entry(data, "samz", 0))
# distance.attrs["units"] = "mm"
# mirror = instrument.create_group("mirror")
# mirror.attrs["NX_class"] = "NXmirror"
# mirror.create_dataset(name="type", data="single")
# mirror.create_dataset(
# name="description",
# data="Grazing incidence mirror to reject high-harmonic wavelengths from the monochromator. There are three coating options available that are used depending on the X-ray energy, no coating (SiO2), rhodium (Rh) or platinum (Pt).",
# )
# incident_angle = mirror.create_dataset(name="incident_angle", data=self.get_entry("mith"))
# incident_angle.attrs["units"] = "degrees"
# substrate_material = mirror.create_dataset(name="substrate_material", data="SiO2")
# substrate_material.attrs["units"] = "NX_CHAR"
# coating_material = mirror.create_dataset(name="coating_material", data="SiO2")
# coating_material.attrs["units"] = "NX_CHAR"
# bend_y = mirror.create_dataset(name="bend_y", data="mibd")
# bend_y.attrs["units"] = "NX_DIMENSIONLESS"
# distance = mirror.create_dataset(
# name="distance", data=-4370 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
slit_5 = instrument.create_group("slit_5")
slit_5.attrs["NX_class"] = "NXslit"
source.create_dataset(name="material", data="Si")
source.create_dataset(name="description", data="Slit 5, experimental hutch, exposure box")
x_gap = source.create_dataset(name="x_gap", data=get_entry(data, "sl5wh"))
x_gap.attrs["units"] = "mm"
y_gap = source.create_dataset(name="y_gap", data=get_entry(data, "sl5wv"))
y_gap.attrs["units"] = "mm"
x_translation = source.create_dataset(name="x_translation", data=get_entry(data, "sl5ch"))
x_translation.attrs["units"] = "mm"
height = source.create_dataset(name="x_translation", data=get_entry(data, "sl5cv"))
height.attrs["units"] = "mm"
# distance = source.create_dataset(name="distance", data=-3140 - get_entry(data, "samz", 0))
# distance.attrs["units"] = "mm"
# xbpm5 = instrument.create_group("XBPM5")
# xbpm5.attrs["NX_class"] = "NXdetector"
# xbpm5_sum = xbpm5.create_group("XBPM5_sum")
# xbpm5_sum_data = xbpm5_sum.create_dataset(name="data", data=self.get_entry("bpm5s"))
# xbpm5_sum_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm5_sum.create_dataset(name="description", data="Sum of counts for the four quadrants.")
# xbpm5_x = xbpm5.create_group("XBPM5_x")
# xbpm5_x_data = xbpm5_x.create_dataset(name="data", data=self.get_entry("bpm5x"))
# xbpm5_x_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm5_x.create_dataset(
# name="description",
# data="Normalized difference of counts between left and right quadrants.",
# )
# xbpm5_y = xbpm5.create_group("XBPM5_y")
# xbpm5_y_data = xbpm5_y.create_dataset(name="data", data=self.get_entry("bpm5y"))
# xbpm5_y_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm5_y.create_dataset(
# name="description",
# data="Normalized difference of counts between high and low quadrants.",
# )
# xbpm5_skew = xbpm5.create_group("XBPM5_skew")
# xbpm5_skew_data = xbpm5_skew.create_dataset(name="data", data=self.get_entry("bpm5z"))
# xbpm5_skew_data.attrs["units"] = "NX_DIMENSIONLESS"
# xbpm5_skew.create_dataset(
# name="description", data="Normalized difference of counts between diagonal quadrants."
# )
beam_stop_1 = instrument.create_group("beam_stop_1")
beam_stop_1.attrs["NX_class"] = "NX_beamstop"
beam_stop_1.create_dataset(name="description", data="circular")
bms1_size = beam_stop_1.create_dataset(name="size", data=3)
bms1_size.attrs["units"] = "mm"
bms1_x = beam_stop_1.create_dataset(name="size", data=get_entry(data, "bs1x"))
bms1_x.attrs["units"] = "mm"
bms1_y = beam_stop_1.create_dataset(name="size", data=get_entry(data, "bs1y"))
bms1_y.attrs["units"] = "mm"
# slit_2 = instrument.create_group("slit_2")
# slit_2.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="Ag")
# source.create_dataset(name="description", data="Slit 2, optics hutch")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl2wh"))
# x_gap.attrs["units"] = "mm"
# y_gap = source.create_dataset(name="y_gap", data=self.get_entry("sl2wv"))
# y_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl2ch"))
# x_translation.attrs["units"] = "mm"
# height = source.create_dataset(name="x_translation", data=self.get_entry("sl2cv"))
# height.attrs["units"] = "mm"
# distance = source.create_dataset(
# name="distance", data=-3140 - np.asarray(self.get_entry("samz", 0))
# )
# distance.attrs["units"] = "mm"
beam_stop_2 = instrument.create_group("beam_stop_2")
beam_stop_2.attrs["NX_class"] = "NX_beamstop"
beam_stop_2.create_dataset(name="description", data="rectangular")
bms2_size_x = beam_stop_2.create_dataset(name="size_x", data=5)
bms2_size_x.attrs["units"] = "mm"
bms2_size_y = beam_stop_2.create_dataset(name="size_y", data=2.25)
bms2_size_y.attrs["units"] = "mm"
bms2_x = beam_stop_2.create_dataset(name="size", data=get_entry(data, "bs2x"))
bms2_x.attrs["units"] = "mm"
bms2_y = beam_stop_2.create_dataset(name="size", data=get_entry(data, "bs2y"))
bms2_y.attrs["units"] = "mm"
bms2_data = beam_stop_2.create_dataset(name="data", data=get_entry(data, "diode"))
bms2_data.attrs["units"] = "NX_DIMENSIONLESS"
# slit_3 = instrument.create_group("slit_3")
# slit_3.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="Si")
# source.create_dataset(name="description", data="Slit 3, experimental hutch, exposure box")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl3wh"))
# x_gap.attrs["units"] = "mm"
# y_gap = source.create_dataset(name="y_gap", data=self.get_entry("sl3wv"))
# y_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl3ch"))
# x_translation.attrs["units"] = "mm"
# height = source.create_dataset(name="x_translation", data=self.get_entry("sl3cv"))
# height.attrs["units"] = "mm"
# # distance = source.create_dataset(name="distance", data=-3140 - self.get_entry("samz", 0))
# # distance.attrs["units"] = "mm"
if "eiger1p5m" in device_manager.devices and device_manager.devices.eiger1p5m.enabled:
eiger_4 = instrument.create_group("eiger_4")
eiger_4.attrs["NX_class"] = "NXdetector"
x_pixel_size = eiger_4.create_dataset(name="x_pixel_size", data=75)
x_pixel_size.attrs["units"] = "um"
y_pixel_size = eiger_4.create_dataset(name="y_pixel_size", data=75)
y_pixel_size.attrs["units"] = "um"
polar_angle = eiger_4.create_dataset(name="polar_angle", data=0)
polar_angle.attrs["units"] = "degrees"
azimuthal_angle = eiger_4.create_dataset(name="azimuthal_angle", data=0)
azimuthal_angle.attrs["units"] = "degrees"
rotation_angle = eiger_4.create_dataset(name="rotation_angle", data=0)
rotation_angle.attrs["units"] = "degrees"
description = eiger_4.create_dataset(
name="description", data="Single-photon counting detector, 320 micron-thick Si chip"
)
orientation = eiger_4.create_group("orientation")
orientation.attrs["description"] = (
"Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
)
orientation.create_dataset(name="transpose", data=1)
orientation.create_dataset(name="rot90", data=3)
# filter_set = instrument.create_group("filter_set")
# filter_set.attrs["NX_class"] = "NXattenuator"
# filter_set.create_dataset(name="material", data="Si")
# filter_set.create_dataset(
# name="description",
# data="The filter set consists of 4 linear stages, each with five filter positions. Additionally, each one allows for an out position to allow 'no filtering'.",
# )
# attenuator_transmission = filter_set.create_dataset(
# name="attenuator_transmission", data=10 ** self.get_entry("ftrans", 0)
# )
# attenuator_transmission.attrs["units"] = "NX_DIMENSIONLESS"
if (
"eiger9m" in device_manager.devices
and device_manager.devices.eiger9m.enabled
and "eiger9m" in file_references
):
eiger9m = instrument.create_group("eiger9m")
eiger9m.attrs["NX_class"] = "NXdetector"
x_pixel_size = eiger9m.create_dataset(name="x_pixel_size", data=75)
x_pixel_size.attrs["units"] = "um"
y_pixel_size = eiger9m.create_dataset(name="y_pixel_size", data=75)
y_pixel_size.attrs["units"] = "um"
polar_angle = eiger9m.create_dataset(name="polar_angle", data=0)
polar_angle.attrs["units"] = "degrees"
azimuthal_angle = eiger9m.create_dataset(name="azimuthal_angle", data=0)
azimuthal_angle.attrs["units"] = "degrees"
rotation_angle = eiger9m.create_dataset(name="rotation_angle", data=0)
rotation_angle.attrs["units"] = "degrees"
description = eiger9m.create_dataset(
name="description", data="Eiger9M detector, in-house developed, Paul Scherrer Institute"
)
orientation = eiger9m.create_group("orientation")
orientation.attrs["description"] = (
"Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
)
orientation.create_dataset(name="transpose", data=1)
orientation.create_dataset(name="rot90", data=3)
data = eiger9m.create_ext_link("data", file_references["eiger9m"]["path"], "EG9M/data")
status = eiger9m.create_ext_link(
"status", file_references["eiger9m"]["path"], "EG9M/status"
)
# slit_4 = instrument.create_group("slit_4")
# slit_4.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="Si")
# source.create_dataset(name="description", data="Slit 4, experimental hutch, exposure box")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl4wh"))
# x_gap.attrs["units"] = "mm"
# y_gap = source.create_dataset(name="y_gap", data=self.get_entry("sl4wv"))
# y_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl4ch"))
# x_translation.attrs["units"] = "mm"
# height = source.create_dataset(name="x_translation", data=self.get_entry("sl4cv"))
# height.attrs["units"] = "mm"
# # distance = source.create_dataset(name="distance", data=-3140 - self.get_entry("samz", 0))
# # distance.attrs["units"] = "mm"
if (
"pilatus_2" in device_manager.devices
and device_manager.devices.pilatus_2.enabled
and "pilatus_2" in file_references
):
pilatus_2 = instrument.create_group("pilatus_2")
pilatus_2.attrs["NX_class"] = "NXdetector"
x_pixel_size = pilatus_2.create_dataset(name="x_pixel_size", data=172)
x_pixel_size.attrs["units"] = "um"
y_pixel_size = pilatus_2.create_dataset(name="y_pixel_size", data=172)
y_pixel_size.attrs["units"] = "um"
polar_angle = pilatus_2.create_dataset(name="polar_angle", data=0)
polar_angle.attrs["units"] = "degrees"
azimuthal_angle = pilatus_2.create_dataset(name="azimuthal_angle", data=0)
azimuthal_angle.attrs["units"] = "degrees"
rotation_angle = pilatus_2.create_dataset(name="rotation_angle", data=0)
rotation_angle.attrs["units"] = "degrees"
description = pilatus_2.create_dataset(
name="description", data="Pilatus 300K detector, Dectris, Switzerland"
)
orientation = pilatus_2.create_group("orientation")
orientation.attrs["description"] = (
"Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
)
orientation.create_dataset(name="transpose", data=1)
orientation.create_dataset(name="rot90", data=2)
data = pilatus_2.create_ext_link(
"data", file_references["pilatus_2"]["path"], "entry/instrument/pilatus_2/data"
)
# slit_5 = instrument.create_group("slit_5")
# slit_5.attrs["NX_class"] = "NXslit"
# source.create_dataset(name="material", data="Si")
# source.create_dataset(name="description", data="Slit 5, experimental hutch, exposure box")
# x_gap = source.create_dataset(name="x_gap", data=self.get_entry("sl5wh"))
# x_gap.attrs["units"] = "mm"
# y_gap = source.create_dataset(name="y_gap", data=self.get_entry("sl5wv"))
# y_gap.attrs["units"] = "mm"
# x_translation = source.create_dataset(name="x_translation", data=self.get_entry("sl5ch"))
# x_translation.attrs["units"] = "mm"
# height = source.create_dataset(name="x_translation", data=self.get_entry("sl5cv"))
# height.attrs["units"] = "mm"
# # distance = source.create_dataset(name="distance", data=-3140 - self.get_entry("samz", 0))
# # distance.attrs["units"] = "mm"
if (
"falcon" in device_manager.devices
and device_manager.devices.falcon.enabled
and "falcon" in file_references
):
falcon = instrument.create_ext_link(
"falcon", file_references["falcon"]["path"], "entry/instrument/FalconX1"
)
# beam_stop_1 = instrument.create_group("beam_stop_1")
# beam_stop_1.attrs["NX_class"] = "NX_beamstop"
# beam_stop_1.create_dataset(name="description", data="circular")
# bms1_size = beam_stop_1.create_dataset(name="size", data=3)
# bms1_size.attrs["units"] = "mm"
# bms1_x = beam_stop_1.create_dataset(name="size", data=self.get_entry("bs1x"))
# bms1_x.attrs["units"] = "mm"
# bms1_y = beam_stop_1.create_dataset(name="size", data=self.get_entry("bs1y"))
# bms1_y.attrs["units"] = "mm"
# beam_stop_2 = instrument.create_group("beam_stop_2")
# beam_stop_2.attrs["NX_class"] = "NX_beamstop"
# beam_stop_2.create_dataset(name="description", data="rectangular")
# bms2_size_x = beam_stop_2.create_dataset(name="size_x", data=5)
# bms2_size_x.attrs["units"] = "mm"
# bms2_size_y = beam_stop_2.create_dataset(name="size_y", data=2.25)
# bms2_size_y.attrs["units"] = "mm"
# bms2_x = beam_stop_2.create_dataset(name="size", data=self.get_entry("bs2x"))
# bms2_x.attrs["units"] = "mm"
# bms2_y = beam_stop_2.create_dataset(name="size", data=self.get_entry("bs2y"))
# bms2_y.attrs["units"] = "mm"
# bms2_data = beam_stop_2.create_dataset(name="data", data=self.get_entry("diode"))
# bms2_data.attrs["units"] = "NX_DIMENSIONLESS"
# if (
# "eiger1p5m" in self.device_manager.devices
# and self.device_manager.devices.eiger1p5m.enabled
# ):
# eiger_4 = instrument.create_group("eiger_4")
# eiger_4.attrs["NX_class"] = "NXdetector"
# x_pixel_size = eiger_4.create_dataset(name="x_pixel_size", data=75)
# x_pixel_size.attrs["units"] = "um"
# y_pixel_size = eiger_4.create_dataset(name="y_pixel_size", data=75)
# y_pixel_size.attrs["units"] = "um"
# polar_angle = eiger_4.create_dataset(name="polar_angle", data=0)
# polar_angle.attrs["units"] = "degrees"
# azimuthal_angle = eiger_4.create_dataset(name="azimuthal_angle", data=0)
# azimuthal_angle.attrs["units"] = "degrees"
# rotation_angle = eiger_4.create_dataset(name="rotation_angle", data=0)
# rotation_angle.attrs["units"] = "degrees"
# description = eiger_4.create_dataset(
# name="description", data="Single-photon counting detector, 320 micron-thick Si chip"
# )
# orientation = eiger_4.create_group("orientation")
# orientation.attrs["description"] = (
# "Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
# )
# orientation.create_dataset(name="transpose", data=1)
# orientation.create_dataset(name="rot90", data=3)
# if (
# "eiger9m" in self.device_manager.devices
# and self.device_manager.devices.eiger9m.enabled
# and "eiger9m" in self.file_references
# ):
# eiger9m = instrument.create_group("eiger9m")
# eiger9m.attrs["NX_class"] = "NXdetector"
# x_pixel_size = eiger9m.create_dataset(name="x_pixel_size", data=75)
# x_pixel_size.attrs["units"] = "um"
# y_pixel_size = eiger9m.create_dataset(name="y_pixel_size", data=75)
# y_pixel_size.attrs["units"] = "um"
# polar_angle = eiger9m.create_dataset(name="polar_angle", data=0)
# polar_angle.attrs["units"] = "degrees"
# azimuthal_angle = eiger9m.create_dataset(name="azimuthal_angle", data=0)
# azimuthal_angle.attrs["units"] = "degrees"
# rotation_angle = eiger9m.create_dataset(name="rotation_angle", data=0)
# rotation_angle.attrs["units"] = "degrees"
# description = eiger9m.create_dataset(
# name="description",
# data="Eiger9M detector, in-house developed, Paul Scherrer Institute",
# )
# orientation = eiger9m.create_group("orientation")
# orientation.attrs["description"] = (
# "Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
# )
# orientation.create_dataset(name="transpose", data=1)
# orientation.create_dataset(name="rot90", data=3)
# data = eiger9m.create_ext_link(
# "data", self.file_references["eiger9m"]["path"], "EG9M/data"
# )
# status = eiger9m.create_ext_link(
# "status", self.file_references["eiger9m"]["path"], "EG9M/status"
# )
# if (
# "pilatus_2" in self.device_manager.devices
# and self.device_manager.devices.pilatus_2.enabled
# and "pilatus_2" in self.file_references
# ):
# pilatus_2 = instrument.create_group("pilatus_2")
# pilatus_2.attrs["NX_class"] = "NXdetector"
# x_pixel_size = pilatus_2.create_dataset(name="x_pixel_size", data=172)
# x_pixel_size.attrs["units"] = "um"
# y_pixel_size = pilatus_2.create_dataset(name="y_pixel_size", data=172)
# y_pixel_size.attrs["units"] = "um"
# polar_angle = pilatus_2.create_dataset(name="polar_angle", data=0)
# polar_angle.attrs["units"] = "degrees"
# azimuthal_angle = pilatus_2.create_dataset(name="azimuthal_angle", data=0)
# azimuthal_angle.attrs["units"] = "degrees"
# rotation_angle = pilatus_2.create_dataset(name="rotation_angle", data=0)
# rotation_angle.attrs["units"] = "degrees"
# description = pilatus_2.create_dataset(
# name="description", data="Pilatus 300K detector, Dectris, Switzerland"
# )
# orientation = pilatus_2.create_group("orientation")
# orientation.attrs["description"] = (
# "Orientation defines the number of counterclockwise rotations by 90 deg followed by a transposition to reach the 'cameraman orientation', that is looking towards the beam."
# )
# orientation.create_dataset(name="transpose", data=1)
# orientation.create_dataset(name="rot90", data=2)
# data = pilatus_2.create_ext_link(
# "data", self.file_references["pilatus_2"]["path"], "entry/instrument/pilatus_2/data"
# )
# if (
# "falcon" in self.device_manager.devices
# and self.device_manager.devices.falcon.enabled
# and "falcon" in self.file_references
# ):
# falcon = instrument.create_ext_link(
# "falcon", self.file_references["falcon"]["path"], "entry/instrument/FalconX1"
# )
return storage