Skip to content

Commit a54e88d

Browse files
authored
Merge pull request #18 from Shimwell/serpent_material_reader
added first draft converting serpent materials
2 parents 3c05e0c + 3067e06 commit a54e88d

6 files changed

Lines changed: 256 additions & 33 deletions

File tree

python/OpenMCMaterial.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,15 @@ def __write_mass_fraction(material, nuclide, mass_frac):
5555
# material xml element
5656
def write_openmc_material(MaterialCard, material_tree):
5757
matid = str(MaterialCard.material_number)
58-
name = "Material " + str(matid)
58+
matname = str(MaterialCard.material_name)
5959
density = str(abs(MaterialCard.density))
6060
if MaterialCard.density < 0:
6161
density_units = "g/cc"
6262
else:
6363
density_units = "atom/b-cm"
6464

65-
material = ET.SubElement(material_tree, "material", id = matid)
65+
material = ET.SubElement(material_tree, "material", id = matid, name = matname)
6666
ET.SubElement(material, "density", value = density, units = density_units)
67-
6867
for nuclide in MaterialCard.composition_dictionary:
6968
mass_frac = MaterialCard.composition_dictionary[nuclide]
7069
nuclide_name = zaid_to_name(nuclide)

python/SerpentInput.py

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from SerpentCellCard import SerpentCellCard, write_serpent_cell
66
from SerpentMaterialCard import SerpentMaterialCard, write_serpent_material
77

8+
import logging
9+
import re
10+
811
class SerpentInput(InputDeck):
912
""" SerpentInput class - does the actual processing
1013
"""
@@ -13,12 +16,91 @@ class SerpentInput(InputDeck):
1316
def __init__(self,filename = ""):
1417
InputDeck.__init__(self,filename)
1518

16-
# def from_input(self,InputDeckClass):
17-
# InputDeck.filename = InputDeckClass.filename
18-
# InputDeck.title = InputDeckClass.title
19-
# InputDeck.cell_list = InputDeckClass.cell_list
20-
# InputDeck.surfcace_list = InputDeckClass.surface_list
21-
# return
19+
# extract a material card from the start line until
20+
def __get_material_card(self, start_line, mat_num):
21+
# we already know that the start line has an mat name
22+
idx = start_line
23+
tokens = self.file_lines[idx].split()
24+
mat_name = tokens[1]
25+
# set the material name
26+
27+
mat_density = float(tokens[2])
28+
29+
# build the first mat string
30+
material_string = ' '
31+
idx += 1
32+
33+
while True:
34+
# if at the end of the file
35+
if idx == len(self.file_lines):
36+
break
37+
while True:
38+
# its possible that we will have advanced to the end of the
39+
# file
40+
if (idx == len(self.file_lines)):
41+
break
42+
if ('mat' == self.file_lines[idx].split()[0]):
43+
break
44+
line = self.file_lines[idx]
45+
if '%' in line:
46+
pos = line.find('%')
47+
line = line[:pos]
48+
material_string += line
49+
# increment the line that we are looking at
50+
idx += 1
51+
break
52+
53+
material = SerpentMaterialCard(mat_num, mat_name, mat_density, material_string)
54+
55+
self.material_list[material.material_number] = material
56+
57+
58+
return
59+
60+
# get the material cards definitions
61+
def __get_material_cards(self):
62+
63+
idx = 0
64+
mat_num = 1
65+
while True:
66+
if idx == len(self.file_lines):
67+
break
68+
69+
# this crazy makes sure that we find an "mat " in the line
70+
if re.match(" *mat /*",self.file_lines[idx]):
71+
logging.debug("%s", "material found on line " + str(idx))
72+
self.__get_material_card(idx, mat_num)
73+
mat_num += 1
74+
idx += 1
75+
return
76+
77+
78+
# process the serpent input deck and read into a generic datastructure
79+
# that we can translate to other formats
80+
def process(self):
81+
82+
# clear out the comment and white space cards
83+
idx = 0
84+
while True:
85+
if idx == len(self.file_lines):
86+
break
87+
if self.file_lines[idx].isspace():
88+
del self.file_lines[idx]
89+
elif self.file_lines[idx].strip().startswith("%"):
90+
del self.file_lines[idx]
91+
else:
92+
idx += 1
93+
94+
if logging.getLogger().isEnabledFor(logging.DEBUG):
95+
logging.debug("%s", "Input Echo")
96+
for idx,line in enumerate(self.file_lines):
97+
logging.debug("%i %s",idx,line)
98+
99+
self.__get_material_cards()
100+
101+
# raise NotImplementedError('Serpent input files are not fully supported yet')
102+
103+
return
22104

