Esempio n. 1
0
    def __init__(
        self,
        bout_paths: Optional[BoutPaths] = None,
        submitter: Optional[LocalSubmitter] = None,
        run_parameters: Optional[RunParameters] = None,
        restart_from: Optional[Path] = None,
    ) -> None:
        """
        Set the input parameters.

        Parameters
        ----------
        bout_paths : BoutPaths or None
            Object containing the paths
            If None, default BoutPaths values will be used
        submitter : AbstractSubmitter
            Object containing the submitter
        run_parameters : RunParameters or None
            Object containing the run parameters
            If None, default parameters will be used
        restart_from : Path or None
            The path to copy the restart files from
        """
        # Set member data
        self.restart_from = restart_from
        # NOTE: We are not setting the default as a keyword argument
        #       as this would mess up the paths
        self.submitter = submitter if submitter is not None else LocalSubmitter(
        )
        self.__bout_paths = bout_paths if bout_paths is not None else BoutPaths(
        )
        self.__run_parameters = (run_parameters if run_parameters is not None
                                 else RunParameters())
        self.__make = Make(self.__bout_paths.project_path)
    def __init__(
        self,
        bout_paths: Optional[BoutPaths] = None,
        submitter: Optional[AbstractSubmitter] = None,
        run_parameters: Optional[RunParameters] = None,
        restart_from: Optional[Path] = None,
    ) -> None:
        """
        Set the input parameters.

        Parameters
        ----------
        bout_paths : BoutPaths or None
            Object containing the paths
            If None, default BoutPaths values will be used
        submitter : AbstractSubmitter
            Object containing the submitter
        run_parameters : RunParameters or None
            Object containing the run parameters
            If None, default parameters will be used
        restart_from : Path or None
            The path to copy the restart files from
        """
        # NOTE: We are not setting the default as a keyword argument
        #       as this would mess up the paths
        # NOTE: We are deepcopying bout_paths as it may be altered by for
        #       example the self.restart_from setter
        logging.info("Start: Making an BoutRunExecutor object")
        self.__bout_paths = (
            deepcopy(bout_paths) if bout_paths is not None else BoutPaths()
        )
        self.__run_parameters = (
            run_parameters if run_parameters is not None else RunParameters()
        )
        self.__make = Make(self.__bout_paths.project_path)

        self.submitter = submitter if submitter is not None else get_submitter()
        if isinstance(self.submitter, AbstractClusterSubmitter):
            self.submitter.store_dir = self.__bout_paths.bout_inp_dst_dir

        self.__restart_from = None
        self.restart_from = restart_from
        logging.info("Done: Making an BoutRunExecutor object")
Esempio n. 3
0
def make_make_object(yield_bout_path: Path) -> Iterator[Tuple[Make, Path]]:
    """
    Set up and tear down the make-object.

    In order not to make collisions with the global fixture which makes the
    `conduction` program, this fixture copies the content of the `conduction`
    directory to a `tmp` directory, which is removed in the teardown.

    This fixture calls make_obj.run_clean() before the yield statement.

    Parameters
    ----------
    yield_bout_path : Path
        Path to the BOUT++ repository. See the yield_bout_path fixture for more details

    Yields
    ------
    make_obj : MakeProject
        The object to call make and make clean from
    exec_file : Path
        The path to the executable

    See Also
    --------
    tests.bout_runners.conftest.get_bout_directory : Fixture returning the BOUT++ path
    """
    # Setup
    bout_path = yield_bout_path
    project_path = bout_path.joinpath("examples", "conduction")
    tmp_path = project_path.parent.joinpath("tmp_make")

    copy_tree(str(project_path), str(tmp_path))

    exec_file = tmp_path.joinpath("conduction")

    make_obj = Make(makefile_root_path=tmp_path)
    make_obj.run_clean()

    yield make_obj, exec_file

    # Teardown
    remove_tree(str(tmp_path))
Esempio n. 4
0
def make_project(yield_conduction_path: Path) -> Iterator[Path]:
    """
    Set up and tear down the Make object.

    The method calls make_obj.run_clean() before and after the yield statement

    Parameters
    ----------
    yield_conduction_path : Path
        Path to the BOUT++ conduction example
        See the yield_conduction_path for more details

    Yields
    ------
    project_path : Path
        The path to the conduction example
    """
    # Setup
    project_path = yield_conduction_path

    make_obj = Make(makefile_root_path=project_path)
    make_obj.run_make()

    yield project_path

    # Teardown
    make_obj.run_clean()
