Skip to content
Closed
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
220 changes: 121 additions & 99 deletions cscs-checks/apps/vasp/vasp_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,118 +4,140 @@
# SPDX-License-Identifier: BSD-3-Clause

import reframe as rfm
import reframe.utility.sanity as sn
from hpctestlib.apps.vasp.base_check import VASP

dom_cpu = {
'maint': (148.7, None, 0.05, 's'),
'prod': (148.7, None, 0.05, 's'),
}

class VASPCheck(rfm.RunOnlyRegressionTest):
def __init__(self):
daint_cpu = {
'maint': (105.3, None, 0.20, 's'),
'prod': (105.3, None, 0.20, 's'),
}

eiger_cpu = {
'maint': (100.0, None, 0.10, 's'),
'prod': (100.0, None, 0.10, 's'),
}

pilatus_cpu = {
'maint': (100.0, None, 0.10, 's'),
'prod': (100.0, None, 0.10, 's'),
}


REFERENCE_CPU_PERFORMANCE = {
'dom:gpu': dom_cpu,
'daint:gpu': daint_cpu,
'eiger:mc': eiger_cpu,
'pilatus:mc': pilatus_cpu
}


dom_gpu = {
'maint': (61.0, None, 0.10, 's'),
'prod': (46.7, None, 0.20, 's'),
}

daint_gpu = {
'maint': (46.7, None, 0.20, 's'),
'prod': (46.7, None, 0.20, 's'),
}

REFERENCE_GPU_PERFORMANCE = {
'dom:gpu': dom_gpu,
'daint:gpu': daint_gpu,
}

REFERENCE_PERFORMANCE = {
'gpu': REFERENCE_GPU_PERFORMANCE,
'cpu': REFERENCE_CPU_PERFORMANCE,
}


@rfm.simple_test
class VASPCheckCSCS(VASP):
mode = parameter(['prod', 'maint'])
modules = ['VASP']
maintainers = ['LM']
tags = {'scs'}
strict_check = False
extra_resources = {
'switches': {
'num_switches': 1
}
}

@run_after('init')
def env_define(self):
if self.current_system.name in ['eiger', 'pilatus']:
self.valid_prog_environs = ['cpeIntel']
else:
self.valid_prog_environs = ['builtin']

self.modules = ['VASP']
force = sn.extractsingle(r'1 F=\s+(?P<result>\S+)',
self.stdout, 'result', float)
self.sanity_patterns = sn.assert_reference(
force, -.85026214E+03, -1e-5, 1e-5
)
self.keep_files = ['OUTCAR']
self.perf_patterns = {
'time': sn.extractsingle(r'Total CPU time used \(sec\):'
r'\s+(?P<time>\S+)', 'OUTCAR',
'time', float)
}
self.maintainers = ['LM']
self.tags = {'scs'}
self.strict_check = False
self.extra_resources = {
'switches': {
'num_switches': 1
}
}
@run_after('init')
def set_tags(self):
self.tags |= {'maintenance' if self.mode == 'maint'
else 'production'}

@run_after('init')
def set_valid_systems(self):
if self.platform_info[0] == 'cpu':
self.valid_systems = ['daint:mc',
'dom:mc',
'eiger:mc',
'pilatus:mc']
else:
self.valid_systems = ['daint:gpu', 'dom:gpu']

@rfm.parameterized_test(*([v] for v in ['maint', 'prod']))
class VASPCpuCheck(VASPCheck):
def __init__(self, variant):
super().__init__()
self.descr = f'VASP CPU check (variant: {variant})'
self.valid_systems = ['daint:mc', 'dom:mc', 'eiger:mc', 'pilatus:mc']

self.executable = 'vasp_std'
if self.current_system.name == 'dom':
self.num_tasks = 72
self.num_tasks_per_node = 12
self.use_multithreading = True
elif self.current_system.name in ['eiger', 'pilatus']:
self.num_tasks = 64
self.num_tasks_per_node = 4
self.num_cpus_per_task = 8
self.num_tasks_per_core = 1
self.use_multithreading = False
self.variables = {
'MPICH_OFI_STARTUP_CONNECT': '1',
'OMP_NUM_THREADS': str(self.num_cpus_per_task),
'OMP_PLACES': 'cores',
'OMP_PROC_BIND': 'close'
}
@run_after('setup')
def set_num_tasks(self):
if self.platform == 'cpu':
if self.current_system.name == 'dom':
self.num_tasks = 72
self.num_tasks_per_node = 12
self.use_multithreading = True
elif self.current_system.name in ['eiger', 'pilatus']:
self.num_tasks = 64
self.num_tasks_per_node = 4
self.num_cpus_per_task = 8
self.num_tasks_per_core = 1
self.use_multithreading = False
self.variables = {
'MPICH_OFI_STARTUP_CONNECT': '1',
'OMP_NUM_THREADS': str(self.num_cpus_per_task),
'OMP_PLACES': 'cores',
'OMP_PROC_BIND': 'close'
}
else:
self.num_tasks = 32
self.num_tasks_per_node = 2
self.use_multithreading = True
else:
self.num_tasks = 32
self.num_tasks_per_node = 2
self.use_multithreading = True

