diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 73749334..504dd9ec 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -94,7 +94,7 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10"] - aiida: [{version: 'aiida-core==2.1.2', name: '2.1.2'}] + aiida: [{version: 'aiida-core==2.3.0', name: '2.3.0'}] masci-tools: [{version: 'git+https://github.com/JuDFTteam/masci-tools.git@develop', name: '-masci-develop'}] allowed-to-fail: [false] @@ -125,7 +125,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0046fce2..2143b919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10"] - aiida: [{version: 'aiida-core==2.1.2', name: '2.1.2'}] + aiida: [{version: 'aiida-core==2.3.0', name: '2.3.0'}] masci-tools: [{version: 'git+https://github.com/JuDFTteam/masci-tools.git@develop', name: '-masci-develop'}] allowed-to-fail: [false] diff --git a/aiida_kkr/parsers/kkrimp.py b/aiida_kkr/parsers/kkrimp.py index 146d8fb5..79783da2 100644 --- a/aiida_kkr/parsers/kkrimp.py +++ b/aiida_kkr/parsers/kkrimp.py @@ -41,8 +41,8 @@ def __init__(self, calc): super(KkrimpParser, self).__init__(calc) # pylint: disable=protected-access - - def parse(self, debug=False, ignore_nan=True, **kwargs): # pylint: disable=unexpected-keyword-arg + # pylint: disable=unexpected-keyword-arg + def parse(self, debug=False, ignore_nan=True, **kwargs): """ Parse output data folder, store results in database. diff --git a/aiida_kkr/tools/find_parent.py b/aiida_kkr/tools/find_parent.py index 2b7431eb..73e8e172 100644 --- a/aiida_kkr/tools/find_parent.py +++ b/aiida_kkr/tools/find_parent.py @@ -30,7 +30,11 @@ def get_remote(parent_folder): try: parent_folder_tmp = parent_folder_tmp0.get_incoming().get_node_by_label('remote_folder') except NotExistent: - parent_folder_tmp = parent_folder_tmp0 + try: + # check if GFhost_folder is there, this is the case for a KkrimpCalculation + parent_folder_tmp = parent_folder_tmp0.get_incoming().get_node_by_label('GFhost_folder') + except NotExistent: + parent_folder_tmp = parent_folder_tmp0 return parent_folder_tmp diff --git a/aiida_kkr/tools/plot_kkr.py b/aiida_kkr/tools/plot_kkr.py index a5667c2a..63a1d6ea 100644 --- a/aiida_kkr/tools/plot_kkr.py +++ b/aiida_kkr/tools/plot_kkr.py @@ -13,10 +13,51 @@ __copyright__ = (u'Copyright (c), 2018, Forschungszentrum Jülich GmbH, ' 'IAS-1/PGI-1, Germany. All rights reserved.') __license__ = 'MIT license, see LICENSE.txt file' -__version__ = '0.7.1' +__version__ = '0.7.2' __contributors__ = ('Philipp Rüßmann') +def get_datetime_from_str(calc, verbose=False): + """ + Return a datetime object from the last time a calculation was checked by the scheduler. + + Every calculation should have the 'scheduler_lastchecktime' attribute which has the + following format: '2023-11-08T22:44:13.543215+00:00'. + This is converted to a datetime object that can be sorted. + """ + from datetime import datetime + # get last time stamp of scheduler from calculation attribute + try: + last_time_on_computer = calc.attributes['scheduler_lastchecktime'] + except: + raise ValueError('Failed to get "scheduler_lastchecktime" from calculation.') + # parse date and time from string + date = last_time_on_computer.split('T')[0] + time = last_time_on_computer.split('T')[1].split('.')[0] + # change format + datetime_str = date[2:].replace('-', '/') + ' ' + time + # convert to datetime object + datetime_object = datetime.strptime(datetime_str, '%y/%m/%d %H:%M:%S') + + if verbose: + print(datetime_object) # printed in default format + + #return datetime object of the last time the calculation was checked + return datetime_object + + +def get_sorting_indices(calcs): + """ + Get the sorting index for a list of calculations. + + For each calculation the datetime object of the last time the scheduler checked the + calculation is extracted. This is then sorted and the sorting index array is returned. + """ + datetimes = [get_datetime_from_str(calc) for calc in calcs] + isort = np.array(datetimes).argsort() + return isort + + def remove_empty_atoms(show_empty_atoms, structure, silent=False): # check if empty sphere need to be removed for plotting (ase structgure cannot be constructed for alloys or vacancies) #print('in remove empty atoms:', structure.has_vacancies, ('X' in [i.kind_name for i in structure.sites]) ) @@ -341,6 +382,8 @@ class plot_kkr(object): :type switch_xy: bool :param iatom: list of atom indices which are supposed to be plotted (default: [], i.e. show all atoms) :type iatom: list + :param debug: activate debug output + :type debug: bool additional keyword arguments are passed onto the plotting function which allows, for example, to change the markers used in a DOS plot to crosses via `marker='x'` @@ -359,8 +402,17 @@ def __init__(self, nodes=None, **kwargs): from aiida import load_profile load_profile() + # used to keep track of structure plotting self.sview = None + # debug mode + self.debug = False + if 'debug' in kwargs: + self.debug = kwargs.pop('debug') + print('start plot_kkr') + print('kwargs:', kwargs) + + # grouping of node if a list of nodes is the input instead of a single node groupmode = False if type(nodes) == list: if len(nodes) > 1: @@ -1006,8 +1058,12 @@ def plot_voro_calc(self, node, **kwargs): def plot_kkrimp_calc(self, node, return_rms=False, return_stot=False, plot_rms=True, **kwargs): """plot things from a kkrimp Calculation node""" + if self.debug: + print('in plot_kkrimp_calc') + print('kwargs:', kwargs) + # plot impurity cluster - if kwargs.get('strucplot', True): + if kwargs.get('strucplot', False): if _has_ase_notebook(): self.sview = plot_imp_cluster(node, **kwargs) else: @@ -1048,7 +1104,7 @@ def plot_kkrimp_calc(self, node, return_rms=False, return_stot=False, plot_rms=T else: ptitle = f'pk= {node.pk}' - self.make_kkrimp_rmsplot([rms], [stot], [0], rms_goal, ptitle, **kwargs) + self.make_kkrimp_rmsplot([rms], [stot], [node], rms_goal, ptitle, **kwargs) # now return values return_any, return_list = False, [] @@ -1074,10 +1130,14 @@ def plot_kkrimp_sub_wc(self, node, **kwargs): """plot things from a kkrimp_sub_wc workflow""" from aiida_kkr.calculations import KkrimpCalculation + if self.debug: + print('in plot_kkrimp_sub_wc') + print('kwargs:', kwargs) + impcalcs = [i.node for i in node.get_outgoing(node_class=KkrimpCalculation).all()] # plot impurity cluster - if len(impcalcs) > 0 and kwargs.get('strucplot', True): + if len(impcalcs) > 0 and kwargs.get('strucplot', False): if _has_ase_notebook(): self.sview = plot_imp_cluster(impcalcs[0], **kwargs) else: @@ -1088,10 +1148,9 @@ def plot_kkrimp_sub_wc(self, node, **kwargs): kwargs.pop(k) # extract rms from calculations - rms_all, pks_all, stot_all = [], [], [] + rms_all, stot_all = [], [] rms_goal = None for impcalc in impcalcs: - pks_all.append(impcalc.pk) rms_tmp, rms_goal_tmp, stot_tmp = self.plot_kkrimp_calc( impcalc, return_rms=True, return_stot=True, plot_rms=False ) @@ -1108,9 +1167,9 @@ def plot_kkrimp_sub_wc(self, node, **kwargs): else: ptitle = f'pk= {node.pk}' - self.make_kkrimp_rmsplot(rms_all, stot_all, pks_all, rms_goal, ptitle, **kwargs) + self.make_kkrimp_rmsplot(rms_all, stot_all, impcalcs, rms_goal, ptitle, **kwargs) - def make_kkrimp_rmsplot(self, rms_all, stot_all, pks_all, rms_goal, ptitle, **kwargs): + def make_kkrimp_rmsplot(self, rms_all, stot_all, list_of_impcalcs, rms_goal, ptitle, **kwargs): """ plot rms and total spin moment of kkrimp calculation or series of kkrimp calculations """ @@ -1141,7 +1200,7 @@ def make_kkrimp_rmsplot(self, rms_all, stot_all, pks_all, rms_goal, ptitle, **kw # plotting of convergence properties (rms etc.) if len(rms_all) > 0: # sort rms values and flatten array - reorder_rms = array(pks_all).argsort()[::-1] + reorder_rms = get_sorting_indices(list_of_impcalcs) rms, niter_calcs, stot = [], [0], [] rms_all_sorted = [rms_all[i] for i in reorder_rms] for i in rms_all_sorted: @@ -1192,6 +1251,10 @@ def plot_kkrimp_dos_wc(self, node, **kwargs): from masci_tools.vis.kkr_plot_dos import dosplot from matplotlib.pyplot import show, figure, title, xticks, xlabel, axvline + if self.debug: + print('in plot_kkrimp_dos_wc') + print('kwargs:', kwargs) + interpol, all_atoms, l_channels, sum_spins, switch_xy = True, False, True, False, False ptitle = None if 'ptitle' in list(kwargs.keys()): diff --git a/tests/data_dir/KkrCalculation-nodes-5e8261f1e3db59cfe2602957481376e3.tar.gz b/tests/data_dir/KkrCalculation-nodes-5e8261f1e3db59cfe2602957481376e3.tar.gz deleted file mode 100644 index 992df15f..00000000 Binary files a/tests/data_dir/KkrCalculation-nodes-5e8261f1e3db59cfe2602957481376e3.tar.gz and /dev/null differ diff --git a/tests/data_dir/KkrCalculation-nodes-9260ecff6d48ebee7adb680b907edcbc.tar.gz b/tests/data_dir/KkrCalculation-nodes-9260ecff6d48ebee7adb680b907edcbc.tar.gz new file mode 100644 index 00000000..79999073 Binary files /dev/null and b/tests/data_dir/KkrCalculation-nodes-9260ecff6d48ebee7adb680b907edcbc.tar.gz differ diff --git a/tests/data_dir/KkrCalculation-nodes-f544fdba7f3eb6ebd85322908203e977.tar.gz b/tests/data_dir/KkrCalculation-nodes-f544fdba7f3eb6ebd85322908203e977.tar.gz new file mode 100644 index 00000000..8fa70406 Binary files /dev/null and b/tests/data_dir/KkrCalculation-nodes-f544fdba7f3eb6ebd85322908203e977.tar.gz differ diff --git a/tests/data_dir/KkrCalculation-nodes-ff38d3ba605e86bfebabea80a103fab0.tar.gz b/tests/data_dir/KkrCalculation-nodes-ff38d3ba605e86bfebabea80a103fab0.tar.gz deleted file mode 100644 index d28410f5..00000000 Binary files a/tests/data_dir/KkrCalculation-nodes-ff38d3ba605e86bfebabea80a103fab0.tar.gz and /dev/null differ diff --git a/tests/data_dir/VoronoiCalculation-nodes-5285e1ed9ee855cfbfbf9fe11b2fca95.tar.gz b/tests/data_dir/VoronoiCalculation-nodes-5285e1ed9ee855cfbfbf9fe11b2fca95.tar.gz deleted file mode 100644 index 0b7d7410..00000000 Binary files a/tests/data_dir/VoronoiCalculation-nodes-5285e1ed9ee855cfbfbf9fe11b2fca95.tar.gz and /dev/null differ diff --git a/tests/data_dir/VoronoiCalculation-nodes-acab3366e24be2dbeddf6a16802cfaf2.tar.gz b/tests/data_dir/VoronoiCalculation-nodes-acab3366e24be2dbeddf6a16802cfaf2.tar.gz index 8c36a5ab..81df80c0 100644 Binary files a/tests/data_dir/VoronoiCalculation-nodes-acab3366e24be2dbeddf6a16802cfaf2.tar.gz and b/tests/data_dir/VoronoiCalculation-nodes-acab3366e24be2dbeddf6a16802cfaf2.tar.gz differ diff --git a/tests/data_dir/VoronoiCalculation-nodes-f69adf0c2a273e0c8fd8eecb66e3ba87.tar.gz b/tests/data_dir/VoronoiCalculation-nodes-f69adf0c2a273e0c8fd8eecb66e3ba87.tar.gz new file mode 100644 index 00000000..2e29a751 Binary files /dev/null and b/tests/data_dir/VoronoiCalculation-nodes-f69adf0c2a273e0c8fd8eecb66e3ba87.tar.gz differ diff --git a/tests/tools/test_find_parent.py b/tests/tools/test_find_parent.py index d6c3c6b5..a3a8cc23 100755 --- a/tests/tools/test_find_parent.py +++ b/tests/tools/test_find_parent.py @@ -23,6 +23,21 @@ def test_find_parent_structure(): assert voro_parent.uuid == '559b9d9b-3525-402e-9b24-ecd8b801853c' +def test_find_structure_kkrimp(): + """ + find parent structure from a KkrimpCalculation + """ + import_with_migration('files/db_dump_kkrimp_out.tar.gz') + kkrimp_calc = load_node('eab8db1b-2cc7-4b85-a524-0df4ff2b7da6') + + # now find voronoi parent and structure + struc, voro_parent = find_parent_structure(kkrimp_calc) + + # check result + assert struc.uuid == 'e51ee6a1-bd27-4901-9612-7bac256bf117' + assert voro_parent.uuid == '559b9d9b-3525-402e-9b24-ecd8b801853c' + + def test_get_calc_from_remote(): """ find parent calc from remote