def wxapp_events(root): """ Start up the AbinitOutputViewer application. Args: root: Can be: None, filename, directory name or list of filenames. None means that we just open the browser without accessing any file. If root is a directory, we locate all the output files starting from root and we visualize them in the main Frame. """ if root is None: filenames = [] elif is_string(root): root = os.path.abspath(root) if os.path.isdir(root): filenames = [os.path.join(root, f) for f in os.listdir(root) if f.endswith(".abo")] else: filenames = [root] else: filenames = root class AbiEventsViewerApp(awx.App): def OnInit(self): frame = AbinitEventsNotebookFrame(None, filenames) self.SetTopWindow(frame) frame.Show() return True return AbiEventsViewerApp()
def add_file(self, label, abifile, filter_abifile=None): """ Add a file to the robot with the given label. Args: label: String used to identify the file (must be unique, ax exceptions is raised if label is already present. abifile: Specify the file to be added. Accepts strings (filepath) or abipy file-like objects. filter_abifile: Function that receives an ``abifile`` object and returns True if the file should be added to the plotter. """ if is_string(abifile): from abipy.abilab import abiopen abifile = abiopen(abifile) if filter_abifile is not None and not filter_abifile(abifile): abifile.close() return # Open file here --> have to close it. self._do_close[abifile.filepath] = True if label in self._abifiles: raise ValueError("label %s is already present!" % label) self._abifiles[label] = abifile
def asabistructure(obj): """ Convert obj into an AbiStructure object. Accepts: - AbiStructure instance - Subinstances of pymatgen. - File paths """ if isinstance(obj, AbiStructure): return obj if isinstance(obj, Structure): # Promote return AbiStructure(obj) if is_string(obj): # Handle file paths. if os.path.isfile(obj): if obj.endswith(".nc"): structure = structure_from_etsf_file(obj) else: structure = Structure.from_file(obj) # Promote return AbiStructure(structure) raise ValueError("Don't know how to convert object %s to an AbiStructure structure" % str(obj))
def compare_d2de_scf_cycles(self, others, show=True): """ Produce and returns a `matplotlib` figure comparing the DFPT self-consistent cycle in self with the ones in others. Args: others: list of `AbinitOutputFile` objects or strings with paths to output files. show: True to diplay plots. """ for i, other in enumerate(others): if is_string(other): others[i] = self.__class__.from_file(other) fig, figures = None, [] while True: cycle = self.next_d2de_scf_cycle() if cycle is None: break fig = cycle.plot(show=False) for i, other in enumerate(others): other_cycle = other.next_d2de_scf_cycle() if other_cycle is None: break last = (i == len(others) - 1) fig = other_cycle.plot(fig=fig, show=show and last) if last: figures.append(fig) self.seek(0) for other in others: other.seek(0) return figures
def add_file(self, label, ncfile): if is_string(ncfile): from abipy.abilab import abiopen ncfile = abiopen(ncfile) self._do_close[ncfile.filepath] = True self._ncfiles[label] = ncfile
def open(cls, obj, nids=None, **kwargs): """ Flexible constructor. obj can be a :class:`Flow` or a string with the directory containing the Flow. nids is an optional list of :class:`Node` identifiers used to filter the set of :class:`Task` in the Flow. """ has_dirpath = False if is_string(obj): try: obj = Flow.pickle_load(obj) except: has_dirpath = True if not has_dirpath: # We have a Flow. smeth is the name of the Task method used to open the file. items = [] smeth = "open_" + cls.EXT.lower() for task in obj.iflat_tasks(nids=nids): #, status=obj.S_OK): open_method = getattr(task, smeth, None) if open_method is None: continue ncfile = open_method() if ncfile is not None: items.append((task.pos_str, ncfile)) return cls(*items) else: # directory --> search for files with the appropriate extension and open it with abiopen. if nids is not None: raise ValueError("nids cannot be used when obj is a directory.") return cls.from_dir(obj)
def product(self, *items): """ Cartesian product of input iterables. Equivalent to nested for-loops. .. code-block:: python inp.product("tsmear", "ngkpt", [[2,2,2], [4,4,4]], [0.1, 0.2, 0.3]) """ # Split items into varnames and values for i, item in enumerate(items): if not is_string(item): break varnames, values = items[:i], items[i:] if len(varnames) != len(values): raise self.Error("The number of variables must equal the number of lists") varnames = [ [varnames[i]] * len(values[i]) for i in range(len(values))] varnames = itertools.product(*varnames) values = itertools.product(*values) idt = 0 for names, values in zip(varnames, values): idt += 1 self[idt].set_vars(**{k: v for k, v in zip(names, values)}) if idt != self.ndtset: raise self.Error("The number of configurations must equal ndtset while %d != %d" % (idt, self.ndtset))
def str2array(obj, dtype=float): if not is_string(obj): return np.asarray(obj) if obj.startswith("*"): raise ValueError("This case should be treated by the caller: %s" % str(obj)) s = expand_star_syntax(obj) # Numpy does not understand "0.00d0 0.00d0" s = s.lower().replace("d", "e") return np.fromstring(s, sep=" ", dtype=dtype)
def from_chgcar_poscar(cls, chgcar, poscar): """ Build a :class`Density` object from Vasp data. Args: chgcar: Either string with the name of a CHGCAR file or :class:`Chgcar` pymatgen object. poscar: Either string with the name of a POSCAR file or :class:`Poscar` pymatgen object. .. warning: The present version does not support non-collinear calculations. The Chgcar object provided by pymatgen does not provided enough information to understand if the calculation is collinear or no. """ if is_string(chgcar): chgcar = Chgcar.from_file(chgcar) if is_string(poscar): poscar = Poscar.from_file(poscar, check_for_POTCAR=False, read_velocities=False) nx, ny, nz = chgcar.dim nspinor = 1 nsppol = 2 if chgcar.is_spin_polarized else 1 nspden = 2 if nsppol == 2 else 1 # Convert pymatgen chgcar data --> abipy representation. abipy_datar = np.empty((nspden, nx, ny, nz)) if nspinor == 1: if nsppol == 1: abipy_datar = chgcar.data["total"] elif nsppol == 2: total, diff = chgcar.data["total"], chgcar.data["diff"] abipy_datar[0] = 0.5 * (total + diff) abipy_datar[1] = 0.5 * (total - diff) else: raise ValueError("Wrong nspden %s" % nspden) else: raise NotImplementedError("nspinor == 2 requires more info in Chgcar") # density in Chgcar is multiplied by volume! abipy_datar /= poscar.structure.volume return cls(nspinor=nspinor, nsppol=nsppol, nspden=nspden, datar=abipy_datar, structure=poscar.structure, iorder="c")
def _select_hosts(self, hostnames): """ Helper function to select hostnames. Receives None, string or list of strings and returns a list of hostnames. """ if hostnames is None: return self.hostnames() else: return [hostnames] if is_string(hostnames) else hostnames
def get_values(self, keys): """Return a list of values associated to a particular list of keys""" if is_string(keys): return [s.__dict__[keys] for s in self.sections] else: values = [] for k in keys: values.append([s.__dict__[k] for s in self.sections]) return values
def check_var(v, w): _error = False if isinstance(v, int): _error = check_int(v, w) elif isinstance(v, float): _error = check_float(v, w) elif is_string(v): _error = check_str(v, w) return _error
def any2sch(obj): """Convert string or int to Schoenflies symbol. Returns None if invalid input""" if is_string(obj): if obj in sch_symbols: return obj else: # Try Hermann-Mauguin return herm2sch(obj) else: # Spacegroup ID? return spgid2sch(obj)
def _get_structure(self, obj): """Extract the structure from the input object.""" if isinstance(obj, Structure): self.structure = obj elif is_string(obj): self.structure = abiopen(obj).structure elif hasattr(obj, "structure"): self.structure = obj.structure else: raise TypeError("Don't know how to extract the structure from %s" % str(obj))
def to_csv(self, fileobj=sys.stdout): """Write data on file fileobj using CSV format.""" openclose = is_string(fileobj) if openclose: fileobj = open(fileobj, "w") for (idx, section) in enumerate(self.sections): fileobj.write(section.to_csvline(with_header=(idx == 0))) fileobj.flush() if openclose: fileobj.close()
def as_event_class(obj): """ Convert obj into a subclass of AbinitEvent. obj can be either a class or a string with the class name or the YAML tag """ if is_string(obj): for c in all_subclasses(AbinitEvent): if c.__name__ == obj or c.yaml_tag == obj: return c raise ValueError("Cannot find event class associated to %s" % obj) # Assume class. assert obj in all_subclasses(AbinitEvent) return obj
def sendmail(subject, text, mailto, sender=None): """ Sends an e-mail with unix sendmail. Args: subject: String with the subject of the mail. text: String with the body of the mail. mailto: String or list of string with the recipients. sender: string with the sender address. If sender is None, username@hostname is used. Returns: Exit status """ def user_at_host(): from socket import gethostname return os.getlogin() + "@" + gethostname() # Body of the message. try: sender = user_at_host() if sender is None else sender except OSError: sender = 'abipyscheduler@youknowwhere' if is_string(mailto): mailto = [mailto] from email.mime.text import MIMEText mail = MIMEText(text) mail["Subject"] = subject mail["From"] = sender mail["To"] = ", ".join(mailto) msg = mail.as_string() # sendmail works much better than the python interface. # Note that sendmail is available only on Unix-like OS. from subprocess import Popen, PIPE import sys sendmail = which("sendmail") if sendmail is None: return -1 if sys.version_info[0] < 3: p = Popen([sendmail, "-t"], stdin=PIPE, stderr=PIPE) else: # msg is string not bytes so must use universal_newlines p = Popen([sendmail, "-t"], stdin=PIPE, stderr=PIPE, universal_newlines=True) outdata, errdata = p.communicate(msg) return len(errdata)
def __init__(self, node, exts=None): """ Args: node: The task or the worfklow associated to the dependency or string with a filepath. exts: Extensions of the output files that are needed for running the other tasks. """ self._node = Node.as_node(node) if exts and is_string(exts): exts = exts.split() # Extract extensions. self.exts = [e for e in exts if not e.startswith("@")] # Save getters self.getters = [e for e in exts if e.startswith("@")]
def __init__(self, parent, filepaths, **kwargs): """ Args: parent: parent window filepaths: List of file paths. """ super(FileListPanel, self).__init__(parent, -1, **kwargs) if filepaths is not None and is_string(filepaths): filepaths = [filepaths] self.filepaths = filepaths if filepaths is not None else [] self.filepaths = map(os.path.abspath, self.filepaths) self.BuildUi()
def sendmail(subject, text, mailto, sender=None): """ Sends an e-mail with unix sendmail. Args: subject: String with the subject of the mail. text: String with the body of the mail. mailto: String or list of string with the recipients. sender: string with the sender address. If sender is None, username@hostname is used. Returns: exit status """ def user_at_host(): from socket import gethostname return os.getlogin() + "@" + gethostname() # Body of the message. sender = user_at_host() if sender is None else sender if is_string(mailto): mailto = [mailto] from email.mime.text import MIMEText mail = MIMEText(text) mail["Subject"] = subject mail["From"] = sender mail["To"] = ", ".join(mailto) msg = mail.as_string() # sendmail works much better than the python interface. # Note that sendmail is available only on Unix-like OS. from subprocess import Popen, PIPE sendmail = which("sendmail") if sendmail is None: return -1 p = Popen([sendmail, "-t"], stdin=PIPE, stderr=PIPE) outdata, errdata = p.communicate(msg) return len(errdata)
def as_node(cls, obj): """ Convert obj into a Node instance. Return: obj if obj is a Node instance, cast obj to :class:`FileNode` instance of obj is a string. None if obj is None """ if isinstance(obj, cls): return obj elif is_string(obj): # Assume filepath. return FileNode(obj) elif obj is None: return obj else: raise TypeError("Don't know how to convert %s to Node instance." % obj)
def str2array_bohr(obj): if not is_string(obj): return np.asarray(obj) # Treat e.g. acell 3 * 1.0 obj = expand_star(obj) tokens = obj.split() if not tokens[-1].isalpha(): # No unit return np.fromstring(obj, sep=" ") unit = tokens[-1].lower() if unit in ("angstr", "angstrom", "angstroms"): return np.fromstring(" ".join(tokens[:-1]), sep=" ") / bohr_to_ang elif unit in ("bohr", "bohrs"): return np.fromstring(" ".join(tokens[:-1]), sep=" ") else: raise ValueError("Don't know how to handle unit: %s" % unit)
def add_file(self, label, ncfile): """ Add a file to the robot with the given label. Args: label: String used to identify the file (must be unique, ax exceptions is raised if label is already present. ncfile: Specify the file to be added. Accepts strings (filepath) or abipy file-like objects. """ if is_string(ncfile): from abipy.abilab import abiopen ncfile = abiopen(ncfile) self._do_close[ncfile.filepath] = True if label in self._ncfiles: raise ValueError("label %s is already present!") self._ncfiles[label] = ncfile
def as_structure(cls, obj): """Convert obj into a structure.""" if isinstance(obj, cls): return obj if isinstance(obj, pymatgen.Structure): obj.__class__ = cls return obj if is_string(obj): return cls.from_file(obj) if isinstance(obj, collections.Mapping): try: return Structure.from_abivars(obj) except: try: return Structure.from_dict(obj) except: raise TypeError("Don't know how to convert dict %s into a structure" % obj) raise TypeError("Don't know how to convert %s into a structure" % type(obj))
def str2array_bohr(obj): if not is_string(obj): return np.asarray(obj) # Treat e.g. acell 3 * 1.0 obj = expand_star_syntax(obj) # Numpy does not understand "0.00d0 0.00d0" obj = obj.lower().replace("d", "e") tokens = obj.split() if not tokens[-1].isalpha(): # No unit return np.fromstring(obj, sep=" ") unit = tokens[-1] if unit in ("angstr", "angstrom", "angstroms"): return np.fromstring(" ".join(tokens[:-1]), sep=" ") / bohr_to_ang elif unit in ("bohr", "bohrs", "au"): return np.fromstring(" ".join(tokens[:-1]), sep=" ") else: raise ValueError("Don't know how to handle unit: %s" % str(unit))
def from_dir(cls, top, workdir=None, name=None, manager=None, max_depth=2): """ Find all flows located withing the directory `top` and build the `BatchLauncher`. Args: top: Top level directory or list of directories. workdir: Batch workdir. name: manager: :class:`TaskManager` object. If None, the manager is read from `manager.yml` In this case the YAML file must provide the entry `batch_manager` that defined the queue adapter used to submit the batch script. max_depth: Search in directory only if it is N or fewer levels below top """ from .flows import Flow def find_pickles(dirtop): # Walk through each directory inside path and find the pickle database. paths = [] for dirpath, dirnames, filenames in os.walk(dirtop): fnames = [f for f in filenames if f == Flow.PICKLE_FNAME] paths.extend([os.path.join(dirpath, f) for f in fnames]) return paths if is_string(top): pickle_paths = find_pickles(top) else: # List of directories. pickle_paths = [] for p in top: pickle_paths.extend(find_pickles(p)) # workdir = os.path.join(top, "batch") if workdir is None else workdir workdir = "batch" if workdir is None else workdir new = cls(workdir, name=name, manager=manager) for path in pickle_paths: new.add_flow(path) return new
def add_mdf_file(self, label, obj): """ Extract dielectric functions from object ``obj``, store data for plotting. Args: label: label associated to the MDF file. Must be unique. mdf: filepath or :class:`MdfFile` object. """ if label in self._mdfs: raise ValueError("label: %s already in: %s" % (label, list(self._mdfs.keys()))) self._mdfs[label] = OrderedDict() if is_string(obj): # Open the file. with MdfFile(obj) as mdf_file: for mdf_type in self.MDF_TYPES: self._mdfs[label][mdf_type] = mdf_file.get_mdf(mdf_type=mdf_type) else: # Extract data from `MdfFile` object for mdf_type in self.MDF_TYPES: self._mdfs[label][mdf_type] = obj.get_mdf(mdf_type=mdf_type)
def get_message(self, metadata=False, asctime=True): """ Return the message after merging any user-supplied arguments with the message. Args: metadata: True if function and module name should be added. asctime: True if time string should be added. """ msg = self.msg if is_string(self.msg) else str(self.msg) if self.args: try: msg = msg % self.args except: msg += str(self.args) if asctime: msg = "[" + self.asctime + "] " + msg # Add metadata if metadata: msg += "\nCalled by %s at %s:%s\n" % (self.func_name, self.pathname, self.lineno) return msg
def open(cls, obj, nids=None, **kwargs): """ Flexible constructor. obj can be a :class:`Flow` or a string with the directory containing the Flow. nids is an optional list of :class:`Node` identifiers used to filter the set of :class:`Task` in the Flow. """ has_dirpath = False if is_string(obj): try: obj = Flow.pickle_load(obj) except: has_dirpath = True items = [] if not has_dirpath: # We have a Flow. smeth is the name of the Task method used to open the file. smeth = "open_" + cls.EXT.lower() for task in obj.iflat_tasks(nids=nids): #, status=obj.S_OK): open_method = getattr(task, smeth, None) if open_method is None: continue ncfile = open_method() if ncfile is not None: items.append((task.pos_str, ncfile)) else: # directory --> search for files with the appropriate extension and open it with abiopen. if nids is not None: raise ValueError("nids cannot be used when obj is a directory.") from abipy.abilab import abiopen for dirpath, dirnames, filenames in os.walk(obj): filenames = [f for f in filenames if f.endswith(cls.EXT + ".nc") or f.endswith(cls.EXT)] for f in filenames: ncfile = abiopen(os.path.join(dirpath, f)) if ncfile is not None: items.append((ncfile.filepath, ncfile)) new = cls(*items) # Save a reference to the initial object so that we can reload it if needed #new._initial_object = obj return new
def compare_d2de_scf_cycles(self, others, show=True): """ Produce and returns a matplotlib_ figure comparing the DFPT self-consistent cycle in self with the ones in others. Args: others: list of :class:`AbinitOutputFile` objects or strings with paths to output files. show: True to diplay plots. """ # Open file here if we receive a string. Files will be closed before returning close_files = [] for i, other in enumerate(others): if is_string(other): others[i] = self.__class__.from_file(other) close_files.append(i) fig, figures = None, [] while True: cycle = self.next_d2de_scf_cycle() if cycle is None: break fig = cycle.plot(show=False) for i, other in enumerate(others): other_cycle = other.next_d2de_scf_cycle() if other_cycle is None: break last = (i == len(others) - 1) fig = other_cycle.plot(ax_list=fig.axes, show=show and last) if last: fig.tight_layout() figures.append(fig) self.seek(0) for other in others: other.seek(0) if close_files: for i in close_files: others[i].close() return figures
def plot_convergence_items(self, items, sortby=None, hue=None, fontsize=6, **kwargs): """ Plot the convergence of a list of ``items`` wrt to the ``sortby`` parameter. Values can optionally be grouped by ``hue``. Args: items: List of attributes (or callables) to be analyzed. sortby: Define the convergence parameter, sort files and produce plot labels. Can be None, string or function. If None, no sorting is performed. If string and not empty it's assumed that the abifile has an attribute with the same name and `getattr` is invoked. If callable, the output of sortby(abifile) is used. hue: Variable that define subsets of the data, which will be drawn on separate lines. Accepts callable or string If string, it's assumed that the abifile has an attribute with the same name and getattr is invoked. Dot notation is also supported e.g. hue="structure.formula" --> abifile.structure.formula If callable, the output of hue(abifile) is used. fontsize: legend and label fontsize. kwargs: keyword arguments are passed to ax.plot Returns: |matplotlib-Figure| """ # Note: in principle one could call plot_convergence inside a loop but # this one is faster as sorting is done only once. # Build grid plot. nrows, ncols = len(items), 1 ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols, sharex=True, sharey=False, squeeze=False) ax_list = ax_list.ravel() # Sort and group files if hue. if hue is None: labels, ncfiles, params = self.sortby(sortby, unpack=True) else: groups = self.group_and_sortby(hue, sortby) marker = kwargs.pop("marker", "o") for i, (ax, item) in enumerate(zip(ax_list, items)): if hue is None: # Extract data. if callable(item): yvals = [float(item(gsr)) for gsr in self.abifiles] else: yvals = [duck.getattrd(gsr, item) for gsr in self.abifiles] if not is_string(params[0]): ax.plot(params, yvals, marker=marker, **kwargs) else: # Must handle list of strings in a different way. xn = range(len(params)) ax.plot(xn, yvals, marker=marker, **kwargs) ax.set_xticks(xn) ax.set_xticklabels(params, fontsize=fontsize) else: for g in groups: # Extract data. if callable(item): yvals = [float(item(gsr)) for gsr in g.abifiles] else: yvals = [duck.getattrd(gsr, item) for gsr in g.abifiles] label = "%s: %s" % (self._get_label(hue), g.hvalue) ax.plot(g.xvalues, yvals, label=label, marker=marker, **kwargs) ax.grid(True) ax.set_ylabel(self._get_label(item)) if i == len(items) - 1: ax.set_xlabel("%s" % self._get_label(sortby)) if sortby is None: rotate_ticklabels(ax, 15) if i == 0 and hue is not None: ax.legend(loc="best", fontsize=fontsize, shadow=True) return fig
def plot_qps_vs_e0(self, with_fields="all", exclude_fields=None, **kwargs): """ Args: with_fields: The names of the qp attributes to plot as function of e0. Accepts: List of strings or string with tokens separated by blanks. See :class:`QPState` for the list of available fields. exclude_fields: Simiar to `with_field` but it excludes ============== ============================================================== kwargs Meaning ============== ============================================================== fermi True to plot the Fermi level. ============== ============================================================== Returns: `matplotlib` figure. """ fermi = kwargs.pop("fermi", None) if is_string(with_fields): if with_fields == "all": fields = list(QPState.get_fields(exclude=["spin", "kpoint"])) else: fields = with_fields.split() if exclude_fields: if is_string(exclude_fields): exclude_fields = exclude_fields.split() for e in exclude_fields: fields.remove(e) # Build grid of plots. num_plots, ncols, nrows = len(fields), 1, 1 if num_plots > 1: ncols = 2 nrows = (num_plots//ncols) + (num_plots % ncols) import matplotlib.pyplot as plt fig, ax_list = plt.subplots(nrows=nrows, ncols=ncols, sharex=True, squeeze=False) ax_list = ax_list.ravel() if self.is_e0sorted: qps = self else: qps = self.sort_by_e0() e0mesh = qps.get_e0mesh() linestyle = kwargs.pop("linestyle", "o") for field, ax in zip(fields, ax_list): ax.grid(True) ax.set_xlabel('e0 [eV]') ax.set_ylabel(field) yy = qps.get_field(field) ax.plot(e0mesh, yy.real, linestyle, **kwargs) #ax.plot(e0mesh, e0mesh) if fermi is not None: ax.plot(2*[fermi], [min(yy), max(yy)]) # Get around a bug in matplotlib if (num_plots % ncols) != 0: ax_list[-1].plot([0,1], [0,1], lw=0) ax_list[-1].axis('off') return fig
def any2mb(s): """Convert string or number to memory in megabytes.""" if is_string(s): return int(Memory.from_string(s).to("Mb")) else: return int(s)
def is_abiunit(s): """ True if string is one of the units supported by the ABINIT parser """ if not is_string(s): return False return s.lower() in ABI_UNIT_NAMES
def asxc(cls, obj): """Convert object into Xcfunc.""" if isinstance(obj, cls): return obj if is_string(obj): return cls.from_name(obj) raise TypeError("Don't know how to convert <%s:%s> to Xcfunc" % (type(obj), str(obj)))
def _add(self, text, pre=""): if is_string(text): self._lines.append(pre + text) else: self._lines.extend([pre + t for t in text])