From 09956a970a3eb13137a0e1563fb7a56d145f10c8 Mon Sep 17 00:00:00 2001 From: Christoph Schmidt <christoph.,schmidt@tugraz.at> Date: Wed, 24 Jan 2024 17:01:49 +0100 Subject: [PATCH] Measurement Routine moved to examples. Now measureme and updated the README.md --- README.md | 52 +++++++++++++++++-- examples/MeasurementRoutine.py | 20 +++---- examples/main.py | 28 +++++----- .../controller/MainThreadController.py | 23 ++++---- .../BaseMeasurementRoutine.py | 5 +- 5 files changed, 84 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index eede008..e4b4e33 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,52 @@ To start the software, simply run the `examples/main.py` file. python main.py ``` -# Measuring using Flexsensor +# Defining a measurement routine +The measurement routine is defined in a python file. Each measurement routine must inherit from the `BaseMeasurementRoutine` class. +Note that the base class has an overloaded constructor that requires the following parameters: +- `prober`: The Prober.Controller object that is used to measure the structures +- `config`: The FlexSensorConfig object that is used to measure the structures +```python +import FlexSensor as fs + +class MeasurementRoutine(fs.BaseMeasurementRoutine): + + def __init__(prober: Prober.Controller, + config: fs.FlexSensorConfig): + super().__init__(prober, config) + + @Slot() + def run(self): + # your code here +``` +In the `run` method, the measurement routine is defined. +The `run` method is called by the `MeasurementRoutineThread` class, which is a QThread object. This allows to run the method +in a separate thread, while the GUI remains responsive. + + + +# Measuring using FlexSensor +It is often useful to measure a large number of structures on a wafer. For this, the software allows to define a +measurement routine that is executed for each structure. +The `vas`-File allows to define a list of structures that are measured. Thede file is parsed and passed +to the `MeasurementRoutine` class. +```python +import FlexSensor as fs +# ... +def readVasFile(self): + self.parsed_file = fs.VASInputFileParser() + + selected_file, self.grouped_structures, self.bookmarks = self.parsed_file.read_file( + input_file='structure_file.vas' + ) +# ... +``` +The `VASInputFileParser` class parses the `vas`-File and returns a list of structures that are measured. +- `selected_file`: The selected file. In case the file is not found, the user is prompted to select a file by a file dialog. +- `grouped_structures`: A list of structures that are measured. Each structure is a python dictionary that contains the + information on how to measure the structure. +- `bookmarks`: A list of bookmarks that are defined in the `vas`-File. These bookmarks are used to create a Klayout + bookmark file that can be used to navigate to the structures in Klayout. ## Input Structure File The measuring process relies on a ```vas```-File that store the positions to the structures. in priciple this file os a list of python dictionary in a predefined format, that allows the easy definiton @@ -69,7 +114,7 @@ Sometimes it is useful to define a group of measurement points that are equally mrr1 = {'y_in' : -1845, 'x_in' : 960, 'y_out' : -2015, 'x_out' : -155, 'num' : 6, 'spacing' : 100, 'repetitons': 200} ``` -## Setup bevore measuring +## Setup before measuring 1. Open the correct wafer map. Open the wafer Map under **Velox** -> **WaferMap**. Load the correct wafer file and select or deselect dies you do not want to capture. @@ -91,13 +136,12 @@ Set our fiber to the correct height. Then use the "Set Contact height". Otherwis This step is crucial and needed to train the output positions. -# Lincence and usage +# Licence and usage This software is licenced under the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.de.html). If you use this software for your work or in your papers please cite me the following: - # FAQ&Issues This section should cover the issues that may occure during usage or development. ## Installation issues and running diff --git a/examples/MeasurementRoutine.py b/examples/MeasurementRoutine.py index 20b693e..2b07886 100644 --- a/examples/MeasurementRoutine.py +++ b/examples/MeasurementRoutine.py @@ -23,22 +23,18 @@ from Properties.WaferProperties import WaferProperties sys.path.append('./src') -# from FlexSensor.FlexSensorConfig import FlexSensorConfig -# from FlexSensor.MeasurementData.MeasuredData.SingleMeasuredData import SingleMeasuredData -# from FlexSensor.MeasurementData.Properties.AD2CaptDeviceProperties import AD2CaptDeviceProperties -# from FlexSensor.MeasurementData.Properties.LaserProperties import LaserProperties -# from FlexSensor.MeasurementData.Properties.MeasurementProperties import MPropertiesFindPeaks, \ -# MeasurementProperties, WaveguidePropertiesMZI -# from FlexSensor.MeasurementData.Properties.WaferProperties import WaferProperties -# from FlexSensor.MeasurementRoutines.BasemeasurementRoutine import BaseMeasurementRoutine -# from FlexSensor.generics.VASInputFileParser import VASInputFileParser, Structure - class MeasurementRoutine(fs.BaseMeasurementRoutine): - def __init__(self, laser: Laser, ad2device: AD2Dev, prober: Prober.Controller, + def __init__(self, + laser: Laser, + ad2device: AD2Dev, + prober: Prober.Controller, config: fs.FlexSensorConfig): - super().__init__(laser, ad2device, prober, config) + super().__init__(prober, config) + + self.ad2device: AD2Dev = ad2device + self.laser: Laser.Controller = laser self.logger = logging.getLogger("Measurement Routine") # The signals for connecting to the UI diff --git a/examples/main.py b/examples/main.py index fc13428..a16b125 100644 --- a/examples/main.py +++ b/examples/main.py @@ -12,12 +12,14 @@ from PySide6.QtWidgets import QApplication # set env variable VELOX_SIM=TRUE # to use the simulator instead of the real hardware import os + os.environ["VELOX_SIM"] = "TRUE" sys.path.append('./src') from MeasurementRoutine import MeasurementRoutine import FlexSensor + def main(argv): FlexSensor.ApplicationInit.setup_logging() logging.info(f"Starting Velox GUI Version {FlexSensor.__version__}") @@ -28,32 +30,32 @@ def main(argv): # Disable loggers that are not needed (e. g. numpy, etc) cw = FlexSensor.ConsoleWindow(app) - #cw.show() + # cw.show() - #FlexSensor.ApplicationInit.setup_logging(cw) + # FlexSensor.ApplicationInit.setup_logging(cw) FlexSensor.ApplicationInit.set_icon(app) # Read the inital config file - config = FlexSensor.ApplicationInit.load_config_file(f"{FlexSensor.configs_root}/init_config.yaml") config.autosave(enable=True, path="autosave_configs/init_config.yaml") - + # Start the main application main_model = FlexSensor.MainThreadModel(config=config) - #wdg = config.view.widget() - #wdg.show() - main_controller = FlexSensor.MainThreadController(main_model, MeasurementRoutine) + main_controller = FlexSensor.MainThreadController(main_model) + # Register your measurement routine here + main_controller.load_measurement_routine(MeasurementRoutine, + ad2device=main_model.ad2_controller, + laser=main_model.laser_controller, + ) main_window = FlexSensor.MainWindow(main_model, main_controller) - # test_win = StructureSelector() - #config.save(f"{FlexSensor.configs_root}/init_config.yaml") + + + main_window.show() splash_screen.finish(main_window) - sys.exit(app.exec()) -if __name__ == "__main__": +if __name__ == "__main__": main(sys.argv) - - diff --git a/src/FlexSensor/MainWindow/controller/MainThreadController.py b/src/FlexSensor/MainWindow/controller/MainThreadController.py index 97b2adb..910383c 100644 --- a/src/FlexSensor/MainWindow/controller/MainThreadController.py +++ b/src/FlexSensor/MainWindow/controller/MainThreadController.py @@ -18,7 +18,6 @@ class MainThreadController(FSBase, object): on_start_laser_sweep = Signal(name='on_start_laser_sweep') def __init__(self, model: MainThreadModel, - measurement_routine: Type[BaseMeasurementRoutine], enable_log: bool = True, log_level: int = logging.DEBUG, log_file: str = "flexsensor.log"): super().__init__() @@ -57,7 +56,7 @@ class MainThreadController(FSBase, object): self._device_initialization() # Load the measurement routine - self.model.measurement_routine = self._load_measurement_routine(measurement_routine) + #self.model.measurement_routine = self._load_measurement_routine(measurement_routine) # Thread for the measurement routine self.measurement_thread = QThread() @@ -105,7 +104,7 @@ class MainThreadController(FSBase, object): self.measurement_thread.started.connect(measurement_routine.run) self.logger.debug("Moved worker/measurement routine to thread and connected the signals.") - def _load_measurement_routine(self, measurement_routine: Type[BaseMeasurementRoutine]) -> BaseMeasurementRoutine: + def load_measurement_routine(self, measurement_routine: Type[BaseMeasurementRoutine], *args, **kwargs) -> BaseMeasurementRoutine: """ Loads the measurement routine and initializes it. @@ -115,16 +114,16 @@ class MainThreadController(FSBase, object): Raises: Exception: If some or all devices have not been initialized. """ - # if not self.device_are_init: - # raise Exception("Some or all devices have not been initialized. First call `_device_initialization()`!") - - _measurement_routine = measurement_routine( - self.model.laser_controller, - self.model.ad2_controller, - self.model.prober_controller, - self.model.config) + self.model.measurement_routine = measurement_routine( + prober=self.model.prober_controller, + config=self.model.config, + *args, **kwargs) + # laser=self.model.laser_controller, + # ad2device=self.model.ad2_controller, + # prober=self.model.prober_controller, + # config=self.model.config) self.logger.debug("Initialized MeasurementRoutine.") - return _measurement_routine + #return _measurement_routine def _device_initialization(self): """ diff --git a/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py b/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py index 8d96026..bbaf795 100644 --- a/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py +++ b/src/FlexSensor/MeasurementRoutines/BaseMeasurementRoutine.py @@ -19,13 +19,12 @@ from FlexSensor.MeasurementRoutines.WorkerSignals import WorkerSignals class BaseMeasurementRoutine(QObject, FSBase): - def __init__(self, laser: Laser.Controller, ad2device: CaptDevice.Controller, prober: ProberController, config: FlexSensorConfig): + def __init__(self, prober: ProberController, config: FlexSensorConfig, *args, **kwargs): super().__init__() self.logger = self.create_new_logger(self.name) self.config = config - self.ad2device: CaptDevice.Controller = ad2device - self.laser: Laser.Controller = laser + self.prober: ProberController = prober self.logger.debug(f"{self.prober.report_kernel_version()}") print(self.prober) -- GitLab