Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Photon Transport Simulation with Two Layers of Material & Unstructured Mesh #27

Draft
wants to merge 68 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
23c1469
Add files via upload
anu1217 Oct 4, 2024
8d1f88b
Deleted unused Energy_List lines
anu1217 Oct 4, 2024
d7e58a3
Update OpenMC_PhotonTransport.py
anu1217 Oct 10, 2024
39e2d4b
Delete unused 'Energy_List.txt' line
anu1217 Oct 10, 2024
3dfb567
Delete print statement
anu1217 Oct 10, 2024
5bb02ff
Remove summed strengths text file as output
anu1217 Oct 10, 2024
1fdb1b1
Read summed photon strengths from Source_Mesh_Reader
anu1217 Oct 10, 2024
569eb28
Add source strengths for each individual mesh element
anu1217 Oct 10, 2024
1008270
Update OpenMC_PhotonTransport.py
anu1217 Oct 15, 2024
19e86ef
Adding materials/geometry files
anu1217 Oct 15, 2024
6fa1367
Import materials/geometry from TwoLayers_Materials & TwoLayers_Geometry
anu1217 Oct 15, 2024
c3cf5db
Delete materials and geometry functions from current script
anu1217 Oct 15, 2024
e217e00
Update OpenMC_PhotonTransport.py
anu1217 Oct 25, 2024
94519f9
Update TwoLayers_Materials.py
anu1217 Nov 8, 2024
3854660
Update TwoLayers_Materials.py
anu1217 Nov 11, 2024
a3db102
Update references to some variables
anu1217 Nov 11, 2024
4199c1b
Update TwoLayers_Geometry.py
anu1217 Nov 11, 2024
fdcb11f
Import variables from TwoLayers_Materials
anu1217 Nov 12, 2024
2e209a6
Update directory of OpenMC_PhotonTransport
anu1217 Nov 14, 2024
e8a305a
Update directory of Photon_Tallytovtk
anu1217 Nov 14, 2024
3aa85b3
Update directory of TwoLayers_Geometry
anu1217 Nov 14, 2024
1cff395
Update directory of TwoLayers_Materials
anu1217 Nov 14, 2024
64d14d5
Update directory of Source_Mesh_Reader
anu1217 Nov 14, 2024
88a9e83
Update TwoLayers_Geometry.py
anu1217 Nov 14, 2024
2259f79
Add functions to read, plot, and save data
anu1217 Nov 14, 2024
84bac07
Fix indentation of return statement
anu1217 Nov 15, 2024
0713d73
Created functions to extract and write relevant data
anu1217 Nov 15, 2024
5c03a21
Define arrange_source_strengths function
anu1217 Nov 15, 2024
d761b1c
Add main function that calls all helper functions
anu1217 Nov 15, 2024
fd3cb83
Rewrite make_source in terms of data_extractor from Source_Mesh_Reader
anu1217 Nov 15, 2024
ed0e05d
Fix summation in make_source loop
anu1217 Nov 15, 2024
c7a0c03
Changed variable name in function definition
anu1217 Nov 15, 2024
4568353
Updated main function that calls helper functions
anu1217 Nov 15, 2024
f91820f
Rename write_source_density
anu1217 Nov 19, 2024
2347332
Rewrite extract_source_data
anu1217 Nov 19, 2024
d3b612e
Change extract_source_data docstring
anu1217 Nov 19, 2024
99af15a
Moved Particle_Filter to tallies
anu1217 Nov 19, 2024
bc4e8d3
Add inner_radius as input
anu1217 Nov 19, 2024
e06fba5
Change inputs required for make_source
anu1217 Nov 19, 2024
7afd568
Remove Mesh_Dist as output of make_source
anu1217 Nov 19, 2024
2b5e67b
Change inputs required for tallies & fix capitalization
anu1217 Nov 20, 2024
4fb3156
Change variable names from uppercase to lowercase
anu1217 Nov 20, 2024
c81e21f
Rewrite export_to_xml as create_openmc_model
anu1217 Nov 20, 2024
1ae47ce
Deleted comments describing self-explanatory code
anu1217 Nov 20, 2024
c3509d6
Add docstrings to functions
anu1217 Nov 21, 2024
6676191
Add input to tallies function
anu1217 Nov 21, 2024
e6c9518
Changed bounds to numpy array
anu1217 Nov 25, 2024
3a09bf8
Change the way upper & lower energy bounds are accessed
anu1217 Nov 26, 2024
0d0418b
Fixed typo in make_source
anu1217 Nov 26, 2024
93d5b56
Add inputs to yaml file
anu1217 Nov 26, 2024
80382a4
Update and rename PhotonTransport_Inputs.yaml to WC_Layers/PhotonTran…
anu1217 Nov 26, 2024
ab1b09b
Remove hard-coded inputs that have been moved to yaml
anu1217 Nov 26, 2024
43270df
Merge branch 'cnerg:main' into mesh_photontransport
anu1217 Nov 27, 2024
8aff672
Add information to calculate effective dose
anu1217 Dec 16, 2024
0679a68
Redefine inputs for make_spherical_shells
anu1217 Dec 16, 2024
fc583b1
Edit function docstring
anu1217 Dec 16, 2024
785511e
Changed inputs for extract_source_data
anu1217 Dec 16, 2024
ee8df5b
Add main function to Source_Mesh_Reader
anu1217 Dec 16, 2024
790db58
Add default to argparse input
anu1217 Dec 16, 2024
3b808c1
Add files via upload
anu1217 Dec 16, 2024
052b312
Merge branch 'cnerg:main' into mesh_photontransport
anu1217 Dec 16, 2024
771b147
Add input to function
anu1217 Dec 16, 2024
7f76500
Add docstrings to functions
anu1217 Dec 16, 2024
2a7d52c
Change variable names and inputs
anu1217 Dec 16, 2024
6b18246
Change variable key
anu1217 Dec 16, 2024
a3a9921
Update PhotonTransport_Inputs.yaml
anu1217 Dec 16, 2024
608adba
Fix typo in run mode
anu1217 Dec 16, 2024
15f64ef
Update and rename Source_Mesh_Reader_Inputs.yaml to WC_Layers/Source_…
anu1217 Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions WC_Layers/OpenMC_PhotonTransport.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 7 10:07:33 2024

