Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

New external parameter model #1284

Merged
merged 48 commits into from
Apr 22, 2024
Merged

New external parameter model #1284

merged 48 commits into from
Apr 22, 2024

Conversation

d-perl
Copy link
Contributor

@d-perl d-perl commented Mar 26, 2024

Fixes #698

Introduces a new set of pydantic classes to replace the old external params. Eventually these will replace the internal params too.

Associated GDA changes at https://gerrit.diamond.ac.uk/c/gda/gda-mx/+/41445

To test:

  1. Run tests

@d-perl d-perl marked this pull request as draft March 26, 2024 13:19
Copy link
Collaborator

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I think this is getting towards the right direction. Some comments in code. We can have a chat about the geometry thing, not sure what a better representation is off the top of my head.

src/hyperion/parameters/components.py Outdated Show resolved Hide resolved
src/hyperion/parameters/components.py Show resolved Hide resolved
src/hyperion/parameters/components.py Show resolved Hide resolved
src/hyperion/parameters/constants.py Outdated Show resolved Hide resolved
src/hyperion/parameters/constants.py Outdated Show resolved Hide resolved
src/hyperion/parameters/gridscan.py Outdated Show resolved Hide resolved
src/hyperion/parameters/gridscan.py Outdated Show resolved Hide resolved
src/hyperion/parameters/rotation.py Outdated Show resolved Hide resolved
src/hyperion/parameters/rotation.py Outdated Show resolved Hide resolved
src/hyperion/parameters/rotation.py Outdated Show resolved Hide resolved
Copy link
Contributor

@olliesilvester olliesilvester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this, this new parameter model is much more intuitive. I think a section on the wiki summarising how it works and what various keywords mean would be very useful for onboarding too.

Also, it would be good to have some tests for the gridscan.py properties, like scan_points and scan_indicies

