def test_dihedral_scanner_range_masks(): """ Test dihedral scanner range limit implemented as masks """ # setup a scanner m = Molecule() m.elem = ['H'] * 5 m.xyzs = [ np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 1], [1, 0, 0]], dtype=float) * 0.5 ] m.build_topology() engine = EngineBlank() dihedrals = [[0, 1, 2, 3], [1, 2, 3, 4]] # two ranges are tested, one is normal, one is "split" crossing boundaries dihedral_ranges = [[-120, 120], [150, 240]] scanner = DihedralScanner(engine, dihedrals=dihedrals, grid_spacing=[30, 30], init_coords_M=m, dihedral_ranges=dihedral_ranges) # check dihedral masks assert scanner.dihedral_ranges == dihedral_ranges assert scanner.dihedral_mask[0] == { -120, -90, -60, -30, 0, 30, 60, 90, 120 } assert scanner.dihedral_mask[1] == {-150, -120, 150, 180} # test validate_task() function task1 = (m, (-120, 120), (-120, 150)) assert scanner.validate_task(task1) == True task2 = (m, (-120, 60), (-120, 90)) assert scanner.validate_task(task2) == False
def test_dihedral_scanner_energy_upper_limit_filter(): """ Test dihedral scanner energy_upper_limit as task filters """ # setup a scanner m = Molecule() m.elem = ['H'] * 5 m.xyzs = [ np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 1], [1, 0, 0]], dtype=float) * 0.5 ] m.build_topology() engine = EngineBlank() dihedrals = [[0, 1, 2, 3], [1, 2, 3, 4]] # two ranges are tested, one is normal, one is "split" crossing boundaries dihedral_ranges = [[-120, 120], [150, 240]] scanner = DihedralScanner(engine, dihedrals=dihedrals, grid_spacing=[30, 30], init_coords_M=m, dihedral_ranges=dihedral_ranges, energy_upper_limit=0.001) # check dihedral masks assert scanner.energy_upper_limit == 0.001 # test validate_task() function scanner.global_minimum_energy = 0.0 m.qm_energies = [0.0] task1 = (m, (-120, 120), (-120, 150)) assert scanner.validate_task(task1) == True m.qm_energies = [0.0015] task2 = (m, (-120, 120), (-120, 150)) assert scanner.validate_task(task2) == False
def test_stack_psi4(): """ Test the stack of torsiondrive -> geomeTRIC -> qcengine -> Psi4 """ orig_path = os.getcwd() this_file_folder = os.path.dirname(os.path.realpath(__file__)) test_folder = os.path.join(this_file_folder, 'files', 'hooh-psi4') os.chdir(test_folder) # Make sure to delete subfolders opt_tmp_folder = os.path.join(test_folder, "opt_tmp") shutil.rmtree(opt_tmp_folder, ignore_errors=True) engine = Psi4QCEngineEngine('start.xyz') scanner = DihedralScanner(engine, dihedrals=[[0, 1, 2, 3]], grid_spacing=[90], verbose=True) scanner.master() result_energies = [ scanner.grid_energies[grid_id] for grid_id in sorted(scanner.grid_energies.keys()) ] assert np.allclose( result_energies, [-151.17367357, -151.16167615, -151.17367357, -151.17370632], atol=1e-4) os.chdir(orig_path)
def main(): import argparse, sys parser = argparse.ArgumentParser(description="Potential energy scan of dihedral angle from 1 to 360 degree", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('inputfile', type=str, help='Input template file for QMEngine. Geometry will be used as starting point for scanning.') parser.add_argument('dihedralfile', type=str, help='File defining all dihedral angles to be scanned.') parser.add_argument('--init_coords', type=str, help='File contain a list of geometries, that will be used as multiple starting points, overwriting the geometry in input file.') parser.add_argument('-g', '--grid_spacing', type=int, nargs='*', default=[15], help='Grid spacing for dihedral scan, i.e. every 15 degrees, multiple values will be mapped to each dihedral angle') parser.add_argument('-e', '--engine', type=str, default="psi4", choices=['qchem', 'psi4', 'terachem', 'openmm', "gaussian"], help='Engine for running scan') parser.add_argument('-c', '--constraints', type=str, default=None, help='Provide a constraints file in geomeTRIC format for additional freeze or set constraints (geomeTRIC or TeraChem only)') parser.add_argument('--native_opt', action='store_true', default=False, help='Use QM program native constrained optimization algorithm. This will turn off geomeTRIC package.') parser.add_argument('--energy_thresh', type=float, default=1e-5, help='Only activate grid points if the new optimization is <thre> lower than the previous lowest energy (in a.u.).') parser.add_argument('--energy_upper_limit', type=float, default=None, help='Only activate grid points if the new optimization is less than <thre> higher than the global lowest energy (in a.u.).') parser.add_argument('--wq_port', type=int, default=None, help='Specify port number to use Work Queue to distribute optimization jobs.') parser.add_argument('--zero_based_numbering', action='store_true', help='Use zero_based_numbering in dihedrals file.') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Print more information while running.') args = parser.parse_args() # print input command for reproducibility print(' '.join(sys.argv)) # parse the dihedral file if args.zero_based_numbering is True: print("The use of command line --zero_based_numbering is deprecated and will be removed in the future. Please use #zero_based_numbering in dihedralfile") dihedral_idxs, dihedral_ranges = load_dihedralfile(args.dihedralfile, args.zero_based_numbering) grid_dim = len(dihedral_idxs) # parse additional constraints constraints_dict = None if args.constraints is not None: with open(args.constraints) as fin: constraints_dict = make_constraints_dict(fin.read()) # check if there are extra constraints conflict with the specified dihedral angles check_conflict_constraints(constraints_dict, dihedral_idxs) # format grid spacing n_grid_spacing = len(args.grid_spacing) if n_grid_spacing == grid_dim: grid_spacing = args.grid_spacing elif n_grid_spacing == 1: grid_spacing = args.grid_spacing * grid_dim else: raise ValueError("Number of grid_spacing values %d is not consistent with number of dihedral angles %d" % (grid_dim, n_grid_spacing)) # create QM Engine, and WorkQueue object if provided port engine = create_engine(args.engine, inputfile=args.inputfile, work_queue_port=args.wq_port, native_opt=args.native_opt) # load init_coords if provided init_coords_M = Molecule(args.init_coords) if args.init_coords else None # create DihedralScanner object scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, dihedral_ranges=dihedral_ranges, grid_spacing=grid_spacing, init_coords_M=init_coords_M, energy_decrease_thresh=args.energy_thresh, energy_upper_limit=args.energy_upper_limit, extra_constraints=constraints_dict, verbose=args.verbose) # Run the scan! scanner.master() # After finish, print result print("Dihedral scan is finished!") print(" Grid ID Energy") for grid_id in sorted(scanner.grid_energies.keys()): print(" %-20s %.10f" % (str(grid_id), scanner.grid_energies[grid_id]))
def test_dihedral_scanner_methods(): """ Testing methods of DihedralScanner """ # setup a scanner m = Molecule() m.elem = ['H'] * 5 m.xyzs = [ np.array([[0, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 1], [1, 0, 0]], dtype=float) * 0.5 ] m.build_topology() engine = EngineBlank() dihedrals = [[0, 1, 2, 3], [1, 2, 3, 4]] scanner = DihedralScanner(engine, dihedrals=dihedrals, grid_spacing=[30, 30], init_coords_M=m) # test methods gid = (120, -60) assert scanner.get_dihedral_id(m) == gid assert scanner.get_dihedral_id(m, check_grid_id=(120, -90)) == None assert set(scanner.grid_neighbors(gid)) == {(90, -60), (150, -60), (120, -90), (120, -30)} assert set(scanner.grid_full_neighbors(gid)) == {(90, -90), (90, -30), (150, -90), (150, -30)} scanner.push_initial_opt_tasks() assert len(scanner.opt_queue) == 1 geo, start_gid, end_gid = scanner.opt_queue.pop() assert start_gid == end_gid
def test_dihedral_scanner_setup(): """ Testing DihedralScanner Setup for 1-D to 4-D Scans """ engine = EngineBlank() for dim in range(1, 5): print("Testing %d-D scan setup" % dim) dihedrals = [list(range(d, d+4)) for d in range(dim)] scanner = DihedralScanner(engine, dihedrals=dihedrals, grid_spacing=[90]*dim) gid = scanner.grid_ids[0] assert len(scanner.grid_ids) == 4**dim and len(gid) == dim, "Wrong dimension of grid_ids" assert len(scanner.grid_neighbors(gid)) == 2*dim, "Wrong dimension of grid_neighbors" assert isinstance(scanner.opt_queue, PriorityQueue), "DihedralScanner.opt_queue should be an instance of PriorityQueue" assert len(scanner.opt_queue) == 0, "DihedralScanner.opt_queue should be empty after setup"
def test_reproduce_1D_examples(example_path): """ Testing Reproducing examples/hooh-1d """ from torsiondrive import launch # reproduce psi4 local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/psi4/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('psi4', inputfile='input.dat') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce psi4 local native_opt os.chdir(example_path) os.chdir('hooh-1d/psi4/run_local/native_opt') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('psi4', inputfile='input.dat', native_opt=True) scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce qchem local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/qchem/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('qchem', inputfile='qc.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce Gaussian local native_opt os.chdir(example_path) os.chdir('hooh-1d/gaussian/run_local/native_opt') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = EngineGaussian(input_file="input.com", native_opt=True, exe="g09") scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce Gaussian local geometric os.chdir(example_path) os.chdir('hooh-1d/gaussian/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = EngineGaussian(input_file="input.com", native_opt=False, exe="g09") scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce qchem local native_opt (skipped because qchem failed in this example) # os.chdir(example_path) # os.chdir('hooh-1d/qchem/run_local/native_opt') # subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) # shutil.copy('scan.xyz', 'orig_scan.xyz') # dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') # engine = launch.create_engine('qchem', inputfile='input.dat', native_opt=True) # scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) # scanner.master() # assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce terachem local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/terachem/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('terachem', inputfile='run.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce terachem local native_opt os.chdir(example_path) os.chdir('hooh-1d/terachem/run_local/native_opt') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('terachem', inputfile='run.in', native_opt=True) scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce openmm local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/openmm/run_local/geometric') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('openmm', inputfile='hooh.pdb') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz')
def test_reproduce_1D_examples(): """ Testing Reproducing examples/hooh-1d """ from torsiondrive import launch this_file_folder = os.path.dirname(os.path.realpath(__file__)) example_path = os.path.join(this_file_folder, '..', '..', 'examples') os.chdir(example_path) subprocess.call('tar zxf hooh-1d.tar.gz ', shell=True) # reproduce psi4 local geomeTRIC os.chdir('hooh-1d/psi4/run_local/geomeTRIC') shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs = launch.load_dihedralfile('dihedrals.txt', zero_based_numbering=True) engine = launch.create_engine('psi4', inputfile='input.dat') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') os.chdir(example_path) # reproduce psi4 local native_opt os.chdir('hooh-1d/psi4/run_local/native_opt') shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs = launch.load_dihedralfile('dihedrals.txt', zero_based_numbering=True) engine = launch.create_engine('psi4', inputfile='input.dat', native_opt=True) scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') os.chdir(example_path) # reproduce qchem local geomeTRIC os.chdir('hooh-1d/qchem/run_local/geomeTRIC') shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs = launch.load_dihedralfile('dihedrals.txt', zero_based_numbering=True) engine = launch.create_engine('qchem', inputfile='qc.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') os.chdir(example_path) # reproduce terachem local geomeTRIC os.chdir('hooh-1d/terachem/run_local/geomeTRIC') shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs = launch.load_dihedralfile('dihedrals.txt', zero_based_numbering=True) engine = launch.create_engine('terachem', inputfile='run.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz')
def test_reproduce_1D_examples(example_path): """ Testing Reproducing examples/hooh-1d """ from torsiondrive import launch # reproduce psi4 local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/psi4/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('psi4', inputfile='input.dat') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce psi4 local native_opt os.chdir(example_path) os.chdir('hooh-1d/psi4/run_local/native_opt') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('psi4', inputfile='input.dat', native_opt=True) scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce qchem local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/qchem/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('qchem', inputfile='qc.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz') # reproduce terachem local geomeTRIC os.chdir(example_path) os.chdir('hooh-1d/terachem/run_local/geomeTRIC') subprocess.run('tar zxf opt_tmp.tar.gz', shell=True, check=True) shutil.copy('scan.xyz', 'orig_scan.xyz') dihedral_idxs, dihedral_ranges = launch.load_dihedralfile('dihedrals.txt') engine = launch.create_engine('terachem', inputfile='run.in') scanner = DihedralScanner(engine, dihedrals=dihedral_idxs, grid_spacing=[15], verbose=True) scanner.master() assert filecmp.cmp('scan.xyz', 'orig_scan.xyz')