Source code for aiida_gulp.potentials.lj

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2019 Chris Sewell
#
# This file is part of aiida-gulp.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms and conditions
# of version 3 of the GNU Lesser General Public License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
from aiida_gulp.potentials.base import PotentialWriterAbstract, PotentialContent
from aiida_gulp.potentials.common import INDEX_SEP
from aiida_gulp.validation import load_schema


[docs]class PotentialWriterLJ(PotentialWriterAbstract): """class for creating gulp lennard-jones type inter-atomic potential inputs """
[docs] @classmethod def get_description(cls): return "Lennard-Jones potential, of the form; E = A/r**m - B/r**n"
@classmethod def _get_schema(cls): return load_schema("potential.lj.schema.json") @classmethod def _get_fitting_schema(cls): return load_schema("fitting.lj.schema.json") def _make_string(self, data, fitting_data=None): """write reaxff data in GULP input format Parameters ---------- data : dict dictionary of data species_filter : list[str] or None list of atomic symbols to filter by Returns ------- str: the potential file content int: number of potential flags for fitting """ lines = [] total_flags = 0 num_fit = 0 for indices in sorted(data["2body"]): species = [ "{:7s}".format(data["species"][int(i)]) for i in indices.split(INDEX_SEP) ] values = data["2body"][indices] lines.append( "lennard {lj_m} {lj_n}".format( lj_m=values.get("lj_m", 12), lj_n=values.get("lj_n", 6) ) ) if "lj_rmin" in values: values_string = "{lj_A:.8E} {lj_B:.8E} {lj_rmin:8.5f} {lj_rmax:8.5f}".format( **values ) else: values_string = "{lj_A:.8E} {lj_B:.8E} {lj_rmax:8.5f}".format(**values) total_flags += 2 if fitting_data is not None: flag_a = flag_b = 0 if "lj_A" in fitting_data.get("2body", {}).get(indices, []): flag_a = 1 if "lj_B" in fitting_data.get("2body", {}).get(indices, []): flag_b = 1 num_fit += flag_a + flag_b values_string += " {} {}".format(flag_a, flag_b) lines.append(" ".join(species) + " " + values_string) return PotentialContent("\n".join(lines), total_flags, num_fit)
[docs] def read_exising(self, lines): """read an existing potential file Parameters ---------- lines : list[str] Returns ------- dict the potential data Raises ------ IOError on parsing failure """ lineno = 0 symbol_set = set() terms = {} while lineno < len(lines): line = lines[lineno] if line.strip().startswith("lennard"): meta_values = line.strip().split() if len(meta_values) != 3: raise IOError( "expected `lennard` option to have only m & n variables: {}".format( line ) ) try: lj_m = int(meta_values[1]) lj_n = int(meta_values[2]) except ValueError: raise IOError( "expected `lennard` option to have only (integer) m & n variables: {}".format( line ) ) lineno, sset, results = self.read_atom_section( lines, lineno + 1, number_atoms=2, global_args={"lj_m": lj_m, "lj_n": lj_n}, ) symbol_set.update(sset) terms.update(results) lineno += 1 pot_data = {"species": sorted(symbol_set), "2body": {}} for key, value in terms.items(): indices = "-".join([str(pot_data["species"].index(term)) for term in key]) variables = value["values"].split() if len(variables) in [3, 5]: pot_data["2body"][indices] = { "lj_m": value["global"]["lj_m"], "lj_n": value["global"]["lj_n"], "lj_A": float(variables[0]), "lj_B": float(variables[1]), "lj_rmax": float(variables[2]), } elif len(variables) in [4, 6]: pot_data["2body"][indices] = { "lj_m": value["global"]["lj_m"], "lj_n": value["global"]["lj_n"], "lj_A": float(variables[0]), "lj_B": float(variables[1]), "lj_rmin": float(variables[2]), "lj_rmax": float(variables[3]), } else: raise IOError("expected 3, 4, 5 or 6 variables: {}".format(value)) return pot_data