from ase.calculators import gaussian from ase.calculators.calculator import FileIOCalculator from ase.io import read, write from typing import TYPE_CHECKING, Optional, Literal from copy import deepcopy GSUB = "/home/fanhj/calcs/lele/tools/gsub_wait" gau_src= gaussian.Gaussian gau_dyn_src = gaussian.GaussianDynamics methodType = Optional[ str | Literal[ "HF", "MP2", "MP3", "MP4", "MP4(DQ)", "MP4(SDQ)", "MP5", "CCSD", "CCSDT", "QCISD", "CID", "CISD", "CIS", "B3LYP", "B3PW91", "BLYP", "PBE", "PBE0", "M06", "M062X", "M06L", "M06HF", "CAM-B3LYP", "wb97xd", "wb97xd3", "LC-wPBE", "HSE06", "LSDA", "SVWN", "PW91", "mPW1PW91", "HCTH", "HCTH147", "HCTH407", "TPSSh", "TPSS", "revPBE", "PBEPBE", "B2PLYP", "mPW2PLYP", "B2PLYPD3", "PBE0DH", "PBEQIDH", ] ] basisType = Optional[ str | Literal[ "STO-3G", "3-21G", "6-31G", "6-31G(d)", "6-31G(d,p)", "6-31+G(d)", "6-31+G(d,p)", "6-31++G(d,p)", "6-311G", "6-311G(d)", "6-311G(d,p)", "6-311+G(d)", "6-311+G(d,p)", "6-311++G(d,p)", "cc-pVDZ", "cc-pVTZ", "cc-pVQZ", "cc-pV5Z", "cc-pV6Z", "aug-cc-pVDZ", "aug-cc-pVTZ", "aug-cc-pVQZ", "aug-cc-pV5Z", "def2SVP", "def2SVPD", "def2TZVP", "def2TZVPD", "def2QZVP", "def2QZVPP", "LANL2DZ", "LANL2MB", "SDD", "CEP-4G", "CEP-31G", "CEP-121G", "DGDZVP", "DGDZVP2", "Gen", "GenECP", ] ] scrfSolventType = Optional[ str | Literal['Water', 'Acetone', 'Acetonitrile', 'Aniline', 'Benzene', 'Bromoform', 'Butanol', 'CarbonDisulfide', 'CarbonTetrachloride', 'Chlorobenzene', 'Chloroform', 'Cyclohexane', 'Dichloroethane', 'Dichloromethane', 'Diethylether', 'Dimethylformamide', 'Dimethylsulfoxide', 'Ethanol', 'Ethylacetate', 'Heptane', 'Hexane', 'Methanol', 'Nitromethane', 'Octanol', 'Pyridine', 'Tetrahydrofuran', 'Toluene', 'Xylene' ] ] class Gaussian(gau_src): mem:int nprocshared:Literal[20,32] charge: int mult: Optional[int] def __init__(self, proc:Literal[20,32]=32, charge:int=0, mult:Optional[int]=None, mem="30GB", label='Gaussian', method:methodType=None, basis:basisType=None, fitting_basis:Optional[str]=None, output_type:Literal['N','P']='P', basisfile:Optional[str]=None, basis_set:Optional[str]=None, xc:Optional[str]=None, extra:Optional[str]=None, ioplist:Optional[list[str]]=None, addsec=None, spinlist=None, zefflist=None, qmomlist=None, nmagmlist=None, znuclist=None, radnuclearlist=None, chk:Optional[str]=None, oldchk:Optional[str]=None, nprocshared:Optional[int]=None, scrfSolvent:scrfSolventType=None, scrf:Optional[str]=None, em:Optional[Literal["GD2","GD3","GD4","GD3BJ"]|str]=None, **kwargs): ''' Parameters ----------- proc: int A short name for nprocshared method: str Level of theory to use, e.g. ``hf``, ``ccsd``, ``mp2``, or ``b3lyp``. Overrides ``xc`` (see below). xc: str Level of theory to use. Translates several XC functionals from their common name (e.g. ``PBE``) to their internal Gaussian name (e.g. ``PBEPBE``). basis: str The basis set to use. If not provided, no basis set will be requested, which usually results in ``STO-3G``. Maybe omitted if basisfile is set (see below). fitting_basis: str The name of the fitting basis set to use. output_type: str Level of output to record in the Gaussian output file - this may be ``N``- normal or ``P`` - additional. basisfile: str The name of the basis file to use. If a value is provided, basis may be omitted (it will be automatically set to 'gen') basis_set: str The basis set definition to use. This is an alternative to basisfile, and would be the same as the contents of such a file. charge: int The system charge. If not provided, it will be automatically determined from the ``Atoms`` object’s initial_charges. mult: int The system multiplicity (``spin + 1``). If not provided, it will be automatically determined from the ``Atoms`` object’s ``initial_magnetic_moments``. extra: str Extra lines to be included in the route section verbatim. It should not be necessary to use this, but it is included for backwards compatibility. ioplist: list A collection of IOPs definitions to be included in the route line. addsec: str Text to be added after the molecular geometry specification, e.g. for defining masses with ``freq=ReadIso``. spinlist: list A list of nuclear spins to be added into the nuclear propeties section of the molecule specification. zefflist: list A list of effective charges to be added into the nuclear propeties section of the molecule specification. qmomlist: list A list of nuclear quadropole moments to be added into the nuclear propeties section of the molecule specification. nmagmlist: list A list of nuclear magnetic moments to be added into the nuclear propeties section of the molecule specification. znuclist: list A list of nuclear charges to be added into the nuclear propeties section of the molecule specification. radnuclearlist: list A list of nuclear radii to be added into the nuclear propeties section of the molecule specification. params: dict Contains any extra keywords and values that will be included in either the link0 section or route section of the gaussian input file. To be included in the link0 section, the keyword must be one of the following: ``mem``, ``chk``, ``oldchk``, ``schk``, ``rwf``, ``oldmatrix``, ``oldrawmatrix``, ``int``, ``d2e``, ``save``, ``nosave``, ``errorsave``, ``cpu``, ``nprocshared``, ``gpucpu``, ``lindaworkers``, ``usessh``, ``ssh``, ``debuglinda``. Any other keywords will be placed (along with their values) in the route section. ''' if nprocshared is not None and proc is not None: if nprocshared == proc:print("Providing both nprocshared and proc is not recomanded") else: raise ValueError("both nprocshared and proc provided, and inequal.") if scrfSolvent is not None and scrf is not None: raise ValueError("scrfSolvent and scrf both not None") if scrfSolvent is not None: scrf = "Solvent="+scrfSolvent optional_keys = ['chk','oldchk','scrf', 'geom', 'integral', 'density', 'nosymm', 'symmetry', 'units', 'temperature', 'pressure', 'counterpoise', 'gfinput', 'gfprint', 'test', 'output', 'punch', 'prop', 'pseudo', 'restart', 'scale', 'sparse', 'window', 'em'] for key in optional_keys: val = locals().get(key,None) if val is not None: kwargs[key] = val super().__init__( nprocshared = proc, mem=mem, label=label, command=GSUB+" "+label, charge = charge, mult = mult, method = method, basis = basis, fitting_basis = fitting_basis, output_type = output_type, basisfile = basisfile, basis_set = basis_set, xc = xc, extra = extra, ioplist = ioplist, addsec = addsec, spinlist = spinlist, zefflist = zefflist, qmomlist = qmomlist, nmagmlist = nmagmlist, znuclist = znuclist, radnuclearlist = radnuclearlist, **kwargs ) assert self.fileio_rules self.fileio_rules.stdin_name = '{prefix}.gin' def mod(self,charge:int=0, mult:int=1) -> "Gaussian": new = deepcopy(self) new.charge = charge new.mult = mult return new def write_input(self, atoms, properties=None, system_changes=None): FileIOCalculator.write_input(self, atoms, properties, system_changes) if TYPE_CHECKING: assert isinstance(self.label, str) assert self.parameters write(self.label + '.gin', atoms, properties=properties, format='gaussian-in', parallel=False, **self.parameters) def read_results(self): if TYPE_CHECKING: assert isinstance(self.label, str) output = read(self.label + '.out', format='gaussian-out') assert output self.calc = output.calc self.results = output.calc.results class GaussianDynamics(gau_dyn_src): def __init__(self, atoms, calc=None): super().__init__(atoms, calc=calc) def run(self, **kwargs): calc_old = self.atoms.calc params_old = 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 + '.out') self.atoms.cell = atoms.cell self.atoms.positions = atoms.positions self.atoms.calc = atoms.calc 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={}', } gaussian.Gaussian = Gaussian gaussian.GaussianDynamics = GaussianDynamics gaussian.GaussianOptimizer = GaussianOptimizer gaussian.GaussianIRC = GaussianIRC __all__ = [ 'Gaussian', 'GaussianDynamics', 'GaussianOptimizer', 'GaussianIRC', 'GSUB' ]