Skip to content
Snippets Groups Projects
pygriffin.py 5.51 KiB
Newer Older
from numbers import Integral
from pathlib import Path
import subprocess
from collections import Iterable
from . import checkvalue as cv
from .config import PyGriffinConfig

class PyGriffin:
    """
    Class for connecting PyGriffin inputs and running the problems

    Parameters
    ----------
    input : str or Path object
        Location of Griffin input file
    n_procs : int
        Number of processes in Griffin run
    """

    def __init__(self, input, mesh=None, n_procs=1):
        self.config = PyGriffinConfig()
        self.input = input
    def run(self, input=None, mesh=None, cwd=None, other_args=None, color=True):
        Parameters
        ----------
        cwd : str or Path
            Directory from which to run Griffin

        Returns
        -------
        int
            Errorcode of the Griffin run (0 is success)
        """

        cmd = []

        # set custom values if requested in method call
        input_file = self.input if input is None else input
        mesh_file = self.mesh if mesh is None else mesh

            if self.config.mpi_enabled:
                cmd += ['mpirun', '-n', str(self.n_procs)]
            else:
                msg = ("MPI is not enabled for this Griffin executable. "
                       "The n_procs argument will be ignored.")
                warnings.warn(msg)

        # add griffin executable to command line
        cmd.append(str(self.config.griffin_exec))

        cmd += ['-i', str(input_file)]

        # append the mesh file to the command if needed
        if str(mesh_file).endswith('.i'):
            cmd.append(str(mesh_file))
        if cwd is not None:
            cwd = Path(cwd)
        else:
            cwd = Path('.')
            msg = ("Specified working directory "
            "doesn't exist: {}".format(cwd))
            raise ValueError(msg)

        if other_args is not None:
            cv.check_type('Additional Griffin arguments', other_args, Iterable)
            cmd += other_args

        # request colorless output
        if not color:
            cmd += ['--color', 'off']

        p = subprocess.Popen(cmd, universal_newlines=True, cwd=str(cwd))
    def process_xs(self, overwrite=False, particle='neutron', cwd=None):
        """
        Runs ISOXML on the current set of cross sections

        Parameters
        ----------
        overwrite : bool
            Overwrite the current xs file if True (default False)
        particle : str
            Indicates what particle type the cross section data is.
            One of ('neutron', 'gamma', 'photon')
        Returns
        -------
            Path to the resulting ISOXML file
        """

        if str(self.xs).endswith('xml'):
            return self.xs

        cv.check_value('Particle data', particle, ('neutron', 'gamma', 'photon'))
        if particle in ('gamma', 'photon'):
            p_flag = '-p'
        else:
            p_flag = '-n'

        if cwd is not None:
            cwd = Path(cwd)
        else:
            cwd = Path('.')

        if cwd and not cwd.is_dir():
            msg = ("Specified working directory "
            "doesn't exist: {}".format(cwd))
            raise ValueError(msg)

        # run isoxml executable on the current xs file
        cmd = [str(self.config.isoxml_exec), p_flag, str(self.xs)]
        p = subprocess.Popen(cmd, universal_newlines=True, cwd=str(cwd))

        p.wait()

        # construct the name of the new xs file and return it
        name_parts = str(self.xs).split('.')
        name_parts[-1] = 'xml'
        xs_name = '.'.join(name_parts)

        return xs_name

    def generate_mesh(self, overwrite=False):
        """
        Generates the mesh for the griffin-problem if needed

        Parameters
        ----------
        overwrite : bool
            Overwrite the current mesh if True (default False)

        Returns
        -------
            Path to the mesh file
        """
        # if a mesh file was passed, no need to generate a new one
        if str(self.mesh).endswith('.e'):
            return self.mesh

        # if a mesh input is set, generate the mesh file
        if str(self.mesh).endswith('.i'):
            name_parts = str(self.mesh).split('.')
            name_parts[-1] = 'e'
            mesh_name = '.'.join(name_parts)
            self.run(input=self.mesh, other_args=['--mesh-only', mesh_name])
            return Path(mesh_name).resolve().absolute()

    def __call__(self, cwd=None):
        return self.run(cwd)
    @property
    def input(self):
        return self._input

    @input.setter
    def input(self, input):
        cv.check_type('Griffin input', input, (str, Path))
        self._input = Path(input).absolute()

    @property
    def mesh(self):
        return self._mesh

    @mesh.setter
    def mesh(self, mesh):
        cv.check_type('Griffin mesh', mesh, (str, Path))

    @property
    def xs(self):
        return self._xs

    @xs.setter
    def xs(self, xs):
        cv.check_type('Cross section file', xs, (str, Path))
        self._xs = xs

    @property
    def mpi_enabled(self):
        return self.config.mpi_enabled

    @property
    def n_procs(self):
        return self._n_procs

    @n_procs.setter
    def n_procs(self, procs):
        cv.check_type('Griffin processes', procs, Integral)
        cv.check_greater_than('Griffin processes', procs, 0)
        self._n_procs = procs