Skip to content

Commit 03a5d9b

Browse files
Added support for U/R methods and X+C combinations
Unrestricted or restricted calculations can be specified for Gaussian 16 using the "U" or "R" prefix to the method. The pure exchange and correlation functionals can be chosen independently in Gaussian 16.
1 parent 5b509a5 commit 03a5d9b

File tree

6 files changed

+288
-12
lines changed

6 files changed

+288
-12
lines changed

ccinput/calculation.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from ccinput.exceptions import InvalidParameter, InternalError, ImpossibleCalculation, \
55
MissingParameter
6-
from ccinput.utilities import get_abs_software, get_abs_method, get_abs_basis_set, \
6+
from ccinput.utilities import get_abs_software, get_method, get_abs_basis_set, \
77
get_abs_solvent, get_theory_level, standardize_memory, \
88
get_npxyz, get_coord
99
from ccinput.constants import ATOMIC_NUMBER, SYN_SOFTWARE
@@ -98,30 +98,29 @@ def __init__(self, software, solvent="", solvation_model="",
9898
solvation_radii="", basis_set="", method="", specifications="",
9999
density_fitting="", custom_basis_sets="", **kwargs):
100100

101-
if solvent.strip() != "":
102-
self.solvent = get_abs_solvent(solvent)
101+
self.solvent = get_abs_solvent(solvent)
102+
if self.solvent != "":
103103
self.solvation_model = solvation_model.lower()
104104
self.solvation_radii = solvation_radii.lower()
105105

106106
if self.solvation_model.strip() == "":
107-
raise InvalidParameter("No solvation model specified, \
108-
although solvation is requested")
107+
raise InvalidParameter("No solvation model specified," +
108+
"although solvation is requested")
109109
if self.solvation_radii.strip() == "":
110110
warn("No solvation radii specified; using default radii")
111111
else:
112-
self.solvent = ""
113112
self.solvation_model = ""
114113
self.solvation_radii = ""
115114

116115
self.software = get_abs_software(software)
117116

118117
if method == "":
119118
if 'functional' in kwargs:
120-
method = get_abs_method(kwargs['functional'])
119+
method = get_method(kwargs['functional'], self.software)
121120
else:
122121
raise InvalidParameter("No calculation method specified (method='...')")
123122
else:
124-
self.method = get_abs_method(method)
123+
self.method = get_method(method, self.software)
125124

126125
self.theory_level = get_theory_level(method)
127126

ccinput/constants.py

+40
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,46 @@ class CalcType(Enum):
512512
'dlpno-qcisd(t)': ['dlpno-qcisdt', 'dlpnoqcisdt'],
513513
}
514514

