Remove htc module

This commit is contained in:
Matteo Giantomassi 2018-01-12 13:35:26 +01:00
parent 4e2c07c24a
commit 9399078334
35 changed files with 405 additions and 5057 deletions

View File

@ -28,11 +28,9 @@ omit =
*/site-packages/*
abipy/data/*
abipy/examples/*
abipy/htc/*
abipy/gui/*
abipy/gw/*
abipy/extensions/*
abipy/gw/*
abipy/scripts/*
abipy/integration_tests/*
./docs/

View File

@ -34,7 +34,7 @@ from abipy.core.structure import (Lattice, Structure, StructureModifier, datafra
mp_match_structure, mp_search, cod_search)
from abipy.core.mixins import CubeFile
from abipy.core.kpoints import set_atol_kdiff
from abipy.htc.input import AbiInput, LdauParams, LexxParams, input_gen
#from abipy.htc.input import LdauParams, LexxParams
from abipy.abio.robots import Robot
from abipy.abio.inputs import AbinitInput, MultiDataset, AnaddbInput, OpticInput
from abipy.abio.abivars import AbinitInputFile
@ -165,8 +165,8 @@ def dir2abifiles(top, recurse=True):
"""
Analyze the filesystem starting from directory `top` and
return an ordered dictionary mapping the directory name to the list
of files supported by `abiopen` contained within that directory.
If not `recurse`, children directories are not analyzed.
of files supported by ``abiopen`` contained within that directory.
If not ``recurse``, children directories are not analyzed.
"""
dl = collections.defaultdict(list)
@ -187,7 +187,7 @@ def dir2abifiles(top, recurse=True):
def isabifile(filepath):
"""
Return True if `filepath` can be opened with `abiopen`.
Return True if `filepath` can be opened with ``abiopen``.
"""
try:
abifile_subclass_from_filename(filepath)

View File

@ -13,7 +13,7 @@ try:
except ImportError:
from pymatgen.serializers.json_coders import pmg_serialize
from abipy.htc.input import LdauParams, LexxParams
from abipy.flowtk.abiobjects import LdauParams, LexxParams
from .inputs import AbinitInput, MultiDataset
import logging

View File

@ -26,7 +26,7 @@ except ImportError:
from abipy.core.structure import Structure
from abipy.core.mixins import Has_Structure
from abipy.core.kpoints import has_timrev_from_kptopt
from abipy.htc.variable import InputVariable
from abipy.abio.variable import InputVariable
from abipy.abio.abivars import is_abivar, is_anaddb_var
from abipy.abio.abivars_db import get_abinit_variables
from abipy.abio.input_tags import *

View File

@ -1,4 +1,4 @@
"""Tests for structure module"""
"""Tests for abivars module"""
from __future__ import print_function, division, unicode_literals, absolute_import
import numpy as np

View File

@ -0,0 +1,17 @@
"""Tests for variable module."""
from __future__ import print_function, division, unicode_literals, absolute_import
import abipy.data as abidata
from abipy.core.testing import AbipyTest
from abipy.abio.variable import InputVariable
class TestInputVariable(AbipyTest):
def test_inputvariable(self):
"""Testing InputVariable."""
v = InputVariable(name="ecut", value=5)
assert v.name == "ecut"
assert not v.units
assert str(v) == " ecut 5"

View File

@ -1,14 +1,14 @@
from __future__ import print_function, division #, unicode_literals
from __future__ import print_function, division, absolute_import #, unicode_literals
import string
import warnings
from .utils import flatten, listify, is_number, is_iter
import collections
import numpy as np
__all__ = ['InputVariable', 'SpecialInputVariable']
__all__ = [
'InputVariable',
]
_SPECIAL_DATASET_INDICES = (':', '+', '?')
@ -60,8 +60,9 @@ def convert_number(value):
class InputVariable(object):
"""An Abinit input variable."""
"""
An Abinit input variable.
"""
def __init__(self, name, value, units='', valperline=3):
self._name = name
@ -89,9 +90,9 @@ class InputVariable(object):
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
#@name.setter
#def name(self, name):
# self._name = name
@property
def basename(self):
@ -111,7 +112,6 @@ class InputVariable(object):
def __str__(self):
"""Declaration of the variable in the input file."""
value = self.value
if value is None or not str(value):
return ''
@ -197,7 +197,6 @@ class InputVariable(object):
def format_list2d(self, values, floatdecimal=0):
"""Format a list of lists."""
lvals = flatten(values)
# Determine the representation
@ -261,7 +260,6 @@ class InputVariable(object):
Interpret a string variable and attempt to return a value of the
appropriate type. If all else fails, return the initial string.
"""
value = None
try:
@ -383,49 +381,50 @@ class InputVariable(object):
return self.sorting_name == other.sorting_name
class SpecialInputVariable(InputVariable):
"""
An Abinit input variable which can be set by replacing
the special dataset indices according to
: --> __s
+ --> __i
? --> __a
hence allowing for pythonic names.
"""
@property
def name(self):
return self._name
def is_number(s):
"""Returns True if the argument can be made a float."""
try:
float(s)
return True
except:
return False
@name.setter
def name(self, name):
name = self.internal_to_declared(name)
self._name = name
@property
def internal_name(self):
return self.declared_to_internal(self.name)
def is_iter(obj):
"""Return True if the argument is list-like."""
return hasattr(obj, '__iter__')
@staticmethod
def internal_to_declared(name):
"""
Make the conversion
__s --> :
__i --> +
__a --> ?
"""
for old, new in _SPECIAL_CONVERSION:
name = name.replace(old, new)
return name
@staticmethod
def declared_to_internal(name):
"""
Make the conversion
: --> __s
+ --> __i
? --> __a
"""
for new, old in _SPECIAL_CONVERSION:
name = name.replace(old, new)
return name
#def is_scalar(obj):
# """Return True if the argument is not list-like."""
# return not is_iter
def flatten(iterable):
"""Make an iterable flat, i.e. a 1d iterable object."""
iterator = iter(iterable)
array, stack = collections.deque(), collections.deque()
while True:
try:
value = next(iterator)
except StopIteration:
if not stack:
return tuple(array)
iterator = stack.pop()
else:
if not isinstance(value, str) \
and isinstance(value, collections.Iterable):
stack.append(iterator)
iterator = iter(value)
else:
array.append(value)
#def listify(obj):
# """Return a flat list out of the argument."""
# if not obj:
# obj = list()
# elif is_iter(obj):
# obj = list(flatten(obj))
# else:
# obj = [obj]
# return deepcopy(obj)

View File

@ -575,7 +575,7 @@ class Structure(pymatgen.Structure, NotebookWriter):
@property
def abi_string(self):
"""Return a string with the ABINIT input associated to this structure."""
from abipy.htc.variable import InputVariable
from abipy.abio.variable import InputVariable
lines = []
app = lines.append
abivars = self.to_abivars()

View File

@ -506,64 +506,3 @@ class AbipyTest(PymatgenTest):
@wraps(get_gsinput_si)
def get_gsinput_si(*args, **kwargs):
return get_gsinput_si(*args, **kwargs)
class AbipyFileTest(AbipyTest):
"""
Test class for files with a __str__ attribute.
At setup, must set the 'file' attribute of the AbipyFileTest.
"""
file = None
@staticmethod
def normalize(string):
string = string.replace('\t', ' ')
string = string.replace("$", " CASH ")
string = string.replace("(", " LP ")
string = string.replace(")", " RP ")
string = string.replace("*", " STAR ")
string = string.strip()
string = '\n'.join([line.strip() for line in string.splitlines()])
return string
def assertContains(self, expression):
"""
Assert that the string representation of the file contains 'expression'
'expression' is trimmed of leading new line.
Each line of 'expression' is trimmed of blank spaces.
Empty lines are ignored.
"""
expression = self.normalize(expression)
ref = self.normalize(str(self.file))
return self.assertRegexpMatches(ref, expression)
def assertContainsNot(self, expression):
"""
Assert that the string representation of the file does not contain
'expression'.
"""
expression = self.normalize(expression)
ref = self.normalize(str(self.file))
return self.assertNotRegexpMatches(ref, expression)
def assertEmpty(self):
"""Assert the string representation is empty."""
s = str(self.file).strip()
self.assertFalse(bool(s))
def assertOrder(self, expression1, expression2):
"""
Assert that the string representation of the file
contains 'expression1' before 'expression2'.
"""
expression1 = self.normalize(expression1)
expression2 = self.normalize(expression2)
ref = self.normalize(str(self.file))
self.assertRegexpMatches(ref, expression1)
self.assertRegexpMatches(ref, expression2)
last = ref.split(expression1)[-1]
return self.assertRegexpMatches(last, expression2)

View File

@ -7,7 +7,7 @@ from __future__ import print_function, division, unicode_literals, absolute_impo
import sys
from abipy.htc.fftbench import FFT_Benchmark
from abipy.tools.fftprof import FFTBenchmark
def main():
@ -18,7 +18,7 @@ def main():
# Plot the benchmark results saved in the files
for prof_file in prof_files:
FFT_Benchmark.from_file(prof_file).plot()
FFTBenchmark.from_file(prof_file).plot()
return 0

View File

@ -15,7 +15,6 @@ from monty.functools import lazy_property
from pymatgen.core.units import EnergyArray, ArrayWithUnit
from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry
from abipy.core.mixins import AbinitNcFile, Has_Header, Has_Structure, Has_ElectronBands, NotebookWriter
from prettytable import PrettyTable
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt
from abipy.abio.robots import Robot
from abipy.electrons.ebands import ElectronsReader, RobotWithEbands
@ -317,6 +316,7 @@ class EnergyTerms(AttrDict):
@property
def table(self):
"""PrettyTable object with the results."""
from prettytable import PrettyTable
table = PrettyTable(["Term", "Value"])
for k, doc in self._NAME2DOC.items():
table.add_row([k, self[k]])

View File

@ -15,6 +15,8 @@ import abipy.data as abidata
import abipy.abilab as abilab
import abipy.flowtk as flowtk
from abipy.flowtk.abiobjects import LdauParams
def make_scf_nscf_dos_inputs(structure, pseudos, luj_params, paral_kgb=1):
# Input file taken from tldau_2.in
@ -96,7 +98,7 @@ def build_flow(options):
for u in u_values:
# Apply U-J on Ni only.
luj_params = abilab.LdauParams(usepawu, structure)
luj_params = LdauParams(usepawu, structure)
luj_params.luj_for_symbol("Ni", l=2, u=u, j=0.1*u, unit="eV")
scf_input, nscf_input, dos_input = make_scf_nscf_dos_inputs(structure, pseudos, luj_params)

View File

@ -1,3 +1,160 @@
from __future__ import print_function, division, unicode_literals, absolute_import
import collections
from pymatgen.core.units import Energy
from pymatgen.io.abinit.abiobjects import *
#__all__ = [
# "LdauParams",
# "LexxParams",
#]
class LujForSpecie(collections.namedtuple("LdauForSpecie", "l u j unit")):
"""
This object stores the value of l, u, j used for a single atomic specie.
"""
def __new__(cls, l, u, j, unit):
"""
Args:
l: Angular momentum (int or string).
u: U value
j: J Value
unit: Energy unit for u and j.
"""
l = l
u, j = Energy(u, unit), Energy(j, unit)
return super(cls, LujForSpecie).__new__(cls, l, u, j, unit)
class LdauParams(object):
"""
This object stores the parameters for LDA+U calculations with the PAW method
It facilitates the specification of the U-J parameters in the Abinit input file.
(see `to_abivars`). The U-J operator will be applied only on the atomic species
that have been selected by calling `lui_for_symbol`.
To setup the Abinit variables for a LDA+U calculation in NiO with a
U value of 5 eV applied on the nickel atoms:
.. code-block:: python
luj_params = LdauParams(usepawu=1, structure=nio_structure)
# Apply U-J on Ni only.
u = 5.0
luj_params.luj_for_symbol("Ni", l=2, u=u, j=0.1*u, unit="eV")
print(luj_params.to_abivars())
"""
def __init__(self, usepawu, structure):
"""
Arg:
usepawu: ABINIT variable `usepawu` defining the LDA+U method.
structure: |Structure| object.
"""
self.usepawu = usepawu
self.structure = structure
self._params = {}
@property
def symbols_by_typat(self):
return [specie.symbol for specie in self.structure.types_of_specie]
def luj_for_symbol(self, symbol, l, u, j, unit="eV"):
"""
Args:
symbol: Chemical symbol of the atoms on which LDA+U should be applied.
l: Angular momentum.
u: Value of U.
j: Value of J.
unit: Energy unit of U and J.
"""
if symbol not in self.symbols_by_typat:
raise ValueError("Symbol %s not in symbols_by_typat:\n%s" % (symbol, self.symbols_by_typat))
if symbol in self._params:
raise ValueError("Symbol %s is already present in LdauParams! Cannot overwrite:\n" % symbol)
self._params[symbol] = LujForSpecie(l=l, u=u, j=j, unit=unit)
def to_abivars(self):
"""Returns a dict with the Abinit variables."""
lpawu, upawu, jpawu = [], [], []
for symbol in self.symbols_by_typat:
p = self._params.get(symbol, None)
if p is not None:
l, u, j = p.l, p.u.to("eV"), p.j.to("eV")
else:
l, u, j = -1, 0, 0
lpawu.append(int(l))
upawu.append(float(u))
jpawu.append(float(j))
# convert upawu and jpaw to string so that we can use
# eV unit in the Abinit input file (much more readable).
return dict(
usepawu=self.usepawu,
lpawu=" ".join(map(str, lpawu)),
upawu=" ".join(map(str, upawu)) + " eV",
jpawu=" ".join(map(str, jpawu)) + " eV")
class LexxParams(object):
"""
This object stores the parameters for local exact exchange calculations with the PAW method
It facilitates the specification of the LEXX parameters in the Abinit input file.
(see `to_abivars`). The LEXX operator will be applied only on the atomic species
that have been selected by calling `lexx_for_symbol`.
To perform a LEXX calculation for NiO in which the LEXX is computed only for the l=2
channel of the nickel atoms:
.. code-block:: python
lexx_params = LexxParams(nio_structure)
lexx_params.lexx_for_symbol("Ni", l=2)
print(lexc_params.to_abivars())
"""
def __init__(self, structure):
"""
Arg:
structure: |Structure| object.
"""
self.structure = structure
self._lexx_for_symbol = {}
@property
def symbols_by_typat(self):
return [specie.symbol for specie in self.structure.types_of_specie]
def lexx_for_symbol(self, symbol, l):
"""
Enable LEXX for the given chemical symbol and the angular momentum l
Args:
symbol: Chemical symbol of the atoms on which LEXX should be applied.
l: Angular momentum.
"""
if symbol not in self.symbols_by_typat:
err_msg = "Symbol %s not in symbols_by_typat:\n%s" % (symbol, self.symbols_by_typat)
raise ValueError(err_msg)
if symbol in self._lexx_for_symbol:
raise ValueError("Symbol %s is already present in LdauParams! Cannot overwrite:" % symbol)
self._lexx_for_symbol[symbol] = l
def to_abivars(self):
"""Returns a dict with the Abinit variables."""
lexx_typat = []
for symbol in self.symbols_by_typat:
l = self._lexx_for_symbol.get(symbol, -1)
lexx_typat.append(int(l))
return dict(useexexch=1, lexexch=" ".join(map(str, lexx_typat)))

View File

@ -0,0 +1,55 @@
"""Tests for flowtk.abiobjects module."""
from __future__ import print_function, division, unicode_literals
import numpy as np
import abipy.data as abidata
from abipy.core.testing import AbipyTest
from abipy.flowtk.abiobjects import LdauParams, LexxParams
class LdauLexxTest(AbipyTest):
def test_nio(self):
"""Test LdauParams and LexxParams."""
aequal, atrue = self.assertEqual, self.assertTrue
structure = abidata.structure_from_ucell("NiO")
pseudos = abidata.pseudos("28ni.paw", "8o.2.paw")
u = 8.0
luj_params = LdauParams(usepawu=1, structure=structure)
luj_params.luj_for_symbol("Ni", l=2, u=u, j=0.1*u, unit="eV")
avars = luj_params.to_abivars()
self.serialize_with_pickle(luj_params, test_eq=False)
atrue(avars["usepawu"] == 1),
aequal(avars["lpawu"], "2 -1"),
aequal(avars["upawu"], "8.0 0.0 eV"),
aequal(avars["jpawu"], "0.8 0.0 eV"),
# Cannot add UJ for non-existent species.
with self.assertRaises(ValueError):
luj_params.luj_for_symbol("Foo", l=2, u=u, j=0.1*u, unit="eV")
# Cannot overwrite UJ.
with self.assertRaises(ValueError):
luj_params.luj_for_symbol("Ni", l=1, u=u, j=0.1*u, unit="eV")
lexx_params = LexxParams(structure)
lexx_params.lexx_for_symbol("Ni", l=2)
avars = lexx_params.to_abivars()
self.serialize_with_pickle(lexx_params, test_eq=False)
aequal(avars["useexexch"], 1),
aequal(avars["lexexch"], "2 -1"),
# Cannot add LEXX for non-existent species.
with self.assertRaises(ValueError):
lexx_params.lexx_for_symbol("Foo", l=2)
# Cannot overwrite LEXX.
with self.assertRaises(ValueError):
lexx_params.lexx_for_symbol("Ni", l=1)

View File

@ -5,7 +5,7 @@ import wx
from collections import OrderedDict
from abipy.gui import awx
from abipy.htc.fftbench import FFTProf
from abipy.tools.fftprof import FFTProf
from abipy.gui.editor import SimpleTextViewer
from .awx.panels import LinspaceControl

View File

@ -1,22 +0,0 @@
"""
Abinit files handling library
"""
from __future__ import print_function, division, unicode_literals
__all__ = []
_mods = [
'input',
'abinitfiles',
'filesfile',
'variable',
'inputfile',
'jobfile',
'abinitinput',
'launcher',
]
#for _mod in _mods:
# exec('from .' + _mod + ' import *')
# exec('__all__.extend(' + _mod + '.__all__)')
# exec('del ' + _mod)

View File

@ -1,195 +0,0 @@
"""
Base class for an ABINIT calculation.
"""
from __future__ import print_function, division #, unicode_literals
from os.path import basename, dirname, join, splitext, realpath
__all__ = ["AbinitFiles"]
# =========================================================================== #
class AbinitFiles(object):
"""
A manager for the abinit file names.
A calculation is organised as follow::
CalcDir/
|-- CalcRoot.in
|-- CalcRoot.out
|-- input_data/
| |-- idat_CalcRoot_DS2_DEN
|-- run/
| |-- CalcRoot.files
| |-- CalcRoot.sh
| |-- CalcRoot.log
| |-- out_data/
| | |-- odat_CalcRoot_DS1_DEN
| | |-- odat_CalcRoot_DS1_WFK
| |-- tmp_data/
| | |-- tmp_CalcRoot_LOG_0001
| | |
"""
_directory = {
'inp' : '',
'out' : '',
'job' : 'run',
'files' : 'run',
'log' : 'run',
'idat' : 'input_data',
'odat' : join('run', 'out_data'),
'tmp' : join('run', 'tmp_data')}
_prefix = {
'inp' : '',
'out' : '',
'job' : '',
'files' : '',
'log' : '',
'idat' : 'idat_',
'odat' : 'odat_',
'tmp' : 'tmp_'}
_suffix = {
'inp' : '.in',
'out' : '.out',
'files' : '.files',
'log' : '.log',
'idat' : '',
'odat' : '',
'tmp' : '',
'job' : '.sh'}
def _form_name(self, filetype):
d = self._directory[filetype]
pr = self._prefix[filetype]
sf = self._suffix[filetype]
return join(self.absdir, d, pr + self.basename + sf)
def __init__(self, rootname='AbinitCalculation/root'):
# Take the root name
if '.' in rootname:
rootname = splitext(rootname)[0]
# The calculation must be in a directory.
if rootname == basename(rootname):
rootname = join(rootname, 'calc')
self.set_rootname(rootname)
def set_rootname(self, name):
"""Set the root name."""
self.__dict__['rootname'] = name
self.__dict__['absdir'] = realpath(dirname(name))
@property
def dirname(self):
"""The top-level directory."""
return dirname(self.rootname)
@property
def basename(self):
"""The basename of the root name."""
return basename(self.rootname)
@property
def name(self):
"""The root name."""
return self.rootname
@property
def files_name(self):
"""The name of the ".files" file given to abinit."""
return self._form_name('files')
@property
def job_name(self):
"""The submission script name."""
return self._form_name('job')
@property
def input_name(self):
"""The input file name."""
return self._form_name('inp')
@property
def log_name(self):
"""The name of the log file."""
return self._form_name('log')
@property
def idat_root(self):
"""The root name for input data files."""
return self._form_name('idat')
@property
def odat_root(self):
"""The root name for output data files."""
return self._form_name('odat')
@property
def tmp_root(self):
"""The root name for temporaty data files."""
return self._form_name('tmp')
@property
def output_name(self):
"""The output file produced (based on the name only)."""
return self._form_name('out')
def get_odat(self, datatype, dtset=0):
"""
Returns an output data file name.
Args:
datatype:
The type of datafile, e.g. 'DEN' or 'WFK'.
dtset:
The dataset index from which to take the data file.
If 0 (the default), no dataset index is used.
"""
file = self.odat_root
if int(dtset) > 0: file += '_DS' + str(dtset)
file += '_' + datatype.upper().lstrip('_')
return file
def get_idat(self, datatype, dtset=0):
"""
Returns an input data file name.
Args:
datatype:
The type of datafile, e.g. 'DEN' or 'WFK'.
dtset:
The dataset index from which to take the data file.
If 0 (the default), no dataset index is used.
"""
file = self.idat_root
if int(dtset) > 0: file += '_DS' + str(dtset)
file += '_' + datatype.upper().lstrip('_')
return file
def get_netcdf(self, datatype, dtset=0):
"""
Returns a netcdf output data file name.
Args:
datatype:
The type of datafile, 'DEN' or 'WFK'.
dtset:
The dataset index from which to take the data file.
If 0 (the default), no dataset index is used.
"""
return self.get_odat(datatype, dtset=dtset) + '.nc'

View File

@ -1,313 +0,0 @@
from __future__ import print_function, division #, unicode_literals
import subprocess
from os import makedirs, readlink, symlink
from os.path import basename, dirname, exists, join, realpath
from abipy.profile import abipy_env
from .filesfile import FilesFile
from .abinitfiles import AbinitFiles
from .inputfile import InputFile
from .jobfile import JobFile, PBSJobFile, SGEJobFile, SlurmJobFile
__all__ = ['AbinitInput']
# =========================================================================== #
class AbinitInput(AbinitFiles):
"""
To Create an Abinit calculation.
The AbinitInput contains three main internal objects:
an :class:`~abipy.htc.InputFile`, a :class:`~abipy.htc.FilesFile`,
and a :class:`~abipy.htc.JobFile`.
**Arguments**:
name:
A string of the form 'directory/rootname' or simply 'directory'.
jobtype:
The type of job, e.g. 'PBS', 'SGE', 'Slurm' or None.
**Keyword arguments for the inputfile**:
variables:
A dictionary of input variables for the calculation.
**Keyword arguments for the filesfile**:
pseudodir:
The directory in which to look for the pseudopotential files.
pseudos:
A list of pseudopotential files.
**Keyword arguments for the jobfile**:
bindir:
The directory in which to look for binaries.
executable:
The binary to be executed. Default is 'abinit'.
mpirun:
The mpi runner. E.g. 'mpiexec -npernode 6'.
modules:
List of modules which will be loaded with 'module load'.
lines_before:
List of lines to be executed before the main execution.
lines_after:
List of lines to be executed after the main execution.
other_lines:
List of command lines for the job submission system.
Any property of the JobFile or the selected subclass
(PBSJobFile, SGEJobFile, SlurmJobFile, ...)
.. code-block:: python
>> calc = AbinitInput('Mycalc/rootname', jobtype='PBS',
.. pseudodir='Data',
.. bindir='/path/to/binaries/',
.. lines_before=['cd ${PBS_O_WORKDIR}'])
>>
>> # Input file properties
>> calc.ecut = 10.
>> calc.tolwfr = 1e-8
>>
>> calc.kptopt = 1
>> calc.ngkpt = [2, 2, 2]
>> calc.nshiftk = 1
>> calc.shiftk = [0.0, 0.0, 0.0]
>>
>> unit_cell = {
.. 'acell' : 3*[8.6277],
.. 'rprim' : [[.0, .5, .5],
.. [.5, .0, .5],
.. [.5, .5, .0]],
.. 'ntypat' : 2,
.. 'znucl' : [30, 8],
.. 'natom' : 2,
.. 'typat' : [1, 2],
.. 'xred' : [[.0, .0, .0],
.. [.25,.25,.25]]}
>>
>> calc.set_variables(unit_cell)
>>
>> # Files file properties
>> calc.set_pseudos('Zn.psp', 'O.psp')
>>
>> # Job file properties
>> calc.set_jobname('MyTest')
>> calc.set_nodes(2)
>> calc.set_ppn(12)
>> calc.set_memory('24gb')
>> calc.set_runtime(48)
>> calc.set_mpirun('mpiexec -npernode 6')
>>
>> calc.write()
As you can see, setting an attribute of the AbinitInput object
will result in setting that input variable in the input file.
Note also that *all* of the :class:`~abipy.htc.JobFile` functions are available
though the AbinitInput.
"""
def __init__(self, name='Calculation/abinit', jobtype='PBS', **kwargs):
AbinitFiles.__init__(self, name)
# Initialize the inputfile
self._setattr(inputfile = InputFile(self.input_name))
# Initialize the filesfile
self._setattr(filesfile = FilesFile(self.files_name,
input=self.input_name,
output=self.output_name,
idat_root=self.idat_root,
odat_root=self.odat_root,
tmp_root=self.tmp_root))
# Initialize the jobfile
jobargs = dict(name=self.job_name, executable='abinit',
input=self.files_name,
log=self.log_name)
#jobtype = abipy_env.get_uservar("jobtype", kwargs)
if jobtype is None: jobtype = ''
if jobtype.lower() == 'pbs':
self._setattr(jobfile = PBSJobFile(**jobargs))
elif jobtype.lower() == 'sge':
self._setattr(jobfile = SGEJobFile(**jobargs))
elif jobtype.lower() == 'slurm':
self._setattr(jobfile = SlurmJobFile(**jobargs))
else:
self._setattr(jobfile = JobFile(**jobargs))
# Create setter function for jobfile attributes.
for prop in self.jobfile.properties():
function = 'set_' + prop
self.__dict__[function] = getattr(self.jobfile, function)
# Pairs of (target, pointer) to be linked.
self._setattr(_to_link = list())
# Other arguments
for key in self.properties():
val = abipy_env.get_default(key, kwargs)
if val is not None:
getattr(self, 'set_' + key)(val)
def _setattr(self, **kwargs):
self.__dict__.update(kwargs)
def __setattr__(self, name, val):
setattr(self.inputfile, name, val)
def write(self, *args, **kwargs):
"""
Write all the files for the calculation.
"""
force = kwargs.get("force", False)
if not force and self.inputfile.exists:
print("Cannot overwrite: %s\tUse -f to force file creation." % self.name)
return
# Create directories
for file in (self.input_name, self.output_name, self.job_name,
self.files_name, self.log_name, self.idat_root,
self.odat_root, self.tmp_root):
directory = dirname(file)
if not exists(directory):
makedirs(directory)
# Link files
for pair in self._to_link:
self._link(*pair)
# Write files
self.inputfile.write()
self.filesfile.write()
self.jobfile.write()
def link_idat(self, file, dtset='auto', datatype='auto'):
"""
Make a symbolic link for input data.
Args:
file:
The name of the file to be linked.
dtset:
The index of the dataset which should read the file.
By default, it is read from the file name.
Set to zero for no dataset index.
datatype:
The type of datafile, e.g. 'DEN' or 'WFK'.
By default, it is read from the file name.
"""
if datatype == 'auto':
datatype = file.split('_')[-1]
if dtset == 'auto':
dtset = file.split('_DS', 1)[-1].split('_')[0]
try:
dtset = int(dtset)
except:
dtset = 0
self._to_link.append((file, self.get_idat(datatype, dtset)))
def link_odat(self, file, dtset='auto', datatype='auto'):
"""
Make a symbolic link for output data.
Args:
file:
The name of the file to be linked.
dtset:
The index of the dataset from which the file belongs.
By default, it is read from the file name.
Set to zero for no dataset index.
datatype:
The type of datafile, e.g. 'DEN' or 'WFK'.
By default, it is read from the file name.
"""
if datatype == 'auto':
datatype = file.split('_')[-1]
if dtset == 'auto':
dtset = file.split('_DS', 1)[-1].split('_')[0]
try:
dtset = int(dtset)
except:
dtset = 0
self._to_link.append((file, self.get_odat(datatype, dtset)))
def link_io(self, idtset, odtset, datatype):
"""
Make a symbolic link from an output data to an input data.
Args:
idtset:
The dataset index of the input file.
odtset:
The dataset index of the output file.
datatype:
The type of datafile, e.g. 'DEN' or 'WFK'.
"""
idat = self.get_idat(datatype, idtset)
odat = self.get_odat(datatype, odtset)
self._to_link.append((odat, idat))
def set_pseudodir(self, pseudodir):
"""Set the directory for the pseudopotentials. Linked to FilesFile."""
return self.filesfile.set_pseudodir(pseudodir)
def set_pseudos(self, *pseudopotentials):
"""Set the pseudopotential files. Linked to FilesFile."""
return self.filesfile.set_pseudos(*pseudopotentials)
def read(self, *args, **kwargs):
"""Read an input file. Linked to InputFile."""
return self.inputfile.read(*args, **kwargs)
def set_variables(self, *args, **kwargs):
"""Set input variables. Linked to InputFile."""
return self.inputfile.set_variables(*args, **kwargs)
def set_comment(self, *args, **kwargs):
"""Set a comment in the input file. Linked to InputFile."""
return self.inputfile.set_comment(*args, **kwargs)
def properties(self):
"""Return the list of properties with a 'set_' function."""
funcs = filter(lambda s: s.startswith('set_'), dir(self))
return [ f.split('set_', 1)[-1] for f in funcs ]
@staticmethod
def _link(target, pointer):
"""
Create the symbolic link target <-- pointer.
Overwrite an existing link, but don't overwrite a file.
"""
atarget = realpath(target)
pointerdir = realpath(dirname(pointer))
apointer = join(pointerdir, basename(pointer))
if not exists(pointerdir):
subprocess.call(('mkdir', '-p', pointerdir))
try:
symlink(atarget, apointer)
except OSError:
try:
oldtarget = realpath(readlink(apointer))
if oldtarget == atarget:
return
else:
subprocess.call(('ln', '-fs', atarget, apointer))
except OSError:
raise OSError("Unable to link the files. " +
"Maybe {0} exists and is not a link.".format(apointer))

View File

@ -1,145 +0,0 @@
from __future__ import print_function, division #, unicode_literals
import warnings
from os import makedirs
from os.path import dirname, join, exists, realpath
from copy import deepcopy
from .abinitfiles import AbinitFiles
__all__ = ['FilesFile']
# =========================================================================== #
class FilesFile(object):
"""
A .files file used as input for abinit.
**Keyword arguments:**
input: Input file.
output: Output file.
idat_root: Root for input data.
odat_root: Root for output data.
tmp_root: Root for temporary files.
pseudodir: The directory for the pseudopotentials.
pseudos: List of pseudopotential files.
.. code-block:: python
>> filesfile = Filesfile('run/abinit.files',
.. input='abinit.in',
.. output='abinit.out',
.. idat_root='run/data_files/idat_',
.. odat_root='run/data_files/odat_',
.. tmp_root='run/data_files/tmp_',)
.. pseudodir='/path/to/pseudopotential/directory',)
>>
>> filesfile.set_pseudos(['H.psp', 'O.psp'])
>> filesfile.write()
>> with open('run/abinit.files', 'r') as f: print f.read()
../CalcRoot.in
../CalcRoot.out
data_files/idat_
data_files/odat_
tmp_files/tmp_
/path/to/pseudopotential/directory/H.psp
/path/to/pseudopotential/directory/O.psp
"""
def __init__(self, name='calc.files', **kwargs):
self.name = name
self.input = 'calc.in'
self.output = 'calc.out'
self.idat_root = 'idat_calc'
self.odat_root = 'odat_calc'
self.tmp_root = 'tmp_calc'
self.pseudodir = '.'
self.pseudos = list()
for (arg, val) in kwargs.items():
getattr(self, 'set_' + arg)(val)
def set_input(self, name):
"""Set the input file."""
self.input = name
def set_output(self, name):
"""Set the output file."""
self.output = name
def set_idat_root(self, name):
"""Set root for input data."""
self.idat_root = name
def set_odat_root(self, name):
"""Set root for output data."""
self.odat_root = name
def set_tmp_root(self, name):
"""Set root for temporary files."""
self.tmp_root = name
def set_pseudodir(self, directory):
"""Set the directory for the pseudopotentials."""
self.pseudodir = realpath(directory)
def set_pseudos(self, *pseudos):
"""
Sets the pseudopotential files.
**Arguments:**
pseudos:
Pseudopotential files.
Both of these syntax work::
>> f.set_pseudos('H.psp', 'O.psp')
>> f.set_pseudos(['H.psp', 'O.psp'])
"""
if not pseudos:
self.pseudos = list()
return
elif '__iter__' in dir(pseudos[0]):
pseudos = tuple(pseudos[0])
self.pseudos = pseudos
@property
def pseudos(self):
"""Pseudopotential files."""
return [ join(self.pseudodir, pseudo) for pseudo in self._pseudos ]
@pseudos.setter
def pseudos(self, vals):
self._pseudos = deepcopy(vals)
@property
def dirname(self):
"""The directory containing the file."""
return dirname(self.name)
def check_pseudos(self):
"""Issue a warning for each pseudopotential file not found."""
for pseudo in self.pseudos:
if not exists(pseudo):
warnings.warn('Pseudopotential file not found: ' + pseudo)
def __str__(self):
lines = [self.input, self.output, self.idat_root, self.odat_root,
self.tmp_root] + self.pseudos
return '\n'.join(lines) + '\n'
def write(self):
"""Write the file."""
self.check_pseudos()
if self.dirname and not exists(self.dirname):
makedirs(self.dirname)
with open(self.name, 'w') as f:
f.write(str(self))

File diff suppressed because it is too large Load Diff

View File

@ -1,394 +0,0 @@
from __future__ import print_function, division #, unicode_literals
import string
import os.path
import warnings
import numpy as np
from os import makedirs
from os.path import dirname, abspath, exists
from collections import OrderedDict
from copy import deepcopy
from .utils import flatten, listify, is_number, is_iter
from .variable import InputVariable, SpecialInputVariable, _UNITS
__all__ = [
'InputFile',
'VariableBlock',
]
_input_variable_blocks = OrderedDict((
('Datasets', '''
ndtset jdtset udtset
'''),
('Basis set', '''
ecut ecutsm
'''),
('Bands', '''
nband nbdbuf
'''),
('k-point grid', '''
kptopt nkpt kpt ngkpt kptrlatt
nshiftk shiftk kptbounds kptns
'''),
('Models', '''
ixc ppmodel ppmfreq usepawu upawu jpawu
'''),
('PAW options', '''
bxctmindg dmatpawu dmatpuopt dmatudiag iboxcut
jpawu lpawu lexexch mqgriddg ngfftdg
pawcpxocc pawcross pawecutdg pawfatbnd
pawlcutd pawlmix pawmixdg pawnhatxc pawnphi
pawntheta pawnzlm pawoptmix pawovlp
pawprtden pawprtdos pawprtvol pawprtwf
pawspnorb pawstgylm pawsushat pawusecp
pawxcdev prtcs prtefg prtfc prtnabla
ptcharge quadmom spnorbscl usedmatpu upawu
useexexch usepawu usexcnhat
'''),
('SCF procedure', '''
iscf nstep nline tolvrs tolwfr
toldfe toldff tolimg tolmxf tolrff
'''),
('KSS generation', '''
kssform nbandkss
'''),
('GW procedure', '''
optdriver gwcalctyp spmeth nkptgw kptgw
bdgw nqptdm qptdm
'''),
('GW param', '''
ecuteps ecutsigx ecutwfn nomegasf
nfreqim nfreqre freqremax npweps rhoqpmix
'''),
('GW options', '''
userre awtr symchi gwpara symsigma gwmem fftgw
'''),
('Structural optimization', '''
amu bmass delayperm diismemory dilatmx dtion dynimage
ecutsm friction fxcartfactor getcell getxcart getxred
goprecon goprecprm iatcon iatfix iatfixx iatfixy iatfixz
imgmov ionmov istatimg mdtemp mdwall natfix natfixx
natfixy natfixz natcon nconeq nimage nnos noseinert
ntime ntimimage optcell pimass pitransform prtatlist qmass
random_atpos restartxf signperm strfact strprecon strtarget
tolimg tolmxf vel vis wtatcon
'''),
('Response function', '''
bdeigrf elph2_imagden esmear frzfermi
ieig2rf mkqmem mk1mem prepanl prepgkk
prtbbb rfasr rfatpol rfddk rfdir rfelfd
rfmeth rfphon rfstrs rfuser rf1atpol rf1dir
rf1elfd rf1phon rf2atpol rf2dir rf2elfd
rf2phon rf3atpol rf3dir rf3elfd rf3phon
sciss smdelta td_maxene td_mexcit
'''),
('Wannier 90', '''
w90iniprj w90prtunk
'''),
('Parallelisation', '''
gwpara localrdwf ngroup_rf npband npfft
npimage npkpt npspinor paral_kgb
paral_rf use_gpu_cuda
'''),
('Unit cell', '''
acell angdeg rprim ntypat znucl natom typat xred xcart
'''),
('Printing', '''
prtvol enunit
'''),
('Files', '''
irdddk irdden ird1den irdqps irdkss irdscr
irdsuscep irdwfk irdwfq ird1wf getcell
getddk getden getgam_eig2nkq getkss getocc
getqps getscr getsuscep getvel getwfk
getwfq getxcart getxred get1den get1wf
'''),
))
# =========================================================================== #
class VariableBlock(list):
"""A block of abinit variables."""
def __init__(self, title, register=''):
# The block title
self.title = title
# A register of all possible input variable.
if isinstance(register, str):
self.register = register.split()
else:
self.register = list(register)
def clear(self):
del self[:]
def __str__(self):
lines = ['#== {0} ==#'.format(self.title)]
for variable in sorted(self):
svar = str(variable)
if svar:
lines.append(svar)
return '\n'.join(lines)
# =========================================================================== #
class InputFile(object):
"""
Abinit input file.
.. code-block:: python
>> f = InputFile('myfile.in')
>> f.read('otherfile.in')
>>
>> f.ndtset = 4 # Variables are set with integers,
>> f.jdtset = [1,2,3,4] # or lists.
>>
>> f.ecut = 25. # Here is a floats.
>> f.ecut = '25.' # But using strings is always possible.
>>
>> f.tolwfr = 1e-20 # Scientific notation
>> f.tolwfr = '1d-20' # is translated like this.
>>
>> f.rprim = [[0.0,0.5,0.5], [0.5,0.0,0.5], [0.5,0.5,0.0]] # These three lines
>> f.rprim = [ 0.0,0.5,0.5 , 0.5,0.0,0.5 , 0.5,0.5,0.0] # produce exactly
>> f.rprim ='\\n 0.0 0.5 0.5 \\n 0.5 0.0 0.5 \\n 0.5 0.5 0.0' # the same result.
>>
>> f.nband4 = 300 # Dataset-specific variable.
>>
>> f.udtset = '2 3' # We will have to remember that:
>> f.nband1__s = 100 # ':' <==> '__s' (start)
>> f.nband1__i = 50 # '+' <==> '__i' (increment)
>> f.ecut__a2 = 20.0 # '?' <==> '__a' (any)
>>
>> f.istwfk = '*1' # In some cases, string is the only way!
>>
>> f.tolvrs = None # Unset a variable. It won't appear in the file.
>>
>> f.fuzzy = 10 # But non-existent variables are written anyway!
>>
>> f.ecut = '100 eV' # This is OK but not recommended since variables
>> f.ecut = [100, 'eV'] # are converted to default units when read from file.
>>
>> f.set_comment('''This is a comment.
.. It will be printed at the top of the file.''')
>>
>> f.write()
See also the function :func:`~abipy.htc.InputFile.set_variables`.
return self.variables
"""
_blocks = _input_variable_blocks
def __init__(self, name='abinit.in'):
self.__dict__['name'] = str(name)
self.__dict__['variables'] = dict()
self.__dict__['_comment'] = str()
self.__dict__['variables_blocks'] = list()
for (name, register) in _input_variable_blocks.items():
self.variables_blocks.append(VariableBlock(name, register))
self.variables_blocks.append(VariableBlock('Other'))
def __str__(self):
lines = list()
# Comments
if self.comment:
lines.append(self.comment)
lines.append('')
# Clear blocks
for block in self.variables_blocks:
block.clear()
# Sort variables in blocks
for name, value in self.variables.items():
variable = SpecialInputVariable(name, value)
placed = False
for block in self.variables_blocks:
if variable.basename in block.register:
block.append(variable)
placed = True
break
if not placed:
self.variables_blocks[-1].append(variable)
# Make the string
for block in self.variables_blocks:
if block:
lines.append(str(block))
lines.append('')
block.clear()
return '\n'.join(lines)
def __setattr__(self, name, value):
"""
F.__setattr__('name', value) <==> F.name = value
Declare a variable in the internal dictionary.
"""
self.set_variable(name, value)
def set_name(self, name):
"""Set the name of the file."""
self.__dict__['name'] = name
@property
def path(self):
"""The absolute path."""
return abspath(self.name)
@property
def exists(self):
"""True if self.path exists."""
return os.path.exists(self.path)
@property
def comment(self):
return self._comment
def set_comment(self, comment):
"""Set a comment to be included at the top of the file."""
lines = [ '# ' + l.lstrip('#').strip() for l in comment.splitlines() ]
self.__dict__['_comment'] = '\n'.join(lines)
def write(self, name=None):
"""Write the inputs to the file."""
if name is None:
name = self.name
if not exists(dirname(self.name)):
makedirs(dirname(self.name))
with open(name, 'w') as f:
f.write(str(self))
def clear(self):
"""Clear variables."""
self.variables.clear()
for block in self.variables_blocks:
block.clear()
def read_string(self, bigstring):
"""Initialize all variables from a string."""
# Split the big string into parts
parts = list()
for line in bigstring.splitlines():
line = line.replace('=', ' ').split('#')[0].strip()
parts.extend(line.split())
# Make a list of variable string declaration
var_list, var_string = list(), ''
for part in parts:
if not part:
continue
if part[0].isalpha() and part not in _UNITS:
if var_string:
var_list.append(var_string)
var_string = ''
var_string += ' ' + part
if var_string:
var_list.append(var_string)
# Initialize all variables.
for var_string in var_list:
variable = SpecialInputVariable.from_str(var_string)
self.variables[variable.name] = variable.get_value()
@classmethod
def from_str(cls, bigstring):
"""Initialize from a string."""
inputfile = cls()
inputfile.read_string(bigstring)
def read(self, file):
"""
Reads the content of an input file and store the variables in the
internal dictionary with the proper type. Comments are thrown away.
"""
self.clear()
with open(file, 'r') as f:
self.read_string(f.read())
def set_variable(self, name, value):
"""Set a single variable."""
self.variables[name] = value
def set_variables(self, variables=None, dataset=0, **kwargs):
"""
Sets variables by providing a dictionary, or expanding a dictionary,
and possibly append them by a dataset index.
.. code-block:: python
>> kpoint_grid_shifted = {
>> 'kptopt' : 1,
>> 'ngkpt' : 3*[4],
>> 'nshiftk' : 4,
>> 'shiftk' : [[0.5,0.5,0.5],
>> [0.5,0.0,0.0],
>> [0.0,0.5,0.0],
>> [0.0,0.0,0.5]],}
>>
>> kpoint_grid_unshifted = {
>> 'kptopt' : 1,
>> 'ngkpt' : 3*[4],
>> 'nshiftk' : 1,
>> 'shiftk' : [0,0,0],}
>>
>> cell = {
>> 'ntypat' : 1
>> 'znucl' : 6.0
>> 'natom' : 2
>> 'typat' : [1, 1]
>> 'xred' : [[0,0,0],[0.25,0.25,0.25]]
>> 'acell' : 3*[6.9]
>> 'rprim' : [[0.0,0.5,0.5],
>> [0.5,0.0,0.5],
>> [0.5,0.5,0.0]]}
>>
>> f = InputFile()
>> f.set_variables(ndtset=3, ecut=4.0, ecutsm=0.5)
>>
>> f.set_variables(cell) # These two lines
>> f.set_variables(**cell) # are equivalent.
>>
>> # Here we append a dataset index at the end of all variables.
>> f.set_variables(kpoint_grid_shifted, dataset=1)
>> f.set_variables(kpoint_grid_unshifted, dataset=[2, 3])
>>
>> f.write('myfile.in') # The name was not set at initialization.
"""
if variables is None:
variables = dict()
variables.update(kwargs)
if not dataset:
dataset = ['']
for ds in listify(dataset):
for (key, val) in variables.items():
newkey = key + str(ds)
self.set_variable(newkey, val)
def get_variables(self):
"""Return a dictionary of the variables."""
return deepcopy(self.variables)
def get_variable(self, variable):
"""Return the value of a variable, or None if it is not set."""
return self.variables.get(variable)

View File

@ -1,806 +0,0 @@
from __future__ import print_function, division #, unicode_literals
from os import makedirs
from os.path import basename, dirname, join, abspath, exists, realpath
from .utils import listify
__all__ = [
'JobFile',
'PBSJobFile',
'SGEJobFile',
'SlurmJobFile',
'MoabJobFile',
]
# =========================================================================== #
class JobFile(object):
"""
The job file is organized as follow::
#!/bin/csh # 1) Shell specification.
#
#PBS -N jobname # 2) Submission commands.
#PBS -l walltime=48:00:00 # Depends on the subclass used.
#PBS -l nodes=4:ppn=12
set MPIRUN="mpiexec" # 3) Declarations.
set EXECUTABLE=/path/to/executable # These are also properties
set INPUT=calculation.in # of the jobfile object.
set LOG=calculation.log
module load intel-compilers # 4) Modules.
module load MPI/Intel/mvapich2
cd ${PBS_O_WORKDIR} # 5) Lines before execution.
limit stacksize unlimited
$MPIRUN $EXECUTABLE < $INPUT > $LOG # 6) Execution line.
echo "Job done!" # 7) Lines after execution.
date
.. attributes:
shell:
The shell binary to be used. E.g. '/bin/csh'.
Default is '/bin/bash'.
mpirun:
The mpi runner. E.g. 'mpiexec -npernode 6'.
Default is none.
executable:
The binary to be executed. Default is abinit.
bindir:
The directory in which to look for binaries. Default is none.
input:
The input file to feed in the executable as the standard input.
Mandatory.
log:
The file into which the standard output is redirected.
Default is 'log'.
stderr:
The file into which the standard error is redirected.
Default is 'stderr'.
modules:
The modules which will be loaded with 'module load'.
Default is none.
lines_before:
Lines before the main execution.
Default is none.
lines_after:
Lines after the main execution.
Default is none.
other_lines:
Other lines your job submission script would like to have.
Must be preceded by the approbriate tag (#!, #PBS).
Default is none.
submission_command:
The command which should be used to launch the job.
E.g. 'qsub', 'bqsub', 'sbatch'.
Default depends on the job type.
"""
_executable = 'abinit'
_mpirun = ''
_modules = list()
_other_lines = list()
_lines_before = list()
_lines_after = list()
def __init__(self, name='job.sh', **kwargs):
# Name
self.name = name
self.absdir = realpath(dirname(self.name))
self.absname = realpath(self.name)
# Shell
self._shell = '/bin/bash'
# Execution lines
self.input = ''
self.log = 'log'
self.stderr = 'stderr'
self.executable = 'abinit'
self.bindir = ''
self.mpirun = ''
# Modules
self.modules = list()
# Other lines
self.other_lines = list()
self.lines_before = list()
self.lines_after = list()
# Command used to submit the job
self.submission_command = 'qsub'
# Set attributes
for (arg, val) in kwargs.items():
try:
getattr(self, 'set_' + arg)(val)
except:
pass
def __str__(self):
lines = []
def app(line):
if '__iter__' in dir(line):
lines.extend(line)
else:
lines.append(line)
# Shell line
app('#!' + self.shell)
app('')
# Submission instructions
app(self._get_command_lines())
# Other submission inscrutions
app(self.other_lines)
app('')
# Declarations
for (key, value) in [('MPIRUN', self.mpirun),
('EXECUTABLE', self.executable),
('INPUT', self.input),
('LOG', self.log),
('STDERR', self.stderr)]:
app(self._declare(key, value))
app('')
# Modules
for module in self.modules:
app('module load ' + module)
app('')
# Lines before execution
app(self.lines_before)
app('')
# Execution lines
if 'csh' in self.shell:
execline = "($MPIRUN $EXECUTABLE < $INPUT > $LOG) >& $STDERR"
else:
execline = "$MPIRUN $EXECUTABLE < $INPUT > $LOG 2> $STDERR"
app(execline)
app('')
# Lines after execution
app(self.lines_after)
app('')
return "\n".join(lines)
def write(self, name=None):
"""Write the file."""
if name is None:
name = self.name
if self.dirname and not exists(self.dirname):
makedirs(self.dirname)
with open(name, 'w') as f:
f.write(str(self))
def _get_command_lines(self):
"""Return the lines specifying instructions for job submission."""
return list()
def _declare(self, key, val):
"""Return a lines setting a variable."""
if 'csh' in self.shell:
declare = 'set '
else:
declare = ''
return declare + key + '=' + val
def _set_property(self, name, *args, **kwargs):
"""Set a property through the corresponding set_ function."""
return getattr(self, 'set_' + key)(*args, **kwargs)
@property
def dirname(self):
"""The directory containing the file."""
return dirname(self.name)
@property
def path(self):
"""The path of the file."""
return abspath(self.name)
@property
def basename(self):
"""The base name of the file."""
return basename(self.name)
@classmethod
def properties(cls):
"""Return the list of properties with a set function."""
funcs = filter(lambda s: s.startswith('set_'), dir(cls))
return [ f.split('set_', 1)[-1] for f in funcs ]
@property
def executable(self):
return join(self.bindir, self._executable)
@executable.setter
def executable(self, executable):
self._executable = basename(executable)
if basename(executable) != executable:
self.set_bindir(dirname(executable))
@property
def mpirun(self):
return '"' + self._mpirun.strip('"').strip("'") + '"'
@mpirun.setter
def mpirun(self, mpirun):
self._mpirun = str(mpirun)
@property
def shell(self):
return self._shell
@shell.setter
def shell(self, shell):
if shell == basename(shell):
self._shell = join('/bin', shell)
else:
self._shell = abspath(shell)
@property
def modules(self):
return self._modules
@modules.setter
def modules(self, modules):
self._modules = listify(modules)
@property
def other_lines(self):
return self._other_lines
@other_lines.setter
def other_lines(self, lines):
self._other_lines = listify(lines)
@property
def lines_before(self):
return self._lines_before
@lines_before.setter
def lines_before(self, lines):
self._lines_before = listify(lines)
@property
def lines_after(self):
return self._lines_after
@lines_after.setter
def lines_after(self, lines):
self._lines_after = listify(lines)
def set_shell(self, shell):
"""
Sets the shell type. The argument can either be an absolute path,
or just the shell type e.g. bash, csh, tcsh, in which case
the executable is assumed to be located in /bin/.
The shell also determine how a variable is declared.
"""
self.shell = shell
def set_mpirun(self, mpirun):
"""
Set the mpi runner to execute the program.
E.g. 'mpiexec -npernode 6', 'mpirun -np 12', ''.
"""
self.mpirun = mpirun
def set_bindir(self, bindir):
"""Set the directory for binaries (abinit, mrgscr...)."""
self.bindir = realpath(bindir)
def set_executable(self, executable):
"""Set the executable to use."""
self.executable = executable
def set_input(self, input):
"""Set the input file for the main executable."""
self.input = input
def set_log(self, log):
"""Set the log file to collect standard output of the executable."""
self.log = log
def set_stderr(self, stderr):
"""Set the log file to collect standard output of the executable."""
self.stderr = stderr
def set_modules(self, *modules):
"""Set one or many modules to be loaded."""
self.modules = modules
def set_other_lines(self, *lines):
"""Set other command lines for the batch submission system."""
self.other_lines = lines
def set_lines_before(self, *lines):
"""Set one or many lines to be executed before the main execution."""
self.lines_before = lines
def set_lines_after(self, *lines):
"""Set one or many lines to be executed after the main execution."""
self.lines_after = lines
def set_submission_command(self, command):
"""
Sets the command used for job submission,
e.g. qsub, bqsub, sbatch, ...
"""
self.submission_command = command
# =========================================================================== #
class PBSJobFile(JobFile):
"""
Portable Batch System.
.. attributes:
jobname:
Name of the job.
runtime:
Maximum time for the job.
nodes:
Number of nodes on which to run the job.
ppn:
Number of processors per node.
memory:
Memory per node. E.g. '48G'.
queue:
The queue to which the job is submitted.
mail:
The mail to which a notification will be sent.
mail_options:
The conditions under which a mail will be sent.
E.G. 'abe'.
submission_command:
default is 'qsub'.
See man qsub for more info.
"""
__doc__ += "\n" + JobFile.__doc__
_command = "#PBS "
def __init__(self, **kwargs):
kwargs.setdefault('submission_command', 'qsub')
JobFile.__init__(self, **kwargs)
nodes = None
def set_nodes(self, val):
self.nodes = val
ppn = None
def set_ppn(self, val):
self.ppn = val
memory = None
def set_memory(self, val):
self.memory = val
runtime = None
def set_runtime(self, val):
"""Either set the numer of hours, or a triplet for (hours,min,sec)."""
if isinstance(val, int):
val = [val, 0, 0]
self.runtime = val
jobname = None
def set_jobname(self, val):
self.jobname = val
queue = None
def set_queue(self, val):
self.queue = val
mail = None
def set_mail(self, val):
self.mail = val
mail_options = None
def set_mail_options(self, val):
self.mail_options = val
def _get_command_lines(self):
"""Return the lines specifying instructions for job submission."""
lines = list()
def add(line):
lines.append(self._command + line) # + '\n')
if self.jobname:
add('-N ' + str(self.jobname))
if self.runtime:
add('-l walltime={0}:{1}:{2}'.format(*self.runtime))
if self.nodes and self.ppn:
add('-l nodes=' + str(self.nodes) + ':ppn=' + str(self.ppn))
if self.memory:
add('-l mem=' + str(self.memory))
if self.queue:
add('-q ' + self.queue)
if self.mail:
add('-M ' + self.mail)
if self.mail_options:
add('-m ' + self.mail_options)
return lines
# =========================================================================== #
class SGEJobFile(JobFile):
"""
Sun Grid Engine.
.. attributes:
jobname:
Name of the job.
runtime:
Maximum time for the job.
nproc:
Number of processors.
queue:
The queue to which the job is submitted.
environment:
The parallel environment under which the job is ran.
memory:
The requested memory, in M.
mail:
The mail to which a notification will be sent.
mail_options:
The conditions under which a mail will be sent.
E.G. 'abe'.
submission_command:
default is 'qsub'.
See man qsub for more info.
"""
__doc__ += "\n" + JobFile.__doc__
_command = "#$ "
def __init__(self, **kwargs):
kwargs.setdefault('submission_command', 'qsub')
JobFile.__init__(self, **kwargs)
jobname = None
def set_jobname(self, val):
self.jobname = val
runtime = None
def set_runtime(self, val):
"""Either set the numer of hours, or a triplet for (hours,min,sec)."""
if isinstance(val, int):
val = [val, 0, 0]
self.runtime = val
nproc = None
def set_nproc(self, val):
self.nproc = val
queue = None
def set_queue(self, val):
self.queue = val
environment = None
def set_environment(self, val):
self.environment = val
memory = None
def set_memory(self, val):
self.memory = val
mail = None
def set_mail(self, val):
self.mail = val
mail_options = None
def set_mail_options(self, val):
self.mail_options = val
def _get_command_lines(self):
"""Return the lines specifying instructions for job submission."""
lines = list()
def add(line):
lines.append(self._command + line) # + '\n')
if self.jobname:
add('-N ' + str(self.jobname))
if self.runtime:
add('-l h_rt={0}:{1}:{2}'.format(*self.runtime))
if self.environment and self.nproc:
line = '-pe ' + self.environment + ' ' + str(self.nproc)
if self.memory:
line += ' -l mem=' + str(self.memory)
add(line)
if self.queue:
add('-q ' + self.queue)
if self.mail:
add('-M ' + self.mail)
if self.mail_options:
add('-m ' + self.mail_options)
return lines
# =========================================================================== #
class SlurmJobFile(JobFile):
"""
Simple Linux Utility for Resource Management.
.. Attributes:
jobname:
Name of the job.
time:
Maximum time for the job.
ntasks:
The number of processes.
cpus_per_task:
The number of cpus per process.
mem_per_cpu:
The memory per cpu.
partition:
The partition...
mail_user:
The mail to which a notification is sent.
mail_type:
The conditions unde which to send a mail.
submission_command:
default is 'sbatch'.
"""
__doc__ += "\n" + JobFile.__doc__
_command = "#SBATCH "
def __init__(self, **kwargs):
kwargs.setdefault('submission_command', 'sbatch')
JobFile.__init__(self, **kwargs)
jobname = None
def set_jobname(self, val):
self.jobname = val
time = None
def set_time(self, val):
"""Either set the number of hours, or a triplet for (hours,min,sec)."""
if isinstance(val, int):
val = [val, 0, 0]
self.time = val
def set_runtime(self, val):
self.set_time(val)
ntasks = None
def set_ntasks(self, val):
self.ntasks = val
ntasks_per_node = None
def set_ntasks_per_node(self, val):
self.ntasks_per_node = val
cpus_per_task = None
def set_cpus_per_task(self, val):
self.cpus_per_task = val
mem_per_cpu = None
def set_mem_per_cpu(self, val):
self.mem_per_cpu = val
partition = None
def set_partition(self, val):
self.partition = val
mail_user = None
def set_mail_user(self, val):
self.mail_user = val
mail_type = None
def set_mail_type(self, val):
self.mail_type = val
def _get_command_lines(self):
"""Return the lines specifying instructions for job submission."""
lines = list()
def add(line):
lines.append(self._command + line) # + '\n')
if self.jobname:
add('--job-name=' + str(self.jobname))
if self.time:
add('--time={0}:{1}:{2}\n'.format(*self.time))
if self.ntasks:
add('--ntasks=' + str(self.ntasks))
if self.partition:
add('--partition=' + self.partition)
if self.ntasks_per_node:
add('--ntasks-per-node=' + str(self.ntasks_per_node))
if self.cpus_per_task:
add('--cpus-per-task=' + str(self.cpus_per_task))
if self.mem_per_cpu:
add('--mem-per-cpu=' + str(self.mem_per_cpu))
if self.mail_user:
add('--mail-user=' + self.mail_user)
if self.mail_type:
add('--mail-type=' + self.mail_type)
return lines
# =========================================================================== #
class MoabJobFile(JobFile):
"""
Moab Workload Manager
.. Attributes:
start_after:
Declares the time after which the job is eligible for execution.
Syntax: (brackets delimit optional items with the default being
current date/time): [CC][YY][MM][DD]hhmm[.SS]
account:
Defines the account associated with the job.
hold:
Put a user hold on the job at submission time.
combine:
Combine stdout and stderr into the same output file.
resources:
Defines the resources that are required by the job.
mail:
Defines the set of conditions (a=abort,b=begin,e=end) when the
server will send a mail message about the job to the user.
jobname:
Gives a user specified name to the job.
priority:
Assigns a user priority value to a job.
queue:
Run the job in the specified queue (pdebug, pbatch, etc.). A host
may also be specified if it is not the local host.
rerun:
Automatically rerun the job is there is a system failure.
env:
Specifically adds a list of environment variables that are exported
to the job.
allenv:
Declares that all environment variables in the msub environment are
exported to the batch job.
"""
__doc__ += "\n" + JobFile.__doc__
_command = "#MSUB "
def __init__(self, **kwargs):
kwargs.setdefault('submission_command', 'srun')
JobFile.__init__(self, **kwargs)
start_after = None
def set_start_after(self, val):
self.start_after = val
account = None
def set_account(self, val):
self.account = val
hold = None
def set_hold(self, val):
self.hold = val
combine = None
def set_combine(self, val):
self.combine = val
resources = dict()
def set_resources(self, val):
self.resources = val
mail = None
def set_mail(self, val):
self.mail = val
jobname = None
def set_jobname(self, val):
self.jobname = val
priority = None
def set_priority(self, val):
self.priority = val
queue = None
def set_queue(self, val):
self.queue = val
rerun = None
def set_rerun(self, val):
self.rerun = val
env = None
def set_env(self, val):
self.env = val
allenv = None
def set_allenv(self, val):
self.allenv = val
def _get_command_lines(self):
"""Return the lines specifying instructions for job submission."""
lines = list()
def add(line):
lines.append(self._command + line) # + '\n')
if self.start_after:
add('-a ' + self.start_after)
if self.account:
add('-A ' + self.account)
if self.hold is True:
add('-h ')
if self.combine is True:
add('-j oe')
if self.resources:
for (arg, val) in self.resources.items():
add('-l ' + arg + '=' + val)
if self.mail:
add('-m ' + self.mail)
if self.jobname:
add('-N ' + self.jobname)
if self.priority:
add('-p ' + self.priority)
if self.queue:
add('-q ' + self.queue)
if self.rerun is True:
add('-r y')
if self.env:
add('-v ' + ','.join(self.env))
if self.allenv is True:
add('-V')
return lines

View File

@ -1,914 +0,0 @@
from __future__ import print_function, division #, unicode_literals
import sys
import os
import warnings
import subprocess
import numpy as np
from os.path import basename, dirname, join, relpath, abspath
from argparse import ArgumentParser, RawDescriptionHelpFormatter
from collections import OrderedDict
from copy import deepcopy
from abipy.core import release, Structure, Density
from .utils import parse_ewc
from .abinitinput import AbinitInput
__all__ = [
'Launcher',
'MassLauncher',
]
# =========================================================================== #
class LauncherArgParser(ArgumentParser):
"""
Base parser used in Launcher to parse the arguments provided by the user
when the function 'execute' is called. The parser consists of a top level
parser responsible for parsing global options such as verbosity level,
version, etc, and sub-parsers for the different sub-commands.
Every class that inherits from Launcher, MassLauncher should define
a parser that inherits from this base class, and use register_subparser
to extend or customize the subparsers. The list of commands supported
by the instance is stored in self.commands so that we know whether
a particular sub-parser can handle the argument or if it should delegate
the superclass.
"""
def __init__(self, *args, **kwargs):
#formatter_class=RawDescriptionHelpFormatter)
ArgumentParser.__init__(self, *args, **kwargs)
# Create the top-level parse responsible for parsing global options
# such as verbosity level, version ....
# NOTE: except for verbose and version, any other option for the top
# level parser should be stored in a variable named --top-optname
# so that we don't pollute the namespace of the subcommands
self.add_argument('-v', '--verbose', default=0, action='count', # -vv --> verbose=2
help='verbose, can be supplied multiple times to increase verbosity')
self.add_argument('--version', action='version', version="abipy " + release.version)
# Create the parser for the sub-commands
self.subparsers = self.add_subparsers(dest='command', help='sub-command help')
# Workaround. see http://stackoverflow.com/questions/8757338/sub-classing-the-argparse-argument-parser
# I know I shouldn't do this, but I don't want to wrap the parser in the object.
self.subparsers._parser_class = ArgumentParser
p_make = self.subparsers.add_parser('make', help='Make files and directories')
p_make.add_argument('-f', '--force', action='store_true', default=False, help='Force file creation')
self.register_subparser("make", p_make)
p_submit = self.subparsers.add_parser('submit', help='Submit the calculation to a batch server.')
#p_submit.add_argument('bar', type=int, help='bar help')
self.register_subparser("submit", p_submit)
p_run = self.subparsers.add_parser('run', help='Run the calculation from the shell.')
#p_run.add_argument('-n', '--py-nthreads', metavar='NUM', type=int, default=1, help='Number of jobs.')
self.register_subparser("run", p_run)
p_report = self.subparsers.add_parser('report', help='Tell if the calculation completed or not.')
#p_report.add_argument('bar', type=int, help='bar help')
self.register_subparser("report", p_report)
p_inspect = self.subparsers.add_parser('inspect', help='Inspect files using EDITOR.')
p_inspect.add_argument('what_inspect', metavar='character(s)', default = "o",
help='Files to inspect: i for the input, o for the output, l for log, j for the job file. f for files file\n' +
'Characters can be concatenated. Use "ol", for example, to inspect both the output and the log file.')
self.register_subparser("inspect", p_inspect)
p_clean = self.subparsers.add_parser('clean', help='Remove log, data files and temporary files.')
#p_clean.add_argument('-f', '--force', action='store_true', help='Force')
self.register_subparser("clean", p_clean)
p_destroy = self.subparsers.add_parser('destroy', help='Remove all files, including input and outputs.')
p_destroy.add_argument('-f', '--force', action='store_true', help='Force')
self.register_subparser("destroy", p_destroy)
p_show = self.subparsers.add_parser('show', help='Print the calculation name and return True.')
#p_show.add_argument('-f', '--force', action='store_true', help='Force')
self.register_subparser("show", p_show)
p_visu = self.subparsers.add_parser('visualize', #aliases=['visu'],
help='Visualize data with an external program e.g. Xcrysden.')
p_visu.add_argument('what_visualize', metavar='STRING', default = "crystal", help=' Type of data to visualize')
self.register_subparser("visualize", p_visu)
def myparse_args(self, args=None, namespace=None):
"""
Wrap the parse_args method of ArgumentParsers
:return: options, args, kwargs
where options is the default output of parse_args and kwargs is a dictionary option_name -> value
"""
if args is None:
self.parse_args(args=["--help"], namespace=namespace)
if '__iter__' not in dir(args): args = [args]
# Call the "true" parse_args
options = self.parse_args(args=args, namespace=namespace)
args = list()
kwargs = deepcopy(vars(options))
return options, args, kwargs
@property
def commands(self):
"The commands registered in the parser"
return self._cmd2subparser.keys()
def can_handle(self, command):
"True if the parser can handle command"
return command in self.commands
def iter_cmdsubparser(self):
"Iterate over (command_string, subparser)"
for tup in self._cmd2subparser.items(): yield tup
def register_subparser(self, command, subparser, solve_conflict=False):
"""
Register the subparser associate to a given command.
:arg solve_conflict: By defaut it's not possible to override an existent subparser associated
to the same command. Use solve_conflict if subparser should replace the old one.
"""
if not hasattr(self, "_cmd2subparser"): self._cmd2subparser = OrderedDict()
if command in self._cmd2subparser and not solve_conflict:
raise ValueError("Cannot overwrite subparser for command %s. Use solve_conflict=True" % command)
self._cmd2subparser[command] = subparser
def unregister_subparser(self, command):
"""Unregister the subparser associated to the given command. Return the subparser removed"""
return self._cmd2subparser.pop(command)
# =========================================================================== #
class LauncherError(Exception):
"""base class for the exceptions raised by Launcher."""
class Launcher(AbinitInput):
"""
A more powerful version of :class:`~abipy.htc.AbinitInput`.
Allows to run a calculation, either from a script or from command line.
.. code-block:: python
>> calc = Launcher('Mycalc/root',
.. jobtype=None,
.. pseudodir='/path/to/pseudos/',
.. pseudos=['14si.pspnc'],
.. bindir='/path/to/binaries/')
>>
>> calc.read('myinput.in')
>>
>> # Write the files.
>> calc.make()
>>
>> # Run the calculation with abinit.
>> calc.run()
>>
>> # Inquire about the calculation status.
>> status = calc.report()
>>
>> if status == 'Completed':
.. # Remove log and data files.
.. calc.clean(force=True)
You can perform all these actions from the command line, using the function 'execute'.
"""
Error = LauncherError
# Parser class and instance are stored as class attributes.
ArgParser = LauncherArgParser
argparser = LauncherArgParser()
def output_files(self):
"""Return all output files produced, in alphabetical order."""
base = self.output_name
files = [base] + [ base + a for a in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ]
return filter(os.path.exists, files)
def last_output(self):
"""Return the last output file produced."""
files = self.output_files()
if not files:
return None
return files[-1]
def idat_files(self):
"""Return all the input data files."""
files = list()
for file in os.listdir(dirname(self.idat_root)):
if file.startswith(basename(self.idat_root)):
files.append(join(dirname(self.idat_root), file))
return files
def odat_files(self):
"""Return all the output data files produced."""
files = list()
for file in os.listdir(dirname(self.odat_root)):
if file.startswith(basename(self.odat_root)):
files.append(join(dirname(self.odat_root), file))
return files
def tmp_files(self):
"""Return all the input data files produced."""
files = list()
for file in os.listdir(dirname(self.tmp_root)):
if file.startswith(basename(self.tmp_root)):
files.append(join(dirname(self.tmp_root), file))
return files
def junk_files(self):
"""Return all the junk files produced."""
files = list()
for file in os.listdir(self.jobfile.dirname):
if (file.startswith('fort.') or
file.endswith('.dat') or
file in ('_GWDIAG',)):
files.append(join(self.jobfile.dirname, file))
return files
def read_mainlog_ewc(self):
"""
Read errors, warnings and comments from the main output and the log file.
:return: Two namedtuple instances: main, log.
The lists of strings with the corresponding messages are
available in main.errors, main.warnings, main.comments, log.errors etc.
"""
from pymatgen.io.abinit.events import EventsParser
parser = EventsParser()
main_events = parser.parse(self.last_output())
log_events = parser.parse(self.log_name)
return main_events, log_events
def make(self, *args, **kwargs):
"""
Write the files.
Keyword arguments:
verbose: (0)
Print message if verbose is not zero.
"""
if kwargs.get('verbose'):
print('Writing ' + self.name)
self.write(*args, **kwargs)
def run(self, *args, **kwargs):
"""
Run the calculation by executing the job file from the shell.
Keyword arguments:
verbose: (0)
Print message if verbose is not zero.
.. warning::
This method must be thread safe since we may want to run several indipendent
calculations with different python threads.
"""
if kwargs.get('verbose'):
print('Running ' + self.name + '\n')
subprocess.call((self.jobfile.shell, self.jobfile.absname))
def submit(self, *args, **kwargs):
"""
Submit the calculation to a batch server.
Keyword arguments:
verbose: (0)
Print message if verbose is not zero.
"""
if kwargs.get('verbose'):
print('Submitting ' + self.name)
curdir = abspath(os.curdir)
os.chdir(self.jobfile.absdir)
subprocess.call((self.jobfile.submission_command, self.jobfile.basename))
os.chdir(curdir)
def clean(self, *args, **kwargs):
"""
Remove log file, data files and tmp files.
Keyword arguments:
force: (False)
Do not ask confirmation.
verbose: (0)
Print message if verbose is not zero.
"""
if kwargs.get('verbose'):
print('Cleaning ' + self.name)
destroy = [self.log_name]
for files in (self.odat_files(), self.tmp_files(), self.junk_files()):
destroy.extend(files)
if destroy:
self._remove_files(destroy, kwargs.get('force', False))
def destroy(self, *args, **kwargs):
"""
Remove all calculation files and directories, if empty.
Keyword arguments:
force: (False)
Do not ask confirmation.
verbose: (0)
Print message if verbose is not zero.
"""
if kwargs.get('verbose'):
print('Destroying ' + self.name)
destroy = [self.input_name, self.log_name, self.job_name, self.files_name]
for files in (self.output_files(), self.idat_files(),
self.odat_files(), self.tmp_files(), self.junk_files()):
destroy.extend(files)
if destroy:
self._remove_files(destroy, kwargs.get('force', False))
self._remove_directory_tree(self.dirname)
def show(self, form=str, *args, **kwargs):
"""Print the calculation name and return True."""
print(form(self.name))
return True
def inspect(self, *args, **kwargs):
"""
Inspect the input/(last) output/ log produced by the run.
:arg what_inspect:
"i" for the input, "o" for the output, "l" for log, "j" for the job file. "f" for the files file
characters can be concatenated. what="ol", for example, will inspect both the output and the log file.
The environment variable EDITOR defines the application to use (default vi).
"""
from ..tools import Editor
editor = Editor()
what_inspect = kwargs.get("what_inspect", "o")
filenames = []
if "i" in what_inspect: filenames.append(self.input_name)
if "o" in what_inspect: filenames.append(self.last_output())
if "l" in what_inspect: filenames.append(self.log_name)
if "j" in what_inspect: filenames.append(self.job_name)
if "f" in what_inspect: filenames.append(self.files_name)
editor.edit_files(filenames, ask_for_exit=True)
def visualize(self, *args, **kwargs):
# TODO Here I have to decide if this method should be defined
# in a subclass of Launcher e.g GSLauncher or in the base class
from .utils import find_file
what_visualize = kwargs.get("what_visualize", "crystal")
visualizer = "xcrysden"
#visualizer = abipy_env.get_uservar("visualizer", kwargs)
# Find the correct output file
out_files = self.odat_files()
gsfname = find_file(out_files, "GSR")
if gsfname is None:
raise RuntimeError("Cannot find GSR file among %s" % out_files)
if what_visualize == "crystal":
structure = Structure.from_file(gsfname)
structure.visualize(visualizer)()
elif what_visualize == "density":
raise NotImplementedError("den_fname?")
density = Density.from_file(den_fname)
density.visualize(visualizer)()
elif what_visualize in ["electrons", "fermisurface",]:
from ..electrons import ElectronBands
energies = ElectronBands.from_file(gsfname)
if what_visualize == "electrons": energies.plot()
if what_visualize == "fermisurface":
raise RuntimeError("No hanlder found for fermisurface")
#visu = energies.visualize(self, visualizer, structure)
#visu()
else:
raise RuntimeError("No handler found for %s" % what_visualize)
# TODO
#def __str__(self):
# string = ""
# return string
def report(self, *args, **kwargs):
"""
Print information on the calculation status and return a status.
Keyword arguments:
verbose: (0)
0 : do not print anything
> 0 : print status
> 1 : print number of errors, warnings and comments
"""
output = self.last_output()
from ..tools import StringColorizer
str_colorizer = StringColorizer(sys.stdout)
status2txtcolor = {
"Completed" : lambda string : str_colorizer(string, "green"),
"Unfinished" : lambda string : str_colorizer(string, "blue"),
"Unstarted" : lambda string : str_colorizer(string, "cyan"),
}
def color(status): return status2txtcolor[status](status)
verbose = kwargs.get('verbose', 0)
if output and self._iscomplete(output):
status = 'Completed'
msg = relpath(output) + ' : ' + color(status)
if verbose:
# Does not work!
pass
## Read the number of errors, warnings and comments
##for the (last) main output and the log file.
#main, log = self.read_mainlog_ewc()
#main_info = main.tostream(sys.stdout)
#log_info = log.tostream(sys.stdout)
#msg += "\n " + "\n ".join([main_info, log_info])
elif os.path.exists(self.log_name):
status = 'Unfinished'
msg = self.name + ' : ' + color(status)
else:
status = 'Unstarted'
msg = self.name + ' : ' + color(status)
if verbose:
print(msg)
if status == 'Completed':
pass
# Does not work!
#for w in main.warnings: print(w)
#if verbose > 1:
# for w in log.warnings: print(w)
return status
def execute(self, *args, **kwargs):
"""
Execute an action from the command line.
* make -- Write the files.
* submit -- Submit the calculation to a batch server.
* run -- Run the calculation from the shell.
* report -- Tell if the calculation completed or not.
* inspect -- Open files in EDITOR
* clean -- Remove log, data files and temporary files.
* show -- Signify that the calculation exists.
* destroy -- Remove all files, including input and outputs.
* visualize -- Visualize data.
Suppose this is the content of 'myscript.py':
.. code-block:: python
> # myscript.py
calc = Launcher('Mycalc/root', jobtype=None,
pseudodir='Data', pseudos=['14si.pspnc'],
executable='abinit')
calc.read('myinput.in')
calc.execute()
Then, from the shell, one can perform the following::
.. code-block:: python
> # bash
> python myscript.py make
Writing Mycalc/root
>
> python myscript.py show
Mycalc/root
>
> python myscript.py run
Running Mycalc/root
>
> python myscript.py report
Mycalc/root.out : Completed
>
> python myscript.py clean
Cleaning Mycalc/root
Typically, one would use the command 'submit' instead of 'run'.
"""
if not args:
args = sys.argv[1:]
options, args, kwargs = self.argparser.myparse_args(args)
if self.argparser.can_handle(options.command):
getattr(self, options.command)(*args, **kwargs)
else:
raise RuntimeError("Don't know how to handle command %s. This should not happen!" % options.command)
@staticmethod
def _remove_files(files, force=False):
"""Remove a list of file, asking confirmation."""
files = filter(os.path.exists, files)
if files and not force:
print("About to remove the following files:")
for file in files:
print(file)
proceed = raw_input("Do you want to proceed? (y/n) ")
if not proceed.lower().startswith('y'):
return
for file in files:
try:
os.remove(file)
except Exception as exc:
warnings.warn(str(exc))
@staticmethod
def _remove_directory_tree(topdir):
"""Remove a directory hierarchy, if it contains no files."""
dirs = [topdir]
for d in dirs:
for f in os.listdir(d):
sub = os.path.join(d, f)
if os.path.isdir(sub):
dirs.append(sub)
else:
return
for d in reversed(dirs):
try:
os.rmdir(d)
except OSError:
warnings.warn("Directory tree partially removed: " + topdir)
@staticmethod
def _iscomplete(output_file):
"Return True if an abinit output file is complete."
with open(output_file, 'r') as f:
lines = f.readlines()
lines.reverse()
for i in range(10):
try:
line = lines[i]
except:
return False
if 'Calculation completed.' in line:
return True
return False
# Does not work !
#from pymatgen.io.abinit.utils import abinit_output_iscomplete
#return abinit_output_iscomplete(output_file)
# =========================================================================== #
class MassLauncherArgParser(LauncherArgParser):
"""
top level parser and subparsers used by MassLauncher.
Handle all the options of Launcher and add the option -c to select the calculations.
"""
def __init__(self, *args, **kwargs):
LauncherArgParser.__init__(self, *args, **kwargs)
for (cmd, subparser) in self.iter_cmdsubparser():
# Add new option
subparser.add_argument('-c', '--calc', dest='only', nargs='*', type=str,
help="Execute command only for the selected calculations.")
# Add py_nthreads arg to the commands that support threads.
if cmd in ["run",]:
subparser.add_argument('-n', '--py_nthreads', nargs='?', type=int, default=1,
help="The number of threads (to run simultaneously).")
# Register the curried subparser so that MassLauncher will take over in execute.
self.register_subparser(cmd, subparser, solve_conflict=True)
class MassLauncher(object):
"""
To launch several nearly-identical launchers.
Acts like a list of launcher.
.. code-block:: python
>> # Let's create four calculations # The rootnames are
>> calcs = MassLauncher(4, 'Mycalcs/calc', # Mycalcs/calc1
>> jobtype='PBS', # Mycalcs/calc2
>> pseudodir='Data', # Mycalcs/calc3
>> executable='abinit') # Mycalcs/calc4
>>
>> # == Common properties ==
>> calcs.read('common.in')
>>
>> calcs.ecut = 10.
>> calcs.tolwfr = 1e-8
>> calcs.nstep = 0
>> calcs.iscf = 7
>>
>> unit_cell = {'ntypat' : 1, 'znucl' : [14], 'natom' : 2, 'typat' : [1, 1],
>> 'rprim' : [[.0, .5, .5], [.5, .0, .5], [.5, .5, .0]],
>> 'acell' : 3*[10.261], 'xred' : [[.0, .0, .0], [.25,.25,.25]]}
>> calcs.set_variables(unit_cell)
>>
>> calcs.set_pseudos('14si.pspnc')
>>
>> calcs.set_jobname('MyTest')
>> calcs.set_nodes(1)
>> calcs.set_ppn(12)
>> calcs.set_memory('1gb')
>> calcs.set_runtime(48)
>>
>> # == Specific properties ==
>> ecut = 10.
>> for calc in calcs:
>> calc.ecut = ecut
>> ecut += 5.
>>
>> # Write them all.
>> calcs.make()
"""
ArgParser = MassLauncherArgParser
argparser = MassLauncherArgParser()
def __init__(self, n=0, name='Calc', *args, **kwargs):
self._setattr(launchers = list())
self._setattr(ids = list())
if n > 0:
index_format = '0=' + str(int(np.log10(n)) + 1)
for i in range(1, n+1):
index = '{i:{f}}'.format(i=i, f=index_format)
calc_name = name + index
launcher = Launcher(calc_name, *args, **kwargs)
self.add_launcher(launcher, index=index)
def __getitem__(self, i): return self.launchers[i]
def __setitem__(self, i, calc): self.launchers[i] = calc
def __delitem__(self, i): del self.launchers[i]
def __iter__(self): return iter(self.launchers)
def __len__(self): return len(self.launchers)
def _setattr(self, **kwargs):
self.__dict__.update(kwargs)
#def __getattr__(self, name):
# """Return a function that passes the arguments to all launchers."""
# def f(*args, **kwargs):
# return [ getattr(c, name)(*args, **kwargs) for c in self ]
# return f
def _distributed(self, func_name):
"""Return a function that passes the arguments to all launchers."""
def f(*args, **kwargs):
return [ getattr(c, func_name)(*args, **kwargs) for c in self ]
f.__doc__ = getattr(self[0], func_name).__doc__
return f
def _make_distributed(f):
"""Make a function distributed to all launchers."""
def g(self, *args, **kwargs):
return self._distributed(f.__name__)(*args, **kwargs)
g.__doc__ = getattr(Launcher, f.__name__).__doc__
return g
def __setattr__(self, name, value):
"""Set an attribute to all launchers."""
return [ setattr(calc, name, value) for calc in self ]
def add_launcher(self, launcher, index=None):
"""Add a Launcher instance (or derivatives) to the list."""
if index is None:
index = str(len(self.launchers) + 1)
# maybe needs an OrderedDict here
self.launchers.append(launcher)
self.ids.append(index)
# Create missing property setter
if len(self.launchers) == 1:
for prop in self.launchers[0].properties():
setter = 'set_' + prop
if not setter in dir(self):
self.__dict__[setter] = self._distributed(setter)
def properties(self):
"""Return the list of properties with a `set_` function."""
funcs = filter(lambda s: s.startswith('set_'), dir(self))
return [ f.split('set_', 1)[-1] for f in funcs ]
def only(self, only=None):
"""Return a list of indexes and a list of calc which are included in 'only'."""
if only:
filtered = list()
for i, calc in zip(self.ids, self):
if str(i) in map(str, only):
filtered.append((i, calc))
else:
filtered= zip(self.ids, self)
return filtered
@_make_distributed
def set_pseudodir(self): return
@_make_distributed
def set_pseudos(self): return
@_make_distributed
def read(self): return
@_make_distributed
def set_variables(self): return
@_make_distributed
def set_comment(self): return
@_make_distributed
def link_idat(self): return
@_make_distributed
def link_odat(self): return
@_make_distributed
def link_io(self): return
def execute(self, *args, **kwargs):
"""
Execute an action given from the command line.
* make -- Write the files.
* submit -- Submit the calculation to a batch server.
* run -- Run the calculation from the shell.
* report -- Tell if the calculation completed or not.
* clean -- Remove log, data files and temporary files.
* show -- Signify that the calculation exists.
* destroy -- Remove all files, including input and outputs.
Command line optional arguments:
-c [id1 [,id2 [id3, ... ]]] :
Select a subset of calculations.
With the previous example, one could issue::
> python myscript.py make
Writing Mycalc/calc1
Writing Mycalc/calc2
Writing Mycalc/calc3
Writing Mycalc/calc4
>
> python myscript.py show -c 1 2
Mycalc/calc1
Mycalc/calc2
>
> python myscript.py run -c 2 3
Running Mycalc/calc2
Running Mycalc/calc3
>
> python myscript.py report
Mycalc/calc1 : Unstarted
Mycalc/calc2.out : Completed
Mycalc/calc3.out : Completed
Mycalc/calc4 : Unstarted
"""
if not args:
args = sys.argv[1:]
options, args, kwargs = self.argparser.myparse_args(args)
kwargs.update(vars(options))
if self.argparser.can_handle(options.command):
try:
nthreads = options.py_nthreads
except AttributeError:
nthreads = 1
print("About to run command", options.command," with nthreads", nthreads)
if nthreads == 1:
if options.command in dir(self):
getattr(self, options.command)(*args, **kwargs)
else:
for index, calc in self.only(options.only):
#for i, calc in zip(self.ids, self):
# if options.only and str(i) not in map(str, options.only):
# continue
getattr(calc, options.command)(*args, **kwargs)
else:
# Threaded version.
from threading import Thread
from Queue import Queue
def worker():
while True:
func, args, kwargs = q.get()
func(*args, **kwargs)
q.task_done()
q = Queue()
for i in range(nthreads):
t = Thread(target=worker)
t.setDaemon(True)
t.start()
#for (i, calc) in zip(self.ids, self):
# if options.only and i not in options.only: continue
for index, calc in self.only(options.only):
func = getattr(calc, options.command)
q.put((func, args, kwargs))
# Block until all tasks are done.
q.join()
else:
raise RuntimeError("Don't know how to handle command %s. This should not happen!" % options.command)
@_make_distributed
def report(self): return
@_make_distributed
def odat_files(self): return
@_make_distributed
def last_output(self): return
#@_make_distributed
def show(self, form=None, *args, **kwargs):
only = kwargs.get('only')
if form is None:
form = str
#@form
def tmpform(s):
return str(index) + ' ' + s
newform = lambda s: form(tmpform(s))
for index, calc in self.only(only):
calc.show(form=newform, *args, **kwargs)
return
@_make_distributed
def make(self): return
@_make_distributed
def run(self): return
@_make_distributed
def submit(self): return
@_make_distributed
def clean(self): return
@_make_distributed
def destroy(self): return

View File

@ -1,49 +0,0 @@
"""Tests for htc.FilesFile."""
from __future__ import print_function, division
import warnings
from abipy.htc.filesfile import FilesFile
from abipy.core.testing import *
# =========================================================================== #
class TestFilesFile(AbipyFileTest):
"""Unit tests for FilesFile."""
def setUp(self):
self.file = FilesFile('MyDir/MyName.files',
input='mycalc.in',
output='mycalc.out',
idat_root='i_mycalc',
odat_root='o_mycalc',
tmp_root='t_mycalc')
self.file.pseudos = ['ps1', 'ps2']
self.file.pseudodir = '/path/to/my/pseudodir'
def test_check_pseudos(self):
"""Test the user is warned of pseudopotential not found."""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
self.file.check_pseudos()
self.assertEqual(len(w), 2)
msg = str(w[-1].message)
self.assertRegexpMatches(msg, "file not found")
def test_str(self):
"""Test the FilesFile is printed correctly."""
self.assertContains("""
mycalc.in
mycalc.out
i_mycalc
o_mycalc
t_mycalc
/path/to/my/pseudodir/ps1
/path/to/my/pseudodir/ps2
""")
if __name__ == "__main__":
import unittest
unittest.main()

View File

@ -1,211 +0,0 @@
"""Tests for htc.FilesFile."""
from __future__ import print_function, division, unicode_literals
import numpy as np
import abipy.data as abidata
from abipy.core.testing import AbipyTest
from abipy.htc.input import *
class AbiInputTest(AbipyTest):
def test_si_input(self):
"""Testing Silicon input with NC pseudo."""
aequal, atrue = self.assertEqual, self.assertTrue
# Create an ABINIT input file with 1 dataset.
inp = AbiInput(pseudos="14si.pspnc", pseudo_dir=abidata.pseudo_dir, ndtset=1)
inp.set_comment("Input file with 1 dataset")
assert inp.isnc
inp.set_mnemonics(True)
assert inp.mnemonics
# One can set the value of the variables directly with the syntax.
inp.ecut = 10.
inp.tolwfr = 1e-8
# It's possible to use strings but use them only for special cases such as:
inp.istwfk = '*1'
# One can create a dictionary mapping keywords to values
unit_cell = {
"acell": 3*[10.217],
'rprim': [[.0, .5, .5],
[.5, .0, .5],
[.5, .5, .0]],
'ntypat': 1,
'znucl': [14,],
'natom': 2,
'typat': [1, 1],
'xred': [[.0, .0, .0],
[.25,.25,.25]]
}
# and set the variables in the input file with the call:
inp.set_vars(**unit_cell)
# Now we have a structure
assert len(inp.structure) == 2
assert inp.num_valence_electrons == 8
# Alternatively, it's possible to create a dictionary on the fly with the syntax.
inp.set_vars(kptopt=1, ngkpt=[2, 2, 2], nshiftk=1,
shiftk=np.reshape([0.0, 0.0, 0.0], (-1,3)))
inp.nshiftk = len(inp.shiftk)
assert inp.nshiftk == 1
inp.remove_vars("nshiftk")
with self.assertRaises(AttributeError): print(inp.nshiftk)
# To print the input to stdout use:
print(inp)
# Test set_structure
new_structure = inp.structure.copy()
new_structure.perturb(distance=0.1)
inp.set_structure(new_structure)
assert inp.structure == new_structure
# To create a new input with a different variable.
new = inp.new_with_vars(kptopt=3)
assert new.kptopt == 3 and inp.kptopt == 1
# Compatible with deepcopy, Pickle and MSONable?
inp.deepcopy()
self.serialize_with_pickle(inp, test_eq=False)
self.assertMSONable(inp)
# A slightly more complicated example: input file with two datasets
inp = AbiInput(pseudos="14si.pspnc", pseudo_dir=abidata.pseudo_dir, ndtset=2)
# Global variable common to all datasets.
inp.tolwfr = 1e-8
# To specify values for the different datasets, one can use the syntax
inp.ecut1 = 10
inp.ecut2 = 20
assert inp[1]["ecut"] == inp.ecut1 and inp[2]["ecut"] == inp.ecut2
assert inp[1].get("ecut") == inp.ecut1 and inp[2].get("foobar") is None
with self.assertRaises(AttributeError): print(inp.ecut)
inp.remove_vars("ecut", dtset=2)
assert inp.ecut1 == 10
with self.assertRaises(AttributeError): print(inp.ecut2)
# or by passing the index of the dataset to set_vars via the dtset argument.
inp.set_vars(ngkpt=[2,2,2], tsmear=0.004, dtset=1)
inp.set_vars(kptopt=[4,4,4], tsmear=0.008, dtset=2)
print(inp)
# Compatible with deepcopy, Pickle and MSONable?
inp.deepcopy()
self.serialize_with_pickle(inp, test_eq=False)
self.assertMSONable(inp)
# pseudo file must exist.
with self.assertRaises(inp.Error):
AbiInput(pseudos="foobar.pspnc", pseudo_dir=abidata.pseudo_dir, ndtset=2)
tsmear_list = [0.005, 0.01]
ngkpt_list = [[4,4,4], [8,8,8]]
occopt_list = [3, 4]
inp = AbiInput(pseudos=abidata.pseudos("14si.pspnc"), ndtset=len(tsmear_list))
inp.linspace("tsmear", start=tsmear_list[0], stop=tsmear_list[-1])
print(inp)
inp = AbiInput(pseudos=abidata.pseudos("14si.pspnc"), ndtset=len(tsmear_list) * len(ngkpt_list))
inp.product("tsmear", "ngkpt", tsmear_list, ngkpt_list)
print(inp)
# If you don't want to use multiple datasets in your calculation,
# you can split the initial input into ndtset different inputs.
separated_inps = inp.split_datasets()
for inp in separated_inps:
print(inp)
atrue(isinstance(inp, AbiInput))
# product accepts an arbitrary number of variables.
inp = AbiInput(pseudos=abidata.pseudos("14si.pspnc"), ndtset=len(tsmear_list) * len(ngkpt_list) * len(occopt_list))
inp.product("tsmear", "ngkpt", "occopt", tsmear_list, ngkpt_list, occopt_list)
print(inp)
# Split datasets.
inp.split_datasets()
# Cannot split datasets when we have get* or ird* variables.
inp[2].set_vars(getwfk=-1)
with self.assertRaises(inp.Error): inp.split_datasets()
def test_niopaw_input(self):
"""Testing AbiInput for NiO with PAW."""
aequal = self.assertEqual
inp = AbiInput(pseudos=abidata.pseudos("28ni.paw", "8o.2.paw"), ndtset=2, comment="NiO calculation")
inp.set_structure(abidata.structure_from_ucell("NiO"))
print(inp)
aequal(inp.ndtset, 2)
aequal(inp.ispaw, True)
# Set global variables.
inp.set_vars(ecut=10)
# Compatible with deepcopy, Pickle and MSONable?
inp.deepcopy()
self.serialize_with_pickle(inp, test_eq=False)
self.assertMSONable(inp)
# Setting an unknown variable should raise an error.
with self.assertRaises(inp.Error): inp.set_vars(foobar=10)
class LdauLexxTest(AbipyTest):
def test_nio(self):
"""Test LdauParams and LexxParams."""
aequal, atrue = self.assertEqual, self.assertTrue
structure = abidata.structure_from_ucell("NiO")
pseudos = abidata.pseudos("28ni.paw", "8o.2.paw")
u = 8.0
luj_params = LdauParams(usepawu=1, structure=structure)
luj_params.luj_for_symbol("Ni", l=2, u=u, j=0.1*u, unit="eV")
vars = luj_params.to_abivars()
self.serialize_with_pickle(luj_params, test_eq=False)
atrue(vars["usepawu"] == 1),
aequal(vars["lpawu"], "2 -1"),
aequal(vars["upawu"], "8.0 0.0 eV"),
aequal(vars["jpawu"], "0.8 0.0 eV"),
# Cannot add UJ for non-existent species.
with self.assertRaises(ValueError):
luj_params.luj_for_symbol("Foo", l=2, u=u, j=0.1*u, unit="eV")
# Cannot overwrite UJ.
with self.assertRaises(ValueError):
luj_params.luj_for_symbol("Ni", l=1, u=u, j=0.1*u, unit="eV")
lexx_params = LexxParams(structure)
lexx_params.lexx_for_symbol("Ni", l=2)
vars = lexx_params.to_abivars()
self.serialize_with_pickle(lexx_params, test_eq=False)
aequal(vars["useexexch"], 1),
aequal(vars["lexexch"], "2 -1"),
# Cannot add LEXX for non-existent species.
with self.assertRaises(ValueError): lexx_params.lexx_for_symbol("Foo", l=2)
# Cannot overwrite LEXX.
with self.assertRaises(ValueError): lexx_params.lexx_for_symbol("Ni", l=1)

View File

@ -1,83 +0,0 @@
"""Tests for htc.InputFile."""
import warnings
from abipy.core.testing import AbipyFileTest
from abipy.htc.jobfile import JobFile
from abipy.htc.inputfile import InputFile
from abipy.htc.variable import SpecialInputVariable
class TestInputVariable(AbipyFileTest):
"""Unit tests for AbinitVariable."""
def setUp(self):
self.file = SpecialInputVariable('ecut', 10.0)
def test_varnames(self):
"""Test printing of variables name."""
self.file.name = 'ecut1'
self.assertContains('ecut1')
self.file.name = 'ecut__s'
self.assertContains('ecut:')
self.file.name = 'ecut__i'
self.assertContains('ecut+')
self.file.name = 'ecut__a'
self.assertContains('ecut?')
self.file.name = 'ecut__s2'
self.assertContains('ecut:2')
self.file.name = 'ecut3__a'
self.assertContains('ecut3?')
self.file.name = 'ecut__s__a'
self.assertContains('ecut:?')
def test_scalar_values(self):
"""Test printing of scalar variables."""
self.file.value = 11.5
self.assertContains('ecut 11.5')
self.file.value = 10
self.assertContains('ecut 10')
self.file.value = '*1'
self.assertContains('ecut *1')
self.file.value = None
self.assertEmpty()
self.file.value = ''
self.assertEmpty()
class TestInputFile(AbipyFileTest):
"""Unit tests for InputFile."""
def setUp(self):
self.file = InputFile('MyDir/MyName.in')
def test_set_variable_attribute(self):
"""Test setting variables by attribute."""
self.file.ecut = 10.
self.assertContains('ecut 10.')
def test_set_variable_function(self):
"""Test setting variables with set_variable."""
self.file.set_variable('ecut', 10.)
self.assertContains('ecut 10.')
def test_set_variables_function(self):
"""Test setting variables with set_variables."""
self.file.set_variables({'ecut':10., 'nstep':100})
self.assertContains('nstep 100')
self.assertContains('ecut 10.')
self.file.set_variables({'ecut':10., 'nstep':100}, 1)
self.assertContains('nstep1 100')
self.assertContains('ecut1 10.')

View File

@ -1,165 +0,0 @@
"""Tests for htc.JobFile."""
from __future__ import print_function, division
import warnings
from abipy.core.testing import AbipyFileTest
from abipy.htc.jobfile import JobFile
class TestJobFile(AbipyFileTest):
"""Unit tests for JobFile."""
def setUp(self):
self.file = JobFile('MyJob.sh', input='myinput')
def test_shell_line(self):
"""Check the shell line is printed correctly."""
self.assertContains("#!/bin/bash")
self.file.shell = 'csh'
self.assertContains("#!/bin/csh")
def test_declaration_lines(self):
"""Check the declaration are printed correctly in bash."""
self.assertContains("""
MPIRUN=""
EXECUTABLE=abinit
INPUT=myinput
LOG=log
STDERR=stderr
""")
def test_execution_line(self):
"""Check the execution line is printed correctly in bash."""
self.assertContains("""
$MPIRUN $EXECUTABLE < $INPUT > $LOG 2> $STDERR
""")
def test_mpirun(self):
"""Check mpirun is set correctly."""
self.file.mpirun = 'openmpirun -n 2'
self.assertContains("""
MPIRUN="openmpirun -n 2"
""")
def test_modules(self):
"""Check the modules are loaded correctly."""
self.file.modules = "single"
self.assertContains("module load single")
m1, m2 = 'mod1', 'mod2/version/1.4-b'
lookfor = """
module load {0}
module load {1}
""".format(m1, m2)
self.file.modules = m1, m2
self.assertContains(lookfor)
self.file.modules = [m1, m2]
self.assertContains(lookfor)
self.file.set_modules(m1, m2)
self.assertContains(lookfor)
self.file.set_modules([m1, m2])
self.assertContains(lookfor)
def test_lines_before(self):
"""Check lines_before are printed correctly."""
single_line = "A single line."
self.file.lines_before = single_line
self.assertContains(single_line)
l1 = "This is my first line!"
l2 = "And that is my ${SECOND_LINE}"
lookfor = '\n'.join([l1, l2])
self.file.lines_before = l1, l2
self.assertContains(lookfor)
self.file.lines_before = [l1, l2]
self.assertContains(lookfor)
self.file.set_lines_before(l1, l2)
self.assertContains(lookfor)
self.file.set_lines_before([l1, l2])
self.assertContains(lookfor)
def test_lines_after(self):
"""Check lines_after are printed correctly."""
single_line = "A single line."
self.file.lines_after = single_line
self.assertContains(single_line)
l1 = "This is my first line!"
l2 = "And that is my ${SECOND_LINE}"
lookfor = '\n'.join([l1, l2])
self.file.lines_after = l1, l2
self.assertContains(lookfor)
self.file.lines_after = [l1, l2]
self.assertContains(lookfor)
self.file.set_lines_after(l1, l2)
self.assertContains(lookfor)
self.file.set_lines_after([l1, l2])
self.assertContains(lookfor)
def test_other_lines(self):
"""Check other_lines are printed correctly."""
single_line = "A single line."
self.file.other_lines = single_line
self.assertContains(single_line)
l1 = "This is my first line!"
l2 = "And that is my ${SECOND_LINE}"
lookfor = '\n'.join([l1, l2])
self.file.other_lines = l1, l2
self.assertContains(lookfor)
self.file.other_lines = [l1, l2]
self.assertContains(lookfor)
self.file.set_other_lines(l1, l2)
self.assertContains(lookfor)
self.file.set_other_lines([l1, l2])
self.assertContains(lookfor)
class TestJobFileCSH(AbipyFileTest):
"""Unit tests for JobFile with csh shell."""
def setUp(self):
self.file = JobFile('MyJob.sh', input='myinput')
self.file.shell='csh'
def test_declaration_lines(self):
"""Check the declaration are printed correctly in csh."""
self.assertContains("""
set MPIRUN=""
set EXECUTABLE=abinit
set INPUT=myinput
set LOG=log
set STDERR=stderr
""")
def test_execution_line(self):
"""Check the execution line is printed correctly in csh."""
self.assertContains("""
($MPIRUN $EXECUTABLE < $INPUT > $LOG) >& $STDERR
""")
if __name__ == "__main__":
import unittest
unittest.main()

View File

@ -1,199 +0,0 @@
"""Tools and helper functions for abinit calculations"""
from __future__ import print_function, division #, unicode_literals
import os.path
import collections
from copy import deepcopy
from itertools import chain
from monty.string import list_strings
##########################################################################################
class _ewc_tuple(collections.namedtuple("ewc_tuple", "errors, warnings, comments")):
def tostream(self, stream):
"Return a string that can be visualized on stream (with colors if stream support them)."
str_colorizer = StringColorizer(stream)
red = lambda num : str_colorizer(str(num), "red")
blue = lambda num : str_colorizer(str(num), "blue")
nums = map(len, [self.errors, self.warnings, self.comments])
colors = (red, blue, str)
for (i, n) in enumerate(nums):
color = colors[i]
nums[i] = color(n) if n else str(n)
return "%s errors, %s warnings, %s comments in main output file" % tuple(nums)
##########################################################################################
def parse_ewc(filename, nafter=5):
"""
Extract errors, warnings and comments from file filename.
:arg nafter: Save nafter lines of trailing context after matching lines.
:return: namedtuple instance. The lists of strings with the corresponding messages are
available in tuple.errors, tuple.warnings, tuple.comments.
"""
# TODO
# we have to standardize the abinit WARNING, COMMENT and ERROR so that we can parse them easily
# without having to use nafter.
errors, warnings, comments = [], [], []
# Note the space after the name.
exc_cases = ["ERROR ", "BUG ", "WARNING ", "COMMENT "]
handlers = {
"ERROR " : errors.append,
"BUG " : errors.append,
"WARNING " : warnings.append,
"COMMENT " : comments.append,
}
def exc_case(line):
for e in exc_cases:
if e in line: return e
else:
return None
with open(filename, "r") as fh:
lines = fh.readlines()
nlines = len(lines)
for (lineno, line) in enumerate(lines):
handle = handlers.get(exc_case(line))
if handle is None: continue
context = lines[lineno: min(lineno+nafter, nlines)]
handle( "".join([c for c in context]) )
return _ewc_tuple(errors, warnings, comments)
##########################################################################################
def find_file(files, ext, prefix=None, dataset=None, image=None):
"""
Given a list of file names, return the file with extension "_" + ext, None if not found.
The prefix, the dataset index and the image index can be specified
.. warning::
There are some border cases that will confuse the algorithm
since the order of dataset and image is not tested.
Solving this problem requires the knowledge of ndtset and nimages
This code, however should work in 99.9% of the cases.
"""
separator = "_"
for filename in list_strings(files):
# Remove Netcdf extension (if any)
f = filename[:-3] if filename.endswith(".nc") else filename
if separator not in f: continue
tokens = f.split(separator)
if tokens[-1] == ext:
found = True
if prefix is not None: found = found and filename.startswith(prefix)
if dataset is not None: found = found and "DS" + str(dataset) in tokens
if image is not None: found = found and "IMG" + str(image) in tokens
if found: return filename
else:
return None
##########################################################################################
def abinit_output_iscomplete(output_file):
"Returns True if the abinit output file is complete."
if not os.path.exists(output_file):
return False
chunk = 5 * 1024 # Read only the last 5Kb of data.
nlines = 10 # Check only in the last 10 lines.
MAGIC = "Calculation completed."
with open(output_file, 'r') as f:
size = f.tell()
f.seek(max(size - chunk, 0))
try:
for line in f.read().splitlines()[-nlines:]:
if MAGIC in line:
return True
except:
pass
return False
# =========================================================================== #
def is_number(s):
"""Returns True if the argument can be made a float."""
try:
float(s)
return True
except:
return False
def is_iter(obj):
"""Return True if the argument is list-like."""
return hasattr(obj, '__iter__')
def is_scalar(obj):
"""Return True if the argument is not list-like."""
return not is_iter
def flatten(iterable):
"""Make an iterable flat, i.e. a 1d iterable object."""
iterator = iter(iterable)
array, stack = collections.deque(), collections.deque()
while True:
try:
value = next(iterator)
except StopIteration:
if not stack:
return tuple(array)
iterator = stack.pop()
else:
if not isinstance(value, str) \
and isinstance(value, collections.Iterable):
stack.append(iterator)
iterator = iter(value)
else:
array.append(value)
def listify(obj):
"""Return a flat list out of the argument."""
if not obj:
obj = list()
elif is_iter(obj):
obj = list(flatten(obj))
else:
obj = [obj]
return deepcopy(obj)
class StringColorizer(object):
COLORS = {"default": "",
"blue": "\x1b[01;34m",
"cyan": "\x1b[01;36m",
"green": "\x1b[01;32m",
"red": "\x1b[01;31m",
# lighting colors.
#"lred": "\x1b[01;05;37;41m"
}
def __init__(self, stream):
self.has_colours = stream_has_colours(stream)
def __call__(self, string, colour):
if self.has_colours:
code = self.COLORS.get(colour, "")
if code:
return code + string + "\x1b[00m"
else:
return string
else:
return string

View File

@ -141,3 +141,5 @@ TODO list:
it and can report this value in the final band structure.
* DONE ecut is not reported in the GSR file. Similar problem for the k-sampling (see SIGRES.nc)
* FFTProf (use file extension and interface it with abiopen)

View File

@ -2,7 +2,7 @@
Python interface to fftprof. Provides objects to benchmark
the FFT libraries used by ABINIT and plot the results with matplotlib.
"""
from __future__ import print_function, division, unicode_literals
from __future__ import print_function, division, unicode_literals, absolute_import
import sys
import os
@ -12,9 +12,10 @@ import numpy as np
from subprocess import Popen, PIPE
from monty.os.path import which
from monty.fnmatch import WildCard
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt
__all__ = [
"FFT_Benchmark",
"FFTBenchmark",
]
_color_fftalg = {
@ -58,14 +59,10 @@ class FFT_Test(object):
def __init__(self, ecut, ngfft, wall_time, info):
"""
Args:
ecut:
List of cutoff energies in Hartree.
ngfft:
List with FFT divisions.
wall_time:
List of wall_time for the different ecut.
info:
Dictionary with extra information.
ecut: List of cutoff energies in Hartree.
ngfft: List with FFT divisions.
wall_time: List of wall_time for the different ecut.
info: Dictionary with extra information.
"""
self.ecut = np.asarray(ecut)
self.necut = len(ecut)
@ -110,11 +107,11 @@ class FFT_Test(object):
return line
class FFT_Benchmark(object):
class FFTBenchmark(object):
"""
Container class storing the results of the FFT benchmark.
Use the class method `from_file` to generate a new instance.
Use the class method ``from_file`` to generate a new instance.
"""
@classmethod
def from_file(cls, fileobj):
@ -128,8 +125,8 @@ class FFT_Benchmark(object):
alg = test.fftalg
if alg not in self._fftalgs:
self._fftalgs.append(alg)
self._fftalgs.sort()
self._fftalgs.sort()
self.tests = [t for t in FFT_tests]
def iter_fftalgs(self):
@ -143,26 +140,13 @@ class FFT_Benchmark(object):
if t.fftalg == fftalg: lst.append(t)
return lst
@add_fig_kwargs
def plot(self, exclude_algs=None, exclude_threads=None, **kwargs):
"""
Plot the wall-time and the speed-up.
Args:
============== ==============================================================
kwargs Meaning
============== ==============================================================
show True to show the figure (Default)
savefig 'abc.png' or 'abc.eps'* to save the figure to a file.
============== ===============================================================
"""
show = kwargs.pop("show", True)
savefig = kwargs.pop("savefig", None)
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1)
exc_algs = []
@ -206,7 +190,6 @@ class FFT_Benchmark(object):
ax2.set_xticklabels(labels, fontdict=None, minor=False, rotation=35)
for fftalg in self.iter_fftalgs():
if fftalg in exc_algs: continue
tests = self.tests_with_fftalg(fftalg)
for t in tests:
@ -247,12 +230,6 @@ class FFT_Benchmark(object):
ideal = [1.0 for i in range(t0.necut)]
ax2.plot(t0.ecut, ideal, "b-", linewidth=3.0)
if show:
plt.show()
if savefig is not None:
fig.savefig(os.path.abspath(savefig))
return fig
@ -260,12 +237,9 @@ def parse_prof_file(fileobj):
"""
Parse the PROF file generated by fftprof.F90.
Args:
fileobj:
String or file-like object.
Args: fileobj: String or file-like object.
Returns:
Instance of FFT_Benchmark.
Returns: Instance of FFTBenchmark.
"""
# The file contains
# 1) An initial header with info on the routine.
@ -321,14 +295,14 @@ def parse_prof_file(fileobj):
except IndexError:
line = None
# Instantiate FFT_Benchmark.
# Instantiate FFTBenchmark.
fft_tests = []
for (idx, wall_time) in enumerate(data):
for idx, wall_time in enumerate(data):
info = info_of_test[idx]
Test = FFT_Test(ecut, ngfft, wall_time, info)
fft_tests.append(Test)
return FFT_Benchmark(title, fft_tests)
return FFTBenchmark(title, fft_tests)
class FFTProfError(Exception):
@ -397,5 +371,5 @@ class FFTProf(object):
if self.verbose:
print("About to plot prof_file: ", prof_file)
bench = FFT_Benchmark.from_file(prof_file)
bench = FFTBenchmark.from_file(prof_file)
bench.plot()

View File

@ -2,7 +2,6 @@
"""Tests for duck module."""
from __future__ import division, print_function, absolute_import, unicode_literals
import numpy as np
from abipy.core.testing import AbipyTest

View File

@ -0,0 +1,34 @@
# coding: utf-8
"""Tests for fftprof module."""
from __future__ import division, print_function, absolute_import, unicode_literals
import os
import abipy.data as abidata
from abipy.core.testing import AbipyTest
from abipy.tools.fftprof import FFTBenchmark
class FftProfTest(AbipyTest):
def test_fft_benchmark(self):
"""Testing FFt benchmark."""
# Plot the benchmark results saved in the files
path = os.path.join(abidata.dirpath, "PROF_fourwf_cplex0_option3_istwfk1")
bench = FFTBenchmark.from_file(path)
assert bench.title.strip() == " Benchmark: routine = fourwf, cplex = 0, option= 3, istwfk= 1".strip()
assert len(bench.tests) == 4
assert len(bench.tests_with_fftalg(112)) == 2
assert len(bench.tests_with_fftalg(512)) == 2
test0 = bench.tests_with_fftalg(112)[0]
test1 = bench.tests_with_fftalg(112)[1]
assert len(test0.ecut) == len(test0.ngfft)
assert str(test0)
test0.speedup_wrt(test1)
if self.has_matplotlib():
#test0.plot_ax()
assert bench.plot(show=False)

View File

@ -84,3 +84,11 @@ abio Package
:members:
:undoc-members:
:show-inheritance:
:mod:`variable` Module
----------------------
.. automodule:: abipy.abio.variable
:members:
:undoc-members:
:show-inheritance:

View File

@ -53,6 +53,14 @@ tools Package
:undoc-members:
:show-inheritance:
:mod:`fftprof` Module
---------------------
.. automodule:: abipy.tools.fftprof
:members:
:undoc-members:
:show-inheritance:
:mod:`iotools` Module
---------------------