Skip to content

Commit

Permalink
Merge pull request #9 from lauragranmar/psi4
Browse files Browse the repository at this point in the history
Added basic support for psi4
  • Loading branch information
RaphaelRobidas committed Apr 17, 2023
2 parents 5e18f47 + 874d43f commit d5a5506
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 2 deletions.
19 changes: 17 additions & 2 deletions ccinput/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class CalcType(Enum):
"singlepoint",
"singlepointenergy",
"energy",
"scf",
],
CalcType.OPT: [
"Geometrical Optimisation",
Expand Down Expand Up @@ -166,6 +165,7 @@ class CalcType(Enum):
"orca": ["orca5"],
"qchem": [],
"xtb": [],
"psi4":["psi4"]
}

SYN_SOLVENTS = {
Expand Down Expand Up @@ -463,7 +463,7 @@ class CalcType(Enum):
"hcth93": [],
"hcth147": [],
"thcth": [],
"hf": ["hartreefock"],
"hf": ["hartreefock", "scf"],
"mndo": [],
"am1": [],
"pm3": [],
Expand Down Expand Up @@ -1608,6 +1608,15 @@ class CalcType(Enum):
"gfnff": "gfn-ff",
"gfn2xtbgfnff": "gfn2-xtb//gfn-ff",
},
"psi4": {
"hf": "scf",
"blyp": "blyp",
"b3lyp": "b3lyp",
"pbe": "pbe",
"pw91": "pw91",
"revpbe": "revpbe",
"rpbe": "rpbe",
},
}

SOFTWARE_BASIS_SETS = {
Expand Down Expand Up @@ -2045,6 +2054,12 @@ class CalcType(Enum):
"def2svp": "def2-svp",
"def2tzvp": "def2-tzvp",
},
"psi4": {
"sto3g": "sto-3g",
"631g": "6-31G",
"ccpvdz": "cc-pVDZ",
"def2tzvp": "def2-tzvp"
}
}

