diff --git a/fibsem/configuration.py b/fibsem/configuration.py index 7969a072..d83a1d95 100644 --- a/fibsem/configuration.py +++ b/fibsem/configuration.py @@ -3,6 +3,132 @@ import os from fibsem.config import CONFIG_PATH, DEFAULT_CONFIGURATION_VALUES +# TODO: +# eucentric heights -> requires taking an image? +# reference rotation -> how to get this without having the user move to position? + +def system_fingerprint(ip_address: str = "192.168.0.1", manufactuer: str = "Thermo") -> dict: + """Automatically configure system based on microscope fingerprinting.""" + + # load default configuration + with open(os.path.join(CONFIG_PATH, "microscope-configuration.yaml"), "r") as f: + config = yaml.safe_load(f) + + if manufactuer != "Thermo": + raise ValueError("Only Thermo Fisher microscopes are currently supported for fingerprinting.") + + # ip, manufacturer + config["info"]["ip"] = ip_address # default ip (support pc -> microscope pc) + config["info"]["manufacturer"] = manufactuer # default manufacturer + + from fibsem.microscope import ThermoMicroscope + from fibsem.structures import SystemSettings, BeamSystemSettings, StageSystemSettings, FibsemDetectorSettings + + microscope = ThermoMicroscope() + microscope.connect_to_microscope(config["info"]["ip"]) + + # get name of system + system_name = microscope.connection.service.system.name + serial_number = microscope.connection.service.system.serial_number + config["info"]["name"] = f"{system_name}-{serial_number}-configuration" + + # stage + # enabled, compustage, rotation, tilt + stage_enabled = microscope.connection.specimen.stage.is_installed + compustage_enabled = microscope.connection.specimen.compustage.is_installed + config["stage"]["enabled"] = stage_enabled or compustage_enabled + config["stage"]["rotation"] = stage_enabled and not compustage_enabled + config["stage"]["tilt"] = stage_enabled or compustage_enabled + + # rotation reference, rotation_180 + if compustage_enabled: # TODO: check if this is accurate + config["stage"]["rotation_reference"] = 0 + config["stage"]["rotation_180"] = 0 + + # otherwise? I think need to get this manually? + # TODO: get the user to move the stage to this position? + # tilt = 0, rotation = same as when loading? + + # eucentric height map, [electron, ion] (otherwise we need to take an image to get this?) + eucentric_height_map = { + "Aquilios": [7e-3, 16.5e-3], + "Helios": [4e-3, 16.5e-3], + "Artcis": [4e-3, 16.5e-3], + "Scios": [4e-3, 10.0e-3] + } + + # check if any key in system_name + for model in eucentric_height_map: + if model in system_name: + system_model = model + + # electron beam + config["electron"]["enabled"] = microscope.connection.beams.electron_beam.is_installed + config["electron"]["column_tilt"] = get_column_tilt(config["info"]["manufacturer"], "electron") + config["electron"]["eucentric_height"] = eucentric_height_map[system_model][0] + + # ion beam + # is_installed, column tilt, eucentric_height (req taking image), plasma, plasma gas + config["ion"]["enabled"] = microscope.connection.beams.ion_beam.is_installed + config["ion"]["column_tilt"] = get_column_tilt(config["info"]["manufacturer"], "ion") + config["ion"]["eucentric_height"] = eucentric_height_map[system_model][1] + + # plasma enabled + ion_plasma_enabled = False + + if config["ion"]["enabled"]: + + try: + # throws an + ion_plasma_gas = microscope.connection.beams.ion_beam.source.plasma_gas.value + ion_plasma_enabled = True + print(f"Ion Plasma Available, Plasma Gas: {ion_plasma_gas}") + except Exception as e: + print(f"Exception: {e}") + ion_plasma_gas = "None" + ion_plasma_enabled = False + + config["ion"]["plasma"] = ion_plasma_enabled + config["ion"]["plasma_gas"] = ion_plasma_gas + + # manipulator + config["manipulator"]["enabled"] = microscope.connection.specimen.manipulator.is_installed + config["manipulator"]["rotation"] = False # always? + config["manipulator"]["tilt"] = False # always? + + # gis + gis_enabled = len(microscope.connection.gas.list_all_gis_ports()) + multichem_enabled = len(microscope.connection.gas.list_all_multichem_ports()) + sputter_coater_enabled = microscope.connection.specimen.sputter_coater.is_installed + + config["gis"]["enabled"] = bool(gis_enabled) + config["gis"]["multichem"] = bool(multichem_enabled) + config["gis"]["sputter_coater"] = sputter_coater_enabled + + print(f"""System Fingerprint: + Electron Beam: + Enabled: {config["electron"]["enabled"]} + Column Tilt: {config["electron"]["column_tilt"]} + Ion Beam: + Enabled: {config["ion"]["enabled"]} + Column Tilt: {config["ion"]["column_tilt"]} + Plasma: {config["ion"]["plasma"]} + Plasma Gas: {config["ion"]["plasma_gas"]} + Stage: + Enabled: {config["stage"]["enabled"]} + Rotation: {config["stage"]["rotation"]} + Tilt: {config["stage"]["tilt"]} + Rotation Reference: {config["stage"]["rotation_reference"]} + Rotation 180: {config["stage"]["rotation_180"]} + Manipulator: + Enabled: {config["manipulator"]["enabled"]} + GIS: + Enabled: {config["gis"]["enabled"]} + Multichem: {config["gis"]["multichem"]} + Sputter Coater: {config["gis"]["sputter_coater"]} + """) + + return config def get_column_tilt(manufacturer: str, beam: str) -> int: diff --git a/fibsem/microscope.py b/fibsem/microscope.py index 61055768..bed084ce 100644 --- a/fibsem/microscope.py +++ b/fibsem/microscope.py @@ -764,7 +764,10 @@ def __init__(self, system_settings: SystemSettings = None): self.experiment = FibsemExperiment() # logging - logging.debug({"msg": "create_microscope_client", "system_settings": system_settings.to_dict()}) + if system_settings is not None: + system_settings = system_settings.to_dict() + logging.debug({"msg": "create_microscope_client", "system_settings": system_settings}) + def reconnect(self): if not hasattr(self, "system"): @@ -808,18 +811,20 @@ def connect_to_microscope(self, ip_address: str, port: int = 7520) -> None: logging.info(f"Microscope client connected to [{ip_address}:{port}]") # system information - self.system.info.model = self.connection.service.system.name - self.system.info.serial_number = self.connection.service.system.serial_number - self.system.info.hardware_version = self.connection.service.system.version - self.system.info.software_version = self.connection.service.autoscript.client.version - info = self.system.info - logging.info(f"Microscope client connected to model {info.model} with serial number {info.serial_number} and software version {info.software_version}.") + if self.system is not None: + self.system.info.model = self.connection.service.system.name + self.system.info.serial_number = self.connection.service.system.serial_number + self.system.info.hardware_version = self.connection.service.system.version + self.system.info.software_version = self.connection.service.autoscript.client.version + info = self.system.info + logging.info(f"Microscope client connected to model {info.model} with serial number {info.serial_number} and software version {info.software_version}.") # autoscript information logging.info(f"Autoscript Client: {self.connection.service.autoscript.client.version}") logging.info(f"Autoscript Server: {self.connection.service.autoscript.server.version}") - self.reset_beam_shifts() + if self.system is not None: # tmp + self.reset_beam_shifts() def acquire_image(self, image_settings:ImageSettings) -> FibsemImage: """