Esempio n. 5
0
    def __init__(
        self,
        db_connector: DatabaseConnector,
        bout_paths: BoutPaths,
        final_parameters: FinalParameters,
    ) -> None:
        """
        Set the database to use.

        Parameters
        ----------
        db_connector : DatabaseConnector
            The database connector
        bout_paths : BoutPaths
            Object containing the paths
        final_parameters : FinalParameters
            Object containing the final parameters
        """
        self.__db_writer = DatabaseWriter(db_connector)
        self.__db_reader = DatabaseReader(db_connector)
        self.__bout_paths = bout_paths
        self.__final_parameters = final_parameters
        self.__make = Make(self.__bout_paths.project_path)
Esempio n. 6
0
class Executor:
    r"""
    Executes the command for submitting a run.

    Attributes
    ----------
    __bout_paths : BoutPaths
        Getter variable for project_path
    __run_parameters : RunParameters
        Object containing the run parameters
    __make : Make
        Object for making the project
    restart_from : None or Path
        Path to copy restart files from prior to the execution
    submitter : AbstractSubmitter
        Object containing the submitter
    bout_paths : BoutPaths
        Object containing the paths
    run_parameters : RunParameters
        Object containing the run parameters

    Methods
    -------
    get_execute_command()
        Return the execute command string
    execute()
        Execute a BOUT++ run

    Examples
    --------
    The easiest way to use the Executor is to run a script from the root directory of
    the project (i.e. where the `Makefile` and `data` directory are normally
    situated. The script can simply call

    >>> Executor().execute()

    and `Executor` takes care of the rest.

    A more elaborate example where all the dependency objects are built manually:

    Import the dependencies

    >>> from pathlib import Path
    >>> from bout_runners.executor.bout_paths import BoutPaths
    >>> from bout_runners.submitter.local_submitter import LocalSubmitter

    Create the `bout_paths` object

    >>> project_path = Path().joinpath('path', 'to', 'project')
    >>> bout_inp_src_dir = Path().joinpath('path', 'to', 'source', 'BOUT.inp')
    >>> bout_inp_dst_dir = Path().joinpath('path', 'to', 'destination', 'BOUT.inp')
    >>> bout_paths = BoutPaths(project_path=project_path,
    ...                        bout_inp_src_dir=bout_inp_src_dir,
    ...                        bout_inp_dst_dir=bout_inp_dst_dir)

    Create the executor object

    >>> run_parameters = RunParameters({'global': {'nout': 0}})
    >>> executor = Executor(
    ...     bout_paths=bout_paths,
    ...     submitter=LocalSubmitter(bout_paths.project_path),
    ...     run_parameters=run_parameters)

    Execute the run

    >>> executor.execute()
    """
    def __init__(
        self,
        bout_paths: Optional[BoutPaths] = None,
        submitter: Optional[LocalSubmitter] = None,
        run_parameters: Optional[RunParameters] = None,
        restart_from: Optional[Path] = None,
    ) -> None:
        """
        Set the input parameters.

        Parameters
        ----------
        bout_paths : BoutPaths or None
            Object containing the paths
            If None, default BoutPaths values will be used
        submitter : AbstractSubmitter
            Object containing the submitter
        run_parameters : RunParameters or None
            Object containing the run parameters
            If None, default parameters will be used
        restart_from : Path or None
            The path to copy the restart files from
        """
        # Set member data
        self.restart_from = restart_from
        # NOTE: We are not setting the default as a keyword argument
        #       as this would mess up the paths
        self.submitter = submitter if submitter is not None else LocalSubmitter(
        )
        self.__bout_paths = bout_paths if bout_paths is not None else BoutPaths(
        )
        self.__run_parameters = (run_parameters if run_parameters is not None
                                 else RunParameters())
        self.__make = Make(self.__bout_paths.project_path)

    @property
    def bout_paths(self) -> BoutPaths:
        """
        Set the properties of self.bout_paths.

        Returns
        -------
        self.__bout_paths : BoutPaths
            Object containing the paths

        Notes
        -----
        The bout_paths is read only
        """
        return self.__bout_paths

    @property
    def run_parameters(self):
        """
        Set the properties of self.run_parameters.

        Returns
        -------
        self.__run_parameters : RunParameters
            Object containing the run parameters

        Notes
        -----
        The run_parameters is read only
        """
        return self.__run_parameters

    def get_execute_command(self) -> str:
        """
        Return the execute command string.

        Returns
        -------
        command : str
            The terminal command for executing the run
        """
        mpi_cmd = "mpirun -np"

        # NOTE: No spaces if parameters are None
        command = (f"{mpi_cmd} "
                   f"{self.submitter.processor_split.number_of_processors} "
                   f"./{self.__make.exec_name} "
                   f"-d {self.__bout_paths.bout_inp_dst_dir} "
                   f"{self.__run_parameters.run_parameters_str}")
        return command

    def execute(self, restart: bool = False) -> AbstractSubmitter:
        """
        Execute a BOUT++ run.

        Parameters
        ----------
        restart : bool
            If True the 'restart' will be appended to the command string

        Returns
        -------
        submitter : AbstractSubmitter
            The submitter
        """
        # Make the project if not already made
        self.__make.run_make()
        # Submit the command
        command = self.get_execute_command()
        if restart:
            command += " restart"
        self.submitter.submit_command(command)
        return self.submitter