515+
516+
517+
# Gaussian allows the combination of exchange and correlation functionals
518+
# without using any special keyword.
519+
520+
EXCHANGE_FUNCTIONALS = {
521+
's': 'S',
522+
'xa': 'XA',
523+
'b': 'B',
524+
'pw91': 'PW91',
525+
'mpw': 'mPW',
526+
'g96': 'G96',
527+
'pbe': 'PBE',
528+
'o': 'O',
529+
'tpss': 'TPSS',
530+
'revtpss': 'RevTPSS',
531+
'brx': 'BRx',
532+
'pkzb': 'PKZB',
533+
'wpbeh': 'wPBEh',
534+
'pbeh': 'PBEh',
535+
}
536+
537+
CORRELATION_FUNCTIONALS = {
538+
'vwn': 'VWN',
539+
'vwn5': 'VWN5',
540+
'lyp': 'LYP',
541+
'pl': 'PL',
542+
'p86': 'P86',
543+
'pw91': 'PW91',
544+
'b95': 'B95',
545+
'pbe': 'PBE',
546+
'tpss': 'TPSS',
547+
'revtpss': 'RevTPSS',
548+
'kcis': 'KCIS',
549+
'brc': 'BRC',
550+
'pkzb': 'PKZB',
551+
'vp86': 'VP86',
552+
'v5lyp': 'V5LYP',
553+
}
554+
515555
SYN_BASIS_SETS = {
516556
'sto-3g': [],
517557

ccinput/packages/orca.py

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def __init__(self, calc):
5151

5252
self.create_input_file()
5353

54+
@property
55+
def confirmed_specifications(self):
56+
""" Returns the effective additional commands; saved in the Parameters object """
57+
return self.additional_commands
58+
5459
def clean(self, s):
5560
WHITELIST = set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/()=-,. ")
5661
return ''.join([c for c in s if c in WHITELIST])

ccinput/tests/test_gaussian.py

+204-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
class GaussianTests(InputTests):
44

55
def test_sp_SE(self):
6-
params = {
7-
'nproc': 8,
6+
params = { 'nproc': 8,
87
'mem': '10000MB',
98
'type': 'Single-Point Energy',
109
'in_file': 'Cl.xyz',
@@ -2331,3 +2330,206 @@ def test_mem_GB(self):
23312330

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

2333+
def test_exchange_correlation_functional(self):
2334+
params = {
2335+
'nproc': 8,
2336+
'mem': '10GB',
2337+
'type': 'Single-Point Energy',
2338+
'in_file': 'Cl.xyz',
2339+
'software': 'Gaussian',
2340+
'method': 'pkzbpkzb',
2341+
'basis_set': '3-21G',
2342+
'charge': '-1',
2343+
}
2344+
2345+
inp = self.generate_calculation(**params)
2346+
2347+
REF = """
2348+
%chk=calc.chk
2349+
%nproc=8
2350+
%mem=10000MB
2351+
#p sp PKZBPKZB/3-21G
2352+
2353+
File created by ccinput
2354+
2355+
-1 1
2356+
Cl 0.0 0.0 0.0
2357+
2358+
"""
2359+
2360+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2361+
2362+
def test_exchange_correlation_functional2(self):
2363+
params = {
2364+
'nproc': 8,
2365+
'mem': '10GB',
2366+
'type': 'Single-Point Energy',
2367+
'in_file': 'Cl.xyz',
2368+
'software': 'Gaussian',
2369+
'method': 'pBeHpkzb',
2370+
'basis_set': '3-21G',
2371+
'charge': '-1',
2372+
}
2373+
2374+
inp = self.generate_calculation(**params)
2375+
2376+
REF = """
2377+
%chk=calc.chk
2378+
%nproc=8
2379+
%mem=10000MB
2380+
#p sp PBEhPKZB/3-21G
2381+
2382+
File created by ccinput
2383+
2384+
-1 1
2385+
Cl 0.0 0.0 0.0
2386+
2387+
"""
2388+
2389+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2390+
2391+
def test_restricted_HF(self):
2392+
params = {
2393+
'nproc': 8,
2394+
'mem': '10GB',
2395+
'type': 'Single-Point Energy',
2396+
'in_file': 'Cl.xyz',
2397+
'software': 'Gaussian',
2398+
'method': 'rHF',
2399+
'basis_set': '3-21G',
2400+
'charge': '-1',
2401+
}
2402+
2403+
inp = self.generate_calculation(**params)
2404+
2405+
REF = """
2406+
%chk=calc.chk
2407+
%nproc=8
2408+
%mem=10000MB
2409+
#p sp RHF/3-21G
2410+
2411+
File created by ccinput
2412+
2413+
-1 1
2414+
Cl 0.0 0.0 0.0
2415+
2416+
"""
2417+
2418+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2419+
2420+
def test_unrestricted_HF(self):
2421+
params = {
2422+
'nproc': 8,
2423+
'mem': '10GB',
2424+
'type': 'Single-Point Energy',
2425+
'in_file': 'Cl.xyz',
2426+
'software': 'Gaussian',
2427+
'method': 'uHF',
2428+
'basis_set': '3-21G',
2429+
'charge': '-1',
2430+
}
2431+
2432+
inp = self.generate_calculation(**params)
2433+
2434+
REF = """
2435+
%chk=calc.chk
2436+
%nproc=8
2437+
%mem=10000MB
2438+
#p sp UHF/3-21G
2439+
2440+
File created by ccinput
2441+
2442+
-1 1
2443+
Cl 0.0 0.0 0.0
2444+
2445+
"""
2446+
2447+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2448+
2449+
def test_unknown_HF(self):
2450+
params = {
2451+
'nproc': 8,
2452+
'mem': '10GB',
2453+
'type': 'Single-Point Energy',
2454+
'in_file': 'Cl.xyz',
2455+
'software': 'Gaussian',
2456+
'method': 'iHF',
2457+
'basis_set': '3-21G',
2458+
'charge': '-1',
2459+
}
2460+
2461+
inp = self.generate_calculation(**params)
2462+
2463+
REF = """
2464+
%chk=calc.chk
2465+
%nproc=8
2466+
%mem=10000MB
2467+
#p sp iHF/3-21G
2468+
2469+
File created by ccinput
2470+
2471+
-1 1
2472+
Cl 0.0 0.0 0.0
2473+
2474+
"""
2475+
2476+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2477+
2478+
def test_unrestricted_DFT(self):
2479+
params = {
2480+
'nproc': 8,
2481+
'mem': '10GB',
2482+
'type': 'Single-Point Energy',
2483+
'in_file': 'Cl.xyz',
2484+
'software': 'Gaussian',
2485+
'method': 'uM062x',
2486+
'basis_set': '3-21G',
2487+
'charge': '-1',
2488+
}
2489+
2490+
inp = self.generate_calculation(**params)
2491+
2492+
REF = """
2493+
%chk=calc.chk
2494+
%nproc=8
2495+
%mem=10000MB
2496+
#p sp UM062X/3-21G
2497+
2498+
File created by ccinput
2499+
2500+
-1 1
2501+
Cl 0.0 0.0 0.0
2502+
2503+
"""
2504+
2505+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2506+
2507+
def test_restricted_DFT(self):
2508+
params = {
2509+
'nproc': 8,
2510+
'mem': '10GB',
2511+
'type': 'Single-Point Energy',
2512+
'in_file': 'Cl.xyz',
2513+
'software': 'Gaussian',
2514+
'method': 'rPBE0',
2515+
'basis_set': '3-21G',
2516+
'charge': '-1',
2517+
}
2518+
2519+
inp = self.generate_calculation(**params)
2520+
2521+
REF = """
2522+
%chk=calc.chk
2523+
%nproc=8
2524+
%mem=10000MB
2525+
#p sp RPBE1PBE/3-21G
2526+
2527+
File created by ccinput
2528+
2529+
-1 1
2530+
Cl 0.0 0.0 0.0
2531+
2532+
"""
2533+
2534+
self.assertTrue(self.is_equivalent(REF, inp.input_file))
2535+

ccinput/tests/test_orca.py

-1
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,6 @@ def test_hirshfeld_pop(self):
12821282
}
12831283

12841284
inp = self.generate_calculation(**params)
1285-
12861285
REF = """
12871286
!SP M062X Def2-SVP
12881287
*xyz -1 1

ccinput/utilities.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -191,19 +191,50 @@ def get_abs_basis_set(basis_set):
191191

192192
def get_abs_solvent(solvent):
193193
_solvent = solvent.strip().lower()
194+
if _solvent in ["", "vacuum", "vac"]:
195+
return ""
194196
for solv in SYN_SOLVENTS:
195197
if _solvent in SYN_SOLVENTS[solv] or _solvent == solv:
196198
return solv
197199
raise InvalidParameter(f"Unknown solvent: '{solvent}'")
198200

201+
def is_exchange_correlation_combination(method):
202+
for x in EXCHANGE_FUNCTIONALS:
203+
if method[:len(x)] == x:
204+
if method[len(x):] in CORRELATION_FUNCTIONALS:
205+
return EXCHANGE_FUNCTIONALS[method[:len(x)]] + \
206+
CORRELATION_FUNCTIONALS[method[len(x):]]
207+
return False
208+
199209
def get_method(method, software):
200210
try:
201211
abs_method = get_abs_method(method)
202212
except InvalidParameter:
213+
if software == 'gaussian':
214+
# As far as I know, this kind of specification does not apply to ORCA
215+
if method.lower()[0] in ['u', 'r']:
216+
try:
217+
abs_method = get_abs_method(method[1:])
218+
except InvalidParameter:
219+
pass
220+
else:
221+
if abs_method not in SOFTWARE_METHODS[software]:
222+
warn(f"Unknown method '{method}'")
223+
return method
224+
225+
return method[0].upper() + SOFTWARE_METHODS[software][abs_method]
226+
227+
xc_check = is_exchange_correlation_combination(method.lower())
228+
if isinstance(xc_check, str):
229+
return xc_check
203230
warn(f"Unknown method '{method}'")
204231
return method
232+
else:
233+
if abs_method not in SOFTWARE_METHODS[software]:
234+
warn(f"Unknown method '{method}'")
235+
return method
205236

206-
return SOFTWARE_METHODS[software][abs_method]
237+
return SOFTWARE_METHODS[software][abs_method]
207238

208239
def get_basis_set(basis_set, software):
209240
try:

0 commit comments

Comments
 (0)