SOFTWARE_SOLVENTS = {
Expand Down
125 changes: 125 additions & 0 deletions ccinput/packages/psi4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import basis_set_exchange
import numpy as np

from ccinput.utilities import (
get_method,
get_solvent,
get_basis_set,
clean_xyz,
get_distance,
get_angle,
get_dihedral,
get_npxyz,
)
from ccinput.calculation import Calculation
from ccinput.constants import CalcType, ATOMIC_NUMBER, LOWERCASE_ATOMIC_SYMBOLS
from ccinput.exceptions import UnimplementedError


class Psi4Calculation:
TEMPLATE = """
molecule {{
{charge} {multiplicity}
{coordinates}
}}
{command_line}
"""

CALC_TYPES = {
CalcType.SP: ["sp","energy"],
CalcType.OPT: ["optimize"],
# CalcType.CONSTR_OPT,
# CalcType.FREQ,
# CalcType.TS,
# CalcType.OPTFREQ,
}

def __init__(self, calc: Calculation):
self.calc = calc
self.has_scan = False
self.appendix = []
self.command_line = ""

self.commands = {}
self.solvation_radii = {}

self.confirmed_specifications = ""
self.xyz_structure = ""
self.input_file = ""

if self.calc.type not in self.CALC_TYPES:
raise UnimplementedError(f"Calculation Type {self.calc.type} not implemented yet for psi4"
)
self.type_method = ""

self.handle_specifications()
self.handle_command()
self.handle_xyz()

self.handle_solvation()



self.create_input_file()

def clean(self, s):
WHITELIST = set(
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/()=-,. "
)
return "".join([c for c in s if c in WHITELIST])

def add_option(self, key, option):
_option = option.strip()
if key in self.commands:
if _option not in self.commands[key]:
self.commands[key].append(_option)
else:
self.commands[key] = [_option]

def add_options(self, key, options):
for option in options:
self.add_option(key, option)

def handle_specifications(self):
return

def handle_command(self):
#method label, can be used to specifyiing xc func or the level of theory.
method = get_method(self.calc.parameters.method,'psi4')

basis_set = get_basis_set(self.calc.parameters.basis_set, 'psi4')

if self.calc.type == CalcType.SP:
self.command_line += f"energy('{method}/{basis_set}')"
elif self.calc.type == CalcType.OPT:
self.command_line += f"optimize('{method}/{basis_set}')"
else:
raise UnimplementedError(f"Calculation Type {self.calc.type} not implemented yet for psi4")



def handle_xyz(self):
lines = [i + "\n" for i in clean_xyz(self.calc.xyz).split("\n") if i != ""]
self.xyz_structure = "".join(lines)

def handle_solvation(self):
return




def create_input_file(self) -> None:
self.input_file = self.TEMPLATE.format(
charge= self.calc.charge,
multiplicity = self.calc.multiplicity,
coordinates = self.xyz_structure,
command_line = self.command_line
)
return



@property
def output(self):
return self.input_file
128 changes: 128 additions & 0 deletions ccinput/tests/test_psi4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from ccinput.tests.testing_utilities import InputTests
from ccinput.exceptions import InvalidParameter, ImpossibleCalculation


class Psi4Tests(InputTests):
# def test_sp_SE(self):
# params = {

# }


# inp = self.generate_calculation(**params)

# REF = """

# """

# self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_sp_HF(self):
params = {
"type": "Energy",
"file": "Cl.xyz",
"software": "psi4",
"method": "hf",
"basis_set": "sto3g",
"charge": "-1",
"multiplicity" : "1",
}
inp = self.generate_calculation(**params)

REF = """
molecule {
-1 1
Cl 0.00000000 0.00000000 0.00000000
}
energy('scf/sto-3g')
"""

self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_sp_DFT(self):
params = {
"type": "Energy",
"file": "Cl.xyz",
"software": "psi4",
"method": "b3lyp",
"basis_set": "def2-tzvp",
"charge": "-1",
"multiplicity" : "1",
}

inp = self.generate_calculation(**params)

REF = """
molecule {
-1 1
Cl 0.00000000 0.00000000 0.00000000
}
energy('b3lyp/def2-tzvp')
"""
self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_opt_HF(self):
params = {
"type": "Geometrical Optimisation",
"file": "Cl.xyz",
"software": "psi4",
"method": "HF",
"basis_set": "ccpVDZ",
"charge": "-1",
"multiplicity" : "1",
}

inp = self.generate_calculation(**params)

REF = """
molecule {
-1 1
Cl 0.00000000 0.00000000 0.00000000
}
optimize('scf/cc-pVDZ')
"""

self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_opt_DFT(self):
params = {
"type": "Opt",
"file": "Cl.xyz",
"software": "psi4",
"method": "b3lyp",
"basis_set": "631g",
"charge": "-1",
}

inp = self.generate_calculation(**params)

REF = """
molecule {
-1 1
Cl 0.00000000 0.00000000 0.00000000
}
optimize('b3lyp/6-31G')
"""

self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_unavailable_calc_type(self):
params = {
"type": "freq",
"file": "Cl.xyz",
"software": "psi4",
"method": "HF",
"basis_set": "cc-pvdz",
"charge": "-1",
}

self.assertRaises(ImpossibleCalculation, msg=f"Calculation Type of {params['type']} not implemented yet for psi4")

2 changes: 2 additions & 0 deletions ccinput/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ccinput.packages.qchem import QChemCalculation
from ccinput.packages.xtb import XtbCalculation
from ccinput.drivers.pysis import PysisDriver
from ccinput.packages.psi4 import Psi4Calculation

from ccinput.calculation import (
Calculation,
Expand Down Expand Up @@ -42,6 +43,7 @@
"pysis": PysisDriver,
"pysisyphus": PysisDriver,
"qchem": QChemCalculation,
"psi4": Psi4Calculation,
}


Expand Down

0 comments on commit d5a5506

Please sign in to comment.