def centre_of_mass(symbols, coordinates): """ Calculates the centre of mass (COM) for a set of atomic positions, based on: COM_x = m1x1 + m2x2 + ... + mnxn / m1 + m2 + ... + mn COM_y = m1y1 + m2y2 + ... + mnyn / m1 + m2 + ... + mn COM_z = m1z1 + m2z2 + ... + mnzn / m1 + m2 + ... + mn Parameters ---------- symbols: List of strings List of elemental symbols coordinates: Nx3 array of floats Array of x,y,z coordinates Returns ---------- COM: np.array Array of x,y,z component of COM """ if len(symbols) != len(coordinates): exit("Inputs not of the same dimension!") masses = np.array([elements.element(i).mass for i in symbols]) mass_sum = np.sum(masses) x_coords = coordinates[:, 0] y_coords = coordinates[:, 1] z_coords = coordinates[:, 2] x_numerator = np.sum(np.dot(masses, x_coords)) y_numerator = np.sum(np.dot(masses, y_coords)) z_numerator = np.sum(np.dot(masses, z_coords)) COM_x = x_numerator / mass_sum COM_y = y_numerator / mass_sum COM_z = z_numerator / mass_sum return np.array([COM_x, COM_y, COM_z])
def read_xyz(g09_file): """ Opens a g09 log file and returns the first geometry in Input orientation. Iterators are used so that the file is not all loaded into memory, which can be expensive. The function searches for the following text pattern in the log file: > Input orientation: > --------------------------------------------------------------------- > Center Atomic Atomic Coordinates (Angstroms) > Number Number Type X Y Z > --------------------------------------------------------------------- And will save the coordinates and the atomic symbols succeeding it Parameters ---------- g09_file: Path to g09 log file File path Returns ------- coordinates: List of lists Outer list is whole xyz file, each inner list is a line of the file containing the symbol and x,y,z coordinates """ with open(g09_file) as f: # Get the number of atoms so we can iterate without loading the file into memory for line in f: # Ensures line is not blank if line.strip(): if line.split()[0] == "NAtoms=": natoms = (int(line.split()[3])) break # Will hold the coordinates and symbols coordinates = [] # Reset the iterator to the top of the file f.seek(0) for line in f: if line.strip(): if "Input orientation:" in line: for i in range(5): # Skip 5 lines to start of coordinates line = next(f) for i in range(natoms): linesplit = line.split() symb = str(elements.element(int(linesplit[1])).symbol) x = float(linesplit[3]) y = float(linesplit[4]) z = float(linesplit[5]) coordinates.append([symb, x, y, z]) line = next(f) break return coordinates
def read_NTO(g09_file, natoms): """ Reads a G09 logfile and returns the atomic centred Natural Transition Charges, obtained via the G09 input line: td=(nstates=1) nosymm Pop=NTO Density=(Transition=1) Parameters ---------- g09_file: Path to g09 log file File path natoms: Integer Number of atoms Returns ------- NTO: np.array N array of NTO charges in order of atomic positions """ NTO = np.zeros(natoms) with open(g09_file) as f: # Get the number of atoms so we can iterate without loading the file into memory for line in f: # Ensures line is not blank if line.strip(): if " Mulliken charges:" in line: next(f) line = next(f) for i in range(natoms): charge_line = line.split() symbol = charge_line[1] charge = float(charge_line[2]) # NTO charge is atomic number - charge NTO[i] = elements.element(symbol).atomic - float( charge) line = next(f) f.close() return NTO