예제 #1
0
    def submit(self, script, cwd=None):
        """Submit a job to the queue.x

        | Args:
        |   script (str): content of the submission script
        |   cwd (Optional[str]): path to the desired working directory
        |
        | Returns:
        |   job_id (str): the job ID assigned by the queue system and parsed
        |                 with sub_outre
        """

        if self._rTarg is None:
            subproc = sp.Popen(self.sub_cmd.split(),
                               stdin=sp.PIPE,
                               stdout=sp.PIPE,
                               stderr=sp.PIPE,
                               cwd=cwd)

            stdout, stderr = safe_communicate(subproc, script)
        else:
            with self._rTarg.context as rTarg:
                stdout, stderr = rTarg.run_cmd(self.sub_cmd,
                                               cwd=cwd,
                                               stdin=script)

        # Parse out the job id!
        match = self.sub_outre.search(stdout)
        if match is None:
            raise RuntimeError('Submission of job has failed with output:\n'
                               '\tSTDOUT: {0}\n\tSTDERR: {1}'.format(
                                   stdout, stderr))
        else:
            return match.groupdict()['job_id']
예제 #2
0
    def list():
        list_proc = sp.Popen(['ps', 'aux'],
                             stdin=sp.PIPE,
                             stdout=sp.PIPE,
                             stderr=sp.PIPE)
        stdout, stderr = safe_communicate(list_proc)
        # Parse stdout
        all_subms = []
        for l in stdout.split('\n'):
            if 'soprano.hpc.submitter._spawn' in l:
                lspl = l.split()
                # File, name, time, PID
                subm = lspl[-3], lspl[-2], lspl[-7], int(lspl[1])
                all_subms.append(subm)

        return all_subms
예제 #3
0
    def kill(self, job_id):
        """Kill the job with the given ID

        | Args:
        |   job_id (str): ID of the job to kill
        |
        """

        if self._rTarg is None:
            subproc = sp.Popen(self.kill_cmd.split() + [job_id],
                               stdout=sp.PIPE,
                               stderr=sp.PIPE)
            stdout, stderr = safe_communicate(subproc)
        else:
            with self._rTarg.context as rTarg:
                stdout, stderr = rTarg.run_cmd(self.kill_cmd +
                                               ' {0}'.format(job_id))
예제 #4
0
    def setup_job(self, name, args, folder):
        """Copy files to temporary folder to prepare for execution"""

        for f in args['files']:
            shutil.move(f, folder)
        # Also copy the pseudopotentials
        for pp in self.pspots:
            shutil.copy(pp, folder)

        success = True

        self.log('Copying files for job {0}\n'.format(name))

        # Perform dryrun test if required
        if self.drun:
            self.log('Performing DRYRUN\n')
            dry_proc = sp.Popen([self.castep_command, name, '--dryrun'],
                                cwd=folder, stdout=sp.PIPE,
                                stderr=sp.PIPE)
            stdout, stderr = safe_communicate(dry_proc)
            # When it's finished...
            try:
                castfile = open(os.path.join(folder, name + '.castep'))
            except IOError:
                return False
            # Does the file contain the required lines?
            drline1 = "|       DRYRUN finished ...                       |"
            drline2 = "|       No problems found with input files.       |"

            castlines = castfile.readlines()
            success = False
            for i, l in enumerate(castlines):
                if drline1 in l:
                    if drline2 in castlines[i+1]:
                        success = True
                        break

            # Ok, now remove the CASTEP file
            castfile.close()
            os.remove(castfile.name)

        return success
예제 #5
0
    def list(self, user='******'):
        """List all jobs found in the queue

        | Returns:
        |   jobs (dict): a dict of jobs classified by ID containing all info
        |                that can be matched through list_outre
        |   user (Optional[str]): user for whom jobs should be listed. Will
        |                         not have any effect if list_user_opt has not
        |                         been specified. Default is $USER.
        |

        """

        cmd = self.list_cmd
        if self.list_user_opt is not None:
            cmd += ' {0} {1}'.format(self.list_user_opt, user)

        if self._rTarg is None:
            subproc = sp.Popen(cmd.split(), stdout=sp.PIPE, stderr=sp.PIPE)

            stdout, stderr = safe_communicate(subproc)
        else:
            with self._rTarg.context as rTarg:
                stdout, stderr = rTarg.run_cmd(cmd)

        # Parse out everything!
        jobs = {}
        for line in stdout.split('\n'):
            match = self.list_outre.search(line)
            if match is None:
                continue
            else:
                jobdict = match.groupdict()
                jobs[jobdict['job_id']] = jobdict

        return jobs
