mirror of https://github.com/abinit/abipy.git
Explain how to subclass Tasks and avoid pickle errors
This commit is contained in:
parent
ff65fab909
commit
1df8b4e162
|
@ -11,7 +11,7 @@ import numpy as np
|
|||
import spglib
|
||||
|
||||
from six.moves import cStringIO
|
||||
from tabulate import tabulate
|
||||
|
||||
from monty.string import is_string
|
||||
from monty.itertools import iuptri
|
||||
from monty.functools import lazy_property
|
||||
|
@ -119,7 +119,7 @@ def _get_det(mat):
|
|||
class Operation(object):
|
||||
"""
|
||||
Abstract base class that defines the methods that must be
|
||||
implememted by the concrete class representing some sort of operation
|
||||
implemented by the concrete class representing some sort of operation
|
||||
"""
|
||||
@abc.abstractmethod
|
||||
def __eq__(self, other):
|
||||
|
@ -148,6 +148,17 @@ class Operation(object):
|
|||
def isE(self):
|
||||
"""True if self is the identity operator"""
|
||||
|
||||
#def commute(self, other)
|
||||
# return self * other == other * self
|
||||
|
||||
#def commutator(self, other)
|
||||
# return self * other - other * self
|
||||
|
||||
#def anticommute(self, other)
|
||||
# return self * other == - other * self
|
||||
|
||||
#def direct_product(self, other)
|
||||
|
||||
|
||||
class SymmOp(Operation, SlotPickleMixin):
|
||||
"""
|
||||
|
@ -236,6 +247,18 @@ class SymmOp(Operation, SlotPickleMixin):
|
|||
self.afm_sign == 1)
|
||||
# end operator protocol.
|
||||
|
||||
#@lazy_property
|
||||
#def order(self):
|
||||
# """Order of the operation."""
|
||||
# n = 0
|
||||
# o = self
|
||||
# while m < 1000:
|
||||
# if o.isE: return n
|
||||
# n += 1
|
||||
# o = self * o
|
||||
# else:
|
||||
# raise ValueError("Cannot find order")
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
|
@ -431,7 +454,7 @@ class OpSequence(collections.Sequence):
|
|||
return -1
|
||||
|
||||
def is_group(self):
|
||||
"""True if the list of operations represent a group."""
|
||||
"""True if this set of operations represent a group."""
|
||||
check = 0
|
||||
|
||||
# Identity must be present.
|
||||
|
@ -454,7 +477,7 @@ class OpSequence(collections.Sequence):
|
|||
return check == 0
|
||||
|
||||
def is_commutative(self):
|
||||
"""True if operations in self commute with each other."""
|
||||
"""True if all operations commute with each other."""
|
||||
for op1, op2 in iuptri(self, diago=False):
|
||||
if op1 * op2 != op2 * op1:
|
||||
return False
|
||||
|
@ -462,7 +485,7 @@ class OpSequence(collections.Sequence):
|
|||
return True
|
||||
|
||||
def is_abelian_group(self):
|
||||
"""True if self is a commutative group."""
|
||||
"""True if commutative group."""
|
||||
return self.is_commutative() and self.is_group()
|
||||
|
||||
def asdict(self):
|
||||
|
@ -472,6 +495,15 @@ class OpSequence(collections.Sequence):
|
|||
"""
|
||||
return {op: idx for idx, op in enumerate(self)}
|
||||
|
||||
#def is_subset(self, other)
|
||||
# indmap = {}
|
||||
# for i, op in self:
|
||||
# j = other.find(op)
|
||||
# if j != -1: indmap[i] = j
|
||||
# return indmap
|
||||
|
||||
#def is_superset(self, other)
|
||||
|
||||
@lazy_property
|
||||
def mult_table(self):
|
||||
"""
|
||||
|
@ -849,7 +881,7 @@ class LittleGroup(OpSequence):
|
|||
|
||||
# Add character_table from Bilbao database.
|
||||
bilbao_ptgrp = bilbao_ptgroup(self.kgroup.sch_symbol)
|
||||
lines.extend(l.strip() for l in bilbao_ptgrp.to_string().splitlines())
|
||||
app(bilbao_ptgrp.to_string(verbose=verbose))
|
||||
app("")
|
||||
|
||||
# Write warning if non-symmorphic little group with k-point at zone border.
|
||||
|
@ -1073,6 +1105,9 @@ class LatticeRotation(Operation):
|
|||
# return t
|
||||
|
||||
|
||||
# TODO: Need to find an easy way to map classes in internal database
|
||||
# onto classes computed by client code when calculation has been done
|
||||
# with non-conventional settings (spglib?)
|
||||
class Irrep(object):
|
||||
"""
|
||||
This object represents an irreducible representation.
|
||||
|
@ -1117,6 +1152,9 @@ class Irrep(object):
|
|||
def character(self):
|
||||
return self._character
|
||||
|
||||
#@lazy_property
|
||||
#def dataframe(self):
|
||||
|
||||
|
||||
def bilbao_ptgroup(sch_symbol):
|
||||
"""
|
||||
|
@ -1184,29 +1222,58 @@ class BilbaoPointGroup(object):
|
|||
"""List with the names of the irreps."""
|
||||
return list(self.irreps_by_name.keys())
|
||||
|
||||
@property
|
||||
@lazy_property
|
||||
def character_table(self):
|
||||
"""Table of strings with the character of the irreps."""
|
||||
"""
|
||||
Dataframe with irreps.
|
||||
"""
|
||||
# 1st row: ptgroup_name class names and multiplicity of each class
|
||||
#name_mult = [name + " [" + str(mult) + "]" for (name, mult) in zip(self.class_names, self.class_len)]
|
||||
#table = [[self.sch_symbol] + name_mult]
|
||||
#app = table.append
|
||||
|
||||
## Add row: irrep_name, character.
|
||||
#for irrep in self.irreps:
|
||||
# character = list(map(str, irrep.character))
|
||||
# app([irrep.name] + character)
|
||||
|
||||
#from tabulate import tabulate
|
||||
#s = tabulate(table[1:], headers=table[0], tablefmt="simple", numalign="left")
|
||||
#print(s)
|
||||
|
||||
# Caveat: class names are not necessarly unique --> use np.stack
|
||||
import pandas as pd
|
||||
name_mult = [name + " [" + str(mult) + "]" for (name, mult) in zip(self.class_names, self.class_len)]
|
||||
table = [[self.sch_symbol] + name_mult]
|
||||
app = table.append
|
||||
columns = ["name"] + name_mult
|
||||
|
||||
# Add row: irrep_name, character.
|
||||
for irrep in self.irreps:
|
||||
character = list(map(str, irrep.character))
|
||||
app([irrep.name] + character)
|
||||
stack = np.stack([irrep.character for irrep in self.irreps])
|
||||
index = [irrep.name for irrep in self.irreps]
|
||||
df = pd.DataFrame(stack, columns=name_mult, index=index)
|
||||
df.index.name = "Irrep"
|
||||
df.columns.name = self.sch_symbol
|
||||
|
||||
return table
|
||||
# TODO
|
||||
#print(df)
|
||||
# Convert complex --> real if all entries in a colums are real.
|
||||
#for k in name_mult:
|
||||
# if np.all(np.isreal(df[k].values)):
|
||||
# #df[k] = df[k].values.real
|
||||
# df[k] = df[k].astype(float)
|
||||
|
||||
def to_string(self, tablefmt="simple", numalign="left"):
|
||||
return df
|
||||
|
||||
def to_string(self, verbose=0):
|
||||
"""
|
||||
Write a string with the character_table to the given ``stream``.
|
||||
``tablefmt`` and ``numalign`` options are passed to ``tabulate``.
|
||||
Return string with the character_table
|
||||
"""
|
||||
s = tabulate(self.character_table[1:], headers=self.character_table[0],
|
||||
tablefmt=tablefmt, numalign=numalign)
|
||||
return s
|
||||
return self.character_table.to_string()
|
||||
|
||||
#def decompose(self, character):
|
||||
# od = collections.OrderedDict()
|
||||
# for irrep in self.irreps:
|
||||
# irrep.name
|
||||
# irrep.character
|
||||
# return od
|
||||
|
||||
#def show_irrep(self, irrep_name):
|
||||
# """Show the mapping rotation --> irrep mat."""
|
||||
|
|
|
@ -1991,7 +1991,7 @@ class DdbRobot(Robot):
|
|||
("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
asr, chneut, dipdip: Anaddb input variable. See official documentation.
|
||||
with_geo: True if structure info should be added to the dataframe
|
||||
with_spglib: True to compute sgplib space group and add it to the DataFrame.
|
||||
with_spglib: True to compute spglib space group and add it to the DataFrame.
|
||||
abspath: True if paths in index should be absolute. Default: Relative to getcwd().
|
||||
funcs: Function or list of functions to execute to add more data to the DataFrame.
|
||||
Each function receives a |DdbFile| object and returns a tuple (key, value)
|
||||
|
@ -2080,7 +2080,7 @@ class DdbRobot(Robot):
|
|||
ddb_header_keys: List of keywords in the header of the DDB file
|
||||
whose value will be added to the Dataframe.
|
||||
with_structure: True to add structure parameters to the DataFrame.
|
||||
with_spglib: True to compute sgplib space group and add it to the DataFrame.
|
||||
with_spglib: True to compute spglib space group and add it to the DataFrame.
|
||||
with_path: True to add DDB path to dataframe
|
||||
manager: |TaskManager| object. If None, the object is initialized from the configuration file
|
||||
verbose: verbosity level. Set it to a value > 0 to get more information
|
||||
|
@ -2256,7 +2256,7 @@ class DdbRobot(Robot):
|
|||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
Write a jupyter_ notebook to nbpath. If ``nbpath`` is None, a temporay file in the current
|
||||
Write a jupyter_ notebook to nbpath. If ``nbpath`` is None, a temporary file in the current
|
||||
working directory is created. Return path to the notebook.
|
||||
"""
|
||||
nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)
|
||||
|
|
|
@ -437,7 +437,7 @@ class DdbRobotTest(AbipyTest):
|
|||
|
||||
# Test anacompare_elastic
|
||||
ddb_header_keys=["nkpt", "tsmear"]
|
||||
r = robot.anacompare_elastic(ddb_header_keys=ddb_header_keys,
|
||||
r = robot.anacompare_elastic(ddb_header_keys=ddb_header_keys, with_path=True,
|
||||
with_structure=True, with_spglib=False, relaxed_ion="automatic", piezo="automatic", verbose=1)
|
||||
df, edata_list = r.df, r.elastdata_list
|
||||
assert "tensor_name" in df.keys()
|
||||
|
|
|
@ -7,7 +7,7 @@ This gallery contains python scripts to generate AbiPy flows from the command li
|
|||
|
||||
Run the scripts to generate the directory with the flow and then use :ref:`abirun.py` to execute the flow.
|
||||
Alternatively, one can use the ``-s`` option to generate the flow and run it immediately with the scheduler.
|
||||
Use ``--help`` to further information on the available options.
|
||||
Use ``--help`` for further information on the available options.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
|
@ -11,4 +11,8 @@ the :ref:`abiopen.py` script and the command::
|
|||
|
||||
abiopen.py FILE -nb
|
||||
|
||||
or use one of the options of :ref:`abiview.py` to plot the results automatically.
|
||||
issue
|
||||
|
||||
abiopen.py FILE --expose
|
||||
|
||||
to generate plots automatically or use one of the options of :ref:`abiview.py` to plot the results automatically.
|
||||
|
|
|
@ -32,6 +32,8 @@ TODO list:
|
|||
|
||||
* Read forces in read_structure ?
|
||||
|
||||
* Automate CHANGELOG creation.
|
||||
|
||||
## Medium priority
|
||||
|
||||
* remove phononflow
|
||||
|
@ -93,8 +95,6 @@ TODO list:
|
|||
* DONE plot_networkx does not work with flows containing callbacks e.g. run_qptdm_flow
|
||||
FIXED with graphviz
|
||||
|
||||
* DONE Use graphvix in flow sphinx-gallery
|
||||
|
||||
* Check xsf_write_data and visualization of potentials.
|
||||
|
||||
* Add phbands.to_bxsf and histogram for phonon modes at a given q-point.
|
||||
|
@ -132,8 +132,6 @@ TODO list:
|
|||
|
||||
* Remove GUI code.
|
||||
|
||||
* _repr_html_ for structure and other basic objects (pymatgen/and abipy)
|
||||
|
||||
* nbjsmol (build system, refactor API?)
|
||||
|
||||
* fatbands with SOC (waiting for Matthieu's refactoring)
|
||||
|
@ -150,3 +148,7 @@ TODO list:
|
|||
* Replace SIGRES with new fileformat based on SIGEPH (long-term)
|
||||
|
||||
* Update spack recipe, add support for EasyBuild, revamp homebrew (?)
|
||||
|
||||
* Classification of phonons/electrons
|
||||
|
||||
* Error handler for tolwfr to increase nband / nbdduf and resubmit
|
||||
|
|
|
@ -16,10 +16,10 @@ Feel free to suggest new entries!
|
|||
Suggestions:
|
||||
|
||||
* Start with the examples available in examples/flows before embarking on large scale calculations.
|
||||
* Make sure the Abinit executable compiled on the machine can be executed both on the frontend
|
||||
* Make sure the Abinit executable compiled on the machine can be executed both on the front end
|
||||
and the compute node (ask your sysadmin)
|
||||
* If you are running on clusters in which the architecture of the compute node is completely different
|
||||
from the one available on the frontend, use ``shell_runner``
|
||||
from the one available on the front end, use ``shell_runner``
|
||||
* Use the ``debug`` command
|
||||
|
||||
Do not:
|
||||
|
@ -91,7 +91,7 @@ When running many calculations,
|
|||
Use ``prtwf -1`` to tell Abinit to produce the wavefunction file only
|
||||
if SCF cycle didn't converged so that AbiPy can reuse the file to restart the calculation.
|
||||
|
||||
Note that it's possibile to use::
|
||||
Note that it's possible to use::
|
||||
|
||||
flow.use_smartio()
|
||||
|
||||
|
@ -101,9 +101,25 @@ for their children.
|
|||
How to extend tasks/works with specialized code
|
||||
-----------------------------------------------
|
||||
|
||||
Remember that pickle_ does not support classes defined inside scripts.
|
||||
Remember that pickle_ does not support classes defined inside scripts (`__main__`).
|
||||
This means that `abirun.py` will likely raise an exception when trying to
|
||||
reconstruct the object from the pickle file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
AttributeError: Cannot get attribute 'MyWork' on <module '__main__'
|
||||
|
||||
If you need to subclass one of the AbiPy Tasks/Works/Flows, define the subclass
|
||||
in a separated python module and import the module inside your script.
|
||||
We suggest to create a python module in the AbiPy package e.g. `abipy/flowtk/my_works.py`
|
||||
in order to have an absolute import that allows one to use
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from abipy.flowtk.my_works import MyWork
|
||||
|
||||
in the script without worrying about relative paths and relative imports.
|
||||
|
||||
|
||||
Kill a scheduler running in background
|
||||
--------------------------------------
|
||||
|
@ -123,6 +139,6 @@ Try to understand why a task failed
|
|||
-----------------------------------
|
||||
|
||||
There are several reasons why a task could fail.
|
||||
Some of these reasons could be related to hardaware failure, disk quota,
|
||||
OS or resource manager errors.
|
||||
others are related to Abinit-specific errors.
|
||||
Some of these reasons could be related to hardware failure, disk quota,
|
||||
OS errors or resource manager errors.
|
||||
Others are related to Abinit-specific errors.
|
||||
|
|
Loading…
Reference in New Issue