Skip to content

Add MultiDeviceEmittance class#277

Open
shamin-slac wants to merge 34 commits intoslaclab:mainfrom
shamin-slac:multi
Open

Add MultiDeviceEmittance class#277
shamin-slac wants to merge 34 commits intoslaclab:mainfrom
shamin-slac:multi

Conversation

@shamin-slac
Copy link
Collaborator

@shamin-slac shamin-slac commented May 14, 2025

  • This pull request adds the MultiDeviceEmittance class, which will allow for emittance measurements with multiple profile monitors and/or wire scanners
    TODO:
  • Have modified compute_emit_bmag
  • Modify MultiDeviceEmittance class (and QuadScanEmittance class) to handle wirescan measurements
  • Create base emittance measurement class from which quad scan and multi device can subclass
  • Write test for multi device (wire) measurement
  • Subclass BeamProfileMeasurementResult for wire scan and profile monitor
  • Maybe add support for getting rmats for multi device class from meme
  • Modify docstrings and comments

@shamin-slac shamin-slac requested a review from roussel-ryan May 22, 2025 22:50
fit_result = self.beam_fit.fit_image(image)
rms_sizes.append(fit_result.rms_size)
centroids.append(fit_result.centroid)
rms_sizes.append(fit_result.rms_size * self.device.resolution) # units of microns
Copy link
Collaborator

Choose a reason for hiding this comment

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

I strongly prefer to work in pixels until working in physical units are necessary, but I'm open to additional opinions, it just limits the generality of the class

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For now, the profile monitor and wirescan measurements have to be handled separately, though eventually I'd like the emittance measurement to be mostly unaware of where it's getting beamsizes from. So I'd like the ScreenBeamProfileMeasurement result in microns to match the wirescan measurement, but I understand the generality of working in pixel units.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is there another use case you have in mind besides the emittance measurement?

self.magnet.scan(scan_settings=self.scan_values, function=self.measure_beamsize)

def measure_beamsize(self):
def _take_measurement(self, beamsize_measurement):
Copy link
Collaborator

Choose a reason for hiding this comment

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

this wrapper function seems like it could be merged into a measure_beamsize function in a more elegant way, additionally it should be public to enable flexibility, we can ponder this. One solution possibly is to all for the wire scan class to accept taking multiple measurements and rename n_measurement_shots since it isn't the right word

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah that's fair. Are you imagining retaking a measurement or something? Otherwise it's pretty internal to the class.

beam_sizes.append(
np.mean(result.rms_sizes, axis=0) * 1e-6
)
elif isinstance(result, WireBeamProfileMeasurementResult):
Copy link
Collaborator

Choose a reason for hiding this comment

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

is the code below something that belongs inside the wire beam profile measurement class / result?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's tricky. The wire scan measurement gives beam sizes for each of the loss monitors associated with that wire scanner. I'm not sure if it makes sense to average over the beam size values from all the loss monitors (certainly not now when they're still being commissioned)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

At the moment (and in the matlab code), the beam size value from one loss monitor is chosen for the emittance measurement. As for whether choosing the loss monitor belongs in the wire beam profile measurement class or the emittance measurement class, it's also unclear. I'd like the emittance specific details to be handled in the emittance measurement class. But also, this rms_sizes attribute is really meant for the emittance measurement class. Maybe that means these beam profile measurement classes need an rms_for_emittance attribute or something.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I could see the "default detector" being moved to the wire scan code in the future.

Without a GUI, a wire scan measurement doesn't really care about a default detector. When the GUI is built (and it's in progress), it would be nice to duplicate the current functionality and automatically display the "default detector" for each wire scanner.

It would be trivial to add this to the WireBeamProfileMeasurementResult class metadata and read the information from Shamin's new yaml file wire_lblms.

@roussel-ryan
Copy link
Collaborator

I merged in #263 so we will need to resolve the conflicts in the different emittance measurement classes, let me know if you'd like to take a stab at it or I can next week

@shamin-slac shamin-slac marked this pull request as ready for review November 10, 2025 18:33
Copy link
Collaborator

@roussel-ryan roussel-ryan left a comment

Choose a reason for hiding this comment

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

Looks pretty good to me. Mostly cosmetic suggestions. However, I would like to discuss with @eloise-nebula regarding the implementation of self.retrieve_beam_profiles_and_optics, self.calculate_emittance,self.construct_result

twiss_betas_alphas, 1, 2
) # make shape 2 x n_measurements x 2

self.emittance_dict = compute_emit_bmag(beamsizes_squared, rmats, twiss_lattice)
Copy link
Collaborator

Choose a reason for hiding this comment

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

when testing this, we should make sure that we test cases where beamsizes_squared contains Nan's, since we are assuming here that all measurements are included (even though some may have failed for one reason or another)

Object containing the results of the emittance measurement
"""

self.retrieve_beam_profiles_and_optics()
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we want these methods to return something to the user such that can be used outside the context of this class? It may make it more modular if these functions take arguments (ie. self.calculate_emittance takes in a list of measurement results and rmats?) I would look for guidance from @eloise-nebula on the best way to design this

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can discuss this further on Monday @eloise-nebula @shamin-slac

shamin-slac and others added 4 commits November 18, 2025 18:39
- Variables named like twiss_lattice reverted to twiss_design
- Slight fix to retrieve_beam_profiles_and_optics for multi to stop accumulation
@nneveu
Copy link
Member

nneveu commented Feb 9, 2026

Merge before tag

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.

4 participants