Skip to content

Commit bc6b9dd

Browse files
authored
Modified MRCI implementation in Molpro and Orca adapters (#746)
Also changed input file memory to be total instead of per CUP Added test Currently testing on the server, do not merge, but comments are welcomed
2 parents 5e8a8e7 + fa70e65 commit bc6b9dd

File tree

25 files changed

+4629
-193
lines changed

25 files changed

+4629
-193
lines changed

arc/job/adapters/molpro.py

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
import math
99
import os
1010
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
11-
import socket
1211

1312
from mako.template import Template
1413

1514
from arc.common import get_logger
16-
from arc.exceptions import JobError
1715
from arc.imports import incore_commands, settings
1816
from arc.job.adapter import JobAdapter
1917
from arc.job.adapters.common import (_initialize_adapter,
@@ -37,7 +35,7 @@
3735
settings['output_filenames'], settings['servers'], settings['submit_filenames']
3836

3937
input_template = """***,${label}
40-
memory,${memory},m;
38+
memory,Total=${memory},m;
4139
4240
geometry={angstrom;
4341
${xyz}}
@@ -47,11 +45,13 @@
4745
${auxiliary_basis}
4846
${cabs}
4947
int;
48+
5049
{hf;${shift}
51-
maxit,1000;
52-
wf,spin=${spin},charge=${charge};}
50+
maxit,999;
51+
wf,spin=${spin},charge=${charge};
52+
}
5353
54-
${restricted}${method};
54+
${restricted}${method}
5555
5656
${job_type_1}
5757
${job_type_2}${block}
@@ -213,7 +213,6 @@ def write_input_file(self) -> None:
213213
'keywords',
214214
'memory',
215215
'method',
216-
'orbitals',
217216
'restricted',
218217
]:
219218
input_dict[key] = ''
@@ -224,10 +223,11 @@ def write_input_file(self) -> None:
224223
input_dict['charge'] = self.charge
225224
input_dict['label'] = self.species_label
226225
input_dict['memory'] = self.input_file_memory
227-
input_dict['method'] = self.level.method
226+
input_dict['method'] = f'{self.level.method};'
228227
input_dict['shift'] = self.args['trsh']['shift'] if 'shift' in self.args['trsh'].keys() else ''
229228
input_dict['spin'] = self.multiplicity - 1
230229
input_dict['xyz'] = xyz_to_str(self.xyz)
230+
input_dict['orbitals'] = '\ngprint,orbitals;\n'
231231

232232
if not is_restricted(self):
233233
input_dict['restricted'] = 'u'
@@ -249,23 +249,44 @@ def write_input_file(self) -> None:
249249
pass
250250

251251
if 'IGNORE_ERROR in the ORBITAL directive' in self.args['trsh'].keys():
252-
keywords.append('ORBITAL,IGNORE_ERROR')
253-
254-
if 'mrci' in self.level.method:
255-
if self.species[0].occ > 16:
256-
raise JobError(f'Will not execute an MRCI calculation with more than 16 occupied orbitals '
257-
f'(got {self.species[0].occ}).\n'
258-
f'Selective occ, closed, core, frozen keyword still not implemented.')
259-
input_dict['orbitals'] = '\ngprint,orbitals;\n'
260-
input_dict['block'] += '\n\nE_mrci=energy;\nE_mrci_Davidson=energd;\n\ntable,E_mrci,E_mrci_Davidson;'
261-
input_dict['method'] = input_dict['rerstricted'] = ''
262-
input_dict['shift'] = 'shift,-1.0,-0.5;'
263-
input_dict['job_type_1'] = f"""{{multi;
264-
{self.species[0].occ}noextra,failsafe,config,csf;
265-
wf,spin={input_dict['spin']},charge={input_dict['charge']};
266-
natorb,print,ci;}}"""
267-
input_dict['job_type_2'] = f"""{{mrci;
268-
${self.species[0].occ}wf,spin=${input_dict['spin']},charge=${input_dict['charge']};}}"""
252+
keywords.append(' ORBITAL,IGNORE_ERROR;')
253+
254+
if 'mrci' in self.level.method or 'rs2' in self.level.method:
255+
active = self.species[0].active
256+
input_dict['restricted'] = ''
257+
if '_' in self.level.method:
258+
methods = self.level.method.split('_')
259+
input_dict['method'] = ''
260+
for method in methods:
261+
input_dict['method'] += '\n{' + method.lower() + ';\n'
262+
if 'mp2' not in method.lower():
263+
input_dict['method'] += ' maxit,999;\n'
264+
input_dict['method'] += f' wf,spin={input_dict["spin"]},charge={input_dict["charge"]};\n'
265+
if 'casscf' in method.lower() and active is not None:
266+
if 'occ' in active:
267+
input_dict['method'] += f' occ,{",".join([str(i) for i in active["occ"]])};\n'
268+
if 'closed' in active:
269+
input_dict['method'] += f' closed,{",".join([str(i) for i in active["closed"]])};\n'
270+
input_dict['method'] += ' state,1;\n' # ground state
271+
input_dict['method'] += '}\n'
272+
else:
273+
input_dict['method'] = f"""{{casscf;
274+
maxit,999;
275+
wf,spin={input_dict['spin']},charge={input_dict['charge']};
276+
"""
277+
if active is not None:
278+
if 'occ' in active:
279+
input_dict['method'] += f' occ,{",".join([str(i) for i in active["occ"]])};\n'
280+
if 'closed' in active:
281+
input_dict['method'] += f' closed,{",".join([str(i) for i in active["closed"]])};\n'
282+
input_dict['method'] += ' state,1;\n' # ground state
283+
input_dict['method'] += '}\n\n'
284+
input_dict['method'] += f"""{{mrci{"-f12" if "f12" in self.level.method.lower() else ""};
285+
maxit,999;
286+
wf,spin={input_dict['spin']},charge={input_dict['charge']};
287+
}}"""
288+
if 'mrci' in self.level.method:
289+
input_dict['block'] += '\n\nE_mrci=energy;\nE_mrci_Davidson=energd;\n\ntable,E_mrci,E_mrci_Davidson;'
269290

270291
input_dict = update_input_dict_with_args(args=self.args, input_dict=input_dict)
271292

@@ -325,19 +346,12 @@ def set_input_file_memory(self) -> None:
325346
"""
326347
Set the input_file_memory attribute.
327348
"""
328-
# Molpro's memory is per cpu core and in MW (mega word; 1000 MW = 7.45 GB on a 64-bit machine)
329-
# The conversion from mW to GB was done using this (https://deviceanalytics.com/words-to-bytes-converter/)
330-
# specifying a 64-bit architecture.
331-
#
332-
# See also:
333-
# https://www.molpro.net/pipermail/molpro-user/2010-April/003723.html
334-
# In the link, they describe the conversion of 100,000,000 Words (100Mword) is equivalent to
335-
# 800,000,000 bytes (800 mb).
336-
# Formula - (100,000,000 [Words]/( 800,000,000 [Bytes] / (job mem in gb * 1000,000,000 [Bytes])))/ 1000,000 [Words -> MegaWords]
337-
# The division by 1E6 is for converting into MWords
338-
# Due to Zeus's configuration, there is only 1 nproc so the memory should not be divided by cpu_cores.
339-
self.input_file_memory = math.ceil(self.job_memory_gb / (7.45e-3 * self.cpu_cores)) if 'zeus' not in socket.gethostname() else math.ceil(self.job_memory_gb / (7.45e-3))
340-
349+
# Molpro's memory is per cpu core, but here we ask for Total memory.
350+
# Molpro measures memory in MW (mega word; 1000 MW = 7.45 GB on a 64-bit machine)
351+
# The conversion from mW to GB was done using https://www.molpro.net/manual/doku.php?id=general_program_structure#memory_option_in_command_line
352+
# 3.2 GB = 100 mw (case sensitive) total (as in this implimentation) -> 31.25 mw/GB is the conversion rate
353+
self.input_file_memory = math.ceil(self.job_memory_gb * 31.25)
354+
341355
def execute_incore(self):
342356
"""
343357
Execute a job incore.

0 commit comments

Comments
 (0)