diff --git a/csg2csg/Input.py b/csg2csg/Input.py index 5f09c38..439246c 100644 --- a/csg2csg/Input.py +++ b/csg2csg/Input.py @@ -1,5 +1,6 @@ # /usr/env/python3 - +from csg2csg.UniverseCard import UniverseCard, uni_fill, mat_fill +import copy class InputDeck: """InputDeck class from which other concrete examples @@ -22,6 +23,7 @@ def __init__(self, filename, quick=False): # TODO maybe these should be dictionaries by index self.cell_list = [] self.surface_list = [] + self.universe_list = [] self.last_free_surface_index = 0 self.importance_list = {} # dictionary of importances self.material_list = {} @@ -76,6 +78,7 @@ def from_input(self, InputDeckClass): self.cell_list = InputDeckClass.cell_list self.surface_list = InputDeckClass.surface_list self.material_list = InputDeckClass.material_list + self.universe_list = InputDeckClass.universe_list return # step through each cell and determine if the cell can @@ -87,3 +90,43 @@ def split_unions(self): # match any splitable unions - this will look like (stuff):(stuff):(stuff) # so we could make 3 cells from that continue + + # prepare universe entries given cells + def create_universes_from_cells(self): + universe_ids = set() + + # count unique universe IDs + universe_ids.update(int(cell.cell_universe) for cell in self.cell_list) + + # Maybe set is empty? In which case, put every cell in universe 1 + #if not universe_ids: + # universe_ids.add(1) + # for cell in self.cell_list: + # cell.cell_universe = 1 + + for uni in universe_ids: + newUni = UniverseCard() + newUni.build_from_cell_list(uni,self.cell_list) + self.universe_list.append(newUni) + + # Need to ensure there is both a root universe and, if cells, + # a cell universe to hold them. This may imply adding another + # universe to the geometry and changing the cell universe IDs. + # First need to identify whether the root universe has cells. + # If so, duplicate the universe, make the new universe a cell + # universe without being root, remove cells from the root universe, + # and make the root universe contain the new universe. + for uni in self.universe_list: + if uni.is_root: + if uni.cell_list: + newID = max(universe_ids) + 1 + newUni = copy.copy(uni) + newUni.universe_id = newID + newUni.is_root = 0 + newUni.border_surface = 0 + uni.cell_list = [] + uni.fill_type = uni_fill + uni.fill_id = newID + self.universe_list.append(newUni) + + return diff --git a/csg2csg/MCNPCellCard.py b/csg2csg/MCNPCellCard.py index f8f6281..a975c08 100644 --- a/csg2csg/MCNPCellCard.py +++ b/csg2csg/MCNPCellCard.py @@ -313,7 +313,7 @@ def __interpret(self): tokens = self.text_string.split() tokens = string.split() - + self.cell_id = int(tokens[0]) material_number = int(tokens[1]) if material_number > 0: diff --git a/csg2csg/MCNPInput.py b/csg2csg/MCNPInput.py index 142923f..400a390 100644 --- a/csg2csg/MCNPInput.py +++ b/csg2csg/MCNPInput.py @@ -635,15 +635,15 @@ def __simplify_cones(self): # loop over the surfaces for surf in self.surface_list: # if we are a cone - print( - surf.surface_type, - surf.surface_type - in [ - SurfaceCard.SurfaceType["CONE_X"], - SurfaceCard.SurfaceType["CONE_Y"], - SurfaceCard.SurfaceType["CONE_Z"], - ], - ) + #print( + # surf.surface_type, + # surf.surface_type + # in [ + # SurfaceCard.SurfaceType["CONE_X"], + # SurfaceCard.SurfaceType["CONE_Y"], + # SurfaceCard.SurfaceType["CONE_Z"], + # ], + #) if surf.surface_type in [ SurfaceCard.SurfaceType["CONE_X"], SurfaceCard.SurfaceType["CONE_Y"], @@ -1166,7 +1166,7 @@ def __get_surface_cards(self, idx): while True: surf_line = strip_dollar_comments(self.file_lines[idx]) if surf_line.isspace(): - logging.debug("%s", "found end of cell cards at line " + str(idx)) + logging.debug("%s", "found end of surface cards at line " + str(idx)) idx += 1 break @@ -1343,7 +1343,7 @@ def process(self): self.__get_material_cards(idx) # need to flatten first to get transformed surface in the # correct place - self.__simplify_cones() + #self.__simplify_cones() self.__flatten_macrobodies() self.__explode_nots() @@ -1401,7 +1401,7 @@ def __write_mcnp_materials(self, filestream): filestream, self.material_list[material], self.preserve_xsid ) - # main write MCNP method, depnds on where the geometry + # main write MCNP method, depends on where the geometry # came from def write_mcnp(self, filename, flat=True): f = open(filename, "w") diff --git a/csg2csg/MCNPSurfaceCard.py b/csg2csg/MCNPSurfaceCard.py index fda1aef..16cbafb 100644 --- a/csg2csg/MCNPSurfaceCard.py +++ b/csg2csg/MCNPSurfaceCard.py @@ -142,7 +142,6 @@ def mcnp_cone_y(SurfaceCard): # write the mcnp form of an cone aligned along the z axis def mcnp_cone_z(SurfaceCard): string = "k/z " - print(SurfaceCard.surface_coefficients) string += str(SurfaceCard.surface_coefficients[0]) + " " string += str(SurfaceCard.surface_coefficients[1]) + " " string += str(SurfaceCard.surface_coefficients[2]) + " " @@ -224,7 +223,6 @@ def write_mcnp_surface(filestream, SurfaceCard): elif SurfaceCard.surface_type == SurfaceCard.SurfaceType["PLANE_Y"]: string += mcnp_plane_y(SurfaceCard) elif SurfaceCard.surface_type == SurfaceCard.SurfaceType["PLANE_Z"]: - print(SurfaceCard) string += mcnp_plane_z(SurfaceCard) elif SurfaceCard.surface_type == SurfaceCard.SurfaceType["CYLINDER_X"]: string += mcnp_cylinder_x(SurfaceCard) diff --git a/csg2csg/MaterialCard.py b/csg2csg/MaterialCard.py index 56b0f0e..b7f5591 100644 --- a/csg2csg/MaterialCard.py +++ b/csg2csg/MaterialCard.py @@ -170,3 +170,4 @@ def explode_elements(self): for key in new_nuclides.keys(): self.composition_dictionary[key] = new_nuclides[key] self.xsid_dictionary[key] = "" + diff --git a/csg2csg/SCONECellCard.py b/csg2csg/SCONECellCard.py new file mode 100644 index 0000000..ed36681 --- /dev/null +++ b/csg2csg/SCONECellCard.py @@ -0,0 +1,78 @@ +#!/usr/env/python3 + +from csg2csg.MCNPFormatter import mcnp_line_formatter + +from csg2csg.CellCard import CellCard +from enum import Enum +import re +import math + +# turn the generic operation type into a scone relevant text string +def scone_op_from_generic(Operation): + # if we are not of type operator - we are string do nowt + if not isinstance(Operation, CellCard.OperationType): + if Operation == "(": + return " < " + elif Operation == ")": + return " > " + else: + return Operation + else: + # otherwise we need to do something + if Operation == CellCard.OperationType["NOT"]: + string = " # " + elif Operation == CellCard.OperationType["AND"]: + string = " " + elif Operation == CellCard.OperationType["UNION"]: + string = " : " + else: + string = "unknown operation" + # return the operation + return string + + +# write the cell card for a scone cell given a generic cell card +def write_scone_cell(filestream, CellCard): + + # In root universe, identify ....... + # Presently assumes only two cells in the root, with one surface, + # as in Serpent. + # Allow multiple cells in root. Fix this later! + #if (CellCard.cell_universe == 0 and + #CellCard.cell_surface_list[0] >= 0): + # return + + # print (CellCard) + string = str(CellCard.cell_id) + " { type unionCell; id " + string += str(CellCard.cell_id) + "; " + + # Need to keep track of universe definitions and return + # to write these separately + if CellCard.cell_fill != 0: + string += " filltype uni; universe " + str(int(CellCard.cell_fill) + 1) + "; " + + # Doesn't have a universe - has a material + # Due to SCONE weirdness, all materials are preceded with an 'm' + if CellCard.cell_fill == 0: + # material 0 is void + string += " filltype mat; material " + if CellCard.cell_material_number == 0: + string += " void; " + else: + string += "m" + str(CellCard.cell_material_number) + "; " + + string += "surfaces [ " + + # build the cell description + for item in CellCard.cell_interpreted: + string += scone_op_from_generic(item) + + string += " ]; }\n" + + # removes any multiple spaces + string = re.sub(" +", " ", string) + + string = mcnp_line_formatter(string) + + filestream.write(string) + diff --git a/csg2csg/SCONEInput.py b/csg2csg/SCONEInput.py new file mode 100644 index 0000000..30e7211 --- /dev/null +++ b/csg2csg/SCONEInput.py @@ -0,0 +1,101 @@ +# /usr/env/python3 + +from csg2csg.Input import InputDeck +from csg2csg.SCONESurfaceCard import write_scone_surface +from csg2csg.SCONECellCard import write_scone_cell +from csg2csg.SCONEMaterialCard import write_scone_material +from csg2csg.SCONEUniverseCard import write_scone_universe + +import logging +import re + + +class SCONEInput(InputDeck): + """SCONEInput class - does the actual processing""" + + # constructor + def __init__(self, filename=""): + InputDeck.__init__(self, filename) + + # open the geometry card + def __write_scone_geometry_start(self, filestream): + filestream.write("geometry { \n") + filestream.write("type geometryStd; \n") + # Surely there is a way to customise this? Am I missing a + # method somewhere? For now I will leave as vacuum - should be easy + # for the user to change + filestream.write("boundary (0 0 0 0 0 0); \n") + filestream.write("graph {type shrunk;} \n") + return + + # close the geometry card + def __write_scone_geometry_end(self, filestream): + filestream.write("} \n") + return + + # open the nuclear data card + def __write_scone_data_start(self, filestream): + filestream.write("nuclearData { \n") + filestream.write("handles { \n") + filestream.write("ce {type aceNeutronDatabase; ") + filestream.write("aceLibrary $SCONE_ACE; ures 0;} \n") + filestream.write("} \n") + return + + # close the data card + def __write_scone_data_end(self, filestream): + filestream.write("} \n") + return + + # write the SCONE surface definitions + def __write_scone_surfaces(self, filestream): + filestream.write("! --- surface definitions --- !\n") + filestream.write("surfaces { \n") + for surface in self.surface_list: + write_scone_surface(filestream, surface) + filestream.write("} \n") + return + + # Write the SCONE Cell definitions + def __write_scone_cells(self, filestream): + filestream.write("! --- cell definitions --- !\n") + filestream.write("cells { \n") + for cell in self.cell_list: + write_scone_cell(filestream, cell) + filestream.write("} \n") + return + + # Write the SCONE universe definitions + # Most codes have universes implicit in their cells, complicating things + # slightly. + def __write_scone_universes(self, filestream): + filestream.write("! --- universe definitions --- !\n") + filestream.write("universes { \n") + for universe in self.universe_list: + write_scone_universe(filestream, universe) + filestream.write("} \n") + + # write the material compositions + def __write_scone_materials(self, filestream): + filestream.write("! --- material definitions --- !\n") + filestream.write("materials { \n") + for material in self.material_list: + write_scone_material(filestream, self.material_list[material]) + filestream.write("} \n") + return + + + # main write scone method, depending upon where the geometry + # came from + def write_scone(self, filename, flat=True): + f = open(filename, "w") + self.__write_scone_geometry_start(f) + self.__write_scone_surfaces(f) + self.__write_scone_cells(f) + self.create_universes_from_cells() + self.__write_scone_universes(f) + self.__write_scone_geometry_end(f) + self.__write_scone_data_start(f) + self.__write_scone_materials(f) + self.__write_scone_data_end(f) + f.close() diff --git a/csg2csg/SCONEMaterialCard.py b/csg2csg/SCONEMaterialCard.py new file mode 100644 index 0000000..fa7e001 --- /dev/null +++ b/csg2csg/SCONEMaterialCard.py @@ -0,0 +1,38 @@ +#!/usr/env/python3 + +from csg2csg.MaterialCard import MaterialCard +from csg2csg.MCNPFormatter import get_fortran_formatted_number + +# write a specific scone material card +def write_scone_material(filestream, MaterialCard): + + string = "! " + MaterialCard.material_name + " \n" + string += "m" + str(MaterialCard.material_number) + " { \n" + string += "composition { \n" + # Stick on .03 regardless until something to read temperature + # from MCNP is added! + # Multiply by adens because SCONE requires absolute densities + dens = MaterialCard.density + if dens > 0: + adens = dens + else: + molar_mass = 0 + for nuc in MaterialCard.composition_dictionary: + molar_mass += MaterialCard.composition_dictionary[nuc] * (int(nuc) % 1000) + + adens = -dens * 6.02214e-01 / molar_mass + + for nuc in MaterialCard.composition_dictionary: + string += "{}.03 {:e}; \n".format( + nuc, MaterialCard.composition_dictionary[nuc] * adens + ) + + string += "} \n" + + # set the relevant colour + if MaterialCard.material_colour: + string += "rgb (" + MaterialCard.material_colour + "); \n" + + string += "} \n" + filestream.write(string) + return diff --git a/csg2csg/SCONESurfaceCard.py b/csg2csg/SCONESurfaceCard.py new file mode 100644 index 0000000..761dd83 --- /dev/null +++ b/csg2csg/SCONESurfaceCard.py @@ -0,0 +1,345 @@ +#!/usr/env/python3 + +from csg2csg.SurfaceCard import SurfaceCard +from math import sqrt, atan, degrees + +# write the general form of a plane +def scone_plane_string(SurfaceCard): + string = " plane; coeffs ( " + string += str(SurfaceCard.surface_coefficients[0]) + " " + string += str(SurfaceCard.surface_coefficients[1]) + " " + string += str(SurfaceCard.surface_coefficients[2]) + " " + string += str(SurfaceCard.surface_coefficients[3]) + "); } \n" + return string + + +# write the specific x form of the plane +def scone_plane_x_string(SurfaceCard): + string = " xPlane; x0 " + str(SurfaceCard.surface_coefficients[3]) + string += "; } \n" + return string + + +# write the specific y form of the plane +def scone_plane_y_string(SurfaceCard): + string = " yPlane; y0 " + str(SurfaceCard.surface_coefficients[3]) + string += "; } \n" + return string + + +# write the specific z form of the plane +def scone_plane_z_string(SurfaceCard): + string = " zPlane; z0 " + str(SurfaceCard.surface_coefficients[3]) + string += "; } \n" + return string + + +# write a cylinder_x +def scone_cylinder_x(SurfaceCard): + string = " xCylinder; radius " + str(SurfaceCard.surface_coefficients[2]) + string += "; origin ( 0.0 " + str(SurfaceCard.surface_coefficients[0]) + string += " " + str(SurfaceCard.surface_coefficients[1]) + "); } \n" + return string + + +# write a cylinder_y +def scone_cylinder_y(SurfaceCard): + string = " yCylinder; radius " + str(SurfaceCard.surface_coefficients[2]) + string += "; origin (" + str(SurfaceCard.surface_coefficients[0]) + " 0 " + string += str(SurfaceCard.surface_coefficients[1]) + "); } \n" + return string + + +# write a cylinder_z +def scone_cylinder_z(SurfaceCard): + string = " zCylinder; radius " + str(SurfaceCard.surface_coefficients[2]) + string += "; origin (" + str(SurfaceCard.surface_coefficients[0]) + " " + string += str(SurfaceCard.surface_coefficients[1]) + " 0); } \n" + return string + + +# write a sphere +def scone_sphere(SurfaceCard): + string = " sphere; origin (" + str(SurfaceCard.surface_coefficients[0]) + " " + string += str(SurfaceCard.surface_coefficients[1]) + " " + string += str(SurfaceCard.surface_coefficients[2]) + "); radius " + string += str(SurfaceCard.surface_coefficients[3]) + "; } \n" + return string + + +# write a general quadratic +def scone_gq(SurfaceCard): + string = " quadric; coeffs ( " + for coefficient in SurfaceCard.surface_coefficients: + string += " " + str(coefficient) + " " + string += "); } \n" + return string + + +def scone_cone_x(SurfaceCard): + x = SurfaceCard.surface_coefficients[0] + y = SurfaceCard.surface_coefficients[1] + z = SurfaceCard.surface_coefficients[2] + t2 = SurfaceCard.surface_coefficients[3] + + if (len(SurfaceCard.surface_coefficients) < 5): + sign = 0 + else: + sign = SurfaceCard.surface_coefficients[4] + + # Do trigonometry to convert mcnp tangent squared, t2, into + # angle and determine hMin and hMax. + # If sign is negative, hMax = vertex = 0, hMin = -10E10 + # If sign is positive, hMin = vertex = 0, hMax = 10E10 + # If +/- 1 is not present in the MCNP definition, make cone infinite + # A bit of a fudge for now. + # Assume no truncation, like in MCNP + if sign < 0: + hMin = -1E10 + hMax = 0 + elif sign > 0: + hMin = 0 + hMax = 1E10 + else: + hMin = -1E10 + hMax = 1E10 + + angle = degrees(atan(sqrt(t2))) + + string = " {} {:f} {:f} {:f} {}\n".format( + " xCone; vertex (", x, y, z," ); ") + string += "angle " + str(angle) + "; hMin " + str(hMin) + string += "; hMax " + str(hMax) + "; } \n" + + return string + + +# scone a cone along y +def scone_cone_y(SurfaceCard): + x = SurfaceCard.surface_coefficients[0] + y = SurfaceCard.surface_coefficients[1] + z = SurfaceCard.surface_coefficients[2] + t2 = SurfaceCard.surface_coefficients[3] + + if (len(SurfaceCard.surface_coefficients) < 5): + sign = 0 + else: + sign = SurfaceCard.surface_coefficients[4] + + # Do trigonometry to convert mcnp tangent squared, t2, into + # angle and determine hMin and hMax. + # If sign is negative, hMax = vertex = 0, hMin = -10E10 + # If sign is positive, hMin = vertex = 0, hMax = 10E10 + # If +/- 1 is not present in the MCNP definition, make cone infinite + # A bit of a fudge for now. + # Assume no truncation, like in MCNP + if sign < 0: + hMin = -1E10 + hMax = 0 + elif sign > 0: + hMin = 0 + hMax = 1E10 + else: + hMin = -1E10 + hMax = 1E10 + + angle = degrees(atan(sqrt(t2))) + + string = " {} {:f} {:f} {:f} {}\n".format( + " yCone; vertex (", x, y, z," ); ") + string += "angle " + str(angle) + "; hMin " + str(hMin) + string += "; hMax " + str(hMax) + "; } \n" + + return string + + +# scone a cone along z +def scone_cone_z(SurfaceCard): + x = SurfaceCard.surface_coefficients[0] + y = SurfaceCard.surface_coefficients[1] + z = SurfaceCard.surface_coefficients[2] + t2 = SurfaceCard.surface_coefficients[3] + + if (len(SurfaceCard.surface_coefficients) < 5): + sign = 0 + else: + sign = SurfaceCard.surface_coefficients[4] + + # Do trigonometry to convert mcnp tangent squared, t2, into + # angle and determine hMin and hMax. + # If sign is negative, hMax = vertex = 0, hMin = -10E10 + # If sign is positive, hMin = vertex = 0, hMax = 10E10 + # If +/- 1 is not present in the MCNP definition, make cone infinite + # A bit of a fudge for now. + # Assume no truncation, like in MCNP + if sign < 0: + hMin = -1E10 + hMax = 0 + elif sign > 0: + hMin = 0 + hMax = 1E10 + else: + hMin = -1E10 + hMax = 1E10 + + angle = degrees(atan(sqrt(t2))) + + string = " {} {:f} {:f} {:f} {}\n".format( + " zCone; vertex (", x, y, z," ); ") + string += "angle " + str(angle) + "; hMin " + str(hMin) + string += "; hMax " + str(hMax) + "; } \n" + + return string + + +""" +# write a conex +def serpent_cone_x(SurfaceCard): + + mcnp xyz r2 -1 +1 + * + || + | \ + | \ + | \ + | \ + | \ + *------* + + From the bounding coodinate appropriate in + this case - if pointing down need the lowest value + + + # cone points down from xyz + if SurfaceCard.surface_coefficients[4] == -1: + h = abs(SurfaceCard.b_box[0]) + x = SurfaceCard.b_box[0] + # cone point up from xyz + if SurfaceCard.surface_coefficients[4] == 1: + h = abs(SurfaceCard.b_box[1]) + x = SurfaceCard.b_box[1] + + y = SurfaceCard.surface_coefficients[1] + z = SurfaceCard.surface_coefficients[2] + r = h*sqrt(SurfaceCard.surface_coefficients[3]) + + string = ' {} {:f} {:f} {:f} {:f} {:f}'.format("conx",x,y,z,r,h) + + return string + +# write a cone y +def serpent_cone_y(SurfaceCard): + + mcnp xyz r2 -1 +1 + * + || + | \ + | \ + | \ + | \ + | \ + *------* + + From the bounding coodinate appropriate in + this case - if pointing down need the lowest value + + + # cone points down from xyz + if SurfaceCard.surface_coefficients[4] == -1: + h = abs(SurfaceCard.b_box[2]) + y = SurfaceCard.b_box[2] + # cone point up from xyz + if SurfaceCard.surface_coefficients[4] == 1: + h = abs(SurfaceCard.b_box[3]) + y = SurfaceCard.b_box[3] + + x = SurfaceCard.surface_coefficients[0] + z = SurfaceCard.surface_coefficients[2] + r = h*sqrt(SurfaceCard.surface_coefficients[3]) + + string = ' {} {:f} {:f} {:f} {:f} {:f}'.format("cony",x,y,z,r,h) + + return string + +# write a cone z +def serpent_cone_z(SurfaceCard): + + mcnp xyz r2 -1 +1 + * + || + | \ + | \ + | \ + | \ + | \ + *------* + + From the bounding coodinate appropriate in + this case - if pointing down need the lowest value + + + # cone points down from xyz + if SurfaceCard.surface_coefficients[4] == -1: + h = abs(SurfaceCard.b_box[5]) + z = SurfaceCard.b_box[5] + # cone point up from xyz + if SurfaceCard.surface_coefficients[4] == 1: + h = abs(SurfaceCard.b_box[6]) + z = SurfaceCard.b_box[6] + + x = SurfaceCard.surface_coefficients[0] + y = SurfaceCard.surface_coefficients[1] + r = h*sqrt(SurfaceCard.surface_coefficients[3]) + + + return string + +""" + +# write the surface description to file +def write_scone_surface(filestream, SurfaceCard): + + string = str(SurfaceCard.surface_id) + " { id " + string += str(SurfaceCard.surface_id) + "; type " + + if SurfaceCard.surface_type is SurfaceCard.SurfaceType["PLANE_GENERAL"]: + string += scone_plane_string(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["PLANE_X"]: + string += scone_plane_x_string(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["PLANE_Y"]: + string += scone_plane_y_string(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["PLANE_Z"]: + string += scone_plane_z_string(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CYLINDER_X"]: + string += scone_cylinder_x(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CYLINDER_Y"]: + string += scone_cylinder_y(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CYLINDER_Z"]: + string += scone_cylinder_z(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["SPHERE_GENERAL"]: + string += scone_sphere(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CONE_X"]: + string += scone_cone_x(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CONE_Y"]: + string += scone_cone_y(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["CONE_Z"]: + string += scone_cone_z(SurfaceCard) + filestream.write(string) + elif SurfaceCard.surface_type is SurfaceCard.SurfaceType["GENERAL_QUADRATIC"]: + string += scone_gq(SurfaceCard) + filestream.write(string) + else: + filestream.write("surface not supported\n") + + return + diff --git a/csg2csg/SCONEUniverseCard.py b/csg2csg/SCONEUniverseCard.py new file mode 100644 index 0000000..d4ea43a --- /dev/null +++ b/csg2csg/SCONEUniverseCard.py @@ -0,0 +1,62 @@ +#!/usr/env/python3 + +from csg2csg.MCNPFormatter import mcnp_line_formatter + +from csg2csg.UniverseCard import UniverseCard, uni_fill, mat_fill +import re +import math + +# write the universe card for a scone universe given a generic cell card +def write_scone_universe(filestream, UniverseCard): + + # print (UniverseCard) + # TODO support lattice universes + if UniverseCard.is_root: + string = "root { type " + string += "rootUniverse; " + string += "border " + str(UniverseCard.border_surface) + "; " + if UniverseCard.fill_type == uni_fill: + string += "fill u<" + str(UniverseCard.fill_id + 1) + ">; " + if UniverseCard.fill_type == mat_fill: + # Name preceded by an m due to SCONE weirdness + string += "fill m" + str(UniverseCard.fill_material) + "; " + else: + string = str(UniverseCard.universe_id + 1) + " { type " + string += "cellUniverse; cells (" + for cell_id in UniverseCard.cell_list: + string += str(cell_id) + " " + string += "); " + + # Need to increment by 1 due to SCONE not allowing Universe ID = 0 + # This is used by other codes to denote the base/root universe + string += "id " + str(UniverseCard.universe_id + 1) +"; " + + # Include transformations + if UniverseCard.universe_offset != 0: + # Convert origin to a translation + string += "translation (" + for i in range(3): + string += str(UniverseCard.universe_offset[i]) +" " + string += "); " + + if UniverseCard.universe_rotation != 0: + # Convert rotation matrix to Euler angles following ZXZ convention + # Need to double check conventions: rotate[5] might have a negative + # sign and rot[2] might be * -1 + rotate = UniverseCard.universe_rotation + rot[0] = math.atan2(rotate[2],-rotate[5]) + rot[1] = math.acos(rotate[8]) + rot[2] = math.atan2(rotate[6],rotate[7]) + rot = math.degrees(rot) + string += "rotation (" + for i in range(3): + string += str(rot[i]) +" " + string += "); " + string += " } \n" + + # removes any multiple spaces + string = re.sub(" +", " ", string) + string = mcnp_line_formatter(string) + filestream.write(string) + + diff --git a/csg2csg/UniverseCard.py b/csg2csg/UniverseCard.py new file mode 100644 index 0000000..ca41508 --- /dev/null +++ b/csg2csg/UniverseCard.py @@ -0,0 +1,105 @@ +# /usr/env/python3 + +from csg2csg.Card import Card +from enum import Enum + +uni_fill = 1 +mat_fill = 2 + +class UniverseCard(Card): + """Class for the storage of the Generic UniverseCard type. + Methods for the generation of UniverseCards should be placed + here. Classes instantiating UniverseCard objects should be + implemented in its own CodeUniverseCard.py file. + This is primarily intended for SCONE - do any other codes + have explicit cell universe cards? Maybe this is useful for + translating lattices? + """ + + # constructor for the universecard class + def __init__(self): + self.universe_comment = "" + self.universe_id = 0 + self.cell_list = set() + self.fill_type = 0 + self.fill_id = 0 + self.fill_mat = '' + self.offset = 0 + self.rotation = 0 + self.is_root = 0 + self.border_surface = 0 + self.universe_offset = 0 + self.universe_rotation = 0 + #Card.__init__(self, card_string) + + # print method + def __str__(self): + string = "Universe Card: \n" + string += "Universe ID " + str(self.universe_id) + "\n" + string += "Comment " + str(self.universe_comment) + "\n" + string += "Is cell universe? " + str(bool(self.cell_list)) + "\n" + if bool(self.cell_list): + string += "Cells in Universe " + str(self.cell_list) + "\n" + string += "Is root? " + str(self.is_root) + "\n" + if self.is_root: + string += "Bounding surface " + str(self.border_surface) + "\n" + if self.fill_type == uni_fill: + string += "Contains universe " + str(self.fill_id) + "\n" + else: + string += "Contains material " + self.fill_mat + "\n" + return string + + # Build from CellCard list + # Loops through cell list to identify any cells it contains. + # Also identifies which cells contain it and takes their + # cell transformations as its own. + def build_from_cell_list(self, uni_id, cell_list): + self.cell_list = [] + self.universe_id = uni_id + + #print(self.__str__()) + #print(uni_id) + + # This is the root universe + if uni_id == 0: + self.is_root = 1 + + for cell in cell_list: + + # Universe contains this cell + if int(cell.cell_universe) == uni_id: + self.cell_list.append(cell.cell_id) + + # Search the root universe for a cell which has a single + # surface in which it is in the positive halfspace. + # This is (probably??) the bounding surface. + # The indicator that a cell is definitely in the positive + # halfspace comes from cell_text_description. Check it for + # a single entry which is positive. + numeric_list = [item for item in cell.cell_text_description if item.lstrip('-').isdigit()] + halfspaces = [int(x) for x in numeric_list] + if (uni_id == 0 and len(halfspaces) == 1): + surface_id = halfspaces[0] + if surface_id > 0: + self.border_surface = surface_id + + + # Universe is contained by this cell + if cell.cell_fill == uni_id: + + # Apply rotations and transformations as appropriate + if cell.cell_universe_rotation != 0: + self.universe_rotation = cell.cell_universe_rotation + + if cell.cell_universe_offset != 0: + self.universe_offset = cell.cell_universe_offset + + # Make sure there isn't something silly + #if (cell.cell_fill == uni_id) and (cell.cell_universe == uni_id): + # print(cell.cell_id) + # print(uni_id) + # raise ValueError('Cell contains and is contained by the same universe') + + + + diff --git a/csg2csg/__main__.py b/csg2csg/__main__.py index 2fa8d90..e9191c4 100755 --- a/csg2csg/__main__.py +++ b/csg2csg/__main__.py @@ -5,6 +5,7 @@ from csg2csg.OpenMCInput import OpenMCInput from csg2csg.FLUKAInput import FLUKAInput from csg2csg.PhitsInput import PhitsInput +from csg2csg.SCONEInput import SCONEInput # for debug info import logging, sys @@ -36,7 +37,7 @@ def main(): parser.add_argument( "-f", "--format", - choices=["mcnp", "serpent", "openmc", "phits", "fluka"], + choices=["mcnp", "serpent", "openmc", "phits", "fluka", "scone"], help="format of the input file", default="mcnp", ) @@ -71,7 +72,7 @@ def main(): filename = args.input if "all" in args.output: - codes = ["mcnp", "serpent", "openmc", "phits", "fluka"] + codes = ["mcnp", "serpent", "openmc", "phits", "fluka", "scone"] else: codes = args.output @@ -91,6 +92,8 @@ def main(): raise NotImplementedError("Phits input files are not supported yet") elif args.format == "fluka": raise NotImplementedError("Fluka input files are not supported yet") + elif args.format == "scone": + raise NotImplementedError("SCONE input files are not supported yet") for code in codes: if "serpent" in code: @@ -123,6 +126,12 @@ def main(): fluka.from_input(input) mkdir("fluka") fluka.write_fluka("fluka/fluka.inp") + if "scone" in code: + print("Producing SCONE output...") + scone = SCONEInput() + scone.from_input(input) + mkdir("scone") + scone.write_scone("scone/scone.inp") logging.info("Finished") diff --git a/tests/terst_openmcmaterial.py b/tests/test_openmcmaterial.py similarity index 100% rename from tests/terst_openmcmaterial.py rename to tests/test_openmcmaterial.py