Skip to content

Commit 2301514

Browse files
committed
tests: added dynamic testing
1 parent 48a8275 commit 2301514

37 files changed

+878
-798
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ target/
116116

117117
# IPython
118118
profile_default/
119-
ipython_config.py
119+
ipython_utils.py
120120

121121
# pyenv
122122
# For a library or package, you might want to ignore these files since the code is
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

examples/example_box.py

+67-26
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,79 @@
11
import pymcnp
22

33

4-
def get_inp(RADIUS_AIR, RADIUS_SHIELD, RADIUS_LEAD):
5-
BOX_AIR = pymcnp.inp.SurfaceOption__Rpp.from_mcnp(
6-
f'rpp {-RADIUS_AIR} {RADIUS_AIR} {-RADIUS_AIR} {RADIUS_AIR} {-RADIUS_AIR} {RADIUS_AIR}'
4+
def get_inp(radius_air, radius_shield, radius_lead):
5+
inp = pymcnp.InpBuilder(title='Box Example')
6+
7+
geometry_air = pymcnp.GeometryBuilder('11')
8+
geometry_shield = pymcnp.GeometryBuilder('12')
9+
geometry_lead = pymcnp.GeometryBuilder('13')
10+
geometry_world = pymcnp.GeometryBuilder('14')
11+
12+
cell_air = pymcnp.CellBuilder(number=1, material=21, density=0.5, geometry=geometry_air)
13+
14+
cell_shield = pymcnp.CellBuilder(
15+
number=2, material=22, density=0.5, geometry=geometry_shield & geometry_air
16+
)
17+
18+
cell_lead = pymcnp.CellBuilder(
19+
number=3, material=23, density=0.5, geometry=geometry_lead & geometry_shield
720
)
8-
BOX_SHIELD = pymcnp.inp.SurfaceOption__Rpp.from_mcnp(
9-
f'rpp {-RADIUS_SHIELD} {RADIUS_SHIELD} {-RADIUS_SHIELD} {RADIUS_SHIELD} {-RADIUS_SHIELD} {RADIUS_SHIELD}'
21+
22+
cell_world = pymcnp.CellBuilder(number=4, material=0, geometry=geometry_world)
23+
24+
inp.append(cell_air)
25+
inp.append(cell_shield)
26+
inp.append(cell_lead)
27+
inp.append(cell_world)
28+
29+
surface_air = pymcnp.SurfaceBuilder(
30+
number=11,
31+
mnemonic='rpp',
32+
parameter=f'{-radius_air} {radius_air} {-radius_air} {radius_air} {-radius_air} {radius_air}',
1033
)
11-
BOX_LEAD = pymcnp.inp.SurfaceOption__Rpp.from_mcnp(
12-
f'rpp {-RADIUS_LEAD} {RADIUS_LEAD} {-RADIUS_LEAD} {RADIUS_LEAD} {-RADIUS_LEAD} {RADIUS_LEAD}'
34+
surface_shield = pymcnp.SurfaceBuilder(
35+
number=12,
36+
mnemonic='rpp',
37+
parameter=f'{-radius_shield} {radius_shield} {-radius_shield} {radius_shield} {-radius_shield} {radius_shield}',
38+
)
39+
surface_lead = pymcnp.SurfaceBuilder(
40+
number=13,
41+
mnemonic='rpp',
42+
parameter=f'{-radius_lead} {radius_lead} {-radius_lead} {radius_lead} {-radius_lead} {radius_lead}',
43+
)
44+
surface_world = pymcnp.SurfaceBuilder(
45+
number=14,
46+
mnemonic='so',
47+
parameter=f'{radius_air + radius_shield + radius_lead + 1}',
1348
)
1449

15-
MATERIAL_AIR = pymcnp.inp.DataOption__M.from_formula(1, {'N2': 0.8, 'O2': 0.2})
16-
MATERIAL_SHIELD = pymcnp.inp.DataOption__M.from_formula(2, {'TiO2': 0.5, 'PbO': 0.5})
17-
MATERIAL_LEAD = pymcnp.inp.DataOption__M.from_formula(3, {'Pb': 1})
50+
inp.append(surface_air)
51+
inp.append(surface_shield)
52+
inp.append(surface_lead)
53+
inp.append(surface_world)
1854

19-
return f"""
20-
Box Example
21-
10 1 0.5 20
22-
11 2 0.5 21:20
23-
12 3 0.5 22:21
24-
13 0 23
55+
material_air = pymcnp.DataBuilder.unbuild(
56+
pymcnp.inp.Data(pymcnp.inp.data.M.from_formula(21, {'N2': 0.8, 'O2': 0.2}))
57+
)
58+
material_shield = pymcnp.DataBuilder.unbuild(
59+
pymcnp.inp.Data(pymcnp.inp.data.M.from_formula(22, {'TiO2': 0.5, 'PbO': 0.5}))
60+
)
61+
material_lead = pymcnp.DataBuilder.unbuild(
62+
pymcnp.inp.Data(pymcnp.inp.data.M.from_formula(23, {'Pb': 1}))
63+
)
64+
65+
sdef = pymcnp.DataBuilder(
66+
mnemonic='sdef',
67+
parameter='x=0 y=0 z=0 erg=2.2',
68+
)
2569

26-
20 {BOX_AIR}
27-
21 {BOX_SHIELD}
28-
22 {BOX_LEAD}
29-
23 SO {RADIUS_AIR + RADIUS_SHIELD + RADIUS_LEAD + 1}
70+
inp.append(material_air)
71+
inp.append(material_shield)
72+
inp.append(material_lead)
73+
inp.append(sdef)
3074

31-
{MATERIAL_AIR}
32-
{MATERIAL_SHIELD}
33-
{MATERIAL_LEAD}
34-
SDEF X=0 Y=0 Z=0 ERG=2.2
35-
"""[1:-1]
75+
return inp.build()
3676

3777

38-
print(get_inp(60, 15, 1))
78+
inp = get_inp(60, 15, 1)
79+
print(inp)

examples/example_draw.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import pathlib
2+
3+
import pymcnp
4+
5+
6+
inp = pymcnp.Inp.from_mcnp_file(pathlib.Path(__file__).parent / 'data/input_files/png.i')
7+
vista = inp.to_pyvista()
8+
vista.plot()

scripts/inp_code.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def _REGEX(element):
5050
o += f'(( {{{attribute.type[12:-1]}._REGEX.pattern}})+)'
5151
else:
5252
if 'Option_' in attribute.type:
53-
o += f'( {{{SNAKE(element.name)}.{CAMEL(element.name)}Option_._REGEX.pattern}})'
53+
o += f'( ({{{SNAKE(element.name)}.{CAMEL(element.name)}Option_._REGEX.pattern}}))'
5454
else:
5555
o += f'( {{{attribute.type}._REGEX.pattern}})'
5656

scripts/inp_tests.py

+4-32
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Test_{CAMEL(parent_name)}{CAMEL(element.name)}:
2525
Tests ``{CAMEL(parent_name)}{CAMEL(element.name)}``.
2626
"""
2727
28-
class Test_FromMcnp(_Test_FromMcnp):
28+
class Test_FromMcnp(_utils._Test_FromMcnp):
2929
"""
3030
Tests ``{CAMEL(parent_name)}{CAMEL(element.name)}.from_mcnp``.
3131
"""
@@ -58,41 +58,13 @@ def get_tests(element, mod, parent_name):
5858
for card in inp_data.cards.options:
5959
tests = get_tests(card, '', '')
6060

61-
res = f'''
61+
res = f"""
6262
import pymcnp
63-
64-
import pytest
65-
66-
67-
class _Test_FromMcnp:
68-
"""
69-
Tests ``McnpElement_.from_mcnp``.
70-
"""
71-
72-
element: pymcnp.utils._object.McnpElement_
73-
EXAMPLE_VALID: list[str]
74-
EXAMPLE_INVALID: list[str]
75-
76-
def test_valid(self):
77-
"""
78-
Tests ``EXAMPLES_VALID``.
79-
"""
80-
81-
for example in self.EXAMPLES_VALID:
82-
self.element.from_mcnp(example)
83-
84-
def test_invalid(self):
85-
"""
86-
Tests ``EXAMPLES_INVALID``.
87-
"""
88-
89-
for example in self.EXAMPLES_INVALID:
90-
with pytest.raises(pymcnp.utils.errors.InpError):
91-
self.element.from_mcnp(example)
63+
import _utils
9264
9365
9466
{'\n\n'.join(tests)}
95-
'''[1:]
67+
"""[1:]
9668

9769
path_file = pathlib.Path(__file__).parent.parent / 'tests' / f'test_{card.name}.py'
9870
with path_file.open('w') as file:

src/pymcnp/InpBuilder.py

+118-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import math
12
import dataclasses
23

34
from . import inp
@@ -17,6 +18,20 @@ class GeometryBuilder:
1718

1819
infix: str
1920

21+
@staticmethod
22+
def unbuild(geometry: types.Geometry):
23+
"""
24+
Generates ``GeometryBuilder`` from ``Geometry``.
25+
26+
Parameter:
27+
geoemtry: ``Geometry`` to unbuild.
28+
29+
Returns:
30+
``GeometryBuilder`` for ``Geometry``.
31+
"""
32+
33+
return GeometryBuilder(infix=geometry.infix)
34+
2035
def __and__(a, b):
2136
"""
2237
Unites ``GeometryBuilder``.
@@ -81,6 +96,25 @@ class CellOptionBuilder:
8196
suffix: str = ''
8297
designator: str = ''
8398

99+
@staticmethod
100+
def unbuild(option: inp.cell.CellOption_):
101+
"""
102+
Generates ``CellOptionBuilder`` from ``CellOption_``.
103+
104+
Parameter:
105+
option: ``CellOption_`` to unbuild.
106+
107+
Returns:
108+
``CellOptionBuilder`` for ``CellOption_``.
109+
"""
110+
111+
return CellOptionBuilder(
112+
mnemonic=option._KEYWORD,
113+
parameter=option.value.to_mcnp(),
114+
suffix=option.suffix.to_mcnp() if hasattr(option, 'suffix') else '',
115+
designator=option.designator.to_mcnp() if hasattr(option, 'designator') else '',
116+
)
117+
84118
def build(self):
85119
"""
86120
Builds ``CellOptionBuilder`` into ``CellOption_``.
@@ -123,6 +157,39 @@ class CellBuilder:
123157
density: float | types.Real = None
124158
atoms_or_grams: bool = True
125159

160+
def append(self, option: CellOptionBuilder):
161+
"""
162+
Stores ``Option_`` in ``CellBuilder``,
163+
164+
Parameters:
165+
option: ``Option_`` to add.
166+
"""
167+
168+
self.options[
169+
f'{option.mnemonic}{option.suffix if hasattr(option, "suffix") else ""}:{option.designator if hasattr(option, "designator") else ""}'
170+
] = option
171+
172+
@staticmethod
173+
def unbuild(cell: inp.Cell):
174+
"""
175+
Generates ``CellBuilder`` from ``Cell``.
176+
177+
Parameter:
178+
cell: ``Cell` to unbuild.
179+
180+
Returns:
181+
``CellBuilder`` for ``Cell``.
182+
"""
183+
184+
return CellBuilder(
185+
number=cell.number.value,
186+
material=cell.material.value,
187+
density=math.abs(cell.density.value),
188+
atoms_or_grams=cell.density > 0,
189+
options={option._KEYWORD: CellOptionBuilder.unbuild(option) for option in cell.options},
190+
geometry=GeometryBuilder.unbuild(cell.geometry),
191+
)
192+
126193
def build(self):
127194
"""
128195
Builds ``CellBuilder`` into ``Cell``.
@@ -138,7 +205,7 @@ def build(self):
138205
if self.density
139206
else None,
140207
geometry=self.geometry.build(),
141-
options=types.Tuple([option.build() for option in self.options]),
208+
options=types.Tuple([option.build() for option in self.options.values()]),
142209
)
143210

144211

@@ -160,6 +227,26 @@ class SurfaceBuilder:
160227
prefix: str = None
161228
transform: int = None
162229

230+
@staticmethod
231+
def unbuild(surface: inp.Surface):
232+
"""
233+
Generates ``SurfaceBuilder`` from ``Surface``.
234+
235+
Parameter:
236+
surface: ``Surface` to unbuild.
237+
238+
Returns:
239+
``SurfaceBuilder`` for ``Surface``.
240+
"""
241+
242+
return SurfaceBuilder(
243+
number=surface.number.value,
244+
parameter=surface.option.value.to_mcnp(),
245+
transform=surface.transform.value,
246+
mnemonic=surface.option._KEYWORD,
247+
prefix=surface.prefix,
248+
)
249+
163250
def build(self):
164251
"""
165252
Builds ``SurfaceBuilder`` into ``Surface``.
@@ -204,6 +291,27 @@ class DataBuilder:
204291
suffix: str = ''
205292
designator: str = ''
206293

294+
@staticmethod
295+
def unbuild(data: inp.Data):
296+
"""
297+
Generates ``DataBuilder`` from ``Data``.
298+
299+
Parameter:
300+
data: ``Data` to unbuild.
301+
302+
Returns:
303+
``DataBuilder`` for ``Data``.
304+
"""
305+
306+
return DataBuilder(
307+
mnemonic=data.option._KEYWORD,
308+
parameter=data.option.value.to_mcnp(),
309+
suffix=data.option.suffix.to_mcnp() if hasattr(data.option, 'suffix') else '',
310+
designator=data.option.designator.to_mcnp()
311+
if hasattr(data.option, 'designator')
312+
else '',
313+
)
314+
207315
def build(self):
208316
"""
209317
Builds ``DataBuilder`` into ``Data``.
@@ -246,9 +354,9 @@ class InpBuilder:
246354
"""
247355

248356
title: str
249-
cells: tuple[CellBuilder] = tuple()
250-
surfaces: tuple[SurfaceBuilder] = tuple()
251-
data: tuple[DataBuilder] = tuple()
357+
cells: dict[str, CellBuilder] = dataclasses.field(default_factory=lambda: ({}))
358+
surfaces: dict[str, SurfaceBuilder] = dataclasses.field(default_factory=lambda: ({}))
359+
data: dict[str, DataBuilder] = dataclasses.field(default_factory=lambda: ({}))
252360
message: str = ''
253361
other: str = ''
254362

@@ -261,11 +369,11 @@ def append(self, card: CellBuilder | SurfaceBuilder | DataBuilder):
261369
"""
262370

263371
if isinstance(card, CellBuilder):
264-
self.cells = (*self.cells, card)
372+
self.cells[card.number] = card
265373
elif isinstance(card, SurfaceBuilder):
266-
self.surfaces = (*self.surfaces, card)
374+
self.surfaces[card.number] = card
267375
elif isinstance(card, DataBuilder):
268-
self.data = (*self.data, card)
376+
self.data[card.mnemonic + card.suffix if hasattr(card, 'suffix') else ''] = card
269377

270378
def build(self):
271379
"""
@@ -279,10 +387,10 @@ def build(self):
279387
title=self.title,
280388
message=self.message,
281389
other=self.other,
282-
cells=types.Tuple([cell.build() for cell in self.cells]),
390+
cells=types.Tuple([cell.build() for cell in self.cells.values()]),
283391
cells_comments=types.Tuple([]),
284-
surfaces=types.Tuple([surface.build() for surface in self.surfaces]),
392+
surfaces=types.Tuple([surface.build() for surface in self.surfaces.values()]),
285393
surfaces_comments=types.Tuple([]),
286-
data=types.Tuple([data.build() for data in self.data]),
394+
data=types.Tuple([data.build() for data in self.data.values()]),
287395
data_comments=types.Tuple([]),
288396
)

src/pymcnp/inp/Cell.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Cell(Card_):
2424
}
2525

2626
_REGEX = re.compile(
27-
rf'\A(\S+)( \S+)((?<! 0) \S+|(?<= 0))( [^a-z]+)(( {cell.CellOption_._REGEX.pattern})+)?\Z'
27+
rf'\A(\S+)( \S+)((?<! 0) \S+|(?<= 0))( [^a-z]+)( ({cell.CellOption_._REGEX.pattern}))*\Z'
2828
)
2929

3030
def __init__(

0 commit comments

Comments
 (0)