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

Feature: Starting Magnetization #409

Merged
merged 8 commits into from
Jul 4, 2023
Merged

Conversation

AndresOrtegaGuerrero
Copy link
Member

@AndresOrtegaGuerrero AndresOrtegaGuerrero commented Jun 1, 2023

This PR implements a class MagnetizationSettings for Advanced Settings in the QE App, to be able to set initial_magnetic_moments in the calculations. Address #238
The user can select the magnetization per kind defined in the input_structure
Screenshot 2023-06-01 at 13 06 46

The will be another PR for an AddingTags Editor, so the user can create new tags for the atoms in the structure.

@mbercx
Copy link
Member

mbercx commented Jun 1, 2023

Hi @AndresOrtegaGuerrero and @unkcpz! I will be very busy the next few weeks on other projects, so unless there is something specific needed from my end (i.e. on the aiida-quantumespresso plugin), I will not have time to review PRs on the QEapp.

In general, I've been less and less involved on the development there. I am simply spread too thin otherwise and then no work gets done anywhere. Apologies.

@AndresOrtegaGuerrero
Copy link
Member Author

Hi @AndresOrtegaGuerrero and @unkcpz! I will be very busy the next few weeks on other projects, so unless there is something specific needed from my end (i.e. on the aiida-quantumespresso plugin), I will not have time to review PRs on the QEapp.

In general, I've been less and less involved on the development there. I am simply spread too thin otherwise and then no work gets done anywhere. Apologies.

No worries, I understand, thank you!

@AndresOrtegaGuerrero AndresOrtegaGuerrero requested review from superstar54 and removed request for mbercx June 1, 2023 12:25
@codecov
Copy link

codecov bot commented Jun 1, 2023

Codecov Report

Patch coverage: 86.13% and project coverage change: +1.66 🎉

Comparison is base (9df98ea) 52.63% compared to head (60723ab) 54.29%.

❗ Current head 60723ab differs from pull request most recent head 08558b4. Consider uploading reports for the commit 08558b4 to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #409      +/-   ##
==========================================
+ Coverage   52.63%   54.29%   +1.66%     
==========================================
  Files          17       17              
  Lines        1879     1978      +99     
==========================================
+ Hits          989     1074      +85     
- Misses        890      904      +14     
Flag Coverage Δ
python-3.10 54.29% <86.13%> (+1.66%) ⬆️
python-3.8 54.35% <86.13%> (+1.66%) ⬆️
python-3.9 54.35% <86.13%> (+1.66%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
aiidalab_qe/app/report.py 28.12% <0.00%> (-0.45%) ⬇️
tests/test_submit_qe_workchain.py 93.15% <83.33%> (-4.85%) ⬇️
aiidalab_qe/app/steps.py 70.88% <86.15%> (+1.96%) ⬆️
tests/conftest.py 97.58% <100.00%> (+0.23%) ⬆️

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@unkcpz
Copy link
Member

unkcpz commented Jun 1, 2023

Giovanni mentioned there will be a discussion for the structure data for this on 9th June, I asked him to invite @AndresOrtegaGuerrero. It might be better to wait for that one.

@unkcpz
Copy link
Member

unkcpz commented Jun 19, 2023

As discussed in the 9th June meeting, summarized at https://hackmd.io/xLA_d3AaSaqhAGVZIhdP7A?view. In QeApp, we don't plan to go that way in the moment but I am agree with @AndresOrtegaGuerrero to do the change from directly widget side.
The pros are we are independent from the core packges and StructureData, and thus can flexiblelly start proceed without blocking, the cons are not such magnetization settings will store in the database therefore impossible for query. But the current StructureData is not easy to query as well, so nothing to lose.
Once we have the widget, it should be not hard to change the backend to support the new extended StructureData in the future.

I'll give it a review.

@unkcpz
Copy link
Member

unkcpz commented Jun 28, 2023

A quick comment, if I didn't select structure, there is a dangling "override" checkbox there which looks a bit weird. I'd suggest having a text under the "Total charge" showing it is the placeholder for setting the initial magnetic moments.

image

Copy link
Member

@unkcpz unkcpz left a comment

Choose a reason for hiding this comment

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

@AndresOrtegaGuerrero thanks for adding this! I only have some minor requests, the overall implementation looks fine, cheers!

aiidalab_qe/app/static/workflow_summary.jinja Outdated Show resolved Hide resolved
aiidalab_qe/app/steps.py Outdated Show resolved Hide resolved
Comment on lines 326 to 327
class MagnetizationSettings(ipw.VBox):
input_structure = traitlets.Instance(StructureData, allow_none=True)
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 add a docstring to this widget to describe what input is expected for input_structure_labels, and give an example of it? It is not very clear from the first glimpse.

)
self.override.observe(self._disable_kings_widgets, "value")

