import os
import warnings
import subprocess
[docs]
def find_binaries_in_path():
# Get the PATH environment variable
path = os.environ.get('PATH', '')
# Split the PATH into individual directories
path_dirs = path.split(':')
# Initialize a list to store the binaries
binaries = []
# Iterate through each directory in the PATH
for directory in path_dirs:
# Check if the directory exists
if os.path.isdir(directory):
# List all files in the directory
for file in os.listdir(directory):
file_path = os.path.join(directory, file)
# Check if the file is executable
if os.path.isfile(file_path) and os.access(file_path, os.X_OK):
binaries.append(file)
# Remove duplicates and sort the list
binaries = sorted(list(set(binaries)))
return binaries
[docs]
def get_mopac():
"""
Checks if the MOPAC binary is within the path. looks for approximate
alternatives. E.g., finds run_mopac7 on ubuntu22, but older MOPAC
versions might parse files differently, thus being incompatible with
this wrapper
"""
binaries = find_binaries_in_path()
if "mopac" in binaries:
return "mopac"
elif "run_mopac7" in binaries:
return "run_mopac7"
else:
print("No MOPAC binary found, fallback to unstable search")
for binary in binaries:
if "mopac" in binary.lower():
last_binary = binary
if "run" in binary:
return binary
if "last_binary" not in locals():
last_binary = None
print("MOPAC binary not found, returning None")
return last_binary
[docs]
def optional_imports(libs, namespace):
if isinstance(libs, str):
libs = [libs]
if not isinstance(libs, list):
raise AttributeError("please supply either a list or str to import")
for lib in libs:
try:
exec(lib, namespace)
except Exception as e:
warnings.warn(f"Failed to import {lib}\n{e}", ImportWarning)
[docs]
def xyz_identifier(geometry):
try:
geometry = geometry.split("\n")
if geometry[0].isnumeric():
geometry = geometry[1:]
geometry = "\n".join(geometry).strip().split("\n")
result = all([xyz_line_checker(line) for line in geometry])
return result, "\n".join([""]+geometry+[""])
except:
return False, None
[docs]
def xyz_line_checker(line):
line = line.split()
if len(line) != 4:
return False
if not isinstance(line[0], str):
return False
return all([float_checker(x) for x in line[1:]])
[docs]
def float_checker(string):
try:
float(string)
return True
except:
return False
[docs]
def checkOverlap(mol):
"""
checks mol object vor overlapping atoms
"""
threshhold = 0.01
conf = mol.GetConformer(0)
atoms = mol.GetNumAtoms()
overlapping_pairs = []
for i in range(atoms):
for j in range(i+1, atoms):
pos_i = conf.GetAtomPosition(i)
pos_j = conf.GetAtomPosition(j)
import numpy as np
dist = np.sqrt(sum((pos_i[k] - pos_j[k])**2 for k in range(3)))
if dist < threshhold:
overlapping_pairs.append((i, j))
return overlapping_pairs
[docs]
def BlockToXyz(s: str):
s = s.strip()
nindex = s.index("\n")
if s[:nindex].isnumeric():
s = s[nindex:].strip()
return s
[docs]
def get_version_string(mopac_path):
version_string = subprocess.run(
[mopac_path, "--version"], capture_output=True, text=True)
version_string = str(version_string.stdout.strip())
return version_string.split()[2]
if __name__ == "__main__":
print(get_mopac())
optional_imports("import numpy as np", globals())
optional_imports(["import matplotlib.pyplot as plt"], globals())
optional_imports("obviously wrong", globals())