from molSimplify.Classes.globalvars import globalvars
from molSimplify.Classes.ligand import (
ligand_assign_original,
ligand_breakdown,
)
from molSimplify.Scripts.geometry import distance
import numpy as np
# ########## UNIT CONVERSION
HF_to_Kcal_mol = 627.503
globs = globalvars()
[docs]def append_descriptors(descriptor_names, descriptors, list_of_names, list_of_props, prefix, suffix, no_suffix=False):
"""
Utility to build standardly formatted RACs.
Parameters
----------
descriptor_names : list
Descriptors names list to be appended to.
descriptors : list
Descriptors list to be appended to.
list_of_names : list
Names to be added.
list_of_props : list
Types of RACs.
prefix : str
Prefix to be added to names.
suffix : str
Suffix to be added to names.
no_suffix : bool
Flag indicating whether to include suffix.
Returns
-------
descriptor_names : list
Compiled list of descriptor names.
descriptors : list
Compiled list of descriptor values.
"""
try:
basestring
except NameError:
basestring = str
str_bool = isinstance(list_of_names[0], basestring)
for names in list_of_names:
if str_bool:
names_2 = [names]
else:
names_2 = names.copy()
if no_suffix:
names_2 = ["-".join([prefix, str(i)]) for i in names_2]
else:
names_2 = ["-".join([prefix, str(i), suffix]) for i in names_2]
descriptor_names += names_2
for values in list_of_props:
if str_bool:
descriptors.append(values)
else:
descriptors.extend(values)
return descriptor_names, descriptors
[docs]def append_descriptor_derivatives(descriptor_derivative_names, descriptor_derivatives,
mat_of_names, dmat, prefix, suffix):
"""
Utility to build standardly formatted RACs derivatives.
Parameters
----------
descriptor_derivative_names : list
RAC names, will be a matrix, will be appended to.
descriptor_derivatives : list
RAC, will be appended to.
mat_of_names : list
Names, will be added.
dmat : list
Mat of RAC derivatives.
prefix : str
RAC prefix.
suffix : str
RAC suffix.
Returns
-------
descriptor_derivative_names : list
Compiled list (matrix) of descriptor derivative names.
descriptor_derivatives : list
Derivatives of RACs w.r.t atomic props (matrix).
"""
for names in mat_of_names:
jnames = ["-".join([prefix, str(i), suffix]) for i in names]
descriptor_derivative_names.append(jnames)
if descriptor_derivatives is None:
descriptor_derivatives = dmat
else:
descriptor_derivatives = np.row_stack([descriptor_derivatives, dmat])
return descriptor_derivative_names, descriptor_derivatives
[docs]def autocorrelation(mol, prop_vec, orig, d, oct=True, use_dist=False, size_normalize=False):
"""
Calculate and return the products autocorrelation.
Parameters
----------
mol : mol3D
mol3D object to calculate autocorrelation over.
prop_vec : np.array
Property of atoms in mol in order of index.
orig : int
Zero-indexed starting atom.
d : int
Maximum number of hops to travel.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Flag is octahedral complex, by default True.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
Returns
-------
result_vector : np.array
Assembled products autocorrelations.
"""
if d < 0:
raise Exception('d must be a non-negative integer.')
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
if use_dist:
result_vector[hopped] = 0.5 * abs(prop_vec[orig]) ** 2.4
else:
result_vector[hopped] = prop_vec[orig] * prop_vec[orig]
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
if use_dist:
this_dist = mol.get_pair_distance(orig, inds)
result_vector[hopped] += prop_vec[orig] * prop_vec[inds] / this_dist
else:
result_vector[hopped] += prop_vec[orig] * prop_vec[inds]
historical_set.update(active_set)
active_set = new_active_set
if size_normalize:
result_vector = result_vector / mol.natoms
return (result_vector)
[docs]def autocorrelation_derivative(mol, prop_vec, orig, d, oct=True):
"""
Returns derivative vector of products autocorrelations.
Parameters
----------
mol : mol3D
mol3D object to calculate derivatives over.
prop_vec : np.array
Property of atoms in mol in order of index.
orig : int
Zero-indexed starting atom.
d : int
Maximum number of hops to travel.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Flag is octahedral complex, by default True.
Returns
-------
derivative_mat : np.array
RAC derivatives matrix.
"""
derivative_mat = np.zeros((d + 1, len(prop_vec)))
# Loop for each atom.
hopped = 0
active_set = set([orig])
historical_set = set()
for derivate_ind in range(0, len(prop_vec)):
if derivate_ind == orig:
derivative_mat[hopped, derivate_ind] = 2 * prop_vec[orig]
else:
derivative_mat[hopped, derivate_ind] = 0
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
for derivate_ind in range(0, len(prop_vec)):
if derivate_ind == orig:
derivative_mat[hopped, derivate_ind] += prop_vec[inds]
elif derivate_ind == inds:
derivative_mat[hopped, derivate_ind] += prop_vec[orig]
historical_set.update(active_set)
active_set = new_active_set
return (derivative_mat)
[docs]def deltametric(mol, prop_vec, orig, d, oct=True, use_dist=False, size_normalize=False):
"""
Returns the deltametric autocorrelation.
Parameters
----------
mol : mol3D
mol3D object to calculate deltametric autocorrelation over.
prop_vec : np.array
Property of atoms in mol in order of index.
orig : int
Zero-indexed starting atom.
d : int
Maximum number of hops to travel.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Flag is octahedral complex, by default True.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
Returns
-------
results_vector : np.array
Deltametric autocorrelations.
"""
if d < 0:
raise Exception('d must be a non-negative integer.')
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
if use_dist:
this_dist = mol.get_pair_distance(orig, inds)
result_vector[hopped] += (prop_vec[orig] - prop_vec[inds]) / (this_dist + 1e-6)
else:
result_vector[hopped] += prop_vec[orig] - prop_vec[inds]
historical_set.update(active_set)
active_set = new_active_set
if size_normalize:
result_vector = result_vector / mol.natoms
return (result_vector)
[docs]def deltametric_derivative(mol, prop_vec, orig, d, oct=True):
"""
Returns the deltametric autocorrelation derivative vector.
Parameters
----------
mol : mol3D
mol3D object to calculate deltametric autocorrelation derivative over.
prop_vec : np.array
Property of atoms in mol in order of index.
orig : int
Zero-indexed starting atom.
d : int
Maximum number of hops to travel.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Flag is octahedral complex, by default True.
Returns
-------
derivative_mat : np.array
Deltametric autocorrelation derivatives matrix.
"""
derivative_mat = np.zeros((d + 1, len(prop_vec)))
hopped = 0
active_set = set([orig])
historical_set = set()
# The zero-depth element is always zero.
for derivate_ind in range(0, len(prop_vec)):
derivative_mat[hopped, derivate_ind] = 0.0
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
for derivate_ind in range(0, len(prop_vec)):
if derivate_ind == orig:
derivative_mat[hopped, derivate_ind] += 1
elif derivate_ind == inds:
derivative_mat[hopped, derivate_ind] += -1
historical_set.update(active_set)
active_set = new_active_set
return (derivative_mat)
[docs]def construct_property_vector(mol, prop, oct=True, modifier=False, custom_property_dict={},
transition_metals_only=True):
"""
Assigns the value of property for atom i (zero index) in mol to position i in returned vector.
Parameters
----------
mol : mol3D
Molecule to generate property vector for.
prop : str
Property to generate vector for - Acceptable prop values: ['electronegativity',
'nuclear_charge', 'ident', 'topology', 'ox_nuclear_charge', 'size', 'vdwrad',
'group_number', 'polarizability', 'bondvalence', 'num_bonds',
'bondvalence_devi', 'bodavrg', 'bodstd', 'charge']
oct : bool, optional
Flag if octahedral complex, by default True.
modifier : bool, optional
If passed - dict, used to modify prop vector (e.g., for adding
ONLY used with ox_nuclear_charge ox or charge)
{"Fe":2, "Co": 3} etc., by default False.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
transition_metals_only : bool, optional
Flag if only transition metals counted as metals, by default True.
Returns
-------
w : np.array
Property vector for mol by atom.
"""
allowed_strings = [
'electronegativity', 'nuclear_charge', 'ident', 'topology',
'ox_nuclear_charge', 'size', 'vdwrad', 'group_number', 'polarizability',
'bondvalence', 'num_bonds', 'bondvalence_devi', 'bodavrg', 'bodstd',
'charge',
]
if len(custom_property_dict):
for k in list(custom_property_dict):
allowed_strings += [k]
prop_dict = dict()
w = np.zeros(mol.natoms)
done = False
if prop not in allowed_strings:
print(f'error, property {prop} is not a vaild choice')
print(f'options are {allowed_strings}')
return False
if prop == 'electronegativity':
prop_dict = globs.endict()
elif prop == 'size':
at_keys = list(globs.amass().keys())
for keys in at_keys:
values = globs.amass()[keys][2]
prop_dict.update({keys: values})
elif prop == 'nuclear_charge':
at_keys = list(globs.amass().keys())
for keys in at_keys:
values = globs.amass()[keys][1]
prop_dict.update({keys: values})
elif prop == 'group_number': # Uses number of valence electrons
at_keys = list(globs.amass().keys())
for keys in at_keys:
values = globs.amass()[keys][3]
prop_dict.update({keys: values})
elif prop == 'ox_nuclear_charge':
if modifier:
at_keys = list(globs.amass().keys())
for keys in at_keys:
values = globs.amass()[keys][1]
if keys in list(modifier.keys()):
values -= float(modifier[keys]) # assumes oxidation state provided (i.e., Fe(IV))
prop_dict.update({keys: values})
else:
print('Error, must give modifier with ox_nuclear_charge')
return False
elif prop == 'polarizability':
prop_dict = globs.polarizability()
for i, atoms in enumerate(mol.getAtoms()):
atom_type = atoms.symbol()
w[i] = prop_dict[atom_type]
elif prop == 'ident':
at_keys = list(globs.amass().keys())
for keys in at_keys:
prop_dict.update({keys: 1})
elif prop == 'topology':
for i, atoms in enumerate(mol.getAtoms()):
w[i] = len(mol.getBondedAtomsSmart(i, oct=oct))
done = True
elif prop == 'vdwrad':
prop_dict = globs.vdwrad()
for i, atoms in enumerate(mol.getAtoms()):
atom_type = atoms.symbol()
if atom_type in globs.metalslist():
w[i] = globs.amass()[atoms.symbol()][2]
else:
w[i] = prop_dict[atoms.symbol()]
done = True
elif prop == 'bondvalence':
assert len(mol.getAtoms()) == len(mol.bv_dict)
for i, atoms in enumerate(mol.getAtoms()):
w[i] = mol.bv_dict[i]
done = True
elif prop == 'num_bonds':
for i, atom in enumerate(mol.getAtoms()):
if atom.ismetal(transition_metals_only=transition_metals_only):
w[i] = len(mol.getBondedAtomsSmart(i, oct=oct))
else:
w[i] = globs.bondsdict()[atom.symbol()]
done = True
elif prop == 'bondvalence_devi':
assert len(mol.getAtoms()) == len(mol.bvd_dict)
for i, atoms in enumerate(mol.getAtoms()):
w[i] = mol.bvd_dict[i]
done = True
elif prop == 'bodavrg':
assert len(mol.getAtoms()) == len(mol.bodavrg_dict)
for i, atoms in enumerate(mol.getAtoms()):
w[i] = mol.bodavrg_dict[i]
done = True
elif prop == 'bodstd':
assert len(mol.getAtoms()) == len(mol.bodstd_dict)
for i, atoms in enumerate(mol.getAtoms()):
w[i] = mol.bodstd_dict[i]
done = True
elif prop == 'charge':
assert len(mol.getAtoms()) == len(mol.charge_dict)
for i, atoms in enumerate(mol.getAtoms()):
w[i] = mol.charge_dict[i]
done = True
elif prop in custom_property_dict:
for i, atom in enumerate(mol.getAtoms()):
try:
w[i] = custom_property_dict[prop][atom.symbol()]
except KeyError:
raise KeyError(f'custom_property_dict dictionary for property {prop} is missing an entry for the element {atom.symbol()}.')
done = True
if not done:
for i, atoms in enumerate(mol.getAtoms()):
w[i] = prop_dict[atoms.symbol()]
return (w)
[docs]def full_autocorrelation(mol, prop, d, oct=True, modifier=False, use_dist=False, size_normalize=False, custom_property_dict={}, transition_metals_only=True):
"""
Calculate full scope product autocorrelations (i.e., start at every atom,
and branch out up to depth d).
Parameters
----------
mol : mol3D
Molecule to calculate full scope RAC over.
prop : str
Property to evaluate.
d : int
Maximum depth of full scope autocorrelation.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Is octahedral flag, by default True.
modifier : bool, optional
Use ox modifier, by default False.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
transition_metals_only : bool, optional
Flag if only transition metals counted as metals, by default True.
Returns
-------
autocorrelation_vector : np.array
Full scope product autocorrelation values.
"""
if d < 0:
raise Exception('d must be a non-negative integer.')
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier, custom_property_dict=custom_property_dict, transition_metals_only=transition_metals_only)
index_set = list(range(0, mol.natoms))
autocorrelation_vector = np.zeros(d + 1)
for centers in index_set:
autocorrelation_vector += autocorrelation(mol, w, centers, d, oct=oct, use_dist=use_dist,
size_normalize=size_normalize)
return (autocorrelation_vector)
[docs]def full_autocorrelation_derivative(mol, prop, d, oct=True, modifier=False):
"""
Calculate full scope product autocorrelations derivatives
(i.e., start at every atom up to depth d).
Parameters
----------
mol : mol3D
Molecule to calculate full scope RAC over.
prop : str
Property to evaluate.
d : int
Maximum depth of scope to evaluate.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Is octahedral flag, by default True.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
modifier : bool, optional
Use ox modifier, by default False.
Returns
-------
autocorrelation_derivative_mat : np.array
Full scope autocorrelation derivative matrix.
"""
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier)
index_set = list(range(0, mol.natoms))
autocorrelation_derivative_mat = np.zeros((d + 1, mol.natoms))
for centers in index_set:
autocorrelation_derivative_mat += autocorrelation_derivative(mol, w, centers, d, oct=oct)
return (autocorrelation_derivative_mat)
[docs]def generate_full_complex_autocorrelations(mol,
depth=4, oct=True,
flag_name=False, modifier=False,
use_dist=False, size_normalize=False,
Gval=False, NumB=False, polarizability=False,
custom_property_dict={},
transition_metals_only=True,
flatten=False):
"""
Utility to manage full complex autocorrelation generation and labeling.
Works on any molecule, not just TM complexes.
Use size_normalize=True to average over all start atoms (all atoms in molecule),
mimicking behavior of generate_metal_* and generate_atomonly_* functions.
Parameters
----------
mol : mol3D
Molecule used for full scope.
depth : int, optional
Maximum depth of autocorrelations to evaluate, by default 4.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Is an octahedral complex, by default True.
flag_name : bool, optional
Prepend "f_all" to results to track full complex, by default False.
modifier : bool, optional
Use ox_modifier on metal charge, by default False.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
Gval : bool, optional
Use G value as RAC, by default False.
NumB : bool, optional
Use number of bonds as RAC, by default False.
polarizability : bool, optional
Use polarizability (alpha) as RAC, by default False.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
If provided, other property RACs (e.g., Z, S, T)
will not be made.
transition_metals_only : bool, optional
Flag if only transition metals counted as metals, by default True.
flatten : bool, optional
Flag to change format of returned dictionary, by default False.
Makes values of dictionary not be nested lists.
Returns
-------
results_dictionary : dict
Formatted dictionary with {'colnames': colnames, 'results': result}.
For key colnames, value is list of lists of str.
For key results, value is list of np.array.
"""
if depth < 0:
raise Exception('depth must be a non-negative integer.')
result = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
if polarizability:
allowed_strings += ["polarizability"]
labels_strings += ["alpha"]
if len(custom_property_dict):
allowed_strings, labels_strings = [], []
for k in list(custom_property_dict):
allowed_strings += [k]
labels_strings += [k]
for ii, properties in enumerate(allowed_strings):
metal_ac = full_autocorrelation(mol, properties, depth,
oct=oct, modifier=modifier,
use_dist=use_dist,
size_normalize=size_normalize,
custom_property_dict=custom_property_dict,
transition_metals_only=transition_metals_only)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(metal_ac)
if flatten:
colnames = [i for j in colnames for i in j]
result = [i for j in result for i in j]
if flag_name:
results_dictionary = {'colnames': colnames, 'results_f_all': result}
else:
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_full_complex_autocorrelation_derivatives(mol, depth=4, oct=True, flag_name=False,
modifier=False, Gval=False, NumB=False):
"""
Utility to manage full complex autocorrelation derivative generation and labeling.
Parameters
----------
mol : mol3D
Molecule used for full scope.
depth : int, optional
Maximum depth of autocorrelations to evaluate, by default 4.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Is an octahedral complex, by default True.
flag_name : bool, optional
Prepend "f_all" to results to track full complex, by default False.
modifier : bool, optional
Use ox_modifier on metal charge, by default False.
Gval : bool, optional
Use G value as RAC, by default False.
NumB : bool, optional
Use number of bonds as RAC, by default False.
Returns
-------
results_dictionary : dict
Formatted dictionary with {'colnames': colnames, 'results': result}.
"""
result = None
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
f_ac_der = full_autocorrelation_derivative(mol, properties, depth, oct=oct, modifier=modifier)
for i in range(0, depth + 1):
colnames.append(['d' + labels_strings[ii] + '-' + str(i) + '/d' + labels_strings[ii] + str(j) for j in
range(0, mol.natoms)])
# colnames.append(this_colnames)
if result is None:
result = f_ac_der
else:
result = np.row_stack([result, f_ac_der])
if flag_name:
results_dictionary = {'colnames': colnames, 'results_f_all': result}
else:
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def atom_only_autocorrelation(mol, prop, d, atomIdx, oct=True, use_dist=False, size_normalize=False, custom_property_dict={}):
"""
Calculate product autocorrelation vectors from a given atom or list of atoms.
Parameters
----------
mol : mol3D
Molecule to calculate atom-only autocorrelations from.
prop : str
Property to evaluate.
d : int
Maximum depth to calculate autocorrelation over.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
atomIdx : int or list of int
Atoms from which the autocorrelation vector should be started.
List of indices or a single index.
oct : bool, optional
Use octahedral flag, by default True.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
Returns
-------
autocorrelation_vector : np.array
List of atom-only autocorrelations.
"""
if d < 0:
raise Exception('d must be a non-negative integer.')
w = construct_property_vector(mol, prop, oct, custom_property_dict=custom_property_dict)
autocorrelation_vector = np.zeros(d + 1)
if hasattr(atomIdx, "__len__"): # Indicative of a list of indices.
for elements in atomIdx:
autocorrelation_vector += autocorrelation(mol, w, elements, d, oct=oct, use_dist=use_dist,
size_normalize=size_normalize)
autocorrelation_vector = np.divide(autocorrelation_vector, len(atomIdx)) # Averaging.
else: # Single index.
autocorrelation_vector += autocorrelation(mol, w, atomIdx, d, oct=oct, use_dist=use_dist,
size_normalize=size_normalize)
return (autocorrelation_vector)
[docs]def atom_only_autocorrelation_derivative(mol, prop, d, atomIdx, oct=True):
"""
Calculate product autocorrelation derivative vectors from a given atom or list of atoms
(e.g., up to depth 4 from the connecting atoms).
Parameters
----------
mol : mol3D
Molecule to calculate atom-only autocorrelation derivatives from.
prop : str
Property to evaluate.
d : int
Maximum depth to calculate derivatives over.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
atomIdx : int or list of int
Atoms from which the autocorrelation vector should be centered.
List of indices or a single index.
oct : bool, optional
Use octahedral flag, by default True.
Returns
-------
autocorrelation_derivative_mat : np.array
List of atom-only autocorrelation derivatives.
"""
w = construct_property_vector(mol, prop, oct)
autocorrelation_derivative_mat = np.zeros((d + 1, mol.natoms))
if hasattr(atomIdx, "__len__"):
for elements in atomIdx:
autocorrelation_derivative_mat += autocorrelation_derivative(mol, w, elements, d, oct=oct)
autocorrelation_derivative_mat = np.divide(autocorrelation_derivative_mat, len(atomIdx))
else:
autocorrelation_derivative_mat += autocorrelation_derivative(mol, w, atomIdx, d, oct=oct)
return (autocorrelation_derivative_mat)
[docs]def atom_only_deltametric(mol, prop, d, atomIdx, oct=True, modifier=False,
use_dist=False, size_normalize=False, custom_property_dict={}):
"""
Calculate deltametric autocorrelation vectors from a given atom or list of atoms.
Parameters
----------
mol : mol3D
Molecule to calculate atom-only deltametrics from.
prop : str
Property to evaluate.
d : int
Maximum depth to calculate deltametric over.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
atomIdx : int or list of int
Atoms from which the autocorrelation vector should be started.
List of indices or a single index.
oct : bool, optional
Use octahedral flag, by default True.
modifier : bool, optional
Use ox modifier, by default False.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
Returns
-------
deltametric_vector : np.array
List of atom-only deltametric autocorrelations.
"""
if d < 0:
raise Exception('d must be a non-negative integer.')
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier, custom_property_dict=custom_property_dict)
deltametric_vector = np.zeros(d + 1)
if hasattr(atomIdx, "__len__"):
for elements in atomIdx:
deltametric_vector += deltametric(mol, w, elements, d, oct=oct, use_dist=use_dist, size_normalize=size_normalize)
deltametric_vector = np.divide(deltametric_vector, len(atomIdx))
else:
deltametric_vector += deltametric(mol, w, atomIdx, d, oct=oct, use_dist=use_dist, size_normalize=size_normalize)
return (deltametric_vector)
[docs]def atom_only_deltametric_derivative(mol, prop, d, atomIdx, oct=True, modifier=False):
"""
Calculate deltametric autocorrelation derivative vectors
from a given atom or list of atoms
(e.g., up to depth 4 from the connecting atoms).
Parameters
----------
mol : mol3D
Molecule to calculate atom-only deltametric autocorrelation derivatives from.
prop : str
Property to evaluate.
d : int
Maximum depth to calculate derivatives over.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
atomIdx : int or list of int
Atoms from which the autocorrelation vector should be centered.
List of indices or a single index.
oct : bool, optional
Use octahedral flag, by default True.
modifier : bool, optional
Use ox_modifier, by default False.
Returns
-------
deltametric_derivative_mat : np.array
Matrix of atom-only deltametric autocorrelation derivatives.
"""
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier)
deltametric_derivative_mat = np.zeros((d + 1, mol.natoms))
if hasattr(atomIdx, "__len__"):
for elements in atomIdx:
deltametric_derivative_mat += deltametric_derivative(mol, w, elements, d, oct=oct)
deltametric_derivative_mat = np.divide(deltametric_derivative_mat, len(atomIdx))
else:
deltametric_derivative_mat += deltametric_derivative(mol, w, atomIdx, d, oct=oct)
return (deltametric_derivative_mat)
[docs]def generate_atomonly_autocorrelations(mol, atomIdx, depth=4, oct=True, Gval=False, NumB=False, polarizability=False,
use_dist=False, size_normalize=False, custom_property_dict={}, flatten=False):
"""
This function gets autocorrelations for a molecule starting
from specified indices.
Parameters
----------
mol : mol3D
mol3D molecule to analyze.
atomIdx : int or list of int
Index or list of indices of atoms to start autocorrelation from.
depth : int, optional
Maximum depth of autocorrelations.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Use octahedral criteria for structure evaluation, by default True.
If complex is octahedral, will use better bond checks.
Gval : bool, optional
Use G value as RAC, by default False.
NumB : bool, optional
Use number of bonds as descriptor property, by default False.
polarizability : bool, optional
Use polarizability (alpha) as RAC, by default False.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
If provided, other property RACs (e.g., Z, S, T)
will not be made.
flatten : bool, optional
Flag to change format of returned dictionary, by default False.
Makes values of dictionary not be nested lists.
Returns
-------
results_dictionary : dict
Dictionary of atom only RAC names and values.
For key colnames, value is list of lists of str.
For key results, value is list of np.array.
"""
if depth < 0:
raise Exception('depth must be a non-negative integer.')
result = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
if polarizability:
allowed_strings += ['polarizability']
labels_strings += ['alpha']
if len(custom_property_dict):
allowed_strings, labels_strings = [], []
for k in list(custom_property_dict):
allowed_strings += [k]
labels_strings += [k]
for ii, properties in enumerate(allowed_strings):
atom_only_ac = atom_only_autocorrelation(mol, properties, depth, atomIdx, oct=oct,
use_dist=use_dist, size_normalize=size_normalize, custom_property_dict=custom_property_dict)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(atom_only_ac)
if flatten:
colnames = [i for j in colnames for i in j]
result = [i for j in result for i in j]
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_atomonly_autocorrelation_derivatives(mol, atomIdx, depth=4, oct=True, NumB=False, Gval=False):
# # This function gets the d/dx for autocorrelations for a molecule starting
# # in one single atom only.
# Inputs:
# mol - mol3D class
# atomIdx - int, index of atom3D class
result = None
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
atom_only_ac = atom_only_autocorrelation_derivative(mol, properties, depth, atomIdx, oct=oct)
for i in range(0, depth + 1):
colnames.append(['d' + labels_strings[ii] + '-' + str(i) + '/d' + labels_strings[ii] + str(j) for j in
range(0, mol.natoms)])
if result is None:
result = atom_only_ac
else:
result = np.row_stack([result, atom_only_ac])
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_atomonly_deltametrics(mol, atomIdx, depth=4, oct=True, Gval=False, NumB=False, polarizability=False,
use_dist=False, size_normalize=False, custom_property_dict={}, flatten=False, non_trivial=False):
"""
This function gets deltametrics for a molecule starting
from specified indices.
Parameters
----------
mol : mol3D
mol3D molecule to analyze.
atomIdx : int or list of int
Index or list of indices of atoms to start deltametric from.
depth : int, optional
Maximum depth of deltametrics.
For example, if set to 3, depths considered will be 0, 1, 2, and 3.
oct : bool, optional
Use octahedral criteria for structure evaluation, by default True.
If complex is octahedral, will use better bond checks.
Gval : bool, optional
Use G value as RAC, by default False.
NumB : bool, optional
Use number of bonds as descriptor property, by default False.
polarizability : bool, optional
Use polarizability (alpha) as RAC, by default False.
use_dist : bool, optional
Weigh autocorrelation by physical distance of scope atom from start atom,
by default False.
size_normalize : bool, optional
Whether or not to normalize by the number of atoms in molecule.
custom_property_dict : dict, optional
Keys are custom property names (str),
values are dictionaries mapping atom symbols (str, e.g., "H", "He") to
the numerical property (float) for that atom.
If provided, other property RACs (e.g., Z, S, T)
will not be made.
flatten : bool, optional
Flag to change format of returned dictionary, by default False.
Makes values of dictionary not be nested lists.
non_trivial : bool, optional
Flag to exclude difference RACs of I, and depth zero difference
RACs. These RACs are always zero. By default False.
Returns
-------
results_dictionary : dict
Dictionary of atom only deltametric names and values.
For key colnames, value is list of lists of str.
For key results, value is list of np.array.
"""
if depth < 0:
raise Exception('depth must be a non-negative integer.')
result = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
if polarizability:
allowed_strings += ["polarizability"]
labels_strings += ["alpha"]
if non_trivial:
# Remove difference RACs of the identity.
allowed_strings.remove('ident')
labels_strings.remove('I')
if len(custom_property_dict):
allowed_strings, labels_strings = [], []
for k in list(custom_property_dict):
allowed_strings += [k]
labels_strings += [k]
for ii, properties in enumerate(allowed_strings):
atom_only_ac = atom_only_deltametric(mol, properties, depth, atomIdx, oct=oct,
use_dist=use_dist, size_normalize=size_normalize, custom_property_dict=custom_property_dict)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(atom_only_ac)
if non_trivial:
if depth == 0:
raise Exception('There are no non-trivial RACs.')
# Remove depth zero difference RACs.
for i in range(len(colnames)):
colnames[i] = colnames[i][1:]
result[i] = result[i][1:]
if flatten:
colnames = [i for j in colnames for i in j]
result = [i for j in result for i in j]
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_atomonly_deltametric_derivatives(mol, atomIdx, depth=4, oct=True, NumB=False, Gval=False):
# # This function gets deltametrics for a molecule starting
# # in one single atom only.
# Inputs:
# mol - mol3D class
# atomIdx - int, index of atom3D class
result = None
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
atom_only_ac_der = atom_only_deltametric_derivative(mol, properties, depth, atomIdx, oct=oct)
for i in range(0, depth + 1):
colnames.append(['d' + labels_strings[ii] + '-' + str(i) + '/d' + labels_strings[ii] + str(j) for j in
range(0, mol.natoms)])
if result is None:
result = atom_only_ac_der
else:
result = np.row_stack([result, atom_only_ac_der])
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def ratiometric(mol, prop_vec_num, prop_vec_den, orig, d, oct=True):
"""This function returns the ratiometrics for one atom.
Parameters
----------
mol : mol3D class
prop_vec : vector, property of atoms in mol in order of index
orig : int, zero-indexed starting atom
d : int, maximum number of hops to travel
oct : bool, if complex is octahedral, will use better bond checks
Returns
-------
result_vector : vector of prop_vec_num / prop_vec_den
"""
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
result_vector[hopped] = prop_vec_num[orig] / prop_vec_den[orig]
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
result_vector[hopped] += prop_vec_num[orig] / prop_vec_den[inds]
historical_set.update(active_set)
active_set = new_active_set
return (result_vector)
[docs]def summetric(mol, prop_vec, orig, d, oct=True):
"""This function returns the summetrics for one atom.
Parameters
----------
mol : mol3D class
prop_vec : vector, property of atoms in mol in order of index
orig : int, zero-indexed starting atom
d : int, maximum number of hops to travel
oct : bool, if complex is octahedral, will use better bond checks
Returns
-------
result_vector : vector of prop_vec_num / prop_vec_den
"""
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
result_vector[hopped] = prop_vec[orig] + prop_vec[orig]
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
result_vector[hopped] += prop_vec[orig] + prop_vec[inds]
historical_set.update(active_set)
active_set = new_active_set
return (result_vector)
[docs]def autocorrelation_catoms(mol, prop_vec, orig, d, oct=True, catoms=None):
# Calculate the autocorrelation for the orig to certain connecting atoms.
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
result_vector[hopped] = prop_vec[orig] * prop_vec[orig]
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
if this_atom == orig and (catoms is not None):
this_atoms_neighbors = catoms
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
result_vector[hopped] += prop_vec[orig] * prop_vec[inds]
historical_set.update(active_set)
active_set = new_active_set
return (result_vector)
[docs]def deltametric_catoms(mol, prop_vec, orig, d, oct=True, catoms=None):
# Calculate the deltametrics for the orig to certain connecting atoms.
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
if this_atom == orig and (catoms is not None):
this_atoms_neighbors = catoms
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
result_vector[hopped] += prop_vec[orig] - prop_vec[inds]
historical_set.update(active_set)
active_set = new_active_set
return (result_vector)
[docs]def multiatom_only_autocorrelation(mol, prop, d, oct=True,
func=autocorrelation, modifier=False,
additional_elements=False):
autocorrelation_vector = np.zeros(d + 1)
metal_list = mol.findMetal()
if additional_elements:
for element in additional_elements:
metal_list += mol.findAtomsbySymbol(element)
n_met = len(metal_list)
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier)
for metal_ind in metal_list:
autocorrelation_vector += func(mol, w, metal_ind, d, oct=oct)
autocorrelation_vector = np.divide(autocorrelation_vector, n_met)
return (autocorrelation_vector)
[docs]def atom_only_ratiometric(mol, prop_num, prop_den, d, atomIdx, oct=True):
# atomIdx must b either a list of indices
# or a single index.
w_num = construct_property_vector(mol, prop_num, oct)
w_den = construct_property_vector(mol, prop_den, oct)
autocorrelation_vector = np.zeros(d + 1)
if hasattr(atomIdx, "__len__"):
for elements in atomIdx:
autocorrelation_vector += ratiometric(mol, w_num, w_den, elements, d, oct=oct)
autocorrelation_vector = np.divide(autocorrelation_vector, len(atomIdx))
else:
autocorrelation_vector += ratiometric(mol, w_num, w_den, atomIdx, d, oct=oct)
return (autocorrelation_vector)
[docs]def atom_only_summetric(mol, prop, d, atomIdx, oct=True):
# atomIdx must b either a list of indices
# or a single index.
w = construct_property_vector(mol, prop, oct)
autocorrelation_vector = np.zeros(d + 1)
if hasattr(atomIdx, "__len__"):
for elements in atomIdx:
autocorrelation_vector += summetric(mol, w, elements, d, oct=oct)
autocorrelation_vector = np.divide(autocorrelation_vector, len(atomIdx))
else:
autocorrelation_vector += summetric(mol, w, atomIdx, d, oct=oct)
return (autocorrelation_vector)
[docs]def multiatom_only_deltametric(mol, prop, d, oct=True,
func=deltametric, modifier=False,
additional_elements=False):
deltametric_vector = np.zeros(d + 1)
metal_list = mol.findMetal()
if additional_elements:
for element in additional_elements:
metal_list += mol.findAtomsbySymbol(element)
n_met = len(metal_list)
w = construct_property_vector(mol, prop, oct=oct, modifier=modifier)
for metal_ind in mol.findMetal():
deltametric_vector += func(mol, w, metal_ind, d, oct=oct)
deltametric_vector = np.divide(deltametric_vector, n_met)
return (deltametric_vector)
[docs]def layer_density_in_3D(mol, prop_vec, orig, d, oct=True):
# # This function returns the density (prop^3/(d+1)^3)
# # for one atom.
# Inputs:
# mol - mol3D class
# prop_vec - vector, property of atoms in mol in order of index
# orig - int, zero-indexed starting atom
# d - int, number of hops to travel
# oct - bool, if complex is octahedral, will use better bond checks
result_vector = np.zeros(d + 1)
hopped = 0
active_set = set([orig])
historical_set = set()
result_vector[hopped] = prop_vec[orig] ** 3 / (hopped + 1) ** 3
while hopped < (d):
hopped += 1
new_active_set = set()
for this_atom in active_set:
# Prepare all atoms attached to this connection.
this_atoms_neighbors = mol.getBondedAtomsSmart(this_atom, oct=oct)
for bound_atoms in this_atoms_neighbors:
if (bound_atoms not in historical_set) and (bound_atoms not in active_set):
new_active_set.add(bound_atoms)
for inds in new_active_set:
result_vector[hopped] += prop_vec[inds] ** 3 / (hopped + 1) ** 3
historical_set.update(active_set)
active_set = new_active_set
return result_vector
[docs]def find_ligand_autocorrelations_oct(mol, prop, loud, depth, name=False,
oct=True, custom_ligand_dict=False):
# # This function takes a
# # symmetric (axial == axial,
# # equatorial == equatorial)
# # octahedral complex
# # and returns autocorrelations for
# # the axial and equatorial ligands.
# # custom_ligand_dict allows the user to skip the breakdown
# # in cases where 3D geo is not correct/formed
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
if custom_ligand_dict:
ax_ligand_list = custom_ligand_dict["ax_ligand_list"]
eq_ligand_list = custom_ligand_dict["eq_ligand_list"]
ax_con_int_list = custom_ligand_dict["ax_con_int_list"]
eq_con_int_list = custom_ligand_dict["eq_con_int_list"]
else:
liglist, ligdents, ligcons = ligand_breakdown(mol, BondedOct=oct)
(ax_ligand_list, eq_ligand_list, ax_natoms_list,
eq_natoms_list, ax_con_int_list, eq_con_int_list,
ax_con_list, eq_con_list, built_ligand_list) = ligand_assign_original(
mol, liglist, ligdents, ligcons, loud, name=False)
# Count ligands.
n_ax = len(ax_ligand_list)
n_eq = len(eq_ligand_list)
# Get full ligand AC.
ax_ligand_ac_full = []
eq_ligand_ac_full = []
for i in range(0, n_ax):
if list(ax_ligand_ac_full):
ax_ligand_ac_full += full_autocorrelation(ax_ligand_list[i].mol, prop, depth)
else:
ax_ligand_ac_full = full_autocorrelation(ax_ligand_list[i].mol, prop, depth)
ax_ligand_ac_full = np.divide(ax_ligand_ac_full, n_ax)
for i in range(0, n_eq):
if list(eq_ligand_ac_full):
eq_ligand_ac_full += full_autocorrelation(eq_ligand_list[i].mol, prop, depth)
else:
eq_ligand_ac_full = full_autocorrelation(eq_ligand_list[i].mol, prop, depth)
eq_ligand_ac_full = np.divide(eq_ligand_ac_full, n_eq)
# Get partial ligand AC.
ax_ligand_ac_con = []
eq_ligand_ac_con = []
for i in range(0, n_ax):
if list(ax_ligand_ac_con):
ax_ligand_ac_con += atom_only_autocorrelation(ax_ligand_list[i].mol, prop, depth, ax_con_int_list[i])
else:
ax_ligand_ac_con = atom_only_autocorrelation(ax_ligand_list[i].mol, prop, depth, ax_con_int_list[i])
ax_ligand_ac_con = np.divide(ax_ligand_ac_con, n_ax)
for i in range(0, n_eq):
if list(eq_ligand_ac_con):
eq_ligand_ac_con += atom_only_autocorrelation(eq_ligand_list[i].mol, prop, depth, eq_con_int_list[i])
else:
eq_ligand_ac_con = atom_only_autocorrelation(eq_ligand_list[i].mol, prop, depth, eq_con_int_list[i])
eq_ligand_ac_con = np.divide(eq_ligand_ac_con, n_eq)
return ax_ligand_ac_full, eq_ligand_ac_full, ax_ligand_ac_con, eq_ligand_ac_con
[docs]def find_ligand_autocorrelation_derivatives_oct(mol, prop, loud, depth, name=False,
oct=True, custom_ligand_dict=False):
# # This function takes a
# # symmetric (axial == axial,
# # equatorial == equatorial)
# # octahedral complex
# # and returns autocorrelations for
# # the axial and equatorial ligands.
# # custom_ligand_dict allows the user to skip the breakdown
# # in cases where 3D geo is not correct/formed
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
if custom_ligand_dict:
ax_ligand_list = custom_ligand_dict["ax_ligand_list"]
eq_ligand_list = custom_ligand_dict["eq_ligand_list"]
ax_con_int_list = custom_ligand_dict["ax_con_int_list"]
eq_con_int_list = custom_ligand_dict["eq_con_int_list"]
else:
liglist, ligdents, ligcons = ligand_breakdown(mol, BondedOct=oct)
(ax_ligand_list, eq_ligand_list, ax_natoms_list, eq_natoms_list, ax_con_int_list,
eq_con_int_list, ax_con_list, eq_con_list, built_ligand_list) = ligand_assign_original(
mol, liglist, ligdents, ligcons, loud, name=False)
# Count ligands.
n_ax = len(ax_ligand_list)
n_eq = len(eq_ligand_list)
# Get full ligand AC.
ax_ligand_ac_full_derivative = None
eq_ligand_eq_full_derivative = None
# Allocate the full Jacobian matrix.
ax_full_j = np.zeros([depth + 1, mol.natoms])
eq_full_j = np.zeros([depth + 1, mol.natoms])
ax_con_j = np.zeros([depth + 1, mol.natoms])
eq_con_j = np.zeros([depth + 1, mol.natoms])
# Full ligand ACs
for i in range(0, n_ax): # For each ax ligand
ax_ligand_ac_full_derivative = full_autocorrelation_derivative(ax_ligand_list[i].mol, prop, depth)
# Now we need to map back to full positions.
for ii, row in enumerate(ax_ligand_ac_full_derivative):
for original_ids in list(ax_ligand_list[i].ext_int_dict.keys()):
ax_full_j[ii, original_ids] += np.divide(row[ax_ligand_list[i].ext_int_dict[original_ids]], n_ax)
for i in range(0, n_eq): # For each eq ligand
# Now we need to map back to full positions.
eq_ligand_eq_full_derivative = full_autocorrelation_derivative(eq_ligand_list[i].mol, prop, depth)
for ii, row in enumerate(eq_ligand_eq_full_derivative):
for original_ids in list(eq_ligand_list[i].ext_int_dict.keys()):
eq_full_j[ii, original_ids] += np.divide(row[eq_ligand_list[i].ext_int_dict[original_ids]], n_eq)
# Ligand connection ACs
for i in range(0, n_ax):
ax_ligand_ac_con_derivative = atom_only_autocorrelation_derivative(ax_ligand_list[i].mol, prop, depth,
ax_con_int_list[i])
# Now we need to map back to full positions.
for ii, row in enumerate(ax_ligand_ac_con_derivative):
for original_ids in list(ax_ligand_list[i].ext_int_dict.keys()):
ax_con_j[ii, original_ids] += np.divide(row[ax_ligand_list[i].ext_int_dict[original_ids]], n_ax)
for i in range(0, n_eq):
eq_ligand_ac_con_derivative = atom_only_autocorrelation_derivative(eq_ligand_list[i].mol, prop, depth,
eq_con_int_list[i])
# Now we need to map back to full positions.
for ii, row in enumerate(eq_ligand_ac_con_derivative):
for original_ids in list(eq_ligand_list[i].ext_int_dict.keys()):
eq_con_j[ii, original_ids] += np.divide(row[eq_ligand_list[i].ext_int_dict[original_ids]], n_eq)
return ax_full_j, eq_full_j, ax_con_j, eq_con_j
[docs]def find_ligand_autocorrs_and_deltametrics_oct_dimers(mol, prop, depth, name=False,
oct=True, custom_ligand_dict=False):
# # This function takes a
# # symmetric (axial == axial,
# # equatorial == equatorial)
# # octahedral complex
# # and returns autocorrelations for
# # the axial and equatorial ligands.
# # custom_ligand_dict allows the user to skip the breakdown
# # in cases where 3D geo is not correct/formed
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
if custom_ligand_dict:
ax1_ligand_list = custom_ligand_dict["ax1_ligand_list"]
ax2_ligand_list = custom_ligand_dict["ax2_ligand_list"]
ax3_ligand_list = custom_ligand_dict["ax3_ligand_list"]
ax1_con_int_list = custom_ligand_dict["ax1_con_int_list"]
ax2_con_int_list = custom_ligand_dict["ax2_con_int_list"]
ax3_con_int_list = custom_ligand_dict["ax3_con_int_list"]
axligs = [ax1_ligand_list, ax2_ligand_list, ax3_ligand_list]
axcons = [ax1_con_int_list, ax2_con_int_list, ax3_con_int_list]
n_axs = [len(i) for i in axligs]
else:
raise ValueError('No custom ligand dict provided!')
# Get full ligand AC.
ax_ligand_ac_fulls = [False, False, False]
for axnum in range(3):
ax_ligand_ac_full = list()
for i in range(0, n_axs[axnum]):
if list(ax_ligand_ac_full):
ax_ligand_ac_full += full_autocorrelation(axligs[axnum][i].mol, prop, depth)
else:
ax_ligand_ac_full = full_autocorrelation(axligs[axnum][i].mol, prop, depth)
ax_ligand_ac_full = np.divide(ax_ligand_ac_full, n_axs[axnum])
ax_ligand_ac_fulls[axnum] = ax_ligand_ac_full
# Get partial ligand AC.
ax_ligand_ac_cons = [False, False, False]
for axnum in range(3):
ax_ligand_ac_con = list()
for i in range(0, n_axs[axnum]):
if list(ax_ligand_ac_con):
ax_ligand_ac_con += atom_only_autocorrelation(axligs[axnum][i].mol, prop, depth, axcons[axnum][i])
else:
ax_ligand_ac_con = atom_only_autocorrelation(axligs[axnum][i].mol, prop, depth, axcons[axnum][i])
ax_ligand_ac_con = np.divide(ax_ligand_ac_con, n_axs[axnum])
ax_ligand_ac_cons[axnum] = ax_ligand_ac_con
# Get deltametrics.
ax_delta_cons = [False, False, False]
for axnum in range(3):
ax_delta_con = list()
for i in range(0, n_axs[axnum]):
if list(ax_delta_con):
ax_delta_con += atom_only_deltametric(axligs[axnum][i].mol, prop, depth, axcons[axnum][i])
else:
ax_delta_con = atom_only_deltametric(axligs[axnum][i].mol, prop, depth, axcons[axnum][i])
ax_delta_con = np.divide(ax_delta_con, n_axs[axnum])
ax_delta_cons[axnum] = ax_delta_con
return ax_ligand_ac_fulls + ax_ligand_ac_cons + ax_delta_cons
[docs]def find_ligand_deltametrics_oct(mol, prop, loud, depth, name=False, oct=True, custom_ligand_dict=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
# # This function takes a
# # octahedral complex
# # and returns deltametrics for
# # the axial and equatorial ligands.
if custom_ligand_dict:
ax_ligand_list = custom_ligand_dict["ax_ligand_list"]
eq_ligand_list = custom_ligand_dict["eq_ligand_list"]
ax_con_int_list = custom_ligand_dict["ax_con_int_list"]
eq_con_int_list = custom_ligand_dict["eq_con_int_list"]
else:
liglist, ligdents, ligcons = ligand_breakdown(mol, BondedOct=oct)
(ax_ligand_list, eq_ligand_list, ax_natoms_list, eq_natoms_list, ax_con_int_list,
eq_con_int_list, ax_con_list, eq_con_list, built_ligand_list) = ligand_assign_original(
mol, liglist, ligdents, ligcons, loud, name=False)
# Count ligands.
n_ax = len(ax_ligand_list)
n_eq = len(eq_ligand_list)
# Get partial ligand AC.
ax_ligand_ac_con = []
eq_ligand_ac_con = []
for i in range(0, n_ax):
if list(ax_ligand_ac_con):
ax_ligand_ac_con += atom_only_deltametric(ax_ligand_list[i].mol, prop, depth, ax_con_int_list[i])
else:
ax_ligand_ac_con = atom_only_deltametric(ax_ligand_list[i].mol, prop, depth, ax_con_int_list[i])
ax_ligand_ac_con = np.divide(ax_ligand_ac_con, n_ax)
for i in range(0, n_eq):
if list(eq_ligand_ac_con):
eq_ligand_ac_con += atom_only_deltametric(eq_ligand_list[i].mol, prop, depth, eq_con_int_list[i])
else:
eq_ligand_ac_con = atom_only_deltametric(eq_ligand_list[i].mol, prop, depth, eq_con_int_list[i])
eq_ligand_ac_con = np.divide(eq_ligand_ac_con, n_eq)
return ax_ligand_ac_con, eq_ligand_ac_con
[docs]def find_ligand_deltametric_derivatives_oct(mol, prop, loud, depth, name=False, oct=True, custom_ligand_dict=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
# # This function takes a
# # octahedral complex
# # and returns deltametrics for
# # the axial and equatorial ligands.
if custom_ligand_dict:
ax_ligand_list = custom_ligand_dict["ax_ligand_list"]
eq_ligand_list = custom_ligand_dict["eq_ligand_list"]
ax_con_int_list = custom_ligand_dict["ax_con_int_list"]
eq_con_int_list = custom_ligand_dict["eq_con_int_list"]
else:
liglist, ligdents, ligcons = ligand_breakdown(mol, BondedOct=oct)
(ax_ligand_list, eq_ligand_list, ax_natoms_list, eq_natoms_list, ax_con_int_list,
eq_con_int_list, ax_con_list, eq_con_list, built_ligand_list) = ligand_assign_original(
mol, liglist, ligdents, ligcons, loud, name=False)
# Count ligands.
n_ax = len(ax_ligand_list)
n_eq = len(eq_ligand_list)
# Allocate the full Jacobian matrix.
ax_con_j = np.zeros([depth + 1, mol.natoms])
eq_con_j = np.zeros([depth + 1, mol.natoms])
for i in range(0, n_ax):
ax_ligand_ac_con_derivative = atom_only_deltametric_derivative(ax_ligand_list[i].mol, prop, depth,
ax_con_int_list[i])
# Now we need to map back to full positions.
for ii, row in enumerate(ax_ligand_ac_con_derivative):
for original_ids in list(ax_ligand_list[i].ext_int_dict.keys()):
ax_con_j[ii, original_ids] += np.divide(row[ax_ligand_list[i].ext_int_dict[original_ids]], n_ax)
for i in range(0, n_eq):
eq_ligand_ac_con_derivative = atom_only_deltametric_derivative(eq_ligand_list[i].mol, prop, depth,
eq_con_int_list[i])
for ii, row in enumerate(eq_ligand_ac_con_derivative):
for original_ids in list(eq_ligand_list[i].ext_int_dict.keys()):
eq_con_j[ii, original_ids] += np.divide(row[eq_ligand_list[i].ext_int_dict[original_ids]], n_eq)
return ax_con_j, eq_con_j
[docs]def generate_all_ligand_autocorrelations(mol, loud, depth=4, name=False, flag_name=False,
custom_ligand_dict=False, NumB=False, Gval=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
result_ax_full = list()
result_eq_full = list()
result_ax_con = list()
result_eq_con = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
(ax_ligand_ac_full,
eq_ligand_ac_full,
ax_ligand_ac_con,
eq_ligand_ac_con) = find_ligand_autocorrelations_oct(
mol,
properties,
loud=loud,
depth=depth,
name=name,
oct=True,
custom_ligand_dict=custom_ligand_dict)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result_ax_full.append(ax_ligand_ac_full)
result_eq_full.append(eq_ligand_ac_full)
result_ax_con.append(ax_ligand_ac_con)
result_eq_con.append(eq_ligand_ac_con)
if flag_name:
results_dictionary = {'colnames': colnames,
'result_ax_full_ac': result_ax_full,
'result_eq_full_ac': result_eq_full,
'result_ax_con_ac': result_ax_con,
'result_eq_con_ac': result_eq_con}
else:
results_dictionary = {'colnames': colnames,
'result_ax_full': result_ax_full,
'result_eq_full': result_eq_full,
'result_ax_con': result_ax_con,
'result_eq_con': result_eq_con}
return results_dictionary
[docs]def generate_all_ligand_autocorrelation_derivatives(mol, loud, depth=4, name=False, flag_name=False,
custom_ligand_dict=False, NumB=False, Gval=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
result_ax_full = None
result_eq_full = None
result_ax_con = None
result_eq_con = None
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
ax_ligand_ac_full, eq_ligand_ac_full, ax_ligand_ac_con, eq_ligand_ac_con = find_ligand_autocorrelation_derivatives_oct(
mol,
properties,
loud=loud,
depth=depth,
name=name,
oct=True,
custom_ligand_dict=custom_ligand_dict)
for i in range(0, depth + 1):
colnames.append(['d' + labels_strings[ii] + '-' + str(i) + '/d' + labels_strings[ii] + str(j) for j in
range(0, mol.natoms)])
if result_ax_full is None:
result_ax_full = ax_ligand_ac_full
else:
result_ax_full = np.row_stack([result_ax_full, ax_ligand_ac_full])
if result_eq_full is None:
result_eq_full = eq_ligand_ac_full
else:
result_eq_full = np.row_stack([result_eq_full, eq_ligand_ac_full])
if result_ax_con is None:
result_ax_con = ax_ligand_ac_con
else:
result_ax_con = np.row_stack([result_ax_con, ax_ligand_ac_con])
if result_eq_con is None:
result_eq_con = eq_ligand_ac_con
else:
result_eq_con = np.row_stack([result_eq_con, eq_ligand_ac_con])
if flag_name:
results_dictionary = {'colnames': colnames, 'result_ax_full_ac': result_ax_full,
'result_eq_full_ac': result_eq_full,
'result_ax_con_ac': result_ax_con, 'result_eq_con_ac': result_eq_con}
else:
results_dictionary = {'colnames': colnames, 'result_ax_full': result_ax_full, 'result_eq_full': result_eq_full,
'result_ax_con': result_ax_con, 'result_eq_con': result_eq_con}
return results_dictionary
[docs]def generate_all_ligand_autocorrs_and_deltametrics_dimers(mol, loud, depth=4, name=False, flag_name=False,
custom_ligand_dict=False, NumB=False, Gval=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
result_ax1_full = list()
result_ax2_full = list()
result_ax3_full = list()
result_ax1_con = list()
result_ax2_con = list()
result_ax3_con = list()
result_delta_ax1_con = list()
result_delta_ax2_con = list()
result_delta_ax3_con = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
# lig_autocorrs is a list of length 6 (ax{i}_ligand_ac_fulls, ax{i}_ligand_ac_cons).
lig_autocorrs = find_ligand_autocorrs_and_deltametrics_oct_dimers(mol,
properties,
depth=depth,
name=name,
oct=True,
custom_ligand_dict=custom_ligand_dict)
this_colnames = []
assert all([len(i) > 0 for i in lig_autocorrs]), 'Some ligand autocorrelations are empty! %s' % lig_autocorrs
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result_ax1_full.append(lig_autocorrs[0])
result_ax2_full.append(lig_autocorrs[1])
result_ax3_full.append(lig_autocorrs[2])
result_ax1_con.append(lig_autocorrs[3])
result_ax2_con.append(lig_autocorrs[4])
result_ax3_con.append(lig_autocorrs[5])
result_delta_ax1_con.append(lig_autocorrs[6])
result_delta_ax2_con.append(lig_autocorrs[7])
result_delta_ax3_con.append(lig_autocorrs[8])
results_dictionary = {'colnames': colnames,
'result_ax1_full': result_ax1_full,
'result_ax2_full': result_ax2_full,
'result_ax3_full': result_ax3_full,
'result_ax1_con': result_ax1_con,
'result_ax2_con': result_ax2_con,
'result_ax3_con': result_ax3_con,
'result_delta_ax1_con': result_delta_ax1_con,
'result_delta_ax2_con': result_delta_ax2_con,
'result_delta_ax3_con': result_delta_ax3_con}
return results_dictionary
[docs]def generate_all_ligand_deltametrics(mol, loud, depth=4, name=False, flag_name=False,
custom_ligand_dict=False, NumB=False, Gval=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
result_ax_con = list()
result_eq_con = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
ax_ligand_ac_con, eq_ligand_ac_con = find_ligand_deltametrics_oct(mol, properties, loud, depth, name, oct=True,
custom_ligand_dict=custom_ligand_dict)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result_ax_con.append(ax_ligand_ac_con)
result_eq_con.append(eq_ligand_ac_con)
if flag_name:
results_dictionary = {'colnames': colnames, 'result_ax_con_del': result_ax_con,
'result_eq_con_del': result_eq_con}
else:
results_dictionary = {'colnames': colnames, 'result_ax_con': result_ax_con, 'result_eq_con': result_eq_con}
return results_dictionary
[docs]def generate_all_ligand_deltametric_derivatives(mol, loud, depth=4, name=False, flag_name=False,
custom_ligand_dict=False, NumB=False, Gval=False):
# # custom_ligand_dict.keys() must be eq_ligands_list, ax_ligand_list
# # ax_con_int_list ,eq_con_int_list
# # with types: eq/ax_ligand_list list of mol3D
# # eq/ax_con_int_list list of list/tuple of int e.g., [[1,2] [1,2]]
result_ax_con = None
result_eq_con = None
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
if Gval:
allowed_strings += ['group_number']
labels_strings += ['Gval']
if NumB:
allowed_strings += ["num_bonds"]
labels_strings += ["NumB"]
for ii, properties in enumerate(allowed_strings):
ax_ligand_ac_con, eq_ligand_ac_con = find_ligand_deltametric_derivatives_oct(mol, properties, loud, depth, name,
oct=True,
custom_ligand_dict=custom_ligand_dict)
for i in range(0, depth + 1):
colnames.append(['d' + labels_strings[ii] + '-' + str(i) + '/d' + labels_strings[ii] + str(j) for j in
range(0, mol.natoms)])
if result_ax_con is None:
result_ax_con = ax_ligand_ac_con
else:
result_ax_con = np.row_stack([result_ax_con, ax_ligand_ac_con])
if result_eq_con is None:
result_eq_con = eq_ligand_ac_con
else:
result_eq_con = np.row_stack([result_eq_con, eq_ligand_ac_con])
if flag_name:
results_dictionary = {'colnames': colnames, 'result_ax_con_del': result_ax_con,
'result_eq_con_del': result_eq_con}
else:
results_dictionary = {'colnames': colnames, 'result_ax_con': result_ax_con, 'result_eq_con': result_eq_con}
return results_dictionary
[docs]def generate_multiatom_autocorrelations(mol, depth=4, oct=True, flag_name=False, additional_elements=False):
# oct - bool, if complex is octahedral, will use better bond checks
result = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
for ii, properties in enumerate(allowed_strings):
metal_ac = multiatom_only_autocorrelation(mol, properties, depth, oct=oct, additional_elements=additional_elements)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(metal_ac)
if flag_name:
results_dictionary = {'colnames': colnames, 'results_mc_ac': result}
else:
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_multiatom_deltametrics(mol, depth=4, oct=True, flag_name=False, additional_elements=False):
# oct - bool, if complex is octahedral, will use better bond checks
result = list()
colnames = []
allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
labels_strings = ['chi', 'Z', 'I', 'T', 'S']
for ii, properties in enumerate(allowed_strings):
metal_ac = multiatom_only_deltametric(mol, properties, depth, oct=oct, additional_elements=additional_elements)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(metal_ac)
if flag_name:
results_dictionary = {'colnames': colnames, 'results_mc_del': result}
else:
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
[docs]def generate_full_complex_coulomb_autocorrelations(mol,
depth=3, oct=True,
flag_name=False, modifier=False,
use_dist=False, transition_metals_only=True):
result = list()
colnames = []
allowed_strings = ['ident', 'topology', 'group_number', "num_bonds"]
labels_strings = ['I', 'T', 'Gval', "NumB"]
for ii, properties in enumerate(allowed_strings):
metal_ac = full_autocorrelation(mol, properties, depth,
oct=oct, modifier=modifier,
use_dist=use_dist,
transition_metals_only=transition_metals_only)
this_colnames = []
for i in range(0, depth + 1):
this_colnames.append(labels_strings[ii] + '-' + str(i))
colnames.append(this_colnames)
result.append(metal_ac)
if flag_name:
results_dictionary = {'colnames': colnames, 'results_f_all': result}
else:
results_dictionary = {'colnames': colnames, 'results': result}
return results_dictionary
#### Possibly Needed - ox_ utilities ###
### End of ox utilities ###