def analyse_bonds(model, A, B): ''' Check A-B distances present in the model. model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" A: string, chemical symbol, e.g. "H" B: string, chemical symbol, e.g. "H" ''' # Read file or Atoms object if isinstance(model, str) is True: model = read(model) analysis = Analysis(model) dash = "-" * 40 print_AB = A + "-" + B # Retrieve bonds and values AB_Bonds = analysis.get_bonds(A, B) AB_BondsValues = analysis.get_values(AB_Bonds) # Table header print(dash) print(print_AB+" Distance / Angstrom") print(dash) print('{:<6.5s}{:>4.10s}{:^13.10s}{:>4.10s}'.format( "count", "average", "minimum", "maximum")) # Table contents print('{:<6.0f}{:>4.6f}{:^12.6f}{:>4.6f}'.format( len(AB_BondsValues[0]), np.average(AB_BondsValues), np.amin(AB_BondsValues), np.amax(AB_BondsValues)))
def analyse_angles(model, A, B, C): ''' Check A-B distances present in the model. model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" A: string, chemical symbol, e.g. "O" B: string, chemical symbol, e.g. "C" C: string, chemical symbol, e.g. "O" ''' # Read file or Atoms object if isinstance(model, str) is True: model = read(model) analysis = Analysis(model) dash = "-"*40 print_ABC = A + "-" + B + "-" + C # Retrieve bonds and values ABC_Angle = analysis.get_angles(A, B, C) ABC_AngleValues = analysis.get_values(ABC_Angle) # Table header print(dash) print(print_ABC+" Angle / Degrees") print(dash) print('{:<6.5s}{:>4.10s}{:^13.10s}{:>4.10s}'.format( "count", "average", "minimum", "maximum")) # Table contents print('{:<6.0f}{:>4.4f}{:^12.4f}{:>4.4f}'.format( len(ABC_Angle[0]), np.average(ABC_AngleValues), np.amin(ABC_AngleValues), np.amax(ABC_AngleValues)))
def search_abnormal_bonds(model): ''' Check all bond lengths in the model for abnormally short ones, ie. less than 0.74 Angstrom. model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" ''' # Combination as AB = BA for bonds, avoiding redundancy from itertools import combinations_with_replacement # Read file or Atoms object if isinstance(model, str) is True: model = read(model) # Define lists of variables abnormal_bonds = [] list_of_abnormal_bonds = [] analysis = Analysis(model) # set() to ensure unique chemical symbols list list_of_symbols = list(set(model.get_chemical_symbols())) all_bonds = combinations_with_replacement(list_of_symbols, 2) # Iterate over all arrangements of chemical symbols for bonds in all_bonds: A = bonds[0] B = bonds[1] print_AB = A+'-'+B AB_Bonds = analysis.get_bonds(A, B) # Make sure bond exist before retrieving values if not AB_Bonds == [[]]: AB_BondsValues = analysis.get_values(AB_Bonds) for i in range(0, len(AB_BondsValues)): for values in AB_BondsValues[i]: if values < 0.74: abnormal_bonds += [1] list_of_abnormal_bonds = list_of_abnormal_bonds + [print_AB] # Abnormality check if not len(abnormal_bonds) == 0: print("A total of", len(abnormal_bonds), "abnormal bond lengths observed (<0.74 A).") print("Identities:", list_of_abnormal_bonds) else: print("OK")
def analyse_all_angles(model): ''' Returns a table of bond angle analysis for the supplied model. Parameters: model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" ''' # Product to get all possible arrangements from itertools import product # Read file or Atoms object if isinstance(model, str) is True: model = read(model) analysis = Analysis(model) dash = "-" * 40 # set() to ensure unique chemical symbols list list_of_symbols = list(set(model.get_chemical_symbols())) all_angles = product(list_of_symbols, repeat=3) # Table heading print(dash) print('{:<9.8s}{:<6.5s}{:>4.10s}{:^13.10s}{:>4.10s}'.format( "Angle", "Count", "Average", "Minimum", "Maximum")) print(dash) # Iterate over all arrangements of chemical symbols for angles in all_angles: A = angles[0] B = angles[1] C = angles[2] print_ABC = A + '-' + B + '-' + C ABC_Angle = analysis.get_angles(A, B, C) # Make sure angles exist before retrieving values, print table contents if not ABC_Angle == [[]]: ABC_AngleValues = analysis.get_values(ABC_Angle) print('{:<9.8s}{:<6.0f}{:>4.4f}{:^12.4f}{:>4.4f}'.format( print_ABC, len(ABC_Angle[0]), np.average(ABC_AngleValues), np.amin(ABC_AngleValues), np.amax(ABC_AngleValues)))
def analyse_all_bonds(model): ''' Returns a table of bond distance analysis for the supplied model. Parameters: model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" ''' # Combination as AB = BA for bonds, avoiding redundancy from itertools import combinations_with_replacement # Read file or Atoms object if isinstance(model, str) is True: model = read(model) analysis = Analysis(model) dash = "-" * 40 # set() to ensure unique chemical symbols list list_of_symbols = list(set(model.get_chemical_symbols())) all_bonds = combinations_with_replacement(list_of_symbols, 2) # Table heading print(dash) print('{:<6.5s}{:<6.5s}{:>4.10s}{:^13.10s}{:>4.10s}'.format( "Bond", "Count", "Average", "Minimum", "Maximum")) print(dash) # Iterate over all arrangements of chemical symbols for bonds in all_bonds: A = bonds[0] B = bonds[1] print_AB = A + '-' + B AB_Bonds = analysis.get_bonds(A, B) # Make sure bond exist before retrieving values, then print contents if not AB_Bonds == [[]]: AB_BondsValues = analysis.get_values(AB_Bonds) print('{:<8.8s}{:<6.0f}{:>4.6f}{:^12.6f}{:>4.6f}'.format( print_AB, len(AB_BondsValues[0]), np.average(AB_BondsValues), np.amin(AB_BondsValues), np.amax(AB_BondsValues)))
def analyse_angles(model, A, B, C, verbose=True, multirow=False): ''' Check A-B-C angles present in the model. Parameters: model: Atoms object XXX A: string, chemical symbol, e.g. "O" B: string, chemical symbol, e.g. "C" C: string, chemical symbol, e.g. "O" verbose: Boolean Whether to print information to screen multirow: Boolean Whether we are returning multiple sets of results in a Table ''' from ase.geometry.analysis import Analysis analysis = Analysis(model) print_ABC = A + "-" + B + "-" + C # Retrieve bonds and values ABC_indices = analysis.get_angles(A, B, C) if len(ABC_indices[0]) == 0: ABC_values = None else: ABC_values = analysis.get_values(ABC_indices) if verbose and ABC_values is not None: # Table header if not multirow: print_angles_table_header() # Table contents import numpy as np print('{:<9.8s}{:<6.0f}{:>4.4f}{:^12.4f}{:>4.4f}'.format( print_ABC, len(ABC_indices[0]), np.average(ABC_values), np.amin(ABC_values), np.amax(ABC_values))) return ABC_indices, ABC_values
def analyse_bonds(model, A, B, verbose=True, multirow=False): ''' Check A-B distances present in the model. Parameters: model: Atoms object XXX A: string, chemical symbol, e.g. "H" B: string, chemical symbol, e.g. "H" verbose: Boolean Whether to print information to screen multirow: Boolean Whether we are working with analyse_all_bonds, so the output is multirow, or just one specific analysis of a bond, in which case the table header is needed. ''' from ase.geometry.analysis import Analysis analysis = Analysis(model) print_AB = A + "-" + B # Retrieve bonds and values AB_Bonds = analysis.get_bonds(A, B) if AB_Bonds == [[]]: AB_BondsValues = None else: AB_BondsValues = analysis.get_values(AB_Bonds) if verbose and AB_BondsValues is not None: if not multirow: print_bond_table_header() # Table contents import numpy as np print('{:<8.8s}{:<6.0f}{:>4.6f}{:^12.6f}{:>4.6f}'.format( print_AB, len(AB_BondsValues[0]), np.average(AB_BondsValues), np.amin(AB_BondsValues), np.amax(AB_BondsValues))) return print_AB, AB_Bonds, AB_BondsValues
PEA2PbSnI4 = read('CONTCAR_PbSn' + str(i)) #print(PEA2PbSnI4) ana = Analysis(PEA2PbSnI4) # Bonds PbIBonds = ana.get_bonds('Pb', 'I', unique=True) SnIBonds = ana.get_bonds('Sn', 'I', unique=True) #print("\nThere are {} Pb-I bonds in PEA2PbSnI4.".format(len(PbIBonds[0]))) #print("There are {} Pb-I bonds in PEA2PbSnI4.".format(len(SnIBonds[0]))) if len(PbIBonds[0]) > 0: PbIBondValues = ana.get_values(PbIBonds) if len(SnIBonds[0]) > 0: SnIBondValues = ana.get_values(SnIBonds) #print("The average Pb-I bond length is {}.".format(np.average(PbIBondValues))) #print("The average Sn-I bond length is {}.".format(np.average(SnIBondValues))) if len(PbIBonds[0]) > 0: AllPbIBonds.append(np.average(PbIBondValues)) if len(SnIBonds[0]) > 0: AllSnIBonds.append(np.average(SnIBondValues)) #
def search_abnormal_bonds(model, verbose=True): ''' Check all bond lengths in the model for abnormally short ones, ie. less than 0.74 Angstrom. Parameters: model: Atoms object or string. If string it will read a file in the same folder, e.g. "name.traj" ''' # Combination as AB = BA for bonds, avoiding redundancy from itertools import combinations_with_replacement # Imports necessary to work out accurate minimum bond distances from ase.data import chemical_symbols, covalent_radii # Read file or Atoms object if isinstance(model, str) is True: model = read(model) # Define lists of variables abnormal_bonds = [] list_of_abnormal_bonds = [] analysis = Analysis(model) # set() to ensure unique chemical symbols list list_of_symbols = list(set(model.get_chemical_symbols())) all_bonds = combinations_with_replacement(list_of_symbols, 2) # Iterate over all arrangements of chemical symbols for bonds in all_bonds: A = bonds[0] B = bonds[1] # For softcoded bond cutoff sum_of_covalent_radii = covalent_radii[chemical_symbols.index( A)] + covalent_radii[chemical_symbols.index(B)] print_AB = A + '-' + B AB_Bonds = analysis.get_bonds(A, B) # Make sure bond exist before retrieving values if not AB_Bonds == [[]]: AB_BondsValues = analysis.get_values(AB_Bonds) for i in range(0, len(AB_BondsValues)): for values in AB_BondsValues[i]: # TODO: move the 75% of sum_of_covalent_radii before the loops if values < max(0.4, sum_of_covalent_radii * 0.75): abnormal_bonds += [1] list_of_abnormal_bonds = list_of_abnormal_bonds + [ print_AB ] # Abnormality check # is it possible to make a loop with different possible values instead of 0.75 and takes the average if len(abnormal_bonds) > 0: if verbose: print( "A total of", len(abnormal_bonds), "abnormal bond lengths observed (<" + str(max(0.4, sum_of_covalent_radii * 0.75)) + " A).") print("Identities:", list_of_abnormal_bonds) return False else: if verbose: print("OK") return True
import numpy as np from ase.io import read from ase.geometry.analysis import Analysis #old file see bonds.py for better version file = read('tin_acetate.xyz') traj = Trajectory('tin_acetate.traj', 'w') traj.write(file) file = read('tin_acetate.traj') ana = Analysis(file) SiOBonds = ana.get_bonds('Sn', 'O') SiOSiAngles = ana.get_angles('O', 'Sn', 'O') print("there are {} Si-O bonds in BETA".format(len(SiOBonds[0]))) print("there are {} Si-O-Si angles in BETA".format(len(SiOSiAngles[0]))) SiOBondsValues = ana.get_values(SiOBonds) SiOSiAngleValues = ana.get_values(SiOSiAngles) print("bond length data:") print("the average Si-O bond length is {}.".format(np.average(SiOBondsValues))) print("the minimum Si-O Distance is:", np.amin(SiOBondsValues)) print("the maximum Si-O Distance is:", np.amax(SiOBondsValues)) print("bond angle data:") print("the average Si-O-Si angle is {}.".format(np.average(SiOSiAngleValues))) print("the maximum Si-O-Si angle is:", np.amax(SiOSiAngleValues)) print("the minimum Si-O-Si angle is:", np.amin(SiOSiAngleValues))