-
Notifications
You must be signed in to change notification settings - Fork 22
Create a new device class for tcavs #261
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
Open
phys-cgarnier
wants to merge
30
commits into
main
Choose a base branch
from
254-create-a-new-device-class-for-tcavs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
4eb4a59
updated python files to account for tcav
phys-cgarnier 932bc05
added stcav2 to lcls_elements.csv, some fields may be in correct
phys-cgarnier 60b57f5
Merge branch 'main' into tcav
phys-cgarnier 60189ec
fixed some import errors
phys-cgarnier 73b9596
committing change to lcls_elements.csv
phys-cgarnier e55cbc9
added tcavs to yaml and updated generate code.
phys-cgarnier 4fb9447
added comment about problematic use case
phys-cgarnier b9a9295
flake8
phys-cgarnier 9c3c9f5
updating PVs for generate.py
phys-cgarnier 4b23307
initial commit of skeleton code for tcav devices
phys-cgarnier 24d7482
changed PVs in skeleton code
phys-cgarnier cefa0d1
fixed a typo in extract tcav
phys-cgarnier 6be4e83
Merge branch 'main' into tcav
phys-cgarnier 35bf110
merged main into branch, updated metadata fields for tcav
phys-cgarnier 65bd63d
ran generation script to pick up tcavs
phys-cgarnier 9957648
added some properties for getting and setting PVs, realized I am mi…
phys-cgarnier 6750b19
built out tcav class, changed some pvs in generate, need to run scrip…
phys-cgarnier 18449b3
added mode_config pv decorator, need to build out the setter more
phys-cgarnier e78ce3f
linter
phys-cgarnier 0cb374c
linter....
phys-cgarnier 8efd654
used pre-commit this time..
phys-cgarnier 441c57b
updated yamls to have new PVs
phys-cgarnier f9c9ff3
added a way to set modecfg value. added docstrings
phys-cgarnier 57246b8
set up write to only write tcav entries on DIAG0 area
phys-cgarnier d2993ce
removed tcavs that are not stcav2, this is because the controls for o…
phys-cgarnier 9c7f53b
bug in check_options tcav function, should be resolved
phys-cgarnier 13eb26a
changed rf frequencey from a str to a float
e21dc28
Merge branch 'main' into tcav
phys-cgarnier 910043e
updated tcav.py to reflect requested changes in PR review
phys-cgarnier 8a84326
removed tcav collection from import since it will never be used
phys-cgarnier File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
from pydantic import ( | ||
NonNegativeFloat, | ||
SerializeAsAny, | ||
field_validator, | ||
) | ||
from typing import ( | ||
Dict, | ||
Optional, | ||
) | ||
from lcls_tools.common.devices.device import ( | ||
Device, | ||
ControlInformation, | ||
Metadata, | ||
PVSet, | ||
) | ||
from epics import PV | ||
|
||
|
||
class TCAVPVSet(PVSet): | ||
amp_set: PV | ||
phase_set: PV | ||
rf_enable: PV | ||
amp_fbenb: PV | ||
phase_fbenb: PV | ||
amp_fbst: PV | ||
phase_fbst: PV | ||
mode_config: PV | ||
|
||
@field_validator("*", mode="before") | ||
def validate_pv_fields(cls, v: str) -> PV: | ||
return PV(v) | ||
|
||
|
||
class TCAVControlInformation(ControlInformation): | ||
PVs: SerializeAsAny[TCAVPVSet] | ||
_mode_config_options: SerializeAsAny[Optional[Dict[str, int]]] = dict() | ||
_amplitude_feedback_options: SerializeAsAny[Optional[Dict[str, int]]] = dict() | ||
_phase_feedback_options: SerializeAsAny[Optional[Dict[str, int]]] = dict() | ||
|
||
def model_post_init(self, __context) -> None: | ||
""" | ||
Post-initialization hook for Pydantic models. | ||
Retrieves and stores all PV enum options immediately after model creation. | ||
Args: | ||
__context: Reserved for Pydantic internals. Must be present for compliance. | ||
Raises: | ||
TimeoutError: If any PV fails to return its control variables. | ||
""" | ||
_ = __context # avoid linter warning for unused variable | ||
self.set_mode_config_option() | ||
self.set_amplitude_feedback_options() | ||
self.setup_phase_feedback_option() | ||
|
||
def set_mode_config_option(self): | ||
""" | ||
Fetches and stores the enumerated options for the mode configuration PV. | ||
This method calls `get_ctrlvars()` on the `mode_configs` PV to retrieve | ||
its enum string options and populates the `_mode_config_options` dictionary. | ||
Raises: | ||
TimeoutError: If the PV does not return control variables within the timeout period. | ||
""" | ||
mode_config_options = self.PVs.mode_configs.get_ctrlvars(timeout=2.5) | ||
if not mode_config_options: | ||
raise TimeoutError( | ||
"Timeout while retrieving control variables from mode_configs PV." | ||
) | ||
|
||
self._mode_config_options.update( | ||
{option: i for i, option in enumerate(mode_config_options["enum_strs"])} | ||
) | ||
|
||
def set_amplitude_feedback_options(self): | ||
""" | ||
Fetches and stores the enumerated options for the amplitude feedback enable PV. | ||
Retrieves enum strings from the `amp_fbenb` PV using `get_ctrlvars()` and | ||
updates `_amplitude_feedback_options`. | ||
Raises: | ||
TimeoutError: If control variables are not returned within the timeout duration. | ||
""" | ||
amplitude_feedback_options = self.PVs.amp_fbenb.get_ctrlvars(timeout=2.5) | ||
if not amplitude_feedback_options: | ||
raise TimeoutError( | ||
"Timeout while retrieving control variables from amp_fbenb PV." | ||
) | ||
|
||
self._amplitude_feedback_options.update( | ||
{ | ||
option: i | ||
for i, option in enumerate(amplitude_feedback_options["enum_strs"]) | ||
} | ||
) | ||
|
||
def setup_phase_feedback_option(self): | ||
""" | ||
Fetches and stores the enumerated options for the phase feedback enable PV. | ||
Uses `get_ctrlvars()` on the `phase_fbenb` PV to retrieve available options | ||
and populates `_phase_feedback_options`. | ||
Raises: | ||
TimeoutError: If control variables are not available within the timeout window. | ||
""" | ||
phase_feedback_option = self.PVs.phase_fbenb.get_ctrlvars(timeout=2.5) | ||
if not phase_feedback_option: | ||
raise TimeoutError( | ||
"Timeout while retrieving control variables from phase_fbenb PV." | ||
) | ||
|
||
self._phase_feedback_options.update( | ||
{option: i for i, option in enumerate(phase_feedback_option["enum_strs"])} | ||
) | ||
|
||
@property | ||
def mode_config_options(self): | ||
return self._mode_config_options | ||
|
||
@property | ||
def amplitude_feedback_options(self): | ||
return self._amplitude_feedback_options | ||
|
||
@property | ||
def phase_feedback_options(self): | ||
return self._phase_feedback_options | ||
|
||
|
||
class TCAVMetadata(Metadata): | ||
l_eff: Optional[NonNegativeFloat] = None | ||
rf_freq: Optional[NonNegativeFloat] = None | ||
|
||
|
||
class TCAV(Device): | ||
controls_information: SerializeAsAny[TCAVControlInformation] | ||
metadata: SerializeAsAny[TCAVMetadata] | ||
|
||
# Decorator didn't want to work, manually controlled types | ||
""" | ||
def validate_enum_value(self, field_options: Dict): | ||
def decorator(setter_method: Callable): | ||
@wraps(setter_method) | ||
def decorated(self, enum_str): | ||
if not isinstance(enum_str,str): | ||
raise TypeError(f"{enum_str} is not of type: str") | ||
if enum_str not in field_options: | ||
raise ValueError(f"{enum_str} not in list of acceptable enumerate string PV values") | ||
return setter_method(self, enum_str) | ||
return decorated | ||
return decorator | ||
""" | ||
|
||
@property | ||
def amp_set(self): | ||
"""The amplitude set point of the TCAV""" | ||
return self.controls_information.PVs.amp_set.get() | ||
|
||
@amp_set.setter | ||
def amp_set(self, amplitude): | ||
if not isinstance(amplitude, float): | ||
return | ||
self.controls_information.PVs.amp_set.put(amplitude) | ||
|
||
@property | ||
def phase_set(self): | ||
"""The phase set point of the TCAV""" | ||
return self.controls_information.PVs.phase_set.get() | ||
|
||
@phase_set.setter | ||
def phase_set(self, phase): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another place for pydantic validation. |
||
if not isinstance([phase], float): | ||
return | ||
self.controls_information.PVs.phase.put(phase) | ||
|
||
@property | ||
def amp_fbenb(self): | ||
"""The status of the amplitude set point feedback""" | ||
return self.controls_information.PVs.amp_fbenb.get() | ||
|
||
@amp_fbenb.setter | ||
def amp_fbenb(self, enum_str: str): | ||
field_options = self.controls_information.amplitude_feedback_options | ||
if not isinstance(enum_str, str): | ||
raise TypeError(f"{enum_str} is not of type: str") | ||
if enum_str not in field_options: | ||
raise ValueError( | ||
f"{enum_str} not in list of acceptable enumerate string PV values" | ||
) | ||
self.controls_information.PVs.amp_fbenb = enum_str | ||
|
||
@property | ||
def phase_fbenb(self): | ||
"""The status of the phase set point feedback""" | ||
return self.controls_information.PVs.phase_fbenb.get() | ||
|
||
@phase_fbenb.setter | ||
def phase_fbenb(self, enum_str: str): | ||
field_options = self.controls_information.phase_feedback_options | ||
if not isinstance(enum_str, str): | ||
raise TypeError(f"{enum_str} is not of type: str") | ||
if enum_str not in field_options: | ||
raise ValueError( | ||
f"{enum_str} not in list of acceptable enumerate string PV values" | ||
) | ||
self.controls_information.PVs.phase_fbenb.put(enum_str) | ||
|
||
@property | ||
def amp_fbst(self): | ||
"""The state of the amplitude feedback""" | ||
return self.controls_information.PVs.amp_fbst.get() | ||
|
||
@property | ||
def phase_fbst(self): | ||
"""The state of the phase feedback""" | ||
return self.controls_information.PVs.phase_fbst.get() | ||
|
||
@property | ||
def mode_config(self): | ||
"""The current ATCA Trigger State""" | ||
return self.controls_information.PVs.mode_config.get(as_string=True) | ||
|
||
@mode_config.setter | ||
def mode_config(self, enum_str): | ||
field_options = self.controls_information.mode_config_options | ||
if not isinstance(enum_str, str): | ||
raise TypeError(f"{enum_str} is not of type: str") | ||
if enum_str not in field_options: | ||
raise ValueError( | ||
f"{enum_str} not in list of acceptable enumerate string PV values" | ||
) | ||
self.controls_information.PVs.mode_config.put(enum_str) | ||
|
||
@property | ||
def l_eff(self): | ||
"""The effective length of the TCAV in meters""" | ||
return self.metadata.l_eff | ||
|
||
@l_eff.setter | ||
def l_eff(self, length): | ||
if not isinstance(length, float): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pydantic validation could replace this. |
||
return | ||
self.metadata.l_eff = length | ||
|
||
@property | ||
def rf_freq(self): | ||
"""The Rf frequency of the TCAV in MHz""" | ||
return self.metadata.rf_freq |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pydantic lets you validate function arguments with function annotations like so:
The if statement shouldn't be necessary.