Exemple #1
0
def test_check_conflict_constraints():
    """
    Test the check_conflict_constraints() function

    Notes
    -----
    Atom indices in constraits_string is 1-indexed
    Atom indices in dihedral_idxs is 0-indexed
    """
    constraits_string = '''
    $freeze
    xyz 1-3,6-7
    distance 1 5
    $set
    distance 1 4 1.0
    angle 4 1 2 30.0
    dihedral 1 2 3 4 60.0
    '''
    constraints_dict = make_constraints_dict(constraits_string)
    # empty check
    check_conflict_constraints(constraints_dict, [])
    # test valid constraints_dict when not conflicting
    dihedral_idxs = [[1, 2, 3, 4], [2, 3, 4, 5]]
    check_conflict_constraints(constraints_dict, dihedral_idxs)
    # test conflicting
    with pytest.raises(ValueError):
        # dihedral conflict (same as scanning)
        check_conflict_constraints(constraints_dict, [[0, 1, 2, 3]])
    with pytest.raises(ValueError):
        # dihedral conflict (share the same center atoms 1, 2)
        check_conflict_constraints(constraints_dict, [[5, 2, 1, 6]])
    with pytest.raises(ValueError):
        # xyz conflict
        check_conflict_constraints(constraints_dict, [[0, 1, 2, 5]])
Exemple #2
0
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]))
Exemple #3
0
def test_make_constraints_dict():
    '''
    Unit test for torsiondrive.qm_engine.make_constraints_dict() function
    '''
    constraits_string = '''
    $freeze
    xyz 1-3,6-7
    distance 1 5
    $set
    distance 1 4 1.0
    angle 4 1 2 30.0
    dihedral 1 2 3 4 60.0
    '''
    constraints_dict = make_constraints_dict(constraits_string)
    # test the freeze constraints
    spec_list = constraints_dict['freeze']
    assert len(spec_list) == 2
    assert spec_list[0]['type'] == 'xyz'
    assert spec_list[0]['indices'] == [0, 1, 2, 5, 6]
    assert spec_list[1]['type'] == 'distance'
    assert spec_list[1]['indices'] == [0, 4]
    # test the set constraints
    spec_list = constraints_dict['set']
    assert len(spec_list) == 3
    assert spec_list[0]['type'] == 'distance'
    assert spec_list[0]['indices'] == [0, 3]
    assert spec_list[0]['value'] == 1.0
    assert spec_list[1]['type'] == 'angle'
    assert spec_list[1]['indices'] == [3, 0, 1]
    assert spec_list[1]['value'] == 30.0
    assert spec_list[2]['type'] == 'dihedral'
    assert spec_list[2]['indices'] == [0, 1, 2, 3]
    assert spec_list[2]['value'] == 60.0
    # test error handling for wrong inputs
    # scan not supported
    wrong_constraits_string = '''
    $scan
    distance 1 2 1.0 2.0 10
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # $unknown not supported
    wrong_constraits_string = '''
    $unknown
    distance 1 2 1.0 2.0 10
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # rotation not supported
    wrong_constraits_string = '''
    $set
    rotation 1-4 10.0
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # freezing x not supported
    wrong_constraits_string = '''
    $freeze
    x 1 1.0
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # missing $set
    wrong_constraits_string = '''
    distance 1 2 1.0
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # setting xyz not supported
    wrong_constraits_string = '''
    $set
    xyz 1-3 1.0 2.0 3.0
    '''
    with pytest.raises(ValueError):
        make_constraints_dict(wrong_constraits_string)
    # wrong index
    wrong_constraits_string = '''
    $set
    distance 0 1 1.0
    '''
    with pytest.raises(AssertionError):
        make_constraints_dict(wrong_constraits_string)