src/hyperion/parameters/components.py Outdated Show resolved Hide resolved
"experiment_param_type": PinCentreThenXrayCentreParams,
"callbacks_factory": create_gridscan_callbacks,
},
"wait_for_robot_load_then_centre": {
"setup": wait_for_robot_load_then_centre_plan.create_devices,
"internal_param_type": WaitForRobotLoadThenCentreInternalParameters,
"internal_param_type": RobotLoadThenCentre,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I started in Hyperion, I found it confusing that we sometimes call it 'centring' and sometimes 'xray-centing' - I thought they were different things

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They sort of are. In this case centre means pin tip centre centre then xray centre. I think it's ok to basically assume "centre" means do the full centring. But I appreciate it's not obvious

src/hyperion/parameters/gridscan.py Show resolved Hide resolved
@d-perl d-perl marked this pull request as ready for review April 4, 2024 08:30
Copy link
Collaborator

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments, sorry. I think we are getting there though...

src/hyperion/parameters/components.py Show resolved Hide resolved
Comment on lines +69 to +74
class I03Constants:
BEAMLINE = "BL03S" if TEST_MODE else "BL03I"
INSERTION_PREFIX = "SR03S" if TEST_MODE else "SR03I"
BASE_DATA_DIR = "/tmp/dls/i03/data/" if TEST_MODE else "/dls/i03/data/"
DETECTOR = "EIGER2_X_16M"
SHUTTER_TIME_S = 0.06
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This point still stands I think, we can just use the object now rather than a string with a lookup? Appreciate we probably need them for now for the conversion to old params but can we write an issue to move to just the object then?

Comment on lines 215 to 240
@property
def normal_axis(self) -> XyzAxis:
"""The axis not used in the gridscan, e.g. Z for a scan in Y and X"""
return ({XyzAxis.X, XyzAxis.Y, XyzAxis.Z} ^ {self.axis_1, self.axis_2}).pop()

@property
def axis_1_start_um(self) -> float:
return self.axis_1.for_axis(self.x_start_um, self.y_start_um, self.z_start_um)

@property
def axis_2_start_um(self) -> float:
return self.axis_2.for_axis(self.x_start_um, self.y_start_um, self.z_start_um)

@property
def normal_axis_start(self) -> float:
return self.normal_axis.for_axis(
self.x_start_um, self.y_start_um, self.z_start_um
)

@property
def axis_1_end_um(self) -> float:
return self.axis_1_start_um + self.axis_1_step_size_um * self.axis_1_steps

@property
def axis_2_end_um(self) -> float:
return self.axis_2_start_um + self.axis_2_step_size_um * self.axis_2_steps
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: normal_axis isn't used, can we remove? I then also find the self.axis_2.for_axis thing a bit awkward to understand. Could we instead have the function on the XyzStarts?

class XyzStarts(BaseModel):
    x_start_um: float
    y_start_um: float
    z_start_um: float

    def _start_for_axis(self, axis: XyzAxis) -> float:
        match axis:
            case XyzAxis.X:
                return self.x_start_um
            case XyzAxis.Y:
                return self.y_start_um
            case XyzAxis.Z:
                return self.z_start_um

Then this becomes:

Suggested change
@property
def normal_axis(self) -> XyzAxis:
"""The axis not used in the gridscan, e.g. Z for a scan in Y and X"""
return ({XyzAxis.X, XyzAxis.Y, XyzAxis.Z} ^ {self.axis_1, self.axis_2}).pop()
@property
def axis_1_start_um(self) -> float:
return self.axis_1.for_axis(self.x_start_um, self.y_start_um, self.z_start_um)
@property
def axis_2_start_um(self) -> float:
return self.axis_2.for_axis(self.x_start_um, self.y_start_um, self.z_start_um)
@property
def normal_axis_start(self) -> float:
return self.normal_axis.for_axis(
self.x_start_um, self.y_start_um, self.z_start_um
)
@property
def axis_1_end_um(self) -> float:
return self.axis_1_start_um + self.axis_1_step_size_um * self.axis_1_steps
@property
def axis_2_end_um(self) -> float:
return self.axis_2_start_um + self.axis_2_step_size_um * self.axis_2_steps
@property
def axis_1_start_um(self) -> float:
return self._start_for_axis(self.axis_1)
@property
def axis_2_start_um(self) -> float:
return self._start_for_axis(self.axis_2)
@property
def axis_1_end_um(self) -> float:
return self.axis_1_start_um + self.axis_1_step_size_um * self.axis_1_steps
@property
def axis_2_end_um(self) -> float:
return self.axis_2_start_um + self.axis_2_step_size_um * self.axis_2_steps

You could even argue axis_1_start_um is then a bit of a redundant function and instead just use self._start_for_axis(self.axis_1) everywhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On discussion removed 2D grid scan params entirely, we will know what it should look like when we need to add it back

Comment on lines 269 to 270
omega_start_deg: float = Field(default=CONST.PARAM.GRIDSCAN.OMEGA_1) # type: ignore
omega2_start_deg: float = Field(default=CONST.PARAM.GRIDSCAN.OMEGA_2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: The start here kind of implies that omega is moving throughout the grid, which it isnt.

return ScanPath(self.scan_spec.calculate()).consume().midpoints


class ThreeDGridScan(SpecifiedGridScan, SplitScan):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: Can we add a docstring on what a 3D gridscan is, as it's not obvious. E.g. do a 2d grid, rotate in omega then do another grid

Comment on lines 319 to 342
def scan_1(self):
x_end = self.x_start_um + self.x_step_size_um * self.x_steps
y1_end = self.y_start_um + self.y_step_size_um * self.y_steps

scan_1_x = Line("sam_x", self.x_start_um, x_end, self.x_steps)
scan_1_omega = Line(
"omega", self.omega_start_deg, self.omega_start_deg, self.x_steps
)
scan_1_z = Line("sam_z", self.z_start_um, self.z_start_um, self.x_steps)
scan_1_y = Line("sam_y", self.y_start_um, y1_end, self.y_steps)
return scan_1_x.zip(scan_1_z).zip(scan_1_omega) * ~scan_1_y

@property
def scan_2(self):
x_end = self.x_start_um + self.x_step_size_um * self.x_steps
z2_end = self.z2_start_um + self.z_step_size_um * self.z_steps

scan_2_x = Line("sam_x", self.x_start_um, x_end, self.x_steps)
scan_2_omega = Line(
"omega", self.omega2_start_deg, self.omega2_start_deg, self.x_steps
)
scan_2_y = Line("sam_y", self.y2_start_um, self.y2_start_um, self.x_steps)
scan_2_z = Line("sam_z", self.z2_start_um, z2_end, self.z_steps)
return scan_2_x.zip(scan_2_y).zip(scan_2_omega) * ~scan_2_z
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: Can we change to grid_1/grid_2 rather than scan_1/scan_2?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: For the fixed things, rather than e.g. Line("sam_z", self.z_start_um, self.z_start_um, self.x_steps) I think we can just do Static("sam_z", self.z_start_um)? See https://dls-controls.github.io/scanspec/main/reference/api.html#scanspec.specs.Static. After that we should probably just run it past @coretl or @callumforrester to confirm it's the simplest it can be.


@property
def directory(self):
directory = str(self.visit_directory / "auto" / str(self.sample_id))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must: This certainly isn't right. From looking round on the file system it looks like some use sample name some use something else. We may have to provide the prefix as in http://agamemnon.diamond.ac.uk/example/collect for now then discuss with SIMS/Analysis how that is actually built.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just redefine it for UDC and say it is always the sample_id but we should shout a bit louder before we do that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take in the storage_directory as a param for now

omega_start_deg: float = Field(default=0) # type: ignore
rotation_axis: RotationAxis = Field(default=RotationAxis.OMEGA)
shutter_opening_time_s: float = Field(default=CONST.I03.SHUTTER_TIME_S)
rotation_angle_deg: float
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should: rotation_angle_deg wasn't immediately obvious to me when I looked at it. Could you add a docstring to say what it is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it to scan_width_deg

scan_spec = Line(
axis="omega",
start=self.omega_start_deg,
stop=(self.rotation_angle_deg + self.omega_start_deg),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The addition being the other way round makes more sense to me but whatever

@DominicOram
Copy link
Collaborator

Additionally, can we update https://github.com/DiamondLightSource/hyperion/wiki/Parameter-model a bit?

@d-perl d-perl force-pushed the 698_new_external_param_model branch from 1029fb8 to 3588167 Compare April 11, 2024 10:34
@d-perl d-perl requested a review from DominicOram April 12, 2024 08:57
Copy link
Collaborator

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Please update the docs at https://github.com/DiamondLightSource/hyperion/wiki/Parameter-model to something close to where we want to be with this and then happy to approve.

@d-perl
Copy link
Contributor Author

d-perl commented Apr 22, 2024

Copy link
Collaborator

@DominicOram DominicOram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good docs, ta!

@d-perl d-perl merged commit ab757d4 into main Apr 22, 2024
6 checks passed
@d-perl d-perl deleted the 698_new_external_param_model branch April 22, 2024 14:52
olliesilvester pushed a commit to olliesilvester/mx-bluesky that referenced this pull request Aug 23, 2024
…Source/698_new_external_param_model

New external parameter model
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

improve external parameters and make pydantic models for them
3 participants