Skip to content

Commit

Permalink
Molpro Mem/CPU Change Tests
Browse files Browse the repository at this point in the history
Molpro Memory Set Update

Will now limit the memory of Molpro to what is req. by Molpro if the CPU is set 1 core.

Fixed local var min_mem_value
  • Loading branch information
calvinp0 committed Nov 26, 2023
1 parent b9060f6 commit 6de7e86
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 23 deletions.
48 changes: 25 additions & 23 deletions arc/job/adapters/molpro.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,19 +320,19 @@ def set_additional_file_paths(self) -> None:
def set_input_file_memory(self) -> None:
"""
Set the input_file_memory attribute.
Molpro's memory is per cpu core and in MW (mega word; 1000 MW = 7.45 GB on a 64-bit machine)
The conversion from mW to GB was done using this (https://deviceanalytics.com/words-to-bytes-converter/)
specifying a 64-bit architecture.
See also:
https://www.molpro.net/pipermail/molpro-user/2010-April/003723.html
In the link, they describe the conversion of 100,000,000 Words (100Mword) is equivalent to
800,000,000 bytes (800 mb).
Formula - (100,000,000 [Words]/( 800,000,000 [Bytes] / (job mem in gb * 1000,000,000 [Bytes])))/ 1000,000 [Words -> MegaWords]
The division by 1E6 is for converting into MWords
"""
# Molpro's memory is per cpu core and in MW (mega word; 1000 MW = 7.45 GB on a 64-bit machine)
# The conversion from mW to GB was done using this (https://deviceanalytics.com/words-to-bytes-converter/)
# specifying a 64-bit architecture.
#
# See also:
# https://www.molpro.net/pipermail/molpro-user/2010-April/003723.html
# In the link, they describe the conversion of 100,000,000 Words (100Mword) is equivalent to
# 800,000,000 bytes (800 mb).
# Formula - (100,000,000 [Words]/( 800,000,000 [Bytes] / (job mem in gb * 1000,000,000 [Bytes])))/ 1000,000 [Words -> MegaWords]
# The division by 1E6 is for converting into MWords
# Due to Zeus's configuration, there is only 1 nproc so the memory should not be divided by cpu_cores.
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))

self.input_file_memory = math.ceil(self.job_memory_gb / (7.45e-3 * self.cpu_cores))
# We need to check if ess_trsh_methods=['cpu'] and ess_trsh_methods=['molpro_memory:] exists
# If it does, we need to reduce the cpu_cores
if self.ess_trsh_methods is not None:
Expand All @@ -347,21 +347,23 @@ def set_input_file_memory(self) -> None:

if memory_values:
min_memory_value = min(memory_values)
required_cores = math.floor(max_memory / (min_memory_value * 7.45e-3))
available_cores = math.floor(max_memory / (min_memory_value * 7.45e-3))
if self.core_change is None:
self.core_change = required_cores
elif self.core_change == required_cores:
self.core_change = available_cores
elif self.core_change == available_cores:
# We have already done this
# Reduce the cores by 1
required_cores -= 1
if required_cores < current_cpu_cores:
self.cpu_cores = required_cores
available_cores -= 1

Check warning on line 356 in arc/job/adapters/molpro.py

View check run for this annotation

Codecov / codecov/patch

arc/job/adapters/molpro.py#L356

Added line #L356 was not covered by tests
if available_cores < current_cpu_cores:
self.cpu_cores = available_cores
logger.info(f'Changing the number of cpu_cores from {current_cpu_cores} to {self.cpu_cores}')
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))




# Situation may occur when the required memory per process by Molpro is only enough for 1 cpu core for us to use (for example, 4300 MW -> 32.04GB and if we have 64GB, we can only use 1 cpu core)
# And this means that for 1 CPU, we may end up using all 64GB of memory which approximates to 8600 MW. We need to take precaution here and not use all the memory.
# We will therefore, limit the MW to 4300 MW
self.input_file_memory = math.ceil(self.job_memory_gb / (7.45e-3 * self.cpu_cores))
if self.cpu_cores == 1 and self.input_file_memory > min_memory_value:
self.input_file_memory = min_memory_value
logger.info(f'Changing the input_file_memory from {self.input_file_memory} to {min_memory_value} as the number of cpu_cores will be restricted to 1 due to the memory requirements of Molpro')

def execute_incore(self):
"""
Expand Down
33 changes: 33 additions & 0 deletions arc/job/adapters/molpro_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ def setUpClass(cls):
species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])],
testing=True,
)
cls.job_3 = MolproAdapter(execution_type='queue',
job_type='opt',
level=Level(method='CCSD(T)', basis='cc-pVQZ'),
project='test',
project_directory=os.path.join(ARC_PATH, 'arc', 'testing', 'test_MolproAdapter_2'),
species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])],
testing=True,
ess_trsh_methods=['memory','cpu', 'molpro_memory: 2800 '],
job_memory_gb=64,
)
cls.job_4 = MolproAdapter(execution_type='queue',
job_type='opt',
level=Level(method='CCSD(T)', basis='cc-pVQZ'),
project='test',
project_directory=os.path.join(ARC_PATH, 'arc', 'testing', 'test_MolproAdapter_2'),
species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])],
testing=True,
ess_trsh_methods=['memory','cpu', 'molpro_memory: 4300 '],
job_memory_gb=64,
)

def test_set_cpu_and_mem(self):
"""Test assigning number of cpu's and memory"""
Expand All @@ -52,6 +72,19 @@ def test_set_cpu_and_mem(self):
self.job_1.set_cpu_and_mem()
self.assertEqual(self.job_1.cpu_cores, 48)

def test_memory_change(self):
"""Test changing the memory
1. Test that the required memory is set correctly and that the number of CPUs changes accordingly
2. Test that the required memory requires 1 CPU and will therefore not attempt to the total memory
"""
self.assertEqual(self.job_3.input_file_memory, 2864)
self.assertEqual(self.job_3.cpu_cores, 3)

self.assertEqual(self.job_4.input_file_memory, 4300)
self.assertEqual(self.job_4.cpu_cores, 1)


def test_set_input_file_memory(self):
"""Test setting the input_file_memory argument"""
self.job_1.input_file_memory = None
Expand Down

0 comments on commit 6de7e86

Please sign in to comment.