Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC: add section on how to write plugin #463

Merged
merged 29 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2987b65
add plugin page
superstar54 Sep 8, 2023
a07f39e
add introduction
superstar54 Sep 8, 2023
04f94b0
update intro
superstar54 Sep 8, 2023
013ede3
udpate index page
superstar54 Sep 8, 2023
2c707f4
update workchain
superstar54 Sep 15, 2023
ef54a03
update doc
superstar54 Sep 20, 2023
81ce871
add architecture
superstar54 Sep 20, 2023
3314b0b
update parameters
superstar54 Sep 21, 2023
6a29f4f
Merge branch 'main' into doc_plugin
superstar54 Sep 22, 2023
9636663
udpate doc
superstar54 Sep 22, 2023
ed7fb61
add detail parameters
superstar54 Oct 7, 2023
60f7480
Merge branch 'main' into doc_plugin
superstar54 Oct 8, 2023
413b7ff
Merge branch 'main' into doc_plugin
superstar54 Oct 10, 2023
7ddf675
add `reset` example
superstar54 Oct 10, 2023
58cc5e2
break lines
superstar54 Oct 12, 2023
9e4b25f
break lines
superstar54 Oct 12, 2023
6cdf2cb
check grammar
superstar54 Oct 22, 2023
a9a767c
add second and third plugin examples
superstar54 Oct 22, 2023
7dd452b
Merge branch 'main' into doc_plugin
superstar54 Oct 22, 2023
cf0fd50
format the code
superstar54 Oct 22, 2023
5b5bab9
Merge branch 'main' into doc_plugin
superstar54 Nov 3, 2023
f766a42
Merge branch 'main' into doc_plugin
superstar54 Nov 3, 2023
9602b18
revise text
superstar54 Nov 3, 2023
fa0010f
Merge branch 'doc_plugin' of https://github.com/aiidalab/aiidalab-qe …
superstar54 Nov 3, 2023
f0718d6
replace hello_world by eos
superstar54 Nov 3, 2023
710848d
replace plugin_example image
superstar54 Nov 3, 2023
ad25ddc
fix format
superstar54 Nov 3, 2023
1dcd6d0
Apply suggestions from code review
unkcpz Nov 7, 2023
546e0d0
Update docs/source/development/plugin.rst
unkcpz Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/source/_static/images/plugin_example.png
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is not very clear, in the text it says "when the user selects to run the properties." but here the properties are not shown. Could you include the properties list and maybe using two figures to show the differents before and after selecting a new property?
Only if you agree with my suggestion, I think PS and replot the figures are tedious and may not make things better, I'll pining @mikibonacci for comments to see which way is better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will vote for Hello world (if we do not use MultiplyAdd instead) and for the gif, as it will be more dynamic and less tedious.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being late, I am pro Hello world since this is more a feature for developers, though i would be more incline to specify something like "Plugin: Custom Property" or "Plugin: Your New Feature" (or property) i think is more related to the idea that each plugin is linked to a new property

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/images/plugin_outline.png
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the description of the plugin the line "A aiidalab-qe plugin to print hello world" indent properly. I know it is the description, but seems like an isolated line. Maybe put a border on the widget?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this description line from the plugin.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/images/plugin_result.png
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super cool!

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/images/plugin_setting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/images/plugin_step.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions docs/source/development/architecture.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.. _develop:architecture:

************************
Architecture
************************

Wizards UI
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
==========

QuantumESPRESSO app uses the Wizards UI, which divides one calculation into four steps.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
Each step may contain several sections (panels), as shown below.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. image:: ../_static/images/plugin_step.png

Parameter transfer between steps
---------------------------------

The data is passed to the next step by linking it to the corresponding ``trail`` of the step.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
For example, the ``confirmed_structure`` of step 1 is linked to the ``input_structure`` ``trail`` of step 2.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. code:: python

ipw.dlink(
(self.structure_selection_step, "confirmed_structure"),
(self.configure_qe_app_work_chain_step, "input_structure"),
)

In the configuration step, there are several panels.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
The parameters from these panels are generated and stored as a dictionary,
which is linked to the ``input_parameters`` ``trail`` of the next submit step.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
The dictionary has the following structure:

.. code:: python

{
"workchain": {
"protocol": "fast",
"relax_type": "positions",
"properties": ["bands", "pdos", "relax"],
"spin_type": "none",
"electronic_type": "insulator",
},
"advanced": {
"initial_magnetic_moments": None,
"pw": {
"parameters": {
"SYSTEM": {"ecutwfc": 30.0, "ecutrho": 240.0, "tot_charge": 0.0}
},
"pseudos": {"Si": "eaef3352-2b0e-4205-b404-e6565a88aec8"},
},
"pseudo_family": "SSSP/1.2/PBEsol/efficiency",
"kpoints_distance": 0.5,
},
"bands": {"kpath_2d": "hexagonal"},
"pdos": {...},
"plugin_1": {...},
"plugin_2": {...},
}

Plugin
======