def _disable_kings_widgets(self, _=None):
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
def _disable_kings_widgets(self, _=None):
def _disable_kinds_widgets(self, _=None):

😃 who is the king?

Copy link
Member Author

Choose a reason for hiding this comment

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

hahahahah!


def update_kinds_widgets(self, change):
self.input_structure_labels = self.input_structure.get_kind_names()
self.kinds = self.create_kinds_widgets()
Copy link
Member

Choose a reason for hiding this comment

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

If this is the first time the self.kinds is initialized and used, I suggest in the __init__ function, call the update and also set a placeholder text something like "Your input structure does not contain magnetic elements or the magnetic calculation is not turned on."

@@ -975,6 +1061,14 @@ def _get_qe_workchain_parameters(self) -> QeWorkChainParameters:
pw_overrides[key]["pw"]["parameters"]["SYSTEM"][
"tot_charge"
] = self.advanced_settings.tot_charge.charge.value
if (
self.advanced_settings.magnetization.override.value
and self.workchain_settings.spin_type.value == "collinear"
Copy link
Member

Choose a reason for hiding this comment

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

I am a bit confused, is "non-collinear" also supported? I didn't see the widget to set the spin_type to "collinear".

Copy link
Member Author

Choose a reason for hiding this comment

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

To define if you are using spin is

        self.spin_type = ipw.ToggleButtons(
            options=[("Off", "none"), ("On", "collinear")],
            value=DEFAULT_PARAMETERS["spin_type"],
            style={"description_width": "initial"},
        )

Copy link
Member

Choose a reason for hiding this comment

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

I see, fair. 👍

@@ -1034,6 +1128,7 @@ def _get_qe_workchain_parameters(self) -> QeWorkChainParameters:
spin_type=spin_type,
electronic_type=electronic_type,
overrides=overrides,
initial_magnetic_moments=starting_magnetization,
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need different names? Can all be called "initial_magnetic_moments" or "starting_magnetiziation"?

@@ -1034,6 +1128,7 @@ def _get_qe_workchain_parameters(self) -> QeWorkChainParameters:
spin_type=spin_type,
electronic_type=electronic_type,
overrides=overrides,
initial_magnetic_moments=starting_magnetization,
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need different names? Can all be called "initial_magnetic_moments" or "starting_magnetiziation"?

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 will update this

Comment on lines 50 to 53
assert (
report_html.count("None") <= 1
or builder_parameters("initial_magnetic_moments") is not None
)
Copy link
Member

Choose a reason for hiding this comment

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

thanks for the test!
I think the test can be more specific, like:

from bs4 import BeautifulSoup

if builder_parameters("initial_magnetic_moments") is None:
    parsed = BeautifulSoup(report_html)
    assert parsed.??.text == "None"


def __init__(self, **kwargs):
self.input_structure = StructureData()
self.kinds = self.create_kinds_widgets()
Copy link
Member

Choose a reason for hiding this comment

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

You initialize the self.kinds but didn't use it in __init__ function. Maybe it makes sense to create and use it when it is used. See the comment below in function update_kinds_widgets.

@AndresOrtegaGuerrero
Copy link
Member Author

@unkcpz Thank you for your suggestions and help. I just added another test for advanced settings and adapted your suggestions. Let me know what you think.

Copy link
Member

@unkcpz unkcpz left a comment

Choose a reason for hiding this comment

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

Thanks @AndresOrtegaGuerrero, three minor requests. It is all fine then.

@@ -318,6 +325,107 @@ def reset(self):
self.override.value = False


class MagnetizationSettings(ipw.VBox):
"""Widget to set the initial_magnetic_moments from each Kind in StructureData
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
"""Widget to set the initial_magnetic_moments from each Kind in StructureData
"""Widget to set initial magnetic moments for each `Kind` (usually the element name, but you can use `Fe1`, `Fe2` to distinguish iron atoms of different sites) of `StructureData`

Am I rephrasing it correctly? Please feel free to polish what I wrote.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you i will expand this 👍

widgets_list = []
for label in self.input_structure_labels:
hbox = ipw.HBox()
float_widget = ipw.BoundedFloatText(
Copy link
Member

Choose a reason for hiding this comment

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

No a big issue since it as a local variable, but I prefer bounded_float or simply w. float_widget seems a bit like a widget that can float on the webpage. Feel free to ignore this comment.

Copy link
Member

Choose a reason for hiding this comment

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

And why not do like this?

hbox = ipw.HBox(
    children=[
        ipw.BoundedFloatText(...
    ]
)

)
hbox.children = [float_widget]
widgets_list.append(hbox)
kinds_widget = ipw.VBox([ipw.HTML("Define magnetization")] + widgets_list)
Copy link
Member

Choose a reason for hiding this comment

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

Here you didn't use HTML tags for formatting, is ipw.HTML really needed?

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 will modify this

Comment on lines 369 to 370
for i in range(1, len(self.kinds.children)):
self.kinds.children[i].children[0].value = 0.0
Copy link
Member

Choose a reason for hiding this comment

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

I understand why it has to set the value like this, from range 1 to skip the HTML widget of index 0, and second children for the HBox. But it is a bit complex and error-prone when looking at this loop independently. Not sure there is a better way, I think having a Kind widget might be too much.
Just think about it, if there is not better way to make it clear, leave it as this and add a comment for why start loop from index 1 and what the second children refer to.

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 will update in such a way that is a VBox instead and to access the valees is self.kinds.children[i].value

@@ -975,6 +1061,14 @@ def _get_qe_workchain_parameters(self) -> QeWorkChainParameters:
pw_overrides[key]["pw"]["parameters"]["SYSTEM"][
"tot_charge"
] = self.advanced_settings.tot_charge.charge.value
if (
self.advanced_settings.magnetization.override.value
and self.workchain_settings.spin_type.value == "collinear"
Copy link
Member

Choose a reason for hiding this comment

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

I see, fair. 👍

tests/test_submit_qe_workchain.py Outdated Show resolved Hide resolved
assert parsed.find("initial_magnetic_moments").text == "None"


def test_create_builder_advanced_settings(
Copy link
Member

Choose a reason for hiding this comment

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

Thanks a lot for this test, very useful!

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes i think here we can add the test for new advanced settings :)

@AndresOrtegaGuerrero
Copy link
Member Author

@unkcpz Let me know i adapted the code :)

Copy link
Member

@unkcpz unkcpz left a comment

Choose a reason for hiding this comment

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

Hi @AndresOrtegaGuerrero, It is all fine. I have one question about the PYTEST_CURRENT_TEST, but I approve it anyway since the logic is all great for me.

self.display_kinds()

def display_kinds(self):
if "PYTEST_CURRENT_TEST" not in os.environ and self.kinds:
Copy link
Member

Choose a reason for hiding this comment

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

Interesting, I didn't know this PYTEST_CURRENT_TEST. Can you double check this is really needed here? I think even is a test it should be found to clear_output and display. Am I missing something?

Copy link
Member Author

@AndresOrtegaGuerrero AndresOrtegaGuerrero Jul 3, 2023

Choose a reason for hiding this comment

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

@unkcpz If i dont use this , it will return the widget during the pytest, so to avoid this behaviour i use the display and clear only if i am not in a pytest , but i do the update before.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I didn't understand, what will happen if the widget is returned during pytest, the test will fail? with what exception?

Copy link
Member Author

Choose a reason for hiding this comment

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

@unkcpz The test wont fail , but during the test in the terminal it will print the widget as text

Copy link
Member

Choose a reason for hiding this comment

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

Did you use pytest -s? Other wise it should not print things. If this is not needed, I'd not add it.
Sorry for the back-and-forth on this PR.

Copy link
Member Author

@AndresOrtegaGuerrero AndresOrtegaGuerrero Jul 4, 2023

Choose a reason for hiding this comment

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

@unkcpz No worries, is good to double check. I did the test with pytest -s without this line and the issue occurs, the test passed but it returns the object in this case a VBox. The line is needed. I push an update in the documentation of the test so is more clear.

Copy link
Member

Choose a reason for hiding this comment

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

I did the test with pytest -s

Yep, -s is to print things to the stdout. I think it is fair to suppress it with your way, otherwise run with -s locally would be a mess.

All good to me now. Do you mind merge this one with writing a description of the commit message? Just click the "squash and merge" below and input the message in the dialog.

@AndresOrtegaGuerrero AndresOrtegaGuerrero merged commit 354c81a into main Jul 4, 2023
12 checks passed
@AndresOrtegaGuerrero AndresOrtegaGuerrero deleted the feature/magnetization branch July 4, 2023 14:35
AndresOrtegaGuerrero added a commit that referenced this pull request Jul 5, 2023
*This PR implements an Editor for the QE App, to enable the user to define extra kinds within a structure.This editor is intended to facilitated spin polarisation calculations with #409
Co-authored-by: Xing Wang <xingwang1991@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants