Beispiel #1
0
    def _constructSpatialGrid(self):
        """
        Build spatial grid.

        If you do not enter latticeDimensions, a unit grid will be produced which must
        be adjusted to the proper dimensions (often by inspection of children) at a
        later time.
        """
        geom = self.geom
        maxIndex = self._getMaxIndex()
        runLog.extra("Creating the spatial grid")
        if geom in (geometry.RZT, geometry.RZ):
            if self.gridBounds is None:
                # This check is regrattably late. It would be nice if we could validate
                # that bounds are provided if R-Theta mesh is being used.
                raise InputError(
                    "Grid bounds must be provided for `{}` to specify a grid with "
                    "r-theta components.".format(self.name))
            for key in ("theta", "r"):
                if key not in self.gridBounds:
                    raise InputError(
                        "{} grid bounds were not provided for `{}`.".format(
                            key, self.name))

            # convert to list, otherwise it is a CommentedSeq
            theta = numpy.array(self.gridBounds["theta"])
            radii = numpy.array(self.gridBounds["r"])
            for l, name in ((theta, "theta"), (radii, "radii")):
                if not _isMonotonicUnique(l):
                    raise InputError(
                        "Grid bounds for {}:{} is not sorted or contains "
                        "duplicates. Check blueprints.".format(
                            self.name, name))
            spatialGrid = grids.ThetaRZGrid(bounds=(theta, radii, (0.0, 0.0)))
        if geom == geometry.HEX:
            pitch = self.latticeDimensions.x if self.latticeDimensions else 1.0
            # add 2 for potential dummy assems
            spatialGrid = grids.HexGrid.fromPitch(pitch, numRings=maxIndex + 2)
        elif geom == geometry.CARTESIAN:
            # if full core or not cut-off, bump the first assembly from the center of
            # the mesh into the positive values.
            xw, yw = ((self.latticeDimensions.x,
                       self.latticeDimensions.y) if self.latticeDimensions else
                      (1.0, 1.0))
            isOffset = (self.symmetry and geometry.THROUGH_CENTER_ASSEMBLY
                        not in self.symmetry)
            spatialGrid = grids.CartesianGrid.fromRectangle(xw,
                                                            yw,
                                                            numRings=maxIndex +
                                                            1,
                                                            isOffset=isOffset)
        runLog.debug("Built grid: {}".format(spatialGrid))
        # set geometric metadata on spatialGrid. This information is needed in various
        # parts of the code and is best encapsulated on the grid itself rather than on
        # the container state.
        spatialGrid.geomType = self.geom
        spatialGrid.symmetry = self.symmetry
        return spatialGrid
Beispiel #2
0
 def gridContents(self, value):  # pylint: disable=method-hidden
     if value is None:
         return True
     if not all(isinstance(key, tuple) for key in value.keys()):
         raise InputError(
             "Keys need to be presented as [i, j]. Check the blueprints."
         )
Beispiel #3
0
    def _moveFiles(self):
        # check for orificed flow bounds files. These will often be named based on the
        # case that this one is dependent upon, but not always. For example, testSassys
        # is dependent on the safety case but requires physics bounds files.  now copy
        # the files over
        copyFilesFrom = [
            filePath
            for possiblePat in self.cs["copyFilesFrom"]
            for filePath in glob.glob(possiblePat)
        ]
        copyFilesTo = self.cs["copyFilesTo"]

        if len(copyFilesTo) in (len(copyFilesFrom), 0, 1):
            # if any files to copy, then use the first as the default, i.e. len() == 1,
            # otherwise assume '.'
            default = copyFilesTo[0] if any(copyFilesTo) else "."
            for filename, dest in zip_longest(
                copyFilesFrom, copyFilesTo, fillvalue=default
            ):
                pathTools.copyOrWarn("copyFilesFrom", filename, dest)
        else:
            runLog.error(
                "cs['copyFilesTo'] must either be length 1, 0, or have the same number of entries as "
                "cs['copyFilesFrom']. Actual values:\n"
                "    copyFilesTo   : {}\n"
                "    copyFilesFrom : {}".format(copyFilesTo, copyFilesFrom)
            )
            raise InputError("Failed to process copyFilesTo/copyFilesFrom")
Beispiel #4
0
    def _selectNuclidesToExpandForModeling(cs):
        elementalsToSkip = set()
        endf70Elementals = [
            nuclideBases.byName[name] for name in ["C", "V", "ZN"]
        ]
        endf71Elementals = [nuclideBases.byName[name] for name in ["C"]]

        if "MCNP" in cs["neutronicsKernel"]:
            if int(cs["mcnpLibrary"]) == 50:
                elementalsToSkip.update(
                    nuclideBases.instances)  # skip expansion
            # ENDF/B VII.0
            elif 70 <= int(cs["mcnpLibrary"]) <= 79:
                elementalsToSkip.update(endf70Elementals)
            # ENDF/B VII.1
            elif 80 <= int(cs["mcnpLibrary"]) <= 89:
                elementalsToSkip.update(endf71Elementals)
            else:
                raise InputError(
                    "Failed to determine nuclides for modeling. "
                    "The `mcnpLibrary` setting value ({}) is not supported.".
                    format(cs["mcnpLibrary"]))

        elif cs["xsKernel"] in ["SERPENT", "MC2v3", "MC2v3-PARTISN"]:
            elementalsToSkip.update(endf70Elementals)
        elif cs["xsKernel"] == "MC2v2":
            elementalsToSkip.update(nuclideBases.instances)  # skip expansion

        return elementalsToSkip
Beispiel #5
0
    def _checkAssemblyAreaConsistency(self, cs):
        references = None
        for a in self.assemblies.values():
            if references is None:
                references = (a, a.getArea())
                continue

            assemblyArea = a.getArea()
            if abs(references[1] - assemblyArea) > 1e-9 and not hasattr(
                a.location, "ThRZmesh"
            ):
                # if the location has a mesh then the assemblies can have irregular areas
                runLog.error("REFERENCE COMPARISON ASSEMBLY:")
                references[0][0].printContents()
                runLog.error("CURRENT COMPARISON ASSEMBLY:")
                a[0].printContents()
                raise InputError(
                    "Assembly {} has a different area {} than assembly {} {}.  Check inputs for accuracy".format(
                        a, assemblyArea, references[0], references[1]
                    )
                )

            blockArea = a[0].getArea()
            for b in a[1:]:
                if (
                    abs(b.getArea() - blockArea) / blockArea
                    > cs["acceptableBlockAreaError"]
                ):
                    runLog.error("REFERENCE COMPARISON BLOCK:")
                    a[0].printContents(includeNuclides=False)
                    runLog.error("CURRENT COMPARISON BLOCK:")
                    b.printContents(includeNuclides=False)

                    for c in b.getChildren():
                        runLog.error(
                            "{0} area {1} effective area {2}"
                            "".format(c, c.getArea(), c.getVolume() / b.getHeight())
                        )

                    raise InputError(
                        "Block {} has a different area {} than block {} {}. Check inputs for accuracy".format(
                            b, b.getArea(), a[0], blockArea
                        )
                    )
Beispiel #6
0
    def _selectNuclidesToExpandForModeling(cs):
        elementalsToSkip = set()
        endf70Elementals = [
            nuclideBases.byName[name] for name in ["C", "V", "ZN"]
        ]
        endf71Elementals = [nuclideBases.byName[name] for name in ["C"]]
        endf80Elementals = []

        if "MCNP" in cs["neutronicsKernel"]:
            if int(cs["mcnpLibrary"]) == 50:
                elementalsToSkip.update(
                    nuclideBases.instances)  # skip expansion
            # ENDF/B VII.0
            elif 70 <= int(cs["mcnpLibrary"]) <= 79:
                elementalsToSkip.update(endf70Elementals)
            # ENDF/B VII.1
            elif 80 <= int(cs["mcnpLibrary"]) <= 89:
                elementalsToSkip.update(endf71Elementals)
            else:
                raise InputError(
                    "Failed to determine nuclides for modeling. "
                    "The `mcnpLibrary` setting value ({}) is not supported.".
                    format(cs["mcnpLibrary"]))

        elif cs["xsKernel"] in ["SERPENT", "MC2v3", "MC2v3-PARTISN"]:
            elementalsToSkip.update(endf70Elementals)
        elif cs["xsKernel"] == "DRAGON":
            # Users need to use default nuclear lib name. This is documented.
            dragLib = cs["dragonDataPath"]
            # only supports ENDF/B VII/VIII at the moment.
            if "7r0" in dragLib:
                elementalsToSkip.update(endf70Elementals)
            elif "7r1" in dragLib:
                elementalsToSkip.update(endf71Elementals)
            elif "8r0" in dragLib:
                elementalsToSkip.update(endf80Elementals)
            else:
                raise ValueError(
                    f"Unrecognized DRAGLIB name: {dragLib} Use default file name."
                )

        elif cs["xsKernel"] == "MC2v2":
            elementalsToSkip.update(nuclideBases.instances)  # skip expansion

        return elementalsToSkip
