예제 #1
0
파일: __init__.py 프로젝트: tdaff/sats
 def __exit__(self, *args):
     os.close(self.stdout_fileno)
     self.extend(os.read(self.pipe_in, 99999).splitlines())
     os.close(self.pipe_in)
     os.dup2(self.stdout_save, self.stdout_fileno)
     os.close(self.stdout_save)
     if self.debug_on_exit:
         for line in self:
             debug(line)
예제 #2
0
파일: __init__.py 프로젝트: tdaff/sats
def kpoint_spacing_to_mesh(structure, density, spacing=None):
    """
    Calculate the kpoint mesh that is equivalent to the given density
    in reciprocal Angstrom.

    Parameters
    ----------
    structure : ase.Atoms
        A structure that can have get_reciprocal_cell called on it.
    density : float
        K-Point density in $A^{-1}$.
    spacing : list
        If a three item list is given it will be replaced with the
        actual calculated spacing.

    Returns
    -------
    kpoint_mesh : [int, int, int]

    """
    # No factor of 2pi in ase, otherwise need to divide through in the mesh
    try:
        r_cell = structure.get_reciprocal_cell()
    except NameError:
        r_cell = inv(structure.cell).transpose()

    r_x = sum(x**2 for x in r_cell[0])**0.5
    r_y = sum(x**2 for x in r_cell[1])**0.5
    r_z = sum(x**2 for x in r_cell[2])**0.5

    kpoint_mesh = [
        int(r_x / (density)) + 1,
        int(r_y / (density)) + 1,
        int(r_z / (density)) + 1
    ]

    debug("Kpoints: {}".format(kpoint_mesh))

    if spacing is not None:
        spacing[:] = [
            r_x / kpoint_mesh[0], r_y / kpoint_mesh[1], r_z / kpoint_mesh[2]
        ]
        debug("Spacing: {}".format(spacing))

    return kpoint_mesh
예제 #3
0
파일: options.py 프로젝트: tdaff/sats
def add_option(section,
               option,
               default_value,
               parser_function,
               doc,
               multiple=False,
               valid_values=None):
    """
    Add a option to the global namespace. Use as a decorator for any functions
    that take need options, these will be made available in the global
    options module.

    Parameters
    ----------
    section : str
        Name of section in which to store the argument.
    option : str
        Name of the option.
    default_value : any
        Default value to assign to the option. May be any type that can
        be interpreted by the options module.
    parser_function : function
        Function to parse individual values of the data, e.g. bool, int,
        float, str...
    doc : str
        Description of the option.
    multiple : bool
        If True, multiple values will be returned as a tuple.
    valid_values : list, optional
        If valid_values are give, these will be the only options that can
        be used with this option and will be added to any other valid_values
        from other calls to this function.

    Returns
    -------
    wrapper : function
        Decorating function that returns the unmodified function
    """

    # No sections exist in the beginning
    if section not in DEFAULTS:
        DEFAULTS[section] = OrderedDict()

    # merge any existing valid values
    if valid_values and option in DEFAULTS[section]:
        valid_values.extend(DEFAULTS[section][option].valid_values)

    DEFAULTS[section][option] = Option(parser_function=parser_function,
                                       default_value=default_value,
                                       doc=doc,
                                       multiple=multiple,
                                       valid_values=valid_values)

    debug("New option {0}.".format(DEFAULTS[section][option]))

    # Return a function that does nothing so we can use this as a decorator
    def wrapper(func):
        """Do nothing but return the original function."""
        return func

    return wrapper