@author: Anupama Rajendra
"""

import openmc
import argparse
import numpy as np
from Source_Mesh_Reader import extract_source_data, Files
from TwoLayers_Materials import *
from TwoLayers_Geometry import *

# These will be moved to a yaml file
openmc_mesh_file = 'OpenMC_Mesh.h5m'
mesh_index = 0
esd = extract_source_data(Files)

parser = argparse.ArgumentParser(description="Specify required inputs: file path to ALARA Element Library, element name, inner radius [cm], outer_radius [cm]")

#Required user inputs:
parser.add_argument('--filepath', type=str, required=True)
parser.add_argument('--element_1', type=str, required=True)
parser.add_argument('--element_2', type=str, required=True)
#Shell radii are left as user inputs, but the mesh is specific to W_inner_radius = 1000, W_outer_radius = 1005, C_inner_radius = 995
parser.add_argument('--W_inner_radius', type=float, required=True)
parser.add_argument('--W_outer_radius', type=float, required=True)
parser.add_argument('--C_inner_radius', type=float, required=True)

args = parser.parse_args()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in a function


fp = args.filepath
E_1 = args.element_1
E_2 = args.element_2
R_W_1 = args.W_inner_radius
R_W_2 = args.W_outer_radius
R_C_1 = args.C_inner_radius
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in a main function


# fp = '../../ALARA/data/elelib.std'
# E_1 = 'W'
# E_2 = 'C'
# R_W_1 = 1000
# R_W_2 = 1005
# R_C_1 = 995
bounds = np.array([0,
1.00e+4,
2.00e+4,
5.00e+4,
1.00e+5,
2.00e+5,
3.00e+5,
4.00e+5,
6.00e+5,
8.00e+5,
1.00e+6,
1.22e+6,
1.44e+6,
1.66e+6,
2.00e+6,
2.50e+6,
3.00e+6,
4.00e+6,
5.00e+6,
6.50e+6,
8.00e+6,
1.00e+7,
1.20e+7,
1.40e+7,
2.00e+7])

def make_source(cells, mesh_file):
'''
Creates a list of OpenMC sources, complete with the relevant space and energy distributions

inputs:
cells: list of OpenMC Cell objects
mesh_file: .h5/.h5m mesh onto which photon source will be distributed

output:
source_list: list of OpenMC independent sources
total_mesh: OpenMC Unstructured Mesh object
'''
source_list = []
total_mesh = openmc.UnstructuredMesh(mesh_file, library='moab')
for index in range(len(bounds) - 1):
mesh_dist = openmc.stats.MeshSpatial(total_mesh, strengths=esd[mesh_index][:,index], volume_normalized=False)
energy_dist = openmc.stats.Uniform(a=bounds[index], b=bounds[index + 1])
source_list.append(openmc.IndependentSource(space=mesh_dist, energy=energy_dist, strength=np.sum(esd[mesh_index][:, index]), particle='photon', domains=cells))
anu1217 marked this conversation as resolved.
Show resolved Hide resolved
return source_list, total_mesh

def tallies(total_mesh, tallied_cells):
'''
Creates tallies and assigns energy, spatial, and particle filters.

inputs:
total_mesh: OpenMC unstructured mesh object
tallied_cells: OpenMC Cell/iterable of OpenMC Cell objects/iterable of Cell ID #

outputs:
talls: OpenMC Tallies object
'''
particle_filter = openmc.ParticleFilter('photon')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You define this particle filter, which makes sense for a photon transport problem, but all the rest of your tally definition seems like it is meant for neutrons, especially the choice of scores, energy filter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, tally 1 originated from the neutron transport model. Perhaps a heating/absorption photon tally (with the appropriate variable names) would provide more relevant information?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For R2S problems, it's customary to do an equivalent dose tally.

total_filter = openmc.MeshFilter(total_mesh)

neutron_tally = openmc.Tally(tally_id=1, name="Neutron tally")
neutron_tally.scores = ['flux', 'elastic', 'absorption']

# Implementing filter for neutron tally through shells with material
cell_filter = openmc.CellFilter(tallied_cells)
neutron_tally.filters = [cell_filter, total_filter]

# Vitamin-J energy filter created to assign to the flux tally.
energy_filter_flux = openmc.EnergyFilter.from_group_structure("VITAMIN-J-42")

spectrum_tally = openmc.Tally(tally_id=2, name="Flux spectrum")
spectrum_tally.filters = [cell_filter, total_filter, energy_filter_flux, particle_filter]
spectrum_tally.scores = ['flux']

talls = openmc.Tallies([neutron_tally, spectrum_tally])
return talls

def settings(source_list):
'''
Creates an OpenMC Settings object

inputs:
source_list: iterable of OpenMC SourceBase objects
outputs:
sets: OpenMC Settings object
'''
sets = openmc.Settings()
sets.batches = 10
sets.inactive = 1
sets.particles = 100000
sets.source = source_list
sets.run_mode = 'fixed source'
return sets

def create_openmc_model(geom_object, mats_object, sets_object, talls_object):
model = openmc.model.Model(geometry = geom_object, materials = mats_object, settings = sets_object, tallies = talls_object)
return model
35 changes: 35 additions & 0 deletions WC_Layers/Photon_TallytoVtk.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some requests for this file:

  • add argparse for filename (with defaults)
  • create separate functions to:
    • read data from statepoint
    • plot data (optoinal via argparse)
    • write data to file (filename set by argparse)
  • all of these called from a main function

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Oct 3 23:18:20 2024

@author: Anupama Rajendra
"""
import openmc
import matplotlib.pyplot as plt

