def run(structure, input_type="cif", output_type="cif", l=1.2, h_i0=-2.0, charge_precision=3, method="ewald", m_r=2, m_k=2, eta=50.0, ionization_data_path=DEFAULT_IONIZATION_PATH, charge_data_path=DEFAULT_CHARGE_PATH): """Runs EQeq on the inputted structure, returning charge data. Args: structure: Either a filename or data encoding a chemical. input_type: (Optional) Specifies input type. Can be anything supported by openbabel, as well as "json" output_type: (Optional) Specifies the output type. Currently, options are "cif", "mol", "pdb", "car", "json", "list", and "files". The first four return modified chemical data formats, "list" returns a Python object, "json" is that object serialized, and "files" saves files of all possible output types. l: (Optional) Lambda, the dielectric screening parameter. h_i0: (Optional) The electron affinity of hydrogen. charge_precision: (Optional) Number of decimals to use for charges. method: (Optional) Method to use. Can be "direct" (default), "nonperiodic", or "ewald". m_r: (Optional) Number of unit cells to consider in "real space". This is measured radially, so m_r = 1 evaluates 27 unit cells. m_k: (Optional) Number of unit cells to consider in "frequency space". This is measured radially, so m_k = 1 evaluates 27 unit cells. eta: (Optional) Ewald splitting parameter ionization_data_path: (Optional) A path to the file containing ion- ization data. By default, assumes the data is in the EQeq folder and saved as "ionizationdata.dat". charge_data_path: (Optional) A path to the file containing charge- center data. By default, assumes the data is in the EQeq folder and saved as "chargecenters.dat". Returns: A string representing the charged crystal. Returns nothing if the output type is set to "files" """ # Error handling on string params. Should spare users some annoyance. o, m = output_type.lower(), method.lower() if o not in ["cif", "pdb", "car", "mol", "json", "list", "files"]: raise NotImplementedError("Output format '%s' is not supported!" % o) if m not in ["direct", "nonperiodic", "ewald"]: raise NotImplementedError("Method '%s' is not supported!" % m) # If linked to openbabel, use it to handle json interconversion externally if input_type != "cif": structure = format_converter.convert(structure, input_type, "cif") structure = structure.replace("\t", " ") # Calls libeqeq.so's run method, returning a string of data result = eqeq.run(structure, ("json" if output_type == "list" else output_type), l, h_i0, charge_precision, method, m_r, m_k, eta, ionization_data_path, charge_data_path) if output_type == "list": return json.loads(result) # This option appends atoms in json/object data with a "charge" attribute if output_type == "json": obj = format_converter.convert(structure, "cif", "object") result = json.loads(result) for atom, charge in zip(obj["atoms"], result): atom["charge"] = charge result = json.dumps(obj) return result
def convert(data, in_format, out_format, pretty=True, add_h=False): """Converts between two inputted chemical formats.""" # Decide on a json formatter depending on desired prettiness dumps = json.dumps if pretty else json.compress # Not doing this can cause segfaults in the underlying openbabel C++ if not IS_PY3: in_format.encode("ascii") out_format.encode("ascii") data.encode("ascii", "replace") # If it's a json string, load it. NOTE: This is a custom chemical format if in_format == "json" and isinstance(data, str if IS_PY3 else basestring): data = json.loads(data) # These use the open babel library to interconvert, with additions for json mol = (json_to_pybel(data) if in_format == "json" else pybel.readstring(in_format, data)) # Infer structure in cases where the input format has no specification # or the specified structure is small if not mol.OBMol.HasNonZeroCoords() or len(mol.atoms) < 50: mol.make3D(steps=500) mol.OBMol.Center() if add_h: mol.addh() return (dumps(pybel_to_json(mol)) if out_format == "json" else mol.write(out_format))
def convert(data, in_format, out_format, pretty=True, add_h=False): """Converts between two inputted chemical formats.""" # Decide on a json formatter depending on desired prettiness dumps = json.dumps if pretty else json.compress # If it's a json string, load it. NOTE: This is a custom chemical format if in_format == "json" and isinstance(data, basestring): data = json.loads(data) # These use the open babel library to interconvert, with additions for json mol = (json_to_pybel(data) if in_format == "json" else pybel.readstring(in_format.encode("ascii"), data.encode("ascii", "replace"))) # Infer structure in cases where the input format has no specification # or the specified structure is small if not mol.OBMol.HasNonZeroCoords() or len(mol.atoms) < 50: mol.make3D(steps=500) mol.OBMol.Center() if add_h: mol.addh() return (dumps(pybel_to_json(mol)) if out_format == "json" else mol.write(out_format.encode("ascii")))
def convert(data, in_format, out_format, pretty=False): """Converts between two inputted chemical formats. Args: data: A string representing the chemical file to be converted. If the `in_format` is "json", this can also be a Python object in_format: The format of the `data` string. Can be "json" or any format recognized by Open Babel out_format: The format to convert to. Can be "json" or any format recognized by Open Babel pretty: (Optional) If True and `out_format` is "json", will pretty- print the output for human readability Returns: A string representing the inputted `data` in the specified `out_format` """ # Decide on a json formatter depending on desired prettiness dumps = json.dumps if pretty else json.compress # If it's a json string, load it if in_format == "json" and isinstance(data, basestring): data = json.loads(data) # A little "hack" to format inputted json if in_format == "json" and out_format == "json": return json.dumps(data) # These are converted manually to retain crystallographic information if in_format == "json" and out_format == "cif": return json_to_cif(data) # These use the open babel library to interconvert, with additions for json mol = (json_to_pybel(data) if in_format == "json" else pybel.readstring(in_format.encode("ascii"), "".join(i for i in data if ord(i) < 128) .encode("ascii"))) # Infer structure in cases where the input format has no specification if not mol.OBMol.HasNonZeroCoords(): mol.make3D() mol.OBMol.Center() # EQeq takes a specific cif format that openbabel does not output. # This manually overrides that. if out_format == "cif": return json_to_cif(pybel_to_json(mol)) if out_format == "object": return pybel_to_json(mol) elif out_format == "json": return dumps(pybel_to_json(mol)) else: return mol.write(out_format)
def convert(data, in_format, out_format, pretty=False): """Converts between two inputted chemical formats. Args: data: A string representing the chemical file to be converted. If the `in_format` is "json", this can also be a Python object in_format: The format of the `data` string. Can be "json" or any format recognized by Open Babel out_format: The format to convert to. Can be "json" or any format recognized by Open Babel pretty: (Optional) If True and `out_format` is "json", will pretty- print the output for human readability Returns: A string representing the inputted `data` in the specified `out_format` """ # Decide on a json formatter depending on desired prettiness dumps = json.dumps if pretty else json.compress # If it's a json string, load it if in_format == "json" and isinstance(data, basestring): data = json.loads(data) # A little "hack" to format inputted json if in_format == "json" and out_format == "json": return json.dumps(data) # These are converted manually to retain crystallographic information if in_format == "json" and out_format == "cif": return json_to_cif(data) # These use the open babel library to interconvert, with additions for json mol = (json_to_pybel(data) if in_format == "json" else pybel.readstring( in_format.encode("ascii"), "".join(i for i in data if ord(i) < 128).encode("ascii"))) # Infer structure in cases where the input format has no specification if not mol.OBMol.HasNonZeroCoords(): mol.make3D() mol.OBMol.Center() # EQeq takes a specific cif format that openbabel does not output. # This manually overrides that. if out_format == "cif": return json_to_cif(pybel_to_json(mol)) if out_format == "object": return pybel_to_json(mol) elif out_format == "json": return dumps(pybel_to_json(mol)) else: return mol.write(out_format)
def convert(data, in_format, out_format, filename=None, pretty=False): """Converts between two inputted chemical formats. Args: data: A string representing the chemical file to be converted. If the `in_format` is "json", this can also be a Python object in_format: The format of the `data` string. Can be "json" or any format recognized by Open Babel out_format: The format to convert to. Can be "json" or any format recognized by Open Babel filename: (Optional) The name of the file containing `data`. This is used primarily to encode data saved in the file naming scheme of the old building-block format pretty: (Optional) If True and `out_format` is "json", will pretty- print the output for human readability Returns: A string representing the inputted `data` in the specified `out_format` """ # Decide on a json formatter depending on desired prettiness dumps = json.dumps if pretty else json.compress # If it's a json string, load it if in_format == "json" and isinstance(data, basestring): data = json.loads(data) # A little "hack" to format inputted json if in_format == "json" and out_format == "json": return json.dumps(data) # These use the open babel library to interconvert, with additions for json mol = (json_to_pybel(data) if in_format == "json" else pybel.readstring(in_format.encode("ascii"), "".join(i for i in data if ord(i) < 128) .encode("ascii"))) # Infer structure in cases where the input format has no specification if not mol.OBMol.HasNonZeroCoords(): mol.make3D() mol.OBMol.Center() return (dumps(pybel_to_json(mol, name=filename)) if out_format == "json" else mol.write(out_format.encode("ascii")))