Project

General

Profile

Creating a new Leginon node » History » Version 25

Anchi Cheng, 08/04/2020 02:26 PM

1 1 Jim Pulokas
h1. Creating a new Leginon node
2
3
The basic steps that will be described in detail below are:
4
5 6 Anchi Cheng
* Code the core functionality in a new subclass
6
* Define required attribute for all node classes:
7
** Node Settings and its defaults
8
** GUI Panel
9
** Input/Output Events
10
* Define new data type or event this node produces
11
* Make the gui
12 1 Jim Pulokas
* register it with the list of available nodes
13
14 5 Jim Pulokas
For each task, it is easiest to look at an existing node as an example.  Usually we just make a copy of a node the is similar in function and go from there.
15 1 Jim Pulokas
16 16 Anchi Cheng
Two examples are provided here:
17 1 Jim Pulokas
18 16 Anchi Cheng
# Buffer Cycle as a condition fixer
19
# Matlab targetfinder
20
21
h2. Example 1: Buffer Cycling
22
23 6 Anchi Cheng
We have a base class in Leginon that creates a node to fix a particular instrument condition.  The module is leginon/condition.py.  When a FixConditionEvent is sent to it, it will check the database to find whether the condition fixing has been done recently.  If it has past the timeout defined in its settings (Defined by ConditionerSettingsData in leginondata.py), then it will execute the action defined in its fixCondition function, and reset the timer.
24 5 Jim Pulokas
25 6 Anchi Cheng
The FixConditionEvent is sent normally from the final exposure Acquisition Node (named "Exposure", "Tomography" etc. depending on the node class and application".  While the condition is being fixed, the node will wait for it to return before starting to process the targets it received (meaning moving to the acquisition position, focusing, etc).
26
27
To make a new subclass that triggers the vacuum pump that pumps the buffer area of the scope, we will make a subclass of Conditioner here, called BufferCycler.  There is no settings change, but we want its settings saved separately from the parent.
28
29 1 Jim Pulokas
h2. Code the core functionality
30
31 6 Anchi Cheng
* Make a new class in your new module.  Let it inherit a class of Leginon nodes.  The lowest base class you can use is node.Node
32 1 Jim Pulokas
33 25 Anchi Cheng
In our example, see leginon/buffercycler.py https://emg.nysbc.org/projects/leginon/repository/revisions/trunk/entry/leginon/buffercycler.py
34 6 Anchi Cheng
35
The new class inherits conditioner.Conditioner.  It defines the string for condition type in setCTypes, and how to call buffer cycling.
36
37 8 Anchi Cheng
h2.  Define the required attributes for all nodes
38 6 Anchi Cheng
39
h3. Settings
40
41
* The data class that is usually added when a new node is added is the one defines its settings in Leginon gui.  Its name should have the class name as prefix.
42
* To make the class uses the new settings class, it is defined in the module.
43
44 9 Anchi Cheng
In our example:
45
46
# Look at the difference in leginon/leginondata.py for r18567, a new subclass of ConditionerSettingsData is defined as BufferCyclerSettingsData without adding anything new.
47
# We define the settings class used in buffercycler.py
48 6 Anchi Cheng
<pre>
49
settingsclass = leginondata.BufferCyclerSettingsData
50
</pre>
51
# The defaults of the buffer cycler settings are also inherited from conditioner.Conditioner
52 7 Anchi Cheng
<pre>
53 6 Anchi Cheng
defaultsettings = conditioner.Conditioner.defaultsettings
54 7 Anchi Cheng
</pre>
55 6 Anchi Cheng
56
h3. GUI panel class
57
58 11 Anchi Cheng
Define panelclass to make the class load the right gui panel that you will write later.
59
60 6 Anchi Cheng
<pre>
61
panelclass = leginon.gui.wx.BufferCycler.Panel
62
</pre>
63 10 Anchi Cheng
64 6 Anchi Cheng
h3. Input/Output Events
65
66
We inherit the eventinputs of the parent class in the example.
67
<pre>
68
eventinputs = conditioner.Conditioner.eventinputs
69
</pre>
70
71
h2. Define new data type or event this node produces
72
73
New output data type should be defined in leginondata.py, and new event, if any, defined in event.py
74
75
Neither is needed in the example.
76
77 1 Jim Pulokas
h2. Create the user interface
78 5 Jim Pulokas
79 6 Anchi Cheng
See source:trunk/leginon/gui/wx/BufferCycler.py for an inherited example that does not need any new definition.  This is the minimal definition of Leginon gui.
80 1 Jim Pulokas
81 6 Anchi Cheng
# Make a new file under leginon/gui/wx for the gui definition.  In the example: gui/wx/BufferCycler.py
82
# Define Panel Class
83
# OnSettingsTool method, SettingsDialog class, and ScrolledSettings are redefined in this module so that the local one is used.
84
85 5 Jim Pulokas
h2. Register the node
86
87 6 Anchi Cheng
Register the node by adding it to leginon/allnodes.py as shown in the modification made in r18567
88
89 12 Anchi Cheng
h2. Add the new node to an application
90
91 13 Anchi Cheng
Use similar procedure as in [[Use_the_Application_Editor_to_create_Leginon_applications|Application Editor in Leginon]] to add your new node and its event bindings to an existing application.
92
93
In our example,
94
95
We can add a new node in "MSI-T" application under "Main".  The node is created from "BufferCycler" class and named as "Pump Buffer".  It needs an FixCondition event binding from "Exposure" node.
96 1 Jim Pulokas
97 16 Anchi Cheng
h2. Example 2: TestTargetFinder
98
99
We have a base class in Leginon that creates a node to set targets on the input image.  The module is leginon/targetfinder.py.  The base class in there is TargetFinder.
100
When a AcquisitionImagePublishEvent is sent to it, it allows targets to be defined on it.
101
102
To make a new subclass that uses simple assignment of targets, we will make a subclass of TargetFinder here, called TestTargetFinder.  You can see the resulting subclass code in leginon/testtargetfinder.py
103
104
h2. Code the core functionality
105
106
* Make a new class in your new module.
107
108
In this example, you can copy leginon/testtargetfinder.py  It inherits targetfinder.TargetFinder
109
110
It overwrites findTargets to create targets from the input and set them on the gui.  In this example, the function you need to modify if you want to make one like it is testFindTarget
111
112
Instead of the example list of tuples (x,y) coordinates on the image
113
<pre>
114
    focus_targets_on_image = [(50,20)]
115
    acquisition_targets_on_image = [(100,100),(200,100)]
116
</pre>
117
Your code should analyze self.image (a numpy array representing the image) and find the target, then set the two variables focus_targets_on_image and acquisition_targets_on_image in the same format.
118
119 17 Anchi Cheng
h2.  The rest of process is the same as the first example.
120
121 18 Anchi Cheng
If your algorithm requires no variable input, you won't have to add new settings, nor add events. gui can also just use gui/wx/TestTargetFinder.py.  You just need to register it in allnodes.py and replace another TargetFinder subclass node in the MSI application.
122 2 Jim Pulokas
123 14 Anchi Cheng
124 15 Anchi Cheng
__________
125
126 4 Jim Pulokas
back to [[Leginon Developer Guide]]