From 03e860bce9b63cf587c2da37f1dc8de2d2aa9123 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 30 Nov 2021 23:52:11 +0000 Subject: [PATCH 1/7] more concise examples --- examples/example_plot_direction_from_initial_source.py | 1 - examples/example_plot_energy_from_initial_source.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/examples/example_plot_direction_from_initial_source.py b/examples/example_plot_direction_from_initial_source.py index c46214b..148aa5c 100644 --- a/examples/example_plot_direction_from_initial_source.py +++ b/examples/example_plot_direction_from_initial_source.py @@ -1,6 +1,5 @@ import openmc_source_plotter as osp import openmc -import numpy as np # initializes a new source object my_source = openmc.Source() diff --git a/examples/example_plot_energy_from_initial_source.py b/examples/example_plot_energy_from_initial_source.py index 5757dac..56c2c98 100644 --- a/examples/example_plot_energy_from_initial_source.py +++ b/examples/example_plot_energy_from_initial_source.py @@ -5,9 +5,6 @@ # initialises a new source object my_source = openmc.Source() -# sets the location of the source to x=0 y=0 z=0 -my_source.space = openmc.stats.Point((0, 0, 0)) - # sets the energy distribution to a Muir distribution neutrons my_source.energy = openmc.stats.Muir(e0=14080000.0, m_rat=5.0, kt=20000.0) From 8d21e37bd0667814ad2465f2a16c7978aea8b764 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Wed, 26 Jan 2022 14:32:47 +0000 Subject: [PATCH 2/7] refactor and allowing source file name to be specified --- openmc_source_plotter/__init__.py | 4 +- openmc_source_plotter/core.py | 91 +--------------- openmc_source_plotter/utils.py | 102 ++++++++++++++++++ ...est_get_particle_data.py => test_utils.py} | 26 ++++- 4 files changed, 130 insertions(+), 93 deletions(-) create mode 100644 openmc_source_plotter/utils.py rename tests/{test_get_particle_data.py => test_utils.py} (53%) diff --git a/openmc_source_plotter/__init__.py b/openmc_source_plotter/__init__.py index 9676cfd..c184e2f 100644 --- a/openmc_source_plotter/__init__.py +++ b/openmc_source_plotter/__init__.py @@ -1,5 +1,5 @@ +from .utils import get_particle_data +from .utils import create_initial_particles from .core import plot_direction_from_initial_source from .core import plot_position_from_initial_source from .core import plot_energy_from_initial_source -from .core import get_particle_data -from .core import create_initial_particles diff --git a/openmc_source_plotter/core.py b/openmc_source_plotter/core.py index cd44613..70bee75 100644 --- a/openmc_source_plotter/core.py +++ b/openmc_source_plotter/core.py @@ -1,97 +1,12 @@ #!/usr/bin/env python3 -"""Provides utilities for creating h5 files containing initial source -information and then plotting that information""" +"""Provides functions for plotting source information""" + -import h5py import numpy as np -import openmc import plotly.graph_objects as go - -def create_initial_particles( - source: openmc.source, number_of_particles: int = 2000, openmc_exec="openmc" -) -> str: - """Accepts an openmc source and creates an initial_source.h5 file that can - be used to find propties of the source particles such as initial x,y,z - coordinates, direction and energy. - - Note, I've found it easiest to install the latest version of openmc as this - has the write_initial_source for fixed source problems and then in a - new empty conda environment I have installed openmc version 0.11.0 with the - 'conda install -c conda-forge openmc==0.11.0' command. I then go back to - the conda environment with the latest openmc version and run the python - script while setting the path to openmc_0.11.0 as the openmc_exec argument. - In my case it is '/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc' - - Args: - source: the openmc source to use - number_of_particles: the number of particles to sample - openmc_exec: the path of openmc executable or executable name if it - appears in your system $PATH. Defaults to 'openmc' which will use - the default openmc in your system $PATH environmental variable. - Returns: - The filename of the initial source file created (initial_source.h5) - """ - - # no real materials are needed for finding the source - mats = openmc.Materials([]) - - # just a minimal geometry - outer_surface = openmc.Sphere(r=100000, boundary_type="vacuum") - cell = openmc.Cell(region=-outer_surface) - universe = openmc.Universe(cells=[cell]) - geom = openmc.Geometry(universe) - - # Instantiate a Settings object - settings = openmc.Settings() - settings.run_mode = "fixed source" - settings.particles = number_of_particles - settings.batches = 1 - settings.inactive = 0 - settings.write_initial_source = True - settings.source = source - - model = openmc.model.Model(geom, mats, settings) - - model.export_to_xml() - - openmc.run(openmc_exec=openmc_exec) - - return "initial_source.h5" - - -def get_particle_data(input_filename: str): - - f = h5py.File(input_filename, "r") - dset = f["source_bank"] - - x_values = [] - y_values = [] - z_values = [] - x_dir = [] - y_dir = [] - z_dir = [] - e_values = [] - - for particle in dset: - x_values.append(particle[0][0]) - y_values.append(particle[0][1]) - z_values.append(particle[0][2]) - x_dir.append(particle[1][0]) - y_dir.append(particle[1][1]) - z_dir.append(particle[1][2]) - e_values.append(particle[2]) - - return { - "x_values": x_values, - "y_values": y_values, - "z_values": z_values, - "x_dir": x_dir, - "y_dir": y_dir, - "z_dir": z_dir, - "e_values": e_values, - } +from .utils import get_particle_data def plot_energy_from_initial_source( diff --git a/openmc_source_plotter/utils.py b/openmc_source_plotter/utils.py new file mode 100644 index 0000000..90d36bd --- /dev/null +++ b/openmc_source_plotter/utils.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +"""Provides utilities for creating h5 files containing initial source +information""" + +import h5py +import openmc +import shutil + + +def get_particle_data(input_filename: str): + + f = h5py.File(input_filename, "r") + dset = f["source_bank"] + + x_values = [] + y_values = [] + z_values = [] + x_dir = [] + y_dir = [] + z_dir = [] + e_values = [] + + for particle in dset: + x_values.append(particle[0][0]) + y_values.append(particle[0][1]) + z_values.append(particle[0][2]) + x_dir.append(particle[1][0]) + y_dir.append(particle[1][1]) + z_dir.append(particle[1][2]) + e_values.append(particle[2]) + + return { + "x_values": x_values, + "y_values": y_values, + "z_values": z_values, + "x_dir": x_dir, + "y_dir": y_dir, + "z_dir": z_dir, + "e_values": e_values, + } + + +def create_initial_particles( + source: openmc.source, + number_of_particles: int = 2000, + openmc_exec="openmc", + output_source_filename="initial_source.h5" +) -> str: + """Accepts an openmc source and creates an initial_source.h5 file that can + be used to find propties of the source particles such as initial x,y,z + coordinates, direction and energy. + + Note, I've found it easiest to install the latest version of openmc as this + has the write_initial_source for fixed source problems and then in a + new empty conda environment I have installed openmc version 0.11.0 with the + 'conda install -c conda-forge openmc==0.11.0' command. I then go back to + the conda environment with the latest openmc version and run the python + script while setting the path to openmc_0.11.0 as the openmc_exec argument. + In my case it is '/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc' + + Args: + source: the openmc source to use + number_of_particles: the number of particles to sample + openmc_exec: the path of openmc executable or executable name if it + appears in your system $PATH. Defaults to 'openmc' which will use + the default openmc in your system $PATH environmental variable. + output_source_filename: the filename of the initial source h5 file + produced. Note openmc will write 'initial_source.h5' but this will + be moved to the output_source_filename specified + Returns: + The filename of the initial source file created (initial_source.h5) + """ + + # no real materials are needed for finding the source + mats = openmc.Materials([]) + + # just a minimal geometry + outer_surface = openmc.Sphere(r=100000, boundary_type="vacuum") + cell = openmc.Cell(region=-outer_surface) + universe = openmc.Universe(cells=[cell]) + geom = openmc.Geometry(universe) + + # Instantiate a Settings object + settings = openmc.Settings() + settings.run_mode = "fixed source" + settings.particles = number_of_particles + settings.batches = 1 + settings.inactive = 0 + settings.write_initial_source = True + settings.source = source + + model = openmc.model.Model(geom, mats, settings) + + model.export_to_xml() + + openmc.run(openmc_exec=openmc_exec) + + if output_source_filename != "initial_source.h5": + shutil.move("initial_source.h5", output_source_filename) + + return output_source_filename \ No newline at end of file diff --git a/tests/test_get_particle_data.py b/tests/test_utils.py similarity index 53% rename from tests/test_get_particle_data.py rename to tests/test_utils.py index 93d31c6..89fbb34 100644 --- a/tests/test_get_particle_data.py +++ b/tests/test_utils.py @@ -1,11 +1,18 @@ import openmc_source_plotter as osp import openmc import unittest +from pathlib import Path -class TestReactor(unittest.TestCase): +class TestUtils(unittest.TestCase): def setUp(self): + self.openmc_exec_dict = { + "ci": "/opt/openmc/build/bin/openmc", + "laptop": "/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", + "desktop": "/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc", + } + # initialises a new source object my_source = openmc.Source() @@ -18,12 +25,13 @@ def setUp(self): # sets the energy distribution to 100% 14MeV neutrons my_source.energy = openmc.stats.Discrete([14e6], [1]) + self.my_source = my_source + # makes an initial_source.h5 file with details of the particles self.initial_source_filename = osp.create_initial_particles( source=my_source, number_of_particles=10, - openmc_exec="/opt/openmc/build/bin/openmc" - # openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", + openmc_exec=self.openmc_exec_dict['ci'] ) def test_keys(self): @@ -41,3 +49,15 @@ def test_keys(self): data = osp.get_particle_data(self.initial_source_filename) for key in key_values: assert key in data.keys() + + def test_initial_source_output_file(self): + initial_source_filename = osp.create_initial_particles( + source=self.my_source, + number_of_particles=10, + output_source_filename='new_initial_source.h5', + openmc_exec=self.openmc_exec_dict['ci'] + ) + + assert initial_source_filename == 'new_initial_source.h5' + assert Path('new_initial_source.h5').exists() + assert Path('initial_source.h5').exists() is False From ca8dd38d670ae8a1b131f770eacf3a5ee6c534bc Mon Sep 17 00:00:00 2001 From: shimwell Date: Wed, 26 Jan 2022 14:33:26 +0000 Subject: [PATCH 3/7] [skip ci] Apply formatting changes --- openmc_source_plotter/utils.py | 4 ++-- tests/test_utils.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openmc_source_plotter/utils.py b/openmc_source_plotter/utils.py index 90d36bd..eb8b199 100644 --- a/openmc_source_plotter/utils.py +++ b/openmc_source_plotter/utils.py @@ -45,7 +45,7 @@ def create_initial_particles( source: openmc.source, number_of_particles: int = 2000, openmc_exec="openmc", - output_source_filename="initial_source.h5" + output_source_filename="initial_source.h5", ) -> str: """Accepts an openmc source and creates an initial_source.h5 file that can be used to find propties of the source particles such as initial x,y,z @@ -99,4 +99,4 @@ def create_initial_particles( if output_source_filename != "initial_source.h5": shutil.move("initial_source.h5", output_source_filename) - return output_source_filename \ No newline at end of file + return output_source_filename diff --git a/tests/test_utils.py b/tests/test_utils.py index 89fbb34..c4256c2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -31,7 +31,7 @@ def setUp(self): self.initial_source_filename = osp.create_initial_particles( source=my_source, number_of_particles=10, - openmc_exec=self.openmc_exec_dict['ci'] + openmc_exec=self.openmc_exec_dict["ci"], ) def test_keys(self): @@ -52,12 +52,12 @@ def test_keys(self): def test_initial_source_output_file(self): initial_source_filename = osp.create_initial_particles( - source=self.my_source, - number_of_particles=10, - output_source_filename='new_initial_source.h5', - openmc_exec=self.openmc_exec_dict['ci'] - ) - - assert initial_source_filename == 'new_initial_source.h5' - assert Path('new_initial_source.h5').exists() - assert Path('initial_source.h5').exists() is False + source=self.my_source, + number_of_particles=10, + output_source_filename="new_initial_source.h5", + openmc_exec=self.openmc_exec_dict["ci"], + ) + + assert initial_source_filename == "new_initial_source.h5" + assert Path("new_initial_source.h5").exists() + assert Path("initial_source.h5").exists() is False From 9ab5ae3749322bf60f76cc3ab0c76c068e3d08c3 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Wed, 26 Jan 2022 14:55:11 +0000 Subject: [PATCH 4/7] allowing multiple sources to be plotted --- openmc_source_plotter/__init__.py | 1 + openmc_source_plotter/core.py | 39 +++++++++++++++++++++++++++++++ openmc_source_plotter/utils.py | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/openmc_source_plotter/__init__.py b/openmc_source_plotter/__init__.py index c184e2f..f41c64a 100644 --- a/openmc_source_plotter/__init__.py +++ b/openmc_source_plotter/__init__.py @@ -3,3 +3,4 @@ from .core import plot_direction_from_initial_source from .core import plot_position_from_initial_source from .core import plot_energy_from_initial_source +from .core import plot_energy_from_initial_sources diff --git a/openmc_source_plotter/core.py b/openmc_source_plotter/core.py index 70bee75..433f8b5 100644 --- a/openmc_source_plotter/core.py +++ b/openmc_source_plotter/core.py @@ -2,6 +2,7 @@ """Provides functions for plotting source information""" +from typing import List import numpy as np import plotly.graph_objects as go @@ -9,6 +10,44 @@ from .utils import get_particle_data +def plot_energy_from_initial_sources( + energy_bins: np.array = np.linspace(0, 20e6, 50), + input_filenames: List[str] = ["initial_source.h5"], +): + """makes a plot of the energy distribution of multiple sources""" + + fig = go.Figure() + + for input_filename in input_filenames: + print('getting particle data', input_filename) + data = get_particle_data(input_filename) + + e_values = data["e_values"] + + # Calculate pdf for source energies + probability, bin_edges = np.histogram(e_values, energy_bins, density=True) + + # Plot source energy histogram + fig.add_trace( + go.Scatter( + x=energy_bins[:-1], + y=probability * np.diff(energy_bins), + line={"shape": "hv"}, + hoverinfo="text", + name=input_filename, + ) + ) + + fig.update_layout( + title="Particle energy", + xaxis={"title": "Energy (eV)"}, + yaxis={"title": "Probability"}, + showlegend=True, + ) + + return fig + + def plot_energy_from_initial_source( energy_bins: np.array = np.linspace(0, 20e6, 50), input_filename: str = "initial_source.h5", diff --git a/openmc_source_plotter/utils.py b/openmc_source_plotter/utils.py index 90d36bd..269cdd4 100644 --- a/openmc_source_plotter/utils.py +++ b/openmc_source_plotter/utils.py @@ -99,4 +99,4 @@ def create_initial_particles( if output_source_filename != "initial_source.h5": shutil.move("initial_source.h5", output_source_filename) - return output_source_filename \ No newline at end of file + return output_source_filename From fa02f4eabcd0a68ef2d78474aa9f63de22facf74 Mon Sep 17 00:00:00 2001 From: shimwell Date: Wed, 26 Jan 2022 14:55:56 +0000 Subject: [PATCH 5/7] [skip ci] Apply formatting changes --- openmc_source_plotter/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc_source_plotter/core.py b/openmc_source_plotter/core.py index 433f8b5..e70cb30 100644 --- a/openmc_source_plotter/core.py +++ b/openmc_source_plotter/core.py @@ -19,7 +19,7 @@ def plot_energy_from_initial_sources( fig = go.Figure() for input_filename in input_filenames: - print('getting particle data', input_filename) + print("getting particle data", input_filename) data = get_particle_data(input_filename) e_values = data["e_values"] From 0ac7c72b34e4b0d261e2a7e5cb0546f3e2af9d6a Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 26 Jan 2022 20:05:34 +0000 Subject: [PATCH 6/7] updated docs, tests and refactored --- README.md | 30 +-- ...=> example_plot_plasma_source_position.py} | 10 +- ...ce.py => example_plot_source_direction.py} | 10 +- ...ource.py => example_plot_source_energy.py} | 11 +- ...rce.py => example_plot_source_position.py} | 15 +- examples/example_plot_two_source_energies.py | 25 +++ openmc_source_plotter/__init__.py | 8 +- openmc_source_plotter/core.py | 193 ++++++++++-------- tests/test_core.py | 64 ++++++ tests/test_utils.py | 5 +- 10 files changed, 242 insertions(+), 129 deletions(-) rename examples/{example_plot_position_from_initial_plasma_source.py => example_plot_plasma_source_position.py} (78%) rename examples/{example_plot_direction_from_initial_source.py => example_plot_source_direction.py} (51%) rename examples/{example_plot_energy_from_initial_source.py => example_plot_source_energy.py} (64%) rename examples/{example_plot_position_from_initial_source.py => example_plot_source_position.py} (73%) create mode 100644 examples/example_plot_two_source_energies.py create mode 100644 tests/test_core.py diff --git a/README.md b/README.md index 8a1e07a..7ffc7ee 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ A Python package for plotting the locations, directions or energy distributions pip install openmc_source_plotter ``` +temporary fix +For fixed source sources it is currently necessary to use openmc version 0.11 +and also to point the ```openmc_exec``` path to the openmc executable +This can be installed with: +```bash +conda install -c conda-forge openmc=0.11 +``` + + # Features The package provides functions to: @@ -33,15 +42,12 @@ my_source = openmc.Source() # sets the energy distribution to a Muir distribution neutrons for DT fusion neutrons my_source.energy = openmc.stats.Muir(e0=14080000.0, m_rat=5.0, kt=20000.0) -# makes an initial_source.h5 file with details of the particles -osp.create_initial_particles( - source=my_source, - number_of_particles=10000, -) - # plots the particle energy distribution -plot = osp.plot_energy_from_initial_source( - energy_bins=np.linspace(0, 20e6, 100) +plot = osp.plot_source_energy( + source=my_source, + number_of_particles=2000, + energy_bins=np.linspace(0, 20e6, 100), + openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", ) plot.show() @@ -59,15 +65,13 @@ my_source = openmc.Source() # sets the direction to isotropic my_source.angle = openmc.stats.Isotropic() -# makes an initial_source.h5 file with details of the particles -initial_source_filename = osp.create_initial_particles( +# plots the particle energy distribution +plot = osp.plot_source_direction( source=my_source, number_of_particles=100, + openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", ) -# plots the particle energy distribution -plot = osp.plot_direction_from_initial_source(input_filename=initial_source_filename) - plot.show() ``` ![openmc particle source direction plot](https://user-images.githubusercontent.com/8583900/143615706-3b3a8467-0233-42d6-a66c-d536c80a01d8.png) diff --git a/examples/example_plot_position_from_initial_plasma_source.py b/examples/example_plot_plasma_source_position.py similarity index 78% rename from examples/example_plot_position_from_initial_plasma_source.py rename to examples/example_plot_plasma_source_position.py index da2f42f..b1b6f84 100644 --- a/examples/example_plot_position_from_initial_plasma_source.py +++ b/examples/example_plot_plasma_source_position.py @@ -1,6 +1,6 @@ + import openmc_source_plotter as osp from openmc_plasma_source import TokamakSource -import openmc my_source = TokamakSource( elongation=1.557, @@ -21,14 +21,12 @@ ion_temperature_beta=6, ).make_openmc_sources() -# makes an initial_source.h5 file with details of the particles -initial_source_filename = osp.create_initial_particles( + +# plots the particle energy distribution +plot = osp.plot_source_position( source=my_source, number_of_particles=10, openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", ) -# plots the particle energy distribution -plot = osp.plot_position_from_initial_source(input_filename=initial_source_filename) - plot.show() diff --git a/examples/example_plot_direction_from_initial_source.py b/examples/example_plot_source_direction.py similarity index 51% rename from examples/example_plot_direction_from_initial_source.py rename to examples/example_plot_source_direction.py index 148aa5c..8b5b687 100644 --- a/examples/example_plot_direction_from_initial_source.py +++ b/examples/example_plot_source_direction.py @@ -1,3 +1,4 @@ + import openmc_source_plotter as osp import openmc @@ -7,14 +8,11 @@ # sets the direction to isotropic my_source.angle = openmc.stats.Isotropic() -# makes an initial_source.h5 file with details of the particles -initial_source_filename = osp.create_initial_particles( +# plots the particle energy distribution +plot = osp.plot_source_direction( source=my_source, number_of_particles=100, - openmc_exec="/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc", + openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", ) -# plots the particle energy distribution -plot = osp.plot_direction_from_initial_source(input_filename=initial_source_filename) - plot.show() diff --git a/examples/example_plot_energy_from_initial_source.py b/examples/example_plot_source_energy.py similarity index 64% rename from examples/example_plot_energy_from_initial_source.py rename to examples/example_plot_source_energy.py index 56c2c98..5e382b1 100644 --- a/examples/example_plot_energy_from_initial_source.py +++ b/examples/example_plot_source_energy.py @@ -1,3 +1,4 @@ + import openmc_source_plotter as osp import openmc import numpy as np @@ -8,16 +9,12 @@ # sets the energy distribution to a Muir distribution neutrons my_source.energy = openmc.stats.Muir(e0=14080000.0, m_rat=5.0, kt=20000.0) -# makes an initial_source.h5 file with details of the particles -initial_source_filename = osp.create_initial_particles( +# plots the particle energy distribution +plot = osp.plot_source_energy( source=my_source, number_of_particles=10000, + energy_bins=np.linspace(0, 20e6, 100), openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", ) -# plots the particle energy distribution -plot = osp.plot_energy_from_initial_source( - energy_bins=np.linspace(0, 20e6, 100), input_filename=initial_source_filename -) - plot.show() diff --git a/examples/example_plot_position_from_initial_source.py b/examples/example_plot_source_position.py similarity index 73% rename from examples/example_plot_position_from_initial_source.py rename to examples/example_plot_source_position.py index 76ee303..7fdd827 100644 --- a/examples/example_plot_position_from_initial_source.py +++ b/examples/example_plot_source_position.py @@ -1,6 +1,6 @@ + import openmc_source_plotter as osp import openmc -import numpy as np # initialises a new source object my_source = openmc.Source() @@ -19,15 +19,10 @@ r=radius, phi=angle, z=z_values, origin=(0.0, 0.0, 0.0) ) - -# makes an initial_source.h5 file with details of the particles -initial_source_filename = osp.create_initial_particles( - source=my_source, - number_of_particles=10, - openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", -) - # plots the particle energy distribution -plot = osp.plot_position_from_initial_source(input_filename=initial_source_filename) +plot = osp.plot_source_position( + source = my_source, + openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc" +) plot.show() diff --git a/examples/example_plot_two_source_energies.py b/examples/example_plot_two_source_energies.py new file mode 100644 index 0000000..828ab93 --- /dev/null +++ b/examples/example_plot_two_source_energies.py @@ -0,0 +1,25 @@ + +import openmc_source_plotter as osp +import openmc +import numpy as np + +# initialises a new source object +my_dt_source = openmc.Source() + +# sets the energy distribution to a Muir distribution DT neutrons +my_dt_source.energy = openmc.stats.Muir(e0=14080000.0, m_rat=5.0, kt=20000.0) + +# initialises a new source object +my_dd_source = openmc.Source() +# sets the energy distribution to a Muir distribution DD neutrons +my_dd_source.energy = openmc.stats.Muir(e0=2080000.0, m_rat=2.0, kt=20000.0) + +# plots the particle energy distribution +plot = osp.plot_source_energy( + source=[my_dt_source, my_dd_source], + number_of_particles=10000, + energy_bins=np.linspace(0, 20e6, 100), + openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", +) + +plot.show() diff --git a/openmc_source_plotter/__init__.py b/openmc_source_plotter/__init__.py index f41c64a..4a9e58b 100644 --- a/openmc_source_plotter/__init__.py +++ b/openmc_source_plotter/__init__.py @@ -1,6 +1,6 @@ from .utils import get_particle_data from .utils import create_initial_particles -from .core import plot_direction_from_initial_source -from .core import plot_position_from_initial_source -from .core import plot_energy_from_initial_source -from .core import plot_energy_from_initial_sources +from .core import plot_source_direction +from .core import plot_source_energy +from .core import plot_source_position + diff --git a/openmc_source_plotter/core.py b/openmc_source_plotter/core.py index e70cb30..cbda60d 100644 --- a/openmc_source_plotter/core.py +++ b/openmc_source_plotter/core.py @@ -2,25 +2,48 @@ """Provides functions for plotting source information""" -from typing import List +import tempfile +from typing import List, Union import numpy as np +import openmc import plotly.graph_objects as go -from .utils import get_particle_data +from .utils import create_initial_particles, get_particle_data -def plot_energy_from_initial_sources( +def plot_source_energy( + source: Union[openmc.Source, List[openmc.Source]], + number_of_particles: int = 2000, + openmc_exec="openmc", energy_bins: np.array = np.linspace(0, 20e6, 50), - input_filenames: List[str] = ["initial_source.h5"], ): - """makes a plot of the energy distribution of multiple sources""" + """makes a plot of the energy distribution OpenMC source(s) + + Args: + source: The openmc.Source object or list of openmc.Source objects to plot. + number_of_particles: The number of source samples to obtain, more will + take longer but produce a smoother plot. + energy_bins: A numpy array of energy bins to use as energy bins. + openmc_exec: The path of the openmc executable to use + """ fig = go.Figure() - for input_filename in input_filenames: - print("getting particle data", input_filename) - data = get_particle_data(input_filename) + if isinstance(source, openmc.Source): + source = [source] + + for single_source in source: + tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] + create_initial_particles( + source= single_source, + number_of_particles=number_of_particles, + openmc_exec=openmc_exec, + output_source_filename=tmp_filename + ) + + print("getting particle data", tmp_filename) + data = get_particle_data(tmp_filename) e_values = data["e_values"] @@ -34,7 +57,7 @@ def plot_energy_from_initial_sources( y=probability * np.diff(energy_bins), line={"shape": "hv"}, hoverinfo="text", - name=input_filename, + name=tmp_filename, ) ) @@ -48,96 +71,104 @@ def plot_energy_from_initial_sources( return fig -def plot_energy_from_initial_source( - energy_bins: np.array = np.linspace(0, 20e6, 50), - input_filename: str = "initial_source.h5", +def plot_source_position( + source: Union[openmc.Source, List[openmc.Source]], + number_of_particles: int = 2000, + openmc_exec="openmc", ): - """makes a plot of the energy distribution of the source""" + """makes a plot of the initial creation postions of an OpenMC source(s) + + Args: + source: The openmc.Source object or list of openmc.Source objects to plot. + number_of_particles: The number of source samples to obtain. + openmc_exec: The path of the openmc executable to use + """ - data = get_particle_data(input_filename) - - e_values = data["e_values"] - - # Calculate pdf for source energies - probability, bin_edges = np.histogram(e_values, energy_bins, density=True) fig = go.Figure() - # Plot source energy histogram - fig.add_trace( - go.Scatter( - x=energy_bins[:-1], - y=probability * np.diff(energy_bins), - line={"shape": "hv"}, - hoverinfo="text", - name="particle direction", - ) - ) - - fig.update_layout( - title="Particle energy", - xaxis={"title": "Energy (eV)"}, - yaxis={"title": "Probability"}, - ) - - return fig - + if isinstance(source, openmc.Source): + source = [source] -def plot_position_from_initial_source(input_filename="initial_source.h5"): - """makes a plot of the initial creation locations of the particle source""" - - data = get_particle_data(input_filename) + for single_source in source: + tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] + create_initial_particles( + source= single_source, + number_of_particles=number_of_particles, + openmc_exec=openmc_exec, + output_source_filename=tmp_filename + ) - text = ["Energy = " + str(i) + " eV" for i in data["e_values"]] + data = get_particle_data(tmp_filename) - fig = go.Figure() + text = ["Energy = " + str(i) + " eV" for i in data["e_values"]] - fig.add_trace( - go.Scatter3d( - x=data["x_values"], - y=data["y_values"], - z=data["z_values"], - hovertext=text, - text=text, - mode="markers", - marker={ - "size": 2, - "color": data["e_values"], - }, + fig.add_trace( + go.Scatter3d( + x=data["x_values"], + y=data["y_values"], + z=data["z_values"], + hovertext=text, + text=text, + mode="markers", + marker={ + "size": 2, + "color": data["e_values"], + }, + ) ) - ) fig.update_layout(title="Particle production coordinates - coloured by energy") return fig -def plot_direction_from_initial_source(input_filename="initial_source.h5"): - """makes a plot of the initial creation directions of the particle source""" +def plot_source_direction( + source: Union[openmc.Source, List[openmc.Source]], + number_of_particles: int = 2000, + openmc_exec="openmc", +): + """makes a plot of the initial creation directions of the particle source + + Args: + source: The openmc.Source object or list of openmc.Source objects to plot. + number_of_particles: The number of source samples to obtain. + openmc_exec: The path of the openmc executable to use + """ + fig = go.Figure() - data = get_particle_data(input_filename) + if isinstance(source, openmc.Source): + source = [source] - fig = go.Figure() + for single_source in source: + tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] + create_initial_particles( + source= single_source, + number_of_particles=number_of_particles, + openmc_exec=openmc_exec, + output_source_filename=tmp_filename + ) + data = get_particle_data(tmp_filename) - fig.add_trace( - { - "type": "cone", - "cauto": False, - "x": data["x_values"], - "y": data["y_values"], - "z": data["z_values"], - "u": data["x_dir"], - "v": data["y_dir"], - "w": data["z_dir"], - "cmin": 0, - "cmax": 1, - "anchor": "tail", - "colorscale": "Viridis", - "hoverinfo": "u+v+w+norm", - "sizemode": "absolute", - "sizeref": 30, - "showscale": False, - } - ) + fig.add_trace( + { + "type": "cone", + "cauto": False, + "x": data["x_values"], + "y": data["y_values"], + "z": data["z_values"], + "u": data["x_dir"], + "v": data["y_dir"], + "w": data["z_dir"], + "cmin": 0, + "cmax": 1, + "anchor": "tail", + "colorscale": "Viridis", + "hoverinfo": "u+v+w+norm", + "sizemode": "absolute", + "sizeref": 30, + "showscale": False, + } + ) fig.update_layout(title="Particle initial directions") diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..89aab25 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,64 @@ +from numpy import isin +import openmc_source_plotter as osp +import openmc +import unittest +from pathlib import Path +import numpy as np +import plotly.graph_objects as go + +class TestUtils(unittest.TestCase): + def setUp(self): + + self.openmc_exec_dict = { + "ci": "/opt/openmc/build/bin/openmc", + "laptop": "/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", + "desktop": "/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc", + } + self.current_computer = "laptop" + + # initialises a new source object + my_source = openmc.Source() + + # sets the location of the source to x=0 y=0 z=0 + my_source.space = openmc.stats.Point((0, 0, 0)) + + # sets the direction to isotropic + my_source.angle = openmc.stats.Isotropic() + + # sets the energy distribution to 100% 14MeV neutrons + my_source.energy = openmc.stats.Discrete([14e6], [1]) + + self.my_source = my_source + + # makes an initial_source.h5 file with details of the particles + self.initial_source_filename = osp.create_initial_particles( + source=my_source, + number_of_particles=10, + openmc_exec=self.openmc_exec_dict[self.current_computer], + ) + + def test_energy_plot(self): + + plot = osp.plot_source_energy( + source=self.my_source, + number_of_particles=10000, + energy_bins=np.linspace(0, 20e6, 100), + openmc_exec=self.openmc_exec_dict[self.current_computer], + ) + assert isinstance(plot, go.Figure) + + def test_position_plot(self): + + plot = osp.plot_source_position( + source = self.my_source, + openmc_exec=self.openmc_exec_dict[self.current_computer] + ) + assert isinstance(plot, go.Figure) + + def test_direction_plot(self): + plot = osp.plot_source_direction( + source=self.my_source, + number_of_particles=100, + openmc_exec=self.openmc_exec_dict['laptop'], + ) + assert isinstance(plot, go.Figure) diff --git a/tests/test_utils.py b/tests/test_utils.py index c4256c2..2c8648d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -12,6 +12,7 @@ def setUp(self): "laptop": "/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc", "desktop": "/home/jshimwell/miniconda3/envs/openmc_0_11_0/bin/openmc", } + self.current_computer = "laptop" # initialises a new source object my_source = openmc.Source() @@ -31,7 +32,7 @@ def setUp(self): self.initial_source_filename = osp.create_initial_particles( source=my_source, number_of_particles=10, - openmc_exec=self.openmc_exec_dict["ci"], + openmc_exec=self.openmc_exec_dict[self.current_computer], ) def test_keys(self): @@ -55,7 +56,7 @@ def test_initial_source_output_file(self): source=self.my_source, number_of_particles=10, output_source_filename="new_initial_source.h5", - openmc_exec=self.openmc_exec_dict["ci"], + openmc_exec=self.openmc_exec_dict[self.current_computer], ) assert initial_source_filename == "new_initial_source.h5" From b4f7f1eaf6f961947b5aa2f5f3d568dccb49ce12 Mon Sep 17 00:00:00 2001 From: shimwell Date: Wed, 26 Jan 2022 20:05:58 +0000 Subject: [PATCH 7/7] [skip ci] Apply formatting changes --- .../example_plot_plasma_source_position.py | 1 - examples/example_plot_source_direction.py | 1 - examples/example_plot_source_energy.py | 1 - examples/example_plot_source_position.py | 4 +--- examples/example_plot_two_source_energies.py | 1 - openmc_source_plotter/__init__.py | 1 - openmc_source_plotter/core.py | 18 +++++++++--------- tests/test_core.py | 7 ++++--- 8 files changed, 14 insertions(+), 20 deletions(-) diff --git a/examples/example_plot_plasma_source_position.py b/examples/example_plot_plasma_source_position.py index b1b6f84..2a118d8 100644 --- a/examples/example_plot_plasma_source_position.py +++ b/examples/example_plot_plasma_source_position.py @@ -1,4 +1,3 @@ - import openmc_source_plotter as osp from openmc_plasma_source import TokamakSource diff --git a/examples/example_plot_source_direction.py b/examples/example_plot_source_direction.py index 8b5b687..d568f6f 100644 --- a/examples/example_plot_source_direction.py +++ b/examples/example_plot_source_direction.py @@ -1,4 +1,3 @@ - import openmc_source_plotter as osp import openmc diff --git a/examples/example_plot_source_energy.py b/examples/example_plot_source_energy.py index 5e382b1..0c5b221 100644 --- a/examples/example_plot_source_energy.py +++ b/examples/example_plot_source_energy.py @@ -1,4 +1,3 @@ - import openmc_source_plotter as osp import openmc import numpy as np diff --git a/examples/example_plot_source_position.py b/examples/example_plot_source_position.py index 7fdd827..381c763 100644 --- a/examples/example_plot_source_position.py +++ b/examples/example_plot_source_position.py @@ -1,4 +1,3 @@ - import openmc_source_plotter as osp import openmc @@ -21,8 +20,7 @@ # plots the particle energy distribution plot = osp.plot_source_position( - source = my_source, - openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc" + source=my_source, openmc_exec="/home/jshim/miniconda3/envs/openmc_0_11_0/bin/openmc" ) plot.show() diff --git a/examples/example_plot_two_source_energies.py b/examples/example_plot_two_source_energies.py index 828ab93..2bd0dfd 100644 --- a/examples/example_plot_two_source_energies.py +++ b/examples/example_plot_two_source_energies.py @@ -1,4 +1,3 @@ - import openmc_source_plotter as osp import openmc import numpy as np diff --git a/openmc_source_plotter/__init__.py b/openmc_source_plotter/__init__.py index 4a9e58b..50c4954 100644 --- a/openmc_source_plotter/__init__.py +++ b/openmc_source_plotter/__init__.py @@ -3,4 +3,3 @@ from .core import plot_source_direction from .core import plot_source_energy from .core import plot_source_position - diff --git a/openmc_source_plotter/core.py b/openmc_source_plotter/core.py index cbda60d..3643f6f 100644 --- a/openmc_source_plotter/core.py +++ b/openmc_source_plotter/core.py @@ -19,7 +19,7 @@ def plot_source_energy( energy_bins: np.array = np.linspace(0, 20e6, 50), ): """makes a plot of the energy distribution OpenMC source(s) - + Args: source: The openmc.Source object or list of openmc.Source objects to plot. number_of_particles: The number of source samples to obtain, more will @@ -36,10 +36,10 @@ def plot_source_energy( for single_source in source: tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] create_initial_particles( - source= single_source, + source=single_source, number_of_particles=number_of_particles, openmc_exec=openmc_exec, - output_source_filename=tmp_filename + output_source_filename=tmp_filename, ) print("getting particle data", tmp_filename) @@ -77,7 +77,7 @@ def plot_source_position( openmc_exec="openmc", ): """makes a plot of the initial creation postions of an OpenMC source(s) - + Args: source: The openmc.Source object or list of openmc.Source objects to plot. number_of_particles: The number of source samples to obtain. @@ -92,10 +92,10 @@ def plot_source_position( for single_source in source: tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] create_initial_particles( - source= single_source, + source=single_source, number_of_particles=number_of_particles, openmc_exec=openmc_exec, - output_source_filename=tmp_filename + output_source_filename=tmp_filename, ) data = get_particle_data(tmp_filename) @@ -128,7 +128,7 @@ def plot_source_direction( openmc_exec="openmc", ): """makes a plot of the initial creation directions of the particle source - + Args: source: The openmc.Source object or list of openmc.Source objects to plot. number_of_particles: The number of source samples to obtain. @@ -142,10 +142,10 @@ def plot_source_direction( for single_source in source: tmp_filename = tempfile.mkstemp(suffix=".h5", prefix=f"openmc_source_")[1] create_initial_particles( - source= single_source, + source=single_source, number_of_particles=number_of_particles, openmc_exec=openmc_exec, - output_source_filename=tmp_filename + output_source_filename=tmp_filename, ) data = get_particle_data(tmp_filename) diff --git a/tests/test_core.py b/tests/test_core.py index 89aab25..b2b17bf 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6,6 +6,7 @@ import numpy as np import plotly.graph_objects as go + class TestUtils(unittest.TestCase): def setUp(self): @@ -50,8 +51,8 @@ def test_energy_plot(self): def test_position_plot(self): plot = osp.plot_source_position( - source = self.my_source, - openmc_exec=self.openmc_exec_dict[self.current_computer] + source=self.my_source, + openmc_exec=self.openmc_exec_dict[self.current_computer], ) assert isinstance(plot, go.Figure) @@ -59,6 +60,6 @@ def test_direction_plot(self): plot = osp.plot_source_direction( source=self.my_source, number_of_particles=100, - openmc_exec=self.openmc_exec_dict['laptop'], + openmc_exec=self.openmc_exec_dict["laptop"], ) assert isinstance(plot, go.Figure)