def read_statepoint(sp_filename, flux_spectrum_tally_id, mesh_number, summed_axes_energy_filter, energy_filter_index):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the addiction of a docstring here, I think some better variable names may emerge:

  • flux_spectrum => flux_spectrum_tally
  • tally_data_reshaped => flux_spectrum_mean
  • flux_sum_energy => total_flux

with openmc.StatePoint(sp_filename) as sp:
flux_spectrum = sp.get_tally(id=flux_spectrum_tally_id)
mesh=sp.meshes[mesh_number]
# Return tally data condensed into 1 dimension per filter
tally_data_reshaped = flux_spectrum.get_reshaped_data(value='mean')
flux_sum_energy = tally_data_reshaped.sum(axis=summed_axes_energy_filter)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me what axes this data is being summed over. The data is originally a flux spectrum of G groups for each of M mesh elements. I assumed that this sum was summing over G, to produce a total flux for each of the M mesh elements. However, when you use this in the plot below, it seems like it may be summing over M to produce a single flux spectrum of G groups. If so, then we need to make sure that the volume normalization is being done correctly. (Full disclosure: I'm not sure when/how volume normalization of tallies happens in OpenMC. If this was MCNP-like, then this operation would be wrong because the results would already be volume normalized per mesh element, and summing would require a volume-weighting.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purpose of plotting the data, the summation is happening over M so that the flux is divided into G groups.

From digging into r2s.py for a bit, I believe that the outputted photon source mesh info is normalized by volume. That said, I don't think there is any division by volume automatically happening on the OpenMC side, so ALARA/r2s may be outputting the wrong units if it is expecting values from MCNP. However, I do have the volume normalization set to False within MeshSpatial of the PhotonTransport code, so there is no remultiplication by volume of the source strengths. I think this is still worth looking into further.

#Vitamin-J energy filter:
e_filter = flux_spectrum.filters[energy_filter_index]
#Lower bounds of the energy bins
e_filter_lower = e_filter.bins[:, 0]
return e_filter_lower, flux_sum_energy, tally_data_reshaped, mesh

def plot_flux_data(e_filter_lower, flux_sum_energy, figure_filename):
# Plot flux spectrum
fix, ax = plt.subplots()
ax.loglog(e_filter_lower, flux_sum_energy, drawstyle='steps-post')
ax.set_xlabel('Energy [eV]')
ax.set_ylabel('Flux [photon-cm/source]')
ax.grid(True, which='both')
plt.savefig(figure_filename)
plt.show()

def write_to_vtk(tally_data_reshaped, summed_axes_mesh_filter, vtk_filename, mesh):
mesh_data = tally_data_reshaped.sum(axis=summed_axes_mesh_filter)
mesh.write_data_to_vtk(filename=vtk_filename, datasets={"mean":mesh_data.flatten()})
47 changes: 47 additions & 0 deletions WC_Layers/Source_Mesh_Reader.py
anu1217 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Sep 30 15:16:44 2024

@author: Anupama Rajendra
"""

import h5py
import numpy as np

source_density_name = 'source_density'

# Open the HDF5 files
File_1 = h5py.File("source_mesh_1.h5m", 'r')
File_2 = h5py.File("source_mesh_2.h5m", 'r')
Files = [File_1, File_2]

def extract_source_data(file_list):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great addition!

'''
Identifies the location of the source density dataset within each mesh file.

input: list of .h5m mesh files (opened by h5py) containing photon source information
output: numpy array of source density data with rows = # of mesh elements and
columns = # number of photon groups, with one array per source mesh
'''
sd_list = np.ndarray((len(file_list), num_elements, photon_groups))

for file_num, file in enumerate(file_list):
sd_list[file_num,:] = file['tstt']['elements']['Tet4']['tags']['source_density'][:]
return sd_list

def save_source_density(sd_list, sd_filename):
'''
Saves source density data as a text file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you open multiple files. Can you add more to the docstring about the difference between files and the structure of the files?


sd_list: list of source density datasets from h5m files
sd_filename: user-provided filename that appears as a prefix for the text files
'''
for sd_index, source_density in enumerate(sd_list):
with open(f'{sd_filename}_{sd_index + 1}.txt', 'w') as source:
for tet_element in source_density:
source.write(' '.join(map(str, tet_element)) + '\n')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this joining across groups? Are you writing a multi-group source for each mesh? Or would it make more sense to write num_groups separate files for each mesh?


def extract_save_sd(file_list, sd_filename):
data_extractor = extract_source_data(file_list)
save_source_density(data_extractor, sd_filename)
return data_extractor
30 changes: 30 additions & 0 deletions WC_Layers/TwoLayers_Geometry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 11 15:56:57 2024

@author: Anupama Rajendra
"""

import openmc

# Create geometry
#Spherical shell:
def make_spherical_shells(layers, inner_radius):
'''
Creates a set of concentric spherical shells, each with its own material & inner/outer radius.

layers: list of tuples with OpenMC Material name and thickness: (material, thickness)
inner_radius: the radius of the innermost spherical shell
'''
anu1217 marked this conversation as resolved.
Show resolved Hide resolved
inner_sphere = openmc.Sphere(r = inner_radius)
cells = [openmc.Cell(fill = None, region = -inner_sphere)]
for (material, thickness) in layers:
outer_radius = inner_radius + thickness
outer_sphere = openmc.Sphere(r = outer_radius)
cells.append(openmc.Cell(fill = material, region = +inner_sphere & -outer_sphere))
outer_radius = inner_radius
outer_sphere = inner_sphere
outer_sphere.boundary_type = 'vacuum'
cells.append(openmc.Cell(fill = None, region = +outer_sphere))
geometry = openmc.Geometry(cells)
return geometry
33 changes: 33 additions & 0 deletions WC_Layers/TwoLayers_Materials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 11 13:49:23 2024

@author: Anupama Rajendra
"""
import openmc

#ALARA Element Library to read density for specified element:
def alara_element_densities(filepath):
with open(""+filepath+"") as ALARA_Lib:
libLines = ALARA_Lib.readlines()
num_lines = len(libLines)
density_dict = {}
line_num = 0
while line_num < num_lines:
element_data = libLines[line_num].strip().split()
element_name = element_data[0].lower()
density_dict[element_name] = float(element_data[3])
line_num += int(element_data[4]) + 1
return density_dict

# Create materials & export to XML:
#Simulating tungsten shell:
def make_element(elements, density_dict):
mats = openmc.Materials([])
for element_id, element in enumerate(elements):
mat = openmc.Material(material_id=element_id+1, name=element)
mat.add_element(element, 1.00)
mat.set_density('g/cm3', density_dict.get(element.lower()))
mats.append(mat)
return mats