references = {
'maint': {
'dom:mc': {'time': (148.7, None, 0.05, 's')},
'daint:mc': {'time': (105.3, None, 0.20, 's')},
'eiger:mc': {'time': (100.0, None, 0.10, 's')},
'pilatus:mc': {'time': (100.0, None, 0.10, 's')}
},
'prod': {
'dom:mc': {'time': (148.7, None, 0.05, 's')},
'daint:mc': {'time': (105.3, None, 0.20, 's')},
'eiger:mc': {'time': (100.0, None, 0.10, 's')},
'pilatus:mc': {'time': (100.0, None, 0.10, 's')}
}
}
self.reference = references[variant]
self.tags |= {'maintenance' if variant == 'maint' else 'production'}
self.variables = {'CRAY_CUDA_MPS': '1'}
self.num_gpus_per_node = 1
if self.current_system.name == 'dom':
self.num_tasks = 6
self.num_tasks_per_node = 1
else:
self.num_tasks = 16
self.num_tasks_per_node = 1

@run_after('setup')
def set_perf_reference(self):
self.reference = REFERENCE_PERFORMANCE[self.platform]

@run_after('setup')
def set_description(self):
self.descr = f'VASP {self.platform} check (benchmark: {self.mode})'

@run_before('run')
def set_task_distribution(self):
self.job.options = ['--distribution=block:block']
if self.platform == 'cpu':
self.job.options = ['--distribution=block:block']

@run_before('run')
def set_cpu_binding(self):
self.job.launcher.options = ['--cpu-bind=cores']


@rfm.parameterized_test(*([v] for v in ['maint', 'prod']))
class VASPGpuCheck(VASPCheck):
def __init__(self, variant):
super().__init__()
self.descr = f'VASP GPU check (variant: {variant})'
self.valid_systems = ['daint:gpu', 'dom:gpu']
self.executable = 'vasp_gpu'
self.variables = {'CRAY_CUDA_MPS': '1'}
self.num_gpus_per_node = 1
if self.current_system.name == 'dom':
self.num_tasks = 6
self.num_tasks_per_node = 1
else:
self.num_tasks = 16
self.num_tasks_per_node = 1

references = {
'maint': {
'dom:gpu': {'time': (61.0, None, 0.10, 's')},
'daint:gpu': {'time': (46.7, None, 0.20, 's')},
},
'prod': {
'dom:gpu': {'time': (61.0, None, 0.10, 's')},
'daint:gpu': {'time': (46.7, None, 0.20, 's')},
}
}
self.reference = references[variant]
self.tags |= {'maintenance' if variant == 'maint' else 'production'}
if self.platform == 'cpu':
self.job.launcher.options = ['--cpu-bind=cores']
89 changes: 89 additions & 0 deletions hpctestlib/apps/vasp/base_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2016-2021 Swiss National Supercomputing Centre (CSCS/ETH Zurich)
# ReFrame Project Developers. See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: BSD-3-Clause

import reframe as rfm
import reframe.utility.sanity as sn


class VASP(rfm.RunOnlyRegressionTest, pin_prefix=True):
'''Base class for the VASP Test.

The Vienna Ab initio Simulation Package (VASP) is a computer
program for atomic scale materials modelling, e.g. electronic
structure calculations and quantum-mechanical molecular
dynamics, from first principles. (see vasp.at)

The presented abstract run-only class checks the perfomance of VASP.
To do this, it is necessary to define in tests the reference
values of force and possible deviations from this value.
This data is used to check if the task is being executed
correctly, that is, the final force is correct (approximately
the reference). The default assumption is that VASP is already
installed on the device under test.
'''

#: Reference value of force, that is used for the comparison
#: with the execution ouput on the sanity step. The absolute
#: difference between final force value and reference value
#: should be smaller than force_tolerance
#:
#: :type: float
#: :default: :class:`required`
force_value = variable(float)

#: Maximum deviation from the reference value of force,
#: that is acceptable.
#:
#: :type: float
#: :default: :class:`required`
force_tolerance = variable(float)

#: Name of the keep files for the case of VASP is standart
keep_files = ['OUTCAR']

#: :default: :class:`required`
num_tasks_per_node = required

force_value = -.85026214E+03
force_tolerance = 1e-5

#: Parameter pack containing the platform name and executable.
platform_info = parameter([
('cpu', 'vasp_std'),
('gpu', 'vasp_gpu')
])

@run_after('init')
def unpack_platform_parameter(self):
'''Set the executable and input file.'''

self.platform, self.executable = self.platform_info

@performance_function('s', perf_key='time')
def set_perf_patterns(self):
return sn.extractsingle(r'Total CPU time used \(sec\):'
r'\s+(?P<time>\S+)', 'OUTCAR',
'time', float)

@run_before('performance')
def set_the_performance_dict(self):
self.perf_variables = {self.mode:
sn.make_performance_function(
sn.extractsingle(
r'Total CPU time used \(sec\):'
r'\s+(?P<time>\S+)', 'OUTCAR',
'time', float), 's')}

@sanity_function
def set_sanity_patterns(self):
'''Assert the obtained energy meets the specified tolerances.'''

force = sn.extractsingle(r'1 F=\s+(?P<result>\S+)',
self.stdout, 'result', float)
force_diff = sn.abs(force - self.force_value)
ref_force_diff = sn.abs(self.force_value *
self.force_tolerance)

return sn.assert_lt(force_diff, ref_force_diff)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.