예제 #6
0
def airssGen(input_file,
             n=100,
             buildcell_command='buildcell',
             buildcell_path=None,
             clone_calc=True):
    """Generator function binding to AIRSS' Buildcell.

    This function searches for a buildcell executable and uses it to
    generate multiple new Atoms structures for a collection.

    | Args:
    |   input_file (str or file): the .cell file with appropriate comments
    |                             specifying the details of buildcell's
    |                             construction work.
    |   n (int): number of structures to generate. If set to None the
    |            generator goes on indefinitely.
    |   buildcell_command (str): command required to call the buildcell
    |                            executable.
    |   buildcell_path (str): path where the buildcell executable can be
    |                         found. If not present, the buildcell command
    |                         will be invoked directly (assuming the
    |                         executable is in the system PATH).
    |   clone_calc (bool): if True, the CASTEP calculator in the input file
    |                      will be copied and attached to the new structures.
    |                      This means that for example any additional CASTEP
    |                      keywords/blocks in the input file will be carried
    |                      on to the new structures. Default is True.

    | Returns:
    |   airssGenerator (generator): an iterable object that yields structures
    |                               created by buildcell.

    """

    # First: check that AIRSS is even installed
    if buildcell_path is None:
        buildcell_path = ''
    airss_cmd = [os.path.join(buildcell_path, buildcell_command)]

    try:
        stdout, stderr = sp.Popen(airss_cmd + ['-h'],
                                  stdout=sp.PIPE,
                                  stderr=sp.PIPE).communicate()
    except OSError:
        # Not even installed!
        raise RuntimeError('No instance of Buildcell found on this system')

    # Now open the given input file
    try:
        input_file = open(input_file)   # If it's a string
    except TypeError:
        pass                            # If it's already a file
    template = input_file.read()
    # Now get the file name
    basename = seedname(input_file.name)
    input_file.close()

    # Calculator (if needed)
    calc = None
    if clone_calc:
        calc = ase_io.read(input_file.name).calc

    # And keep track of the count!
    # (at least if it's not infinite)
    i = 0

    while True:
        if n is not None:
            if i >= n:
                return
            i += 1

        # Generate a structure
        subproc = sp.Popen(airss_cmd,
                           universal_newlines=True,
                           stdin=sp.PIPE,
                           stdout=sp.PIPE,
                           stderr=sp.PIPE)
        stdout, stderr = safe_communicate(subproc, template)

        # Now turn it into a proper Atoms object
        # To do this we need to make it look like a file to ASE's io.read
        newcell = ase_io.read(StringIO(stdout), format='castep-cell')
        if clone_calc:
            newcell.set_calculator(copy.deepcopy(calc))
        # Generate it a name, function of its properties
        postfix = hashlib.md5(str(newcell.get_positions()
                                  ).encode()).hexdigest()
        newcell.info['name'] = '{0}_{1}'.format(basename, postfix)
        yield newcell
