Skip to main content
`Ctrl`+`K`

#

# Source code for ase.calculators.gaussian

    # fmt: off

    import copy
    import os
    from collections.abc import Iterable

    from ase.calculators.calculator import FileIOCalculator
    from ase.io import read, write

    class GaussianDynamics:
        calctype = 'optimizer'
        delete = ['force']
        keyword: str | None = None
        special_keywords: dict[str, str] = {}

        def __init__(self, atoms, calc=None):
            self.atoms = atoms
            if calc is not None:
                self.calc = calc
            else:
                if self.atoms.calc is None:
                    raise ValueError("{} requires a valid Gaussian calculator "
                                     "object!".format(self.__class__.__name__))

                self.calc = self.atoms.calc

        def todict(self):
            return {'type': self.calctype,
                    'optimizer': self.__class__.__name__}

        def delete_keywords(self, kwargs):
            """removes list of keywords (delete) from kwargs"""
            for d in self.delete:
                kwargs.pop(d, None)

        def set_keywords(self, kwargs):
            args = kwargs.pop(self.keyword, [])
            if isinstance(args, str):
                args = [args]
            elif isinstance(args, Iterable):
                args = list(args)

            for key, template in self.special_keywords.items():
                if key in kwargs:
                    val = kwargs.pop(key)
                    args.append(template.format(val))

            kwargs[self.keyword] = args

        def run(self, **kwargs):
            calc_old = self.atoms.calc
            params_old = copy.deepcopy(self.calc.parameters)

            self.delete_keywords(kwargs)
            self.delete_keywords(self.calc.parameters)
            self.set_keywords(kwargs)

            self.calc.set(**kwargs)
            self.atoms.calc = self.calc

            try:
                self.atoms.get_potential_energy()
            except OSError:
                converged = False
            else:
                converged = True

            atoms = read(self.calc.label + '.log')
            self.atoms.cell = atoms.cell
            self.atoms.positions = atoms.positions

            self.calc.parameters = params_old
            self.calc.reset()
            if calc_old is not None:
                self.atoms.calc = calc_old

            return converged

    class GaussianOptimizer(GaussianDynamics):
        keyword = 'opt'
        special_keywords = {
            'fmax': '{}',
            'steps': 'maxcycle={}',
        }

    class GaussianIRC(GaussianDynamics):
        keyword = 'irc'
        special_keywords = {
            'direction': '{}',
            'steps': 'maxpoints={}',
        }

    class Gaussian(FileIOCalculator):
        _legacy_default_command = 'g16 < PREFIX.com > PREFIX.log'
        implemented_properties = ['energy', 'forces', 'dipole']
        discard_results_on_any_change = True

        fileio_rules = FileIOCalculator.ruleset(
            stdin_name='{prefix}.com',
            stdout_name='{prefix}.log')

        def __init__(self, *args, label='Gaussian', **kwargs):
            super().__init__(*args, label=label, **kwargs)

        def write_input(self, atoms, properties=None, system_changes=None):
            super().write_input(atoms, properties, system_changes)
            write(self.label + '.com', atoms, properties=properties,
                  format='gaussian-in', parallel=False, **self.parameters)

        def read_results(self):
            output = read(self.label + '.log', format='gaussian-out')
            self.calc = output.calc
            self.results = output.calc.results

        # Method(s) defined in the old calculator, added here for
        # backwards compatibility
        def clean(self):
            for suffix in ['.com', '.chk', '.log']:
                try:
                    os.remove(os.path.join(self.directory, self.label + suffix))
                except OSError:
                    pass

        def get_version(self):
            raise NotImplementedError  # not sure how to do this yet