diff --git a/.gitignore b/.gitignore
index ff7a0b785..0ab77b6b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,11 +35,14 @@ coverage.xml
# neutronics simulation files
*.h5
*.out
+*.vtk
# 2D and 3D images of the model
*.svg
*.png
*.vtk
+*.jpg
+*.xcf
# sphinx built documetation
docs/build/
diff --git a/Dockerfile b/Dockerfile
index aaf097706..a3fdfcc51 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -105,7 +105,7 @@ RUN if [ "$include_neutronics" = "true" ] ; \
mkdir build ; \
cd build ; \
cmake .. -DCMAKE_INSTALL_PREFIX=.. \
- -DEMBREE_ISPC_SUPPORT=OFF ; \
+ -DEMBREE_ISPC_SUPPORT=OFF ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
fi
@@ -119,19 +119,20 @@ RUN if [ "$include_neutronics" = "true" ] ; \
git clone --single-branch --branch develop https://bitbucket.org/fathomteam/moab/ ; \
cd build ; \
cmake ../moab -DENABLE_HDF5=ON \
- -DENABLE_NETCDF=ON \
- -DBUILD_SHARED_LIBS=OFF \
- -DENABLE_FORTRAN=OFF \
- -DCMAKE_INSTALL_PREFIX=/MOAB ; \
+ -DENABLE_NETCDF=ON \
+ -DENABLE_FORTRAN=OFF \
+ -DENABLE_BLASLAPACK=OFF \
+ -DBUILD_SHARED_LIBS=OFF \
+ -DCMAKE_INSTALL_PREFIX=/MOAB ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
rm -rf * ; \
- cmake ../moab -DBUILD_SHARED_LIBS=ON \
- -DENABLE_HDF5=ON \
- -DENABLE_PYMOAB=ON \
- -DENABLE_BLASLAPACK=OFF \
- -DENABLE_FORTRAN=OFF \
- -DCMAKE_INSTALL_PREFIX=/MOAB ; \
+ cmake ../moab -DENABLE_HDF5=ON \
+ -DENABLE_PYMOAB=ON \
+ -DENABLE_FORTRAN=OFF \
+ -DBUILD_SHARED_LIBS=ON \
+ -DENABLE_BLASLAPACK=OFF \
+ -DCMAKE_INSTALL_PREFIX=/MOAB ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
cd pymoab ; \
@@ -146,10 +147,9 @@ RUN if [ "$include_neutronics" = "true" ] ; \
cd double-down ; \
mkdir build ; \
cd build ; \
- cmake .. -DCMAKE_INSTALL_PREFIX=.. \
- -DMOAB_DIR=/MOAB \
- -DEMBREE_DIR=/embree/lib/cmake/embree-3.12.1 \
- -DEMBREE_ROOT=/embree/lib/cmake/embree-3.12.1 ; \
+ cmake .. -DMOAB_DIR=/MOAB \
+ -DCMAKE_INSTALL_PREFIX=.. \
+ -DEMBREE_DIR=/embree/lib/cmake/embree-3.12.1 ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
fi
@@ -162,10 +162,10 @@ RUN if [ "$include_neutronics" = "true" ] ; \
mkdir build ; \
cd build ; \
cmake ../dagmc -DBUILD_TALLY=ON \
- -DCMAKE_INSTALL_PREFIX=/dagmc/ \
- -DMOAB_DIR=/MOAB \
- -DBUILD_STATIC_LIBS=OFF \
- -DBUILD_STATIC_EXE=OFF ; \
+ -DMOAB_DIR=/MOAB \
+ -DBUILD_STATIC_EXE=OFF \
+ -DBUILD_STATIC_LIBS=OFF \
+ -DCMAKE_INSTALL_PREFIX=/dagmc/ ; \
make -j"$compile_cores" install ; \
rm -rf /DAGMC/dagmc /DAGMC/build ; \
fi
@@ -176,9 +176,10 @@ RUN if [ "$include_neutronics" = "true" ] ; \
cd /opt/openmc ; \
mkdir build ; \
cd build ; \
- cmake -Doptimize=on -Ddagmc=ON \
- -DDAGMC_DIR=/DAGMC/ \
- -DHDF5_PREFER_PARALLEL=on .. ; \
+ cmake -Doptimize=on \
+ -Ddagmc=ON \
+ -DDAGMC_DIR=/DAGMC/ \
+ -DHDF5_PREFER_PARALLEL=on .. ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
cd .. ; \
@@ -191,9 +192,9 @@ ENV OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml
# Copies over the Paramak code from the local repository
RUN if [ "$include_neutronics" = "true" ] ; \
- then pip install neutronics_material_maker ; \
+ then pip install vtk ; \
pip install parametric_plasma_source ; \
- pip install vtk ; \
+ pip install neutronics_material_maker ; \
fi
COPY requirements.txt requirements.txt
diff --git a/DockerfileDependencies b/DockerfileDependencies
index 86dad2c80..64e1f133d 100644
--- a/DockerfileDependencies
+++ b/DockerfileDependencies
@@ -106,7 +106,7 @@ RUN if [ "$include_neutronics" = "true" ] ; \
mkdir build ; \
cd build ; \
cmake .. -DCMAKE_INSTALL_PREFIX=.. \
- -DEMBREE_ISPC_SUPPORT=OFF ; \
+ -DEMBREE_ISPC_SUPPORT=OFF ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
fi
@@ -120,24 +120,20 @@ RUN if [ "$include_neutronics" = "true" ] ; \
git clone --single-branch --branch develop https://bitbucket.org/fathomteam/moab/ ; \
cd build ; \
cmake ../moab -DENABLE_HDF5=ON \
- -DENABLE_NETCDF=ON \
- -DBUILD_SHARED_LIBS=OFF \
- -DENABLE_FORTRAN=OFF \
- -DCMAKE_INSTALL_PREFIX=/MOAB ; \
+ -DENABLE_NETCDF=ON \
+ -DBUILD_SHARED_LIBS=OFF \
+ -DENABLE_FORTRAN=OFF \
+ -DENABLE_BLASLAPACK=OFF ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
rm -rf * ; \
cmake ../moab -DBUILD_SHARED_LIBS=ON \
- -DENABLE_HDF5=ON \
- -DENABLE_PYMOAB=ON \
- -DENABLE_BLASLAPACK=OFF \
- -DENABLE_FORTRAN=OFF \
- -DCMAKE_INSTALL_PREFIX=/MOAB ; \
+ -DENABLE_HDF5=ON \
+ -DENABLE_PYMOAB=ON \
+ -DENABLE_FORTRAN=OFF \
+ -DENABLE_BLASLAPACK=OFF ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
- cd pymoab ; \
- bash install.sh ; \
- python setup.py install ; \
fi
@@ -148,9 +144,8 @@ RUN if [ "$include_neutronics" = "true" ] ; \
mkdir build ; \
cd build ; \
cmake .. -DCMAKE_INSTALL_PREFIX=.. \
- -DMOAB_DIR=/MOAB \
- -DEMBREE_DIR=/embree/lib/cmake/embree-3.12.1 \
- -DEMBREE_ROOT=/embree/lib/cmake/embree-3.12.1 ; \
+ -DMOAB_DIR=/usr/local \
+ -DEMBREE_DIR=/embree/lib/cmake/embree-3.12.1 ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
fi
@@ -163,10 +158,10 @@ RUN if [ "$include_neutronics" = "true" ] ; \
mkdir build ; \
cd build ; \
cmake ../dagmc -DBUILD_TALLY=ON \
- -DCMAKE_INSTALL_PREFIX=/dagmc/ \
- -DMOAB_DIR=/MOAB \
- -DBUILD_STATIC_LIBS=OFF \
- -DBUILD_STATIC_EXE=OFF ; \
+ -DCMAKE_INSTALL_PREFIX=/dagmc/ \
+ -DMOAB_DIR=/usr/local \
+ -DBUILD_STATIC_LIBS=OFF \
+ -DBUILD_STATIC_EXE=OFF ; \
make -j"$compile_cores" install ; \
rm -rf /DAGMC/dagmc /DAGMC/build ; \
fi
@@ -177,9 +172,10 @@ RUN if [ "$include_neutronics" = "true" ] ; \
cd /opt/openmc ; \
mkdir build ; \
cd build ; \
- cmake -Doptimize=on -Ddagmc=ON \
- -DDAGMC_DIR=/DAGMC/ \
- -DHDF5_PREFER_PARALLEL=on .. ; \
+ cmake -Doptimize=on \
+ -Ddagmc=ON \
+ -DDAGMC_DIR=/DAGMC/ \
+ -DHDF5_PREFER_PARALLEL=on .. ; \
make -j"$compile_cores" ; \
make -j"$compile_cores" install ; \
cd .. ; \
@@ -189,12 +185,10 @@ RUN if [ "$include_neutronics" = "true" ] ; \
ENV OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml
-# Copies over the Paramak code from the local repository
-
RUN if [ "$include_neutronics" = "true" ] ; \
- then pip install neutronics_material_maker ; \
+ then pip install vtk ; \
pip install parametric_plasma_source ; \
- pip install vtk ; \
+ pip install neutronics_material_maker ; \
fi
COPY requirements.txt requirements.txt
diff --git a/README.md b/README.md
index 074ff155c..f32b514df 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[![N|Python](https://www.python.org/static/community_logos/python-powered-w-100x40.png)](https://www.python.org)
[![CircleCI](https://circleci.com/gh/ukaea/paramak/tree/main.svg?style=svg)](https://circleci.com/gh/ukaea/paramak/tree/main)
[![codecov](https://codecov.io/gh/ukaea/paramak/branch/main/graph/badge.svg)](https://codecov.io/gh/ukaea/paramak)
-[![PyPI version](https://badge.fury.io/py/paramak.svg)](https://badge.fury.io/py/paramak)
+[![PyPI](https://img.shields.io/pypi/v/paramak?color=green&label=green&logo=green&logoColor=green)](https://pypi.org/project/paramak/)
[![Documentation Status](https://readthedocs.org/projects/paramak/badge/?version=main)](https://paramak.readthedocs.io/en/main/?badge=main)
[![dockerhub-publish-stable](https://github.com/ukaea/paramak/workflows/dockerhub-publish-stable/badge.svg)](https://github.com/ukaea/paramak/actions?query=workflow%3Adockerhub-publish-stable)
[![DOI](https://zenodo.org/badge/269635577.svg)](https://zenodo.org/badge/latestdoi/269635577)
@@ -89,7 +89,7 @@ flag when running Docker so that you can retrieve files from the Docker
enviroment to your base system.
Docker can also be used to run the tests using the command
-```docker run -rm ukaea/parama pytest tests```
+```docker run --rm ukaea/paramak pytest tests```
## Features
diff --git a/build.sh b/build.sh
index fec5047cc..60a2367c1 100644
--- a/build.sh
+++ b/build.sh
@@ -1 +1 @@
-$PYTHON setup.py install # Python command to install the script.
\ No newline at end of file
+python setup.py install # Python command to install the script.
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 08aa72300..3e6ab93ff 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -43,7 +43,8 @@
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.coverage",
- "sphinx.ext.napoleon"]
+ "sphinx.ext.napoleon",
+ "sphinx_autodoc_typehints"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 86ecc61ca..2308c700e 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -15,9 +15,8 @@ straightforward for developers with Python knowledge.
.. raw:: html
-
-
+
.. toctree::
:maxdepth: 1
diff --git a/docs/source/paramak.parametric_neutronics.rst b/docs/source/paramak.parametric_neutronics.rst
index df14b53cf..294f406c9 100644
--- a/docs/source/paramak.parametric_neutronics.rst
+++ b/docs/source/paramak.parametric_neutronics.rst
@@ -14,14 +14,24 @@ the material tag names. mbsize -ll dagmc.h5m | grep 'mat:'
The creation of the dagmc.h5m file can be carried out via three routes.
-Option 1. Use of the `OCC_Faceter `_
-and the `PPP `_
+Option 1. Use of `PyMoab `_ which is
+distributed with MOAB. Thus method can not imprint or merge the surfaces of the
+geometry that touch. Therefore this method should only be used for single
+components or components that touch on flat surfaces. Curved surfaces converted
+via this method can potentially overlap and cause errors with the particle
+tracking.
Option 2. Use of `Trelis `_ by
-Coreform
+Coreform along with the DAGMC
+`plugin `_ / This method
+can support imprinting and merging of shared surfaces between components and is
+therefore suitable for converting more complex CAD geometry to the PyMoab
+method.
-Option 3. Use of `PyMoab `_ by
-Coreform
+Option 3. Use of the `PPP `_
+and `OCC_Faceter `_ . This option
+has not yet been fully demonstrated but is partly included to test the
+promising new method.
To create a model it is also necessary to define the source and the materials
used.
@@ -34,7 +44,7 @@ Details of the Neutronics Material Maker are available from the
and the `source code repository `_
. However openmc.Materials can also be used directly.
-The [UKAEA openmc workshop](https://github.com/ukaea/openmc_workshop) also has
+The `OpenMC workshop `_ also has
some Paramak with DAGMC and OpenMC based tasks that might be of interest.
NeutronicsModel()
diff --git a/examples/example_neutronics_simulations/component_based_mesh_simulation.py b/examples/example_neutronics_simulations/component_based_mesh_simulation.py
new file mode 100644
index 000000000..0f375e615
--- /dev/null
+++ b/examples/example_neutronics_simulations/component_based_mesh_simulation.py
@@ -0,0 +1,69 @@
+"""This example creates a curved center column with a few different sizes.
+The shape is then converted into a neutronics geometry and the heat deposited
+is simulated for a few different sizes of ceter column"""
+
+import matplotlib.pyplot as plt
+import openmc
+import paramak
+
+
+def make_model_and_simulate():
+ simulation_values = []
+ for mid_radius in [60, 70, 80]:
+
+ # makes the component with a few different size mid radius values
+ my_shape = paramak.CenterColumnShieldHyperbola(
+ height=500,
+ inner_radius=50,
+ mid_radius=mid_radius,
+ outer_radius=100,
+ material_tag='center_column_shield_mat'
+ )
+
+ my_shape.export_stp('my_shape' + str(mid_radius) + '.stp')
+
+ # makes the openmc neutron source at x,y,z 0, 0, 0 with isotropic
+ # diections
+ source = openmc.Source()
+ source.space = openmc.stats.Point((0, 0, 0))
+ source.angle = openmc.stats.Isotropic()
+
+ # converts the geometry into a neutronics geometry
+ my_model = paramak.NeutronicsModel(
+ geometry=my_shape,
+ source=source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ cell_tallies=['heating', 'TBR'],
+ mesh_tally_2D=['heating'],
+ mesh_tally_3D=['heating'],
+ simulation_batches=10, # should be increased for more accurate result
+ simulation_particles_per_batch=10 # settings are low to reduce time required
+ )
+
+ # performs an openmc simulation on the model
+ my_model.simulate(method='pymoab')
+
+ # extracts the heat from the results dictionary
+ heat = my_model.results['center_column_shield_mat_heating']['Watts']['result']
+
+ # adds the heat and the mid radius value to a list
+ simulation_values.append((mid_radius, heat))
+
+ # plots the simualtion results vs the mid_radius used for the simulation
+ plt.plot(
+ [i[0] for i in simulation_values],
+ [i[1] for i in simulation_values],
+ '-p'
+ )
+
+ # adds labels to the graph
+ plt.title("heating vs thickness")
+ plt.xlabel("thickness (cm)")
+ plt.ylabel("heating (watts)")
+
+ plt.savefig('heating_vs_thickness.svg')
+ plt.show()
+
+
+if __name__ == "__main__":
+ make_model_and_simulate()
diff --git a/examples/example_neutronics_simulations/shape_with_spectra_cell_tally.py b/examples/example_neutronics_simulations/shape_with_spectra_cell_tally.py
new file mode 100644
index 000000000..a959cfe0a
--- /dev/null
+++ b/examples/example_neutronics_simulations/shape_with_spectra_cell_tally.py
@@ -0,0 +1,107 @@
+
+import openmc
+import paramak
+import plotly.graph_objects as go
+
+my_shape = paramak.CenterColumnShieldHyperbola(
+ height=500,
+ inner_radius=50,
+ mid_radius=60,
+ outer_radius=100,
+ material_tag='center_column_shield_mat'
+)
+
+# makes the openmc neutron source at x,y,z 0, 0, 0 with isotropic directions
+source = openmc.Source()
+source.space = openmc.stats.Point((0, 0, 0))
+source.energy = openmc.stats.Discrete([14e6], [1])
+source.angle = openmc.stats.Isotropic()
+
+
+# converts the geometry into a neutronics geometry
+my_model = paramak.NeutronicsModel(
+ geometry=my_shape,
+ source=source,
+ materials={'center_column_shield_mat': 'Be'},
+ cell_tallies=['heating', 'flux', 'TBR', 'spectra'],
+ simulation_batches=10,
+ simulation_particles_per_batch=200
+)
+
+# performs an openmc simulation on the model
+output_filename = my_model.simulate(method='pymoab')
+
+# this extracts the values from the results dictionary
+energy_bins = my_model.results['center_column_shield_mat_photon_spectra']['Flux per source particle']['energy']
+neutron_spectra = my_model.results['center_column_shield_mat_neutron_spectra']['Flux per source particle']['result']
+photon_spectra = my_model.results['center_column_shield_mat_photon_spectra']['Flux per source particle']['result']
+
+fig = go.Figure()
+
+# this sets the axis titles and range
+fig.update_layout(
+ xaxis={'title': 'Energy (eV)',
+ 'range': (0, 14.1e6)},
+ yaxis={'title': 'Neutrons per cm2 per source neutron'}
+)
+
+# this adds the neutron spectra line to the plot
+fig.add_trace(go.Scatter(
+ x=energy_bins[:-85], # trims off the high energy range
+ y=neutron_spectra[:-85], # trims off the high energy range
+ name='neutron spectra',
+ line=dict(shape='hv')
+)
+)
+
+# this adds the photon spectra line to the plot
+fig.add_trace(go.Scatter(
+ x=energy_bins[:-85], # trims off the high energy range
+ y=photon_spectra[:-85], # trims off the high energy range
+ name='photon spectra',
+ line=dict(shape='hv')
+)
+)
+
+# this adds the drop down menu fo log and linear scales
+fig.update_layout(
+ updatemenus=[
+ go.layout.Updatemenu(
+ buttons=list([
+ dict(
+ args=[{
+ "xaxis.type": 'lin', "yaxis.type": 'lin',
+ 'xaxis.range': (0, 14.1e6)
+ }],
+ label="linear(x) , linear(y)",
+ method="relayout"
+ ),
+ dict(
+ args=[{"xaxis.type": 'log', "yaxis.type": 'log'}],
+ label="log(x) , log(y)",
+ method="relayout"
+ ),
+ dict(
+ args=[{"xaxis.type": 'log', "yaxis.type": 'lin'}],
+ label="log(x) , linear(y)",
+ method="relayout"
+ ),
+ dict(
+ args=[{"xaxis.type": 'lin', "yaxis.type": 'log',
+ 'xaxis.range': (0, 14.1e6)
+ }],
+ label="linear(x) , log(y)",
+ method="relayout"
+ )
+ ]),
+ pad={"r": 10, "t": 10},
+ showactive=True,
+ x=0.5,
+ xanchor="left",
+ y=1.1,
+ yanchor="top"
+ ),
+ ]
+)
+
+fig.show()
diff --git a/examples/example_parametric_components/make_all_parametric_components_images_for_docs.py b/examples/example_parametric_components/make_all_parametric_components_images_for_docs.py
index 33f57e809..02d2fd66b 100644
--- a/examples/example_parametric_components/make_all_parametric_components_images_for_docs.py
+++ b/examples/example_parametric_components/make_all_parametric_components_images_for_docs.py
@@ -13,7 +13,6 @@ def export_images():
for componet in all_componets:
componet.workplane = "XY"
componet.export_svg(componet.stp_filename[:-3] + "svg")
- # os.system('conver')
if __name__ == "__main__":
diff --git a/examples/example_parametric_reactors/ball_reactor.py b/examples/example_parametric_reactors/ball_reactor.py
index 00354ae91..f10d0ac06 100644
--- a/examples/example_parametric_reactors/ball_reactor.py
+++ b/examples/example_parametric_reactors/ball_reactor.py
@@ -8,7 +8,7 @@
import paramak
-def make_ball_reactor(outputs=['stp', 'neutronics', 'svg', 'stl', 'html'],
+def make_ball_reactor(outputs=('stp', 'neutronics', 'svg', 'stl', 'html'),
output_folder='BallReactor'):
my_reactor = paramak.BallReactor(
@@ -48,4 +48,4 @@ def make_ball_reactor(outputs=['stp', 'neutronics', 'svg', 'stl', 'html'],
if __name__ == "__main__":
- make_ball_reactor(['stp', 'neutronics', 'svg', 'stl', 'html'])
+ make_ball_reactor(('stp', 'neutronics', 'svg', 'stl', 'html'))
diff --git a/examples/example_parametric_reactors/segmented_blanket_ball_reactor.py b/examples/example_parametric_reactors/segmented_blanket_ball_reactor.py
index 45741fe4f..146dcde77 100644
--- a/examples/example_parametric_reactors/segmented_blanket_ball_reactor.py
+++ b/examples/example_parametric_reactors/segmented_blanket_ball_reactor.py
@@ -38,10 +38,10 @@ def make_ball_reactor_seg(outputs=['stp', 'neutronics', 'svg', 'stl', 'html']):
)
# finds the correct edges to fillet
- x = my_reactor.major_radius
+ x_coord = my_reactor.major_radius
front_face = my_reactor._blanket.solid.faces(
- cq.NearestToPointSelector((x, 0, 0)))
- front_edge = front_face.edges(cq.NearestToPointSelector((x, 0, 0)))
+ cq.NearestToPointSelector((x_coord, 0, 0)))
+ front_edge = front_face.edges(cq.NearestToPointSelector((x_coord, 0, 0)))
front_edge_length = front_edge.val().Length()
my_reactor._blanket.solid = my_reactor._blanket.solid.edges(
paramak.EdgeLengthSelector(front_edge_length)).fillet(
diff --git a/paramak/__init__.py b/paramak/__init__.py
index 83aa62762..52c7e4490 100644
--- a/paramak/__init__.py
+++ b/paramak/__init__.py
@@ -3,6 +3,7 @@
from .utils import rotate, extend, distance_between_two_points, diff_between_angles
from .utils import EdgeLengthSelector, FaceAreaSelector
from .neutronics_utils import define_moab_core_and_tags, add_stl_to_moab_core
+from .neutronics_utils import get_neutronics_results_from_statepoint_file
from .parametric_shapes.extruded_mixed_shape import ExtrudeMixedShape
from .parametric_shapes.extruded_spline_shape import ExtrudeSplineShape
diff --git a/paramak/neutronics_utils.py b/paramak/neutronics_utils.py
index e003ec7cc..01cd12885 100644
--- a/paramak/neutronics_utils.py
+++ b/paramak/neutronics_utils.py
@@ -1,4 +1,8 @@
+import math
+from collections import defaultdict
+
+import matplotlib.pyplot as plt
import numpy as np
@@ -14,7 +18,7 @@ def define_moab_core_and_tags():
try:
from pymoab import core, types
except ImportError as err:
- raise err('PyMoab not found, export_h5m method not available')
+ raise err('PyMoab not found, export_h5m method is not available')
# create pymoab instance
moab_core = core.Core()
@@ -57,11 +61,11 @@ def define_moab_core_and_tags():
def add_stl_to_moab_core(
moab_core,
- surface_id,
- volume_id,
- material_name,
+ surface_id: int,
+ volume_id: int,
+ material_name: str,
tags,
- stl_filename):
+ stl_filename: str):
"""Computes the m and c coefficients of the equation (y=mx+c) for
a straight line from two points.
@@ -119,3 +123,236 @@ def add_stl_to_moab_core(
moab_core.add_entity(group_set, volume_set)
return moab_core
+
+
+def _save_2d_mesh_tally_as_png(score: str, filename: str, tally):
+ """Extracts 2D mesh tally results from a tally and saves the result as
+ a png image.
+
+ Arguments:
+ score (str): The tally score to filter the tally with, e.g. ‘flux’,
+ ‘heating’, etc.
+ filename (str): The filename to use when saving the png output file
+ tally (opencmc.tally()): The OpenMC to extract the mesh tally
+ resutls from.
+ """
+
+ try:
+ import openmc
+ except ImportError as err:
+ raise err(
+ 'openmc not found, _save_2d_mesh_tally_as_png method is not \
+ available')
+
+ my_slice = tally.get_slice(scores=[score])
+ tally_filter = tally.find_filter(filter_type=openmc.MeshFilter)
+ shape = tally_filter.mesh.dimension.tolist()
+ shape.remove(1)
+ my_slice.mean.shape = shape
+
+ fig = plt.subplot()
+ fig.imshow(my_slice.mean).get_figure().savefig(filename, dpi=300)
+ fig.clear()
+
+
+def get_neutronics_results_from_statepoint_file(
+ statepoint_filename: str,
+ fusion_power: float = None):
+ """Reads the statepoint file from the neutronics simulation
+ and extracts the tally results.
+
+ Arguments:
+ statepoint_filename (str): The name of the statepoint file
+ fusion_power (float): The fusion power of the reactor, which is used to
+ scale some tallies. Defaults to None
+
+ Returns:
+ dict: a dictionary of the simulation results
+ """
+
+ try:
+ import openmc
+ except ImportError as err:
+ raise err(
+ 'openmc not found, get_neutronics_results_from_statepoint_file \
+ method is not available')
+
+ # open the results file
+ statepoint = openmc.StatePoint(statepoint_filename)
+
+ results = defaultdict(dict)
+
+ # access the tallies
+ for tally in statepoint.tallies.values():
+
+ if tally.name.endswith('TBR'):
+
+ data_frame = tally.get_pandas_dataframe()
+ tally_result = data_frame["mean"].sum()
+ tally_std_dev = data_frame['std. dev.'].sum()
+ results[tally.name] = {
+ 'result': tally_result,
+ 'std. dev.': tally_std_dev,
+ }
+
+ if tally.name.endswith('heating'):
+
+ data_frame = tally.get_pandas_dataframe()
+ tally_result = data_frame["mean"].sum()
+ tally_std_dev = data_frame['std. dev.'].sum()
+ results[tally.name]['MeV per source particle'] = {
+ 'result': tally_result / 1e6,
+ 'std. dev.': tally_std_dev / 1e6,
+ }
+
+ if fusion_power is not None:
+ results[tally.name]['Watts'] = {
+ 'result': tally_result * 1.602176487e-19 * (fusion_power / ((17.58 * 1e6) / 6.2415090744e18)),
+ 'std. dev.': tally_std_dev * 1.602176487e-19 * (fusion_power / ((17.58 * 1e6) / 6.2415090744e18)),
+ }
+
+ if tally.name.endswith('flux'):
+
+ data_frame = tally.get_pandas_dataframe()
+ tally_result = data_frame["mean"].sum()
+ tally_std_dev = data_frame['std. dev.'].sum()
+ results[tally.name]['Flux per source particle'] = {
+ 'result': tally_result,
+ 'std. dev.': tally_std_dev,
+ }
+
+ if tally.name.endswith('spectra'):
+ data_frame = tally.get_pandas_dataframe()
+ tally_result = data_frame["mean"]
+ tally_std_dev = data_frame['std. dev.']
+ results[tally.name]['Flux per source particle'] = {
+ 'energy': openmc.mgxs.GROUP_STRUCTURES['CCFE-709'].tolist(),
+ 'result': tally_result.tolist(),
+ 'std. dev.': tally_std_dev.tolist(),
+ }
+
+ if tally.name.startswith('tritium_production_on_2D_mesh'):
+
+ _save_2d_mesh_tally_as_png(
+ score='(n,Xt)',
+ tally=tally,
+ filename='tritium_production_on_2D_mesh' + tally.name[-3:]
+ )
+
+ if tally.name.startswith('flux_on_2D_mesh'):
+
+ _save_2d_mesh_tally_as_png(
+ score='flux',
+ tally=tally,
+ filename='flux_on_2D_mesh' + tally.name[-3:]
+ )
+
+ if tally.name.startswith('heating_on_2D_mesh'):
+
+ _save_2d_mesh_tally_as_png(
+ score='heating',
+ tally=tally,
+ filename='heating_on_2D_mesh' + tally.name[-3:]
+ )
+
+ if '_on_3D_mesh' in tally.name:
+ mesh_id = 1
+ mesh = statepoint.meshes[mesh_id]
+
+ xs = np.linspace(
+ mesh.lower_left[0],
+ mesh.upper_right[0],
+ mesh.dimension[0] + 1
+ )
+ ys = np.linspace(
+ mesh.lower_left[1],
+ mesh.upper_right[1],
+ mesh.dimension[1] + 1
+ )
+ zs = np.linspace(
+ mesh.lower_left[2],
+ mesh.upper_right[2],
+ mesh.dimension[2] + 1
+ )
+ tally = statepoint.get_tally(name=tally.name)
+
+ data = tally.mean[:, 0, 0]
+ error = tally.std_dev[:, 0, 0]
+
+ data = data.tolist()
+ error = error.tolist()
+
+ for content in [data, error]:
+ for counter, i in enumerate(content):
+ if math.isnan(i):
+ content[counter] = 0.
+
+ write_3d_mesh_tally_to_vtk(
+ xs=xs,
+ ys=ys,
+ zs=zs,
+ tally_label=tally.name,
+ tally_data=data,
+ error_data=error,
+ outfile=tally.name + '.vtk'
+ )
+
+ return results
+
+
+def write_3d_mesh_tally_to_vtk(
+ xs,
+ ys,
+ zs,
+ tally_label: str,
+ tally_data,
+ error_data,
+ outfile):
+ try:
+ import vtk
+ except (ImportError, ModuleNotFoundError):
+ msg = "Conversion to VTK requested," \
+ "but the Python VTK module is not installed."
+ raise ImportError(msg)
+
+ vtk_box = vtk.vtkRectilinearGrid()
+
+ vtk_box.SetDimensions(len(xs), len(ys), len(zs))
+
+ vtk_x_array = vtk.vtkDoubleArray()
+ vtk_x_array.SetName('x-coords')
+ vtk_x_array.SetArray(xs, len(xs), True)
+ vtk_box.SetXCoordinates(vtk_x_array)
+
+ vtk_y_array = vtk.vtkDoubleArray()
+ vtk_y_array.SetName('y-coords')
+ vtk_y_array.SetArray(ys, len(ys), True)
+ vtk_box.SetYCoordinates(vtk_y_array)
+
+ vtk_z_array = vtk.vtkDoubleArray()
+ vtk_z_array.SetName('z-coords')
+ vtk_z_array.SetArray(zs, len(zs), True)
+ vtk_box.SetZCoordinates(vtk_z_array)
+
+ tally = np.array(tally_data)
+ tally_data = vtk.vtkDoubleArray()
+ tally_data.SetName(tally_label)
+ tally_data.SetArray(tally, tally.size, True)
+
+ error = np.array(error_data)
+ error_data = vtk.vtkDoubleArray()
+ error_data.SetName("error_tag")
+ error_data.SetArray(error, error.size, True)
+
+ vtk_box.GetCellData().AddArray(tally_data)
+ vtk_box.GetCellData().AddArray(error_data)
+
+ writer = vtk.vtkRectilinearGridWriter()
+
+ writer.SetFileName(outfile)
+
+ writer.SetInputData(vtk_box)
+
+ print('Writing %s' % outfile)
+
+ writer.Write()
diff --git a/paramak/parametric_components/blanket_constant_thickness_arc_h.py b/paramak/parametric_components/blanket_constant_thickness_arc_h.py
index 51a674160..c4b338644 100644
--- a/paramak/parametric_components/blanket_constant_thickness_arc_h.py
+++ b/paramak/parametric_components/blanket_constant_thickness_arc_h.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
from paramak import RotateMixedShape
@@ -8,31 +9,29 @@ class BlanketConstantThicknessArcH(RotateMixedShape):
horizontally for the thickness of the blanket to back of the blanket.
Arguments:
- inner_mid_point ((float, float)): the x,z coordinates of the mid
- point on the inner surface of the blanket.
- inner_upper_point ((float, float)): the x,z coordinates of the upper
- point on the inner surface of the blanket.
- inner_lower_point ((float, float)): the x,z coordinates of the lower
- point on the inner surface of the blanket.
- thickness (float): the radial thickness of the blanket in cm.
- stp_filename (str, optional): Defaults to
- "BlanketConstantThicknessArcH.stp".
- stl_filename (str, optional): Defaults to
- "BlanketConstantThicknessArcH.stl".
- material_tag (str, optional): Defaults to "blanket_mat".
+ inner_mid_point: the x,z coordinates of the mid point on the inner
+ surface of the blanket.
+ inner_upper_point: the x,z coordinates of the upper point on the
+ inner surface of the blanket.
+ inner_lower_point: the x,z coordinates of the lower point on the
+ inner surface of the blanket.
+ thickness: the radial thickness of the blanket in cm.
+ stp_filename: Defaults to "BlanketConstantThicknessArcH.stp".
+ stl_filename: Defaults to "BlanketConstantThicknessArcH.stl".
+ material_tag: Defaults to "blanket_mat".
"""
def __init__(
self,
- inner_mid_point,
- inner_upper_point,
- inner_lower_point,
- thickness,
- stp_filename="BlanketConstantThicknessArcH.stp",
- stl_filename="BlanketConstantThicknessArcH.stl",
- material_tag="blanket_mat",
+ inner_mid_point: Tuple[float, float],
+ inner_upper_point: Tuple[float, float],
+ inner_lower_point: Tuple[float, float],
+ thickness: float,
+ stp_filename: Optional[str] = "BlanketConstantThicknessArcH.stp",
+ stl_filename: Optional[str] = "BlanketConstantThicknessArcH.stl",
+ material_tag: Optional[str] = "blanket_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/blanket_constant_thickness_arc_v.py b/paramak/parametric_components/blanket_constant_thickness_arc_v.py
index c14e85cc5..fe0834f5a 100644
--- a/paramak/parametric_components/blanket_constant_thickness_arc_v.py
+++ b/paramak/parametric_components/blanket_constant_thickness_arc_v.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
from paramak import RotateMixedShape
@@ -8,31 +9,29 @@ class BlanketConstantThicknessArcV(RotateMixedShape):
vertically for the thickness of the blanket to back of the blanket.
Arguments:
- inner_mid_point ((float, float)): the x,z coordinates of the mid
- point on the inner surface of the blanket.
- inner_upper_point ((float, float)): the x,z coordinates of the upper
- point on the inner surface of the blanket.
- inner_lower_point ((float, float)): the x,z coordinates of the lower
- point on the inner surface of the blanket.
- thickness (float): the radial thickness of the blanket in cm.
- stp_filename (str, optional): Defaults to
- "BlanketConstantThicknessArcV.stp".
- stl_filename (str, optional): Defaults to
- "BlanketConstantThicknessArcV.stl".
- material_tag (str, optional): Defaults to "blanket_mat".
+ inner_mid_point: the x,z coordinates of the mid point on the inner
+ surface of the blanket.
+ inner_upper_point: the x,z coordinates of the upper point on the
+ inner surface of the blanket.
+ inner_lower_point: the x,z coordinates of the lower point on the
+ inner surface of the blanket.
+ thickness: the radial thickness of the blanket in cm.
+ stp_filename: Defaults to "BlanketConstantThicknessArcV.stp".
+ stl_filename: Defaults to "BlanketConstantThicknessArcV.stl".
+ material_tag: Defaults to "blanket_mat".
"""
def __init__(
self,
- inner_mid_point,
- inner_upper_point,
- inner_lower_point,
- thickness,
- stp_filename="BlanketConstantThicknessArcV.stp",
- stl_filename="BlanketConstantThicknessArcV.stl",
- material_tag="blanket_mat",
+ inner_mid_point: Tuple[float, float],
+ inner_upper_point: Tuple[float, float],
+ inner_lower_point: Tuple[float, float],
+ thickness: float,
+ stp_filename: Optional[str] = "BlanketConstantThicknessArcV.stp",
+ stl_filename: Optional[str] = "BlanketConstantThicknessArcV.stl",
+ material_tag: Optional[str] = "blanket_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/blanket_cutter_parallels.py b/paramak/parametric_components/blanket_cutter_parallels.py
index c96972661..16c7781d1 100644
--- a/paramak/parametric_components/blanket_cutter_parallels.py
+++ b/paramak/parametric_components/blanket_cutter_parallels.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import ExtrudeStraightShape
from paramak.utils import cut_solid
@@ -11,36 +12,35 @@ class BlanketCutterParallels(ExtrudeStraightShape):
sections with a fixed distance between each section.
Args:
- thickness (float): extruded distance (cm) of the cutter which
- translates to being the gap size between blankets when the cutter
- is used to segment blankets.
- gap_size (float): the distance between the inner edges of the two
- parrallel extrusions
- height (float, optional): height (cm) of the port. Defaults to 2000.0.
- width (float, optional): width (cm) of the port. Defaults to 2000.0.
- azimuth_placement_angle (list or float, optional): Defaults
- to [0., 36., 72., 108., 144., 180., 216., 252., 288., 324.]
- stp_filename (str, optional): Defaults to "BlanketCutterParallels.stp".
- stl_filename (str, optional): Defaults to "BlanketCutterParallels.stl".
- name (str, optional): Defaults to "blanket_cutter_Parallels".
- material_tag (str, optional): Defaults to
- "blanket_cutter_parallels_mat".
+ thickness: extruded distance (cm) of the cutter which translates to
+ being the gap size between blankets when the cutter is used to
+ segment blankets.
+ gap_size: the distance between the inner edges of the two parallel
+ extrusions
+ height: height (cm) of the port. Defaults to 2000.0.
+ width: width (cm) of the port. Defaults to 2000.0.
+ stp_filename: Defaults to "BlanketCutterParallels.stp".
+ stl_filename: Defaults to "BlanketCutterParallels.stl".
+ name: Defaults to "blanket_cutter_Parallels".
+ material_tag: Defaults to "blanket_cutter_parallels_mat".
+ azimuth_placement_angle (float or list of floats): Defaults to [0., 36.,
+ 72., 108., 144., 180., 216., 252., 288., 324.].
"""
def __init__(
self,
- thickness,
- gap_size,
- height=2000.,
- width=2000.,
- azimuth_placement_angle=[0., 36., 72., 108., 144., 180., 216., 252.,
- 288., 324.],
- stp_filename="BlanketCutterParallels.stp",
- stl_filename="BlanketCutterParallels.stl",
- name="blanket_cutter_parallels",
- material_tag="blanket_cutter_parallels_mat",
+ thickness: float,
+ gap_size: float,
+ height: Optional[float] = 2000.,
+ width: Optional[float] = 2000.,
+ azimuth_placement_angle=[0., 36., 72., 108., 144., 180., 216.,
+ 252., 288., 324.],
+ stp_filename: Optional[str] = "BlanketCutterParallels.stp",
+ stl_filename: Optional[str] = "BlanketCutterParallels.stl",
+ name: Optional[str] = "blanket_cutter_parallels",
+ material_tag: Optional[str] = "blanket_cutter_parallels_mat",
**kwargs
- ):
+ ) -> None:
self.main_cutting_shape = \
ExtrudeStraightShape(
distance=gap_size / 2.0,
diff --git a/paramak/parametric_components/blanket_cutters_star.py b/paramak/parametric_components/blanket_cutters_star.py
index ce276e24f..9e3be0d4b 100644
--- a/paramak/parametric_components/blanket_cutters_star.py
+++ b/paramak/parametric_components/blanket_cutters_star.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import ExtrudeStraightShape
@@ -9,33 +10,40 @@ class BlanketCutterStar(ExtrudeStraightShape):
sections with a fixed gap between each section.
Args:
- distance (float): extruded distance (cm) of the cutter which translates
- to being the gap size between blankets when the cutter is used to
- segment blankets.
- height (float, optional): height (cm) of the port. Defaults to 2000.0.
- width (float, optional): width (cm) of the port. Defaults to 2000.0.
- azimuth_placement_angle (list or float, optional): Defaults
- to [0., 36., 72., 108., 144., 180., 216., 252., 288., 324.]
- stp_filename (str, optional): Defaults to "BlanketCutterStar.stp".
- stl_filename (str, optional): Defaults to "BlanketCutterStar.stl".
- name (str, optional): defaults to "blanket_cutter_star".
- material_tag (str, optional): Defaults to
- "blanket_cutter_star_mat".
+ distance: extruded distance (cm) of the cutter which translates to being
+ the gap size between blankets when the cutter is used to segment
+ blankets.
+ height: height (cm) of the port. Defaults to 2000.0.
+ width: width (cm) of the port. Defaults to 2000.0.
+ azimuth_placement_angle (list or float, optional): Defaults to
+ [0., 36., 72., 108., 144., 180., 216., 252., 288., 324.]
+ stp_filename: Defaults to "BlanketCutterStar.stp".
+ stl_filename: Defaults to "BlanketCutterStar.stl".
+ name: defaults to "blanket_cutter_star".
+ material_tag: Defaults to "blanket_cutter_star_mat".
"""
def __init__(
- self,
- distance,
- height=2000.,
- width=2000.,
- azimuth_placement_angle=[0., 36., 72., 108., 144., 180., 216., 252.,
- 288., 324.],
- stp_filename="BlanketCutterStar.stp",
- stl_filename="BlanketCutterStar.stl",
- name="blanket_cutter_star",
- material_tag="blanket_cutter_star_mat",
- **kwargs
- ):
+ self,
+ distance: float,
+ height: Optional[float] = 2000.,
+ width: Optional[float] = 2000.,
+ azimuth_placement_angle: Optional[float] = [
+ 0.,
+ 36.,
+ 72.,
+ 108.,
+ 144.,
+ 180.,
+ 216.,
+ 252.,
+ 288.,
+ 324.],
+ stp_filename: Optional[str] = "BlanketCutterStar.stp",
+ stl_filename: Optional[str] = "BlanketCutterStar.stl",
+ name: Optional[str] = "blanket_cutter_star",
+ material_tag: Optional[str] = "blanket_cutter_star_mat",
+ **kwargs) -> None:
super().__init__(
extrude_both=True,
diff --git a/paramak/parametric_components/blanket_fp.py b/paramak/parametric_components/blanket_fp.py
index 5ea75cb13..153ddf755 100644
--- a/paramak/parametric_components/blanket_fp.py
+++ b/paramak/parametric_components/blanket_fp.py
@@ -2,7 +2,6 @@
import warnings
import mpmath
-
import numpy as np
import sympy as sp
from paramak import RotateMixedShape, diff_between_angles
diff --git a/paramak/parametric_components/center_column_circular.py b/paramak/parametric_components/center_column_circular.py
index b29793ba0..0d0b07dbe 100644
--- a/paramak/parametric_components/center_column_circular.py
+++ b/paramak/parametric_components/center_column_circular.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import RotateMixedShape
@@ -7,33 +8,28 @@ class CenterColumnShieldCircular(RotateMixedShape):
cylindrical inner profile.
Args:
- height (float): height of the center column shield (cm).
- inner_radius (float): the inner radius of the center column shield
- (cm).
- mid_radius (float): the inner radius of the outer hyperbolic profile of
- the center colunn shield (cm).
- outer_radius (float): the outer radius of the center column shield.
- stp_filename (str, optional): Defaults to
- "CenterColumnShieldCircular.stp".
- stl_filename (str, optional): Defaults to
- "CenterColumnShieldCircular.stl".
- name (str, optional): Defaults to "center_column_shield".
- material_tag (str, optional): Defaults to
- "center_column_shield_mat".
+ height: height of the center column shield (cm).
+ inner_radius: the inner radius of the center column shield (cm).
+ mid_radius: the inner radius of the outer hyperbolic profile of the center
+ colunn shield (cm).
+ outer_radius: the outer radius of the center column shield.
+ stp_filename: Defaults to "CenterColumnShieldCircular.stp".
+ stl_filename: Defaults to "CenterColumnShieldCircular.stl".
+ name: Defaults to "center_column_shield".
+ material_tag: Defaults to "center_column_shield_mat".
"""
def __init__(
self,
- height,
- inner_radius,
- mid_radius,
- outer_radius,
- stp_filename="CenterColumnShieldCircular.stp",
- stl_filename="CenterColumnShieldCircular.stl",
- name="center_column_shield",
- material_tag="center_column_shield_mat",
+ height: float,
+ inner_radius: float,
+ mid_radius: float,
+ outer_radius: float,
+ stp_filename: Optional[str] = "CenterColumnShieldCircular.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldCircular.stl",
+ material_tag: Optional[str] = "center_column_shield_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/center_column_cylinder.py b/paramak/parametric_components/center_column_cylinder.py
index c102ae424..22e5cffc9 100644
--- a/paramak/parametric_components/center_column_cylinder.py
+++ b/paramak/parametric_components/center_column_cylinder.py
@@ -1,31 +1,30 @@
+from typing import Optional
from paramak import RotateStraightShape
class CenterColumnShieldCylinder(RotateStraightShape):
"""A cylindrical center column shield volume with constant thickness.
- Arguments:
- height (float): height of the center column shield.
- inner_radius (float): the inner radius of the center column shield.
- outer_radius (float): the outer radius of the center column shield.
- stp_filename (str, optional): Defaults to
- "CenterColumnShieldCylinder.stp".
- stl_filename (str, optional): Defaults to
- "CenterColumnShieldCylinder.stl".
- material_tag (str, optional): Defaults to "center_column_shield_mat".
+ Args:
+ height: height of the center column shield.
+ inner_radius: the inner radius of the center column shield.
+ outer_radius: the outer radius of the center column shield.
+ stp_filename: Defaults to "CenterColumnShieldCylinder.stp".
+ stl_filename: Defaults to "CenterColumnShieldCylinder.stl".
+ material_tag: Defaults to "center_column_shield_mat".
"""
def __init__(
self,
- height,
- inner_radius,
- outer_radius,
- stp_filename="CenterColumnShieldCylinder.stp",
- stl_filename="CenterColumnShieldCylinder.stl",
- material_tag="center_column_shield_mat",
+ height: float,
+ inner_radius: float,
+ outer_radius: float,
+ stp_filename: Optional[str] = "CenterColumnShieldCylinder.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldCylinder.stl",
+ material_tag: Optional[str] = "center_column_shield_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/center_column_flat_top_circular.py b/paramak/parametric_components/center_column_flat_top_circular.py
index f5db9b557..8b6e89bc4 100644
--- a/paramak/parametric_components/center_column_flat_top_circular.py
+++ b/paramak/parametric_components/center_column_flat_top_circular.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import RotateMixedShape
@@ -8,34 +9,32 @@ class CenterColumnShieldFlatTopCircular(RotateMixedShape):
cylindrical inner profile.
Args:
- height (float): height of the center column shield.
- arc_height (float): height of the outer circular profile of the center
+ height: height of the center column shield.
+ arc_height: height of the outer circular profile of the center column
+ shield.
+ inner_radius: the inner radius of the center column shield.
+ mid_radius: the inner radius of the outer circular profile of the center
column shield.
- inner_radius (float): the inner radius of the center column shield.
- mid_radius (float): the inner radius of the outer circular profile of
- the center column shield.
- outer_radius (float): the outer radius of the center column shield.
- stp_filename (str, optional): Defaults to
- "CenterColumnShieldFlatTopCircular.stp".
- stl_filename (str, optional): Defaults to
- "CenterColumnShieldFlatTopCircular.stl".
- name (str, optional): Defaults to "center_column".
- material_tag (str, optional): Defaults to "center_column_shield_mat".
+ outer_radius: the outer radius of the center column shield.
+ stp_filename: Defaults to "CenterColumnShieldFlatTopCircular.stp".
+ stl_filename: Defaults to "CenterColumnShieldFlatTopCircular.stl".
+ name: Defaults to "center_column".
+ material_tag: Defaults to "center_column_shield_mat".
"""
def __init__(
self,
- height,
- arc_height,
- inner_radius,
- mid_radius,
- outer_radius,
- stp_filename="CenterColumnShieldFlatTopCircular.stp",
- stl_filename="CenterColumnShieldFlatTopCircular.stl",
- name="center_column",
- material_tag="center_column_shield_mat",
+ height: float,
+ arc_height: float,
+ inner_radius: float,
+ mid_radius: float,
+ outer_radius: float,
+ stp_filename: Optional[str] = "CenterColumnShieldFlatTopCircular.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldFlatTopCircular.stl",
+ name: Optional[str] = "center_column",
+ material_tag: Optional[str] = "center_column_shield_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
name=name,
diff --git a/paramak/parametric_components/center_column_flat_top_hyperbola.py b/paramak/parametric_components/center_column_flat_top_hyperbola.py
index c9d2f17e5..17a75f088 100644
--- a/paramak/parametric_components/center_column_flat_top_hyperbola.py
+++ b/paramak/parametric_components/center_column_flat_top_hyperbola.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import RotateMixedShape
@@ -8,34 +9,32 @@ class CenterColumnShieldFlatTopHyperbola(RotateMixedShape):
cylindrical inner profile.
Args:
- height (float): height of the center column shield.
- arc_height (float): height of the outer hyperbolic profile of the
+ height: height of the center column shield.
+ arc_height: height of the outer hyperbolic profile of the center column
+ shield.
+ inner_radius: the inner radius of the center column shield.
+ mid_radius: the inner radius of the outer hyperbolic profile of the
center column shield.
- inner_radius (float): the inner radius of the center column shield.
- mid_radius (float): the inner radius of the outer hyperbolic profile of
- the center column shield.
- outer_radius (float): the outer_radius of the center column shield.
- stp_filename (str, optional): Defaults to
- "CenterColumnShieldFlatTopHyperbola.stp".
- stl_filename (str, optional): Defaults to
- "CenterColumnShieldFlatTopHyperbola.stl".
- name (str, optional): Defaults to "center_column".
- material_tag (str, optional): Defaults to "center_column_shield_mat".
+ outer_radius: the outer_radius of the center column shield.
+ stp_filename: Defaults to "CenterColumnShieldFlatTopHyperbola.stp".
+ stl_filename: Defaults to "CenterColumnShieldFlatTopHyperbola.stl".
+ name: Defaults to "center_column".
+ material_tag: Defaults to "center_column_shield_mat".
"""
def __init__(
self,
- height,
- arc_height,
- inner_radius,
- mid_radius,
- outer_radius,
- stp_filename="CenterColumnShieldFlatTopHyperbola.stp",
- stl_filename="CenterColumnShieldFlatTopHyperbola.stl",
- name="center_column",
- material_tag="center_column_shield_mat",
+ height: float,
+ arc_height: float,
+ inner_radius: float,
+ mid_radius: float,
+ outer_radius: float,
+ stp_filename: Optional[str] = "CenterColumnShieldFlatTopHyperbola.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldFlatTopHyperbola.stl",
+ name: Optional[str] = "center_column",
+ material_tag: Optional[str] = "center_column_shield_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
name=name,
diff --git a/paramak/parametric_components/center_column_hyperbola.py b/paramak/parametric_components/center_column_hyperbola.py
index 210536a74..bd8b52924 100644
--- a/paramak/parametric_components/center_column_hyperbola.py
+++ b/paramak/parametric_components/center_column_hyperbola.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import RotateMixedShape
@@ -7,29 +8,29 @@ class CenterColumnShieldHyperbola(RotateMixedShape):
constant cylindrical inner profile.
Args:
- height (float): height of the center column shield.
- inner_radius (float): the inner radius of the center column shield.
- mid_radius (float): the inner radius of the outer hyperbolic profile of
+ height: height of the center column shield.
+ inner_radius: the inner radius of the center column shield.
+ mid_radius: the inner radius of the outer hyperbolic profile of
the center column shield.
- outer_radius (float): the outer radius of the center column shield.
- stp_filename (str, optional): Defaults to "CenterColumnShieldHyperbola.stp".
- stl_filename (str, optional): Defaults to "CenterColumnShieldHyperbola.stl".
- name (str, optional): Defaults to "center_column".
- material_tag (str, optional): Defaults to "center_column_shield_mat".
+ outer_radius: the outer radius of the center column shield.
+ stp_filename: Defaults to "CenterColumnShieldHyperbola.stp".
+ stl_filename: Defaults to "CenterColumnShieldHyperbola.stl".
+ name: Defaults to "center_column".
+ material_tag: Defaults to "center_column_shield_mat".
"""
def __init__(
self,
- height,
- inner_radius,
- mid_radius,
- outer_radius,
- stp_filename="CenterColumnShieldHyperbola.stp",
- stl_filename="CenterColumnShieldHyperbola.stl",
- name="center_column",
- material_tag="center_column_shield_mat",
+ height: float,
+ inner_radius: float,
+ mid_radius: float,
+ outer_radius: float,
+ stp_filename: Optional[str] = "CenterColumnShieldHyperbola.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldHyperbola.stl",
+ name: Optional[str] = "center_column",
+ material_tag: Optional[str] = "center_column_shield_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
name=name,
diff --git a/paramak/parametric_components/center_column_plasma_dependant.py b/paramak/parametric_components/center_column_plasma_dependant.py
index 1b71de121..5c2ff4518 100644
--- a/paramak/parametric_components/center_column_plasma_dependant.py
+++ b/paramak/parametric_components/center_column_plasma_dependant.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import Plasma, RotateMixedShape
@@ -9,42 +10,36 @@ class CenterColumnShieldPlasmaHyperbola(RotateMixedShape):
inner radius.
Args:
- height (float): height of the center column shield.
- inner_radius (float): the inner radius of the center column shield.
- mid_offset (float): the offset of the shield from the plasma at the
- plasma center.
- edge_offset (float): the offset of the shield from the plasma at the
- plasma edge.
- major_radius (int, optional): the major radius of the plasma. Defaults
- to 450.0.
- minor_radius (int, optional): the minor radius of the plasma. Defaults
- to 150.0.
- triangularity (float, optional): the triangularity of the plasma.
- Defaults to 0.55.
- elongation (float, optional): the elongation of the plasma. Defaults
- to 2.0.
- material_tag (str, optional): Defaults to "center_column_shield_mat".
- stp_filename (str, optional): Defaults to
- "CenterColumnShieldPlasmaHyperbola.stp".
- stl_filename (str, optional): Defaults to
- "CenterColumnShieldPlasmaHyperbola.stl".
+ height: height of the center column shield.
+ inner_radius: the inner radius of the center column shield.
+ mid_offset: the offset of the shield from the plasma at the plasma
+ center.
+ edge_offset: the offset of the shield from the plasma at the plasma
+ edge.
+ major_radius: the major radius of the plasma. Defaults to 450.0.
+ minor_radius: the minor radius of the plasma. Defaults to 150.0.
+ triangularity: the triangularity of the plasma. Defaults to 0.55.
+ elongation: the elongation of the plasma. Defaults to 2.0.
+ material_tag: Defaults to "center_column_shield_mat".
+ stp_filename: Defaults to "CenterColumnShieldPlasmaHyperbola.stp".
+ stl_filename: Defaults to "CenterColumnShieldPlasmaHyperbola.stl".
"""
def __init__(
self,
- height,
- inner_radius,
- mid_offset,
- edge_offset,
- major_radius=450.0,
- minor_radius=150.0,
- triangularity=0.55,
- elongation=2.0,
- material_tag="center_column_shield_mat",
- stp_filename="CenterColumnShieldPlasmaHyperbola.stp",
- stl_filename="CenterColumnShieldPlasmaHyperbola.stl",
+ height: float,
+ inner_radius: float,
+ mid_offset: float,
+ edge_offset: float,
+ major_radius: Optional[float] = 450.0,
+ minor_radius: Optional[float] = 150.0,
+ triangularity: Optional[float] = 0.55,
+ elongation: Optional[float] = 2.0,
+ material_tag: Optional[str] = "center_column_shield_mat",
+ stp_filename: Optional[str] = "CenterColumnShieldPlasmaHyperbola.stp",
+ stl_filename: Optional[str] = "CenterColumnShieldPlasmaHyperbola.stl",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/coolant_channel_ring_curved.py b/paramak/parametric_components/coolant_channel_ring_curved.py
index ee6339348..cff431225 100644
--- a/paramak/parametric_components/coolant_channel_ring_curved.py
+++ b/paramak/parametric_components/coolant_channel_ring_curved.py
@@ -1,4 +1,5 @@
+from typing import Optional
import numpy as np
from paramak import SweepCircleShape
@@ -8,41 +9,38 @@ class CoolantChannelRingCurved(SweepCircleShape):
constant thickness.
Args:
- height (float): height of each coolant channel in ring.
- channel_radius (float): radius of each coolant channel in ring.
- number_of_coolant_channels (float): number of coolant channels in ring.
- ring_radius (float): radius of coolant channel ring.
+ height: height of each coolant channel in ring.
+ channel_radius: radius of each coolant channel in ring.
+ number_of_coolant_channels: number of coolant channels in ring.
+ ring_radius: radius of coolant channel ring.
+ start_angle: angle at which the first channel in the ring is placed.
+ Defaults to 0.0.
+ stp_filename: Defaults to "CoolantChannelRingCurved.stp".
+ stl_filename: Defaults to "CoolantChannelRingCurved.stl".
+ material_tag: Defaults to "coolant_channel_mat".
+ rotation_axis: azimuthal axis around which the separate coolant channels
+ are placed. Default calculated by workplane and path_workplane.
workplane (str, optional): plane in which the cross-sections of the
coolant channels lie. Defaults to "XY".
- start_angle (float, optional): angle at which the first channel in the
- ring is placed. Defaults to 0.
- path_workplane (str, optional): plane in which the cross-sections of
- the coolant channels are swept. Defaults to "XZ".
- rotation_axis (str, optional): azimuthal axis around which the separate
- coolant channels are placed. Default calculated by workplane and
- path_workplane.
+ path_workplane (str, optional): plane in which the cross-sections of the
+ coolant channels are swept. Defaults to "XZ".
force_cross_section (bool, optional): forces coolant channels to have a
more constant cross-section along their curve. Defaults to False.
- stp_filename (str, optional): Defaults to
- "CoolantChannelRingCurved.stp".
- stl_filename (str, optional): Defaults to
- "CoolantChannelRingCurved.stl".
- material_tag (str, optional): Defaults to "coolant_channel_mat".
"""
def __init__(
self,
- height,
- channel_radius,
- number_of_coolant_channels,
- ring_radius,
- mid_offset,
- start_angle=0,
- stp_filename="CoolantChannelRingCurved.stp",
- stl_filename="CoolantChannelRingCurved.stl",
- material_tag="coolant_channel_mat",
+ height: float,
+ channel_radius: float,
+ number_of_coolant_channels: int,
+ ring_radius: float,
+ mid_offset: float,
+ start_angle: Optional[float] = 0.0,
+ stp_filename: Optional[str] = "CoolantChannelRingCurved.stp",
+ stl_filename: Optional[str] = "CoolantChannelRingCurved.stl",
+ material_tag: Optional[str] = "coolant_channel_mat",
**kwargs
- ):
+ ) -> None:
self.ring_radius = ring_radius
self.mid_offset = mid_offset
diff --git a/paramak/parametric_components/coolant_channel_ring_straight.py b/paramak/parametric_components/coolant_channel_ring_straight.py
index c0540adef..17f6de96b 100644
--- a/paramak/parametric_components/coolant_channel_ring_straight.py
+++ b/paramak/parametric_components/coolant_channel_ring_straight.py
@@ -1,4 +1,5 @@
+from typing import Optional
import numpy as np
from paramak import ExtrudeCircleShape
@@ -8,35 +9,33 @@ class CoolantChannelRingStraight(ExtrudeCircleShape):
constant thickness.
Args:
- height (float): height of each coolant channel in ring.
- channel_radius (float): radius of each coolant channel in ring.
- number_of_coolant_channels (float): number of coolant channels in ring.
- ring radius (float): radius of coolant channel ring.
- start_angle (float, optional): angle at which the first channel in the
- ring is placed. Defaults to 0.
- workplane (str, optional): plane in which the cross-sections of the
- coolant channels lie. Defaults to "XY".
+ height: height of each coolant channel in ring.
+ channel_radius: radius of each coolant channel in ring.
+ number_of_coolant_channels: number of coolant channels in ring.
+ ring radius: radius of coolant channel ring.
+ start_angle: angle at which the first channel in the ring is placed.
+ Defaults to 0.0.
+ stp_filename: Defaults to "CoolantChannelRingStraight.stp".
+ stl_filename: Defaults to "CoolantChannelRingStraight.stl".
+ material_tag: Defaults to "coolant_channel_mat".
rotation_axis (str, optional): azimuthal axis around which the separate
coolant channels are placed.
- stp_filename (str, optional): Defaults to
- "CoolantChannelRingStraight.stp".
- stl_filename (str, optional): Defaults to
- "CoolantChannelRingStraight.stl".
- material_tag (str, optional): Defaults to "coolant_channel_mat".
+ workplane (str, optional): plane in which the cross-sections of the
+ coolant channels lie. Defaults to "XY".
"""
def __init__(
self,
- height,
- channel_radius,
- number_of_coolant_channels,
- ring_radius,
- start_angle=0,
- stp_filename="CoolantChannelRingStraight.stp",
- stl_filename="CoolantChannelRingStraight.stl",
- material_tag="coolant_channel_mat",
+ height: float,
+ channel_radius: float,
+ number_of_coolant_channels: int,
+ ring_radius: float,
+ start_angle: Optional[float] = 0.0,
+ stp_filename: Optional[str] = "CoolantChannelRingStraight.stp",
+ stl_filename: Optional[str] = "CoolantChannelRingStraight.stl",
+ material_tag: Optional[str] = "coolant_channel_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=height,
diff --git a/paramak/parametric_components/cutting_wedge.py b/paramak/parametric_components/cutting_wedge.py
index 468350944..df957b49f 100644
--- a/paramak/parametric_components/cutting_wedge.py
+++ b/paramak/parametric_components/cutting_wedge.py
@@ -1,4 +1,5 @@
+from typing import Optional
from paramak import RotateStraightShape
@@ -7,25 +8,25 @@ class CuttingWedge(RotateStraightShape):
can be useful for cutting sector models.
Args:
- height (float): the vertical (z axis) height of the coil (cm).
- radius (float): the horizontal (x axis) width of the coil (cm).
- stp_filename (str, optional): Defaults to "CuttingWedge.stp".
- stl_filename (str, optional): Defaults to "CuttingWedge.stl".
- rotation_angle (float, optional): Defaults to 180.0.
- material_tag (str, optional): Defaults to "cutting_slice_mat".
+ height: the vertical (z axis) height of the coil (cm).
+ radius: the horizontal (x axis) width of the coil (cm).
+ stp_filename: Defaults to "CuttingWedge.stp".
+ stl_filename: Defaults to "CuttingWedge.stl".
+ rotation_angle: Defaults to 180.0.
+ material_tag: Defaults to "cutting_slice_mat".
"""
def __init__(
self,
- height,
- radius,
- stp_filename="CuttingWedge.stp",
- stl_filename="CuttingWedge.stl",
- rotation_angle=180.0,
- material_tag="cutting_slice_mat",
+ height: float,
+ radius: float,
+ stp_filename: Optional[str] = "CuttingWedge.stp",
+ stl_filename: Optional[str] = "CuttingWedge.stl",
+ rotation_angle: Optional[float] = 180.0,
+ material_tag: Optional[str] = "cutting_slice_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/cutting_wedge_fs.py b/paramak/parametric_components/cutting_wedge_fs.py
index 97a1fe730..2749b26a0 100644
--- a/paramak/parametric_components/cutting_wedge_fs.py
+++ b/paramak/parametric_components/cutting_wedge_fs.py
@@ -4,6 +4,8 @@
from paramak import CuttingWedge
+SAFETY_FACTOR = 3
+
class CuttingWedgeFS(CuttingWedge):
"""Creates a wedge from a Shape that can be useful for cutting sector
@@ -130,6 +132,5 @@ def find_radius_height(self):
else:
raise ValueError('cutting_wedge cannot be created')
- safety_factor = 3
- self.radius = safety_factor * max_x
- self.height = safety_factor * max_y
+ self.radius = SAFETY_FACTOR * max_x
+ self.height = SAFETY_FACTOR * max_y
diff --git a/paramak/parametric_components/inner_tf_coils_circular.py b/paramak/parametric_components/inner_tf_coils_circular.py
index e80f202ed..1e2fbc50f 100644
--- a/paramak/parametric_components/inner_tf_coils_circular.py
+++ b/paramak/parametric_components/inner_tf_coils_circular.py
@@ -1,6 +1,6 @@
import math
-
+from typing import Optional
import numpy as np
from paramak import ExtrudeMixedShape
@@ -10,34 +10,34 @@ class InnerTfCoilsCircular(ExtrudeMixedShape):
constant gaps between each coil.
Args:
- height (float): height of tf coils.
- inner_radius (float): inner radius of tf coils.
- outer_radius (float): outer radius of tf coils.
- number_of_coils (int): number of tf coils.
- gap_size (float): gap between adjacent tf coils.
- azimuth_start_angle (float, optional): Defaults to 0.0.
- stp_filename (str, optional): Defaults to "InnerTfCoilsCircular.stp".
- stl_filename (str, optional): Defaults to "InnerTfCoilsCircular.stl".
- material_tag (str, optional): Defaults to "inner_tf_coil_mat".
- workplane (str, optional): Defaults to "XY".
- rotation_axis (str, optional): Defaults to "Z".
+ height: height of tf coils.
+ inner_radius: inner radius of tf coils.
+ outer_radius: outer radius of tf coils.
+ number_of_coils: number of tf coils.
+ gap_size: gap between adjacent tf coils.
+ azimuth_start_angle: Defaults to 0.0.
+ stp_filename: Defaults to "InnerTfCoilsCircular.stp".
+ stl_filename: Defaults to "InnerTfCoilsCircular.stl".
+ material_tag: Defaults to "inner_tf_coil_mat".
+ workplane: Defaults to "XY".
+ rotation_axis: Defaults to "Z".
"""
def __init__(
self,
- height,
- inner_radius,
- outer_radius,
- number_of_coils,
- gap_size,
- azimuth_start_angle=0.0,
- stp_filename="InnerTfCoilsCircular.stp",
- stl_filename="InnerTfCoilsCircular.stl",
- material_tag="inner_tf_coil_mat",
- workplane="XY",
- rotation_axis="Z",
+ height: float,
+ inner_radius: float,
+ outer_radius: float,
+ number_of_coils: int,
+ gap_size: float,
+ azimuth_start_angle: Optional[float] = 0.0,
+ stp_filename: Optional[str] = "InnerTfCoilsCircular.stp",
+ stl_filename: Optional[str] = "InnerTfCoilsCircular.stl",
+ material_tag: Optional[str] = "inner_tf_coil_mat",
+ workplane: Optional[str] = "XY",
+ rotation_axis: Optional[str] = "Z",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=height,
diff --git a/paramak/parametric_components/inner_tf_coils_flat.py b/paramak/parametric_components/inner_tf_coils_flat.py
index e3de68c14..59bea0c12 100644
--- a/paramak/parametric_components/inner_tf_coils_flat.py
+++ b/paramak/parametric_components/inner_tf_coils_flat.py
@@ -1,6 +1,6 @@
import math
-
+from typing import Optional
import numpy as np
from paramak import ExtrudeStraightShape
@@ -10,34 +10,34 @@ class InnerTfCoilsFlat(ExtrudeStraightShape):
constant gaps between each coil.
Args:
- height (float): height of tf coils.
- inner_radius (float): inner radius of tf coils.
- outer_radius (float): outer radius of tf coils.
- number_of_coils (int): number of tf coils.
- gap_size (float): gap between adjacent tf coils.
- azimuth_start_angle (float, optional): defaults to 0.0.
- stp_filename (str, optional): defaults to "InnerTfCoilsFlat.stp".
- stl_filename (str, optional): defaults to "InnerTfCoilsFlat.stl".
- material_tag (str, optional): defaults to "inner_tf_coil_mat".
- workplane (str, optional):defaults to "XY".
- rotation_axis (str, optional): Defaults to "Z".
+ height: height of tf coils.
+ inner_radius: inner radius of tf coils.
+ outer_radius: outer radius of tf coils.
+ number_of_coils: number of tf coils.
+ gap_size: gap between adjacent tf coils.
+ azimuth_start_angle: defaults to 0.0.
+ stp_filename: defaults to "InnerTfCoilsFlat.stp".
+ stl_filename: defaults to "InnerTfCoilsFlat.stl".
+ material_tag: defaults to "inner_tf_coil_mat".
+ workplane:defaults to "XY".
+ rotation_axis: Defaults to "Z".
"""
def __init__(
self,
- height,
- inner_radius,
- outer_radius,
- number_of_coils,
- gap_size,
- azimuth_start_angle=0.0,
- stp_filename="InnerTfCoilsFlat.stp",
- stl_filename="InnerTfCoilsFlat.stl",
- material_tag="inner_tf_coil_mat",
- workplane="XY",
- rotation_axis="Z",
+ height: float,
+ inner_radius: float,
+ outer_radius: float,
+ number_of_coils: int,
+ gap_size: float,
+ azimuth_start_angle: Optional[float] = 0.0,
+ stp_filename: Optional[str] = "InnerTfCoilsFlat.stp",
+ stl_filename: Optional[str] = "InnerTfCoilsFlat.stl",
+ material_tag: Optional[str] = "inner_tf_coil_mat",
+ workplane: Optional[str] = "XY",
+ rotation_axis: Optional[str] = "Z",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=height,
diff --git a/paramak/parametric_components/poloidal_field_coil.py b/paramak/parametric_components/poloidal_field_coil.py
index 54626b37c..1c6ef2286 100644
--- a/paramak/parametric_components/poloidal_field_coil.py
+++ b/paramak/parametric_components/poloidal_field_coil.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
from paramak import RotateStraightShape
@@ -6,27 +7,26 @@ class PoloidalFieldCoil(RotateStraightShape):
"""Creates a rectangular poloidal field coil.
Args:
- height (float): the vertical (z axis) height of the coil (cm).
- width (float): the horizontal (x axis) width of the coil (cm).
- center_point (tuple of floats): the center of the coil (x,z) values
- (cm).
- stp_filename (str, optional): defaults to "PoloidalFieldCoil.stp".
- stl_filename (str, optional): defaults to "PoloidalFieldCoil.stl".
- name (str, optional): defaults to "pf_coil".
- material_tag (str, optional): defaults to "pf_coil_mat".
+ height: the vertical (z axis) height of the coil (cm).
+ width: the horizontal (x axis) width of the coil (cm).
+ center_point: the center of the coil (x,z) values (cm).
+ stp_filename: defaults to "PoloidalFieldCoil.stp".
+ stl_filename: defaults to "PoloidalFieldCoil.stl".
+ name: defaults to "pf_coil".
+ material_tag: defaults to "pf_coil_mat".
"""
def __init__(
self,
- height,
- width,
- center_point,
- stp_filename="PoloidalFieldCoil.stp",
- stl_filename="PoloidalFieldCoil.stl",
- name="pf_coil",
- material_tag="pf_coil_mat",
+ height: float,
+ width: float,
+ center_point: Tuple[float, float],
+ stp_filename: Optional[str] = "PoloidalFieldCoil.stp",
+ stl_filename: Optional[str] = "PoloidalFieldCoil.stl",
+ name: Optional[str] = "pf_coil",
+ material_tag: Optional[str] = "pf_coil_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
name=name,
diff --git a/paramak/parametric_components/poloidal_field_coil_case.py b/paramak/parametric_components/poloidal_field_coil_case.py
index 51af0e9aa..c72fe454b 100644
--- a/paramak/parametric_components/poloidal_field_coil_case.py
+++ b/paramak/parametric_components/poloidal_field_coil_case.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
from paramak import RotateStraightShape
@@ -7,28 +8,26 @@ class PoloidalFieldCoilCase(RotateStraightShape):
describe the existing coil and the thickness of the casing required.
Args:
- coil_height (float): the vertical (z axis) height of the coil (cm).
- coil_width (float): the horizontal(x axis) width of the coil (cm).
- center_point (tuple of floats): the center of the coil (x,z) values
- (cm).
- casing_thickness (tuple of floats): the thickness of the coil casing
- (cm).
- stp_filename (str, optional): defaults to "PoloidalFieldCoilCase.stp".
- stl_filename (str, optional): defaults to "PoloidalFieldCoilCase.stl".
- material_tag (str, optional): defaults to "pf_coil_case_mat".
+ coil_height: the vertical (z axis) height of the coil (cm).
+ coil_width: the horizontal (x axis) width of the coil (cm).
+ center_point: the center of the coil (x,z) values (cm).
+ casing_thickness: the thickness of the coil casing (cm).
+ stp_filename: defaults to "PoloidalFieldCoilCase.stp".
+ stl_filename: defaults to "PoloidalFieldCoilCase.stl".
+ material_tag: defaults to "pf_coil_case_mat".
"""
def __init__(
self,
- casing_thickness,
- coil_height,
- coil_width,
- center_point,
- stp_filename="PoloidalFieldCoilCase.stp",
- stl_filename="PoloidalFieldCoilCase.stl",
- material_tag="pf_coil_case_mat",
+ casing_thickness: Tuple[float, float],
+ coil_height: float,
+ coil_width: float,
+ center_point: Tuple[float, float],
+ stp_filename: Optional[str] = "PoloidalFieldCoilCase.stp",
+ stl_filename: Optional[str] = "PoloidalFieldCoilCase.stl",
+ material_tag: Optional[str] = "pf_coil_case_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
material_tag=material_tag,
diff --git a/paramak/parametric_components/poloidal_segmenter.py b/paramak/parametric_components/poloidal_segmenter.py
index fa42d1c10..a3eb2033e 100644
--- a/paramak/parametric_components/poloidal_segmenter.py
+++ b/paramak/parametric_components/poloidal_segmenter.py
@@ -3,8 +3,8 @@
import cadquery as cq
from paramak import RotateStraightShape
-from paramak.utils import (coefficients_of_line_from_points, get_hash,
- intersect_solid, rotate)
+from paramak.utils import (coefficients_of_line_from_points, intersect_solid,
+ rotate)
class PoloidalSegments(RotateStraightShape):
@@ -61,7 +61,7 @@ def number_of_segments(self):
@number_of_segments.setter
def number_of_segments(self, value):
if isinstance(value, int) is False:
- raise ValueError(
+ raise TypeError(
"PoloidalSegmenter.number_of_segments must be an int.")
if value < 1:
raise ValueError(
diff --git a/paramak/parametric_components/toroidal_field_coil_coat_hanger.py b/paramak/parametric_components/toroidal_field_coil_coat_hanger.py
index ecdafb05a..2e2af7ecb 100644
--- a/paramak/parametric_components/toroidal_field_coil_coat_hanger.py
+++ b/paramak/parametric_components/toroidal_field_coil_coat_hanger.py
@@ -1,6 +1,7 @@
import math
+from typing import Optional, Tuple
import cadquery as cq
import numpy as np
from paramak import ExtrudeStraightShape
@@ -11,43 +12,40 @@ class ToroidalFieldCoilCoatHanger(ExtrudeStraightShape):
"""Creates a coat hanger shaped toroidal field coil.
Args:
- horizontal_start_point (tuple of 2 floats): the (x,z) coordinates of
- the inner upper point (cm).
- horizontal_length (tuple of 2 floats): the radial length of the
- horizontal section of the TF coil (cm).
- vertical_mid_point (tuple of 2 points): the (x,z) coordinates of the
- mid point of the outboard vertical section (cm).
- vertical_length (tuple of 2 floats): the radial length of the outboard
- vertical section of the TF coil (cm).
- thickness (float): the thickness of the toroidal field coil.
- distance (float): the extrusion distance.
- number_of_coils (int): the number of TF coils. This changes with
+ horizontal_start_point: the (x,z) coordinates of the inner upper
+ point (cm).
+ horizontal_length: the radial length of the horizontal section of
+ the TF coil (cm).
+ vertical_mid_point: the (x,z) coordinates of the mid point of the
+ outboard vertical section (cm).
+ vertical_length: the radial length of the outboard vertical section
+ of the TF coil (cm).
+ thickness: the thickness of the toroidal field coil.
+ distance: the extrusion distance.
+ number_of_coils: the number of TF coils. This changes with
azimuth_placement_angle dividing up 360 degrees by the number of
coils.
- with_inner_leg (bool, optional): Include the inner TF leg. Defaults to
- True.
- stp_filename (str, optional): defaults to
- "ToroidalFieldCoilCoatHanger.stp".
- stl_filename (str, optional): defaults to
- "ToroidalFieldCoilCoatHanger.stl".
- material_tag (str, optional): defaults to "outer_tf_coil_mat".
+ with_inner_leg: Include the inner TF leg. Defaults to True.
+ stp_filename: Defaults to "ToroidalFieldCoilCoatHanger.stp".
+ stl_filename: Defaults to "ToroidalFieldCoilCoatHanger.stl".
+ material_tag: Defaults to "outer_tf_coil_mat".
"""
def __init__(
self,
- horizontal_start_point,
- horizontal_length,
- vertical_mid_point,
- vertical_length,
- thickness,
- distance,
- number_of_coils,
- with_inner_leg=True,
- stp_filename="ToroidalFieldCoilCoatHanger.stp",
- stl_filename="ToroidalFieldCoilCoatHanger.stl",
- material_tag="outer_tf_coil_mat",
+ horizontal_start_point: Tuple[float, float],
+ horizontal_length: float,
+ vertical_mid_point: Tuple[float, float],
+ vertical_length: float,
+ thickness: float,
+ distance: float,
+ number_of_coils: int,
+ with_inner_leg: Optional[bool] = True,
+ stp_filename: Optional[str] = "ToroidalFieldCoilCoatHanger.stp",
+ stl_filename: Optional[str] = "ToroidalFieldCoilCoatHanger.stl",
+ material_tag: Optional[str] = "outer_tf_coil_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=distance,
diff --git a/paramak/parametric_components/toroidal_field_coil_princeton_d.py b/paramak/parametric_components/toroidal_field_coil_princeton_d.py
index 06f04ece3..970e5fbd3 100644
--- a/paramak/parametric_components/toroidal_field_coil_princeton_d.py
+++ b/paramak/parametric_components/toroidal_field_coil_princeton_d.py
@@ -1,4 +1,6 @@
+from typing import Optional
+
import numpy as np
from paramak import ExtrudeMixedShape
from paramak.utils import add_thickness
@@ -10,38 +12,34 @@ class ToroidalFieldCoilPrincetonD(ExtrudeMixedShape):
"""Toroidal field coil based on Princeton-D curve
Args:
- R1 (float): smallest radius (cm)
- R2 (float): largest radius (cm)
- thickness (float): magnet thickness (cm)
- distance (float): extrusion distance (cm)
- number_of_coils (int): the number of tf coils. This changes by the
+ R1: smallest radius (cm)
+ R2: largest radius (cm)
+ thickness: magnet thickness (cm)
+ distance: extrusion distance (cm)
+ number_of_coils: the number of tf coils. This changes by the
azimuth_placement_angle dividing up 360 degrees by the number of
coils.
- vertical_displacement (float, optional): vertical displacement (cm).
- Defaults to 0.0.
- with_inner_leg (bool, optional): Include the inner tf leg. Defaults to
- True.
- stp_filename (str, optional): defaults to
- "ToroidalFieldCoilPrincetonD.stp".
- stl_filename (str, optional): defaults to
- "ToroidalFieldCoilPrincetonD.stl".
- material_tag (str, optional): defaults to "outer_tf_coil_mat".
+ vertical_displacement: vertical displacement (cm). Defaults to 0.0.
+ with_inner_leg: Include the inner tf leg. Defaults to True.
+ stp_filename: Defaults to "ToroidalFieldCoilPrincetonD.stp".
+ stl_filename: Defaults to "ToroidalFieldCoilPrincetonD.stl".
+ material_tag: Defaults to "outer_tf_coil_mat".
"""
def __init__(
self,
- R1,
- R2,
- thickness,
- distance,
- number_of_coils,
- vertical_displacement=0.0,
- with_inner_leg=True,
- stp_filename="ToroidalFieldCoilPrincetonD.stp",
- stl_filename="ToroidalFieldCoilPrincetonD.stl",
- material_tag="outer_tf_coil_mat",
+ R1: float,
+ R2: float,
+ thickness: float,
+ distance: float,
+ number_of_coils: int,
+ vertical_displacement: Optional[float] = 0.0,
+ with_inner_leg: Optional[bool] = True,
+ stp_filename: Optional[str] = "ToroidalFieldCoilPrincetonD.stp",
+ stl_filename: Optional[str] = "ToroidalFieldCoilPrincetonD.stl",
+ material_tag: Optional[str] = "outer_tf_coil_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=distance,
diff --git a/paramak/parametric_components/toroidal_field_coil_rectangle.py b/paramak/parametric_components/toroidal_field_coil_rectangle.py
index 3b0a7400a..2e0004882 100644
--- a/paramak/parametric_components/toroidal_field_coil_rectangle.py
+++ b/paramak/parametric_components/toroidal_field_coil_rectangle.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
import cadquery as cq
import numpy as np
from paramak import ExtrudeStraightShape
@@ -9,37 +10,34 @@ class ToroidalFieldCoilRectangle(ExtrudeStraightShape):
"""Creates a rectangular shaped toroidal field coil.
Args:
- horizontal_start_point (tuple of 2 floats): the (x,z) coordinates of
- the inner upper point (cm).
- vertical_mid_point (tuple of 2 points): the (x,z) coordinates of the
- mid point of the vertical section (cm).
- thickness (float): the thickness of the toroidal field coil.
- distance (float): the extrusion distance.
- number_of_coils (int): the number of tf coils. This changes by the
+ horizontal_start_point: the (x,z) coordinates of the inner upper
+ point (cm).
+ vertical_mid_point: the (x,z) coordinates of the mid point of the
+ vertical section (cm).
+ thickness: the thickness of the toroidal field coil.
+ distance: the extrusion distance.
+ number_of_coils: the number of tf coils. This changes by the
azimuth_placement_angle dividing up 360 degrees by the number of
coils.
- with_inner_leg (bool, optional): include the inner tf leg. Defaults to
- True.
- stp_filename (str, optional): defaults to
- "ToroidalFieldCoilRectangle.stp".
- stl_filename (str, optional): defaults to
- "ToroidalFieldCoilRectangle.stl".
- material_tag (str, optional): defaults to "outer_tf_coil_mat".
+ with_inner_leg: include the inner tf leg. Defaults to True.
+ stp_filename: Defaults to "ToroidalFieldCoilRectangle.stp".
+ stl_filename: Defaults to "ToroidalFieldCoilRectangle.stl".
+ material_tag: Defaults to "outer_tf_coil_mat".
"""
def __init__(
self,
- horizontal_start_point,
- vertical_mid_point,
- thickness,
- distance,
- number_of_coils,
- with_inner_leg=True,
- stp_filename="ToroidalFieldCoilRectangle.stp",
- stl_filename="ToroidalFieldCoilRectangle.stl",
- material_tag="outer_tf_coil_mat",
+ horizontal_start_point: Tuple[float, float],
+ vertical_mid_point: Tuple[float, float],
+ thickness: float,
+ distance: float,
+ number_of_coils: int,
+ with_inner_leg: Optional[bool] = True,
+ stp_filename: Optional[str] = "ToroidalFieldCoilRectangle.stp",
+ stl_filename: Optional[str] = "ToroidalFieldCoilRectangle.stl",
+ material_tag: Optional[str] = "outer_tf_coil_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=distance,
diff --git a/paramak/parametric_components/toroidal_field_coil_triple_arc.py b/paramak/parametric_components/toroidal_field_coil_triple_arc.py
index 138b9fc6a..ceff4a6ae 100644
--- a/paramak/parametric_components/toroidal_field_coil_triple_arc.py
+++ b/paramak/parametric_components/toroidal_field_coil_triple_arc.py
@@ -1,4 +1,5 @@
+from typing import Optional, Tuple
import numpy as np
from paramak import ExtrudeMixedShape
@@ -7,43 +8,38 @@ class ToroidalFieldCoilTripleArc(ExtrudeMixedShape):
"""Toroidal field coil made of three arcs
Args:
- R1 (float): smallest radius (cm)
- h (float): height of the straight section (cm)
- radii ((float, float)): radii of the small and medium arcs (cm)
- coverages ((float, float)): coverages of the small and medium arcs
- (deg)
- thickness (float): magnet thickness (cm)
- distance (float): extrusion distance (cm)
- number_of_coils (int): the number of TF coils. This changes by the
+ R1: smallest radius (cm).
+ h: height of the straight section (cm).
+ radii: radii of the small and medium arcs (cm).
+ coverages: coverages of the small and medium arcs (deg).
+ thickness: magnet thickness (cm).
+ distance: extrusion distance (cm).
+ number_of_coils: the number of TF coils. This changes by the
azimuth_placement_angle dividing up 360 degrees by the number of
coils.
- vertical_displacement (float, optional): vertical displacement (cm).
- Defaults to 0.0.
- with_inner_leg (bool, optional): Include the inner tf leg. Defaults to
- True.
- stp_filename (str, optional): defaults to
- "ToroidalFieldCoilTripleArc.stp".
- stl_filename (str, optional): defaults to
- "ToroidalFieldCoilTripleArc.stl".
- material_tag (str, optional): defaults to "outer_tf_coil_mat".
+ vertical_displacement: vertical displacement (cm). Defaults to 0.0.
+ with_inner_leg: Include the inner tf leg. Defaults to True.
+ stp_filename: Defaults to "ToroidalFieldCoilTripleArc.stp".
+ stl_filename: Defaults to "ToroidalFieldCoilTripleArc.stl".
+ material_tag: Defaults to "outer_tf_coil_mat".
"""
def __init__(
self,
- R1,
- h,
- radii,
- coverages,
- thickness,
- distance,
- number_of_coils,
- vertical_displacement=0.0,
- with_inner_leg=True,
- stp_filename="ToroidalFieldCoilTripleArc.stp",
- stl_filename="ToroidalFieldCoilTripleArc.stl",
- material_tag="outer_tf_coil_mat",
+ R1: float,
+ h: float,
+ radii: Tuple[float, float],
+ coverages: Tuple[float, float],
+ thickness: float,
+ distance: float,
+ number_of_coils: int,
+ vertical_displacement: Optional[float] = 0.0,
+ with_inner_leg: Optional[bool] = True,
+ stp_filename: Optional[str] = "ToroidalFieldCoilTripleArc.stp",
+ stl_filename: Optional[str] = "ToroidalFieldCoilTripleArc.stl",
+ material_tag: Optional[str] = "outer_tf_coil_mat",
**kwargs
- ):
+ ) -> None:
super().__init__(
distance=distance,
diff --git a/examples/example_neutronics_simulations/make_faceteted_neutronics_model.py b/paramak/parametric_neutronics/make_faceteted_neutronics_model.py
similarity index 66%
rename from examples/example_neutronics_simulations/make_faceteted_neutronics_model.py
rename to paramak/parametric_neutronics/make_faceteted_neutronics_model.py
index c587a46f0..04b16b421 100644
--- a/examples/example_neutronics_simulations/make_faceteted_neutronics_model.py
+++ b/paramak/parametric_neutronics/make_faceteted_neutronics_model.py
@@ -18,21 +18,30 @@
# With additional arguments to overwrite the defaults
# trelis -batch -nographics make_faceteted_neutronics_model.py "faceting_tolerance='1e-4'" "merge_tolerance='1e-4'"
-# An example manifest file would contain a list of dictionaries with entry having
-# stp_filename and material keywords. Here is an example manifest file with just
-# two entries.
+# An example manifest file would contain a list of dictionaries with entries
+# having stp_filename and material keywords. Here is an example manifest file
+# with just two entries.
# [
# {
# "material": "m1",
-# "stp_filename": "inboard_tf_coils.stp",
+# "stp_filename": "inboard_tf_coils.stp"
# },
# {
# "material": "m2",
-# "stp_filename": "center_column_shield.stp",
+# "stp_filename": "center_column_shield.stp"
# }
# ]
+# entries can also contain a "surface_reflectivity" key to indicate reflecting
+# surfaces. This will then be used to automatically tag the surfaces.
+
+# {
+# "material": "m3",
+# "stp_filename": "large_cake_slice.stp",
+# "surface_reflectivity": true
+# }
+
def find_number_of_volumes_in_each_step_file(input_locations, basefolder):
body_ids = ""
@@ -85,10 +94,28 @@ def find_number_of_volumes_in_each_step_file(input_locations, basefolder):
" ".join(
entry["volumes"]))
# cubit.cmd('volume in group '+str(starting_group_id)+' copy rotate 45 about z repeat 7')
+ if 'surface_reflectivity' in entry.keys():
+ entry['surface_reflectivity'] = find_all_surfaces_of_reflecting_wedge(new_vols_after_unite)
+ print("entry['surface_reflectivity']", entry['surface_reflectivity'])
cubit.cmd("separate body all")
return input_locations
+def find_all_surfaces_of_reflecting_wedge(new_vols):
+ surfaces_in_volume = cubit.parse_cubit_list("surface", " in volume "+' '.join(new_vols))
+ surface_info_dict = {}
+ for surface_id in surfaces_in_volume:
+ surface = cubit.surface(surface_id)
+ #area = surface.area()
+ vertex_in_surface = cubit.parse_cubit_list("vertex", " in surface " + str(surface_id))
+ if surface.is_planar() == True and len(vertex_in_surface) == 4:
+ surface_info_dict[surface_id] = {'reflector': True}
+ else:
+ surface_info_dict[surface_id] = {'reflector': False}
+ print('surface_info_dict', surface_info_dict)
+ return surface_info_dict
+
+
def byteify(input):
if isinstance(input, dict):
return {byteify(key): byteify(value)
@@ -101,6 +128,34 @@ def byteify(input):
return input
+def find_reflecting_surfaces_of_reflecting_wedge(geometry_details):
+ print('running find_reflecting_surfaces_of_reflecting_wedge')
+ wedge_volume = None
+ for entry in geometry_details:
+ print(entry)
+ print(entry.keys())
+ if 'surface_reflectivity' in entry.keys():
+ print('found surface_reflectivity')
+ surface_info_dict = entry['surface_reflectivity']
+ wedge_volume = ' '.join(entry['volumes'])
+ print('wedge_volume', wedge_volume)
+ surfaces_in_wedge_volume = cubit.parse_cubit_list("surface", " in volume "+str(wedge_volume))
+ print('surfaces_in_wedge_volume', surfaces_in_wedge_volume)
+ for surface_id in surface_info_dict.keys():
+ if surface_info_dict[surface_id]['reflector'] == True:
+ print(surface_id, 'surface originally reflecting but does it still exist')
+ if surface_id not in surfaces_in_wedge_volume:
+ del surface_info_dict[surface_id]
+ for surface_id in surfaces_in_wedge_volume:
+ if surface_id not in surface_info_dict.keys():
+ surface_info_dict[surface_id] = {'reflector': True}
+ cubit.cmd('group "boundary:Reflecting" add surf ' + str(surface_id))
+ cubit.cmd('surface ' + str(surface_id)+' visibility on')
+ entry['surface_reflectivity'] = surface_info_dict
+ return geometry_details, wedge_volume
+ return geometry_details, wedge_volume
+
+
def tag_geometry_with_mats(geometry_details):
for entry in geometry_details:
cubit.cmd(
@@ -163,4 +218,6 @@ def save_output_files():
imprint_and_merge_geometry()
+find_reflecting_surfaces_of_reflecting_wedge(geometry_details)
+
save_output_files()
diff --git a/paramak/parametric_neutronics/neutronics_model.py b/paramak/parametric_neutronics/neutronics_model.py
index def689647..c74a7210e 100644
--- a/paramak/parametric_neutronics/neutronics_model.py
+++ b/paramak/parametric_neutronics/neutronics_model.py
@@ -1,11 +1,13 @@
import json
import os
+import pathlib
+import shutil
import warnings
-from collections import defaultdict
from pathlib import Path
+from typing import List
-import matplotlib.pyplot as plt
+from paramak import get_neutronics_results_from_statepoint_file
try:
import openmc
@@ -24,12 +26,14 @@
class NeutronicsModel():
"""Creates a neuronics model of the provided shape geometry with assigned
materials, source and neutronics tallies. There are three methods
- available for producing the imprinted and merged h5m geometry (PyMoab, PPP
- or Trelis) and one method of producing non imprinted and non merged
- geometry (PyMoab). make_watertight is also used to seal the DAGMC geoemtry.
- If using the Trelis option you must have the
- make_faceteted_neutronics_model.py in the same directory as your Python
- script. Further details on imprinting and merging are available on the
+ available for producing the the DAGMC h5m file. The PyMoab option is able
+ to produce non imprinted and non merged geometry so is more suited to
+ individual components or reactors without touching surfaces. Trelis is
+ the only method currently able to produce imprinted and merged DAGMC h5m
+ geometry. PPP is a experimental route that has not been fully demonstrated
+ yet but is partly intergrated to test this promising new method.
+ make_watertight is also used to seal the DAGMC geoemtry produced by Trelis.
+ Further details on imprinting and merging are available on the
DAGMC homepage
https://svalinn.github.io/DAGMC/usersguide/trelis_basics.html
The Parallel-PreProcessor is an open-source tool available
@@ -37,7 +41,8 @@ class NeutronicsModel():
conjunction with the OCC_faceter
(https://github.com/makeclean/occ_faceter) to create imprinted and
merged geometry while Trelis (also known as Cubit) is available from
- the CoreForm website https://www.coreform.com/
+ the CoreForm website https://www.coreform.com/ version 17.1 is the version
+ of Trelis used when testing the Paramak code.
Arguments:
geometry (paramak.Shape, paramak.Rector): The geometry to convert to a
@@ -77,13 +82,15 @@ def __init__(
materials,
cell_tallies=None,
mesh_tally_2D=None,
- simulation_batches=100,
- simulation_particles_per_batch=10000,
- max_lost_particles=10,
- faceting_tolerance=1e-1,
- merge_tolerance=1e-4,
- mesh_2D_resolution=(400, 400),
- fusion_power=1e9 # convert from watts to activity source_activity
+ mesh_tally_3D=None,
+ simulation_batches: int = 100,
+ simulation_particles_per_batch: int = 10000,
+ max_lost_particles: int = 10,
+ faceting_tolerance: float = 1e-1,
+ merge_tolerance: float = 1e-4,
+ mesh_2D_resolution: float = (400, 400),
+ mesh_3D_resolution: float = (100, 100, 100),
+ fusion_power: float = 1e9 # convert from watts to activity source_activity
):
self.materials = materials
@@ -91,14 +98,20 @@ def __init__(
self.source = source
self.cell_tallies = cell_tallies
self.mesh_tally_2D = mesh_tally_2D
+ self.mesh_tally_3D = mesh_tally_3D
self.simulation_batches = simulation_batches
self.simulation_particles_per_batch = simulation_particles_per_batch
self.max_lost_particles = max_lost_particles
self.faceting_tolerance = faceting_tolerance
self.merge_tolerance = merge_tolerance
self.mesh_2D_resolution = mesh_2D_resolution
- self.model = None
+ self.mesh_3D_resolution = mesh_3D_resolution
self.fusion_power = fusion_power
+ self.model = None
+ self.results = None
+ self.tallies = None
+ self.output_filename = None
+ self.statepoint_filename = None
@property
def faceting_tolerance(self):
@@ -143,7 +156,7 @@ def cell_tallies(self, value):
raise TypeError(
"NeutronicsModelFromReactor.cell_tallies should be a\
list")
- output_options = ['TBR', 'heating', 'flux', 'fast flux', 'dose']
+ output_options = ['TBR', 'heating', 'flux', 'spectra', 'dose']
for entry in value:
if entry not in output_options:
raise ValueError(
@@ -175,6 +188,28 @@ def mesh_tally_2D(self, value):
output_options)
self._mesh_tally_2D = value
+ @property
+ def mesh_tally_3D(self):
+ return self._mesh_tally_3D
+
+ @mesh_tally_3D.setter
+ def mesh_tally_3D(self, value):
+ if value is not None:
+ if not isinstance(value, list):
+ raise TypeError(
+ "NeutronicsModelFromReactor.mesh_tally_3D should be a\
+ list")
+ output_options = ['tritium_production', 'heating', 'flux',
+ 'fast flux', 'dose']
+ for entry in value:
+ if entry not in output_options:
+ raise ValueError(
+ "NeutronicsModelFromReactor.mesh_tally_3D argument",
+ entry,
+ "not allowed, the following options are supported",
+ output_options)
+ self._mesh_tally_3D = value
+
@property
def materials(self):
return self._materials
@@ -217,7 +252,7 @@ def simulation_particles_per_batch(self, value):
should be an int")
self._simulation_particles_per_batch = value
- def create_material(self, material_tag, material_entry):
+ def create_material(self, material_tag: str, material_entry):
if isinstance(material_entry, str):
openmc_material = nmm.Material(
material_entry,
@@ -263,47 +298,61 @@ def create_materials(self):
return self.mats
- def create_neutronics_geometry(self, method=None):
+ def create_neutronics_geometry(self, method: str = None):
"""Produces a dagmc.h5m neutronics file compatable with DAGMC
simulations.
Arguments:
method: (str): The method to use when making the imprinted and
- merged geometry. Options are "ppp", "trelis", "pymoab".
- Defaults to None.
+ merged geometry. Options are "ppp", "trelis", "pymoab" and
+ None. Defaults to None.
"""
- os.system('rm dagmc_not_watertight.h5m')
- os.system('rm dagmc.h5m')
-
- if method not in ['ppp', 'trelis', 'pymoab']:
+ if method in ['ppp', 'trelis', 'pymoab']:
+ os.system('rm dagmc_not_watertight.h5m')
+ os.system('rm dagmc.h5m')
+ elif method is None and Path('dagmc.h5m').is_file():
+ print('Using previously made dagmc.h5m file')
+ else:
raise ValueError(
"the method using in create_neutronics_geometry \
- should be either ppp or trelis not", method)
+ should be either ppp, trelis, pymoab or None.", method)
if method == 'ppp':
- self.geometry.export_stp()
- self.geometry.export_neutronics_description()
- # as the installer connects to the system python not the conda
- # python this full path is needed for now
- if os.system(
- '/usr/bin/python3 /usr/bin/geomPipeline.py manifest.json') != 0:
- raise ValueError(
- "geomPipeline.py failed, check PPP is installed")
-
- # TODO allow tolerance to be user controlled
- if os.system(
- 'occ_faceter manifest_processed/manifest_processed.brep') != 0:
- raise ValueError(
- "occ_faceter failed, check occ_faceter is install and the \
- occ_faceter/bin folder is in the path directory")
- self._make_watertight()
+ raise NotImplementedError(
+ "PPP + OCC Faceter / Gmesh option is under development and not \
+ ready to be implemented. Further details on the repositories \
+ https://github.com/makeclean/occ_faceter/ \
+ https://github.com/ukaea/parallel-preprocessor ")
+
+ # TODO when the development is ready to test
+ # self.geometry.export_stp()
+ # self.geometry.export_neutronics_description()
+ # # as the installer connects to the system python not the conda
+ # # python this full path is needed for now
+ # if os.system(
+ # '/usr/bin/python3 /usr/bin/geomPipeline.py manifest.json') != 0:
+ # raise ValueError(
+ # "geomPipeline.py failed, check PPP is installed")
+
+ # # TODO allow tolerance to be user controlled
+ # if os.system(
+ # 'occ_faceter manifest_processed/manifest_processed.brep') != 0:
+ # raise ValueError(
+ # "occ_faceter failed, check occ_faceter is install and the \
+ # occ_faceter/bin folder is in the path directory")
+ # self._make_watertight()
elif method == 'trelis':
self.geometry.export_stp()
self.geometry.export_neutronics_description()
+ shutil.copy(
+ src=pathlib.Path(__file__).parent.absolute() /
+ 'make_faceteted_neutronics_model.py',
+ dst=pathlib.Path().absolute())
+
if not Path("make_faceteted_neutronics_model.py").is_file():
raise FileNotFoundError(
"The make_faceteted_neutronics_model.py was \
@@ -312,7 +361,8 @@ def create_neutronics_geometry(self, method=None):
str(self.faceting_tolerance) + "'\" \"merge_tolerance='" + str(self.merge_tolerance) + "'\"")
if not Path("dagmc_not_watertight.h5m").is_file():
- raise ValueError("The dagmc_not_watertight.h5m was not found \
+ raise FileNotFoundError(
+ "The dagmc_not_watertight.h5m was not found \
in the directory, the Trelis stage has failed")
self._make_watertight()
@@ -322,8 +372,7 @@ def create_neutronics_geometry(self, method=None):
filename='dagmc.h5m',
tolerance=self.faceting_tolerance
)
-
- print('neutronics model saved as dagmc.h5m')
+ return 'dagmc.h5m'
def _make_watertight(self):
"""Runs the DAGMC make_watertight script thatt seals the facetets of
@@ -339,7 +388,7 @@ def _make_watertight(self):
"make_watertight failed, check DAGMC is install and the \
DAGMC/bin folder is in the path directory")
- def create_neutronics_model(self, method=None):
+ def create_neutronics_model(self, method: str = None):
"""Uses OpenMC python API to make a neutronics model, including tallies
(cell_tallies and mesh_tally_2D), simulation settings (batches,
particles per batch).
@@ -371,137 +420,173 @@ def create_neutronics_model(self, method=None):
settings.max_lost_particles = self.max_lost_particles
# details about what neutrons interactions to keep track of (tally)
- tallies = openmc.Tallies()
+ self.tallies = openmc.Tallies()
+
+ if self.mesh_tally_3D is not None:
+ mesh_xyz = openmc.RegularMesh(mesh_id=1, name='3d_mesh')
+ mesh_xyz.dimension = self.mesh_3D_resolution
+ mesh_xyz.lower_left = [
+ -self.geometry.largest_dimension,
+ -self.geometry.largest_dimension,
+ -self.geometry.largest_dimension
+ ]
+
+ mesh_xyz.upper_right = [
+ self.geometry.largest_dimension,
+ self.geometry.largest_dimension,
+ self.geometry.largest_dimension
+ ]
+
+ for standard_tally in self.mesh_tally_3D:
+ if standard_tally == 'tritium_production':
+ score = '(n,Xt)' # where X is a wild card
+ prefix = 'tritium_production'
+ else:
+ score = standard_tally
+ prefix = standard_tally
+
+ mesh_filter = openmc.MeshFilter(mesh_xyz)
+ tally = openmc.Tally(name=prefix + '_on_3D_mesh')
+ tally.filters = [mesh_filter]
+ tally.scores = [score]
+ self.tallies.append(tally)
if self.mesh_tally_2D is not None:
# Create mesh which will be used for tally
- mesh_xz = openmc.RegularMesh()
+ mesh_xz = openmc.RegularMesh(mesh_id=2, name='2d_mesh_xz')
+
mesh_xz.dimension = [
self.mesh_2D_resolution[1],
1,
- self.mesh_2D_resolution[0]]
- mesh_xz.lower_left = [-self.geometry.largest_dimension, -
- 1, -self.geometry.largest_dimension]
+ self.mesh_2D_resolution[0]
+ ]
+
+ mesh_xz.lower_left = [
+ -self.geometry.largest_dimension,
+ -1,
+ -self.geometry.largest_dimension
+ ]
+
mesh_xz.upper_right = [
self.geometry.largest_dimension,
1,
- self.geometry.largest_dimension]
+ self.geometry.largest_dimension
+ ]
- mesh_xy = openmc.RegularMesh()
+ mesh_xy = openmc.RegularMesh(mesh_id=3, name='2d_mesh_xy')
mesh_xy.dimension = [
self.mesh_2D_resolution[1],
self.mesh_2D_resolution[0],
- 1]
- mesh_xy.lower_left = [-self.geometry.largest_dimension, -
- self.geometry.largest_dimension, -1]
+ 1
+ ]
+
+ mesh_xy.lower_left = [
+ -self.geometry.largest_dimension,
+ -self.geometry.largest_dimension,
+ -1
+ ]
+
mesh_xy.upper_right = [
self.geometry.largest_dimension,
self.geometry.largest_dimension,
- 1]
-
- mesh_yz = openmc.RegularMesh()
- mesh_yz.dimension = [1,
- self.mesh_2D_resolution[1],
- self.mesh_2D_resolution[0]]
- mesh_yz.lower_left = [-1, -self.geometry.largest_dimension, -
- self.geometry.largest_dimension]
- mesh_yz.upper_right = [1,
- self.geometry.largest_dimension,
- self.geometry.largest_dimension]
-
- if 'tritium_production' in self.mesh_tally_2D:
- mesh_filter = openmc.MeshFilter(mesh_xz)
- mesh_tally = openmc.Tally(
- name='tritium_production_on_2D_mesh_xz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['(n,Xt)']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_xy)
- mesh_tally = openmc.Tally(
- name='tritium_production_on_2D_mesh_xy')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['(n,Xt)']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_yz)
- mesh_tally = openmc.Tally(
- name='tritium_production_on_2D_mesh_yz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['(n,Xt)']
- tallies.append(mesh_tally)
-
- if 'heating' in self.mesh_tally_2D:
- mesh_filter = openmc.MeshFilter(mesh_xz)
- mesh_tally = openmc.Tally(name='heating_on_2D_mesh_xz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['heating']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_xy)
- mesh_tally = openmc.Tally(name='heating_on_2D_mesh_xy')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['heating']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_yz)
- mesh_tally = openmc.Tally(name='heating_on_2D_mesh_yz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['heating']
- tallies.append(mesh_tally)
-
- if 'flux' in self.mesh_tally_2D:
- mesh_filter = openmc.MeshFilter(mesh_xz)
- mesh_tally = openmc.Tally(name='flux_on_2D_mesh_xz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['flux']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_xy)
- mesh_tally = openmc.Tally(name='flux_on_2D_mesh_xy')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['flux']
- tallies.append(mesh_tally)
-
- mesh_filter = openmc.MeshFilter(mesh_yz)
- mesh_tally = openmc.Tally(name='flux_on_2D_mesh_yz')
- mesh_tally.filters = [mesh_filter]
- mesh_tally.scores = ['flux']
- tallies.append(mesh_tally)
+ 1
+ ]
+
+ mesh_yz = openmc.RegularMesh(mesh_id=4, name='2d_mesh_yz')
+ mesh_yz.dimension = [
+ 1,
+ self.mesh_2D_resolution[1],
+ self.mesh_2D_resolution[0]
+ ]
+
+ mesh_yz.lower_left = [
+ -1,
+ -self.geometry.largest_dimension,
+ -self.geometry.largest_dimension
+ ]
+
+ mesh_yz.upper_right = [
+ 1,
+ self.geometry.largest_dimension,
+ self.geometry.largest_dimension
+ ]
+
+ for standard_tally in self.mesh_tally_2D:
+ if standard_tally == 'tritium_production':
+ score = '(n,Xt)' # where X is a wild card
+ prefix = 'tritium_production'
+ else:
+ score = standard_tally
+ prefix = standard_tally
+
+ for mesh_filter, plane in zip(
+ [mesh_xz, mesh_xy, mesh_yz], ['xz', 'xy', 'yz']):
+ mesh_filter = openmc.MeshFilter(mesh_filter)
+ tally = openmc.Tally(name=prefix + '_on_2D_mesh_' + plane)
+ tally.filters = [mesh_filter]
+ tally.scores = [score]
+ self.tallies.append(tally)
if self.cell_tallies is not None:
- if 'TBR' in self.cell_tallies:
- blanket_mat = self.openmc_materials['blanket_mat']
- material_filter = openmc.MaterialFilter(blanket_mat)
- tally = openmc.Tally(name="TBR")
- tally.filters = [material_filter]
- tally.scores = ["(n,Xt)"] # where X is a wild card
- tallies.append(tally)
-
- if 'heating' in self.cell_tallies:
- for key, value in self.openmc_materials.items():
- if key != 'DT_plasma':
- material_filter = openmc.MaterialFilter(value)
- tally = openmc.Tally(name=key + "_heating")
- tally.filters = [material_filter]
- tally.scores = ["heating"]
- tallies.append(tally)
-
- if 'flux' in self.cell_tallies:
- for key, value in self.openmc_materials.items():
- if key != 'DT_plasma':
- material_filter = openmc.MaterialFilter(value)
- tally = openmc.Tally(name=key + "_flux")
- tally.filters = [material_filter]
- tally.scores = ["flux"]
- tallies.append(tally)
+ for standard_tally in self.cell_tallies:
+ if standard_tally == 'TBR':
+ score = '(n,Xt)' # where X is a wild card
+ sufix = 'TBR'
+ tally = openmc.Tally(name='TBR')
+ tally.scores = [score]
+ self.tallies.append(tally)
+ self._add_tally_for_every_material(sufix, score)
+
+ elif standard_tally == 'spectra':
+ neutron_particle_filter = openmc.ParticleFilter([
+ 'neutron'])
+ photon_particle_filter = openmc.ParticleFilter(['photon'])
+ energy_bins = openmc.mgxs.GROUP_STRUCTURES['CCFE-709']
+ energy_filter = openmc.EnergyFilter(energy_bins)
+
+ self._add_tally_for_every_material(
+ 'neutron_spectra',
+ 'flux',
+ [neutron_particle_filter, energy_filter]
+ )
+
+ self._add_tally_for_every_material(
+ 'photon_spectra',
+ 'flux',
+ [photon_particle_filter, energy_filter]
+ )
+ else:
+ score = standard_tally
+ sufix = standard_tally
+ self._add_tally_for_every_material(sufix, score)
# make the model from gemonetry, materials, settings and tallies
- self.model = openmc.model.Model(geom, self.mats, settings, tallies)
+ self.model = openmc.model.Model(
+ geom, self.mats, settings, self.tallies)
+
+ def _add_tally_for_every_material(self, sufix: str, score: str,
+ additional_filters: List = None) -> None:
+ """Adds a tally to self.tallies for every material.
- def simulate(self, verbose=True, method=None):
+ Arguments:
+ sufix: the string to append to the end of the tally name to help
+ identify the tally later.
+ score: the openmc.Tally().scores value that contribute to the tally
+ """
+ if additional_filters is None:
+ additional_filters = []
+ for key, value in self.openmc_materials.items():
+ if key != 'DT_plasma':
+ material_filter = openmc.MaterialFilter(value)
+ tally = openmc.Tally(name=key + '_' + sufix)
+ tally.filters = [material_filter] + additional_filters
+ tally.scores = [score]
+ self.tallies.append(tally)
+
+ def simulate(self, verbose: bool = True, method: str = None,
+ cell_tally_results_filename: str = 'results.json'):
"""Run the OpenMC simulation. Deletes exisiting simulation output
(summary.h5) if files exists.
@@ -522,98 +607,21 @@ def simulate(self, verbose=True, method=None):
# Deletes summary.h5m if it already exists.
# This avoids permission problems when trying to overwrite the file
os.system('rm summary.h5')
+ os.system('rm statepoint.' + str(self.simulation_batches) + '.h5')
- self.output_filename = self.model.run(output=verbose)
- self.results = self.get_results()
-
- return self.output_filename
-
- def get_results(self):
- """Reads the output file from the neutronics simulation
- and prints the TBR tally result to screen
-
- Returns:
- dict: a dictionary of the simulation results
- """
-
- # open the results file
- sp = openmc.StatePoint(self.output_filename)
-
- results = defaultdict(dict)
-
- # access the tallies
- for tally in sp.tallies.values():
-
- if tally.name == 'TBR':
-
- df = tally.get_pandas_dataframe()
- tally_result = df["mean"].sum()
- tally_std_dev = df['std. dev.'].sum()
- results[tally.name] = {
- 'result': tally_result,
- 'std. dev.': tally_std_dev,
- }
-
- if tally.name.endswith('heating'):
-
- df = tally.get_pandas_dataframe()
- tally_result = df["mean"].sum()
- tally_std_dev = df['std. dev.'].sum()
- results[tally.name]['MeV per source particle'] = {
- 'result': tally_result / 1e6,
- 'std. dev.': tally_std_dev / 1e6,
- }
- results[tally.name]['Watts'] = {
- 'result': tally_result * 1.602176487e-19 * (self.fusion_power / ((17.58 * 1e6) / 6.2415090744e18)),
- 'std. dev.': tally_std_dev * 1.602176487e-19 * (self.fusion_power / ((17.58 * 1e6) / 6.2415090744e18)),
- }
-
- if tally.name.endswith('flux'):
-
- df = tally.get_pandas_dataframe()
- tally_result = df["mean"].sum()
- tally_std_dev = df['std. dev.'].sum()
- results[tally.name]['Flux per source particle'] = {
- 'result': tally_result,
- 'std. dev.': tally_std_dev,
- }
-
- if tally.name.startswith('tritium_production_on_2D_mesh'):
-
- my_tally = sp.get_tally(name=tally.name)
- my_slice = my_tally.get_slice(scores=['(n,Xt)'])
-
- my_slice.mean.shape = self.mesh_2D_resolution
-
- fig = plt.subplot()
- fig.imshow(my_slice.mean).get_figure().savefig(
- 'tritium_production_on_2D_mesh' + tally.name[-3:], dpi=300)
- fig.clear()
-
- if tally.name.startswith('heating_on_2D_mesh'):
-
- my_tally = sp.get_tally(name=tally.name)
- my_slice = my_tally.get_slice(scores=['heating'])
-
- my_slice.mean.shape = self.mesh_2D_resolution
-
- fig = plt.subplot()
- fig.imshow(my_slice.mean).get_figure().savefig(
- 'heating_on_2D_mesh' + tally.name[-3:], dpi=300)
- fig.clear()
-
- if tally.name.startswith('flux_on_2D_mesh'):
-
- my_tally = sp.get_tally(name=tally.name)
- my_slice = my_tally.get_slice(scores=['flux'])
-
- my_slice.mean.shape = self.mesh_2D_resolution
+ # this removes any old file from previous simulations
+ os.system('rm geometry.xml')
+ os.system('rm materials.xml')
+ os.system('rm settings.xml')
+ os.system('rm tallies.xml')
- fig = plt.subplot()
- fig.imshow(my_slice.mean).get_figure().savefig(
- 'flux_on_2D_mesh' + tally.name[-3:], dpi=300)
- fig.clear()
+ self.statepoint_filename = self.model.run(output=verbose)
+ self.results = get_neutronics_results_from_statepoint_file(
+ statepoint_filename=self.statepoint_filename,
+ fusion_power=self.fusion_power
+ )
- self.results = json.dumps(results, indent=4, sort_keys=True)
+ with open(cell_tally_results_filename, 'w') as outfile:
+ json.dump(self.results, outfile, indent=4, sort_keys=True)
- return results
+ return self.statepoint_filename
diff --git a/paramak/parametric_reactors/center_column_study_reactor.py b/paramak/parametric_reactors/center_column_study_reactor.py
index b1a665375..44da9f067 100644
--- a/paramak/parametric_reactors/center_column_study_reactor.py
+++ b/paramak/parametric_reactors/center_column_study_reactor.py
@@ -24,6 +24,8 @@ class CenterColumnStudyReactor(paramak.Reactor):
thickness of the center column shield at the upper point (cm)
inboard_firstwall_radial_thickness (float): the radial thickness
of the inboard firstwall (cm)
+ divertor_radial_thickness (float): the radial thickness of the divertor
+ (cm)
inner_plasma_gap_radial_thickness (float): the radial thickness of
the inboard gap between the plasma and the center column shield
(cm)
diff --git a/paramak/parametric_shapes/sweep_circle_shape.py b/paramak/parametric_shapes/sweep_circle_shape.py
index d80f6245e..64a2c2766 100644
--- a/paramak/parametric_shapes/sweep_circle_shape.py
+++ b/paramak/parametric_shapes/sweep_circle_shape.py
@@ -96,31 +96,31 @@ def create_solid(self):
factor *= -1
if self.force_cross_section:
- wire = cq.Workplane(self.workplane).moveTo(0, 0)
+ wire = cq.Workplane(self.workplane).center(0, 0)
for point in self.path_points[:-1]:
wire = wire.workplane(offset=point[1] * factor).\
- moveTo(point[0], 0).\
+ center(point[0], 0).\
circle(self.radius).\
- moveTo(0, 0).\
+ center(-point[0], 0).\
workplane(offset=-point[1] * factor)
self.wire = wire
- solid = wire.workplane(offset=self.path_points[-1][1] * factor).moveTo(
+ solid = wire.workplane(offset=self.path_points[-1][1] * factor).center(
self.path_points[-1][0], 0).circle(self.radius).sweep(path, multisection=True)
- if not self.force_cross_section:
+ else:
wire = (
cq.Workplane(self.workplane)
.workplane(offset=self.path_points[0][1] * factor)
- .moveTo(self.path_points[0][0], 0)
+ .center(self.path_points[0][0], 0)
.workplane()
.circle(self.radius)
- .moveTo(-self.path_points[0][0], 0)
+ .center(-self.path_points[0][0], 0)
.workplane(offset=-self.path_points[0][1] * factor)
.workplane(offset=self.path_points[-1][1] * factor)
- .moveTo(self.path_points[-1][0], 0)
+ .center(self.path_points[-1][0], 0)
.workplane()
.circle(self.radius)
)
diff --git a/paramak/reactor.py b/paramak/reactor.py
index f70327b5c..6e61d5339 100644
--- a/paramak/reactor.py
+++ b/paramak/reactor.py
@@ -24,7 +24,7 @@ class Reactor:
shapes_and_components (list): list of paramak.Shape
"""
- def __init__(self, shapes_and_components):
+ def __init__(self, shapes_and_components: list):
self.material_tags = []
self.stp_filenames = []
@@ -133,7 +133,7 @@ def graveyard_offset(self, value):
if value is None:
self._graveyard_offset = None
elif not isinstance(value, (float, int)):
- raise ValueError("graveyard_offset must be a number")
+ raise TypeError("graveyard_offset must be a number")
elif value < 0:
raise ValueError("graveyard_offset must be positive")
self._graveyard_offset = value
@@ -167,8 +167,8 @@ def solid(self):
def solid(self, value):
self._solid = value
- def neutronics_description(self, include_plasma=False,
- include_graveyard=True
+ def neutronics_description(self, include_plasma: bool = False,
+ include_graveyard: bool = True
):
"""A description of the reactor containing material tags, stp filenames,
and tet mesh instructions. This is used for neutronics simulations which
@@ -211,7 +211,7 @@ def neutronics_description(self, include_plasma=False,
# This add the neutronics description for the graveyard which is unique
# as it is automatically calculated instead of being added by the user.
# Also the graveyard must have 'Graveyard' as the material name
- if include_graveyard is True:
+ if include_graveyard:
self.make_graveyard()
neutronics_description.append(
self.graveyard.neutronics_description())
@@ -220,9 +220,9 @@ def neutronics_description(self, include_plasma=False,
def export_neutronics_description(
self,
- filename="manifest.json",
- include_plasma=False,
- include_graveyard=True):
+ filename: str = "manifest.json",
+ include_plasma: bool = False,
+ include_graveyard: bool = True) -> str:
"""
Saves Reactor.neutronics_description to a json file. The resulting json
file contains a list of dictionaries. Each dictionary entry comprises
@@ -269,8 +269,11 @@ def export_neutronics_description(
return str(path_filename)
- def export_stp(self, output_folder="", graveyard_offset=100,
- mode='solid'):
+ def export_stp(
+ self,
+ output_folder: str = "",
+ graveyard_offset: float = 100,
+ mode: str = 'solid') -> list:
"""Writes stp files (CAD geometry) for each Shape object in the reactor
and the graveyard.
@@ -318,7 +321,8 @@ def export_stp(self, output_folder="", graveyard_offset=100,
return filenames
- def export_stl(self, output_folder="", tolerance=0.001):
+ def export_stl(self, output_folder: str = "",
+ tolerance: float = 0.001) -> list:
"""Writes stl files (CAD geometry) for each Shape object in the reactor
:param output_folder: the folder for saving the stp files to
@@ -369,10 +373,10 @@ def export_stl(self, output_folder="", tolerance=0.001):
def export_h5m(
self,
- filename='dagmc.h5m',
- skip_graveyard=False,
- tolerance=0.001,
- graveyard_offset=100):
+ filename: str = 'dagmc.h5m',
+ skip_graveyard: bool = False,
+ tolerance: float = 0.001,
+ graveyard_offset: float = 100) -> str:
"""Converts stl files into DAGMC compatible h5m file using PyMOAB. The
DAGMC file produced has not been imprinted and merged unlike the other
supported method which uses Trelis to produce an imprinted and merged
@@ -440,9 +444,9 @@ def export_h5m(
moab_core.write_file(str(path_filename))
- return filename
+ return str(path_filename)
- def export_physical_groups(self, output_folder=""):
+ def export_physical_groups(self, output_folder: str = "") -> list:
"""Exports several JSON files containing a look up table which is
useful for identifying faces and volumes. The output file names are
generated from .stp_filename properties.
@@ -470,12 +474,13 @@ def export_physical_groups(self, output_folder=""):
Path(output_folder) / Path(entry.stp_filename))
return filenames
- def export_svg(self, filename):
+ def export_svg(self, filename: str = 'reactor.svg') -> str:
"""Exports an svg file for the Reactor.solid. If the filename provided
doesn't end with .svg it will be added.
Args:
- filename (str): the filename of the svg file to be exported
+ filename (str): the filename of the svg file to be exported.
+ Defaults to "reactor.svg".
"""
path_filename = Path(filename)
@@ -489,10 +494,12 @@ def export_svg(self, filename):
exporters.exportShape(self.solid, "SVG", out_file)
print("Saved file as ", path_filename)
+ return str(path_filename)
+
def export_graveyard(
self,
- graveyard_offset=100,
- filename="Graveyard.stp"):
+ graveyard_offset: float = 100,
+ filename: str = "Graveyard.stp"):
"""Writes an stp file (CAD geometry) for the reactor graveyard. This
is needed for DAGMC simulations. This method also calls
Reactor.make_graveyard with the offset.
@@ -508,11 +515,11 @@ def export_graveyard(
"""
self.make_graveyard(graveyard_offset=graveyard_offset)
- self.graveyard.export_stp(Path(filename))
+ new_filename = self.graveyard.export_stp(Path(filename))
- return filename
+ return new_filename
- def make_graveyard(self, graveyard_offset=100):
+ def make_graveyard(self, graveyard_offset: float = 100):
"""Creates a graveyard volume (bounding box) that encapsulates all
volumes. This is required by DAGMC when performing neutronics
simulations.
@@ -548,10 +555,10 @@ def make_graveyard(self, graveyard_offset=100):
def export_2d_image(
self,
filename="2d_slice.png",
- xmin=0.0,
- xmax=900.0,
- ymin=-600.0,
- ymax=600.0):
+ xmin: float = 0.0,
+ xmax: float = 900.0,
+ ymin: float = -600.0,
+ ymax: float = 600.0) -> str:
"""Creates a 2D slice image (png) of the reactor.
Args:
diff --git a/paramak/shape.py b/paramak/shape.py
index dc0c3e949..2711f8c5f 100644
--- a/paramak/shape.py
+++ b/paramak/shape.py
@@ -3,10 +3,7 @@
import numbers
import warnings
from collections import Iterable
-from os import fdopen, remove
from pathlib import Path
-from shutil import copymode, move
-from tempfile import mkstemp
import cadquery as cq
import matplotlib.pyplot as plt
@@ -18,7 +15,8 @@
import paramak
from paramak.neutronics_utils import (add_stl_to_moab_core,
define_moab_core_and_tags)
-from paramak.utils import cut_solid, get_hash, intersect_solid, union_solid
+from paramak.utils import (cut_solid, get_hash, intersect_solid, union_solid,
+ _replace)
class Shape:
@@ -57,6 +55,9 @@ class Shape:
floats. Defaults to None.
tet_mesh (str, optional): If not None, a tet mesh flag will be added to
the neutronics description output. Defaults to None.
+ surface_reflectivity (Boolean, optional): If True, a
+ surface_reflectivity flag will be added to the neutronics
+ description output. Defaults to None.
physical_groups (dict, optional): contains information on physical
groups (volumes and surfaces). Defaults to None.
cut (paramak.shape or list, optional): If set, the current solid will
@@ -72,17 +73,18 @@ class Shape:
def __init__(
self,
- points=None,
+ points: list = None,
connection_type="mixed",
name=None,
color=(0.5, 0.5, 0.5),
- material_tag=None,
- stp_filename=None,
- stl_filename=None,
+ material_tag: str = None,
+ stp_filename: str = None,
+ stl_filename: str = None,
azimuth_placement_angle=0.0,
- workplane="XZ",
+ workplane: str = "XZ",
rotation_axis=None,
- tet_mesh=None,
+ tet_mesh: str = None,
+ surface_reflectivity: bool = False,
physical_groups=None,
cut=None,
intersect=None,
@@ -107,6 +109,7 @@ def __init__(
# neutronics specific properties
self.material_tag = material_tag
self.tet_mesh = tet_mesh
+ self.surface_reflectivity = surface_reflectivity
self.physical_groups = physical_groups
@@ -185,7 +188,7 @@ def largest_dimension(self):
"""Calculates a bounding box for the Shape and returns the largest
absolute value of the largest dimension of the bounding box"""
largest_dimension = 0
- if isinstance(self.solid, cq.Compound):
+ if isinstance(self.solid, (cq.Compound, cq.occ_impl.shapes.Solid)):
for solid in self.solid.Solids():
largest_dimension = max(
abs(self.solid.BoundingBox().xmax),
@@ -577,15 +580,12 @@ def create_solid(self):
if self.workplane in ["XZ", "YX", "ZY"]:
factor *= -1
- solid = cq.Workplane(self.workplane).moveTo(0, 0)
+ solid = cq.Workplane(self.workplane).center(0, 0)
if self.force_cross_section:
for point in self.path_points[:-1]:
- solid = solid.workplane(
- offset=point[1] *
- factor).moveTo(
- point[0],
- 0).workplane()
+ solid = solid.workplane(offset=point[1] * factor).\
+ center(point[0], 0).workplane()
for entry in instructions:
if list(entry.keys())[0] == "spline":
solid = solid.spline(
@@ -594,16 +594,16 @@ def create_solid(self):
solid = solid.polyline(list(entry.values())[0])
if list(entry.keys())[0] == "circle":
p0, p1, p2 = list(entry.values())[0][:3]
- solid = solid.moveTo(
- p0[0], p0[1]).threePointArc(
- p1, p2)
- solid = solid.close().moveTo(
- 0, 0).moveTo(-point[0], 0).workplane(offset=-point[1] * factor)
+ solid = solid.moveTo(p0[0], p0[1]).\
+ threePointArc(p1, p2)
+ solid = solid.close()
+ solid = solid.center(-point[0], 0).\
+ workplane(offset=-point[1] * factor)
elif self.force_cross_section == False:
solid = solid.workplane(
offset=self.path_points[0][1] *
- factor).moveTo(
+ factor).center(
self.path_points[0][0],
0).workplane()
for entry in instructions:
@@ -620,12 +620,12 @@ def create_solid(self):
p0[0], p0[1]).threePointArc(
p1, p2)
- solid = solid.close().moveTo(0,
- 0).moveTo(-self.path_points[0][0],
- 0).workplane(offset=-self.path_points[0][1] * factor)
+ solid = solid.close().center(0, 0).\
+ center(-self.path_points[0][0], 0).\
+ workplane(offset=-self.path_points[0][1] * factor)
- solid = solid.workplane(
- offset=self.path_points[-1][1] * factor).moveTo(self.path_points[-1][0], 0).workplane()
+ solid = solid.workplane(offset=self.path_points[-1][1] * factor).\
+ center(self.path_points[-1][0], 0).workplane()
else:
# for rotate and extrude shapes
@@ -732,7 +732,7 @@ def create_limits(self):
return self.x_min, self.x_max, self.z_min, self.z_max
- def export_stl(self, filename, tolerance=0.001):
+ def export_stl(self, filename: str, tolerance: float = 0.001) -> str:
"""Exports an stl file for the Shape.solid. If the provided filename
doesn't end with .stl it will be added
@@ -754,7 +754,11 @@ def export_stl(self, filename, tolerance=0.001):
return str(path_filename)
- def export_stp(self, filename=None, units='mm', mode='solid'):
+ def export_stp(
+ self,
+ filename=None,
+ units='mm',
+ mode: str = 'solid') -> str:
"""Exports an stp file for the Shape.solid. If the filename provided
doesn't end with .stp or .step then .stp will be added. If a
filename is not provided and the shape's stp_filename property is
@@ -791,7 +795,7 @@ def export_stp(self, filename=None, units='mm', mode='solid'):
only accepts 'solid' or 'wire'", self)
if units == 'cm':
- self._replace(
+ _replace(
path_filename,
'SI_UNIT(.MILLI.,.METRE.)',
'SI_UNIT(.CENTI.,.METRE.)')
@@ -800,7 +804,7 @@ def export_stp(self, filename=None, units='mm', mode='solid'):
return str(path_filename)
- def export_physical_groups(self, filename):
+ def export_physical_groups(self, filename: str) -> str:
"""Exports a JSON file containing a look up table which is useful for
identifying faces and volumes. If filename provided doesn't end with
.json then .json will be added.
@@ -828,9 +832,9 @@ def export_physical_groups(self, filename):
)
)
- return filename
+ return str(path_filename)
- def export_svg(self, filename):
+ def export_svg(self, filename: str) -> str:
"""Exports an svg file for the Shape.solid. If the provided filename
doesn't end with .svg it will be added.
@@ -851,7 +855,7 @@ def export_svg(self, filename):
return str(path_filename)
- def export_html(self, filename):
+ def export_html(self, filename: str):
"""Creates a html graph representation of the points and connections
for the Shape object. Shapes are colored by their .color property.
Shapes are also labelled by their .name. If filename provided doesn't
@@ -958,7 +962,8 @@ def _trace(self):
return trace
def export_2d_image(
- self, filename, xmin=0., xmax=900., ymin=-600., ymax=600.):
+ self, filename: str, xmin: float = 0., xmax: float = 900.,
+ ymin: float = -600., ymax: float = 600.):
"""Exports a 2d image (png) of the reactor. Components are colored by
their Shape.color property. If filename provided doesn't end with .png
then .png will be added.
@@ -1030,7 +1035,7 @@ def _create_patch(self):
self.patch = patch
return patch
- def neutronics_description(self):
+ def neutronics_description(self) -> dict:
"""Returns a neutronics description of the Shape object. This is needed
for the use with automated neutronics model methods which require
linkage between the stp files and materials. If tet meshing of the
@@ -1051,6 +1056,9 @@ def neutronics_description(self):
if self.tet_mesh is not None:
neutronics_description["tet_mesh"] = self.tet_mesh
+ if self.surface_reflectivity is True:
+ neutronics_description["surface_reflectivity"] = self.surface_reflectivity
+
if self.stl_filename is not None:
neutronics_description["stl_filename"] = self.stl_filename
@@ -1081,34 +1089,7 @@ def perform_boolean_operations(self, solid, **kwargs):
return solid
- def _replace(self, filename, pattern, subst):
- """Opens a file and replaces occurances of a particular string
- (pattern)with a new string (subst) and overwrites the file.
- Used internally within the paramak to ensure .STP files are
- in units of cm not the default mm.
- Args:
- filename (str): the filename of the file to edit
- pattern (str): the string that should be removed
- subst (str): the string that should be used in the place of the
- pattern string
- """
- # Create temp file
- file_handle, abs_path = mkstemp()
- with fdopen(file_handle, 'w') as new_file:
- with open(filename) as old_file:
- for line in old_file:
- new_file.write(line.replace(pattern, subst))
-
- # Copy the file permissions from the old file to the new file
- copymode(filename, abs_path)
-
- # Remove original file
- remove(filename)
-
- # Move new file
- move(abs_path, filename)
-
- def make_graveyard(self, graveyard_offset=100):
+ def make_graveyard(self, graveyard_offset: int = 100):
"""Creates a graveyard volume (bounding box) that encapsulates all
volumes. This is required by DAGMC when performing neutronics
simulations.
@@ -1142,10 +1123,10 @@ def make_graveyard(self, graveyard_offset=100):
def export_h5m(
self,
- filename='dagmc.h5m',
- skip_graveyard=False,
- tolerance=0.001,
- graveyard_offset=100):
+ filename: str = 'dagmc.h5m',
+ skip_graveyard: bool = False,
+ tolerance: float = 0.001,
+ graveyard_offset: float = 100) -> str:
"""Converts stl files into DAGMC compatible h5m file using PyMOAB. The
DAGMC file produced has not been imprinted and merged unlike the other
supported method which uses Trelis to produce an imprinted and merged
@@ -1208,12 +1189,12 @@ def export_h5m(
moab_core.write_file(str(path_filename))
- return filename
+ return str(path_filename)
def export_graveyard(
self,
- graveyard_offset=100,
- filename="Graveyard.stp"):
+ graveyard_offset: float = 100,
+ filename: str = "Graveyard.stp") -> str:
"""Writes an stp file (CAD geometry) for the reactor graveyard. This
is needed for DAGMC simulations. This method also calls
Reactor.make_graveyard with the offset.
@@ -1229,6 +1210,6 @@ def export_graveyard(
"""
self.make_graveyard(graveyard_offset=graveyard_offset)
- self.graveyard.export_stp(Path(filename))
+ new_filename = self.graveyard.export_stp(Path(filename))
- return filename
+ return new_filename
diff --git a/paramak/utils.py b/paramak/utils.py
index 4ba232328..4c34d1cb3 100644
--- a/paramak/utils.py
+++ b/paramak/utils.py
@@ -2,6 +2,10 @@
import math
from collections import Iterable
from hashlib import blake2b
+from os import fdopen, remove
+from shutil import copymode, move
+from tempfile import mkstemp
+from typing import Tuple, List
import cadquery as cq
import numpy as np
@@ -9,16 +13,17 @@
import paramak
-def coefficients_of_line_from_points(point_a, point_b):
+def coefficients_of_line_from_points(
+ point_a: Tuple[float, float], point_b: Tuple[float, float]) -> Tuple[float, float]:
"""Computes the m and c coefficients of the equation (y=mx+c) for
a straight line from two points.
Args:
- point_a (float, float): point 1 coordinates
- point_b (float, float): point 2 coordinates
+ point_a: point 1 coordinates
+ point_b: point 2 coordinates
Returns:
- (float, float): m coefficient and c coefficient
+ m coefficient and c coefficient
"""
points = [point_a, point_b]
@@ -49,7 +54,7 @@ def cut_solid(solid, cutter):
return solid
-def diff_between_angles(angle_a, angle_b):
+def diff_between_angles(angle_a: float, angle_b: float) -> float:
"""Calculates the difference between two angles angle_a and angle_b
Args:
@@ -66,7 +71,8 @@ def diff_between_angles(angle_a, angle_b):
return delta_mod
-def distance_between_two_points(point_a, point_b):
+def distance_between_two_points(point_a: Tuple[float, float],
+ point_b: Tuple[float, float]) -> float:
"""Computes the distance between two points.
Args:
@@ -83,7 +89,8 @@ def distance_between_two_points(point_a, point_b):
return np.linalg.norm(u_vec)
-def extend(point_a, point_b, L):
+def extend(point_a: Tuple[float, float], point_b: Tuple[float, float],
+ L: float) -> Tuple[float, float]:
"""Creates a point C in (ab) direction so that \\|aC\\| = L
Args:
@@ -104,7 +111,9 @@ def extend(point_a, point_b, L):
return xc, yc
-def find_center_point_of_circle(point_a, point_b, point3):
+def find_center_point_of_circle(point_a: Tuple[float, float],
+ point_b: Tuple[float, float],
+ point3: Tuple[float, float]) -> Tuple[Tuple[float, float], float]:
"""
Calculates the center and the radius of a circle
passing through 3 points.
@@ -156,7 +165,8 @@ def intersect_solid(solid, intersecter):
return solid
-def rotate(origin, point, angle):
+def rotate(origin: Tuple[float, float], point: Tuple[float, float],
+ angle: float):
"""
Rotate a point counterclockwise by a given angle around a given origin.
The angle should be given in radians.
@@ -208,7 +218,8 @@ def calculate_wedge_cut(self):
return cutting_wedge
-def add_thickness(x, y, thickness, dy_dx=None):
+def add_thickness(x: List[float], y: List[float], thickness: float,
+ dy_dx: List[float] = None):
"""Computes outer curve points based on thickness
Args:
@@ -256,7 +267,7 @@ def add_thickness(x, y, thickness, dy_dx=None):
return x_outer, y_outer
-def get_hash(shape, ignored_keys=[]):
+def get_hash(shape, ignored_keys: List) -> str:
"""Computes a unique hash vaue for the shape.
Args:
@@ -271,15 +282,44 @@ def get_hash(shape, ignored_keys=[]):
hash_object = blake2b()
shape_dict = dict(shape.__dict__)
- for key in ignored_keys:
- if key in shape_dict.keys():
- shape_dict[key] = None
+ if ignored_keys is not None:
+ for key in ignored_keys:
+ if key in shape_dict.keys():
+ shape_dict[key] = None
hash_object.update(str(list(shape_dict.values())).encode("utf-8"))
value = hash_object.hexdigest()
return value
+def _replace(filename: str, pattern: str, subst: str) -> None:
+ """Opens a file and replaces occurances of a particular string
+ (pattern)with a new string (subst) and overwrites the file.
+ Used internally within the paramak to ensure .STP files are
+ in units of cm not the default mm.
+ Args:
+ filename (str): the filename of the file to edit
+ pattern (str): the string that should be removed
+ subst (str): the string that should be used in the place of the
+ pattern string
+ """
+ # Create temp file
+ file_handle, abs_path = mkstemp()
+ with fdopen(file_handle, 'w') as new_file:
+ with open(filename) as old_file:
+ for line in old_file:
+ new_file.write(line.replace(pattern, subst))
+
+ # Copy the file permissions from the old file to the new file
+ copymode(filename, abs_path)
+
+ # Remove original file
+ remove(filename)
+
+ # Move new file
+ move(abs_path, filename)
+
+
class FaceAreaSelector(cq.Selector):
"""A custom CadQuery selector the selects faces based on their area with a
tolerance. The following useage example will fillet the faces of an extrude
@@ -292,9 +332,9 @@ class FaceAreaSelector(cq.Selector):
(+/-) while still being selected by the custom selector.
"""
- def __init__(self, area, tol=0.1):
+ def __init__(self, area, tolerance=0.1):
self.area = area
- self.tol = tol
+ self.tolerance = tolerance
def filter(self, objectList):
"""Loops through all the faces in the object checking if the face
@@ -313,7 +353,7 @@ def filter(self, objectList):
face_area = obj.Area()
# Only return faces that meet the requirements
- if face_area > self.area - self.tol and face_area < self.area + self.tol:
+ if face_area > self.area - self.tolerance and face_area < self.area + self.tolerance:
new_obj_list.append(obj)
return new_obj_list
@@ -332,9 +372,9 @@ class EdgeLengthSelector(cq.Selector):
"""
- def __init__(self, length, tol=0.1):
+ def __init__(self, length: float, tolerance: float = 0.1):
self.length = length
- self.tol = tol
+ self.tolerance = tolerance
def filter(self, objectList):
"""Loops through all the edges in the object checking if the edge
@@ -355,7 +395,7 @@ def filter(self, objectList):
edge_len = obj.Length()
# Only return edges that meet our requirements
- if edge_len > self.length - self.tol and edge_len < self.length + self.tol:
+ if edge_len > self.length - self.tolerance and edge_len < self.length + self.tolerance:
new_obj_list.append(obj)
print('length(new_obj_list)', len(new_obj_list))
diff --git a/requirements.txt b/requirements.txt
index 9302ecce1..7af6b571f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,5 +13,6 @@ pillow
# cython # needed for export_h5m with pymoab
# Additional packages needed for neutronics simulations
+# vtk
# neutronics_material_maker
# parametric_plasma_source
diff --git a/setup.py b/setup.py
index 973c3e335..f45c1332c 100644
--- a/setup.py
+++ b/setup.py
@@ -34,6 +34,7 @@
],
extras_require={
"neutronics": [
+ "vtk",
"neutronics_material_maker",
"parametric_plasma_source",
]})
diff --git a/tests/test_Reactor.py b/tests/test_Reactor.py
index 0f1335f72..7701f5f5a 100644
--- a/tests/test_Reactor.py
+++ b/tests/test_Reactor.py
@@ -747,15 +747,15 @@ def test_graveyard_error(self):
def str_graveyard_offset():
test_reactor.graveyard_offset = 'coucou'
+ self.assertRaises(TypeError, str_graveyard_offset)
def negative_graveyard_offset():
test_reactor.graveyard_offset = -2
+ self.assertRaises(ValueError, negative_graveyard_offset)
def list_graveyard_offset():
test_reactor.graveyard_offset = [1.2]
- self.assertRaises(ValueError, str_graveyard_offset)
- self.assertRaises(ValueError, negative_graveyard_offset)
- self.assertRaises(ValueError, list_graveyard_offset)
+ self.assertRaises(TypeError, list_graveyard_offset)
def test_compound_in_shapes(self):
shape1 = paramak.RotateStraightShape(
diff --git a/tests/test_parametric_components/test_CenterColumnShieldCylinder.py b/tests/test_parametric_components/test_CenterColumnShieldCylinder.py
index 51d323dd4..ea33f9482 100644
--- a/tests/test_parametric_components/test_CenterColumnShieldCylinder.py
+++ b/tests/test_parametric_components/test_CenterColumnShieldCylinder.py
@@ -106,16 +106,14 @@ def test_center_column_shield_cylinder_invalid_parameters_errors(self):
as shape parameters."""
def incorrect_inner_radius():
- self.test_shape.inner_radius = self.test_shape.outer_radius + 1
- self.test_shape.outer_radius = 20
- self.test_shape.inner_radius = 40
+ self.test_shape.inner_radius = 250
def incorrect_outer_radius():
- self.test_shape.outer_radius = self.test_shape.inner_radius + 1
- self.test_shape.inner_radius = 40
- self.test_shape.outer_radius = 20
+ self.test_shape.inner_radius = 100
+ self.test_shape.outer_radius = 50
def incorrect_height():
+ self.test_shape.outer_radius = 200
self.test_shape.height = None
self.assertRaises(ValueError, incorrect_inner_radius)
diff --git a/tests/test_parametric_components/test_CenterColumnShieldFlatTopHyperbola.py b/tests/test_parametric_components/test_CenterColumnShieldFlatTopHyperbola.py
index b6ba864ee..3dc8180fd 100644
--- a/tests/test_parametric_components/test_CenterColumnShieldFlatTopHyperbola.py
+++ b/tests/test_parametric_components/test_CenterColumnShieldFlatTopHyperbola.py
@@ -38,8 +38,7 @@ def test_creation(self):
assert self.test_shape.solid is not None
assert self.test_shape.volume > 1000
- def test_invalid_parameters_errors(
- self):
+ def test_invalid_parameters_errors(self):
"""Checks that the correct errors are raised when invalid arguments are input as
shape parameters."""
@@ -48,14 +47,17 @@ def incorrect_inner_radius():
self.test_shape.solid
def incorrect_mid_radius():
- self.test_shape.mid_radius = 220
+ self.test_shape.inner_radius = 100
+ self.test_shape.mid_radius = 250
self.test_shape.solid
def incorrect_outer_radius():
+ self.test_shape.mid_radius = 150
self.test_shape.outer_radius = 130
self.test_shape.solid
def incorrect_arc_height():
+ self.test_shape.outer_radius = 200
self.test_shape.arc_height = 700
self.test_shape.solid
diff --git a/tests/test_parametric_components/test_CenterColumnShieldHyperbola.py b/tests/test_parametric_components/test_CenterColumnShieldHyperbola.py
index b9fe61704..907765702 100644
--- a/tests/test_parametric_components/test_CenterColumnShieldHyperbola.py
+++ b/tests/test_parametric_components/test_CenterColumnShieldHyperbola.py
@@ -48,10 +48,12 @@ def incorrect_inner_radius():
self.test_shape.solid
def incorrect_mid_radius():
+ self.test_shape.inner_radius = 100
self.test_shape.mid_radius = 80
self.test_shape.solid
def incorrect_outer_radius():
+ self.test_shape.mid_radius = 150
self.test_shape.outer_radius = 130
self.test_shape.solid
diff --git a/tests/test_parametric_components/test_CenterColumnShieldPlasmaHyperbola.py b/tests/test_parametric_components/test_CenterColumnShieldPlasmaHyperbola.py
index 480688183..c376b5b8b 100644
--- a/tests/test_parametric_components/test_CenterColumnShieldPlasmaHyperbola.py
+++ b/tests/test_parametric_components/test_CenterColumnShieldPlasmaHyperbola.py
@@ -52,7 +52,8 @@ def incorrect_inner_radius():
self.test_shape.solid
def incorrect_height():
- self.test_shape.height = 301
+ self.test_shape.inner_radius = 100
+ self.test_shape.height = 300
self.test_shape.solid
self.assertRaises(ValueError, incorrect_inner_radius)
diff --git a/tests/test_parametric_components/test_CuttingWedge.py b/tests/test_parametric_components/test_CuttingWedge.py
index 39db4d17e..83c484009 100644
--- a/tests/test_parametric_components/test_CuttingWedge.py
+++ b/tests/test_parametric_components/test_CuttingWedge.py
@@ -26,3 +26,15 @@ def test_volume_of_for_5_random_dimentions(self):
angle_fraction = 360 / rotation_angle
correct_volume = (math.pi * radius ** 2 * height) / angle_fraction
assert test_shape.volume == pytest.approx(correct_volume)
+
+ def test_surface_reflectivity_in_neutronics_description(self):
+ test_shape = paramak.CuttingWedge(
+ height=1000,
+ radius=1000,
+ rotation_angle=270,
+ surface_reflectivity=True
+ )
+
+ json_dict = test_shape.neutronics_description()
+ assert 'surface_reflectivity' in json_dict.keys()
+ assert json_dict['surface_reflectivity'] is True
diff --git a/tests/test_parametric_components/test_CuttingWedgeFS.py b/tests/test_parametric_components/test_CuttingWedgeFS.py
index b199cb04c..3d3a793fd 100644
--- a/tests/test_parametric_components/test_CuttingWedgeFS.py
+++ b/tests/test_parametric_components/test_CuttingWedgeFS.py
@@ -24,14 +24,16 @@ def test_shape_construction_and_volume(self):
assert cutter.volume > hoop_shape.volume
- def test_error(self):
- """Checks that errors are raised when invalid arguments are set
- """
+ def test_invalid_parameters_errors(self):
+ """Checks that the correct errors are raised when invalid arguments are input as
+ shape parameters."""
+
shape = paramak.ExtrudeStraightShape(
- 1,
+ distance=1,
points=[(0, 0), (0, 1), (1, 1)],
rotation_angle=180
)
+
cutter = paramak.CuttingWedgeFS(
shape=shape,
azimuth_placement_angle=0,
@@ -39,16 +41,15 @@ def test_error(self):
def incorrect_rotation_angle():
shape.rotation_angle = 360
- print(cutter.shape.rotation_angle)
cutter.solid
def incorrect_shape_points():
shape.rotation_angle = 180
cutter.shape.points = [(0, 0, 'straight')]
- print(shape.points)
cutter.solid
def incorrect_shape_rotation_angle():
+ cutter.shape.points = [(0, 0), (0, 1), (1, 1)]
shape.rotation_angle = 360
cutter.shape = shape
diff --git a/tests/test_parametric_components/test_Plasma.py b/tests/test_parametric_components/test_Plasma.py
index 9771be5e8..b8bd3dd21 100644
--- a/tests/test_parametric_components/test_Plasma.py
+++ b/tests/test_parametric_components/test_Plasma.py
@@ -1,6 +1,7 @@
import os
import unittest
+import pytest
from pathlib import Path
import paramak
@@ -223,12 +224,11 @@ def test_export_plasma_from_points_export(self):
assert Path("plasma.stp").exists()
os.system("rm plasma.stp")
- # TODO: fix issue #435
- # def test_plasma_relative_volume(self):
- # """Creates plasmas using the Plasma parametric component and checks that
- # the relative volumes of the solids created are correct"""
+ def test_plasma_relative_volume(self):
+ """Creates plasmas using the Plasma parametric component and checks that
+ the relative volumes of the solids created are correct"""
- # test_plasma = paramak.Plasma()
- # test_plasma_volume = test_plasma.volume
- # test_plasma.rotation_angle = 180
- # assert test_plasma.volume == pytest.approx(test_plasma_volume * 0.5)
+ test_plasma = paramak.Plasma()
+ test_plasma_volume = test_plasma.volume
+ test_plasma.rotation_angle = 180
+ assert test_plasma.volume == pytest.approx(test_plasma_volume * 0.5)
diff --git a/tests/test_parametric_components/test_PoloidalFieldCoilCaseSet.py b/tests/test_parametric_components/test_PoloidalFieldCoilCaseSet.py
index 7a2b1d638..5061740c9 100644
--- a/tests/test_parametric_components/test_PoloidalFieldCoilCaseSet.py
+++ b/tests/test_parametric_components/test_PoloidalFieldCoilCaseSet.py
@@ -114,20 +114,39 @@ def test_absolute_areas(self):
assert self.test_shape.areas.count(
pytest.approx(40 * math.pi * 2 * 80)) == 1
- def test_invalid_args(self):
- """Creates PoloidalFieldCoilCaseSets with invalid arguments and checks
- that the correct errors are raised."""
+ def test_PoloidalFieldCoilCaseSet_incorrect_thicknesses_1(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSet is made
+ with the wrong number of casing thicknesses."""
- def test_invalid_casing_thicknesses_1():
+ def make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_1():
self.test_shape.casing_thicknesses = [5, 5, 10]
self.test_shape.solid
- def test_invalid_casing_thicknesses_2():
+ self.assertRaises(
+ ValueError,
+ make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_1
+ )
+
+ def test_PoloidalFieldCoil_incorrect_thicknesses_2(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSet is made
+ with invalid casing thicknesses."""
+
+ def make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_2():
self.test_shape.casing_thicknesses = [5, 5, 5, 'ten']
- def test_invalid_casing_thicknesses_3():
+ self.assertRaises(
+ ValueError,
+ make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_2
+ )
+
+ def test_PoloidalFieldCoil_incorrect_thicknesses_3(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSet is made
+ with invalid casing thicknesses."""
+
+ def make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_3():
self.test_shape.casing_thicknesses = "ten"
- self.assertRaises(ValueError, test_invalid_casing_thicknesses_1)
- self.assertRaises(ValueError, test_invalid_casing_thicknesses_2)
- self.assertRaises(ValueError, test_invalid_casing_thicknesses_3)
+ self.assertRaises(
+ ValueError,
+ make_PoloidalFieldCoilCaseSet_incorrect_thicknesses_3
+ )
diff --git a/tests/test_parametric_components/test_PoloidalFieldCoilCaseSetFC.py b/tests/test_parametric_components/test_PoloidalFieldCoilCaseSetFC.py
index a5f9d4a51..de20e5924 100644
--- a/tests/test_parametric_components/test_PoloidalFieldCoilCaseSetFC.py
+++ b/tests/test_parametric_components/test_PoloidalFieldCoilCaseSetFC.py
@@ -114,25 +114,24 @@ def test_from_pf_coil_set_absolute_areas(self):
assert self.test_shape.areas.count(
pytest.approx(40 * math.pi * 2 * 80)) == 1
- def test_incorrect_args(self):
- """Creates a solid using the PoloidalFieldCoilCaseSet with incorrect
- args"""
-
- def test_PoloidalFieldCoilSet_incorrect_lengths_FC():
- """Checks PoloidalFieldCoilSet with the wrong number of casing
- thicknesses (3) using a coil set object with 4 pf_coils."""
+ def test_PoloidalFieldCoilCaseSetFC_incorrect_lengths_FC(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSetFC is made
+ with the wrong number of casing thicknesses using a coil set object."""
+ def make_PoloidalFieldCoilCaseSetFC_incorrect_lengths_FC():
self.test_shape.casing_thicknesses = [5, 5, 10]
self.test_shape.solid
self.assertRaises(
ValueError,
- test_PoloidalFieldCoilSet_incorrect_lengths_FC)
+ make_PoloidalFieldCoilCaseSetFC_incorrect_lengths_FC
+ )
- def test_PoloidalFieldCoilSet_incorrect_lengths():
- """Checks PoloidalFieldCoilSet with the wrong number of casing
- thicknesses using a list."""
+ def test_PoloidalFieldCoilCaseSetFC_incorrect_lengths(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSetFC is made
+ with the wrong number of casing thicknesses using a list."""
+ def make_PoloidalFieldCoilCaseSetFC_incorrect_lengths():
self.pf_coils_set.height = 10
self.pf_coils_set.width = 10
self.pf_coils_set.center_point = (100, 100)
@@ -142,18 +141,21 @@ def test_PoloidalFieldCoilSet_incorrect_lengths():
self.assertRaises(
ValueError,
- test_PoloidalFieldCoilSet_incorrect_lengths)
+ make_PoloidalFieldCoilCaseSetFC_incorrect_lengths
+ )
- def test_PoloidalFieldCoilSet_incorrect_pf_coil():
- """Checks PoloidalFieldCoilSet with the pf_coils as an incorrect
- entry."""
+ def test_PoloidalFieldCoilCaseSetFC_incorrect_pf_coil(self):
+ """Checks that an error is raised when a PoloidalFieldCoilCaseSetFC is made
+ with the pf_coils as an incorrect entry."""
+ def make_PoloidalFieldCoilCaseSetFC_incorrect_pf_coil():
self.test_shape.pf_coils = 20
self.test_shape.solid
self.assertRaises(
ValueError,
- test_PoloidalFieldCoilSet_incorrect_pf_coil)
+ make_PoloidalFieldCoilCaseSetFC_incorrect_pf_coil
+ )
def test_from_list(self):
"""Creates a set of PF coil cases from a list of PF coils with a list
@@ -183,7 +185,7 @@ def test_from_list(self):
assert test_shape.solid is not None
assert len(test_shape.solid.Solids()) == 4
- def test_PoloidalFieldCoilCaseFC_with_number_thickness(self):
+ def test_PoloidalFieldCoilCaseSetFC_with_number_thickness(self):
"""Creates a set of PF coil cases from a list of PF coils with a
single numerical thicknesses."""
diff --git a/tests/test_parametric_components/test_PoloidalFieldCoilSet.py b/tests/test_parametric_components/test_PoloidalFieldCoilSet.py
index 1e03f0486..f6df4e89d 100644
--- a/tests/test_parametric_components/test_PoloidalFieldCoilSet.py
+++ b/tests/test_parametric_components/test_PoloidalFieldCoilSet.py
@@ -75,13 +75,11 @@ def test_absolute_areas(self):
assert self.test_shape.areas.count(
pytest.approx(5 * math.pi * (2 * 315))) == 1
- def test_incorrect_args(self):
- """Creates a solid using the PoloidalFieldCoilSet parametric component
- and checks that a cadquery solid is created."""
-
- def test_incorrect_height():
- """Checks PoloidalFieldCoilSet with height as the wrong type."""
+ def test_PoloidalFieldCoilSet_incorrect_height(self):
+ """Checks that an error is raised when a PoloidalFieldCoilSet is made
+ with height passed as the wrong type."""
+ def make_PoloidalFieldCoilSet_incorrect_height():
paramak.PoloidalFieldCoilSet(
heights=10,
widths=[20, 20, 20],
@@ -89,11 +87,14 @@ def test_incorrect_height():
self.assertRaises(
ValueError,
- test_incorrect_height)
+ make_PoloidalFieldCoilSet_incorrect_height
+ )
- def test_incorrect_width():
- """Checks PoloidalFieldCoilSet with width as the wrong type."""
+ def test_PoloidalFieldCoilSet_incorrect_width(self):
+ """Checks that an error is raised when a PoloidalFieldCoilSet is made
+ with width passed as the wrong type."""
+ def make_PoloidalFieldCoilSet_incorrect_width():
paramak.PoloidalFieldCoilSet(
heights=[10, 10, 10],
widths=20,
@@ -101,12 +102,14 @@ def test_incorrect_width():
self.assertRaises(
ValueError,
- test_incorrect_width)
+ make_PoloidalFieldCoilSet_incorrect_width
+ )
- def test_incorrect_center_points():
- """Checks PoloidalFieldCoilSet with center_points as the wrong
- type."""
+ def test_PoloidalFieldCoilSet_incorrect_center_points(self):
+ """Checks that an error is raised when a PoloidalFieldCoilSet is made
+ with center_points passed as the wrong type."""
+ def make_PoloidalFieldCoilSet_incorrect_center_points():
paramak.PoloidalFieldCoilSet(
heights=[10, 10, 10],
widths=[20, 20, 20],
@@ -114,10 +117,14 @@ def test_incorrect_center_points():
self.assertRaises(
ValueError,
- test_incorrect_center_points)
+ make_PoloidalFieldCoilSet_incorrect_center_points
+ )
- def test_incorrect_width_length():
- """Checks PoloidalFieldCoilSet with not enough entries in width."""
+ def test_PoloidalFieldCoilSet_incorrect_width_length(self):
+ """Checks that an error is raised when a PoloidalFieldCoilSet is made
+ with the incorrect number of widths."""
+
+ def make_PoloidalFieldCoilSet_incorrect_width_length():
paramak.PoloidalFieldCoilSet(
heights=[10, 10, 10],
widths=[20, 20],
@@ -125,4 +132,5 @@ def test_incorrect_width_length():
self.assertRaises(
ValueError,
- test_incorrect_width_length)
+ make_PoloidalFieldCoilSet_incorrect_width_length
+ )
diff --git a/tests/test_parametric_components/test_PoloidalSegments.py b/tests/test_parametric_components/test_PoloidalSegments.py
index 4ed387922..a3a1ed8f9 100644
--- a/tests/test_parametric_components/test_PoloidalSegments.py
+++ b/tests/test_parametric_components/test_PoloidalSegments.py
@@ -23,7 +23,7 @@ def create_shape():
)
self.assertRaises(
- ValueError, create_shape)
+ TypeError, create_shape)
def test_solid_count_with_incorect_inputs2(self):
"""Checks the segmenter does not take a negative int as an input."""
diff --git a/tests/test_parametric_components/test_ToroidalFieldCoilRectangle.py b/tests/test_parametric_components/test_ToroidalFieldCoilRectangle.py
index 14c3ff4e7..30a469ea7 100644
--- a/tests/test_parametric_components/test_ToroidalFieldCoilRectangle.py
+++ b/tests/test_parametric_components/test_ToroidalFieldCoilRectangle.py
@@ -140,19 +140,30 @@ def test_rotation_angle(self):
self.test_shape.rotation_angle = 180
assert self.test_shape.volume == pytest.approx(test_volume * 0.5)
- def test_error(self):
- """Checks errors are raised with invalid arguments."""
+ def test_ToroidalFieldCoilRectangle_incorrect_horizonal_start_point(self):
+ """Checks that an error is raised when a ToroidalFieldCoilRectangle is made
+ with an incorrect horizontal_start_point."""
- def incorrect_horizontal_start_point():
+ def make_ToroidalFieldCoilRectangle_incorrect_horizontal_start_point():
self.test_shape.vertical_mid_point = (800, 0)
self.test_shape.horizontal_start_point = (801, 700)
self.test_shape.solid
- self.assertRaises(ValueError, incorrect_horizontal_start_point)
+ self.assertRaises(
+ ValueError,
+ make_ToroidalFieldCoilRectangle_incorrect_horizontal_start_point
+ )
+
+ def test_ToroidalFieldCoilRectangle_incorrect_vertical_mid_point(self):
+ """Checks that an error is raised when a ToroidalFieldCoilRectangle is made
+ with an incorrect vertical_mid_point."""
- def incorrect_vertical_mid_point():
+ def make_ToroidalFieldCoilRectangle_incorrect_vertical_mid_point():
self.test_shape.horizontal_start_point = (100, 700)
self.test_shape.vertical_mid_point = (800, 701)
self.test_shape.solid
- self.assertRaises(ValueError, incorrect_vertical_mid_point)
+ self.assertRaises(
+ ValueError,
+ make_ToroidalFieldCoilRectangle_incorrect_vertical_mid_point
+ )
diff --git a/tests/test_parametric_neutronics/test_NeutronicModel.py b/tests/test_parametric_neutronics/test_NeutronicModel.py
index c719f39ba..28ce9b264 100644
--- a/tests/test_parametric_neutronics/test_NeutronicModel.py
+++ b/tests/test_parametric_neutronics/test_NeutronicModel.py
@@ -22,11 +22,43 @@ def setUp(self):
)
# makes the openmc neutron source at x,y,z 0, 0, 0 with isotropic
- # diections
+ # directions
self.source = openmc.Source()
self.source.space = openmc.stats.Point((0, 0, 0))
self.source.angle = openmc.stats.Isotropic()
+ def simulation_with_previous_h5m_file(self):
+ """This performs a simulation using previously created h5m file"""
+
+ os.system('rm *.h5m')
+
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'WC'},
+ )
+
+ my_model.create_neutronics_geometry(method='pymoab')
+
+ my_model.simulate(method=None)
+
+ my_model.results is not None
+
+ def test_merge_tolerance_setting_and_getting(self):
+ """Makes a neutronics model and checks the default merge_tolerance"""
+
+ # converts the geometry into a neutronics geometry
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ )
+
+ assert my_model.merge_tolerance == 1e-4
+
+ my_model.merge_tolerance = 1e-6
+ assert my_model.merge_tolerance == 1e-6
+
def test_neutronics_component_simulation_with_openmc_mat(self):
"""Makes a neutronics model and simulates with a cell tally"""
@@ -45,11 +77,17 @@ def test_neutronics_component_simulation_with_openmc_mat(self):
)
# performs an openmc simulation on the model
- my_model.simulate(method='pymoab')
+ output_filename = my_model.simulate(
+ method='pymoab',
+ )
+
+ assert output_filename.name == 'statepoint.2.h5'
+
+ results = openmc.StatePoint(output_filename)
+ assert len(results.tallies.items()) == 1
# extracts the heat from the results dictionary
heat = my_model.results['center_column_shield_mat_heating']['Watts']['result']
-
assert heat > 0
def test_neutronics_component_simulation_with_nmm(self):
@@ -68,19 +106,71 @@ def test_neutronics_component_simulation_with_nmm(self):
)
# performs an openmc simulation on the model
- my_model.simulate(method='pymoab')
+ output_filename = my_model.simulate(method='pymoab')
+
+ results = openmc.StatePoint(output_filename)
+ assert len(results.tallies.items()) == 1
# extracts the heat from the results dictionary
heat = my_model.results['center_column_shield_mat_heating']['Watts']['result']
-
assert heat > 0
- def test_incorrect_args(self):
- """Checks that an error is raised when the shape is
- defined as ."""
+ def test_cell_tally_output_file_creation(self):
+ """Performs a neutronics simulation and checks the cell tally output
+ file is created and named correctly"""
+
+ os.system('rm custom_name.json')
+ os.system('rm results.json')
+
+ test_mat = openmc.Material()
+ test_mat.add_element('Fe', 1.0)
+ test_mat.set_density(units='g/cm3', density=4.2)
+
+ # converts the geometry into a neutronics geometry
+ # this simulation has no tally to test this edge case
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': test_mat},
+ simulation_batches=2,
+ simulation_particles_per_batch=2
+ )
+
+ # performs an openmc simulation on the model
+ output_filename = my_model.simulate(
+ method='pymoab',
+ cell_tally_results_filename='custom_name.json'
+ )
+
+ assert output_filename.name == 'statepoint.2.h5'
+ assert Path('custom_name.json').exists() is True
+
+ output_filename = my_model.simulate(
+ method='pymoab',
+ )
+ assert Path('results.json').exists() is True
+
+ def test_missing_dagmc_not_watertight_file(self):
+
+ def missing_dagmc_not_watertight_file():
+ """Sets faceting_tolerance as a string which should raise an error"""
+ test_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ )
+
+ test_model._make_watertight()
+
+ self.assertRaises(
+ ValueError,
+ missing_dagmc_not_watertight_file
+ )
+
+ def test_incorrect_faceting_tolerance(self):
def incorrect_faceting_tolerance():
- "Tries to set faceting_tolerance as a string"
+ """Sets faceting_tolerance as a string which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -93,8 +183,10 @@ def incorrect_faceting_tolerance():
incorrect_faceting_tolerance
)
+ def test_incorrect_faceting_tolerance_too_small(self):
+
def incorrect_faceting_tolerance_too_small():
- "Tries to set faceting_tolerance as a negative number"
+ """Set faceting_tolerance as a negative int which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -107,8 +199,10 @@ def incorrect_faceting_tolerance_too_small():
incorrect_faceting_tolerance_too_small
)
+ def test_incorrect_merge_tolerance(self):
+
def incorrect_merge_tolerance():
- "Tries to set merge_tolerance as a string"
+ """Set merge_tolerance as a string which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -121,8 +215,10 @@ def incorrect_merge_tolerance():
incorrect_merge_tolerance
)
+ def test_incorrect_merge_tolerance_too_small(self):
+
def incorrect_merge_tolerance_too_small():
- "Tries to set merge_tolerance as a negative number"
+ """Set merge_tolerance as a negative number which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -135,8 +231,10 @@ def incorrect_merge_tolerance_too_small():
incorrect_merge_tolerance_too_small
)
+ def test_incorrect_cell_tallies(self):
+
def incorrect_cell_tallies():
- "Tries to set a cell tally that is not accepted"
+ """Set a cell tally that is not accepted which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -149,8 +247,26 @@ def incorrect_cell_tallies():
incorrect_cell_tallies
)
- def incorrect_mesh_tally_2D():
- "Tries to set a mesh_tally_2D that is not accepted"
+ def test_incorrect_cell_tally_type(self):
+
+ def incorrect_cell_tally_type():
+ """Set a cell tally that is the wrong type which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ cell_tallies=1,
+ )
+
+ self.assertRaises(
+ TypeError,
+ incorrect_cell_tally_type
+ )
+
+ def test_incorrect_mesh_tally_2d(self):
+
+ def incorrect_mesh_tally_2d():
+ """Set a mesh_tally_2D that is not accepted which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -160,11 +276,61 @@ def incorrect_mesh_tally_2D():
self.assertRaises(
ValueError,
- incorrect_mesh_tally_2D
+ incorrect_mesh_tally_2d
+ )
+
+ def test_incorrect_mesh_tally_2d_type(self):
+
+ def incorrect_mesh_tally_2d_type():
+ """Set a mesh_tally_2D that is the wrong type which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ mesh_tally_2D=1,
+ )
+
+ self.assertRaises(
+ TypeError,
+ incorrect_mesh_tally_2d_type
+ )
+
+ def test_incorrect_mesh_tally_3d(self):
+
+ def incorrect_mesh_tally_3d():
+ """Set a mesh_tally_3D that is not accepted which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ mesh_tally_3D=['coucou'],
+ )
+
+ self.assertRaises(
+ ValueError,
+ incorrect_mesh_tally_3d
+ )
+
+ def test_incorrect_mesh_tally_3d_type(self):
+
+ def incorrect_mesh_tally_3d_type():
+ """Set a mesh_tally_3D that is the wrong type which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ mesh_tally_3D=1,
+ )
+
+ self.assertRaises(
+ TypeError,
+ incorrect_mesh_tally_3d_type
)
+ def test_incorrect_materials(self):
+
def incorrect_materials():
- "Tries to set a material that is not accepted"
+ """Set a material as a string which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -176,8 +342,27 @@ def incorrect_materials():
incorrect_materials
)
+ def test_incorrect_materials_type(self):
+
+ def incorrect_materials_type():
+ """Sets a material as an int which should raise an error"""
+ test_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 23},
+ )
+
+ test_model.create_materials()
+
+ self.assertRaises(
+ TypeError,
+ incorrect_materials_type
+ )
+
+ def test_incorrect_simulation_batches_to_small(self):
+
def incorrect_simulation_batches_to_small():
- """The simulation batch must be above 2"""
+ """Sets simulation batch below 2 which should raise an error"""
paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
@@ -190,45 +375,184 @@ def incorrect_simulation_batches_to_small():
incorrect_simulation_batches_to_small
)
- def test_neutronics_component_cell_simulation(self):
+ def test_incorrect_simulation_batches_wrong_type(self):
+
+ def incorrect_simulation_batches_wrong_type():
+ """Sets simulation_batches as a string which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ simulation_batches='one'
+ )
+
+ self.assertRaises(
+ TypeError,
+ incorrect_simulation_batches_wrong_type
+ )
+
+ def test_incorrect_simulation_particles_per_batch_wrong_type(self):
+
+ def incorrect_simulation_particles_per_batch_wrong_type():
+ """Sets simulation_particles_per_batch below 2 which should raise an error"""
+ paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'eurofer'},
+ simulation_particles_per_batch='one'
+ )
+
+ self.assertRaises(
+ TypeError,
+ incorrect_simulation_particles_per_batch_wrong_type
+ )
+
+ def test_neutronics_component_cell_simulation_heating(self):
"""Makes a neutronics model and simulates with a cell tally"""
+ os.system('rm *.h5')
+ mat = openmc.Material()
+ mat.add_element('Li', 1)
+ mat.set_density('g/cm3', 2.1)
+
# converts the geometry into a neutronics geometry
my_model = paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
- materials={'center_column_shield_mat': 'Be'},
- cell_tallies=['heating'],
+ materials={'center_column_shield_mat': mat},
+ cell_tallies=['heating', 'flux', 'TBR', 'spectra'],
simulation_batches=2,
simulation_particles_per_batch=2
)
# performs an openmc simulation on the model
- my_model.simulate(method='pymoab')
+ output_filename = my_model.simulate(method='pymoab')
+
+ results = openmc.StatePoint(output_filename)
+ # spectra add two tallies in this case (photons and neutrons)
+ # TBR adds two tallies global TBR and material TBR
+ assert len(results.tallies.items()) == 6
+ assert len(results.meshes) == 0
# extracts the heat from the results dictionary
heat = my_model.results['center_column_shield_mat_heating']['Watts']['result']
+ flux = my_model.results['center_column_shield_mat_flux']['Flux per source particle']['result']
+ mat_tbr = my_model.results['center_column_shield_mat_TBR']['result']
+ tbr = my_model.results['TBR']['result']
+ spectra_neutrons = my_model.results['center_column_shield_mat_neutron_spectra']['Flux per source particle']['result']
+ spectra_photons = my_model.results['center_column_shield_mat_photon_spectra']['Flux per source particle']['result']
+ energy = my_model.results['center_column_shield_mat_photon_spectra']['Flux per source particle']['energy']
assert heat > 0
+ assert flux > 0
+ assert tbr > 0
+ assert mat_tbr > 0
+ assert mat_tbr == tbr # as there is just one shape
+ assert len(energy) == 710
+ assert len(spectra_neutrons) == 709
+ assert len(spectra_photons) == 709
def test_neutronics_component_2d_mesh_simulation(self):
"""Makes a neutronics model and simulates with a 2D mesh tally"""
os.system('rm *_on_2D_mesh_*.png')
+ os.system('rm *.h5')
+
+ # converts the geometry into a neutronics geometry
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'Be'},
+ mesh_tally_2D=['heating'],
+ simulation_batches=2,
+ simulation_particles_per_batch=2
+ )
+
+ # performs an openmc simulation on the model
+ output_filename = my_model.simulate(method='pymoab')
+
+ results = openmc.StatePoint(output_filename)
+ assert len(results.meshes) == 3
+ assert len(results.tallies.items()) == 3
+
+ assert Path("heating_on_2D_mesh_xz.png").exists() is True
+ assert Path("heating_on_2D_mesh_xy.png").exists() is True
+ assert Path("heating_on_2D_mesh_yz.png").exists() is True
+
+ def test_neutronics_component_3d_mesh_simulation(self):
+ """Makes a neutronics model and simulates with a 3D mesh tally and
+ checks that the vtk file is produced"""
+
+ os.system('rm *.h5')
+
+ # converts the geometry into a neutronics geometry
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'Be'},
+ mesh_tally_3D=['heating', 'tritium_production'],
+ simulation_batches=2,
+ simulation_particles_per_batch=2
+ )
+
+ # performs an openmc simulation on the model
+ output_filename = my_model.simulate(method='pymoab')
+
+ results = openmc.StatePoint(output_filename)
+ assert len(results.meshes) == 1
+ assert len(results.tallies.items()) == 2
+
+ assert Path(output_filename).exists() is True
+ assert Path('heating_on_3D_mesh.vtk').exists() is True
+ assert Path('tritium_production_on_3D_mesh.vtk').exists() is True
+
+ def test_batches_and_particles_convert_to_int(self):
+ """Makes a neutronics model and simulates with a 3D and 2D mesh tally
+ and checks that the vtk and png files are produced. This checks the
+ mesh ID values don't overlap"""
+
+ os.system('rm *.h5')
+
+ # converts the geometry into a neutronics geometry
+ my_model = paramak.NeutronicsModel(
+ geometry=self.my_shape,
+ source=self.source,
+ materials={'center_column_shield_mat': 'Be'},
+ simulation_batches=3.1,
+ simulation_particles_per_batch=2.1
+ )
+
+ assert isinstance(my_model.simulation_batches, int)
+ assert my_model.simulation_batches == 3
+ assert isinstance(my_model.simulation_particles_per_batch, int)
+ assert my_model.simulation_particles_per_batch == 2
+
+ def test_neutronics_component_3d_and_2d_mesh_simulation(self):
+ """Makes a neutronics model and simulates with a 3D and 2D mesh tally
+ and checks that the vtk and png files are produced. This checks the
+ mesh ID values don't overlap"""
+
+ os.system('rm *.h5')
# converts the geometry into a neutronics geometry
my_model = paramak.NeutronicsModel(
geometry=self.my_shape,
source=self.source,
materials={'center_column_shield_mat': 'Be'},
+ mesh_tally_3D=['heating'],
mesh_tally_2D=['heating'],
simulation_batches=2,
simulation_particles_per_batch=2
)
# performs an openmc simulation on the model
- my_model.simulate(method='pymoab')
+ output_filename = my_model.simulate(method='pymoab')
+ results = openmc.StatePoint(output_filename)
+ assert len(results.meshes) == 4 # one 3D and three 2D
+ assert len(results.tallies.items()) == 4 # one 3D and three 2D
+ assert Path(output_filename).exists() is True
+ assert Path('heating_on_3D_mesh.vtk').exists() is True
assert Path("heating_on_2D_mesh_xz.png").exists() is True
assert Path("heating_on_2D_mesh_xy.png").exists() is True
assert Path("heating_on_2D_mesh_yz.png").exists() is True
@@ -373,7 +697,6 @@ def test_reactor_from_shapes_2d_mesh_tallies(self):
# starts the neutronics simulation using trelis
neutronics_model.simulate(verbose=False, method='pymoab')
- neutronics_model.get_results()
assert Path("tritium_production_on_2D_mesh_xz.png").exists() is True
assert Path("tritium_production_on_2D_mesh_xy.png").exists() is True
diff --git a/tests/test_parametric_shapes/test_RotateStraightShape.py b/tests/test_parametric_shapes/test_RotateStraightShape.py
index a4ad99776..5c3050280 100644
--- a/tests/test_parametric_shapes/test_RotateStraightShape.py
+++ b/tests/test_parametric_shapes/test_RotateStraightShape.py
@@ -136,6 +136,24 @@ def test_export_stp_extension(self):
assert Path("RotateStraightShape.stp").exists() is True
os.system("rm RotateStraightShape.stp")
+ def test_export_stp_extension_in_cm(self):
+ """Creates a RotateStraightShape and checks that a stp file of the
+ shape can be exported with the correct suffix using the export_stp
+ method."""
+
+ os.system("rm filename.stp filename.step")
+ self.test_shape.export_stp("filename.stp", units='cm')
+ self.test_shape.export_stp("filename.step", units='cm')
+ assert Path("filename.stp").exists() is True
+ assert Path("filename.step").exists() is True
+ os.system("rm filename.stp filename.step")
+ self.test_shape.export_stp("filename", units='cm')
+ assert Path("filename.stp").exists() is True
+ os.system("rm filename.stp")
+ self.test_shape.export_stp(units='cm')
+ assert Path("RotateStraightShape.stp").exists() is True
+ os.system("rm RotateStraightShape.stp")
+
def test_export_stl(self):
"""Creates a RotateStraightShape and checks that a stl file of the
shape can be exported with the correct suffix using the export_stl
@@ -255,6 +273,18 @@ def export_mode_incorrect():
self.assertRaises(ValueError, export_mode_incorrect)
+ def test_graveyard_filename(self):
+ """Checks the name of the stp file for the Graveyard is correct
+ """
+ output_filename = self.test_shape.export_graveyard()
+ assert 'Graveyard.stp' == output_filename
+
+ output_filename = self.test_shape.export_graveyard(filename='test.stp')
+ assert 'test.stp' == output_filename
+
+ output_filename = self.test_shape.export_graveyard(filename='test2')
+ assert 'test2.stp' == output_filename
+
if __name__ == "__main__":
unittest.main()