예제 #7
0
def get_gulp_charges(s,
                     charge_method="eem",
                     save_charges=True,
                     gulp_command='gulp',
                     gulp_path=None):
    """Calculate the atomic partial charges using GULP.

    | Parameters:
    |   s (ase.Atoms): the structure to calculate the energy of
    |   charge_method (Optional[str]): which method to use for atomic partial
    |                                  charge calculation. Can be any of
    |                                  'eem', 'qeq' and 'pacha'.
    |                                  Default is 'eem'.
    |   save_charges (Optional[bool]): whether to save or not the charges in
    |                                  the given ase.Atoms object. Default is
    |                                  True.
    |   gulp_command (Optional[str]): command required to call the GULP
    |                                 executable.
    |   gulp_path (Optional[str]): path where the GULP executable can be
    |                              found. If not present, the GULP command
    |                              will be invoked directly (assuming the
    |                              executable is in the system PATH).

    | Returns:
    |   charges(np.array(float)): per-atom partial charges

    """

    # Sanity check
    if charge_method not in ['eem', 'qeq', 'pacha']:
        raise ValueError('Invalid charge_method passed to get_gulp_charges')

    # Now define the input
    gin = "{0}\n".format(charge_method)
    gin += _gulp_cell_definition(s)

    # AND GO!
    if gulp_path is None:
        gulp_path = ''

    gulp_cmd = [os.path.join(gulp_path, gulp_command)]

    # Run the thing...
    try:
        gulp_proc = sp.Popen(gulp_cmd,
                             universal_newlines=True,
                             stdin=sp.PIPE,
                             stdout=sp.PIPE,
                             stderr=sp.PIPE)
        stdout, stderr = safe_communicate(gulp_proc, gin)
    except OSError:
        raise RuntimeError('GULP not found on this system with the given '
                           'command')

    # Necessary for compatibility in Python2
    try:
        stdout = unicode(stdout)
    except NameError:
        pass

    # And parse the output
    gulp_lines = stdout.split('\n')
    charges = _gulp_parse_charges(gulp_lines)
    if charges is None:
        raise RuntimeError('ERROR - GULP run failed to return charges')

    # Run a security check
    if not np.all(s.get_atomic_numbers() == charges['Z']):
        raise RuntimeError('ERROR - Invalid charges parsed from GULP output')

    charges = charges['q']

    if save_charges:
        s.set_initial_charges(charges)

    return charges
예제 #8
0
def get_w99_energy(s,
                   charge_method='eem',
                   Etol=1e-6,
                   gulp_command='gulp',
                   gulp_path=None,
                   save_charges=False):
    """Calculate the W99 force field energy using GULP.

    | Parameters:
    |   s (ase.Atoms): the structure to calculate the energy of
    |   charge_method (Optional[str]): which method to use for atomic partial
    |                                  charge calculation. Can be any of
    |                                  'eem', 'qeq' and 'pacha'.
    |                                  Default is 'eem'.
    |   Etol (Optional[float]): tolerance on energy for intermolecular
    |                           potential cutoffs (relative to single
    |                           interaction energy). Default is 1e-6 eV.
    |   gulp_command (Optional[str]): command required to call the GULP
    |                                 executable.
    |   gulp_path (Optional[str]): path where the GULP executable can be
    |                              found. If not present, the GULP command
    |                              will be invoked directly (assuming the
    |                              executable is in the system PATH).
    |   save_charges (Optional[bool]): whether to retrieve also the charges
    |                                  and save them in the Atoms object.
    |                                  False by default.

    | Returns:
    |   energy (float): the calculated energy

    """

    # Sanity check
    if charge_method not in ['eem', 'qeq', 'pacha']:
        raise ValueError('Invalid charge_method passed to get_w99_energy')

    # First, atom types
    find_w99_atomtypes(s)

    # Now define the input
    gin = "molq {0} dipole\n".format(charge_method)
    gin += _gulp_cell_definition(s, syms=s.get_array('w99_types'))

    # Finally, the potential definition
    gin += _w99_field_definition(s, Etol)

    # AND GO!
    if gulp_path is None:
        gulp_path = ''

    gulp_cmd = [os.path.join(gulp_path, gulp_command)]

    try:
        gulp_proc = sp.Popen(gulp_cmd,
                             universal_newlines=True,
                             stdin=sp.PIPE,
                             stdout=sp.PIPE,
                             stderr=sp.PIPE)
        stdout, stderr = safe_communicate(gulp_proc, gin)
    except OSError:
        raise RuntimeError('GULP not found on this system with the given '
                           'command')

    # Necessary for compatibility in Python2
    try:
        stdout = unicode(stdout)
    except NameError:
        pass

    # Now parse the energy
    gulp_lines = stdout.split('\n')
    E = _gulp_parse_energy(gulp_lines)
    if E is None:
        raise RuntimeError('ERROR - GULP run failed to return energy')

    # Remember it with a mock ASE calculator
    calc = SinglePointCalculator(s, energy=E)
    s.set_calculator(calc)

    if save_charges:
        qs = _gulp_parse_charges(gulp_lines)
        s.set_initial_charges(qs['q'])

    return E