|
| 1 | +"""Module for handling automated calculation via aiida-quantumespress.""" |
| 2 | +from __future__ import annotations |
| 3 | + |
| 4 | +import time |
| 5 | +import numpy as np |
| 6 | + |
| 7 | +from .Ensemble import Ensemble |
| 8 | +try: |
| 9 | + import aiida |
| 10 | + import aiida_quantumespresso |
| 11 | +except ImportError: |
| 12 | + import warnings |
| 13 | + warnings.warn('aiida or aiida-quantumespresso are not installed') |
| 14 | + |
| 15 | + |
| 16 | +class AiiDAEnsemble(Ensemble): |
| 17 | + """Ensemble subclass to interface SSCHA with aiida-quantumespresso.""" |
| 18 | + |
| 19 | + def compute_ensemble( |
| 20 | + self, |
| 21 | + pw_code: str, |
| 22 | + profile: str | None = None, |
| 23 | + protocol: str = 'moderate', |
| 24 | + options: dict = None, |
| 25 | + overrides: dict = None, |
| 26 | + **kwargs |
| 27 | + ): |
| 28 | + """Get ensemble properties. |
| 29 | +
|
| 30 | + All the parameters refer to the |
| 31 | + :func:`aiida_quantumespresso.workflows.pw.base.PwBaseWorkChain.get_builder_from_protocol` |
| 32 | + method. |
| 33 | +
|
| 34 | + Parameters |
| 35 | + --------- |
| 36 | + pw_code: |
| 37 | + The string associated with the AiiDA code for `pw.x` |
| 38 | + profile: |
| 39 | + AiiDA profile to use during the calculations. If None, the default is used |
| 40 | + protocol: |
| 41 | + The protocol to be used; available protocols are 'fast', 'moderate' and 'precise' |
| 42 | + options: |
| 43 | + The options for the calculations, such as the resources, wall-time, etc. |
| 44 | + overrides: |
| 45 | + The overrides for the get_builder_from_protocol |
| 46 | + kwargs: |
| 47 | + The kwargs for the get_builder_from_protocol |
| 48 | + """ |
| 49 | + from aiida import load_profile |
| 50 | + from aiida.engine import submit |
| 51 | + from aiida.plugins import WorkflowFactory |
| 52 | + from aiida.orm import StructureData |
| 53 | + |
| 54 | + PwBaseWorkChain = WorkflowFactory('quantumespresso.pw') |
| 55 | + |
| 56 | + if profile: |
| 57 | + load_profile(profile) |
| 58 | + else: |
| 59 | + load_profile() |
| 60 | + |
| 61 | + # Check if not all the calculation needs to be done |
| 62 | + n_calcs = np.sum( self.force_computed.astype(int)) |
| 63 | + computing_ensemble = self |
| 64 | + |
| 65 | + if overrides: |
| 66 | + try: |
| 67 | + tstress = overrides['pw']['parameters']['CONTROL']['tstress'] |
| 68 | + self.has_stress = tstress |
| 69 | + except KeyError: |
| 70 | + self.has_stress = True # by default we calculate stresses with the `get_builder_from_protocol` |
| 71 | + |
| 72 | + # Check wheter compute the whole ensemble, or just a small part |
| 73 | + should_i_merge = False |
| 74 | + if n_calcs != self.N: |
| 75 | + should_i_merge = True |
| 76 | + computing_ensemble = self.get_noncomputed() |
| 77 | + self.remove_noncomputed() |
| 78 | + |
| 79 | + # ============= HERE AIIDA PART ============= # |
| 80 | + structures_data = [StructureData(ase=cc.get_ase_atoms()) for cc in self.structures] |
| 81 | + workchains = [] |
| 82 | + |
| 83 | + for i, structure in enumerate(structures_data): |
| 84 | + builder = PwBaseWorkChain.get_builder_from_protocol( |
| 85 | + code=pw_code, |
| 86 | + structure=structure, |
| 87 | + options=options, |
| 88 | + overrides=overrides, |
| 89 | + **kwargs |
| 90 | + ) |
| 91 | + builder.label = str(i) |
| 92 | + workchains.append(submit(builder)) |
| 93 | + |
| 94 | + workchains_success = [] |
| 95 | + workchains_failed = [] |
| 96 | + |
| 97 | + while(workchains): |
| 98 | + for workchain in workchains: |
| 99 | + if workchain.is_finished: |
| 100 | + if workchain.is_failed: |
| 101 | + workchains_failed.append(workchain) |
| 102 | + else: |
| 103 | + workchains_success.append(workchain) |
| 104 | + workchains.remove(workchain) # here it may be critical |
| 105 | + |
| 106 | + time.sleep(60) # wait before checking again |
| 107 | + |
| 108 | + # ---- TO DO |
| 109 | + # * Take energies, forces, stresses |
| 110 | + # * Print which one was successfull |
| 111 | + # * Add correct labels to workchains to gather afterwards |
| 112 | + # * For sure something else |
| 113 | + # * Add the possibility of adding wc to group |
| 114 | + # * Keep track is some better way (printing?) of the workchains submitted |
| 115 | + # ============= HERE AIIDA PART ============= # |
| 116 | + |
| 117 | + print("CE BEFORE MERGE:", len(self.force_computed)) |
| 118 | + |
| 119 | + if should_i_merge: |
| 120 | + # Remove the noncomputed ensemble from here, and merge |
| 121 | + self.merge(computing_ensemble) |
| 122 | + print("CE AFTER MERGE:", len(self.force_computed)) |
| 123 | + |
| 124 | + print('ENSEMBLE ALL PROPERTIES:', self.all_properties) |
| 125 | + |
0 commit comments