23105
# Write the Serpent Cell definitions
24106
def __write_serpent_cells(self, filestream):

python/SerpentMaterialCard.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/env/python3
22

33
from MaterialCard import MaterialCard
4+
from MCNPFormatter import get_fortran_formatted_number
45

56
# write a specific serpent material card
67
def write_serpent_material(filestream, material):
@@ -21,5 +22,39 @@ def write_serpent_material(filestream, material):
2122
""" Class to handle SerpentMaterialCard tranlation
2223
"""
2324
class SerpentMaterialCard(MaterialCard):
24-
def __init__(self, card_string):
25-
MaterialCard.__init__(self, card_string)
25+
26+
def __init__(self, material_number, material_name, material_density, card_string):
27+
MaterialCard.__init__(self, material_number, card_string)
28+
self.material_name = material_name
29+
self.material_number = material_number
30+
self.density = material_density
31+
self.__process_string()
32+
33+
# populate the Serpent Material Card
34+
def __process_string(self):
35+
# need to reset the dictionary
36+
# otherwise state seems to linger - weird
37+
self.composition_dictionary = {}
38+
39+
mat_string = self.text_string
40+
mat_string = mat_string.replace("\n"," ")
41+
42+
# split string
43+
tokens = mat_string.split()
44+
45+
if len(tokens)%2 != 0:
46+
raise Exception("Material string not correctly processed")
47+
48+
while len(tokens) != 0:
49+
nuclide = tokens[0].split(".")
50+
nucid = nuclide[0]
51+
try:
52+
xsid = nuclide[1]
53+
except:
54+
xsid = ""
55+
frac = get_fortran_formatted_number(tokens[1])
56+
tokens.pop(0)
57+
tokens.pop(0)
58+
self.composition_dictionary[nucid] = frac
59+
self.xsid_dictionary[nucid] = xsid
60+
return

python/csg2csg.py

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,28 @@ def mkdir(directory):
2323
def main(argv):
2424

2525
parser = argparse.ArgumentParser(description='csg conversion tool.')
26-
parser.add_argument('-d','--debug', help = 'turn on debug logging',
26+
27+
parser.add_argument('-d','--debug',
28+
help = 'Turn on debug logging',
2729
action="store_true")
28-
parser.add_argument('-f','--file', help = 'filename to read')
30+
31+
parser.add_argument('-i','--input',
32+
help = 'Filename to read in',
33+
required=True)
34+
35+
parser.add_argument('-f','--format',
36+
choices=["mcnp","serpent","openmc","phits","fluka"],
37+
help = 'format of the input file',
38+
default = 'mcnp')
39+
2940
parser.add_argument('-p','--preserve',
30-
help = 'preserve existing cross section id numbers on write',
31-
action="store_true")
41+
help = 'Preserve existing cross section id numbers on write',
42+
action = "store_true")
3243

33-
parser.add_argument('-o','--output', help = 'output code selections')
44+
parser.add_argument('-o','--output',
45+
nargs='+',
46+
help = 'Output code selections',
47+
default = 'all')
3448

3549
# parse the arguments
3650
args = parser.parse_args(argv)
@@ -41,25 +55,30 @@ def main(argv):
4155

4256
logging.info("Started")
4357

44-
if args.file is None:
45-
print('file not specified')
46-
sys.exit(1)
47-
else:
48-
filename = args.file
58+
filename = args.input
4959

50-
if args.output is None:
51-
print('no output options selected')
52-
sys.exit(1)
60+
61+
if "all" in args.output:
62+
codes = ["mcnp","serpent","openmc","phits","fluka"]
5363
else:
54-
if "all" in args.output:
55-
codes = ["mcnp","serpent","openmc","phits","fluka"]
56-
else:
57-
codes = args.output.split(',')
58-
59-
# read the mcnp input
60-
input = MCNPInput(filename)
61-
input.read()
62-
input.process()
64+
codes = args.output
65+
66+
if args.format == 'mcnp':
67+
# read the mcnp input
68+
input = MCNPInput(filename)
69+
input.read()
70+
input.process()
71+
elif args.format == 'serpent':
72+
# read the serpent input
73+
input = SerpentInput(filename)
74+
input.read()
75+
input.process()
76+
elif args.format == 'openmc':
77+
raise NotImplementedError('OpenMC input files are not supported yet')
78+
elif args.format == 'phits':
79+
raise NotImplementedError('Phits input files are not supported yet')
80+
elif args.format == 'fluka':
81+
raise NotImplementedError('Fluka input files are not supported yet')
6382

