Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from cyllab:main #44

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 75 additions & 89 deletions ccinput/packages/nwchem.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
get_basis_set,
clean_xyz,
warn,
parse_specifications,
)
from ccinput.constants import (
CalcType,
Expand Down Expand Up @@ -246,96 +247,81 @@ def parse_custom_basis_set(self, base_bs):
self.basis_set += "\n".join(to_append_ecp)
self.basis_set += " end"

def handle_specifications(self):
if self.clean(self.calc.parameters.specifications).strip() != "":
temp = "\n" # Here we will store frequency related specifiations in case of FREQOPT calculations
s = self.separate_lines(self.calc.parameters.specifications)
# Could be more sophisticated to catch other incorrect specifications
if s.count("(") != s.count(")"):
raise InvalidParameter(
"Invalid specifications: parenthesis not matching"
def add_option(self, key, option):
temp = "\n" # Here we will store frequency related specifications in case of FREQOPT calculation
if option == "":
# To make a difference between NEB (default MEP method) and freezing string method,
# User has to put some of the following keyword as specification, independant of what calculation was specified in input
if key in [
"string",
"freezing string sethod",
"fsm",
"freezing string",
]:
self.tasks = self.tasks.replace("neb", "string")
else:
self.additional_block += f"{key} \n"
else:
"""
command = matched.group(1)
if command.find(",") != -1:
command = command.replace(",", "\n").strip()
"""
command = option.replace("=", " ")
block_name = key # spec[: matched.span(1)[0] - 1]
if block_name == "scf" or block_name == "dft" or block_name == "hf":
if command == "adft" and self.calc.parameters.density_fitting == "":
raise InvalidParameter("adft keyword requires auxilary basis set")
self.method_block += f"{command} \n"
elif (block_name == "opt" or block_name == "ts") and (
self.calc.type
in [
CalcType.CONSTR_OPT,
CalcType.OPT,
CalcType.TS,
CalcType.OPTFREQ,
]
):
if self.calculation_block == "":
self.calculation_block += f"\n driver \n"
self.calculation_block += f"{command} \n"
elif block_name == "nmr" and self.calc.type == CalcType.NMR:
self.calculation_block += f"{command} \n"
elif block_name == "freq" and self.calc.type == CalcType.FREQ:
if self.calculation_block == "":
self.calculation_block += f"\n freq \n"
self.calculation_block += f"{command} \n"
elif block_name == "freq" and self.calc.type == CalcType.OPTFREQ:
temp += f"{command} \n"
elif (
block_name in ["neb", "string", "fsm", "mep"]
and self.calc.type == CalcType.MEP
):
if self.calculation_block == "":
self.calculation_block += f"\n neb \n"
self.calculation_block += f"{command} \n"
elif block_name == "sol" or block_name == "cosmo" or block_name == "smd":
self.additional_block = self.additional_block.replace(
"cosmo \n", f"cosmo \n {command} \n"
)
for spec in s.split("\n"):
# format of the specifications is BLOCK_NAME1(command1);BLOCK_NAME2(command2);...
matched = re.search(r".*\((.*)\)", spec)
if matched == None:
# To make a difference between neb(defualt mep method) and freezing string method
# User has to put some of the following keyword as specification, independant of what calculation was specified in input
if spec in [
"string",
"freezing string sethod",
"fsm",
"freezing string",
]:
self.tasks = self.tasks.replace("neb", "string")
else:
self.additional_block += f"{spec} \n"
else:
command = matched.group(1)
if command.find(",") != -1:
command = command.replace(",", "\n").strip()
block_name = spec[: matched.span(1)[0] - 1]
if block_name == "scf" or block_name == "dft" or block_name == "hf":
if (
command == "adft"
and self.calc.parameters.density_fitting == ""
):
raise InvalidParameter(
"adft keyword requires auxilary basis set"
)
self.method_block += f"{command} \n"
elif (block_name == "opt" or block_name == "ts") and (
self.calc.type
in [
CalcType.CONSTR_OPT,
CalcType.OPT,
CalcType.TS,
CalcType.OPTFREQ,
]
):
if self.calculation_block == "":
self.calculation_block += f"\n driver \n"
self.calculation_block += f"{command} \n"
elif block_name == "nmr" and self.calc.type == CalcType.NMR:
self.calculation_block += f"{command} \n"
elif block_name == "freq" and self.calc.type == CalcType.FREQ:
if self.calculation_block == "":
self.calculation_block += f"\n freq \n"
self.calculation_block += f"{command} \n"
elif block_name == "freq" and self.calc.type == CalcType.OPTFREQ:
temp += f"{command} \n"
elif (
block_name in ["neb", "string", "fsm", "mep"]
and self.calc.type == CalcType.MEP
):
if self.calculation_block == "":
self.calculation_block += f"\n neb \n"
self.calculation_block += f"{command} \n"
elif (
block_name == "sol"
or block_name == "cosmo"
or block_name == "smd"
):
self.additional_block = self.additional_block.replace(
"cosmo \n", f"cosmo \n {command} \n"
)
elif (
block_name == "mp2"
and self.calc.parameters.theory_level == "mp2"
):
self.method_block += f"{command} \n"
elif (
block_name == "cc"
and self.calc.parameters.theory_level == "ccsd"
):
self.method_block += f"{command} \n"
elif (
block_name in ["mcscf", "casscf"]
and self.calc.type == CalcType.SP
):
self.method_block += f"{command} \n"
if temp != "\n":
self.additional_block += f"\n freq {temp} end \n"
elif block_name == "mp2" and self.calc.parameters.theory_level == "mp2":
self.method_block += f"{command} \n"
elif block_name == "cc" and self.calc.parameters.theory_level == "ccsd":
self.method_block += f"{command} \n"
elif block_name in ["mcscf", "casscf"] and self.calc.type == CalcType.SP:
self.method_block += f"{command} \n"

if temp != "\n":
self.additional_block += f"\n freq {temp} end \n"

def handle_specifications(self):
clean_specs = self.clean(
self.calc.parameters.specifications.replace(";", " ")
).strip()

if clean_specs != "":
parse_specifications(clean_specs, self.add_option, condense=False)

if self.tasks.find("string") != -1:
self.calculation_block = self.calculation_block.replace("neb", "string")
# Check if there are necessary specifications for mcscf calculation:
Expand Down
21 changes: 0 additions & 21 deletions ccinput/packages/orca.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,6 @@ def handle_specifications(self):

parse_specifications(_specifications, self.add_option, condense=False)

"""
if _specifications != "":
sspecs = _specifications.split()
ind = 0
while ind < len(sspecs):
spec = sspecs[ind]
if spec == "--phirshfeld":
self.add_to_block("output", ["Print[ P_Hirshfeld] 1"])
elif spec == "--nimages":
nimages = sspecs[ind + 1]
try:
nimages = int(nimages)
except ValueError:
raise InvalidParameter("Invalid specifications")
self.specifications["nimages"] = nimages
ind += 1


ind += 1
"""

if self.calc.parameters.d3:
self.specifications_list.append("d3zero")
elif self.calc.parameters.d3bj:
Expand Down
108 changes: 108 additions & 0 deletions ccinput/tests/test_nwchem.py
Original file line number Diff line number Diff line change
Expand Up @@ -2616,6 +2616,114 @@ def test_specifications_alternative2(self):

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

def test_specifications_alternative3(self):
params = {
"nproc": 8,
"mem": "10000MB",
"type": "Geometrical Optimisation",
"file": "ethanol.xyz",
"software": "nwchem",
"method": "M06-2X",
"basis_set": "Def2-SVP",
"charge": "0",
"specifications": "SCF(Tight); opt(maxiter=5) scf(direct)",
}

inp = self.generate_calculation(**params)

REF = """
TITLE "File created by ccinput"
start ethanol
memory total 1250 mb
charge 0

geometry units angstroms noautosym
C -1.31970000 -0.64380000 0.00000000
H -0.96310000 -1.65260000 0.00000000
H -0.96310000 -0.13940000 -0.87370000
H -2.38970000 -0.64380000 0.00000000
C -0.80640000 0.08220000 1.25740000
H -1.16150000 1.09160000 1.25640000
H -1.16470000 -0.42110000 2.13110000
O 0.62360000 0.07990000 1.25870000
H 0.94410000 0.53240000 2.04240000
end

basis
* library Def2-SVP
end

dft
xc m06-2x
mult 1
tight
direct
end

driver
maxiter 5
end

task dft optimize
"""

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

def test_specifications_alternative4(self):
params = {
"nproc": 8,
"mem": "10000MB",
"type": "Geometrical Optimisation",
"file": "ethanol.xyz",
"software": "nwchem",
"method": "M06-2X",
"basis_set": "Def2-SVP",
"charge": "0",
"specifications": "SCF(Tight, direct); opt(maxITer=5, truST=0.2, convggm 5.0d-04)",
}

inp = self.generate_calculation(**params)

REF = """
TITLE "File created by ccinput"
start ethanol
memory total 1250 mb
charge 0

geometry units angstroms noautosym
C -1.31970000 -0.64380000 0.00000000
H -0.96310000 -1.65260000 0.00000000
H -0.96310000 -0.13940000 -0.87370000
H -2.38970000 -0.64380000 0.00000000
C -0.80640000 0.08220000 1.25740000
H -1.16150000 1.09160000 1.25640000
H -1.16470000 -0.42110000 2.13110000
O 0.62360000 0.07990000 1.25870000
H 0.94410000 0.53240000 2.04240000
end

basis
* library Def2-SVP
end

dft
xc m06-2x
mult 1
tight
direct
end

driver
maxiter 5
trust 0.2
convggm 5.0d-04
end

task dft optimize
"""

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

def test_specifications_mixed(self):
params = {
"nproc": 8,
Expand Down
39 changes: 39 additions & 0 deletions ccinput/tests/test_orca.py
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,45 @@ def test_NEB2(self):
"""
self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_NEB3(self):
params = {
"nproc": 8,
"type": "Minimum Energy Path",
"file": "elimination_substrate.xyz",
"auxiliary_file": "elimination_product.xyz",
"software": "ORCA",
"specifications": "neb(nimages=12,printlevel=2)",
"charge": -1,
"method": "gfn2-xtb",
}

inp = self.generate_calculation(**params)

REF = """!NEB xtb2
*xyz -1 1
C -0.74277 0.14309 0.12635
C 0.71308 -0.12855 -0.16358
Cl 0.90703 -0.47793 -1.61303
H -0.84928 0.38704 1.20767
H -1.36298 -0.72675 -0.06978
H -1.11617 0.99405 -0.43583
H 1.06397 -0.95639 0.44985
H 1.30839 0.75217 0.07028
O -0.91651 0.74066 3.00993
H -1.82448 0.94856 3.28105
*
%neb
nimages 12
printlevel 2
product "calc2.xyz"
end
%pal
nprocs 8
end
%MaxCore 125
"""
self.assertTrue(self.is_equivalent(REF, inp.input_file))

def test_NEB_aux_name(self):
params = {
"nproc": 8,
Expand Down
2 changes: 1 addition & 1 deletion ccinput/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def parse_specifications(specs, add_option_fn, condense=True):
elif c == ")":
remove = False

for spec in _specifications.split(" "):
for spec in _specifications.lower().split(" "):
if spec.strip() == "":
continue
if spec.find("(") != -1:
Expand Down
Loading
Loading