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

Latin Hypercube Neutronic Sampling #10

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5352233
lhs for parameter space, adjust burnup parameters to shorten calculation
aaswenson Mar 19, 2018
b1f3e4e
generate inputs, tar them
aaswenson Mar 19, 2018
5fb7b85
some htc utiltiles, testing with 40 samples
aaswenson Mar 19, 2018
f995797
--ignore
aaswenson Mar 20, 2018
a9ca809
A module to parse MCNP depletion outputs
aaswenson Mar 20, 2018
f6797df
storing results
aaswenson Mar 20, 2018
71d51d4
test data
aaswenson Mar 20, 2018
30bba7e
plotting and fitting data
aaswenson Mar 21, 2018
d89deca
adding core_power
aaswenson Mar 21, 2018
b0e8814
don't store strings in memory
aaswenson Apr 2, 2018
786c062
initial attempt at multiple regression
aaswenson Apr 3, 2018
50be3ad
adding mass
aaswenson Apr 4, 2018
a44887c
calculate mass
aaswenson Apr 4, 2018
abe77b5
fix ordering of header parameters
aaswenson Apr 11, 2018
ebb7296
added ability to include constant parameters
aaswenson Apr 12, 2018
2e17eb6
data
aaswenson Apr 12, 2018
677fa4e
ND interpolation of the data
aaswenson Apr 16, 2018
2f53046
debuggin NN
aaswenson Apr 17, 2018
667a118
linear fit on the log data, code (rough) processes error
aaswenson Apr 19, 2018
1a5e34a
plot axis labels
aaswenson Apr 23, 2018
39216a6
linear regression use sklearn
aaswenson Apr 26, 2018
d0101a6
convienience featurees in skit_fit.py
aaswenson Apr 30, 2018
162d809
lots of plotting capability, huge commit, kept forgetting to commit...
aaswenson May 2, 2018
47cfb2a
trying different regression models
aaswenson May 2, 2018
88839e8
lots of plotting changes
aaswenson May 7, 2018
e2d25cb
added titles to plotting
aaswenson May 9, 2018
a860836
depletion parser
aaswenson May 14, 2018
2f3ac24
cleaned up neutronic_sweeps.py nad parse_outputs.py
aaswenson May 14, 2018
0d1e51e
more docstrings, comments, and clarifying code changes
aaswenson May 15, 2018
c3f6ffc
remove depletion results csv
aaswenson May 15, 2018
22d0077
docstrings and clarifying comments in parse_outputs.py
aaswenson May 15, 2018
4e511cd
more clarifying comments in neutronics_sweeps.py
aaswenson May 16, 2018
4681c38
set seed for lhs as default optional variable in 'gen_hypercube' func…
aaswenson May 16, 2018
202f162
convert float dimensions to tuples, keep consistency in calculation f…
aaswenson May 21, 2018
73d4418
simplify the parameter range calculation using numpy arrays
aaswenson May 21, 2018
7cd54b2
add reference csv to test output parser, fix energy average
aaswenson May 22, 2018
390aec9
conversion factors, clarifying comments, removal of magic numbers
aaswenson May 22, 2018
49a450e
add pyDOE install to yaml
aaswenson May 22, 2018
c73d6c7
cd into proper directories for testing
aaswenson May 22, 2018
af30af4
fix variable name
aaswenson May 22, 2018
f0c4c66
pep8 spacing, remove dated docstring from get_sampling_params()
aaswenson May 22, 2018
82d4db7
remove incorrect energy tally parser, simplify the keff parser, renam…
aaswenson Jun 20, 2018
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
4 changes: 2 additions & 2 deletions neutronics/base_input.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
MCNP6 homog depltion r= ${r_core} frac= ${cool_frac}
${model_information}
c Cell Card
1 1 -${fuel_rho} -1 4 -5 imp:n=1
2 2 -1.7 (-2 1 -7 6):(-1 5 -7):(6 -1 -4) imp:n=1
Expand All @@ -15,7 +15,7 @@ c Surface Card
c Data Card
c
c Burnup
burn time=0.25 0.5 9R 10 5R 100 3R 365.25 8R power=${thermal_power} pfrac=1 29R
burn time=0.25 65 300 365.25 8R power=${core_power} pfrac=1 11R
bopt=1 14 -1 mat= 1
omit= -1 128 66159 67163 67164 67166 68163 68165 68169 69166
69167 69171 69172 69173 70168 70169 70170 70171 70172 70173
Expand Down
12 changes: 6 additions & 6 deletions neutronics/mcnp_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def write_mat_string(self):
# write mcnp-form string
self.fuel_string = self.homog_mat.mcnp().strip('\n')

