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

Implementing lazy-loading #802

Open
wants to merge 68 commits into
base: main
Choose a base branch
from
Open

Implementing lazy-loading #802

wants to merge 68 commits into from

Conversation

edan-bainglass
Copy link
Member

@edan-bainglass edan-bainglass commented Sep 9, 2024

This PR aims to improve the user's experience by isolating loading of widgets/resources to where they are needed (requested).

The overall approach is as follows (per widget):

  1. Move bulk of __init__ logic to a new render method
  2. Add a loading widget (introduced in this PR) as a child in __init__
  3. Observe the container of the widget (widget might be in an accordion, a tab, etc. -> observe the selected_index trait of the container)
  4. On observable notification (e.g., tab switch), trigger widget's render method

Additionally, I take here an MVC (Model-View-Controller) approach to the app. The app's logic is migrated out to Model classes that represent the so-called "business-logic" of the app. Ideally, though perhaps not quite there yet, it should be possible to prepare and submit a QE calculation entirely via the Model classes!

A combination of a View and a Controller, here represented in a single class, is then simply a "window" to the Model's data. The View (the widgets) represent the UI. The Controller (the _on_<event> methods) is in charge of reacting to events either triggered by the user via the View, or triggered internally via the Model network.

Note that as I worked on this PR, several competing "flavors" of MVC came about. The present implementation is not a settled one. There are still some issues to address in order to properly establish our standard. One major issue is described below.

Open design concern

Currently, the ConfigurationModel, which represents the data of step 2, is injected into all other SettingsPanels. There, traits of the corresponding SettingsModel can be linked to the corresponding traits in the ConfigurationModel. This effectively syncs the specific settings with the app's configuration. There are presently a couple of idea to resolve this coupling between settings. Glad to discuss with those who are interested.

Glad to adjust where necessary 🙂

Update

Recent changes decouple the ConfigurationModel from the SettingsPanels. The AdvancedSettings class is still coupled with its "sub-settings", e.g., smearing, magnetization, etc. This is primarily due to the highly coupled set_model_state and get_model_state methods of the AdvancedModel. But this okay for now, and perhaps in general, as the advanced settings is presented all together in one panel.

The decoupling hinges on a mechanism of announcing dependencies. For example, the PDOS plugin requires both the input structure and the protocol. Hence, it defines

class PdosModel(SettingsModel):
    dependencies = [
        "input_structure",
        "workchain.protocol",
    ]

    input_structure = tl.Instance(orm.StructureData, allow_none=True)
    protocol = tl.Unicode(allow_none=True)
...

During plugin discovery, these dependencies are used to set up directional links, connecting the model to the configuration model network.

Note, however, that in decoupling the ConfigurationModel, I made a decision to extract the structure relaxation and property selection parts out from the basic settings. The new design of the configuration step is now split into sub-steps (thanks @mikibonacci for the suggestion to refer to these as step 2.x).

Glad to discuss and adjust where necessary 🙂

Documentation

Of course, once the PR is approved, documentation of the settled approach (or at least the current one) will be added!

@edan-bainglass edan-bainglass marked this pull request as draft September 9, 2024 10:04
@edan-bainglass
Copy link
Member Author

@PNOGillespie Hi Peter. I'm reaching out regarding this PR in hope that you may assist with one part relating to your XAS plugin.

To keep it brief, the settings module of your XAS plugin triggers a good deal of logic on import. This prevents the implementation of lazy-loading w.r.t XAS.

A simple solution would be to do as @superstar54 did in the XPS plugin, i.e., wrap such logic in a function to be lazily triggered on demand. Do you think this is something you could look into in a separate PR? If not, could you please comment on the reason?

@PNOGillespie
Copy link
Contributor

Hi @edan-bainglass. I can move the logic for updating the pseudopotentials (which is what lines 67 - 112 in settings do on starting the plugin) to be under _update_element_select_panel(). This should mean that the logic is only triggered by _update_structure(). Is that what you meant? Please let me know if I'm missing something.