6483
for code in codes:
6584
if "serpent" in code:
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/env/python3
2+
3+
import unittest
4+
import sys
5+
sys.path.append("..")
6+
7+
from MCNPMaterialCard import MCNPMaterialCard
8+
from MCNPInput import MCNPInput
9+
10+
class TestMCNPMaterial(unittest.TestCase):
11+
12+
def test_mcnp_material(self):
13+
string ="29063 6.917000e-01 \n" + \
14+
"29065.31c 3.083000e-01 \n"
15+
number = 1
16+
name = "M1"
17+
matcard = MCNPMaterialCard(number,string)
18+
19+
self.assertEqual(matcard.material_number,number)
20+
self.assertEqual(matcard.material_name,name)
21+
self.assertEqual(len(matcard.composition_dictionary),2)
22+
23+
self.assertEqual(list(matcard.composition_dictionary.keys())[0],'29063')
24+
self.assertEqual(list(matcard.composition_dictionary.keys())[1],'29065')
25+
26+
self.assertEqual(list(matcard.composition_dictionary.values())[0],6.917000e-01)
27+
self.assertEqual(list(matcard.composition_dictionary.values())[1],3.083000e-01)
28+
29+
self.assertEqual(len(matcard.xsid_dictionary),2)
30+
31+
self.assertEqual(list(matcard.xsid_dictionary.keys())[0],'29063')
32+
self.assertEqual(list(matcard.xsid_dictionary.keys())[1],'29065')
33+
34+
self.assertEqual(list(matcard.xsid_dictionary.values())[0],'')
35+
self.assertEqual(list(matcard.xsid_dictionary.values())[1],'31c')
36+
37+
if __name__ == '__main__':
38+
unittest.main()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/env/python3
2+
3+
import unittest
4+
import sys
5+
sys.path.append("..")
6+
7+
from SerpentMaterialCard import SerpentMaterialCard
8+
from SerpentInput import SerpentInput
9+
10+
class TestSerpentMaterial(unittest.TestCase):
11+
12+
def test_serpent_material(self):
13+
string ="29063 6.917000e-01 \n" + \
14+
"29065.31c 3.083000e-01 \n"
15+
number = 1
16+
name = "copper"
17+
density = 8.93
18+
matcard = SerpentMaterialCard(number,name,density,string)
19+
20+
self.assertEqual(matcard.density,density)
21+
self.assertEqual(matcard.material_number,number)
22+
self.assertEqual(matcard.material_name,name)
23+
self.assertEqual(len(matcard.composition_dictionary),2)
24+
25+
self.assertEqual(list(matcard.composition_dictionary.keys())[0],'29063')
26+
self.assertEqual(list(matcard.composition_dictionary.keys())[1],'29065')
27+
28+
self.assertEqual(list(matcard.composition_dictionary.values())[0],6.917000e-01)
29+
self.assertEqual(list(matcard.composition_dictionary.values())[1],3.083000e-01)
30+
31+
self.assertEqual(len(matcard.xsid_dictionary),2)
32+
33+
self.assertEqual(list(matcard.xsid_dictionary.keys())[0],'29063')
34+
self.assertEqual(list(matcard.xsid_dictionary.keys())[1],'29065')
35+
36+
self.assertEqual(list(matcard.xsid_dictionary.values())[0],'')
37+
self.assertEqual(list(matcard.xsid_dictionary.values())[1],'31c')
38+
39+
def test_serpent_mat_input(self):
40+
string = ["mat 1 8.93\n",
41+
"29063 6.917000e-01\n",
42+
"29065 3.083000e-01\n"]
43+
44+
serpent = SerpentInput()
45+
serpent.file_lines = string
46+
serpent.process()
47+
48+
49+
if __name__ == '__main__':
50+
unittest.main()

0 commit comments

Comments
 (0)