Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mono photon energy calculator #306

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 54 additions & 10 deletions sed/config/flash_example_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,19 @@ dataframe:
# slice: if the group contains multidim data, where to slice

channels:
# pulse ID is a necessary channel for using the loader.
pulseId:
timeStamp:
format: per_train
group_name: "/uncategorised/FLASH.DIAG/TIMINGINFO/TIME1.BUNCH_FIRST_INDEX.1/"
pulseId: # pulse ID is a necessary channel for using the loader.
format: per_electron
group_name: "/uncategorised/FLASH.EXP/HEXTOF.DAQ/DLD1/"
slice: 2

dldPosX:
# DLD channels
dldPosX: # x position on the DLD detector
format: per_electron
group_name: "/uncategorised/FLASH.EXP/HEXTOF.DAQ/DLD1/"
slice: 1

dldPosY:
dldPosY: # x position on the DLD detector
format: per_electron
group_name: "/uncategorised/FLASH.EXP/HEXTOF.DAQ/DLD1/"
slice: 0
Expand All @@ -108,10 +109,8 @@ dataframe:
format: per_electron
group_name: "/uncategorised/FLASH.EXP/HEXTOF.DAQ/DLD1/"
slice: 3

# The auxillary channel has a special structure where the group further contains
# a multidim structure so further aliases are defined below
dldAux:
dldAux: # The auxillary channel has a special structure where the group further contains
# a multidim structure so further aliases are defined below
format: per_pulse
group_name: "/uncategorised/FLASH.EXP/HEXTOF.DAQ/DLD1/"
slice: 4
Expand All @@ -123,6 +122,49 @@ dataframe:
cryoTemperature: 4
sampleTemperature: 5
dldTimeBinSize: 15
# FEL channels
gmdBda: # in uJ per pulse
format: per_pulse
group_name: "/FL1/Photon Diagnostic/GMD/Average energy/energy BDA/"
slice: 0
gmdPosh: # verrical position of the FEL
format: per_pulse
group_name: "/FL1/Photon Diagnostic/GMD/Average energy/energy BDA/"
slice: 2
gmdPosv: # horizontal position of the FEL
format: per_pulse
group_name: "/FL1/Photon Diagnostic/GMD/Average energy/energy BDA/"
slice: 3
bam: # Here we use the DBC2 BAM as the "normal" one is broken.
format: per_pulse
group_name: "/uncategorised/FLASH.SDIAG/BAM.DAQ/FL0.DBC2.ARRIVAL_TIME.ABSOLUTE.SA1.COMP/"
monochromatorPhotonEnergy: # single value. to be changed
format: per_train
group_name: "/FL1/Beamlines/PG/Monochromator/monochromator photon energy/"
monoDelta1:
format: per_train
group_name: "/FL1/Beamlines/PG/Monochromator/ADC.PGM2/"
slice: 0
monoDelta2:
format: per_train
group_name: "/FL1/Beamlines/PG/Monochromator/ADC.PGM2/"
slice: 1
monoMirrorAngle:
format: per_train
group_name: "/FL1/Beamlines/PG/Monochromator/ADC.PGM2/"
slice: 2
monoGratingAngle:
format: per_train
group_name: "/FL1/Beamlines/PG/Monochromator/ADC.PGM2/"
slice: 3

# Optical laser channels
delayStage:
format: per_train
group_name: "/zraw/FLASH.SYNC/LASER.LOCK.EXP/F1.PG.OSC/FMC0.MD22.1.ENCODER_POSITION.RD/dGroup/"
opticalDiode:
format: per_pulse
group_name: "/zraw/FLASH.LASER/FLACPUPGLASER1.PULSEENERGY/PG2_incoupl/dGroup/"

# The prefixes of the stream names for different DAQ systems for parsing filenames
# (Not to be changed by user)
Expand All @@ -139,6 +181,8 @@ dataframe:
# (Not to be changed by user)
beamtime_dir:
pg2: "/asap3/flash/gpfs/pg2/"
hextof: "/asap3/fs-flash-o/gpfs/hextof/"
wespe: "/asap3/fs-flash-o/gpfs/wespe/"

# metadata collection from scicat
# metadata:
Expand Down
7 changes: 7 additions & 0 deletions sed/loader/flash/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from sed.core import dfops
from sed.loader.base.loader import BaseLoader
from sed.loader.flash.metadata import MetadataRetriever
from sed.loader.utils import add_monochromator_photon_energy
from sed.loader.utils import parse_h5_keys
from sed.loader.utils import split_dld_time_from_sector_id

Expand Down Expand Up @@ -631,6 +632,12 @@ def create_dataframe_per_file(
# correct the 3 bit shift which encodes the detector ID in the 8s time
if self._config["dataframe"].get("split_sector_id_from_dld_time", False):
df = split_dld_time_from_sector_id(df, config=self._config)
mono_channels = ["delta1", "delta2"]
if all([channel in df.columns for channel in mono_channels]):
grating_density = self._config["dataframe"].get("gratingDensity", None)
order = self._config["dataframe"].get("order", None)
if grating_density is not None and order is not None:
df = add_monochromator_photon_energy(df)
return df

def create_buffer_file(self, h5_path: Path, parquet_path: Path) -> Union[bool, Exception]:
Expand Down
53 changes: 53 additions & 0 deletions sed/loader/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,56 @@ def split_dld_time_from_sector_id(
types=[np.int8, np.int32],
)
return df


def calculate_monochromator_photon_energy(
delta1: float,
delta2: float,
grating_density: int,
order: int,
) -> float:
"""
Calculates the photon energy of the monochromator using the grating density and order.

Args:
delta1 (float): The angle of the first crystal in radians.
delta2 (float): The angle of the second crystal in radians.
grating_density (int): The grating density in grooves per mm.
order (int): The order of the diffraction.

Returns:
float: The photon energy in eV.
"""
alpha = 2.0 * delta1 + 90.0 - delta2
beta = -1.0 * delta2 - 86.0
num = 1e6 * (np.sin(beta / 180.0 * np.pi) + np.sin(alpha / 180.0 * np.pi))
den = order * grating_density
lambda_nm = num / den
hc = 1239.84
lambda_ev = hc / lambda_nm
return lambda_ev


def add_monochromator_photon_energy(
df: Union[pd.DataFrame, dask.dataframe.DataFrame],
config: dict = None,
) -> Union[pd.DataFrame, dask.dataframe.DataFrame]:
mono_channels = ["delta1", "delta2", "gratingDensity", "order"]
if config is None:
raise ValueError("config must be given.")
for channel in mono_channels:
if channel not in config["dataframe"]:
raise ValueError(f"config must contain {channel}.")
if "monoPhotonEnergy" in df.columns:
raise ValueError(
"Column monoPhotonEnergy already in dataframe. ",
)
df = df.assign(
monoPhotonEnergy=calculate_monochromator_photon_energy(
df[config["dataframe"]["delta1"]],
df[config["dataframe"]["delta2"]],
config["dataframe"]["gratingDensity"],
config["dataframe"]["order"],
),
)
return df
Loading