1+ import re
12import typing
23
4+ import pandas
5+
6+ from . import outp
37from .utils import types
48from .utils import errors
59from .utils import _object
@@ -10,27 +14,50 @@ class Outp(_object.McnpFile):
1014 Represents OUTP files.
1115
1216 Attributes:
13- lines: OUTP lines.
17+ header: OUPT header.
18+ blocks: OUTP tables.
19+ footer: OUTP footer.
1420 """
1521
16- def __init__ (self , lines : types .Tuple [types .String ]):
22+ _REGEX = re .compile (
23+ rf'({ outp .Header ._REGEX .pattern [2 :- 2 ]} )'
24+ r'([\s\S]*)'
25+ rf'({ outp .Footer ._REGEX .pattern [2 :- 2 ]} )'
26+ )
27+
28+ def __init__ (
29+ self ,
30+ header : outp .Header ,
31+ blocks : types .Tuple [outp .Block ],
32+ footer : outp .Footer ,
33+ ):
1734 """
1835 Initializes ``Outp``.
1936
2037 Parameters:
21- lines: OUTP lines.
38+ header: OUPT header.
39+ blocks: OUTP tables.
40+ footer: OUTP footer.
2241
2342 Raises:
24- OutpError: SEMANTICS_OUTP .
43+ OutpError: SEMANTICS_TABLE .
2544 """
2645
27- if lines is None or None in lines :
28- raise errors .OutpError (errors .OutpCode .SEMANTICS_OUTP , lines )
46+ if header is None :
47+ raise errors .OutpError (errors .OutpCode .SEMANTICS_TABLE , header )
48+
49+ if blocks is None or None in blocks :
50+ raise errors .OutpError (errors .OutpCode .SEMANTICS_TABLE , blocks )
2951
30- self .lines : typing .Final [types .Tuple [types .String ]] = lines
52+ if footer is None :
53+ raise errors .OutpError (errors .OutpCode .SEMANTICS_TABLE , footer )
3154
32- @classmethod
33- def from_mcnp (cls , source : str ):
55+ self .header : typing .Final [outp .Header ] = header
56+ self .blocks : typing .Final [types .Tuple [outp .Block ]] = blocks
57+ self .footer : typing .Final [outp .Footer ] = footer
58+
59+ @staticmethod
60+ def from_mcnp (source : str ):
3461 """
3562 Generates ``Outp`` from OUTP.
3663
@@ -41,9 +68,38 @@ def from_mcnp(cls, source: str):
4168 ``Outp``.
4269 """
4370
44- lines = types .Tuple (map (lambda line : types .String (line ), source .split ('\n ' )))
71+ tokens = Outp ._REGEX .match (source )
72+
73+ if not tokens :
74+ raise errors .OutpError (errors .OutpCode .SYNTAX_TABLE , source )
75+
76+ offset = 0
77+ header = outp .Header .from_mcnp (tokens [1 + offset ])
78+ offset += outp .Header ._REGEX .groups
79+
80+ blocks = []
81+ for subsource in outp .Block ._REGEX .finditer (tokens [2 + offset ]):
82+ for subclass in outp .Block .__subclasses__ ():
83+ try :
84+ if block := subclass .from_mcnp (subsource [0 ]):
85+ break
86+ else :
87+ continue
88+ except Exception :
89+ continue
90+ else :
91+ raise errors .OutpError (errors .OutpCode .SYNTAX_TABLE , source )
92+
93+ blocks .append (block )
4594
46- return cls (lines )
95+ blocks = types .Tuple (blocks )
96+ footer = outp .Footer .from_mcnp (tokens [3 + offset ])
97+
98+ return Outp (
99+ header ,
100+ blocks ,
101+ footer ,
102+ )
47103
48104 def to_mcnp (self ):
49105 """
@@ -53,4 +109,32 @@ def to_mcnp(self):
53109 OUTP for ``Outp``.
54110 """
55111
56- return '\n ' .join (line for line in self .lines )
112+ return f"{ self .header } \n { "\n " .join (map (str , self .blocks ))} { self .footer } "
113+
114+ def to_dataframe (self ):
115+ """
116+ Generates ``pandas.DataFrame`` from ``Outp``.
117+
118+ Returns:
119+ Tuple of ``pandas.DataFrame``.
120+ """
121+
122+ tallynps1 = {}
123+ tallynps2 = {}
124+ tallynps4 = {}
125+
126+ for block in self .blocks :
127+ if isinstance (block , outp .TallyNps1 ):
128+ tallynps1 [block .tally ] = block
129+ elif isinstance (block , outp .TallyNps2 ):
130+ tallynps2 [block .tally ] = block
131+ elif isinstance (block , outp .TallyNps4 ):
132+ tallynps4 [block .tally ] = block
133+ else :
134+ continue
135+
136+ return (
137+ pandas .DataFrame (tallynps1 ),
138+ pandas .DataFrame (tallynps2 ),
139+ pandas .DataFrame (tallynps4 ),
140+ )
0 commit comments