CustomFunction: Difference between revisions

From SweepMe! Wiki
Jump to navigation Jump to search
Line 28: Line 28:
* return values with the 'main' function according to the lenghth of '''variables''' and '''units'''.
* return values with the 'main' function according to the lenghth of '''variables''' and '''units'''.


This is a minimal working example:
This is a minimal working example (new style):
{{syntaxhighlight|lang=python|code=
{{syntaxhighlight|lang=python|code=
class Main():
class Main():
Line 45: Line 45:


         print(kwargs)  # Now you can dow some processing with the arguments. kwargs is a dictionary containing the value for each argument name.
         print(kwargs)  # Now you can dow some processing with the arguments. kwargs is a dictionary containing the value for each argument name.
        var1 = 0
        var2 = "another text"
        return variable1, variable2  # make sure you return an as many values as you have defined variables
}}
This is a minimal working example of the old style to define arguments:
{{syntaxhighlight|lang=python|code=
class Main():
    """ here you can add some description of your script by using html.
    This description will be shown in the description box of the CustomFunction module
    """
    variables = ["Variable1", "Variable2"]  # add as many return variables as you like as strings
    units = ["unit1", "unit2"]  # add units as strings in the same number as you have defined variables
    arguments = {"Argument 1": "some text",  # a string
                "Argument 2": 42,  # an integer
                "Argument 3": 3.14,  # a float
        }
    def main(self, argument1="some text", argument2=42, argument3=3.14)
        print("Arguments:", argument1, argument2, argument3)


         var1 = 0
         var1 = 0

Revision as of 13:22, 30 September 2022

version: 2022-08-17 or later

The CustomFunction module is designed to allow users to run their own python functions. The main purpose is to hand over measurement data from multiple modules to a function which takes care about calculating further parameters and about data processing. It can be used for many different purposes and is one basic opportunity to run individual python code.

The position of the CustomFunction module in the Sequencer is essential. It determines the amount of data that is handed over to the CustomFunction function.

A simplified rule is: Whenever a function of the CustomFunction module is called, all values generated since the last call of this function are handed over.

Adding a new function

  1. Add a CustomFunction module to the sequencer
  2. Go to the tab of the CustomFunction module
  3. Press "Copy selected function" and enter the name of the new function, it will be a copy of the example function.
  4. You can modify your new function using 'Open/Modify'
  5. Your new function can be found in the public folder '.\DataModules\CustomFunction\Functions'. This folder can also be found by using the button "Open folder".
  6. Edit the arguments of the function 'main' to add or remove further GUI items that are displayed to the user.
  7. Change the lists 'variables' and 'units' and return the corresponding values at the end of the function 'main'.
  8. Use the button 'Reload' to refresh the CustomFunction module after you did changed to your function.

Creating a function

A CustomFunction script is basically a python file that must contain a class 'Main' with a function 'main'. The arguments of the function 'main' automatically define the user interface that is shown to the user inside the CustomFunction module. When modifying a function, the following points are important:

  • variables: set a list of strings defining the names of your returned values
  • units: set a list of strings defining the names of the units corresponding to variables
  • variables and units need to have the same length as the number of returned values of your function 'main'
  • Arguments/Input parameters: Define the names and the types of the input parameters according to the Function 'Example'. Basically, the arguments of the function 'main' automatically define the user interface fields that are shown in the CustomFunction module.
  • return values with the 'main' function according to the lenghth of variables and units.

This is a minimal working example (new style):

class Main():
    """ here you can add some description of your script by using html. 
    This description will be shown in the description box of the CustomFunction module 
    """

    variables = ["Variable1", "Variable2"]  # add as many return variables as you like as strings
    units = ["unit1", "unit2"]  # add units as strings in the same number as you have defined variables
    arguments = {"Argument 1": "some text",  # a string
                 "Argument 2": 42,  # an integer
                 "Argument 3": 3.14,  # a float
        }

    def main(self, **kwargs)

         print(kwargs)  # Now you can dow some processing with the arguments. kwargs is a dictionary containing the value for each argument name.

         var1 = 0
         var2 = "another text"
         return variable1, variable2  # make sure you return an as many values as you have defined variables


This is a minimal working example of the old style to define arguments:

class Main():
    """ here you can add some description of your script by using html. 
    This description will be shown in the description box of the CustomFunction module 
    """

    variables = ["Variable1", "Variable2"]  # add as many return variables as you like as strings
    units = ["unit1", "unit2"]  # add units as strings in the same number as you have defined variables
    arguments = {"Argument 1": "some text",  # a string
                 "Argument 2": 42,  # an integer
                 "Argument 3": 3.14,  # a float
        }

    def main(self, argument1="some text", argument2=42, argument3=3.14)

         print("Arguments:", argument1, argument2, argument3)

         var1 = 0
         var2 = "another text"
         return variable1, variable2  # make sure you return an as many values as you have defined variables


Don't forget to use the 'Reload' button to update changes.

Arguments/Input parameters

  • Data from SweepMe!: tuple -> () Please note: data is always handed over as numpy array, independent whether is is just a single value or a list. Please make sure you process the data correctly before you return it.
  • Integer: int -> any integer number which will be the preset value
  • Float: float -> any float value which will be the preset value
  • String: str -> any string which will be the preset value
  • List: list -> any list of strings which will be presented in ComboBox for selection by the user
  • Bool: bool -> set to True or False; the user can later select using a CheckBox
  • Directory: pathlib.Path(<directory>) -> an empty pathlib.Path object or a non-empty pathlib.Path object with a given directory <directory>. The user will see a QFileDialog to choose a folder.
  • File: pathlib.Path(<file>) -> a non-empty pathlib.Path object with a given file <file>. The user will see a QFileDialog to choose a file.

Procedure

Whenever CustomFunction is part of an iteration in a branch of the sequencer, the defined function 'main' is called with the given parameters and the defined variables must be returned. SweepMe! measurement values that are requested by using a tuple () as argument are automatically handed over as an array of the values that have been acquired since the last call CustomFunction. For example to get a single number from this array, one can take the item at the first index, e.g 'val[0]' assuming that 'val' is the list that has been handed over. Please also take about care changing to the correct type beforehand.

Function calls

main

The function 'main' that defines the arguments and returns the variables, is called in process of the Sequencer procedure.

prepare_run / prepare_stop

You can add prepare_run and prepare_stop to your script. These functions have no arguments and return no values. They are called before and after the measurement inside the GUI thread.

initialize / deinitialize

You can add initialize and deinitialize to your script. These functions have no arguments and return no values. They are called according to the Sequencer procedure at the start and at the end of the run, respectively.

configure / unconfigure

You can add configure and unconfigure to your script. These functions have no arguments and return no values. They are called according to the Sequencer procedure when the module is in the new branch or not anymore in the next branch, respectively.

signin / signout

You can add signin and signout to your script. These functions have no arguments and return no values. They are called according to the Sequencer procedure when a new setvalue in a module above your CustomFunction module is started or finished.

Handling arguments

Arguments that can be set by the user are automatically defined by the function 'main' whose arguments are used to create the user interface.

As an alternative, one can set the arguments also with a static variable 'arguments' that must be a dictionary having the argument names as keys and the default values as values. This allows to dynamically change the number of arguments when loading the custom function. To handover the arguments to the 'main' function use

def main(self, **kwargs):
   print(kwargs)  # this will print out the dictionary that contains the keyword-word argument names as keys and the user selection as values.

The arguments are according to the one defined in the static variable "arguments". One advantage of this handling is that also arguments with spaces can be used that are more user-friendly names.

If you need to know the arguments very early at the beginning before the 'main' function is called, you can used the variable 'self.main_arguments' that is handed over to the class instance of the script during "initialize"

def initialize(self):
   print(self.main_arguments)  # prints the dictionary with the argument names being the keys and the values being the user selection

GUI mode

Creating GUI widgets, e.g. by using PySide2 package, leads to a program crash as CustomFunction is running in the measurement thread of SweepMe! while GUI widgets must run in the main GUI thread of the program. For that reason, CustomFunction provides a GUI mode that can be enabled by using the function 'renew_widget' that takes care about exchanging Qwidget objects with the CustomFunction module. The function must be defined in class 'Main'. Please, use the function 'Example_GUI' to see how to use it.

def renew_widget(self, widget = None):
    """ gets the widget from the module and returns the same widget or creates a new one"""
    
    if widget is None:
        # if the widget has not been created so far, we create it now and store it as self.widget
        self.widget = Widget()
    else:
        # the second time a run is started, we can use the widget, that is handed over to renwe_widget, to store is as self.widget
        self.widget = widget
            
    # return the actual widget to inform the module which one has to be inserted into the DockWidget of the Dashboard    
    return self.widget

As shown in the code snippet above, 'renew_widget' expects an argument 'widget' that is None at the very first call. Thus, one has to create a new QWidget-type object called here 'Widget()' that is set to 'self.widget' and returned at the end of the function. The second time 'renew_widget' is called, e.g. when a measurement is started again, the module CustomFunction hands over the last known Qwidget to 'renew_widget' and the widget can be set to 'self.widget' in order to make it available to other function of the class 'Main'.

Qwidget objects that are returned by 'renew_widget' are automatically placed into a QDockWidget that can be placed by the user into the dashboard. 'renew_widget' is called before every measurement and whenever the selected function is changed. Thus, it is also possible to store the layout of the dock widget to the setting. However, values that are entered in such custom widgets are not automatically saved to the setting file.

Importing packages

Importing external python packages that are not shipped with SweepMe! just works like for Driver Programming. You can find a guide here External libraries and dependencies.

Applications

  • Data smoothing
  • Repetitive curve fitting and extraction of fit parameters
  • Parameter extraction
  • Specializing a measurement setup to certain needs
  • pre-evaluation of the data
  • using SweepMe! as a frontend for simulations
  • Control loops, e.g. a PID controller
  • creating output GUI widgets to display data
  • creating input GUI widgets to let the user change a parameter
  • Manipulating or Copying data files after a run

Examples

  • Characteriztion of field-effect transistors: Transfer characteristics are measured in the linear regime. Current and voltage measurement data is handed over to the Evaluation module where charge carrier mobility and threshold voltage is extracted.
  • Characterization of LEDs: Spectra and current-voltage characteristics can be handed over to the Evaluation module to calculate several device efficiency parameters.
  • Calculation of peak values, zeroing, derivation, integral, mean, standard deviation, ...
  • Creating a custom GUI widgets including a number of slider and input fields to control a certain process.
  • Displaying several values in human-machine-interface (HMI) like way.