예제 #4
0
def molecular_dynamics(system,
                       potential,
                       potential_filename=None,
                       temperature=300,
                       total_steps=1100000,
                       timestep=1.0,
                       connect_interval=200,
                       write_interval=20000,
                       equilibration_steps=100000,
                       out_of_plane=None,
                       random_seed=None):
    """
    Run very simple molecular dynamics to generate some configurations. Writes
    configurations out as xyz and CASTEP files.
    """

    info("Inside MD.")
    if random_seed is None:
        random_seed = random.SystemRandom().randint(0, 2**63)
    quippy.system.system_set_random_seeds(random_seed)
    info("Quippy Random Seed {0}.".format(random_seed))
    system = Atoms(system)

    # Can take Potential objects, or just use a string
    if not isinstance(potential, Potential):
        if potential_filename:
            potential = Potential(potential, param_filename=potential_filename)
        else:
            potential = Potential(potential)
    system.set_calculator(potential)

    dynamical_system = DynamicalSystem(system)
    with Capturing(debug_on_exit=True):
        dynamical_system.rescale_velo(temperature)

    if out_of_plane is not None:
        # Stop things moving vertically in the cell
        dynamical_system.atoms.velo[3, :] = 0

    base_dir = os.getcwd()
    run_path = '{0}_{1:g}/'.format(system.info['name'], temperature)
    info("Putting files in {0}.".format(run_path))
    os.mkdir(run_path)
    os.chdir(run_path)

    trajectory = 'traj_{0}_{1:g}.xyz'.format(system.info['name'], temperature)
    out = AtomsWriter(trajectory)

    dynamical_system.atoms.set_cutoff(potential.cutoff() + 2.0)
    dynamical_system.atoms.calc_connect()
    potential.calc(dynamical_system.atoms,
                   force=True,
                   energy=True,
                   virial=True)

    structure_count = 0

    # Basic NVE molecular dynamics
    for step_number in range(1, total_steps + 1):
        dynamical_system.advance_verlet1(timestep,
                                         virial=dynamical_system.atoms.virial)
        potential.calc(dynamical_system.atoms,
                       force=True,
                       energy=True,
                       virial=True)
        dynamical_system.advance_verlet2(timestep,
                                         f=dynamical_system.atoms.force,
                                         virial=dynamical_system.atoms.virial)

        # Maintenance of the system
        if not step_number % connect_interval:
            debug("Connect at step {0}".format(step_number))
            dynamical_system.atoms.calc_connect()
            if step_number < equilibration_steps:
                with Capturing(debug_on_exit=True):
                    dynamical_system.rescale_velo(temperature)

        if not step_number % write_interval:
            debug("Status at step {0}".format(step_number))
            # Print goes to captured stdout
            with Capturing(debug_on_exit=True):
                dynamical_system.print_status(
                    epot=dynamical_system.atoms.energy)
                dynamical_system.rescale_velo(temperature)

            if step_number > equilibration_steps:
                debug("Write at step {0}".format(step_number))
                out.write(dynamical_system.atoms)
                sp_path = '{0:03d}'.format(structure_count)
                write_filename = '{0}_{1:g}.{2:03d}'.format(
                    system.info['name'], temperature, structure_count)
                os.mkdir(sp_path)
                os.chdir(sp_path)
                castep_write(dynamical_system.atoms, filename=write_filename)
                espresso_write(dynamical_system.atoms, prefix=write_filename)
                write_extxyz("{0}.xyz".format(write_filename),
                             dynamical_system.atoms)
                info("Wrote a configuration {0}.".format(write_filename))
                os.chdir('..')
                structure_count += 1

    out.close()
    os.chdir(base_dir)

    info("MD Done.")
예제 #5
0
def slice_sample(bulk,
                 potential,
                 potential_filename,
                 temperature,
                 pressure,
                 lattice_delta,
                 atom_delta,
                 m_max,
                 e0=None,
                 init_d=0,
                 num_configs=10,
                 write_interval=-1,
                 random_seed=None):

    info("Inside Slice Sample.")

    # Randomise the random seed
    if random_seed is None:
        random_seed = SystemRandom().randint(0, 2**63)
    quippy.system.system_set_random_seeds(random_seed)
    seed(random_seed)
    info("Quippy Random Seed {0}.".format(random_seed))
    info("Python Random Seed {0}.".format(random_seed))

    if not isinstance(potential, Potential):
        if potential_filename:
            potential = Potential(potential, param_filename=potential_filename)
        else:
            potential = Potential(potential)

    bulk = Atoms(bulk)
    # pressure in GPa -> eV/A^3
    pressure = pressure / quippy.GPA
    density_function = create_density_function(bulk, potential, pressure,
                                               temperature, e0)

    # Convert to triangle lattice representation (lower triangle in cell)
    scaled_positions = bulk.get_scaled_positions()
    lattice_params = quippy.get_lattice_params(bulk.lattice)
    new_cell = quippy.make_lattice(*lattice_params).T
    bulk.set_cell(new_cell)
    bulk.set_scaled_positions(scaled_positions)
    params = [
        bulk.cell[0][0], bulk.cell[1][0], bulk.cell[1][1], bulk.cell[2][0],
        bulk.cell[2][1], bulk.cell[2][2]
    ]
    info("Re-orineted to cell: {0}.".format(new_cell.tolist()))

    for atom in bulk.positions.tolist()[1:]:
        params.extend(atom)

    # value for the first iteration
    df_value = density_function(params)

    # Floating count so that division by write_interval make it integer for
    # written configurations
    count = 0.0
    idx = init_d
    output = ParamWriter(bulk, bulk.info['name'], potential)

    # Only write once everything has changed
    if write_interval < 1:
        write_interval = len(params)
    info("Writing configurations after {0} steps.".format(write_interval))

    # Loop just iterates to the next value of x
    while count / write_interval < num_configs:
        # Determine the delta value outside the incrementer, so we can make it
        # do less work
        if idx < 6:
            delta = lattice_delta
        else:
            delta = atom_delta
        # Here's where the magic happens
        params, df_value = increment_params(density_function,
                                            params,
                                            idx,
                                            delta,
                                            m_max,
                                            df_0=df_value)

        debug("SLICE_SAMPLE: {0:g}".format(count / write_interval))
        debug("Params: {0}.".format(", ".join("{0}".format(x)
                                              for x in params)))

        if not count % write_interval:
            output.write_config(params)

        count += 1
        idx += 1
        if idx >= len(params):
            idx = 0

    output.close()
    info("Slice Sample Done.")