Skip to content
Merged
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
21 changes: 13 additions & 8 deletions docs/describing_runs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Describing runs
Once we have a model structure, a configuration for a specific scenario, and programs to
do the calculations, there's only one thing left to configure and that is the run
itself. In yMMSL, we can specify the compute resources to use for each program, and if
the programs support then it we can configure when to checkpoint the simulation.
the programs support it we can configure when to checkpoint the simulation.

Resources
`````````
Expand All @@ -23,20 +23,25 @@ threads:
:caption: Resources for threaded processes

resources:
macro:
model.macro:
threads: 1

micro:
model.micro:
threads: 8

Note that the component is designated by the name of the top-level model, followed by
the component name. If the component is inside of a submodel, then you have to specify
the path all the way from the top, e.g. ``model.micro.c1`` if ``micro`` is implemented
by a submodel that has a component named ``c1``.

If no resource is defined for a non-MPI component, a default of 1 thread will
be assigned to it at runtime (e.g. by MUSCLE3). So, you could also define:

.. code-block:: yaml
:caption: Resources for threaded processes

resources:
micro:
model.micro:
threads: 8

On the Python side, this is represented by :class:`.ymmsl.v0_2.ThreadedResReq` (short
Expand All @@ -53,9 +58,9 @@ processes, and optionally the number of threads per MPI process:
:caption: Core-based resources for MPI components

resources:
macro:
model.macro:
mpi_processes: 32
micro:
model.micro:
mpi_processes: 16
threads_per_mpi_process: 8

Expand All @@ -69,11 +74,11 @@ already specify them as follows:
:caption: Node-based resources for MPI components

resources:
macro:
model.macro:
nodes: 8
mpi_processes_per_node: 4
threads_per_mpi_process: 8
micro:
model.micro:
nodes: 1
mpi_processes_per_node: 16

Expand Down
27 changes: 25 additions & 2 deletions ymmsl/conversion/convert_v0_1_to_v0_2.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from copy import deepcopy
from typing import Dict, List, Optional
from typing import Dict, List, MutableMapping, Optional
import warnings

import ymmsl.v0_1 as v0_1
Expand Down Expand Up @@ -30,7 +30,7 @@ def convert_v0_1_to_v0_2(config: v0_1.PartialConfiguration) -> v0_2.Configuratio
' incorrect wiring easier to debug. While there, add a description too!'
)

resources = deepcopy(config.resources)
resources = convert_resources(config.resources, models)
checkpoints = deepcopy(config.checkpoints)
resume = deepcopy(config.resume)

Expand Down Expand Up @@ -162,3 +162,26 @@ def convert_ports(ports: v0_1.Ports) -> v0_2.Ports:
list(map(str, ports.o_i)),
list(map(str, ports.s)),
list(map(str, ports.o_f)))


def convert_resources(
resources: MutableMapping[v0_1.Reference, v0_1.ResourceRequirements],
models: Optional[List[v0_2.Model]]
) -> MutableMapping[v0_2.Reference, v0_2.ResourceRequirements]:
if not models:
warnings.warn(
'When specifying resources in yMMSL v0.2, component names must be'
' prefixed with the name of the top (outermost) model, e.g. as'
' my_model.my_component rather than just my_component. This file'
' does not contain a model, so its name cannot be added automatically.'
' Please add the model name yourself.')
return deepcopy(resources)
else:
mname = models[0].name
result = dict()
for res_req in resources.values():
new_res_req = deepcopy(res_req)
new_res_req.name = mname + res_req.name
result[new_res_req.name] = new_res_req

return result
9 changes: 5 additions & 4 deletions ymmsl/conversion/tests/test_convert_v0_1_to_v0_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


@pytest.mark.filterwarnings('ignore:Comments.*')
@pytest.mark.filterwarnings('ignore:When specifying resources.*')
def test_convert_simple_config(empty_config: v0_1.PartialConfiguration) -> None:
v2 = convert_v0_1_to_v0_2(empty_config)

Expand Down Expand Up @@ -66,16 +67,16 @@ def test_convert_full_config(full_config: v0_1.Configuration) -> None:
assert v2.resources is not full_config.resources
assert len(v2.resources) == 2

ra = v2.resources[Ref2('A')]
ra = v2.resources[Ref2('test_model.A')]
assert ra is not full_config.resources[Ref1('A')]
assert isinstance(ra, v0_2.ThreadedResReq)
assert ra.name == 'A'
assert ra.name == 'test_model.A'
assert ra.threads == 8

rb = v2.resources[Ref2('B')]
rb = v2.resources[Ref2('test_model.B')]
assert rb is not full_config.resources[Ref1('B')]
assert isinstance(rb, v0_2.MPICoresResReq)
assert rb.name == 'B'
assert rb.name == 'test_model.B'
assert rb.mpi_processes == 4
assert rb.threads_per_mpi_process == 8

Expand Down
1 change: 1 addition & 0 deletions ymmsl/tests/test_load_as.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def test_load_as_v0_1(test_yaml1: str) -> None:


@pytest.mark.filterwarnings('ignore:Comments.*')
@pytest.mark.filterwarnings('ignore:When specifying resources.*')
def test_load_as_v0_2(test_yaml1: str) -> None:
config = load_as(v0_2.Configuration, test_yaml1)
assert isinstance(config, v0_2.Configuration)
Expand Down
Loading