def write_input(self):
def write_input(self, file_num, header):
Copy link
Member

Choose a reason for hiding this comment

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

Add arguments to docstring....

Not sure what file_num is: is it actually just a number? If so, then not sure about the filename below

""" Write MCNP6 input files.
This function writes the MCNP6 input files for the leakage experiment using
the template input string. It writes a bare and reflected core input file
Expand All @@ -166,7 +166,8 @@ def write_input(self):
self.write_mat_string()
input_tmpl = open('base_input.txt')
templ = Template(input_tmpl.read())
file_string = templ.substitute(cool_frac = self.vfrac_cermet,
file_string = templ.substitute(model_information = header,
cool_frac = self.vfrac_cermet,
r_core = self.r,
core_z = self.z,
r_refl = self.r + self.refl_t,
Expand All @@ -175,11 +176,10 @@ def write_input(self):
fuel_string = self.fuel_string,
fuel_rho = self.rho,
fuel_vol = self.core_vol,
refl_vol = self.core_vol,
thermal_power = self.Q_therm)
refl_vol = self.refl_vol,
core_power = self.Q_therm)
# write the file
filename = 'r_{0}_{1}.i'.format(round(self.vfrac_cermet, 3),
round(self.r, 3))
filename = '{0}.i'.format(file_num)
ifile = open(filename, 'w')
ifile.write(file_string)
ifile.close()
Expand Down
147 changes: 147 additions & 0 deletions neutronics/neutronic_sweeps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"""This module contains functions to sweep parameter-space, creating MCNP
depletion inputs to calculate keff at EOL.
* AR
* core_z
* cool_r
* PD
* power
* enrich
"""
from pyDOE import lhs
Copy link
Member

Choose a reason for hiding this comment

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

PEP8: missing blank line

import os
import glob
import numpy as np
import tarfile

from mcnp_inputs import HomogeneousInput, build_pyne_matlib

_dimensions = ['AR', 'core_r', 'cool_r', 'PD', 'power', 'enrich']
Copy link
Member

Choose a reason for hiding this comment

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

doctoring to explain what those variables are.


# number of samples for each sampled dimension
nsamples = 100

dims = {'core_r' : (20, 50),
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't _dimensions be set by looking at the keys of this variable to ensure consistency?

'AR' : (0.7, 1.3),
'PD' : (1.4, 1.6),
'enrich' : (0.3, 0.9),
'cool_r' : 0.5,
'power' : 150
}

def get_sampling_params():
"""Decide which parameters are constants and which are ranges to be sampled.

Returns:
--------
sampled (list): list of keys for sampled parameters
const (list): keys for constant parameters
dim (float): length of sampled parameters for LHS sampling function.
"""
const = list(filter(lambda x: type(dims[x]) != tuple, dims.keys()))
sampled = [x for x in dims.keys() if x not in const]

dim = len(sampled)

return sampled, const, dim
Copy link
Member

Choose a reason for hiding this comment

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

why returning len(sampled) when you actually have sampled?



Copy link
Member

Choose a reason for hiding this comment

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

2 lines there

def gen_hypercube(samples, N):
"""Generate N-dimensional latin hypercube to sample dimensional reactor
space.

Arguments:
----------
samples (int): number of test cases to try
N (int): number of dimensions to test