QuantumESPRESSO app supports running multiple properties (bands, pdos, etc.) calculations in one app.
Please take into account the following facts:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a rule for developers or it is a thing to note?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to This integration is made possible due to several key aspects:


- the configuration for a property calculation has its settings unrelated to other properties.
- the sub-workchain of the properties can be run independently.
- the analysis of the results of the properties is also independent.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

Thus, we can develop a property separately and integrate it into the QuantumESPRESSO app as a plugin.
Each plugin responsible for one property calculation.
For example, we could create a PDOS plugin, including its settings, workchain, and result analysis.
The GUI of the PDOS plugin is only loaded when the user selects to run the PDOS property.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
Here is an example, where two new setting panels are shown when the user selects to run the properties.

.. figure:: ../_static/images/plugin_example.png
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment on this file, I think it maybe better to have two static figures to show before and after the property being selected?



A QuantumESPRESSO app plugin will typically register new panels (setting, result), and workchain to extend the app's functionality.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A QuantumESPRESSO app plugin will typically register new panels (setting, result), and workchain to extend the app's functionality.
A QuantumESPRESSO app plugin will register new corresponding panels (setting, result), and workchain to extend functionalities of the App.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to keep typically, and not add corresponding.

The plugin design makes the QuantumESPRESSO app more modularized and pluggable.
So the developer can maintain their plugin as a separate folder in the QuantumESPRESSO app (even a separate package).
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 13 additions & 0 deletions docs/source/development/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. _develop-apps:

###################
Developer guide
###################

This guide explains how to extend the functionality of the app.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. toctree::
:maxdepth: 1

architecture
plugin
244 changes: 244 additions & 0 deletions docs/source/development/plugin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
.. _develop:create-plugin:

************************
Create your plugin
************************

A QuantumESPRESSO app plugin will typically register new panels (setting, result), and workchain to extend the app's functionality.


Your First Plugin
================================

Here is the simplest plugin to print the formula of the input structure:
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

Outline
-----------------------
A :class:`~aiidalab_qe.common.panel.Outline` will add an item in the properties section of the workflow panel.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
For this example, we'll add the ``Hello World`` item, as shown below.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved


.. image:: ../_static/images/plugin_outline.png
:align: center



The **Outline** will be shown as a checkbox.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: python

from aiidalab_qe.common.panel import OutlinePanel

class Outline(OutlinePanel):
title = "Hello World"
superstar54 marked this conversation as resolved.
Show resolved Hide resolved


superstar54 marked this conversation as resolved.
Show resolved Hide resolved

Setting
-----------------------
A :class:`~aiidalab_qe.common.panel.Panel` will register a new panel in the configuration step, e.g. the ``Hello world`` panel.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit confusing to me. Does a panel register a new panel? Can you be more specific?

Copy link
Member Author

@superstar54 superstar54 Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to A setting Panel widget will register a new panel in the configuration step.
In the feature, we may create a SettingPanel class for the setting, like the ResultPanel.


superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. image:: ../_static/images/plugin_setting.png

In this class, one can add widgets (e.g. Float, Int) to the GUI.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
The values of these widgets will be used in the WorkChain.
One needs to override the ``get_panel_value`` method to tell QuantumESPRESSO app how to use the values from the widgets.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
One also need to override the ``set_panel_value`` method to tell QuantumESPRESSO app how to reload the panel values from previous calculation, and the ``reset`` method to reset the panel to the default values.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: python

from aiidalab_qe.common.panel import Panel

class Setting(Panel):
""""""
title = "Hello world"

def __init__(self, **kwargs):
self.name = ipw.Text(value="", description="Your name:")
self.children = [self.name]
super().__init__(**kwargs)

def get_panel_value(self):
"""Get the panel value"""
return {"name": Str(self.name.value)}

def set_panel_value(self, input_dict):
"""Set the panel value"""
self.name.value = input_dict.get("name", 1)

def reset(self):
"""Reset the panel"""
self.name.value = ""

Result
-----------------------
A :class:`~aiidalab_qe.common.panel.ResultPanel` will register a new panel in the Results Step, e.g., the ``Hello world`` panel.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, maybe "register" -> "render"

Copy link
Member Author

@superstar54 superstar54 Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to use register. The plugin registers (adds) a new panel into the App. The web browser and Jupyter render the panel in the GUI.

superstar54 marked this conversation as resolved.
Show resolved Hide resolved


.. image:: ../_static/images/plugin_result.png

In this class, one needs to specific the `workchain_labels` to tell QuantumESPRESSO app which workchain the panel is for.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
Then, one needs to implement the ``_update_view`` method to tell QuantumESPRESSO app how to show the results of the workchain.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
The output of the workchain will be stored in ``self.outputs.hello_world``.
For example, the ``name`` and ``structure`` are the outputs of the ``HelloWorldWorkChain``.


.. code-block:: python

from aiidalab_qe.common.panel import ResultPanel

class Result(ResultPanel):
title = "Hello world"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, "hello world" example is used very specifically for programming language, I guess even aiida plugin didn't use a "hello world" example. Here more specific name could be better. Please consider to change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use the "MultiplyAddWorkChain" from AiiDA tutorial? https://aiida.readthedocs.io/projects/aiida-core/en/latest/intro/tutorial.html . This is just a detail, but maybe we can make the very same example.

