Skip to content

Conversation

@fajinyuan
Copy link
Contributor

Fixes #1568

Instructions to reviewer on how to test:

  1. added additional motors for each crystal
  2. waiting for missing PVs in EPICS IOC for i16 DCM

Checks for reviewer

  • Would the PR title make sense to a scientist on a set of release notes
  • If a new device has been added does it follow the standards
  • If changing the API for a pre-existing device, ensure that any beamlines using this device have updated their Bluesky plans accordingly
  • Have the connection tests for the relevant beamline(s) been run via dodal connect ${BEAMLINE}

@fajinyuan fajinyuan requested a review from a team as a code owner September 25, 2025 14:50
@fajinyuan fajinyuan linked an issue Sep 25, 2025 that may be closed by this pull request
@fajinyuan fajinyuan self-assigned this Sep 25, 2025
@fajinyuan
Copy link
Contributor Author

waiting for https://jira.diamond.ac.uk/browse/I16-960 to pass 'dodal connect i16' test

@codecov
Copy link

codecov bot commented Sep 25, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.80%. Comparing base (2585faf) to head (6eedc1d).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1580      +/-   ##
==========================================
- Coverage   98.82%   98.80%   -0.03%     
==========================================
  Files         250      262      +12     
  Lines        8992     9501     +509     
==========================================
+ Hits         8886     9387     +501     
- Misses        106      114       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@DominicOram
Copy link
Contributor

Big fan of pushing for standardisation on the controls side. See #592 where we went through this look for i22/i03

Copy link
Contributor

@oliwenmandiamond oliwenmandiamond left a comment

Choose a reason for hiding this comment

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

This is very similar to I22 DCM with some slight differences. That class also doesn't have tests associated with it and uses the same method of overriding the read and describe methods.

As we are waiting on controls to standardise the PV's, I am inclined to approve of this so it's not held in limbo. I do however think once more beamlines have created more custom DCM's, we re-evaluate this in near future so that:

  1. We can create another class that can form a base for more beamline DCMs to eliminate more duplicate code.
  2. We add some tests if they have to override the read and describe methods with custom logic

Until all the beamlines DCM's are added, I don't think it is worth doing yet until we have a clear picture of what all the beamline requirements are. I will make an issue to track this.

Copy link
Contributor

@oliwenmandiamond oliwenmandiamond left a comment

Choose a reason for hiding this comment

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

I22 do have tests for their DCM device. Please add some tests for I16 DCM device and then we create a new issue to consolidate the two devices (+ any others) in future once all DCM's are added and know all beamline requirements.

@oliwenmandiamond oliwenmandiamond changed the title add suprot for i16 DCM - there are PVs still missing in EPICS add support for i16 DCM - there are PVs still missing in EPICS Sep 30, 2025
Comment on lines 99 to 125
async def describe(self) -> dict[str, DataKey]:
default_describe = await super().describe()
return {
f"{self.name}-wavelength_in_a": DataKey(
dtype="number",
shape=[],
source=self.name,
units="angstrom",
),
**default_describe,
}

async def read(self) -> dict[str, Reading]:
default_reading = await super().read()
energy: float = default_reading[f"{self.name}-energy_in_kev"]["value"]
if energy > 0.0:
wavelength = _CONVERSION_CONSTANT / energy
else:
wavelength = 0.0

return {
**default_reading,
f"{self.name}-wavelength_in_a": Reading(
value=wavelength,
timestamp=time.time(),
),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should: I think this is the perfect place for derived signal.
This probably overcome the issue they discussing here

Then you only need to add it as readable

Something like this:

inside  __init__
        with self.add_children_as_readables():
            self.wavelength = derived_signal_r(
                raw_to_derived=self._read_wavelength,
                derived_units="angstrom",
                energy=self.energy_in_kev,
        )

def _read_wavelength(self, energy: float) -> float:
        if energy > 0.0:
            wavelength = _CONVERSION_CONSTANT / energy
        else:
            wavelength = 0.0

        return wavelength

Copy link
Contributor

@Relm-Arrowny Relm-Arrowny Sep 30, 2025

Choose a reason for hiding this comment

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

Must: Add test for read.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just saw #1584 may be it should be in the base class?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes agreed, I think there needs to be a different approach to this for I16 and I22 to get this to work

Copy link
Contributor Author

@fajinyuan fajinyuan Oct 2, 2025

Choose a reason for hiding this comment

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

why we do the energy to wavelength conversion here, not just simply use EPICS wavelength PV ?

Copy link
Contributor

@oliwenmandiamond oliwenmandiamond Oct 2, 2025

Choose a reason for hiding this comment

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

Some reading on bluesky verbs for read and describe. https://blueskyproject.io/bluesky/main/hardware.html

They are called at every point in a scan. read returns the data to record and save. describe tells us about the type, shape, PV used, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your comments @oliwenmandiamond and @Relm-Arrowny @DominicOram. It looked I choose a wrong dcm.py from i22 to use for i16 then.
I will remove describe and read method from i16/dcm.py, and use derived signal instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry @Relm-Arrowny I just realised the wavelength is already in BaseDCM, why I need to redo it using derived signal here, could you explain this to me please?

Copy link
Contributor

@oliwenmandiamond oliwenmandiamond Oct 3, 2025

Choose a reason for hiding this comment

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

#1598 should help fix this as you will have two options on which class to inherit from for DCM. One of them won't include wavelength, so you can define it yourself as a derived signal then.

Copy link
Contributor

Choose a reason for hiding this comment

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

sorry @Relm-Arrowny I just realised the wavelength is already in BaseDCM, why I need to redo it using derived signal here, could you explain this to me please?

The only reason I suggested it is because I saw the conversion from energy, if they already exit then you can ignore me and you should not need to modify read or describe.

@DG-At-Diamond
Copy link
Contributor

The last I remember of this issue was we discovered that the 'DCM' on i16 was actually a CCM that had originally been designed as a DCM. It would still in theory be usable as a DCM if the crystals were replaced but this is not done in practice. We were going to discuss the requirements with the beamline but probably implement it as a CCM when we are ready to implement that. Can anyone confirm this is still as far as the conversation got @fajinyuan @oliwenmandiamond? If so it might be worth closing this request without merging it.

@fajinyuan
Copy link
Contributor Author

Please implement the CCM, instead of DCM. Also please update the ticket replacing DCM with CCM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add DCM device for i16

6 participants