Beispiel #7
0
def autoSelectElementsToKeepFromSettings(cs):
    """
    Intelligently choose elements to expand based on settings.

    If settings point to a particular code and library and we know
    that combo requires certain elementals to be expanded, we
    flag them here to make the user input as simple as possible.

    This determines both which elementals to keep and which
    specific expansion subsets to use.

    Notes
    -----
    This logic is expected to be moved to respective plugins in time.

    Returns
    -------
    elementalsToKeep : set
        Set of NaturalNuclideBase instances to not expand into
        natural isotopics.
    expansions : dict
        Element to list of nuclides for expansion.
        For example: {oxygen: [oxygen16]} indicates that all
        oxygen should be expanded to O16, ignoring natural
        O17 and O18. (variables are Natural/NuclideBases)

    """
    elementalsToKeep = set()
    oxygenElementals = [nuclideBases.byName["O"]]
    hydrogenElementals = [nuclideBases.byName[name] for name in ["H"]]
    endf70Elementals = [nuclideBases.byName[name] for name in ["C", "V", "ZN"]]
    endf71Elementals = [nuclideBases.byName[name] for name in ["C"]]
    endf80Elementals = []
    elementalsInMC2 = set()
    expansionStrings = {}
    mc2Expansions = {
        "HE": ["HE4"],  # neglect HE3
        "O": ["O16"],  # neglect O17 and O18
        "W": ["W182", "W183", "W184", "W186"],  # neglect W180
    }
    mcnpExpansions = {"O": ["O16"]}

    for element in elements.byName.values():
        # any NaturalNuclideBase that's available in MC2 libs
        nnb = nuclideBases.byName.get(element.symbol)
        if nnb and nnb.mc2id:
            elementalsInMC2.add(nnb)

    if "MCNP" in cs["neutronicsKernel"]:
        expansionStrings.update(mcnpExpansions)
        if int(cs["mcnpLibrary"]) == 50:
            elementalsToKeep.update(nuclideBases.instances)  # skip expansion
        # ENDF/B VII.0
        elif 70 <= int(cs["mcnpLibrary"]) <= 79:
            elementalsToKeep.update(endf70Elementals)
        # ENDF/B VII.1
        elif 80 <= int(cs["mcnpLibrary"]) <= 89:
            elementalsToKeep.update(endf71Elementals)
        else:
            raise InputError(
                "Failed to determine nuclides for modeling. "
                "The `mcnpLibrary` setting value ({}) is not supported.".
                format(cs["mcnpLibrary"]))

    elif cs["xsKernel"] in ["", "SERPENT", "MC2v3", "MC2v3-PARTISN"]:
        elementalsToKeep.update(endf70Elementals)
        expansionStrings.update(mc2Expansions)

    elif cs["xsKernel"] == "DRAGON":
        # Users need to use default nuclear lib name. This is documented.
        dragLib = cs["dragonDataPath"]
        # only supports ENDF/B VII/VIII at the moment.
        if "7r0" in dragLib:
            elementalsToKeep.update(endf70Elementals)
        elif "7r1" in dragLib:
            elementalsToKeep.update(endf71Elementals)
        elif "8r0" in dragLib:
            elementalsToKeep.update(endf80Elementals)
            elementalsToKeep.update(hydrogenElementals)
            elementalsToKeep.update(oxygenElementals)
        else:
            raise ValueError(
                f"Unrecognized DRAGLIB name: {dragLib} Use default file name.")

    elif cs["xsKernel"] == "MC2v2":
        # strip out any NaturalNuclideBase with no mc2id (not on mc2Nuclides.yaml)
        elementalsToKeep.update(elementalsInMC2)
        expansionStrings.update(mc2Expansions)

    # convert convenient string notation to actual NuclideBase objects
    expansions = {}
    for nnb, nbs in expansionStrings.items():
        expansions[nuclideBases.byName[nnb]] = [
            nuclideBases.byName[nb] for nb in nbs
        ]

    return elementalsToKeep, expansions
