From 453ad9f51b4e67f60c6c34ed793e12c418e8661d Mon Sep 17 00:00:00 2001 From: Emiel Slootman <4210747+EmielSlootman@users.noreply.github.com> Date: Mon, 2 May 2022 10:51:29 +0200 Subject: [PATCH] Update to v1.0.6 * Changes GAMESS to presets * Small fixes * Update test * Added docs warning * Change test * Update version --- docs/qmcblip/gamess.rst | 17 ++- examples/C2-gamess/run.py | 13 +- qmcblip/gamess/__init__.py | 4 +- qmcblip/gamess/utils.py | 290 +++++++++++++++++++----------------- setup.py | 2 +- tests/gamess/test_gamess.py | 27 +--- 6 files changed, 179 insertions(+), 174 deletions(-) diff --git a/docs/qmcblip/gamess.rst b/docs/qmcblip/gamess.rst index 3d13658..708f6e3 100644 --- a/docs/qmcblip/gamess.rst +++ b/docs/qmcblip/gamess.rst @@ -1,7 +1,8 @@ Creating Wavefunction --------------------- -Important warning: this part is currently still experimental and only confirmed to work for C2. +.. warning:: + This part is currently still experimental and only confirmed to work for C2. QMCblip also includes some tools to make the wavefunction for CHAMP using GAMESS. To use it, first import: @@ -18,13 +19,11 @@ We can now initialize our :obj:`WavefunctionCreator >> wf.setup_rhf() ->>> wf.setup_cas(system=dict(mwords=500), drt=dict(nmcc=2, ndoc=2, nval=2)) ->>> wf.setup_ci(system=dict(mwords=500), cidrt=dict(nfzc=2, ndoc=2, nval=2)) +>>> wf.run_gamess(label='rhf', ...) After GAMESS is done we can convert the GAMESS output to CHAMP wavefunction. ->>> wf.convert_to_champ() +>>> wf.convert_to_champ('rhf') And we can also quickly make a CHAMP input file (``vmc.inp``). @@ -35,6 +34,14 @@ Here ``input`` is of the :obj:`Settings ` type. With t >>> from qmcblip.champ import CHAMP >>> atoms.calc = CHAMP(champ_loc='../../champ/bin/vmc.mov1', settings = input) +QMCblip also contains some preconfigured GAMESS simulations. Currently QMCblip only has a preset for C2. To make a wavefunction for C2: + +>>> from qmcblip.gamess.utils import Presets +>>> +>>> input = Presets.C2().build('../../champ') + +It is that easy! + For more examples, see :doc:`../examples/examples`. .. _`GAMESS documentation`: https://www.msg.chem.iastate.edu/gamess/GAMESS_Manual/docs-input.txt \ No newline at end of file diff --git a/examples/C2-gamess/run.py b/examples/C2-gamess/run.py index 87581c7..7ef0518 100644 --- a/examples/C2-gamess/run.py +++ b/examples/C2-gamess/run.py @@ -1,16 +1,9 @@ -from ase import Atoms -from qmcblip.gamess.utils import WavefunctionCreator +from qmcblip.gamess.utils import Presets from qmcblip.champ import CHAMP -from qmcblip.champio import Settings -atoms = Atoms('C2', [(0,0,-0.7), (0,0, 0.7)]) -wf = WavefunctionCreator(atoms, '../../champ') +atoms = Presets.C2().atoms -wf.setup_rhf() -wf.setup_cas(system=dict(mwords=500), drt=dict(nmcc=2, ndoc=2, nval=2)) -wf.setup_ci(system=dict(mwords=500), cidrt=dict(nfzc=2, ndoc=2, nval=2)) -wf.convert_to_champ() -input = wf.create_champ_input() +input = Presets.C2().build('../../champ') input.optwf.nopt_iter = 100 diff --git a/qmcblip/gamess/__init__.py b/qmcblip/gamess/__init__.py index 747fef9..6818cdc 100644 --- a/qmcblip/gamess/__init__.py +++ b/qmcblip/gamess/__init__.py @@ -1,5 +1,5 @@ """GAMESS""" -from .utils import WavefunctionCreator +from .utils import WavefunctionCreator, Presets -__all__ = ['WavefunctionCreator'] +__all__ = ['WavefunctionCreator', 'Presets'] diff --git a/qmcblip/gamess/utils.py b/qmcblip/gamess/utils.py index 914a32f..8266c8a 100644 --- a/qmcblip/gamess/utils.py +++ b/qmcblip/gamess/utils.py @@ -8,6 +8,8 @@ from shutil import copyfile import ase.io.gamess_us +from ase import Atoms +from pydantic import BaseModel from qmcblip.champio import Settings @@ -41,6 +43,7 @@ def __init__(self, atoms, champ_loc): self.gamess = GAMESSUS self.basename = atoms.symbols.get_chemical_formula() + self.userscr = None if not Path('pool').is_dir(): os.mkdir('pool') @@ -52,26 +55,66 @@ def __init__(self, atoms, champ_loc): copyfile(self.champ_path.joinpath('pool/BFD/ECP_gamess/' + atom), 'gamess/' + atom) copyfile(self.champ_path.joinpath('pool/BFD/ECP_champ/BFD.gauss_ecp.dat.' + atom), 'pool/BFD.gauss_ecp.dat.' + atom) + self._get_ecp() - if not Path('pool/jastrow').is_file(): - with open(self.champ_path.joinpath('pool/jastrow.0'), 'r', encoding='utf-8') as file: - lines = file.readlines() - with open('pool/jastrow', 'w', encoding='utf-8') as file: - for line in lines: - if line[0] not in ('&', '#'): - file.write(line) + self._create_jastrow() + + self._create_jastrow_der() - if not Path('pool/jastrow_der').is_file(): - with open(self.champ_path.joinpath('pool/opt.inp'), 'r', encoding='utf-8') as file: - lines = file.readlines() - with open('pool/jastrow_der', 'w', encoding='utf-8') as file: - for line in lines: - if line[0] not in ('&', '#'): - file.write(line) self.vec = None + def _create_jastrow(self): + """Create a jastrow file. + """ + with open('pool/jastrow', 'w', encoding='utf-8') as file: + file.write("jastrow_parameter 1\n") + file.write(" 5 5 0 norda,nordb,nordc\n") + file.write(" 0.60000000 0.00000000 scalek,a21\n") + + for _, _ in enumerate(self.symbols): + file.write(" 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " 0.00000000 (a(iparmj),iparmj=1,nparma)\n") + + file.write(" 0.50000000 0.50000000 0.00000000 0.00000000" +\ + " 0.00000000 0.00000000 (b(iparmj),iparmj=1,nparmb)\n") + + for _, _ in enumerate(self.symbols): + file.write(" 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " 0.00000000 0.00000000 0.00000000 0.00000000" +\ + " (c(iparmj),iparmj=1,nparmc)\n") + + file.write("end\n") + + def _create_jastrow_der(self): + """Create a jastrow_der file. + """ + + with open('pool/jastrow_der', 'w', encoding='utf-8') as file: + file.write("jasderiv\n") + + for _, _ in enumerate(self.symbols): + file.write("4 ") + + file.write("5 0 0 0 0 0 0 nparma,nparmb,nparmc,nparmf\n") + + for _, _ in enumerate(self.symbols): + file.write(" 3 4 5 6 (iwjasa(iparm),iparm=1,nparma)\n") + + file.write("2 3 4 5 6 (iwjasb(iparm),iparm=1,nparmb)\n") + + for _, _ in enumerate(self.symbols): + file.write("3 5 7 8 9 11 13 14 15 16 17 18 20 21 23 " +\ + "(c(iparmj),iparmj=1,nparmc)\n") + + file.write("end\n") + def _get_ecp(self): + """Get the ECP potential in GAMESS format. + """ self.ecp = {} self.ecp_p = {} @@ -89,153 +132,60 @@ def _get_ecp(self): self.ecp[ind] = self.ecp_p[atom] has_occured[atom] = True - - - def setup_rhf(self, **kwargs): - """Perform RHF setup. - - Args: - kwargs: arguments for GAMESS. - """ - name = self.basename + "_rhf" + def _get_vec(self, simname): os.chdir('gamess') - # Figure out units - calc = self.gamess(label=name, - contrl=dict(scftyp='RHF', runtyp="ENERGY", mult=1, normf=1, coord="UNIQUE", - units="BOHR", ecp="READ"), - system=dict(timlim=60, memory=1000000), - basis=dict(extfil=".TRUE.", gbasis='BFD-D'), - guess=dict(guess="HUCKEL"), - ecp=self.ecp) - - for key, item in kwargs.items(): - if isinstance(item, dict): - for key2, item2 in item.items(): - calc.parameters[key][key2] = item2 - elif key == "userscr": - calc.userscr = item - else: - calc.parameters[key] = item - - calc.calculate(self.atoms) + name = self.basename + "_" + simname + ".dat" - if calc.userscr is None: + if self.userscr is None: raise RuntimeError("USERSCR is not defined") - if not Path(calc.userscr).is_dir(): - raise RuntimeError("USERSCR is not found at: " + calc.userscr) + if not Path(self.userscr).is_dir(): + raise RuntimeError("USERSCR is not found at: " + self.userscr) - copyfile(Path(calc.userscr).joinpath(name + '.dat'), name + '.dat') + copyfile(Path(self.userscr).joinpath(name), name) self.vec = '\n'.join(str(subprocess.check_output( str(self.champ_path.joinpath('tools/interface/getvec.pl')) +\ - ' -t VEC ' + name+ '.dat', shell=True)).split('\\n')[1:-2]) + ' -t VEC ' + name, + shell=True)).split('\\n')[1:-2]).split(" $END \n $VEC \n")[-1] os.chdir('..') - def setup_cas(self, **kwargs): - """Perform CAS setup. + def run_gamess(self, label, **kwargs): + """Run a GAMESS simulation. Args: - kwargs: arguments for GAMESS. + label (:obj:`str`): simulation name. + **kwargs: other input for GAMESS. """ - if self.vec is None: - raise ValueError("No vectors.") + if 'userscr' in kwargs and kwargs['userscr'] is not None: + self.userscr = kwargs['userscr'] + if 'vec' in kwargs: + self._get_vec(kwargs['vec']) + kwargs['vec'] = self.vec + if 'ecp' in kwargs and kwargs['ecp']: + kwargs['ecp'] = self.ecp - name = self.basename + "_cas" - os.chdir('gamess') - # Figure out units - calc = self.gamess(label=name, - contrl=dict(scftyp='MCSCF', runtyp="ENERGY", mult=1, normf=0, coord="UNIQUE", - units="BOHR", ecp="READ", ICHARG=0), - system=dict(mwords=1500), - basis=dict(extfil=".TRUE.", gbasis='BFD-D'), - guess=dict(guess="MOREAD", norb=28, norder=1), - drt=dict(mxnint=50000, nmcc=2, ndoc=2, nval=0, next=-1, group='NONE', - istsym=1, fors='.TRUE.', nprt=0), - mcscf=dict(cistep="GUGA", fullnr=".TRUE.", maxit=200), - gugdia=dict(prttol=0.0, kprint=2, nstate=1, itermx=200), - ecp=self.ecp, - vec=self.vec) - - for key, item in kwargs.items(): - if isinstance(item, dict): - for key2, item2 in item.items(): - calc.parameters[key][key2] = item2 - elif key == "userscr": - calc.userscr = item - else: - calc.parameters[key] = item - - calc.calculate(self.atoms) - - if calc.userscr is None: - raise RuntimeError("USERSCR is not defined") - if not Path(calc.userscr).is_dir(): - raise RuntimeError("USERSCR is not found at: " + calc.userscr) - - copyfile(Path(calc.userscr).joinpath(name + '.dat'), name + '.dat') - - self.vec = '\n'.join(str(subprocess.check_output( - str(self.champ_path.joinpath('tools/interface/getvec.pl')) +\ - ' -t VEC ' + name+ '.dat', - shell=True)).split('\\n')[1:-2]).split(" $END \n $VEC \n")[1] - - os.chdir('..') + kwargs['label'] = self.basename + '_' + label - def setup_ci(self, **kwargs): - """Perform CI setup. - - Args: - kwargs: arguments for GAMESS. - """ - if self.vec is None: - raise ValueError("No vectors.") - - name = self.basename + "_ci" os.chdir('gamess') - # Figure out units - calc = self.gamess(label=name, - contrl=dict(scftyp='NONE', runtyp="ENERGY", mult=1, normf=0, coord="UNIQUE", - units="BOHR", ecp="READ", cityp='GUGA', ICHARG=0), - system=dict(mwords=1500), - basis=dict(extfil=".TRUE.", gbasis='BFD-D'), - guess=dict(guess="MOREAD", norb=28, norder=0, prtmo='.TRUE.'), - cidrt=dict(mxnint=50000, nfzc=2, ndoc=2, nval=0, next=-1, group='NONE', istsym=1, - fors='.TRUE.', nprt=2), - mcscf=dict(cistep="GUGA", fullnr=".TRUE.", maxit=200), - gugdia=dict(prttol=0.0, kprint=2, nstate=1, itermx=200), - ecp=self.ecp, - vec=self.vec) - - for key, item in kwargs.items(): - if isinstance(item, dict): - for key2, item2 in item.items(): - calc.parameters[key][key2] = item2 - elif key == "userscr": - calc.userscr = item - else: - calc.parameters[key] = item + calc = self.gamess(**kwargs) calc.calculate(self.atoms) - if calc.userscr is None: - raise RuntimeError("USERSCR is not defined") - if not Path(calc.userscr).is_dir(): - raise RuntimeError("USERSCR is not found at: " + calc.userscr) - - copyfile(Path(calc.userscr).joinpath(name + '.dat'), name + '.dat') + if self.userscr is None: + self.userscr = calc.userscr os.chdir('..') - def convert_to_champ(self): + def convert_to_champ(self, simname): """Convert GAMESS output to CHAMP input. """ os.chdir('gamess') - name = self.basename + '_ci' + name = self.basename + '_' + simname if not Path(name + ".log").is_file(): - raise ValueError("CI log does not exist. Did you already run GAMESS?") + raise ValueError("Log does not exist. Did you already run GAMESS?") subprocess.run([str(Path(self.champ_path).joinpath("tools/interface/gamess2qmc")), '-d', '0.0', '-r', '-t', 'initial', name + '.log'], check=True) @@ -291,3 +241,77 @@ def create_champ_input(self): jastrow_der="pool/jastrow_der", electrons=Settings.Electrons(nup=nup, nelec=nelec)) return settings + +class Presets: + """Presets for different GAMESS simulations. + """ + class Template(BaseModel, arbitrary_types_allowed=True): + """Template for preset. + """ + userscr: Path = None + + def build(self, champ_loc): + """Build the wavefunction. + + Args: + champ_loc (:obj:`Path`): location of CHAMP base directory. + + Returns: + :obj:`qmcblip.champio.Settings`: CHAMP settings object. + """ + wf = WavefunctionCreator(self.atoms, champ_loc) + label = None + for key, items in self.dict().items(): + if isinstance(items, dict): + wf.run_gamess(label=key, userscr=self.userscr, **items) + label = key + wf.convert_to_champ(label) + return wf.create_champ_input() + class C2(Template): + """Preset for C2 wavefunction. + """ + atoms = Atoms('C2', [(0, 0, -0.7), (0, 0, 0.7)]) + class RHF(BaseModel): + """RHF simulation for C2. + """ + contrl = dict(scftyp='RHF', runtyp="ENERGY", mult=1, normf=1, coord="UNIQUE", + units="BOHR", ecp="READ") + system = dict(timlim=60, memory=1000000) + basis = dict(extfil=".TRUE.", gbasis='BFD-D') + guess = dict(guess="HUCKEL") + ecp = True + + class CAS(BaseModel): + """CAS simulation for C2. + """ + contrl = dict(scftyp='MCSCF', runtyp="ENERGY", mult=1, normf=0, coord="UNIQUE", + units="BOHR", ecp="READ", ICHARG=0) + system = dict(mwords=500) + basis = dict(extfil=".TRUE.", gbasis='BFD-D') + guess = dict(guess="MOREAD", norb=28, norder=1) + drt = dict(mxnint=50000, nmcc=2, ndoc=2, nval=2, next=-1, group='NONE', istsym=1, + fors='.TRUE.', nprt=0) + mcscf=dict(cistep="GUGA", fullnr=".TRUE.", maxit=200) + gugdia=dict(prttol=0.0, kprint=2, nstate=1, itermx=200) + ecp = True + vec = 'rhf' + + class CI(BaseModel): + """CI simulation for C2. + """ + contrl = dict(scftyp='NONE', runtyp="ENERGY", mult=1, normf=0, coord="UNIQUE", + units="BOHR", ecp="READ", cityp='GUGA', ICHARG=0) + system = dict(mwords=500) + basis = dict(extfil=".TRUE.", gbasis='BFD-D') + guess = dict(guess="MOREAD", norb=28, norder=0, prtmo='.TRUE.') + cidrt = dict(mxnint=50000, nfzc=2, ndoc=2, nval=2, next=-1, group='NONE', istsym=1, + fors='.TRUE.', nprt=2) + mcscf = dict(cistep="GUGA", fullnr=".TRUE.", maxit=200) + gugdia = dict(prttol=0.0, kprint=2, nstate=1, itermx=200) + ecp = True + vec = 'cas' + + + rhf: RHF = RHF() + cas: CAS = CAS() + ci: CI = CI() diff --git a/setup.py b/setup.py index a0269bd..38860a9 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name="QMCblip", - version="1.0.5", + version="1.0.6", author="Emiel Slootman", author_email="e.slootman@esciencecenter.nl", description="A small package to couple Quantum Monte Carlo codes to Machine Learning Force Fields through ASE.", diff --git a/tests/gamess/test_gamess.py b/tests/gamess/test_gamess.py index 04c34d7..7f33ec8 100644 --- a/tests/gamess/test_gamess.py +++ b/tests/gamess/test_gamess.py @@ -6,8 +6,7 @@ import pytest from ase import Atoms from qmcblip.champ import CHAMP -from qmcblip.champio import Settings -from qmcblip.gamess.utils import WavefunctionCreator +from qmcblip.gamess.utils import Presets found_champ = pytest.mark.skipif( not Path.home().joinpath(Path('software/champ')).is_dir(), reason="CHAMP not found." @@ -25,35 +24,17 @@ def setUp(self): os.mkdir("tests/test_data/temp") os.chdir('tests/test_data/temp') - @found_gamess - @found_champ - def test_userscrError(self): - atoms = Atoms('C2', [(0,0,-0.61385), (0,0,0.61385)]) - wf = WavefunctionCreator(atoms, str(Path.home().joinpath('software/champ'))) - with self.assertRaises(RuntimeError): - wf.setup_rhf(userscr=None) - os.chdir('..') - with self.assertRaises(FileNotFoundError): - wf.setup_rhf(userscr="not_exist") - os.chdir('..') - - @found_champ @found_gamess def test_gamess(self): - atoms = Atoms('C2', [(0,0,-0.61385), (0,0,0.61385)]) - wf = WavefunctionCreator(atoms, str(Path.home().joinpath('software/champ'))) - wf.setup_rhf(userscr=str(Path.home().joinpath(Path('software/gamess/restart')))) - wf.setup_cas(system=dict(mwords=500), drt=dict(nmcc=2, ndoc=2, nval=2), userscr=str(Path.home().joinpath(Path('software/gamess/restart')))) - wf.setup_ci(system=dict(mwords=500), cidrt=dict(nfzc=2, ndoc=2, nval=2), userscr=str(Path.home().joinpath(Path('software/gamess/restart')))) - wf.convert_to_champ() - input = wf.create_champ_input() + atoms = Presets.C2().atoms + input = Presets.C2(userscr=str(Path.home().joinpath(Path('software/gamess/restart')))).build(str(Path.home().joinpath('software/champ'))) input.optwf.nopt_iter = 10 input.write('vmc.inp') atoms.calc = CHAMP(champ_loc=str(Path.home().joinpath('software/champ'))+"/bin/vmc.mov1", settings = input) energy = atoms.get_total_energy() print(energy) - self.assertEqual(int(energy+297.5), 0) + self.assertEqual(int((energy+297.5)/5), 0) def tearDown(self): os.chdir("../../..")