class BoutRunExecutor:
    r"""
    Executes the command for submitting a bout run.

    Attributes
    ----------
    __bout_paths : BoutPaths
        Getter variable for project_path
    __make : Make
        Object for making the project
    __run_parameters : RunParameters
        Object containing the run parameters
    bout_paths : BoutPaths
        Object containing the paths
    exec_name : str
        Name of the executable
    restart_from : None or Path
        Path to copy restart files from prior to the execution
    run_parameters : RunParameters
        Object containing the run parameters
    submitter : AbstractSubmitter
        Object containing the submitter

    Methods
    -------
    get_execute_command()
        Return the execute command string
    execute()
        Execute a BOUT++ run

    Examples
    --------
    The easiest way to use the Executor is to run a script from the root directory of
    the project (i.e. where the `Makefile` and `data` directory are normally
    situated. The script can simply call

    >>> BoutRunExecutor().execute()

    and `Executor` takes care of the rest.

    A more elaborate example where all the dependency objects are built manually:

    Import the dependencies

    >>> from pathlib import Path
    >>> from bout_runners.executor.bout_paths import BoutPaths
    >>> from bout_runners.submitter.local_submitter import LocalSubmitter

    Create the `bout_paths` object

    >>> project_path = Path().joinpath('path', 'to', 'project')
    >>> bout_inp_src_dir = Path().joinpath('path', 'to', 'source', 'BOUT.inp')
    >>> bout_inp_dst_dir = Path().joinpath('path', 'to', 'destination', 'BOUT.inp')
    >>> bout_paths = BoutPaths(project_path=project_path,
    ...                        bout_inp_src_dir=bout_inp_src_dir,
    ...                        bout_inp_dst_dir=bout_inp_dst_dir)

    Create the executor object

    >>> run_parameters = RunParameters({'global': {'nout': 0}})
    >>> executor = BoutRunExecutor(
    ...     bout_paths=bout_paths,
    ...     submitter=LocalSubmitter(bout_paths.project_path),
    ...     run_parameters=run_parameters)

    Execute the run

    >>> executor.execute()
    """

    def __init__(
        self,
        bout_paths: Optional[BoutPaths] = None,
        submitter: Optional[AbstractSubmitter] = None,
        run_parameters: Optional[RunParameters] = None,
        restart_from: Optional[Path] = None,
    ) -> None:
        """
        Set the input parameters.

        Parameters
        ----------
        bout_paths : BoutPaths or None
            Object containing the paths
            If None, default BoutPaths values will be used
        submitter : AbstractSubmitter
            Object containing the submitter
        run_parameters : RunParameters or None
            Object containing the run parameters
            If None, default parameters will be used
        restart_from : Path or None
            The path to copy the restart files from
        """
        # NOTE: We are not setting the default as a keyword argument
        #       as this would mess up the paths
        # NOTE: We are deepcopying bout_paths as it may be altered by for
        #       example the self.restart_from setter
        logging.info("Start: Making an BoutRunExecutor object")
        self.__bout_paths = (
            deepcopy(bout_paths) if bout_paths is not None else BoutPaths()
        )
        self.__run_parameters = (
            run_parameters if run_parameters is not None else RunParameters()
        )
        self.__make = Make(self.__bout_paths.project_path)

        self.submitter = submitter if submitter is not None else get_submitter()
        if isinstance(self.submitter, AbstractClusterSubmitter):
            self.submitter.store_dir = self.__bout_paths.bout_inp_dst_dir

        self.__restart_from = None
        self.restart_from = restart_from
        logging.info("Done: Making an BoutRunExecutor object")

    @property
    def restart_from(self) -> Optional[Path]:
        """
        Set the properties of self.restart from and update bout_inp_dst_dir.

        The bout_inp_dst_dir is updated to reflect that this is a restart run.

        The new bout_inp_dst_dir will be the same as
        bout_run_setup.executor.restart_from with _restart_/d* appended
        /d* will be the next digit based on the number of other restart directories

        Notes
        -----
        This will not copy the restart files as the restart files may not be ready.
        Copying of files can either be done manually using
        bout_runner.utils.file_operations.copy_restart_files or automatically by
        using BoutRunner.__inject_copy_restart_files_node which is called from
        BoutRunner.__prepare_run

        See Also
        --------
        bout_runners.runner.bout_runner.BoutRunner.__inject_copy_restart_files_node
            Search for restart files, make a restart node where needed
        """
        return self.__restart_from

    @restart_from.setter
    def restart_from(self, restart_from: Optional[Path]) -> None:
        self.__restart_from = restart_from
        if restart_from is not None:
            logging.debug(
                "Changing bout_paths.bout_inp_dst_dir as restart_from is not None"
            )
            restart_dir_parent = restart_from.parent
            restart_dir_name = restart_from.name
            restart_dirs = list(restart_dir_parent.glob(f"{restart_dir_name}*"))
            restart_number = 0
            restart_numbers = list()
            pattern = r"_restart_(\d)+$"
            for restart_dir in restart_dirs:
                match = re.search(pattern, restart_dir.name)
                if match is not None:
                    # NOTE: The zeroth group is the matching string
                    restart_numbers.append(int(match.group(1)))
            if len(restart_numbers) != 0:
                restart_numbers.sort()
                restart_number = restart_numbers[-1] + 1
            prev_inp_dst_dir = self.bout_paths.bout_inp_dst_dir
            stripped_restart_dir_name = re.sub(pattern, "", restart_dir_name)
            new_inp_dst_dir = restart_dir_parent.joinpath(
                f"{stripped_restart_dir_name}_restart_{restart_number}"
            )
            self.bout_paths.bout_inp_dst_dir = new_inp_dst_dir
            logging.debug(
                "bout_run_setup.bout_paths.bout_inp_dst_dir set from %s to %s",
                prev_inp_dst_dir,
                new_inp_dst_dir,
            )

    @property
    def bout_paths(self) -> BoutPaths:
        """
        Get the properties of self.bout_paths.

        Returns
        -------
        self.__bout_paths : BoutPaths
            Object containing the paths

        Notes
        -----
        The bout_paths is read only
        """
        return self.__bout_paths

    @property
    def exec_name(self) -> str:
        """
        Set the properties of self.bout_paths.

        Returns
        -------
        self.__bout_paths : BoutPaths
            Object containing the paths

        Notes
        -----
        The exec_name is read only
        """
        return self.__make.exec_name

    @property
    def run_parameters(self) -> RunParameters:
        """
        Get the properties of self.run_parameters.

        Returns
        -------
        self.__run_parameters : RunParameters
            Object containing the run parameters

        Notes
        -----
        The run_parameters is read only
        """
        return self.__run_parameters

    def get_execute_command(self) -> str:
        """
        Return the execute command string.

        Returns
        -------
        command : str
            The terminal command for executing the run
        """
        mpi_cmd = "mpirun -np"

        # NOTE: No spaces if parameters are None
        command = (
            f"{mpi_cmd} "
            f"{self.submitter.processor_split.number_of_processors} "
            f"{self.__bout_paths.project_path.joinpath(self.exec_name)} "
            f"-d {self.__bout_paths.bout_inp_dst_dir} "
            f"{self.__run_parameters.run_parameters_str}"
        )
        return command

    def execute(self, restart: bool = False) -> None:
        """
        Execute a BOUT++ run.

        Parameters
        ----------
        restart : bool
            If True the 'restart' will be appended to the command string
        """
        # Make the project if not already made
        self.__make.run_make()
        # Submit the command
        command = self.get_execute_command()
        if restart:
            command += " restart"
        self.submitter.submit_command(command)