Run an OpenFOAM simulation

from pathlib import Path
import time
from remote_run.run import (
    ExecutionContext,
    SlurmSchedulingEngine,
    GuixRunner,
    GitProject,
    remote,
    is_finished,
    SshExecution,
)
from pyopenfoam.tutorials import generate_pitz_daily_case

we use pyopenfoam to call OpenFOAM from python this means adding this channel to the guix channels. This can also be read from a file directly.

channels = """(list
      (channel
       (name 'guix)
       (url "https://git.savannah.gnu.org/git/guix.git")
       (branch "master")
       (commit
        "ee8be372972bc1e84b5870df738c6e0bbdd975ff")
       (introduction
        (make-channel-introduction
         "9edb3f66fd807b096b48283debdcddccfea34bad"
         (openpgp-fingerprint
          "BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA"))))
      (channel
       (name 'python-pyopenfoam)
       (url "https://gitlab.ost.ch/sce-floss/pyopenfoam.git")
       (branch "main")
       (commit
        "ab8b4130bd8e3c199e72b47c6ca1809011be3b5e"))
      (channel
       (name 'guix-ost)
       (url "https://gitlab.ost.ch/scl/guix-ost.git")
       (branch "main")
       (commit
        "2a64fa887f4a2069ea9426e423f55838bc8987e9")))"""

define execution variables

num_cpus = 10

Define an execution context with a scheduling engine. For slurm you can pass slurm parameters directly here.

execution_context = ExecutionContext(
    execution=SshExecution(
        machine="shpc0003.ost.ch",
        working_directory=Path("/cluster/raid/home/reza.housseini"),
    ),
    num_cpus=num_cpus,
    project=GitProject(),
    runner=GuixRunner(
        dependencies=[
            "python-pyvista",
            "python-pint",
            "python-pyopenfoam",
            "openfoam-org",
            "openmpi",
        ],
        channels=channels,
    ),
    scheduling_engine=SlurmSchedulingEngine(
        job_name="openfoam_sim",
        mail_type="ALL",
        mail_user="reza.housseini@ost.ch",
    ),
)

define simulation variables

duration = 0.1  # seconds

create an OpenFOAM case locally

pitz_daily_case = generate_pitz_daily_case(duration=duration, num_cpus=num_cpus)
case_path = Path("pitz_daily_case")
pitz_daily_case.write(folder=case_path)

decorate your functions you want to run in the specified execution context, in this case we want to execute our OpenFOAM case in parallel and return the field “alpha.liquid”

@remote(execution_context)
def sim_job(run_path=None):
    # call import statements here for modules needed remotely
    from pyopenfoam.cli.scripts import of_run
    import pyvista as pv

    remote_case_path = run_path / case_path.name
    of_run(remote_case_path)
    # return simulation data
    foam_file = run_path / (case_path.name + ".foam")
    foam_file.touch()
    reader = pv.POpenFOAMReader(foam_file)
    return reader.read()

this call will run on the remote machine specified in execution_context but due to the asynchronous nature of scheduling engines this will not return the result, instead you get the job id and a function to retrieve the result later. Inject the identifier keyword argument, it will be replaced with the Identifier object holding the paths.

job_id, result_func = sim_job(identifier=None)

now we wait for the remote execution to finish before retrieving the result normally this step is decoupled when using a scheduler.

time.sleep(10)

we should check if the job id has finished before retrieving the result

if is_finished(execution_context, job_id):
    result = result_func()

Gallery generated by Sphinx-Gallery