diff --git a/src/pymcnp/files/inp/__init__.py b/src/pymcnp/files/inp/__init__.py index a051507..a595f6a 100644 --- a/src/pymcnp/files/inp/__init__.py +++ b/src/pymcnp/files/inp/__init__.py @@ -62,6 +62,7 @@ from .surface_cards import Trc as SurfaceTrc from .surface_cards import Ell as SurfaceEll from .surface_cards import Wed as SurfaceWed +from .surface_cards import Arb as SurfaceArb from .data import Data from .data_mnemonic import DataMnemonic from .data_entry import DataEntry @@ -183,6 +184,7 @@ 'SurfaceTrc', 'SurfaceEll', 'SurfaceWed', + 'SurfaceArb', 'Data', 'DataMnemonic', 'DataEntry', diff --git a/src/pymcnp/files/inp/_cadquery.py b/src/pymcnp/files/inp/_cadquery.py deleted file mode 100644 index 5ab8607..0000000 --- a/src/pymcnp/files/inp/_cadquery.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -Contains classes and functions for generating CADQUERY. -""" - -from __future__ import annotations -import math - -import numpy as np - - -class CqVector: - """ - ``CqVector`` represents vectors in Cadquery workplanes. - - ``CqVector`` abstracts the vectors used in constructing, translating, and - rotating Cadquery workplanes and INP visualizations. - - Attributes: - x: Vector x component. - y: Vector y component. - z: Vector z component. - """ - - def __init__(self, x: float, y: float, z: float): - """ - ``__init__`` initializes ``CqVector``. - """ - - self.x: float = x - self.y: float = y - self.z: float = z - - def norm(self) -> float: - """ - ``norm`` computes vector norms. - - ``norm`` calculates the length of``CqVector`` vectors using the - ``numpy`` package. - - Returns: - Length of the ``CqVector`` vector. - """ - - return np.linalg.norm([self.x, self.y, self.z]) - - def apothem(self) -> float: - """ - ``apothem`` computes vector apothems. - - ``apothem`` calculates the apothem, i.e. the length of the line - from the center of a polygon to its side given the vector points from - the center of a polygon to a corner using the ``numpy`` package. - - Returns: - Length of the apothem associated with the ``CqVector`` vector. - """ - - return np.linalg.norm([self.x, self.y, self.z]) * 2 / math.sqrt(3) - - @staticmethod - def cross(a: CqVector, b: CqVector): - """ - ``cross`` computes cross products of two vectors. - - ``cross`` calculates the cross products of the given ``CqVector`` - vectors using the ``numpy`` package. - - Parameters: - a: Operand ``CqVector`` vector #1. - b: Operand ``CqVector`` vector #2. - - Returns: - ``CqVector`` cross product of ``a`` and ``b``. - """ - - return CqVector(*np.cross([a.x, a.y, a.z], [b.x, b.y, b.z])) - - @staticmethod - def angle(a: CqVector, b: CqVector) -> float: - """ - ``angle`` computes angles between vectors. - - ``angle`` calculates the angle between the given ``CqVector`` vectors - using the ``numpy`` package. - - Parameters: - a: Operand ``CqVector`` vector #1. - b: Operand ``CqVector`` vector #2. - - Returns: - Angle between ``a`` and ``b`` in degrees. - """ - - return np.degrees(np.arccos(np.dot([a.x, a.y, a.z], [b.x, b.y, b.z]))) - - -def add_box(a: CqVector, b: CqVector, c: CqVector) -> str: - """ - ``add_box`` adds boxes to Cadquery workplanes. - - ``add_box`` writes Cadquery to represent an arbitrarily oriented - othogonal boxs given three orthogonal ``CqVector`` vectors representing - a path along the box edges the in order ``a``, ``b``, ``c``. It substitutes - vector endpoints into calls of the Cadquery ``polyline`` method which adds - squares to the Cadquery workplane. ``add_box`` includes calls to ``loft`` - and ``close`` in its output to turn the sqaures into surfaces and loft them - into boxs. - - Paremeters - a: Operand ``CqVector`` vector #1. - b: Operand ``CqVector`` vector #2. - c: Operand ``CqVector`` vector #3. - - Returns: - Cadquery representing an arbitrarily oriented othogonal box. - """ - - return ( - f'.polyline([' - f'(0, 0, 0), ' - f'({a.x}, {a.y}, {a.z}), ' - f'({a.x + b.x}, {a.y + b.y}, {a.z + b.z}), ' - f'({b.x}, {b.y}, {b.z}), ' - f']).close()' - f'.polyline([' - f'({c.x}, {c.y}, {c.z}), ' - f'({a.x + c.x}, {a.y + c.y}, {a.z + c.z}), ' - f'({a.x + b.x + c.x}, {a.y + b.y + c.y}, {a.z + b.z + c.z}), ' - f'({b.x + c.x}, {b.y + c.y}, {b.z + c.z}), ' - f']).close()' - f'.loft()' - ) - - -def add_sphere(r: float) -> str: - """ - ``add_sphere`` adds shperes to Cadquery workplanes. - - ``add_sphere`` writes Cadquery to represent spheres given radii. It - substitutes radii values into calls of the Cadquery ``sphere`` method which - adds spheres to the Cadquery workplane. - - Paremeters - r: Sphere radius. - - Returns: - Cadquery representing a sphere. - """ - - return f'.sphere({r})' - - -def add_cylinder_circle(h: float, r: float) -> str: - """ - ``add_cylinder_circle`` adds circular cylinders to Cadquery workplanes. - - ``add_cylinder_circle`` writes Cadquery to represent circular cylinder given - radii and heights. It substitutes the these values into calls of the - Cadquery ``cylinder`` method which adds cylidners to the workplane. - - Paremeters - r: Circular cylinder radius. - h: Circular cylinder height. - - Returns: - Cadquery representing a circular cylinder. - """ - - return f'.cylinder({h}, {r})' - - -def add_prism_polygon(h: float, a: float, n: int = 6) -> str: - """ - ``add_prism_polygon`` adds polygonal prisms to Cadquery workplanes. - - ``add_prism_polygon`` writes Cadquery to represent n-sided polygonal - prisms given apothem lengths and heights. It substitutes the these values - into calls of the Cadquery ``regularPolygon`` method which sketches these - polygons in the Cadquery workplane. ``add_prism_polygon`` includes calls to - ``sketch``, ``finalize``, and ``extrude`` to transform the polygon sketches - into surfaces and extend them into polgyonal prisms. - - Paremeters - a: n-Sided polygonal prism apothem length. - h: n-Sided polygonal prism height. - n: Number of sides of the polygon. - - Returns: - Cadquery representing a n-polygonal prism. - """ - - return f'.sketch().regularPolygon({a}, {n}).finalize().extrude({h})' - - -def add_cylinder_ellipse(h: float, a: float, b: float) -> str: - """ - ``add_cylinder_ellipse`` adds elliptical cylinders to Cadquery workplanes. - - ``add_cylinder_ellipse`` writes Cadquery to represent elliptical cylinder - given minor and major axis length and heights. It substitutes these values - into calls of the Cadquery ``ellipse`` method which adds ellipses to the - Cadquery workplane. ``add_cylinder_ellipse`` includes calls to ``extrude`` - in its output to extend the ellipses into elliptical cylinders. - - Paremeters - a: Elliptical cylinder major axis length. - b: Elliptical cylinder minor axis length. - h: Elliptical cylinder height. - - Returns: - Cadquery representing an elliptical cylinder. - """ - - return f'.ellipse({a}, {b}).extrude({h})' - - -def add_cone_truncated(h: float, r1: float, r2: float) -> str: - """ - ``add_cone_truncated`` adds truncated cones to Cadquery workplanes. - - ``add_cone_truncated`` writes Cadquery to represent truncated cones given - two radii and heights. It substitutes these values into calls of the - Cadquery ``circle`` method which adds circles to the Cadquery workplane. - ``add_cone_truncated`` includes calls to ``loft`` in its output to loft the - circles into truncated cones. - - Paremeters - h: Truncated cone height. - r1: Truncated cone radius #1. - r2: Truncated cone radius #2. - - Returns: - Cadquery representing a truncated cone. - """ - - return f'.circle({r1}).workplane(offset={h}).circle({r2}).loft()' - - -def add_ellipsoid(a: float, b: float) -> str: - """ - ``add_ellipsoid`` adds ellipsoids to Cadquery workplanes. - - ``add_ellipsoid`` writes Cadquery to represent ellipsoids given minor and - major axis length. It substitutes these values into calls of the Cadquery - ``ellipseArc`` method which adds ellipsoids to the Cadquery workplane. - ``add_cylinder_ellipse`` includes calls to ``revolove`` in its output to - build a complete ellipsoid from an ellipse. - - Paremeters - a: Ellipsoid major axis length. - b: Ellipsoid minor axis length. - - Returns: - Cadquery representing an ellispoid. - """ - - return f'.ellipseArc({a}, {b}, -90, 90).close().revolve(axisStart=(0, -{a}, 0), axisEnd=(0, {a}, 0))' - - -def add_wedge(a: CqVector, b: CqVector, c: CqVector) -> str: - """ - ``add_wedge`` adds wedges to Cadquery workplanes. - - ``add_wedge`` writes Cadquery to represent wedges given three vectors. It - substitutes these values into calls of the Cadquery ``polyline`` method - which adds a sketchs wedges to the Cadquery workplane. ``add_wedge`` - includes calls to ``loft`` in its output to loft the polylines in to shape. - - Paremeters - a: Wedge vector #1. - b: Wedge vector #2. - c: Wedge vector #3. - - Returns: - Cadquery representing a wedge. - """ - - return ( - f'.polyline([({a.x}, {a.y}, {a.z}), (0, 0, 0), ({b.x}, {b.y}, {b.z})]).close().' - 'polyline([({a.x + c.x}, {a.y + c.y}, {a.z + c.z}), ({c.x}, {c.y}, {c.z}), ({b.x + c.x}, {b.y + c.y}, {b.z + c.z})]).' - 'close().loft()' - ) - - -def add_translation(v: CqVector) -> str: - """ - ``add_translation`` adds translations to Cadquey workplanes. - - ``add_translation`` writes Cadquery to translate Cadquery workplanes given - vectors specifiying the trasformation. It substitutes vectors' components - into calls of the Cadquery ``translate`` method which moves the workplane - based on the given vector. - - Parameters: - v: Vector specifying the translation. - - Returns: - Cadquery representing a truncated cone. - """ - - return f'.translate(({v.x}, {v.y}, {v.z}))' - - -def add_rotation(axis: CqVector, angle: float) -> str: - """ - ``add_rotation`` adds rotations to Cadquey workplanes. - - ``add_rotation`` writes Cadquery to rotate Cadquery workplanes given axeses - of rotation and angles. It substitutes axes' components and the angles into - calls of the Cadquery ``rotate`` method which moves the workplane based - on the given axis and angle. - - Parameters: - v: Vector specifying the translation. - """ - - return f'.rotate(({-axis.x}, {-axis.y}, {-axis.z}), ({axis.x}, {axis.y}, {axis.z}), {angle})' diff --git a/src/pymcnp/files/inp/inp.py b/src/pymcnp/files/inp/inp.py index 66d0b8d..ec7a5e2 100644 --- a/src/pymcnp/files/inp/inp.py +++ b/src/pymcnp/files/inp/inp.py @@ -3,9 +3,10 @@ """ import re +import pathlib from typing import Final -import pathlib +import pyvista from .comment import Comment from .cell import Cell @@ -104,6 +105,7 @@ from ..utils import errors from ..utils import _parser from ..utils import _object +from ..utils import _visualization class Inp(_object.PyMcnpFileObject): @@ -726,3 +728,18 @@ def to_mcnp_file(self, filename: str | pathlib.Path): filename = pathlib.Path(filename) filename.write_text(self.to_mcnp()) + + def to_pyvista(self) -> pyvista.PolyData: + """ + Generates ``pyvista.PolyData`` representing ``Inp``. + + Returns: + ``pyvista.PolyData`` for ``Inp``. + """ + + vis = _visualization.PyMcnpVisualization() + + for surface in self.surfaces.values(): + vis += _visualization.PyMcnpVisualization(surface.to_pyvista()) + + return vis.data diff --git a/src/pymcnp/files/inp/surface.py b/src/pymcnp/files/inp/surface.py index b845afc..ac960e4 100644 --- a/src/pymcnp/files/inp/surface.py +++ b/src/pymcnp/files/inp/surface.py @@ -47,3 +47,6 @@ def to_mcnp(self) -> str: source = f'{number_str} {transform_str} {self.mnemonic.to_mcnp()} {parameter_str}' return _parser.Postprocessor.add_continuation_lines(source) + + def to_pyvista(self): + raise NotImplementedError diff --git a/src/pymcnp/files/inp/surface_cards/arb.py b/src/pymcnp/files/inp/surface_cards/arb.py index 87140ef..8685e79 100644 --- a/src/pymcnp/files/inp/surface_cards/arb.py +++ b/src/pymcnp/files/inp/surface_cards/arb.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Arb(Surface): @@ -88,7 +91,6 @@ def __init__( """ Initializes ``Arb``. - Parameters: ax: Polyhedron corner #1 x component. ay: Polyhedron corner #1 y component. @@ -423,3 +425,45 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Arb``. + + Returns: + ``pyvista.PolyData`` for ``Arb``. + """ + + a = _visualization.Vector(self.ax.value, self.ay.value, self.az.value) + b = _visualization.Vector(self.bx.value, self.by.value, self.bz.value) + c = _visualization.Vector(self.cx.value, self.cy.value, self.cz.value) + d = _visualization.Vector(self.dx.value, self.dy.value, self.dz.value) + e = _visualization.Vector(self.ex.value, self.ey.value, self.ez.value) + f = _visualization.Vector(self.fx.value, self.fy.value, self.fz.value) + g = _visualization.Vector(self.gx.value, self.gy.value, self.gz.value) + h = _visualization.Vector(self.hx.value, self.hy.value, self.hz.value) + + vectices = [] + for vec in [a, b, c, d, e, f, g, h]: + if vec.x == 0 and vec.y == 0 and vec.z == 0: + continue + else: + vectices.append(vec) + + faces = [] + for n in [ + self.n1.value, + self.n2.value, + self.n3.value, + self.n4.value, + self.n5.value, + self.n6.value, + ]: + if n == 0: + continue + else: + faces.append([n // 1000 % 10, n // 100 % 10, n // 10 % 10, n // 1 % 10]) + + vis = _visualization.PyMcnpVisualization.get_polyhedron(vectices, faces) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/box.py b/src/pymcnp/files/inp/surface_cards/box.py index b2367e7..dfa1314 100644 --- a/src/pymcnp/files/inp/surface_cards/box.py +++ b/src/pymcnp/files/inp/surface_cards/box.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Box(Surface): @@ -52,7 +55,6 @@ def __init__( """ Initializes ``Box``. - Parameters: vx: Box macrobody position vector x component. vy: Box macrobody position vector y component. @@ -230,3 +232,25 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Box``. + + Returns: + ``pyvista.PolyData`` for ``Box``. + """ + + v = _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + a1 = _visualization.Vector(self.a1x.value, self.a1y.value, self.a1z.value) + a2 = _visualization.Vector(self.a2x.value, self.a2y.value, self.a2z.value) + a3 = _visualization.Vector(self.a3x.value, self.a3y.value, self.a3z.value) + + cross = _visualization.Vector(1, 0, 0) * a1 + angle = _visualization.Vector(1, 0, 0) & a1 + + vis = _visualization.PyMcnpVisualization.get_box(a1.norm(), a2.norm(), a3.norm()) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(v) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/c_x.py b/src/pymcnp/files/inp/surface_cards/c_x.py index 5bdca57..fdb2f33 100644 --- a/src/pymcnp/files/inp/surface_cards/c_x.py +++ b/src/pymcnp/files/inp/surface_cards/c_x.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class C_x(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``C_x``. - Parameters: y: Parallel-to-x-axis cylinder center y component. z: Parallel-to-x-axis cylinder center z component. @@ -147,3 +149,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``C_x``. + + Returns: + ``pyvista.PolyData`` for ``C_x``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(0, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/c_y.py b/src/pymcnp/files/inp/surface_cards/c_y.py index 03cf03c..c5074c3 100644 --- a/src/pymcnp/files/inp/surface_cards/c_y.py +++ b/src/pymcnp/files/inp/surface_cards/c_y.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class C_y(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``C_y``. - Parameters: x: Parallel-to-y-axis cylinder center x component. z: Parallel-to-y-axis cylinder center z component. @@ -147,3 +149,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``C_y``. + + Returns: + ``pyvista.PolyData`` for ``C_y``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, 0, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/c_z.py b/src/pymcnp/files/inp/surface_cards/c_z.py index faffbf1..1183b30 100644 --- a/src/pymcnp/files/inp/surface_cards/c_z.py +++ b/src/pymcnp/files/inp/surface_cards/c_z.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class C_z(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``C_z``. - Parameters: x: Parallel-to-z-axis cylinder center x component. y: Parallel-to-z-axis cylinder center y component. @@ -147,3 +149,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``C_z``. + + Returns: + ``pyvista.PolyData`` for ``C_z``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/cx.py b/src/pymcnp/files/inp/surface_cards/cx.py index 0702af0..40168c2 100644 --- a/src/pymcnp/files/inp/surface_cards/cx.py +++ b/src/pymcnp/files/inp/surface_cards/cx.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Cx(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Cx``. - Parameters: r: On-x-axis cylinder radius. @@ -125,3 +127,16 @@ def from_mcnp(source: str): return Cx( number, transform, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Cx``. + + Returns: + ``pyvista.PolyData`` for ``Cx``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/cy.py b/src/pymcnp/files/inp/surface_cards/cy.py index 249c3d8..6d924c9 100644 --- a/src/pymcnp/files/inp/surface_cards/cy.py +++ b/src/pymcnp/files/inp/surface_cards/cy.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Cy(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Cy``. - Parameters: r: On-y-axis cylinder radius. @@ -125,3 +127,16 @@ def from_mcnp(source: str): return Cy( number, transform, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Cy``. + + Returns: + ``pyvista.PolyData`` for ``Cy``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/cz.py b/src/pymcnp/files/inp/surface_cards/cz.py index 0edd001..2845b1a 100644 --- a/src/pymcnp/files/inp/surface_cards/cz.py +++ b/src/pymcnp/files/inp/surface_cards/cz.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Cz(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Cz``. - Parameters: r: On-z-axis cylinder radius. @@ -125,3 +127,15 @@ def from_mcnp(source: str): return Cz( number, transform, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Cz``. + + Returns: + ``pyvista.PolyData`` for ``Cz``. + """ + + vis = _visualization.PyMcnpVisualization.get_cylinder_unbounded(self.r.value) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/ell.py b/src/pymcnp/files/inp/surface_cards/ell.py index 32cb724..faa15be 100644 --- a/src/pymcnp/files/inp/surface_cards/ell.py +++ b/src/pymcnp/files/inp/surface_cards/ell.py @@ -2,11 +2,15 @@ Contains the ``Ell`` subclass of ``Surface``. """ +import math from typing import Final from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Ell(Surface): @@ -42,7 +46,6 @@ def __init__( """ Initializes ``Ell``. - Parameters: v1x: Ellipsoid focus #1 or center x component. v1y: Ellipsoid focus #1 or center y component. @@ -183,3 +186,35 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Ell``. + + Returns: + ``pyvista.PolyData`` for ``Ell``. + """ + + v1 = _visualization.Vector(self.v1x.value, self.v1y.value, self.v1z.value) + v2 = _visualization.Vector(self.v2x.value, self.v2y.value, self.v2z.value) + + if self.rm > 0: + center = _visualization.Vector( + (v2 - v1).x / 2 + v1.x, (v2 - v1).y / 2 + v1.y, (v2 - v1).z / 2 + v1.z + ) + major_length = self.rm.value + minor_length = 2 * math.sqrt((major_length / 2) ** 2 - ((v2 - v1).norm() / 2) ** 2) + cross = (v2 - v1) * _visualization.Vector(1, 0, 0) + angle = (v2 - v1) & _visualization.Vector(1, 0, 0) + elif self.rm < 0: + center = v1 + major_length = v2.norm() + minor_length = -self.rm.value + cross = v2 * _visualization.Vector(1, 0, 0) + angle = v2 & _visualization.Vector(1, 0, 0) + + vis = _visualization.PyMcnpVisualization.get_ellipsoid(major_length, minor_length) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(center) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/gq.py b/src/pymcnp/files/inp/surface_cards/gq.py index 24fb885..a15a79a 100644 --- a/src/pymcnp/files/inp/surface_cards/gq.py +++ b/src/pymcnp/files/inp/surface_cards/gq.py @@ -6,7 +6,9 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import types +from ...utils import errors +from ...utils import _parser class Gq(Surface): @@ -48,7 +50,6 @@ def __init__( """ Initializes ``Gq``. - Parameters: a: Oblique special quadratic A coefficent. b: Oblique special quadratic B coefficent. diff --git a/src/pymcnp/files/inp/surface_cards/k_x.py b/src/pymcnp/files/inp/surface_cards/k_x.py index 2e84ecd..17993bf 100644 --- a/src/pymcnp/files/inp/surface_cards/k_x.py +++ b/src/pymcnp/files/inp/surface_cards/k_x.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class K_x(Surface): @@ -38,7 +41,6 @@ def __init__( """ Initializes ``K_x``. - Parameters: x: Parallel-to-x-axis cone center x component. y: Parallel-to-x-axis cone center y component. @@ -165,3 +167,19 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``K_x``. + + Returns: + ``pyvista.PolyData`` for ``K_x``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/k_y.py b/src/pymcnp/files/inp/surface_cards/k_y.py index 1e36959..3f490c5 100644 --- a/src/pymcnp/files/inp/surface_cards/k_y.py +++ b/src/pymcnp/files/inp/surface_cards/k_y.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class K_y(Surface): @@ -38,7 +41,6 @@ def __init__( """ Initializes ``K_y``. - Parameters: x: Parallel-to-y-axis cone center x component. y: Parallel-to-y-axis cone center y component. @@ -165,3 +167,19 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``K_y``. + + Returns: + ``pyvista.PolyData`` for ``K_y``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/k_z.py b/src/pymcnp/files/inp/surface_cards/k_z.py index c49c23e..c456efe 100644 --- a/src/pymcnp/files/inp/surface_cards/k_z.py +++ b/src/pymcnp/files/inp/surface_cards/k_z.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class K_z(Surface): @@ -38,7 +41,6 @@ def __init__( """ Initializes ``K_z``. - Parameters: x: Parallel-to-z-axis cone center x component. y: Parallel-to-z-axis cone center y component. @@ -165,3 +167,18 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``K_z``. + + Returns: + ``pyvista.PolyData`` for ``K_z``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/kx.py b/src/pymcnp/files/inp/surface_cards/kx.py index aca078e..2b83411 100644 --- a/src/pymcnp/files/inp/surface_cards/kx.py +++ b/src/pymcnp/files/inp/surface_cards/kx.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Kx(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``Kx``. - Parameters: x: On-x-axis cone center x component. t_squared: On-x-axis cone t^2 coefficent. @@ -147,3 +149,19 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Kx``. + + Returns: + ``pyvista.PolyData`` for ``Kx``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/ky.py b/src/pymcnp/files/inp/surface_cards/ky.py index 9436fd6..66eb78a 100644 --- a/src/pymcnp/files/inp/surface_cards/ky.py +++ b/src/pymcnp/files/inp/surface_cards/ky.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Ky(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``Ky``. - Parameters: y: On-y-axis cone center y component. t_squared: On-y-axis cone t^2 coefficent. @@ -147,3 +149,19 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Ky``. + + Returns: + ``pyvista.PolyData`` for ``Ky``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(0, self.y.value, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/kz.py b/src/pymcnp/files/inp/surface_cards/kz.py index ab7a238..40b41ef 100644 --- a/src/pymcnp/files/inp/surface_cards/kz.py +++ b/src/pymcnp/files/inp/surface_cards/kz.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Kz(Surface): @@ -34,7 +37,6 @@ def __init__( """ Initializes ``Kz``. - Parameters: z: On-z-axis cone center z component. t_squared: On-z-axis cone t^2 coefficent. @@ -147,3 +149,18 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Kz``. + + Returns: + ``pyvista.PolyData`` for ``Kz``. + """ + + vis = _visualization.PyMcnpVisualization.get_cone_quadratic( + self.t_squared.value ** (1 / 2), self.plusminus_1.value + ) + vis = vis.add_translation(_visualization.Vector(0, 0, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/p.py b/src/pymcnp/files/inp/surface_cards/p.py index 17dccde..d988e37 100644 --- a/src/pymcnp/files/inp/surface_cards/p.py +++ b/src/pymcnp/files/inp/surface_cards/p.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class P(Surface): @@ -36,7 +39,6 @@ def __init__( """ Initializes ``P``. - Parameters: a: Equation-defined general plane A coefficent. b: Equation-defined general plane B coefficent. @@ -156,3 +158,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``P``. + + Returns: + ``pyvista.PolyData`` for ``P``. + """ + + vis = _visualization.PyMcnpVisualization.get_plane( + self.a.value, self.b.value, self.c.value, self.d.value + ) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/px.py b/src/pymcnp/files/inp/surface_cards/px.py index 03397e2..b008a1f 100644 --- a/src/pymcnp/files/inp/surface_cards/px.py +++ b/src/pymcnp/files/inp/surface_cards/px.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Px(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Px``. - Parameters: d: Normal-to-the-x-axis plane D coefficent. @@ -125,3 +127,16 @@ def from_mcnp(source: str): return Px( number, transform, d, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Px``. + + Returns: + ``pyvista.PolyData`` for ``Px``. + """ + + vis = _visualization.PyMcnpVisualization.get_plane(1, 0, 0, self.d.value) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/py.py b/src/pymcnp/files/inp/surface_cards/py.py index ede2a81..1feab74 100644 --- a/src/pymcnp/files/inp/surface_cards/py.py +++ b/src/pymcnp/files/inp/surface_cards/py.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Py(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Py``. - Parameters: d: Normal-to-the-y-axis plane D coefficent. @@ -125,3 +127,16 @@ def from_mcnp(source: str): return Py( number, transform, d, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Py``. + + Returns: + ``pyvista.PolyData`` for ``Py``. + """ + + vis = _visualization.PyMcnpVisualization.get_plane(0, 1, 0, self.d.value) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/pz.py b/src/pymcnp/files/inp/surface_cards/pz.py index 0272339..29ef610 100644 --- a/src/pymcnp/files/inp/surface_cards/pz.py +++ b/src/pymcnp/files/inp/surface_cards/pz.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Pz(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``Pz``. - Parameters: d: Normal-to-the-z-axis plane D coefficent. @@ -125,3 +127,15 @@ def from_mcnp(source: str): return Pz( number, transform, d, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Pz``. + + Returns: + ``pyvista.PolyData`` for ``Pz``. + """ + + vis = _visualization.PyMcnpVisualization.get_plane(0, 0, 1, self.d.value) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/rcc.py b/src/pymcnp/files/inp/surface_cards/rcc.py index aba8b5f..0ed134a 100644 --- a/src/pymcnp/files/inp/surface_cards/rcc.py +++ b/src/pymcnp/files/inp/surface_cards/rcc.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Rcc(Surface): @@ -42,7 +45,6 @@ def __init__( """ Initializes ``Rcc``. - Parameters: vx: Circular cylinder macrobody position vector x component. vy: Circular cylinder macrobody position vector y component. @@ -183,3 +185,23 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Rcc``. + + Returns: + ``pyvista.PolyData`` for ``Rcc``. + """ + + v = _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + h = _visualization.Vector(self.hx.value, self.hy.value, self.hz.value) + + cross = v * _visualization.Vector(0, 0, 1) + angle = v & _visualization.Vector(0, 0, 1) + + vis = _visualization.PyMcnpVisualization.get_cylinder_circle(h.norm(), self.r.value) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(v) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/rec.py b/src/pymcnp/files/inp/surface_cards/rec.py index 538b4d7..2fc2081 100644 --- a/src/pymcnp/files/inp/surface_cards/rec.py +++ b/src/pymcnp/files/inp/surface_cards/rec.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Rec(Surface): @@ -52,7 +55,6 @@ def __init__( """ Initializes ``Rec``. - Parameters: vx: Elliptical cylinder position vector x component. vy: Elliptical cylinder position vector y component. @@ -230,3 +232,27 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Rec``. + + Returns: + ``pyvista.PolyData`` for ``Rec``. + """ + + v = _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + h = _visualization.Vector(self.hx.value, self.hy.value, self.hz.value) + v1 = _visualization.Vector(self.v1x.value, self.v1y.value, self.v1z.value) + v2 = _visualization.Vector(self.v2x.value, self.v2y.value, self.v2z.value) + + cross = v * _visualization.Vector(0, 0, 1) + angle = v & _visualization.Vector(0, 0, 1) + + vis = _visualization.PyMcnpVisualization.get_cylinder_ellipse( + h.norm(), v1.norm(), v2.norm() + ) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(v) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/rhp.py b/src/pymcnp/files/inp/surface_cards/rhp.py index b349e60..e744712 100644 --- a/src/pymcnp/files/inp/surface_cards/rhp.py +++ b/src/pymcnp/files/inp/surface_cards/rhp.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Rhp(Surface): @@ -58,7 +61,6 @@ def __init__( """ Initializes ``Rhp``. - Parameters: vx: Hexagonal prism position vector x component. vy: Hexagonal prism position vector y component. @@ -257,3 +259,28 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Rhp``. + + Returns: + ``pyvista.PolyData`` for ``Rhp``. + """ + + v = _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + h = _visualization.Vector(self.hx.value, self.hy.value, self.hz.value) + r = _visualization.Vector(self.r1.value, self.r2.value, self.r3.value) + s = _visualization.Vector(self.s1.value, self.s2.value, self.s3.value) + t = _visualization.Vector(self.t1.value, self.t2.value, self.t3.value) + + cross = v * _visualization.Vector(0, 0, 1) + angle = v & _visualization.Vector(0, 0, 1) + + vis = _visualization.PyMcnpVisualization.get_cylinder_hexagon( + h.norm(), r.apothem(), s.apothem(), t.apothem() + ) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(v) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/rpp.py b/src/pymcnp/files/inp/surface_cards/rpp.py index a097108..a8aa3a0 100644 --- a/src/pymcnp/files/inp/surface_cards/rpp.py +++ b/src/pymcnp/files/inp/surface_cards/rpp.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Rpp(Surface): @@ -40,7 +43,6 @@ def __init__( """ Initializes ``Rpp``. - Parameters: xmin: Parallelepiped x termini minimum. xmax: Parallelepiped x termini maximum. @@ -174,3 +176,22 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Rpp``. + + Returns: + ``pyvista.PolyData`` for ``Rpp``. + """ + + vis = _visualization.PyMcnpVisualization.get_parallelipiped( + self.xmin.value, + self.xmax.value, + self.ymin.value, + self.ymax.value, + self.zmin.value, + self.zmax.value, + ) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/s.py b/src/pymcnp/files/inp/surface_cards/s.py index 7dcb86e..1629f62 100644 --- a/src/pymcnp/files/inp/surface_cards/s.py +++ b/src/pymcnp/files/inp/surface_cards/s.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class S(Surface): @@ -36,7 +39,6 @@ def __init__( """ Initializes ``S``. - Parameters: x: General sphere center x component. y: General sphere center y component. @@ -156,3 +158,16 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``S``. + + Returns: + ``pyvista.PolyData`` for ``S``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/so.py b/src/pymcnp/files/inp/surface_cards/so.py index fbfbece..044b078 100644 --- a/src/pymcnp/files/inp/surface_cards/so.py +++ b/src/pymcnp/files/inp/surface_cards/so.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class So(Surface): @@ -30,7 +33,6 @@ def __init__( """ Initializes ``So``. - Parameters: r: Origin-centered sphere radius. @@ -125,3 +127,15 @@ def from_mcnp(source: str): return So( number, transform, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``So``. + + Returns: + ``pyvista.PolyData`` for ``So``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/sph.py b/src/pymcnp/files/inp/surface_cards/sph.py index b68dbd5..f649a41 100644 --- a/src/pymcnp/files/inp/surface_cards/sph.py +++ b/src/pymcnp/files/inp/surface_cards/sph.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Sph(Surface): @@ -36,7 +39,6 @@ def __init__( """ Initializes ``Sph``. - Parameters: vx: Sphere macrobody position vector x component. vy: Sphere macrobody position vector y component. @@ -156,3 +158,18 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Sph``. + + Returns: + ``pyvista.PolyData`` for ``Sph``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + vis = vis.add_translation( + _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + ) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/sq.py b/src/pymcnp/files/inp/surface_cards/sq.py index ecec736..86d9e94 100644 --- a/src/pymcnp/files/inp/surface_cards/sq.py +++ b/src/pymcnp/files/inp/surface_cards/sq.py @@ -6,7 +6,9 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import types +from ...utils import errors +from ...utils import _parser class Sq(Surface): @@ -48,7 +50,6 @@ def __init__( """ Initializes ``Sq``. - Parameters: a: Oblique special quadratic A coefficent. b: Oblique special quadratic B coefficent. diff --git a/src/pymcnp/files/inp/surface_cards/sx.py b/src/pymcnp/files/inp/surface_cards/sx.py index 27fce5a..e008f25 100644 --- a/src/pymcnp/files/inp/surface_cards/sx.py +++ b/src/pymcnp/files/inp/surface_cards/sx.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Sx(Surface): @@ -32,7 +35,6 @@ def __init__( """ Initializes ``Sx``. - Parameters: x: On-x-axis sphere center x component. r: On-x-axis sphere radius. @@ -133,3 +135,16 @@ def from_mcnp(source: str): return Sx( number, transform, x, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Sx``. + + Returns: + ``pyvista.PolyData`` for ``Sx``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + vis = vis.add_translation(_visualization.Vector(self.x.value, 0, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/sy.py b/src/pymcnp/files/inp/surface_cards/sy.py index 2702ae6..ca5fdc2 100644 --- a/src/pymcnp/files/inp/surface_cards/sy.py +++ b/src/pymcnp/files/inp/surface_cards/sy.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Sy(Surface): @@ -32,7 +35,6 @@ def __init__( """ Initializes ``Sy``. - Parameters: y: On-y-axis sphere center y component. r: On-y-axis sphere radius. @@ -133,3 +135,17 @@ def from_mcnp(source: str): return Sy( number, transform, y, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Sy``. + + Returns: + ``pyvista.PolyData`` for ``Sy``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(0, self.y.value, 0)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/sz.py b/src/pymcnp/files/inp/surface_cards/sz.py index 78119b5..e0d8445 100644 --- a/src/pymcnp/files/inp/surface_cards/sz.py +++ b/src/pymcnp/files/inp/surface_cards/sz.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Sz(Surface): @@ -32,7 +35,6 @@ def __init__( """ Initializes ``Sz``. - Parameters: z: On-z-axis sphere center z component. r: On-z-axis sphere radius. @@ -133,3 +135,16 @@ def from_mcnp(source: str): return Sz( number, transform, z, r, is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Sz``. + + Returns: + ``pyvista.PolyData`` for ``Sz``. + """ + + vis = _visualization.PyMcnpVisualization.get_sphere(self.r.value) + vis = vis.add_translation(_visualization.Vector(0, 0, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/trc.py b/src/pymcnp/files/inp/surface_cards/trc.py index 64d2952..3944100 100644 --- a/src/pymcnp/files/inp/surface_cards/trc.py +++ b/src/pymcnp/files/inp/surface_cards/trc.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Trc(Surface): @@ -44,7 +47,6 @@ def __init__( """ Initializes ``Trc``. - Parameters: vx: Truncated cone position vector x component. vy: Truncated cone position vector y component. @@ -192,3 +194,26 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Trc``. + + Returns: + ``pyvista.PolyData`` for ``Trc``. + """ + + h = _visualization.Vector(self.hx.value, self.hy.value, self.hz.value) + + cross = h * _visualization.Vector(0, 0, 1) + angle = h & _visualization.Vector(0, 0, 1) + + vis = _visualization.PyMcnpVisualization.get_cone_truncated( + h.norm(), self.r1.value, self.r2.value + ) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation( + _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + ) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/tx.py b/src/pymcnp/files/inp/surface_cards/tx.py index 9de2fbe..021b92a 100644 --- a/src/pymcnp/files/inp/surface_cards/tx.py +++ b/src/pymcnp/files/inp/surface_cards/tx.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Tx(Surface): @@ -40,7 +43,6 @@ def __init__( """ Initializes ``Tx``. - Parameters: x: Parallel-to-x-axis tori center x component. y: Parallel-to-x-axis tori center y component. @@ -174,3 +176,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Tx``. + + Returns: + ``pyvista.PolyData`` for ``Tx``. + """ + + vis = _visualization.PyMcnpVisualization.get_torus(self.b.value, self.c.value, self.a.value) + vis = vis.add_rotation(_visualization.Vector(0, 1, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/ty.py b/src/pymcnp/files/inp/surface_cards/ty.py index 6634c7b..07f1073 100644 --- a/src/pymcnp/files/inp/surface_cards/ty.py +++ b/src/pymcnp/files/inp/surface_cards/ty.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Ty(Surface): @@ -40,7 +43,6 @@ def __init__( """ Initializes ``Ty``. - Parameters: x: Parallel-to-y-axis tori center x component. y: Parallel-to-y-axis tori center y component. @@ -174,3 +176,17 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Ty``. + + Returns: + ``pyvista.PolyData`` for ``Ty``. + """ + + vis = _visualization.PyMcnpVisualization.get_torus(self.b.value, self.c.value, self.a.value) + vis = vis.add_rotation(_visualization.Vector(1, 0, 0), 90, (0, 0, 0)) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/tz.py b/src/pymcnp/files/inp/surface_cards/tz.py index 4b8f4df..6ea00fb 100644 --- a/src/pymcnp/files/inp/surface_cards/tz.py +++ b/src/pymcnp/files/inp/surface_cards/tz.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Tz(Surface): @@ -40,7 +43,6 @@ def __init__( """ Initializes ``Tz``. - Parameters: x: Parallel-to-z-axis tori center x component. y: Parallel-to-z-axis tori center y component. @@ -174,3 +176,16 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Tz``. + + Returns: + ``pyvista.PolyData`` for ``Tz``. + """ + + vis = _visualization.PyMcnpVisualization.get_torus(self.b.value, self.c.value, self.a.value) + vis = vis.add_translation(_visualization.Vector(self.x.value, self.y.value, self.z.value)) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/wed.py b/src/pymcnp/files/inp/surface_cards/wed.py index 8d12e04..2f63ec9 100644 --- a/src/pymcnp/files/inp/surface_cards/wed.py +++ b/src/pymcnp/files/inp/surface_cards/wed.py @@ -6,7 +6,10 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import _visualization +from ...utils import types +from ...utils import errors +from ...utils import _parser class Wed(Surface): @@ -52,7 +55,6 @@ def __init__( """ Initializes ``Wed``. - Parameters: vx: Wedge position vector x component. vy: Wedge position vector y component. @@ -230,3 +232,25 @@ def from_mcnp(source: str): is_whiteboundary=is_whiteboundary, is_reflecting=is_reflecting, ) + + def to_pyvista(self): + """ + Generates ``pyvista.PolyData`` representing ``Wed``. + + Returns: + ``pyvista.PolyData`` for ``Wed``. + """ + + v = _visualization.Vector(self.vx.value, self.vy.value, self.vz.value) + v1 = _visualization.Vector(self.v1x.value, self.v1y.value, self.v1z.value) + v2 = _visualization.Vector(self.v2x.value, self.v2y.value, self.v2z.value) + v3 = _visualization.Vector(self.v3x.value, self.v3y.value, self.v3z.value) + + cross = _visualization.Vector(1, 0, 0) * v1 + angle = _visualization.Vector(1, 0, 0) & v1 + + vis = _visualization.PyMcnpVisualization.get_wedge(v1.norm(), v2.norm(), v3.norm()) + vis = vis.add_rotation(cross, angle, (0, 0, 0)) + vis = vis.add_translation(v) + + return vis.data diff --git a/src/pymcnp/files/inp/surface_cards/x.py b/src/pymcnp/files/inp/surface_cards/x.py index cfd5511..aee0d68 100644 --- a/src/pymcnp/files/inp/surface_cards/x.py +++ b/src/pymcnp/files/inp/surface_cards/x.py @@ -6,7 +6,9 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import types +from ...utils import errors +from ...utils import _parser class X(Surface): @@ -40,7 +42,6 @@ def __init__( """ Initializes ``X``. - Parameters: x1: X-axisymmetric point-defined surface point #1 x component. r1: X-axisymmetric point-defined surface point #1 radius. @@ -79,17 +80,11 @@ def __init__( if r1 is None: raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r1)) - if x2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(x2)) - - if r2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r2)) - - if x3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(x3)) + if x3 is None != r3 is None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(x3) + str(r3)) - if r3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r3)) + if x2 is None != r2 is None and x3 is not None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(x2) + str(r2)) self.ident: Final[int] = number.value self.number: Final[types.McnpInteger] = number diff --git a/src/pymcnp/files/inp/surface_cards/y.py b/src/pymcnp/files/inp/surface_cards/y.py index 5500483..7ef1761 100644 --- a/src/pymcnp/files/inp/surface_cards/y.py +++ b/src/pymcnp/files/inp/surface_cards/y.py @@ -6,7 +6,9 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import types +from ...utils import errors +from ...utils import _parser class Y(Surface): @@ -40,7 +42,6 @@ def __init__( """ Initializes ``Y``. - Parameters: y1: Y-axisymmetric point-defined surface point #1 y component. r1: Y-axisymmetric point-defined surface point #1 radius. @@ -79,17 +80,11 @@ def __init__( if r1 is None: raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r1)) - if y2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(y2)) - - if r2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r2)) - - if y3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(y3)) + if y3 is None != r3 is None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(y3) + str(r3)) - if r3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r3)) + if y2 is None != r2 is None and y3 is not None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(y2) + str(r2)) self.ident: Final[int] = number.value self.number: Final[types.McnpInteger] = number diff --git a/src/pymcnp/files/inp/surface_cards/z.py b/src/pymcnp/files/inp/surface_cards/z.py index 06c540c..49acaac 100644 --- a/src/pymcnp/files/inp/surface_cards/z.py +++ b/src/pymcnp/files/inp/surface_cards/z.py @@ -6,7 +6,9 @@ from ..surface import Surface from ..surface_mnemonic import SurfaceMnemonic -from ...utils import types, errors, _parser +from ...utils import types +from ...utils import errors +from ...utils import _parser class Z(Surface): @@ -40,7 +42,6 @@ def __init__( """ Initializes ``Z``. - Parameters: z1: Z-axisymmetric point-defined surface point #1 z component. r1: Z-axisymmetric point-defined surface point #1 radius. @@ -79,17 +80,11 @@ def __init__( if r1 is None: raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r1)) - if z2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(z2)) - - if r2 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r2)) - - if z3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(z3)) + if z3 is None != r3 is None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(z3) + str(r3)) - if r3 is None: - raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(r3)) + if z2 is None != r2 is None and z3 is not None: + raise errors.McnpError(errors.McnpCode.INVALID_SURFACE_PARAMETER, str(z2) + str(r2)) self.ident: Final[int] = number.value self.number: Final[types.McnpInteger] = number diff --git a/src/pymcnp/files/utils/_visualization.py b/src/pymcnp/files/utils/_visualization.py new file mode 100644 index 0000000..fc9ad04 --- /dev/null +++ b/src/pymcnp/files/utils/_visualization.py @@ -0,0 +1,591 @@ +""" +Contains classes and functions for generating CADQUERY. +""" + +from __future__ import annotations +from typing import Final +import math + +import numpy +import pyvista + + +_BOUND: Final[float] = 500 +_RESOLUTION: Final[int] = 100 +_UNBOUNDED_SIZE: Final[float] = 1000 + + +class Vector: + """ + ``Vector`` represents vector for PyMCNP visualization. + + Attributes: + x: Vector x component. + y: Vector y component. + z: Vector z component. + """ + + def __init__(self, x: float, y: float, z: float): + """ + Initializes ``Vector``. + """ + + self.x: Final[float] = x + self.y: Final[float] = y + self.z: Final[float] = z + + def norm(self) -> float: + """ + Computes vector norms. + + Returns: + Length of the ``Vector`` vector. + """ + + return numpy.linalg.norm([self.x, self.y, self.z]) + + def apothem(self) -> float: + """ + Computes vector apothems. + + Returns: + Length of the apothem associated with the ``Vector`` vector. + """ + + return numpy.linalg.norm([self.x, self.y, self.z]) * 2 / math.sqrt(3) + + def __eq__(a: Vector, b: Vector) -> bool: + """ + Checks for vector equality. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + True/False if vectors are/aren't equal. + """ + + return a.x == b.x and a.y == b.y and a.z == b.z + + def __add__(a: Vector, b: Vector) -> Vector: + """ + Computes sum of vectors. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + Vector sum. + """ + + return Vector(a.x + b.x, a.y + b.y, a.z + b.z) + + def __sub__(a: Vector, b: Vector) -> Vector: + """ + Computes difference of vectors. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + Vector difference. + """ + + return Vector(a.x - b.x, a.y - b.y, a.z - b.z) + + def __mul__(a: Vector, b: Vector) -> Vector: + """ + Computes cross products of vectors. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + Cross product of vectors. + """ + + return Vector(*numpy.cross([a.x, a.y, a.z], [b.x, b.y, b.z])) + + def __matmul__(a: Vector, b: Vector) -> float: + """ + Computes dot products of vectors. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + Dot product of vectors. + """ + + return numpy.dot([a.x, a.y, a.z], [b.x, b.y, b.z]) + + def __and__(a: Vector, b: Vector) -> float: + """ + Computes angles between vectors. + + Parameters: + a: Operand ``Vector`` vector #1. + b: Operand ``Vector`` vector #2. + + Returns: + Angle between vectors in degrees. + """ + + if a * b == Vector(0, 0, 0): + return 0 + else: + return numpy.degrees(numpy.arccos(a @ b)) + + +class PyMcnpVisualization: + """ + Represents PyMCNP visualizations of cells, surfaces, etc. + + ``Visualization`` specifies common methods and attributes for PyMCNP + visualizations + """ + + def __init__(self, data: pyvista.PolyData = pyvista.PolyData()): + """ + Initializes ``PyMcnpVisualization``. + """ + + self.data: Final[pyvista.PolyData] = data + + @staticmethod + def get_plane(a: float, b: float, c: float, d: float) -> PyMcnpVisualization: + """ + Creates PyVISTA planes. + + Paremeters: + a: Plane equation parameter #1. + b: Plane equation parameter #2. + c: Plane equation parameter #3. + d: Plane equation parameter #4. + + Returns: + ``PyMcnpVisualization`` plane. + """ + + if c == 0 and b == 0 and a == 0: + point = (0, 0, d) + elif c == 0 and b == 0: + point = (d / a, 0, 0) + elif c == 0 and a == 0: + point = (0, d / b, 0) + elif a == 0 and b == 0: + point = (0, 0, d / c) + elif a == 0: + point = (0, 0, d / c) + elif b == 0: + point = (0, 0, d / c) + elif c == 0: + point = (0, d / b, 0) + else: + point = (0, 0, d) + + return PyMcnpVisualization( + pyvista.Plane( + center=point, + direction=(a, b, c), + i_size=_UNBOUNDED_SIZE, + j_size=_UNBOUNDED_SIZE, + ) + ) + + @staticmethod + def get_box(a: float, b: float, c: float) -> PyMcnpVisualization: + """ + Creates PyVISTA boxes. + + Paremeters: + a: Box side length #1. + b: Box side length #2. + c: Box side length #3. + + Returns: + ``PyMcnpVisualization`` box. + """ + + return PyMcnpVisualization( + pyvista.Box( + bounds=(0, a, 0, b, 0, c), + ) + ) + + @staticmethod + def get_parallelipiped( + xmin: float, xmax: float, ymin: float, ymax: float, zmin: float, zmax: float + ) -> PyMcnpVisualization: + """ + Creates PyVISTA parallelipipeds. + + Paremeters: + xmin: Parllelipied lower x bound. + xmax: Parllelipied upper x bound. + ymin: Parllelipied lower y bound. + ymax: Parllelipied upper y bound. + zmin: Parllelipied lower z bound. + zmax: Parllelipied upper z bound. + + Returns: + ``PyMcnpVisualization`` parallelipiped. + """ + + return PyMcnpVisualization( + pyvista.Box( + bounds=(xmin, xmax, ymin, ymax, zmin, zmax), + ) + ) + + @staticmethod + def get_sphere(r: float) -> PyMcnpVisualization: + """ + Creates PyVISTA spheres. + + Paremeters: + r: Sphere radius. + + Returns: + ``PyMcnpVisualization`` sphere. + """ + + return PyMcnpVisualization( + pyvista.Sphere( + radius=r, + center=(0.0, 0.0, 0.0), + ) + ) + + @staticmethod + def get_cylinder_unbounded(r: float) -> PyMcnpVisualization: + """ + Creates PyVISTA unbounded circular cylinders. + + Paremeters: + r: Circular cylinder radius. + + Returns: + ``PyMcnpVisualization`` circular cylinder. + """ + + return PyMcnpVisualization( + pyvista.Cylinder( + radius=r, + height=_UNBOUNDED_SIZE, + direction=(0.0, 0.0, 1.0), + capping=False, + ) + ) + + @staticmethod + def get_cylinder_circle(h: float, r: float) -> PyMcnpVisualization: + """ + Creates PyVISTA circular cylinders. + + Paremeters: + r: Circular cylinder radius. + h: Circular cylinder height. + + Returns: + ``PyMcnpVisualization`` circular cylinder. + """ + + return PyMcnpVisualization( + pyvista.Cylinder( + radius=r, + height=h, + direction=(0.0, 0.0, 1.0), + ) + ) + + @staticmethod + def get_cylinder_ellipse(h: float, a: float, b: float) -> PyMcnpVisualization: + """ + Creates PyVISTA elliptical cylinders. + + Paremeters: + a: Elliptical cylinder major axis length. + b: Elliptical cylinder minor axis length. + h: Elliptical cylinder height. + + Returns: + ``PyMcnpVisualization`` elliptical cylinder. + """ + + return PyMcnpVisualization( + pyvista.ParametricSuperEllipsoid( + xradius=a, + yradius=b, + zradius=h, + n1=0.001, + ) + ) + + @staticmethod + def get_cylinder_hexagon(h: float, a: float, b: float, c: float) -> PyMcnpVisualization: + """ + Creates PyVISTA hexagonal prism. + + Paremeters: + a: Hexagon apothem length #1. + b: Hexagon apothem length #2. + c: Hexagon apothem length #3. + h: Hexagon height. + + Returns: + ``PyMcnpVisualization`` hexagonal prism. + """ + + points = [ + [a * math.cos((math.pi / 3) * 0), a * math.sin((math.pi / 3) * 0), 0.0], + [a * math.cos((math.pi / 3) * 1), a * math.sin((math.pi / 3) * 1), 0.0], + [b * math.cos((math.pi / 3) * 2), b * math.sin((math.pi / 3) * 2), 0.0], + [b * math.cos((math.pi / 3) * 3), b * math.sin((math.pi / 3) * 3), 0.0], + [c * math.cos((math.pi / 3) * 4), c * math.sin((math.pi / 3) * 4), 0.0], + [c * math.cos((math.pi / 3) * 5), c * math.sin((math.pi / 3) * 5), 0.0], + [a * math.cos((math.pi / 3) * 0), a * math.sin((math.pi / 3) * 0), h], + [a * math.cos((math.pi / 3) * 1), a * math.sin((math.pi / 3) * 1), h], + [b * math.cos((math.pi / 3) * 2), b * math.sin((math.pi / 3) * 2), h], + [b * math.cos((math.pi / 3) * 3), b * math.sin((math.pi / 3) * 3), h], + [c * math.cos((math.pi / 3) * 4), c * math.sin((math.pi / 3) * 4), h], + [c * math.cos((math.pi / 3) * 5), c * math.sin((math.pi / 3) * 5), h], + ] + + cells = [len(points), *list(range(len(points)))] + + return PyMcnpVisualization( + pyvista.UnstructuredGrid( + cells, + [pyvista.CellType.HEXAGONAL_PRISM], + points, + ) + ) + + @staticmethod + def get_cone(r: float, h: float) -> PyMcnpVisualization: + """ + Creates PyVISTA cones. + + Parameters: + r: Cone radius. + + Returns: + ``PyMcnpVisualization`` cone. + """ + + return PyMcnpVisualization( + pyvista.Cone( + direction=(0.0, 0.0, 1), + radius=r, + height=h, + resolution=_RESOLUTION, + ) + ) + + @staticmethod + def get_cone_unbounded(m: float, sign: int) -> PyMcnpVisualization: + """ + Creates PyVISTA unbounded cones. + + Parameters: + m: Cone slope. + sign: Cone sheet. + + Returns: + ``PyMcnpVisualization`` cone. + """ + + points = [(0, 0, 0), (_UNBOUNDED_SIZE, 0, _UNBOUNDED_SIZE * sign / m)] + cells = [len(points), *list(range(len(points)))] + line = pyvista.UnstructuredGrid( + cells, + [pyvista.CellType.LINE], + points, + ) + + return PyMcnpVisualization( + line.extract_surface().extrude_rotate(resolution=_RESOLUTION, capping=False) + ) + + @staticmethod + def get_cone_truncated(h: float, r1: float, r2: float) -> PyMcnpVisualization: + """ + Creates PyVISTA truncated cones. + + Parameters: + h: Truncated cone height. + r1: Truncated cone radius #1. + r2: Truncated cone radius #2. + + Returns: + ``PyMcnpVisualization`` truncated cone. + """ + + points = [[0, 0, 0], [r1, 0, 0], [r2, 0, h], [0, 0, h]] + cells = [len(points), *list(range(len(points)))] + trapazoid = pyvista.UnstructuredGrid(cells, [pyvista.CellType.QUAD], points) + + return PyMcnpVisualization( + trapazoid.extract_surface().extrude_rotate(capping=True, resolution=_RESOLUTION) + ) + + @staticmethod + def get_ellipsoid(a: float, b: float) -> PyMcnpVisualization: + """ + Creates PyVISTA ellipsoids. + + Paremeters: + a: Ellipsoid major axis length. + b: Ellipsoid minor axis length. + + Returns: + ``PyMcnpVisualization`` ellipsoid. + """ + + return PyMcnpVisualization( + pyvista.ParametricEllipsoid( + xradius=a, + yradius=b, + zradius=b, + ) + ) + + @staticmethod + def get_wedge(a: float, b: float, h: float) -> PyMcnpVisualization: + """ + Creates PyVISTA wedge. + + Parameters: + a: Wedge triangle base small side #1. + b: Wedge triangle base small side #2. + h: Wedge height. + + Returns: + ``PyMcnpVisualization`` wedge. + """ + + points = [ + [0, 0, 0], + [a, 0, 0], + [0, b, 0], + [0, 0, h], + [a, 0, h], + [0, b, h], + ] + cells = [len(points), *list(range(len(points)))] + + return PyMcnpVisualization( + pyvista.UnstructuredGrid( + cells, + [pyvista.CellType.WEDGE], + points, + ) + ) + + @staticmethod + def get_polyhedron(vertices: tuple[Vector], faces: tuple[tuple[int]]) -> PyMcnpVisualization: + """ + Creates PyVISTA polyhedron. + + Parameters: + verticies: List of vertex vectors. + faces: List of four vertex indicies. + + Returns: + ``PyMcnpVisualization`` polyhedron. + """ + + vertices = numpy.array([[vertex.x, vertex.y, vertex.z] for vertex in vertices]) + faces = numpy.hstack( + [[len(face), *[int((side - 1) % len(faces)) for side in face]] for face in faces] + ) + + @staticmethod + def get_torus(a: float, b: float, r: float) -> PyMcnpVisualization: + """ + Creates PyVISTA tori. + + Parameters: + a: Torus tube semi-major axis length. + b: Torus tube semi-minor axis length. + r: Torus ring radius. + """ + + alpha = 2 * math.pi / _RESOLUTION + points = [ + [a * math.cos(alpha * i) + r, 0, b * math.sin(alpha * i)] for i in range(_RESOLUTION) + ] + cells = [len(points), *list(range(len(points)))] + ellipse = pyvista.UnstructuredGrid(cells, [pyvista.CellType.POLYGON], points) + + return ellipse.extract_surface().extrude_rotate( + capping=False, + resolution=_RESOLUTION, + ) + + def add_translation(self, vector: Vector): + """ + Translates ``PyMcnpVisualization`` instances. + + Parameters: + vector: Translation vector. + + Returns: + Translated ``PyMcnpVisualization``. + """ + + return PyMcnpVisualization(self.data.translate(xyz=(vector.x, vector.y, vector.z))) + + def add_rotation(self, axis: Vector, angle: float, center: tuple[float]): + """ + Translates ``PyMcnpVisualization`` instances. + + Parameters: + center: Center of rotation. + + Returns: + Rotated ``PyMcnpVisualization``. + """ + + if axis.x == 0 and axis.y == 0 and axis.z == 0: + return self + else: + return PyMcnpVisualization( + self.data.rotate_vector( + vector=(axis.x, axis.y, axis.z), + angle=angle, + point=center, + ) + ) + + def add_bounds(self) -> PyMcnpVisualization: + """ + Bounds ``PyMcnpVisualuzation`` inside the bounding cube. + + Returns: + Rotated ``PyMcnpVisualization``. + """ + + bound = pyvista.Cube(center=(0, 0, 0), x_length=_BOUND, y_length=_BOUND, z_length=_BOUND) + + return PyMcnpVisualization(self.data.clip_box(bound, invert=False)) + + def __add__(a: PyMcnpVisualization, b: PyMcnpVisualization): + """ + Adds ``PyMcnpVisualization`` instances. + + Parameters: + a: Addend #1. + b: Addend #2. + + Returns: + Merged ``PyMcnpVisualization``. + """ + + return PyMcnpVisualization(pyvista.merge([a.data, b.data], merge_points=False))