Returns:
--------
cube (ndarray): normalized, N-D latin hypercube
"""

np.random.seed(4654562)
Copy link
Member

Choose a reason for hiding this comment

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

why always the same seed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I do the analysis again, I want to be able to generate the same input files.

hypercube = lhs(N, samples=samples)

return hypercube

def fill_data_array(swept, const, cube):
"""Fill an ndarray with the sampling set generated by lhs and bounded by the
ranges provided for each sampled dimension.

Arguments:
----------
swept (list): keys for sampled dimensions
const (list): keys for constant dimensions
cube (ndarray): latin hypercube

Returns:
--------
rxt_confs (ndarray): array of data for every reactor configuration. This
data is used to build MCNP6 input files.
"""
# initialize array
rxt_confs = np.zeros(nsamples, dtype={'names' : list(dims.keys()),
'formats' : ['f8']*len(dims)})
# for all samples in latin hypercube
for sample_idx, sample in enumerate(cube):
# set values for every sampled dimension
for dim_idx, dim in enumerate(swept):
# skip constants
l_limit = dims[dim][0]
u_limit = dims[dim][1]
# uniform distribution
a = u_limit - l_limit
Copy link
Member

Choose a reason for hiding this comment

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

better variable name: width

b = l_limit
Copy link
Member

Choose a reason for hiding this comment

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

why not just use l_limit?

# save to ndarray
rxt_confs[sample_idx][dim] = b + cube[sample_idx][dim_idx] * a
Copy link
Member

Choose a reason for hiding this comment

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

seems like there is probably a matrix-vector implementation of this?

This won't work as is, but with a little thought on data structures, this whole inner loop can probably be replaced by something like this:
rxtr_confs[sample_idx] = dims[:][0] + cube[sample_idx] * (dims[:][1] - dims[:][0])

# set constant value dimensions
for dim in const:
rxt_confs[sample_idx][dim] = dims[dim]
Copy link
Member

Choose a reason for hiding this comment

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

What if you defined the upper and lower limit of these dimensions to be the same as each other and then used the same math as above?


return rxt_confs

def write_inputs(sampling_data):
"""Write MCNP depletion inputs for each reactor configuration.

Arguments:
----------
sampling_data (ndarray): array of reactor configurations, one for each
MCNP6 input file.
"""
# build PyNE material library
pyne_mats = build_pyne_matlib()
# initialize tarball to save input files
tarputs = tarfile.open('smpl_mcnp_depl_inps.tar', 'w')
# generate inputs
for num, sample in enumerate(sampling_data):
input = HomogeneousInput(sample['core_r'],
sample['core_r']*sample['AR'],
sample['power'], pyne_mats)
homog_comp = input.homog_core(sample['enrich'],
sample['cool_r'],
sample['PD'])
input.write_mat_string()

# identifying header string for post-processing
header_str = ''
for param in _dimensions:
header_str += str(round(sample[param], 5)) + ','
# write the input and tar it
filename = input.write_input(num, header_str)
tarputs.add(filename)
Copy link
Member

Choose a reason for hiding this comment

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

It would be cleanest to delete the file as soon as possible after you add it to the tarfile.


# write HTC input list
htc_inputs = open('input_list.txt', 'w')
htc_inputs.write('\n'.join(glob.glob("*.i")))
Copy link
Member

Choose a reason for hiding this comment

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

If this is the list of files you've just created, can't you generate it without a glob. Isn't it safer?

'\n'.join(["{0}.i".format(num) for num in range(len(sample_data))])

htc_inputs.close()

tarputs.add('input_list.txt')
tarputs.close()

if __name__=='__main__':
swept, const, dim = get_sampling_params()
cube = gen_hypercube(nsamples, dim)
data = fill_data_array(swept, const, cube)
write_inputs(data)
# cleanup
os.system('rm *.i input_list.txt')
Copy link
Member

Choose a reason for hiding this comment

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

There are modules to manipulate files without having to make system calls, I think:

https://stackoverflow.com/questions/6996603/how-to-delete-a-file-or-folder

Loading