slaclab / lcls-tools

Python tools for LCLS: post processing data, PV handling, pulling archive settings, etc.
Apache License 2.0
2 stars 21 forks source link

create measurement class and io function #129

Closed roussel-ryan closed 7 months ago

roussel-ryan commented 8 months ago

Adds abstract classes for file io, measurements

roussel-ryan commented 8 months ago

lcls_tools_objects

roussel-ryan commented 8 months ago

An example of how a basic image diagnostic would work:

class ScreenBeamProfile(Measurement):
    name = "beam_profile"
    device: Screen
    image_processer: Any
    fitting_tool: FittingTool
    fit_profile: bool = True

    n_shots: int = 5
    charge_window: Optional[ChargeWindow] = None

    def measure(self) -> dict:
        images = []
        while len(images) < self.n_shots:
            measurement = self.single_measure()
            if len(measurement):
                images += [self.single_measure()]

        # fit profile if requested
        if self.fit_profile:
            results = []
            for ele in images:
                results += [self.fitting_tool.fit_image(ele["processed_image"])]

            # combine images with profile info
            final_results = {}
        else:
            # concat list elements into a single dict
            final_results = {}

        if self.save_data:
            self.dump_controller.dump_data_to_file(final_results, self)

        return final_results

    def single_measure(self) -> dict:
        # measure profiles
        # get raw data
        raw_image = self.device.image

        # get ICT measurements and return None if not in window
        if self.charge_window is not None:
            if not self.charge_window.in_window():
                return {}

        processed_image = self.image_processer.process(raw_image)
        return {"raw_image": raw_image, "processed_image": processed_image}
roussel-ryan commented 8 months ago

Keep in mind that the scope of this PR is specific to constructing the overall framework (abstract classes) and changes can be easily made to the implementations of specific functions. Any implementations shown here are just examples to understand how the classes interact with one another

nneveu commented 8 months ago

Let's use NotImplemented instead of pass. I think it's fine to have this as a framework, but if there are things we know need to add, I'd prefer to take the extra time to do it now. That way it stands as a better example. I can commit some of the changes.

roussel-ryan commented 8 months ago

Let's use NotImplemented instead of pass. I think it's fine to have this as a framework, but if there are things we know need to add, I'd prefer to take the extra time to do it now. That way it stands as a better example. I can commit some of the changes.

Ok thats fine if you want to mostly finish the ICT measurement example, I'm holding off on adding device specific code (ie. screen code, @phys-cgarnier's projection fitting code) until this PR is merged.

roussel-ryan commented 8 months ago

I decided against specifying a separate multi-shot wrapper class since each type of measurement might have different ways of effectively measuring and calculating statistics

nneveu commented 7 months ago

Note, will add an issue to update yaml files to have a real ICT example.