def connect_wheel(opts): """ Connect wheel molecule to selected atom position. The wheel molecule must have a connection site (Xc) and alignmen site (Xa) to specify connectivity. The selected wheel molecule is added to selected atom by aligning the vector of the wheel. """ selected = [idx for idx, atm in enumerate(opts['cjson']['atoms']['selected']) if atm] if len(selected) == 1: # Get chassi coordinates and bonds coords = np.array(opts['cjson']['atoms']['coords']['3d']) connections = opts['cjson']['bonds']['connections']['index'] atoms = [periodictable.elements[i].symbol for i in opts['cjson']['atoms']['elements']['number']] chassi = Molecule(atoms=atoms, coordinates=np.array(coords).reshape((int(len(coords) / 3)), 3)) # Get connection site for the chassis selected_cidx = int(selected[0] * 3) selected_coors = coords[selected_cidx:selected_cidx + 3] # Find atom connected to the selected atom bond_idx = connections.index(selected[0]) if bond_idx % 2 == 0: bond_idx += 1 else: bond_idx -= 1 bond_idx = int(connections[bond_idx] * 3) # Get vector btw selected atom and atom connected to it v_chassi = selected_coors - np.array(coords[bond_idx:bond_idx + 3]) # Read wheel molecule information wheel = read_wheel(opts['wheel']) # Align the wheel with chassis connection vector v_wheel = wheel.coordinates[wheel.alignment_site] - wheel.coordinates[wheel.connection_site] wheel.align(v_wheel, v_chassi) # Translate the wheel to match dummy coor with selected coor v_trans = selected_coors - wheel.coordinates[wheel.connection_site] wheel.translate(v_trans) # Adjust bond distance v_bond = wheel.coordinates[wheel.connection_site] - wheel.coordinates[wheel.alignment_site] d_bond = np.linalg.norm(v_bond) v_bond = v_bond - v_bond / d_bond * opts['d'] wheel.translate(v_bond) # Remove dummy atoms for alignment and connection sites wheel.coordinates = np.delete(wheel.coordinates, [wheel.connection_site, wheel.alignment_site], axis=0) wheel.atoms = np.delete(wheel.atoms, [wheel.connection_site, wheel.alignment_site]) if not opts['append']: wheel += chassi wheel = mol2xyz(wheel) else: print('Only 1 atom should be selected!') wheel = None return wheel
def test_read_xyz_benzene_molecule(): """Tests reading xyz formatted molecule file""" benzene = Molecule(read=benzene_xyz) assert len(benzene) == 12 assert len(benzene.atoms) == 12 assert len(benzene.coordinates) == 12 assert benzene.header == 'benzene' for atom, ref_atom in zip(benzene.atoms, benzene_atoms): assert atom == ref_atom assert np.allclose(benzene.coordinates, benzene_coors)
def test_trajectory_append_molecule(): """Tests appending molecule to trajectory""" benzene_traj = Trajectory(read=benzene_traj_x) n_frames = len(benzene_traj) benzene_mol = Molecule(read=benzene_xyz) benzene_traj.append(benzene_mol) assert len(benzene_traj) == n_frames + 1 assert benzene_traj.atoms.shape[0] == n_frames + 1 assert benzene_traj.atoms.shape[1] == len(benzene_mol) assert benzene_traj.coordinates.shape[0] == n_frames + 1 assert benzene_traj.coordinates.shape[1] == len(benzene_mol)
def test_benzene_addition(): """Tests molecular addition of two benzenes""" benzene = Molecule(read=benzene_xyz) benzene2 = benzene + benzene assert len(benzene2.atoms) == 2 * len(benzene.atoms) assert len(benzene2.coordinates) == 2 * len(benzene.coordinates) assert np.allclose(benzene2.coordinates[:12, :], benzene.coordinates) assert np.allclose(benzene2.coordinates[12:, :], benzene.coordinates) for atom, ref_atom in zip(benzene2.atoms[12:], benzene.atoms): assert atom == ref_atom for atom, ref_atom in zip(benzene2.atoms[:12], benzene.atoms): assert atom == ref_atom assert benzene2.name == 'benzene+benzene'
def test_piyzaz_replication_2_2_2_with_centering(): """Tests replicating PIYZAZ (CCDC) 2x2x2 with centering. Reference structure is generated using Mercury software.""" piyzaz = Molecule(read=piyzaz111_xyz) piyzaz.set_cell(piyzaz_cell_parameters) piyzaz222 = piyzaz.replicate([2, 2, 2], center=True) # Move the reference structure so that it's centered to original cell position piyzaz222_ref = Molecule(read=piyzaz222_xyz) transvec = np.sum(piyzaz.cell.vectors, axis=0) * -1 / 2 piyzaz222_ref.translate(transvec) assert np.allclose(piyzaz222.coordinates, piyzaz222_ref.coordinates) assert set(piyzaz222.atoms) == set(piyzaz222_ref.atoms) assert piyzaz222.cell.a == piyzaz.cell.a * 2 assert piyzaz222.cell.b == piyzaz.cell.b * 2 assert piyzaz222.cell.c == piyzaz.cell.c * 2 assert piyzaz222.cell.alpha == piyzaz.cell.alpha assert piyzaz222.cell.beta == piyzaz.cell.beta assert piyzaz222.cell.gamma == piyzaz.cell.gamma
def test_trajectory_from_molecule(): """Tests converting Molecule to Trajectory object""" benzene = Molecule(read=benzene_xyz) benzene_traj = Trajectory(molecule=benzene) assert len(benzene_traj) == 1 assert benzene_traj.name == 'benzene' assert np.shape(benzene_traj.coordinates) == (1, 12, 3) assert np.shape(benzene_traj.atoms) == (1, 12) # Test atom names are read correctly for frame in benzene_traj: assert len(frame.coordinates) == 12 for atom, ref_atom in zip(frame.atoms, benzene.atoms): assert atom == ref_atom
def __getitem__(self, i): """ Indexing method. Returns a Molecule object for given index (frame). Returns a Trajectory object if used as slicing. """ if isinstance(i, slice): indices = range(len(self))[i.start:i.stop:i.step] if len(indices) == 0: return [] else: new_traj = Trajectory(molecule=self[indices[0]]) for j in indices[1:]: new_traj.append(self[j]) return new_traj else: return Molecule(atoms=self.atoms[i], coordinates=self.coordinates[i])
def test_piyzaz_replication_4_4_4_without_centering(): """Tests replicating PIYZAZ (CCDC) 4x4x4 without centering. Reference structure is generated using Mercury software.""" piyzaz = Molecule(read=piyzaz111_xyz) piyzaz.set_cell(piyzaz_cell_parameters) piyzaz444 = piyzaz.replicate([4, 4, 4], center=False) piyzaz444_ref = Molecule(read=piyzaz444_xyz) assert np.allclose(piyzaz444.coordinates, piyzaz444_ref.coordinates) assert set(piyzaz444.atoms) == set(piyzaz444_ref.atoms) assert piyzaz444.cell.a == piyzaz.cell.a * 4 assert piyzaz444.cell.b == piyzaz.cell.b * 4 assert piyzaz444.cell.c == piyzaz.cell.c * 4 assert piyzaz444.cell.alpha == piyzaz.cell.alpha assert piyzaz444.cell.beta == piyzaz.cell.beta assert piyzaz444.cell.gamma == piyzaz.cell.gamma
def test_piyzaz_replication_2_3_1_without_centering(): """Tests replicating PIYZAZ (CCDC) 2x3x1 without centering. Reference structure is generated using Mercury software.""" piyzaz = Molecule(read=piyzaz111_xyz) piyzaz.set_cell(piyzaz_cell_parameters) piyzaz231 = piyzaz.replicate([2, 3, 1], center=False) piyzaz231_ref = Molecule(read=piyzaz231_xyz) assert np.allclose(piyzaz231.coordinates, piyzaz231_ref.coordinates) assert set(piyzaz231.atoms) == set(piyzaz231_ref.atoms) assert piyzaz231.cell.a == piyzaz.cell.a * 2 assert piyzaz231.cell.b == piyzaz.cell.b * 3 assert piyzaz231.cell.c == piyzaz.cell.c * 1 assert piyzaz231.cell.alpha == piyzaz.cell.alpha assert piyzaz231.cell.beta == piyzaz.cell.beta assert piyzaz231.cell.gamma == piyzaz.cell.gamma
def setup_lammps(opts): """Write LAMMPS simulation files.""" # Read structure information coords = np.array(opts['cjson']['atoms']['coords']['3d']) atoms = [ periodictable.elements[i].symbol for i in opts['cjson']['atoms']['elements']['number'] ] nanocar = Molecule(atoms=atoms, coordinates=np.array(coords).reshape( (int(len(coords) / 3)), 3)) opts['box_x'], opts['box_y'], opts[ 'box_z'] = opts['box_x'] * 10, opts['box_y'] * 10, opts['box_z'] * 10 nanocar.set_cell([opts['box_x'], opts['box_y'], opts['box_z'], 90, 90, 90]) nanocar.center([opts['box_x'] / 2, opts['box_y'] / 2, opts['box_z'] / 2]) if not os.path.isdir(opts['dir']): # try removing the last part of the path (a file) parent = (Path(opts['dir']).parent.absolute()) if not os.path.isdir(parent): opts['dir'] = PLUGIN_DIR print('Directory not found! Using plug-in directory -> %s' % PLUGIN_DIR) else: opts['dir'] = parent data_file = os.path.join(opts['dir'], 'data.nanocar') write_data_file(data_file, nanocar) # Write input file surface_info = read_surface_info() surface_ids = surface_info['id'] surface_atoms = surface_ids[1] - surface_ids[0] num_atoms = len(nanocar.atoms) if surface_ids[0] == 1: mol_ids = [num_atoms - surface_atoms, num_atoms] else: mol_ids = [1, num_atoms - surface_atoms - 1] input_file = os.path.join(opts['dir'], 'in.nanocar') inp_parameters = { 'sim_length': opts['sim_length'], 'ts': opts['timestep'], 'mol_ids': mol_ids, 'surface_ids': surface_ids, 'T': 300 } write_input_file(input_file, nanocar, inp_parameters)
def test_caffeine_molecular_weight(): """ Testing impotant stuff here """ caffeine = Molecule(atoms=['C'] * 8 + ['H'] * 10 + ['N'] * 4 + ['O'] * 2, coordinates=[]) mw = caffeine.get_molecular_weight() assert np.isclose(mw, 194.194, atol=0.01)
def test_benzene_molecular_weight(): """ Tests molecular weight calculation for benzene molecule """ benzene = Molecule(read=benzene_xyz) mw = benzene.get_molecular_weight() assert np.isclose(mw, 78.11, atol=0.01)
def test_benzene_delete(): """Tests deleting atoms from benzene molecule""" benzene = Molecule(read=benzene_xyz) benzene.delete([0, 2, 4, 6, 8, 10]) assert len(benzene.atoms) == 6 assert all([a == 'H' for a in benzene.atoms])
def build_nanocar(opts): """Builds Nanocar molecule.""" chassis = Molecule(read=os.path.join(chassis_dir, '%s.xyz' % opts['chassis'])) chassis.center([opts['center-x'], opts['center-y'], opts['center-z']]) return mol2xyz(chassis)
def test_benzene_reflection_yz_plane_should_change_x_axis_position(): mol = Molecule(read=benzene_xyz) mol.center([5, 0, 0]) mol.reflect('yz') assert np.allclose(mol.get_center(), [-5, 0, 0])
def test_benzene_reflection_xy_plane_should_not_change_orientation(): mol = Molecule(read=benzene_xyz) mol.reflect('xy') assert np.allclose(mol.coordinates, benzene_coors)
def read_wheel(wheel_name): """Read yaml file to Molecule object""" wheel = Molecule(read=os.path.join(wheel_dir, '%s.xyz' % wheel_name)) wheel.connection_site, = np.where(wheel.atoms == 'Xc')[0] wheel.alignment_site, = np.where(wheel.atoms == 'Xa')[0] return wheel
def test_piyzaz_chemical_formula(): """ Testing chemical formula for PIYZAZ in 111 and 222 packing""" piyzaz111 = Molecule(read=piyzaz111_xyz) assert piyzaz111.get_chemical_formula() == {'C': 8, 'Cd': 2} piyzaz222 = Molecule(read=piyzaz222_xyz) assert piyzaz222.get_chemical_formula() == {'C': 64, 'Cd': 16}
def test_benzene_chemical_formula(): """ Tests chemical formula for benzene molecule """ benzene = Molecule(read=benzene_xyz) assert benzene.get_chemical_formula() == {'C': 6, 'H': 6}
def main(): parser = argparse.ArgumentParser( description=""" ================================================= __ __ ---- Ångström ---- __ __ __/ \__/ \__ ╔═╗ __/ \__/ \__ / \__/ \__/ \ ╚═╝ / \__/ \__/ \\ \__/ \__/ \__/ ███████╗ \__/ \__/ \__/ / \__/ \__/ \ ██╔════██╗ / \__/ \__/ \\ \__/ \__/ \__/ ██║ ██║ \__/ \__/ \__/ / \__/ \__/ \ ██║██████║ / \__/ \__/ \\ \__/ \__/ \__/ ██║ ██║ \__/ \__/ \__/ \__/ \__/ ██╝ ██╝ \__/ \__/ ================================================= Command-line molecular visualization............. ================================================= """, epilog=""" Example: > angstrom my_molecule.pdb would generate my_molecule.png file. """, formatter_class=argparse.RawDescriptionHelpFormatter) # Positional arguments parser.add_argument('molecule', type=str, help='Molecule file (pdb / xyz) to read') # Optional arguments parser.add_argument('--read-config', '-conf', default='', type=str, metavar='', help="Read config yaml file.") parser.add_argument('--exe', '-x', default='', type=str, metavar='', help="Blender executable path") parser.add_argument('--video', '-vid', action='store_true', default=False, help="Render video.") parser.add_argument( '--rotate', '-rot', default=[0], type=int, metavar='', nargs=5, help= "Rotate molecule -> degrees x y z (axis) frames. (ex: 360 0 0 1 50)") parser.add_argument('--no-center', action='store_true', default=False, help="Center molecule to origin.") parser.add_argument( '--model', '-m', default='default', type=str, metavar='', help= "Molecular representation model ([default] | ball_and_stick | space_filling | stick | surface)" ) parser.add_argument( '--zoom', '-z', default=20, type=int, metavar='', help= "Image zoom, molecule gets smaller as zoom gets bigger (default: 20)") parser.add_argument( '--view', default='xy', type=str, metavar='', help="Camera view plane ([xy] | xz | yx | yz | zx | zy)") parser.add_argument('--distance', '-d', default=10, type=int, metavar='', help="Camera distance from origin (default: 10)") parser.add_argument('--camera', '-c', default='ORTHO', type=str, metavar='', help="Camera type ([ORTHO] | PERSP)") parser.add_argument('--light', '-l', default=2000.0, type=float, metavar='', help="Light energy (default: 2000 W)") parser.add_argument( '--resolution', '-r', default='1920x1080', type=str, metavar='', help="Image resolution (WIDTHxHEIGHT) (default: 1920x1080)") parser.add_argument( '--bcolor', '-bc', default=None, type=float, metavar='', nargs='+', help= "Background color in RGBA (ex: 1.0 1.0 1.0 1.0 for white | default: transparent)" ) parser.add_argument('--no-render', '-nr', action='store_true', default=False, help="Don't render the image (default: False)") parser.add_argument( '--save', '-s', default='', type=str, metavar='', help="Save .blend file [ex: molecule.blend] (default: don't save)") parser.add_argument('--verbose', '-v', action='store_true', default=False, help="Verbosity (default: False)") args = parser.parse_args() # Set options -------------------------------------------------------------------------------------- # Search for Blender executable if not given if args.exe == '': args.exe = search_blender_executable() blend = Blender() if args.read_config != '': print('Reading config file -> %s' % args.read_config) blend.read_config(args.read_config) blend.config['pdb']['filepath'] = args.molecule blend.config['img_file'] = '%s.png' % os.path.splitext( args.molecule)[0] else: img_file = os.path.join( os.getcwd(), '%s.png' % os.path.splitext(os.path.basename(args.molecule))[0]) blend.configure( mol_file=args.molecule, img_file=img_file, executable=args.exe, model=args.model, save=args.save, render=(not args.no_render), verbose=args.verbose, camera_zoom=args.zoom, camera_type=args.camera.upper(), camera_view=args.view, camera_distance=args.distance, background_color=args.bcolor, light=args.light, resolution=[int(i) for i in args.resolution.split('x')]) blend.config['pdb']['use_center'] = (not args.no_center) blend.print_config() if args.video: blend.config['pdb']['use_center'] = False if len(args.rotate) == 5: mol = Molecule(read=args.molecule) rot_axis = ([0, 0, 0], args.rotate[1:4]) traj = rotation(mol, args.rotate[4], args.rotate[0], rot_axis, interpolation='linear') else: traj = Trajectory(read=args.molecule) render(traj, os.path.splitext(args.molecule)[0], renderer=blend, verbose=args.verbose) else: if os.path.splitext(args.molecule)[1] == '.pdb': blend.run() elif os.path.splitext(args.molecule)[1] == '.xyz': mol = Molecule(read=args.molecule) render(mol, os.path.splitext(args.molecule)[0], renderer=blend, verbose=args.verbose) else: print('File format not supported for -> %s' % args.molecule)
for i, (atom, coor) in enumerate(zip(elements, coordinates)): rm.write('%2i %2s_%3s % 5.4f % 5.4f % 5.4f\n' % (i, atom, code, coor[0], coor[1], coor[2])) rm.write( "# Chiral centers Bond BondDipoles Bend UrayBradley InvBend Torsion Imp." + " Torsion Bond/Bond Stretch/Bend Bend/Bend Bend/Torsion IntraVDW IntraCoulomb\n" + " 0 %3i 0 0 0 0 0" % len(bonds) + " 0 0 0 0 0 0 0\n" + "# Bond stretch: atom n1-n2, type, parameters\n" ) # Write bonds for b in bonds: rm.write("%2i %2i RIGID_BOND\n" % (b[0], b[1])) rm.write("# Number of config moves\n0\n") mol_file = os.path.abspath(sys.argv[1]) print('Reading -> %s' % mol_file) mol = Molecule(read=mol_file) mol.get_bonds() if len(sys.argv) > 2: mol_name = os.path.basename(sys.argv[2]).split('.')[0] raspa_molecule_file = os.path.abspath(sys.argv[2]) else: mol_name = os.path.basename(mol_file).split('.')[0] raspa_molecule_file = os.path.join(os.path.split(mol_file)[0], '%s.def' % mol_name) print('Writing -> %s' % raspa_molecule_file) write_raspa_molecule(mol, raspa_molecule_file)
def __getitem__(self, i): """ Indexing method. Returns a Molecule object for given index (frame). """ return Molecule(atoms=self.atoms[i], coordinates=self.coordinates[i])
""" --- Ångström --- Tests bond, angle, dihedral estimation for Molecule class. """ from angstrom import Molecule import os benzene_xyz = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'benzene.xyz') ethane = Molecule(atoms=['H', 'C', 'H', 'H', 'C', 'H', 'H', 'H'], coordinates=[[1.185080, -0.003838, 0.987524], [0.751621, -0.022441, -0.020839], [1.166929, 0.833015, -0.569312], [1.115519, -0.932892, -0.514525], [-0.751587, 0.022496, 0.020891], [-1.166882, -0.833372, 0.568699], [-1.115691, 0.932608, 0.515082], [-1.184988, 0.004424, -0.987522]]) def test_ethane_should_have_seven_bonds(): expected_bonds = [(0, 1), (1, 2), (1, 3), (1, 4), (4, 5), (4, 6), (4, 7)] ethane.get_bonds() assert ethane.bonds == expected_bonds def test_ethane_should_have_twelve_angles(): expected_angles = [(0, 1, 2), (0, 1, 3), (0, 1, 4), (1, 4, 5), (1, 4, 6), (1, 4, 7), (2, 1, 3), (2, 1, 4), (3, 1, 4), (5, 4, 6), (5, 4, 7), (6, 4, 7)] ethane.get_angles()
def test_centering_benzene_molecule_to_given_coordinates(): """Tests molecule center for benzene""" benzene = Molecule(read=benzene_xyz) benzene.center([5, 0, -5]) assert np.allclose(benzene.get_center(), [5, 0, -5]) benzene.center() assert np.allclose(benzene.get_center(), [0, 0, 0]) benzene.translate([0, 0, 7]) assert np.allclose(benzene.get_center(), [0, 0, 7]) benzene.rotate(([0, 0, 0], [0, 1, 0]), np.pi / 2) assert np.allclose(benzene.get_center(), [7, 0, 0]) benzene.rotate(([0, 0, 0], [0, 1, 0]), np.pi / 2, center=True) assert np.allclose(benzene.get_center(), [7, 0, 0])
def test_benzene_reflection_should_not_change_bonding(): mol = Molecule(read=benzene_xyz) mol.reflect('xy') mol.get_bonds() assert np.allclose(mol.bonds, benzene_bonds) mol.reflect('yz') mol.get_bonds() assert np.allclose(mol.bonds, benzene_bonds) mol.reflect('xz') mol.get_bonds() assert np.allclose(mol.bonds, benzene_bonds)