Beispiel #8
0
    def _constructSpatialGrid(self):
        """
        Build spatial grid.

        If you do not enter latticeDimensions, a unit grid will be produced which must
        be adjusted to the proper dimensions (often by inspection of children) at a
        later time.
        """
        symmetry = (geometry.SymmetryType.fromStr(self.symmetry)
                    if self.symmetry else None)
        geom = self.geom
        maxIndex = self._getMaxIndex()
        runLog.extra("Creating the spatial grid")
        if geom in (geometry.RZT, geometry.RZ):
            if self.gridBounds is None:
                # This check is regrattably late. It would be nice if we could validate
                # that bounds are provided if R-Theta mesh is being used.
                raise InputError(
                    "Grid bounds must be provided for `{}` to specify a grid with "
                    "r-theta components.".format(self.name))
            for key in ("theta", "r"):
                if key not in self.gridBounds:
                    raise InputError(
                        "{} grid bounds were not provided for `{}`.".format(
                            key, self.name))

            # convert to list, otherwise it is a CommentedSeq
            theta = numpy.array(self.gridBounds["theta"])
            radii = numpy.array(self.gridBounds["r"])
            for l, name in ((theta, "theta"), (radii, "radii")):
                if not _isMonotonicUnique(l):
                    raise InputError(
                        "Grid bounds for {}:{} is not sorted or contains "
                        "duplicates. Check blueprints.".format(
                            self.name, name))
            spatialGrid = grids.ThetaRZGrid(bounds=(theta, radii, (0.0, 0.0)))
        if geom in (geometry.HEX, geometry.HEX_CORNERS_UP):
            pitch = self.latticeDimensions.x if self.latticeDimensions else 1.0
            # add 2 for potential dummy assems
            spatialGrid = grids.HexGrid.fromPitch(
                pitch,
                numRings=maxIndex + 2,
                pointedEndUp=geom == geometry.HEX_CORNERS_UP,
            )
        elif geom == geometry.CARTESIAN:
            # if full core or not cut-off, bump the first assembly from the center of
            # the mesh into the positive values.
            xw, yw = ((self.latticeDimensions.x,
                       self.latticeDimensions.y) if self.latticeDimensions else
                      (1.0, 1.0))

            # Specifically in the case of grid blueprints, where we have grid contents
            # available, we can also infer "through center" based on the contents.
            # Note that the "through center" symmetry check cannot be performed when
            # the grid contents has not been provided (i.e., None or empty).
            if self.gridContents:
                nx = (max(key[0] for key in self.gridContents) -
                      min(key[0] for key in self.gridContents) + 1)
                ny = (max(key[1] for key in self.gridContents) -
                      min(key[1] for key in self.gridContents) + 1)
                if nx == ny and nx % 2 == 1:
                    symmetry.isThroughCenterAssembly = True

            isOffset = symmetry is not None and not symmetry.isThroughCenterAssembly

            spatialGrid = grids.CartesianGrid.fromRectangle(xw,
                                                            yw,
                                                            numRings=maxIndex +
                                                            1,
                                                            isOffset=isOffset)
        runLog.debug("Built grid: {}".format(spatialGrid))
        # set geometric metadata on spatialGrid. This information is needed in various
        # parts of the code and is best encapsulated on the grid itself rather than on
        # the container state.
        spatialGrid._geomType: str = str(self.geom)
        self.symmetry = str(symmetry)
        spatialGrid._symmetry: str = self.symmetry
        return spatialGrid