I'm somewhat busy both this week and next, but I should be able to put together a separate PR soon for the changes if it's just a case of moving things around.

@edan-bainglass
Copy link
Member Author

Hi @PNOGillespie 👋

Hi @edan-bainglass. I can move the logic for updating the pseudopotentials (which is what lines 67 - 112 in settings do on starting the plugin) to be under _update_element_select_panel(). This should mean that the logic is only triggered by _update_structure(). Is that what you meant? Please let me know if I'm missing something.

Yes, this sounds right. As stated, @superstar54's approach in the XPS plugin is likely the way to go, for reference 🙂 Once the PR is ready, I test against my lazy-loading work and we see more clearly if it's sufficient 👍

I'm somewhat busy both this week and next, but I should be able to put together a separate PR soon for the changes if it's just a case of moving things around.

No worries. The lazy-loading work will take a few pass (possibly incremental PRs), so the XAS part can be addressed once your PR is in.

Thanks 🙏

@edan-bainglass
Copy link
Member Author

@PNOGillespie @superstar54 just wondering, why were the XPS and XAS plugins included in the core app? Would it be better to maintain them as external plugins, say aiidalab-qe-xps and aiidalab-qe-xas, to be installed by those interested? What do you think?

@edan-bainglass edan-bainglass force-pushed the lazy-loading branch 2 times, most recently from fa7c4ef to 9b6d792 Compare September 20, 2024 04:28
@edan-bainglass edan-bainglass force-pushed the lazy-loading branch 2 times, most recently from 1f1206a to a1235b2 Compare September 22, 2024 13:29
PNOGillespie added a commit to PNOGillespie/aiidalab-qe that referenced this pull request Sep 23, 2024
Addresses requirements for lazy-loading (PR aiidalab#802) by moving logic
for checking core-hole pseudopotentials to `_update_structure()`.
@edan-bainglass edan-bainglass force-pushed the lazy-loading branch 2 times, most recently from 7d26bf6 to 2561827 Compare October 7, 2024 05:53
@edan-bainglass edan-bainglass force-pushed the lazy-loading branch 4 times, most recently from 4bd2e20 to 21aa97b Compare October 24, 2024 09:13
@edan-bainglass edan-bainglass marked this pull request as ready for review October 24, 2024 09:13
@edan-bainglass
Copy link
Member Author

Hi all. The PR is ready for review. As mentioned, it is massive! If necessary, maybe we split the work a bit, say, one app step per person? Not sure if this helps. Anyhow, I'm available for questions :)

src/aiidalab_qe/app/result/model.py Outdated Show resolved Hide resolved
self._status_message = f"""
<div class='alert alert-danger'>
ERROR: failed to obtain recommended cutoffs for pseudos
`{pseudo_family}`: {exception}
Copy link
Member

Choose a reason for hiding this comment

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

I would add some details here, like "Please select a custom ecut and ecutrho"... But actually,
the get_builder_from_protocol will except because indeed no cutoff are found. So,
We can put actuallly a "please select another pseudopotential family". This is kind of a bug
from aiida-pseudo, hopefully we can solve it easily

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed! Could you open an issue (to be PR'd soon)? 🙏

@mikibonacci found an issue when selecting `PBEsol` with `SSSP Precision` (does not define stringency). Issue to be raised with `aiida_pseudos`.
@danielhollas
Copy link
Contributor

@edan-bainglass it would be very helpful to me if you could point me to the things you want me to look at, I am feeling a bit lost right now. :-) Or we can wait till Monday, where you will present the approach in general?

@edan-bainglass
Copy link
Member Author

@edan-bainglass it would be very helpful to me if you could point me to the things you want me to look at, I am feeling a bit lost right now. :-) Or we can wait till Monday, where you will present the approach in general?

Best if I walk you through it on Monday. However, in the meantime, you can take a look at #919, where I've started documenting the core principles.

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.

6 participants