workchain_labels = ["hello_world"]

def _update_view(self):
name = self.outputs.hello_world.name.value
formula = self.outputs.hello_world.structure.get_formula()
self.summary_view = ipw.HTML(
f"""<div> <h4>Hello {name}</h4> The input structure is: {formula} </div>""".format()
)
self.children = [ipw.HBox(children=[self.summary_view])]


WorkChain and Builder
-----------------------
One needs to implement a ``get_builder`` function to tell QuantumESPRESSO app how to use the input parameters from the GUI.

The `parameters` passed to the `get_builder` function has the following structure:

.. code:: python

{
"workchain": {
"protocol": "fast",
"relax_type": "positions",
"properties": ["bands", "pdos", "relax"],
"spin_type": "none",
"electronic_type": "insulator",
},
"advanced": {
"initial_magnetic_moments": None,
"pw": {
"parameters": {
"SYSTEM": {"ecutwfc": 30.0, "ecutrho": 240.0, "tot_charge": 0.0}
},
"pseudos": {"Si": "eaef3352-2b0e-4205-b404-e6565a88aec8"},
},
"pseudo_family": "SSSP/1.2/PBEsol/efficiency",
"kpoints_distance": 0.5,
},
"bands": {"kpath_2d": "hexagonal"},
"pdos": {...},
"hello_world": {...},
"plugin_1": {...},
}

One needs to decide which parameters are needed for the workchain, and how to use them.
For example, the ``HelloWorldWorkChain`` needs the ``name`` parameter, which is defined in the ``Setting`` panel.
The ``get_builder`` function will return a ``builder`` for the ``HelloWorldWorkChain``.
The ``builder`` will be used to submit the workchain.



.. code-block:: python

def get_builder(codes, structure, parameters):
"""Get the workchain specific parameters
"""
parameters = parameters.get("hello_world", {})
builder = HelloWorldWorkChain.get_builder_from_protocol(
codes=codes,
structure=structure,
parameters=parameters,
)
return builder

Then register the workchain and builder in the `workchain_and_builder` dict, so that the QuantumESPRESSO app can load them.

.. code-block:: python

# register the workchain and builder
workchain_and_builder = {
"workchain": HelloWorldWorkChain,
"get_builder": get_builder,
}

Entry point
-----------------------
Finally, one needs to register the entry point of the plugin. Here is the entry point for this plugin.

.. code-block:: python

# this is the entry point of the plugin
hello_world ={
"outline": Outline,
"setting": Setting,
"workchain": workchain_and_builder,
"result": Result,
}

Install the plugin
-----------------------
To install the plugin, you can creating a new package or adding it to the `aiidalab_qe.plugins` folder.
One needs to add the path of ``hello_world`` to ``entry_points`` inside the setup file.

.. code-block:: python

entry_points={
"aiidalab_qe.properties": [
"hello_world = aiidalab_qe_hello_world:hello_world",
],
},

**Bringing It All Together**, You can find all the code above in this github repository: https://github.com/superstar54/aiidalab-qe-hello-world
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
superstar54 marked this conversation as resolved.
Show resolved Hide resolved

Your second plugin
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
================================
One plugin does not need to register all the items (settings, workchain, results).
The panel in each step is pluggable, which means you could only register one item in a plugin.
For example, you can only add a new `Result` panel without doing any property calculation.
The built-in `electronic_structure` plugin only has a result panel, which needs the result from both `pdos`` and `bands`` plugins.
This is set by the `workchain_labels` attribute.

.. code-block:: python

class Result(ResultPanel):
title = "Electronic Structure"
workchain_labels = ["bands", "pdos"]

Here is the entry point for this plugin.

.. code-block:: python

from .result import Result

electronic_structure = {
"result": Result,
}

Your third plugin
================================
The plugin API also allows the user to add a new structure importer and editor:

- add structure `importer` specific for particular structures, e.g. surface, adsorbate.
- add a new `editor` to edit a structure for the plugin, e.g. edit tags, and cut surface.

Here is the example for such plugin.

.. code-block:: python

from .structure_importer import StructureImporter
from .structure_editor import StructureEditor

my_plugin ={
"importer": StructureImporter,
"editor": StructureEditor,
}



Further Reading
================================
QuantumESPRESSO app comes with built-in plugins, which can be found in the ``aiidalab_qe.plugins`` folder.
You can also use them as templates to create your own plugins.
superstar54 marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 18 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,23 @@ Welcome Page

To the how-to guides

.. grid-item-card:: Development
:text-align: center
:shadow: md

Learn how to develop the app

++++

.. button-ref:: development/index
:ref-type: doc
:click-parent:
:expand:
:color: primary
:outline:

To the development guide

.. grid-item-card:: Report an Issue
:text-align: center
:shadow: md
Expand All @@ -102,6 +119,7 @@ Welcome Page
installation/index
tutorials/index
howto/index
development/index
report_issue

----
Expand Down