From 9400a700b5e5eb973f2be3e633d5d2002e86ede3 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Mon, 21 Jun 2021 22:52:52 +0100 Subject: [PATCH 1/2] removed neutronics files --- paramak/neutronics_utils.py | 839 ------------------ paramak/parametric_neutronics/__init__.py | 0 .../parametric_neutronics/neutronics_model.py | 745 ---------------- 3 files changed, 1584 deletions(-) delete mode 100644 paramak/neutronics_utils.py delete mode 100644 paramak/parametric_neutronics/__init__.py delete mode 100644 paramak/parametric_neutronics/neutronics_model.py diff --git a/paramak/neutronics_utils.py b/paramak/neutronics_utils.py deleted file mode 100644 index 01381fe9e..000000000 --- a/paramak/neutronics_utils.py +++ /dev/null @@ -1,839 +0,0 @@ - -import math -import os -import shutil -import subprocess -import warnings -from collections import defaultdict -from pathlib import Path -from typing import List, Optional -from xml.etree.ElementTree import SubElement - -import defusedxml.ElementTree as ET -import matplotlib.pyplot as plt -import numpy as np -from remove_dagmc_tags import remove_tags - - -def find_material_groups_in_h5m( - filename: Optional[str] = 'dagmc.h5m' -) -> List[str]: - """Reads in a DAGMC h5m file and uses mbsize to find the names of the - material groups in the file - - Arguments: - filename: - - Returns: - The filename of the h5m file created - """ - - try: - terminal_output = subprocess.check_output( - "mbsize -ll {} | grep 'mat:'".format(filename), - shell=True, - universal_newlines=True, - ) - except BaseException: - raise ValueError( - "mbsize failed, check MOAB is install and the MOAB/build/bin " - "folder is in the path directory (Linux and Mac) or set as an " - "enviromental varible (Windows)") - - list_of_mats = terminal_output.split() - list_of_mats = list(filter(lambda a: a != '=', list_of_mats)) - list_of_mats = list(filter(lambda a: a != 'NAME', list_of_mats)) - list_of_mats = list(filter(lambda a: a != 'EXTRA_NAME0', list_of_mats)) - list_of_mats = list(set(list_of_mats)) - - return list_of_mats - - -def trelis_command_to_create_dagmc_h5m( - faceting_tolerance: float, - merge_tolerance: float, - material_key_name: Optional[str] = 'material_tag', - geometry_key_name: Optional[str] = 'stp_filename', - batch: Optional[bool] = True, - h5m_filename: str = 'dagmc_not_watertight.h5m', - manifest_filename: str = 'manifest.json', - cubit_filename: str = 'dagmc.cub', - trelis_filename: str = 'dagmc.trelis', - geometry_details_filename: str = 'geometry_details.json', - surface_reflectivity_name: str = 'reflective', -) -> List[str]: - """Runs the Trelis executable command with the - make_faceteted_neutronics_model.py script which produces a non water tight - DAGMC h5m file. - - Arguments: - faceting_tolerance: the tolerance to use when faceting surfaces. - merge_tolerance: the tolerance to use when merging surfaces. - material_key_name: the dictionary key containing the str or int to use - as the material identifier. - geometry_key_name: the dictionary key containing the str to uses as the - CAD file identifier. - batch: Run the Trelis command in batch model with no GUI (True) or with - the GUI enabled (False). - h5m_filename: the filename of the DAGMC h5m file produced. This is not - water tight at this stage. - manifest_filename: The filename of the json file containing a list of - material_keys and geometry_keys. - cubit_filename: The output filename of the file. If None then no cubit - file will be exported. - trelis_filename: The output filename of the file. If None then no - trelis file will be exported. - geometry_details_filename: The output filename of the JSON file - containing details of the DAGMC geometry. This includes the - resulting volume numbers of the input CAD files, which can be - useful for specifying tallies. If None then no JSON fie will be - exported. - surface_reflectivity_name: The tag to assign to the reflective boundary - in the resulting DAGMC geometry Shift requires "spec.reflect" and - MCNP requires "boundary:Reflecting". - - Returns: - The filename of the h5m file created - """ - output_filenames = [ - h5m_filename, - trelis_filename, - cubit_filename, - geometry_details_filename] - filenames_extensions = ['.h5m', '.trelis', '.cub', '.json'] - - path_output_filenames = [] - - for output_file, extension in zip(output_filenames, filenames_extensions): - - if output_file is not None: - path_filename = Path(output_file) - - if path_filename.suffix != extension: - path_filename = path_filename.with_suffix(extension) - - path_filename.parents[0].mkdir(parents=True, exist_ok=True) - - path_output_filenames.append(str(path_filename)) - - shutil.copy( - src=Path(__file__).parent.absolute() / Path('parametric_neutronics') / - 'make_faceteted_neutronics_model.py', - dst=Path().absolute() - ) - - if not Path("make_faceteted_neutronics_model.py").is_file(): - raise FileNotFoundError( - "The make_faceteted_neutronics_model.py was not found in the \ - directory") - - os.system('rm dagmc_not_watertight.h5m') - - if batch: - trelis_cmd = 'trelis -batch -nographics' - else: - trelis_cmd = 'trelis' - - os.system( - trelis_cmd + - " make_faceteted_neutronics_model.py \"faceting_tolerance='" + - str(faceting_tolerance) + - "'\" \"merge_tolerance='" + - str(merge_tolerance) + - "'\" \"material_key_name='" + - str(material_key_name) + - "'\" \"geometry_key_name='" + - str(geometry_key_name) + - "'\" \"h5m_filename='" + - str(h5m_filename) + - "'\" \"manifest_filename='" + - str(manifest_filename) + - "'\" \"cubit_filename='" + - str(cubit_filename) + - "'\" \"trelis_filename='" + - str(trelis_filename) + - "'\" \"geometry_details_filename='" + - str(geometry_details_filename) + - "'\" \"surface_reflectivity_name='" + - str(surface_reflectivity_name) + - "'\"") - - os.system('rm make_faceteted_neutronics_model.py') - - if not Path(h5m_filename).is_file(): - raise FileNotFoundError( - "The h5m file " + h5m_filename + " was not found \ - in the directory, the Trelis stage has failed") - - return path_output_filenames - - -def make_watertight( - input_filename: str = "dagmc_not_watertight.h5m", - output_filename: str = "dagmc.h5m", -) -> str: - """Runs the DAGMC make_watertight executable that seals the facetets of - the geometry with specified input and output h5m files. Not needed for - h5m file produced with pymoab method. - - Arguments: - input_filename: the non watertight h5m file to make watertight. - output_filename: the filename of the watertight h5m file. - - Returns: - The filename of the h5m file created - """ - - if not Path(input_filename).is_file(): - raise FileNotFoundError("Failed to find {}".format(input_filename)) - - os.system('rm {}'.format(output_filename)) - - try: - output = subprocess.check_output( - "make_watertight {} -o {}".format(input_filename, output_filename), - shell=True, - universal_newlines=True, - ) - print(output) - except BaseException: - raise NameError( - "make_watertight failed, check DAGMC is install and the DAGMC/bin " - "folder is in the path directory (Linux and Mac) or set as an " - "enviromental varible (Windows)") - - if not Path(output_filename).is_file(): - raise FileNotFoundError("Failed to produce dagmc.h5m") - - return output_filename - - -def define_moab_core_and_tags(): - """Creates a MOAB Core instance which can be built up by adding sets of - triangles to the instance - - Returns: - (pymoab Core): A pymoab.core.Core() instance - (pymoab tag_handle): A pymoab.core.tag_get_handle() instance - """ - - try: - from pymoab import core, types - except ImportError: - raise ImportError( - 'PyMoab not found, export_h5m method is not available') - - # create pymoab instance - moab_core = core.Core() - - tags = dict() - - sense_tag_name = "GEOM_SENSE_2" - sense_tag_size = 2 - tags['surf_sense'] = moab_core.tag_get_handle( - sense_tag_name, - sense_tag_size, - types.MB_TYPE_HANDLE, - types.MB_TAG_SPARSE, - create_if_missing=True) - - tags['category'] = moab_core.tag_get_handle( - types.CATEGORY_TAG_NAME, - types.CATEGORY_TAG_SIZE, - types.MB_TYPE_OPAQUE, - types.MB_TAG_SPARSE, - create_if_missing=True) - tags['name'] = moab_core.tag_get_handle( - types.NAME_TAG_NAME, - types.NAME_TAG_SIZE, - types.MB_TYPE_OPAQUE, - types.MB_TAG_SPARSE, - create_if_missing=True) - tags['geom_dimension'] = moab_core.tag_get_handle( - types.GEOM_DIMENSION_TAG_NAME, - 1, - types.MB_TYPE_INTEGER, - types.MB_TAG_DENSE, - create_if_missing=True) - - # Global ID is a default tag, just need the name to retrieve - tags['global_id'] = moab_core.tag_get_handle(types.GLOBAL_ID_TAG_NAME) - - return moab_core, tags - - -def export_vtk( - h5m_filename: str, - filename: Optional[str] = 'dagmc.vtk', - include_graveyard: Optional[bool] = False -): - """Produces a vtk geometry compatable from the dagmc h5m file. This is - useful for checking the geometry that is used for transport. - - Arguments: - filename: filename of vtk outputfile. If the filename does not end - with .vtk then .vtk will be added. - h5m_filename: filename of h5m outputfile. If the filename does not - end with .h5m then .h5m will be added. - include_graveyard: optionally include the graveyard in the vtk file - - Returns: - filename of the vtk file produced - """ - - path_h5m_filename = Path(h5m_filename) - if path_h5m_filename.suffix != ".h5m": - path_h5m_filename = path_h5m_filename.with_suffix(".h5m") - - if path_h5m_filename.is_file() is False: - raise FileNotFoundError( - 'h5m_filename not found in location', path_h5m_filename - ) - - path_filename = Path(filename) - if path_filename.suffix != ".vtk": - path_filename = path_filename.with_suffix(".vtk") - - if include_graveyard: - tags_to_remove = None - else: - tags_to_remove = [ - 'graveyard.stp', - 'mat:graveyard', - 'reflective', - 'mat:vacuum', - 'cuttingwedge.stp'] - remove_tags( - input=str(path_h5m_filename), - output=str(path_filename), - tags=tags_to_remove - ) - - return str(path_filename) - - -def remove_tag_from_h5m_file( - input_h5m_filename: Optional[str] = 'dagmc.h5m', - output_h5m_filename: Optional[str] = 'dagmc_removed_tag.h5m', - tag_to_remove: Optional[str] = 'graveyard', -) -> str: - """Removes a specific tag from a dagmc h5m file and saves the remaining - geometry as a new h5m file. Useful for visulising the geometry by removing - the graveyard tag and then the vtk file can be made without a bounding box - graveyard obstructing the view. Adapted from - https://github.com/svalinn/DAGMC-viz source code - - Arguments: - input_h5m_filename: The name of the h5m file to remove the graveyard from - output_h5m_filename: The name of the outfile h5m without a graveyard - - Returns: - filename of the new dagmc h5m file with the tags removed - """ - - try: - from pymoab import core, types - from pymoab.types import MBENTITYSET - except ImportError: - raise ImportError( - 'PyMoab not found, remove_tag_from_h5m_file method is not ' - 'available' - ) - - moab_core = core.Core() - moab_core.load_file(input_h5m_filename) - - tag_name = moab_core.tag_get_handle(str(types.NAME_TAG_NAME)) - - tag_category = moab_core.tag_get_handle(str(types.CATEGORY_TAG_NAME)) - root = moab_core.get_root_set() - - # An array of tag values to be matched for entities returned by the - # following call. - group_tag_values = np.array(["Group"]) - - # Retrieve all EntitySets with a category tag of the user input value. - group_categories = list(moab_core.get_entities_by_type_and_tag( - root, MBENTITYSET, tag_category, group_tag_values)) - - # Retrieve all EntitySets with a name tag. - group_names = moab_core.tag_get_data(tag_name, group_categories, flat=True) - - # Find the EntitySet whose name includes tag provided - sets_to_remove = [ - group_set for group_set, - name in zip( - group_categories, - group_names) if tag_to_remove in str( - name.lower())] - - # Remove the graveyard EntitySet from the data. - groups_to_write = [ - group_set for group_set in group_categories if group_set not in sets_to_remove] - - moab_core.write_file(output_h5m_filename, output_sets=groups_to_write) - - return output_h5m_filename - - -def add_stl_to_moab_core( - moab_core, - surface_id: int, - volume_id: int, - material_name: str, - tags, - stl_filename: str): - """Computes the m and c coefficients of the equation (y=mx+c) for - a straight line from two points. - - Args: - moab_core (pymoab.core.Core): - surface_id (int): the id number to apply to the surface - volume_id (int): the id numbers to apply to the volumes - material_name (str): the material tag name to add. the value provided - will be prepended with "mat:" unless it is "reflective" which is - a special case and therefore will remain as is. - tags (pymoab tag_handle): the MOAB tags - stl_filename (str): the filename of the stl file to load into the moab - core - - Returns: - (pymoab Core): An updated pymoab.core.Core() instance - """ - - surface_set = moab_core.create_meshset() - volume_set = moab_core.create_meshset() - - # recent versions of MOAB handle this automatically - # but best to go ahead and do it manually - moab_core.tag_set_data(tags['global_id'], volume_set, volume_id) - - moab_core.tag_set_data(tags['global_id'], surface_set, surface_id) - - # set geom IDs - moab_core.tag_set_data(tags['geom_dimension'], volume_set, 3) - moab_core.tag_set_data(tags['geom_dimension'], surface_set, 2) - - # set category tag values - moab_core.tag_set_data(tags['category'], volume_set, "Volume") - moab_core.tag_set_data(tags['category'], surface_set, "Surface") - - # establish parent-child relationship - moab_core.add_parent_child(volume_set, surface_set) - - # set surface sense - sense_data = [volume_set, np.uint64(0)] - moab_core.tag_set_data(tags['surf_sense'], surface_set, sense_data) - - # load the stl triangles/vertices into the surface set - moab_core.load_file(stl_filename, surface_set) - - group_set = moab_core.create_meshset() - moab_core.tag_set_data(tags['category'], group_set, "Group") - - # reflective is a special case that should not have mat: in front - if not material_name == 'reflective': - dag_material_tag = "mat:{}".format(material_name) - else: - dag_material_tag = material_name - - moab_core.tag_set_data( - tags['name'], - group_set, - dag_material_tag - ) - moab_core.tag_set_data(tags['geom_dimension'], group_set, 4) - - # add the volume to this group set - moab_core.add_entity(group_set, volume_set) - - return moab_core - - -def _save_2d_mesh_tally_as_png( - score: str, - filename: str, - tally -) -> str: - """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: - from openmc import MeshFilter - 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=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() - - return filename - - -def get_neutronics_results_from_statepoint_file( - statepoint_filename: str, - fusion_power: Optional[float] = None -) -> dict: - """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: - from openmc import StatePoint - from openmc.mgxs import GROUP_STRUCTURES - except ImportError as err: - raise err( - 'openmc not found, get_neutronics_results_from_statepoint_file \ - method is not available') - - # open the results file - statepoint = 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, - } - - elif 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)), - } - - elif 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, - } - - elif 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': GROUP_STRUCTURES['CCFE-709'].tolist(), - 'result': tally_result.tolist(), - 'std. dev.': tally_std_dev.tolist(), - } - - elif '_on_2D_mesh' in tally.name: - score = tally.name.split('_')[0] - _save_2d_mesh_tally_as_png( - score=score, - tally=tally, - filename=tally.name.replace( - '(', - '').replace( - ')', - '').replace( - ',', - '-')) - - elif '_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.replace( - '(', - '').replace( - ')', - '').replace( - ',', - '-') + - '.vtk') - - else: - # this must be a standard score cell tally - data_frame = tally.get_pandas_dataframe() - tally_result = data_frame["mean"].sum() - tally_std_dev = data_frame['std. dev.'].sum() - results[tally.name]['events per source particle'] = { - 'result': tally_result, - 'std. dev.': tally_std_dev, - } - - return results - - -def write_3d_mesh_tally_to_vtk( - xs: np.linspace, - ys: np.linspace, - zs: np.linspace, - tally_data: List[float], - error_data: Optional[List[float]] = None, - outfile: Optional[str] = '3d_mesh_tally_data.vtk', - tally_label: Optional[str] = '3d_mesh_tally_data', -) -> str: - """Converts regular 3d data into a vtk file for visualising the data. - Programs that can visualise vtk files include Paraview - https://www.paraview.org/ and VisIt - https://wci.llnl.gov/simulation/computer-codes/visit - - Arguments: - xs: A numpy array containing evenly spaced numbers from the lowest x - coordinate value to the highest x coordinate value. - ys: A numpy array containing evenly spaced numbers from the lowest y - coordinate value to the highest y coordinate value. - zs: A numpy array containing evenly spaced numbers from the lowest z - coordinate value to the highest z coordinate value. - tally_data: A list of data values to assign to the vtk dataset. - error_data: A list of error data values to assign to the vtk dataset. - outfile: The filename of the output vtk file. - tally_label: The name to assign to the dataset in the vtk file. - - Returns: - str: the filename of the file produced - """ - try: - import vtk - except (ImportError, ModuleNotFoundError): - msg = "Conversion to VTK requested," \ - "but the Python VTK module is not installed. Try pip install pyvtk" - 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) - - if error_data is not None: - 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() - - return outfile - - -def create_inital_particles( - source, - number_of_source_particles: int = 2000 -) -> str: - """Accepts an openmc source and creates an inital_source.h5 that can be - used to find intial xyz, direction and energy of the partice source. - - Arguments: - source: (openmc.Source()): the OpenMC source to create an inital source - file from. - number_of_source_particles: The number of particle to sample. - - Returns: - str: the filename of the h5 file produced - """ - try: - from openmc import Materials, Sphere, Cell, Universe, Geometry, \ - Settings, run - from openmc.model import Model - except ImportError as err: - raise err( - 'openmc not found, _save_2d_mesh_tally_as_png method is not \ - available') - # MATERIALS - - # no real materials are needed for finding the source - mats = Materials([]) - - # GEOMETRY - - # just a minimal geometry - outer_surface = Sphere(r=100000, boundary_type='vacuum') - cell = Cell(region=-outer_surface) - universe = Universe(cells=[cell]) - geom = Geometry(universe) - - # SIMULATION SETTINGS - - # Instantiate a Settings object - sett = Settings() - # this will fail but it will write the inital_source.h5 file first - sett.run_mode = "eigenvalue" - sett.particles = number_of_source_particles - sett.batches = 1 - sett.inactive = 0 - sett.write_initial_source = True - - sett.source = source - - model = Model(geom, mats, sett) - - os.system('rm *.xml') - model.export_to_xml() - - # this just adds write_initial_source == True to the settings.xml - tree = ET.parse("settings.xml") - root = tree.getroot() - elem = SubElement(root, "write_initial_source") - elem.text = "true" - tree.write("settings.xml") - - # This will crash hence the try except loop, but it writes the - # inital_source.h5 - try: - run(output=False) - except BaseException: - pass - - return "initial_source.h5" - - -def extract_points_from_initial_source( - input_filename: str = 'initial_source.h5', - view_plane: str = 'RZ' -) -> list: - """Reads in an inital source h5 file (generated by OpenMC), extracts point - and projects them onto a view plane. - - Arguments: - input_filename: the OpenMC source to create an inital source - file from. - view_plane: The plane to project. Options are 'XZ', 'XY', 'YZ', - 'YX', 'ZY', 'ZX', 'RZ' and 'XYZ'. Defaults to 'RZ'. Defaults to - 'RZ'. - - Returns: - list: list of points extracted - """ - import h5py - h5_file = h5py.File(input_filename, 'r') - dset = h5_file['source_bank'] - - points = [] - - for particle in dset: - if view_plane == 'XZ': - points.append((particle[0][0], particle[0][2])) - elif view_plane == 'XY': - points.append((particle[0][0], particle[0][1])) - elif view_plane == 'YZ': - points.append((particle[0][1], particle[0][2])) - elif view_plane == 'YX': - points.append((particle[0][1], particle[0][0])) - elif view_plane == 'ZY': - points.append((particle[0][2], particle[0][1])) - elif view_plane == 'ZX': - points.append((particle[0][2], particle[0][0])) - elif view_plane == 'RZ': - xy_coord = math.pow(particle[0][0], 2) + \ - math.pow(particle[0][1], 2) - points.append((math.sqrt(xy_coord), particle[0][2])) - elif view_plane == 'XYZ': - points.append((particle[0][0], particle[0][1], particle[0][2])) - else: - raise ValueError('view_plane value of ', view_plane, - ' is not supported') - return points diff --git a/paramak/parametric_neutronics/__init__.py b/paramak/parametric_neutronics/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/paramak/parametric_neutronics/neutronics_model.py b/paramak/parametric_neutronics/neutronics_model.py deleted file mode 100644 index d805a7f5d..000000000 --- a/paramak/parametric_neutronics/neutronics_model.py +++ /dev/null @@ -1,745 +0,0 @@ - -import json -import os -import warnings -from pathlib import Path -from typing import List, Optional, Tuple, Union - -import paramak -from paramak import get_neutronics_results_from_statepoint_file -from paramak.neutronics_utils import (create_inital_particles, - extract_points_from_initial_source) -from paramak.utils import plotly_trace - -try: - import openmc - from openmc.data import REACTION_MT, REACTION_NAME -except ImportError: - warnings.warn('OpenMC not found, NeutronicsModelFromReactor.simulate \ - method not available', UserWarning) - -try: - import neutronics_material_maker as nmm -except ImportError: - warnings.warn("neutronics_material_maker not found, \ - NeutronicsModelFromReactor.materials can't accept strings or \ - neutronics_material_maker objects", UserWarning) - - -class NeutronicsModel(): - """Creates a neutronics model of the provided shape geometry with assigned - materials, source and neutronics tallies. - - Arguments: - geometry: The geometry to convert to a neutronics model. e.g. - geometry=paramak.RotateMixedShape() or - geometry=paramak.BallReactor(). - source (openmc.Source()): the particle source to use during the - OpenMC simulation. - materials: Where the dictionary keys are the material tag - and the dictionary values are either a string, openmc.Material, - neutronics-material-maker.Material or - neutronics-material-maker.MultiMaterial. All components within the - geometry object must be accounted for. Material tags required - for a Reactor or Shape can be obtained with .material_tags() and - material_tag respectively. - simulation_batches: the number of batch to simulate. - simulation_particles_per_batch: particles per batch. - cell_tallies: the cell based tallies to calculate, options include - spectra, TBR, heating, flux, MT numbers and OpenMC standard scores - such as (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores - mesh_tally_2d: the 2D mesh based tallies to calculate, options include - heating and flux , MT numbers and OpenMC standard scores such as - (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores - mesh_tally_3d: the 3D mesh based tallies to calculate, - options include heating and flux , MT numbers and OpenMC standard - scores such as (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores - mesh_3d_resolution: The 3D mesh resolution in the height, width and - depth directions. The larger the resolution the finer the mesh and - the more computational intensity is required to converge each mesh - element. - mesh_2d_resolution: The 3D mesh resolution in the height and width - directions. The larger the resolution the finer the mesh and more - computational intensity is required to converge each mesh element. - mesh_2d_corners: The upper and lower corner locations for the 2d - mesh. This sets the location of the mesh. Defaults to None which - uses the NeutronicsModel.geometry.largest_dimension property to set - the corners. - mesh_3d_corners: The upper and lower corner locations for the 3d - mesh. This sets the location of the mesh. Defaults to None which - uses the NeutronicsModel.geometry.largest_dimension property to set - the corners. - fusion_power: the power in watts emitted by the fusion reaction - recalling that each DT fusion reaction emitts 17.6 MeV or - 2.819831e-12 Joules - """ - - def __init__( - self, - geometry: Union[paramak.Reactor, paramak.Shape], - source, - materials: dict, - simulation_batches: Optional[int] = 100, - simulation_particles_per_batch: Optional[int] = 10000, - cell_tallies: Optional[List[str]] = None, - mesh_tally_2d: Optional[List[str]] = None, - mesh_tally_3d: Optional[List[str]] = None, - mesh_2d_resolution: Optional[Tuple[int, int, int]] = (400, 400), - mesh_3d_resolution: Optional[Tuple[int, int, int]] = (100, 100, 100), - mesh_2d_corners: Optional[Tuple[Tuple[float, float, - float], Tuple[float, float, float]]] = None, - mesh_3d_corners: Optional[Tuple[Tuple[float, float, - float], Tuple[float, float, float]]] = None, - fusion_power: Optional[float] = 1e9, - photon_transport: Optional[bool] = True, - # convert from watts to activity source_activity - max_lost_particles: Optional[int] = 10, - ): - - self.materials = materials - self.geometry = geometry - 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.mesh_2d_resolution = mesh_2d_resolution - self.mesh_3d_resolution = mesh_3d_resolution - self.mesh_2d_corners = mesh_2d_corners - self.mesh_3d_corners = mesh_3d_corners - self.photon_transport = photon_transport - self.fusion_power = fusion_power - - self.model = None - self.results = None - self.tallies = None - self.output_filename = None - self.statepoint_filename = None - - @property - def geometry(self): - return self._geometry - - @geometry.setter - def geometry(self, value): - if isinstance(value, (paramak.Shape, paramak.Reactor, type(None))): - self._geometry = value - else: - raise TypeError( - "NeutronicsModelFromReactor.geometry should be a \ - paramak.Shape(), paramak.Reactor()") - - @property - def source(self): - return self._source - - @source.setter - def source(self, value): - if not isinstance(value, (openmc.Source, type(None))): - raise TypeError( - "NeutronicsModelFromReactor.source should be an \ - openmc.Source() object") - self._source = value - - @property - def cell_tallies(self): - return self._cell_tallies - - @cell_tallies.setter - def cell_tallies(self, value): - if value is not None: - if not isinstance(value, list): - raise TypeError( - "NeutronicsModelFromReactor.cell_tallies should be a\ - list") - output_options = ['TBR', 'heating', 'flux', 'spectra', 'absorption'] + \ - list(REACTION_MT.keys()) + list(REACTION_NAME.keys()) - for entry in value: - if entry not in output_options: - raise ValueError( - "NeutronicsModelFromReactor.cell_tallies argument", - entry, - "not allowed, the following options are supported", - output_options) - self._cell_tallies = value - - @property - def mesh_tally_2d(self): - return self._mesh_tally_2d - - @mesh_tally_2d.setter - def mesh_tally_2d(self, value): - if value is not None: - if not isinstance(value, list): - raise TypeError( - "NeutronicsModelFromReactor.mesh_tally_2d should be a\ - list") - output_options = ['heating', 'flux', 'absorption'] + \ - list(REACTION_MT.keys()) + list(REACTION_NAME.keys()) - for entry in value: - if entry not in output_options: - raise ValueError( - "NeutronicsModelFromReactor.mesh_tally_2d argument", - entry, - "not allowed, the following options are supported", - 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 = ['heating', 'flux', 'absorption'] + \ - list(REACTION_MT.keys()) + list(REACTION_NAME.keys()) - 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 - - @materials.setter - def materials(self, value): - if not isinstance(value, dict): - raise TypeError("NeutronicsModelFromReactor.materials should be a\ - dictionary") - self._materials = value - - @property - def simulation_batches(self): - return self._simulation_batches - - @simulation_batches.setter - def simulation_batches(self, value): - if isinstance(value, float): - value = int(value) - if not isinstance(value, int): - raise TypeError( - "NeutronicsModelFromReactor.simulation_batches should be an int") - if value < 2: - raise ValueError( - "The minimum of setting for simulation_batches is 2" - ) - self._simulation_batches = value - - @property - def simulation_particles_per_batch(self): - return self._simulation_particles_per_batch - - @simulation_particles_per_batch.setter - def simulation_particles_per_batch(self, value): - if isinstance(value, float): - value = int(value) - if not isinstance(value, int): - raise TypeError( - "NeutronicsModelFromReactor.simulation_particles_per_batch\ - should be an int") - self._simulation_particles_per_batch = value - - def create_material(self, material_tag: str, material_entry): - if isinstance(material_entry, str): - openmc_material = nmm.Material.from_library( - name=material_entry, material_id=None).openmc_material - elif isinstance(material_entry, openmc.Material): - # sets the material name in the event that it had not been set - openmc_material = material_entry - elif isinstance(material_entry, (nmm.Material)): - # sets the material tag in the event that it had not been set - openmc_material = material_entry.openmc_material - else: - raise TypeError("materials must be either a str, \ - openmc.Material, nmm.MultiMaterial or nmm.Material object \ - not a ", type(material_entry), material_entry) - openmc_material.name = material_tag - return openmc_material - - def create_openmc_materials(self): - # # checks all the required materials are present - # for reactor_material in self.geometry.material_tags: - # if reactor_material not in self.materials.keys(): - # raise ValueError( - # "material included by the reactor model has not \ - # been added", reactor_material) - - # # checks that no extra materials we added - # for reactor_material in self.materials.keys(): - # if reactor_material not in self.geometry.material_tags: - # raise ValueError( - # "material has been added that is not needed for this \ - # reactor model", reactor_material) - - os.system('rm materials.xml') - - openmc_materials = {} - for material_tag, material_entry in self.materials.items(): - openmc_material = self.create_material( - material_tag, material_entry) - openmc_materials[material_tag] = openmc_material - - self.openmc_materials = openmc_materials - - self.mats = openmc.Materials(list(self.openmc_materials.values())) - - self.mats.export_to_xml() - - return self.mats - - def export_xml( - self, - simulation_batches: Optional[int] = None, - source=None, - max_lost_particles: Optional[int] = None, - simulation_particles_per_batch: Optional[int] = None, - mesh_tally_3d: Optional[float] = None, - mesh_tally_2d: Optional[float] = None, - cell_tallies: Optional[float] = None, - mesh_2d_resolution: Optional[Tuple[int, int, int]] = None, - mesh_3d_resolution: Optional[Tuple[int, int, int]] = None, - mesh_2d_corners: Optional[Tuple[Tuple[float, float, float], Tuple[float, float, float]]] = None, - mesh_3d_corners: Optional[Tuple[Tuple[float, float, float], Tuple[float, float, float]]] = None, - ): - """Uses OpenMC python API to make a neutronics model, including tallies - (cell_tallies and mesh_tally_2d), simulation settings (batches, - particles per batch). - - Arguments: - simulation_batches: the number of batch to simulate. - source: (openmc.Source): the particle source to use during the - OpenMC simulation. Defaults to NeutronicsModel.source - max_lost_particles: The maximum number of particles that can be - lost during the simuation before terminating the simulation. - Defaults to None which uses the - NeutronicsModel.max_lost_particles attribute. - simulation_particles_per_batch: particles simulated per batch. - Defaults to None which uses the - NeutronicsModel.simulation_particles_per_batch attribute. - mesh_tally_3d: the 3D mesh based tallies to calculate, options - include heating and flux , MT numbers and OpenMC standard - scores such as (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores. - Defaults to None which uses the NeutronicsModel.mesh_tally_3d - attribute. - mesh_tally_2d: . the 2D mesh based tallies to calculate, options - include heating and flux , MT numbers and OpenMC standard - scores such as (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores . - Defaults to None which uses the NeutronicsModel.mesh_tally_2d - attribute. - cell_tallies: the cell based tallies to calculate, options include - TBR, heating, flux, MT numbers and OpenMC standard scores such - as (n,Xa) which is helium production are also supported - https://docs.openmc.org/en/latest/usersguide/tallies.html#scores. - Defaults to None which uses the NeutronicsModel.cell_tallies - attribute. - mesh_2d_resolution: The 2D mesh resolution in the height and - width directions. The larger the resolution the finer the mesh - and more computational intensity is required to converge each - mesh element. Defaults to None which uses the - NeutronicsModel.mesh_2d_resolution attribute - mesh_3d_resolution: The 3D mesh resolution in the height, width - and depth directions. The larger the resolution the finer the - mesh and the more computational intensity is required to - converge each mesh element. Defaults to None which uses the - NeutronicsModel.mesh_3d_resolution attribute. - mesh_2d_corners: The upper and lower corner locations for the 2d - mesh. Defaults to None which uses the - NeutronicsModel.mesh_2d_corners - mesh_3d_corners: The upper and lower corner locations for the 2d - mesh. Defaults to None which uses the - NeutronicsModel.mesh_2d_corners - - Returns: - openmc.model.Model(): The openmc model object created - """ - - if simulation_batches is None: - simulation_batches = self.simulation_batches - if source is None: - source = self.source - if max_lost_particles is None: - max_lost_particles = self.max_lost_particles - if simulation_particles_per_batch is None: - simulation_particles_per_batch = self.simulation_particles_per_batch - if mesh_tally_3d is None: - mesh_tally_3d = self.mesh_tally_3d - if mesh_tally_2d is None: - mesh_tally_2d = self.mesh_tally_2d - if cell_tallies is None: - cell_tallies = self.cell_tallies - if mesh_2d_resolution is None: - mesh_2d_resolution = self.mesh_2d_resolution - if mesh_3d_resolution is None: - mesh_3d_resolution = self.mesh_3d_resolution - if mesh_2d_corners is None: - mesh_2d_corners = self.mesh_2d_corners - if mesh_3d_corners is None: - mesh_3d_corners = self.mesh_3d_corners - - # this removes any old file from previous simulations - os.system('rm geometry.xml') - os.system('rm settings.xml') - os.system('rm tallies.xml') - - # materials.xml is removed in this function - self.create_openmc_materials() - - # this is the underlying geometry container that is filled with the - # faceteted DGAMC CAD model - self.universe = openmc.Universe() - geom = openmc.Geometry(self.universe) - - # settings for the number of neutrons to simulate - settings = openmc.Settings() - settings.batches = self.simulation_batches - settings.inactive = 0 - settings.particles = self.simulation_particles_per_batch - settings.run_mode = "fixed source" - settings.dagmc = True - settings.photon_transport = self.photon_transport - if self.photon_transport: - settings.electron_treatment = 'ttb' - settings.source = self.source - settings.max_lost_particles = self.max_lost_particles - - # details about what neutrons interactions to keep track of (tally) - 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 - if self.mesh_3d_corners is None: - 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 - ] - else: - mesh_xyz.lower_left = self.mesh_3d_corners[0] - mesh_xyz.upper_right = self.mesh_3d_corners[1] - - for standard_tally in self.mesh_tally_3d: - 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_id=2, name='2d_mesh_xz') - - mesh_xz.dimension = [ - self.mesh_2d_resolution[1], - 1, - self.mesh_2d_resolution[0] - ] - - if self.mesh_2d_corners is None: - 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 - ] - else: - mesh_xz.lower_left = self.mesh_2d_corners[0] - mesh_xz.upper_right = self.mesh_2d_corners[1] - - 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 - ] - - if self.mesh_2d_corners is None: - 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 - ] - else: - mesh_xy.lower_left = self.mesh_2d_corners[0] - mesh_xy.upper_right = self.mesh_2d_corners[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] - ] - - if self.mesh_2d_corners is None: - 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 - ] - else: - mesh_yz.lower_left = self.mesh_2d_corners[0] - mesh_yz.upper_right = self.mesh_2d_corners[1] - - for standard_tally in self.mesh_tally_2d: - 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: - - 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': - - energy_bins = openmc.mgxs.GROUP_STRUCTURES['CCFE-709'] - energy_filter = openmc.EnergyFilter(energy_bins) - - neutron_particle_filter = openmc.ParticleFilter([ - 'neutron']) - self._add_tally_for_every_material( - 'neutron_spectra', - 'flux', - [neutron_particle_filter, energy_filter] - ) - if self.photon_transport is True: - photon_particle_filter = openmc.ParticleFilter([ - 'photon']) - 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 geometry, materials, settings and tallies - model = openmc.model.Model( - geom, self.mats, settings, self.tallies) - - geom.export_to_xml() - settings.export_to_xml() - self.tallies.export_to_xml() - - self.model = model - return model - - 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. - - 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: Optional[bool] = True, - cell_tally_results_filename: Optional[str] = 'results.json', - threads: Optional[int] = None, - export_h5m: Optional[bool] = True, - export_xml: Optional[bool] = True, - ) -> str: - """Run the OpenMC simulation. Deletes existing simulation output - (summary.h5) if files exists. - - Arguments: - verbose: Print the output from OpenMC (True) to the terminal or - don't print the OpenMC output (False). - cell_tally_results_filename: the filename to use when saving the - cell tallies to file. - threads: Sets the number of OpenMP threads used for the simulation. - None takes all available threads by default. - export_h5m: controls the creation of the DAGMC geometry - file (dagmc.h5m). Set to True to create the DAGMC geometry - file with the default settings as determined by the - NeutronicsModel.geometry.method attributes or set to False and - run the export_h5m() method yourself with more - direct control over the settings. - export_xml: controls the creation of the OpenMC model - files (xml files). Set to True to create the OpenMC files with - the default settings as determined by the NeutronicsModel - attributes or set to False and use existing xml files or run - the export_xml() method yourself with more - direct control over the settings and creation of the xml files. - - Returns: - The h5 simulation output filename - """ - if export_xml is True: - self.export_xml() - - if export_h5m is True: - os.system('rm *.h5') - self.geometry.export_h5m() - - # checks all the nessecary files are found - for required_file in ['geometry.xml', 'materials.xml', 'settings.xml', - 'tallies.xml']: - if not Path(required_file).is_file(): - msg = "{} file was not found. Please set export_xml \ - to True or use the export_xml() \ - method to create the xml files".format(required_file) - raise FileNotFoundError(msg) - - if not Path('dagmc.h5m').is_file(): - msg = """dagmc.h5m file was not found. Please set export_h5m to - True or use the export_h5m() methods to create the dagmc.h5m - file""" - raise FileNotFoundError(msg) - - # 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.statepoint_filename = self.model.run( - output=verbose, threads=threads - ) - self.results = get_neutronics_results_from_statepoint_file( - statepoint_filename=self.statepoint_filename, - fusion_power=self.fusion_power - ) - - with open(cell_tally_results_filename, 'w') as outfile: - json.dump(self.results, outfile, indent=4, sort_keys=True) - - return self.statepoint_filename - - def export_html( - self, - filename: Optional[str] = "neutronics_model.html", - facet_splines: Optional[bool] = True, - facet_circles: Optional[bool] = True, - tolerance: Optional[float] = 1., - view_plane: Optional[str] = 'RZ', - number_of_source_particles: Optional[int] = 1000): - """Creates a html graph representation of the points for the Shape - objects that make up the reactor and optionally the source. Shapes - are colored by their .color property. Shapes are also labelled by their - .name. If filename provided doesn't end with .html then .html will be - added. - - Args: - filename: the filename used to save the html graph. Defaults to - neutronics_model.html - facet_splines: If True then spline edges will be faceted. Defaults - to True. - facet_circles: If True then circle edges will be faceted. Defaults - to True. - tolerance: faceting toleranceto use when faceting cirles and - splines. Defaults to 1e-3. - view_plane: The plane to project. Options are 'XZ', 'XY', 'YZ', - 'YX', 'ZY', 'ZX', 'RZ' and 'XYZ'. Defaults to 'RZ'. Defaults to - 'RZ'. - number_of_source_particles - Returns: - plotly.Figure(): figure object - """ - - fig = self.geometry.export_html( - filename=None, - facet_splines=facet_splines, - facet_circles=facet_circles, - tolerance=tolerance, - view_plane=view_plane, - ) - - if number_of_source_particles != 0: - source_filename = create_inital_particles( - self.source, number_of_source_particles) - points = extract_points_from_initial_source( - source_filename, view_plane) - - fig.add_trace( - plotly_trace( - points=points, - mode="markers", - name='source' - ) - ) - - if filename is not None: - - Path(filename).parents[0].mkdir(parents=True, exist_ok=True) - - path_filename = Path(filename) - - if path_filename.suffix != ".html": - path_filename = path_filename.with_suffix(".html") - - fig.write_html(str(path_filename)) - - print("Exported html graph to ", path_filename) - - return fig From d827df24616096019f7e4b89bad73146afe254c8 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Mon, 21 Jun 2021 23:27:45 +0100 Subject: [PATCH 2/2] added missing packages --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index df3dd3b91..8842bdc57 100644 --- a/setup.py +++ b/setup.py @@ -21,6 +21,8 @@ tests_require=[ "pytest-cov", "pytest-runner", + "nbformat", + "nbconvert", ], install_requires=[ "pytest-cov", @@ -32,4 +34,5 @@ "matplotlib", "plasmaboundaries", "remove_dagmc_tags", + "jupyter-cadquery", ])