Skip to content

Commit 63e7a2b

Browse files
committed
Attempt of inner mpi call
1 parent e477665 commit 63e7a2b

4 files changed

Lines changed: 101 additions & 4 deletions

File tree

aiida/engine/processes/calcjobs/calcjob.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,8 @@ def presubmit(self, folder: Folder) -> CalcInfo:
740740
else:
741741
prepend_cmdline_params = []
742742

743+
cmdline_params = [str(this_code.get_executable())] + (code_info.cmdline_params or [])
744+
743745
escape_exec_line = False
744746
if isinstance(this_code, Containerized):
745747
prepend_cmdline_params += this_code.get_engine_command()
@@ -749,7 +751,19 @@ def presubmit(self, folder: Folder) -> CalcInfo:
749751
# therefore default set to False.
750752
escape_exec_line = this_code.escape_exec_line
751753

752-
cmdline_params = [str(this_code.get_executable())] + (code_info.cmdline_params or [])
754+
inner_mpi = this_code.inner_mpi
755+
if inner_mpi:
756+
# First always serials outside
757+
prepend_cmdline_params = this_code.get_engine_command()
758+
759+
# Set mpi args for code if not exist use the computer one as default
760+
if this_code.get_mpirun_command():
761+
code_mpi_args = this_code.get_mpirun_command()
762+
else:
763+
code_mpi_args = mpi_args
764+
765+
# import ipdb; ipdb.set_trace()
766+
cmdline_params = [arg.format(**subst_dict) for arg in code_mpi_args] + cmdline_params
753767

754768
tmpl_code_info = JobTemplateCodeInfo()
755769
tmpl_code_info.prepend_cmdline_params = prepend_cmdline_params

aiida/orm/nodes/data/code/containerized.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,23 @@ class Containerized(AbstractCode):
3434
_KEY_ATTRIBUTE_ENGINE_COMMAND: str = 'engine_command'
3535
_KEY_ATTRIBUTE_IMAGE: str = 'image'
3636
_KEY_ATTRIBUTE_ESCAPE_EXEC_LINE: str = 'escape_exec_line'
37-
38-
def __init__(self, engine_command: str, image: str, escape_exec_line: bool = False, **kwargs):
37+
_KEY_ATTRIBUTE_INNER_MPI: str = 'inner_mpi'
38+
_KEY_ATTRIBUTE_MPI_ARGS: str = 'mpi_args'
39+
40+
def __init__(
41+
self,
42+
engine_command: str,
43+
image: str,
44+
inner_mpi: bool = False,
45+
mpi_args: str = '',
46+
escape_exec_line: bool = False,
47+
**kwargs
48+
):
3949
super().__init__(**kwargs)
4050
self.engine_command = engine_command
4151
self.image = image
52+
self.inner_mpi = inner_mpi
53+
self.mpi_args = mpi_args
4254
self.escape_exec_line = escape_exec_line
4355

4456
@property
@@ -62,6 +74,16 @@ def engine_command(self, value: str) -> None:
6274

6375
self.base.attributes.set(self._KEY_ATTRIBUTE_ENGINE_COMMAND, value)
6476

77+
@property
78+
def mpi_args(self) -> str:
79+
return self.base.attributes.get(self._KEY_ATTRIBUTE_MPI_ARGS)
80+
81+
@mpi_args.setter
82+
def mpi_args(self, value: str) -> None:
83+
type_check(value, str)
84+
85+
self.base.attributes.set(self._KEY_ATTRIBUTE_MPI_ARGS, value)
86+
6587
@property
6688
def escape_exec_line(self) -> bool:
6789
"""True for escape whole execute line after engine command in double quotes.
@@ -80,6 +102,16 @@ def escape_exec_line(self, value: bool) -> None:
80102

81103
self.base.attributes.set(self._KEY_ATTRIBUTE_ESCAPE_EXEC_LINE, value)
82104

105+
@property
106+
def inner_mpi(self) -> bool:
107+
return self.base.attributes.get(self._KEY_ATTRIBUTE_INNER_MPI)
108+
109+
@inner_mpi.setter
110+
def inner_mpi(self, value: bool) -> None:
111+
type_check(value, bool)
112+
113+
self.base.attributes.set(self._KEY_ATTRIBUTE_INNER_MPI, value)
114+
83115
@property
84116
def image(self) -> str:
85117
"""The image of container
@@ -107,6 +139,12 @@ def get_engine_command(self) -> str:
107139

108140
return cmdline.split()
109141

142+
def get_mpirun_command(self) -> list:
143+
"""Return the mpi_args in terms of code."""
144+
mpi_args = self.mpi_args
145+
146+
return mpi_args.split()
147+
110148
@classmethod
111149
def _get_cli_options(cls) -> dict:
112150
"""Return the CLI options that would allow to create an instance of this class."""

tests/engine/processes/calcjobs/test_calc_job.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,46 @@ def test_containerized_installed_code(file_regression, aiida_localhost):
264264
file_regression.check(content, extension='.sh')
265265

266266

267+
@pytest.mark.requires_rmq
268+
@pytest.mark.usefixtures('clear_database_before_test', 'chdir_tmp_path')
269+
def test_containerized_inner_mpi(file_regression, aiida_localhost):
270+
"""test run container code"""
271+
aiida_localhost.set_use_double_quotes(True)
272+
engine_command = """conda run --name {image}"""
273+
override_mpirun_command = 'inner_mpirun -np {tot_num_mpiprocs}'
274+
containerized_code = orm.InstalledContainerizedCode(
275+
default_calc_job_plugin='core.arithmetic.add',
276+
filepath_executable='/bin/bash',
277+
engine_command=engine_command,
278+
image='myenv',
279+
inner_mpi=True,
280+
mpi_args=override_mpirun_command,
281+
computer=aiida_localhost,
282+
escape_exec_line=False,
283+
).store()
284+
285+
inputs = {
286+
'code': containerized_code,
287+
'metadata': {
288+
'dry_run': True,
289+
'options': {
290+
'resources': {
291+
'num_machines': 1,
292+
'num_mpiprocs_per_machine': 1
293+
},
294+
'withmpi': True,
295+
}
296+
}
297+
}
298+
299+
_, node = launch.run_get_node(DummyCalcJob, **inputs)
300+
folder_name = node.dry_run_info['folder']
301+
submit_script_filename = node.get_option('submit_script_filename')
302+
content = (pathlib.Path(folder_name) / submit_script_filename).read_bytes().decode('utf-8')
303+
304+
file_regression.check(content, extension='.sh')
305+
306+
267307
@pytest.mark.requires_rmq
268308
@pytest.mark.usefixtures('clear_database_before_test', 'chdir_tmp_path')
269309
def test_containerized_portable_code(file_regression, tmp_path, aiida_localhost):
@@ -339,7 +379,6 @@ def test_multi_codes_run_withmpi(aiida_local_code_factory, file_regression, calc
339379
@pytest.mark.usefixtures('clear_database_before_test', 'chdir_tmp_path')
340380
def test_portable_code(tmp_path, aiida_localhost):
341381
"""test run container code"""
342-
import pathlib
343382
(tmp_path / 'bash').write_bytes(b'bash implementation')
344383
subdir = tmp_path / 'sub'
345384
subdir.mkdir()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
exec > _scheduler-stdout.txt
3+
exec 2> _scheduler-stderr.txt
4+
5+
6+
"conda" "run" "--name" "myenv" 'inner_mpirun' '-np' '1' '/bin/bash' '--version' '-c' < "aiida.in" > "aiida.out" 2> "aiida.err"

0 commit comments

Comments
 (0)