Merge pull request #1298 from paulromano/particle-filter-str

Use strings instead of arbitrary numbers for particle filter
This commit is contained in:
Amanda Lund 2019-07-22 11:04:09 -04:00 committed by GitHub
commit cca3012a53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 39 deletions

View file

@ -4,9 +4,6 @@
Test Suite
==========
Running Tests
-------------
The OpenMC test suite consists of two parts, a regression test suite and a unit
test suite. The regression test suite is based on regression or integrated
testing where different types of input files are configured and the full OpenMC
@ -14,27 +11,35 @@ code is executed. Results from simulations are compared with expected
results. The unit tests are primarily intended to test individual
functions/classes in the OpenMC Python API.
The test suite relies on the third-party `pytest <https://pytest.org>`_
package. To run either or both the regression and unit test suites, it is
assumed that you have OpenMC fully installed, i.e., the :ref:`scripts_openmc`
executable is available on your :envvar:`PATH` and the :mod:`openmc` Python
module is importable. In development where it would be onerous to continually
install OpenMC every time a small change is made, it is recommended to install
OpenMC in development/editable mode. With setuptools, this is accomplished by
running::
Prerequisites
-------------
python setup.py develop
- The test suite relies on the third-party `pytest <https://pytest.org>`_
package. To run either or both the regression and unit test suites, it is
assumed that you have OpenMC fully installed, i.e., the :ref:`scripts_openmc`
executable is available on your :envvar:`PATH` and the :mod:`openmc` Python
module is importable. In development where it would be onerous to continually
install OpenMC every time a small change is made, it is recommended to install
OpenMC in development/editable mode. With setuptools, this is accomplished by
running::
or using pip (recommended)::
python setup.py develop
pip install -e .[test]
or using pip (recommended)::
It is also assumed that you have cross section data available that is pointed to
by the :envvar:`OPENMC_CROSS_SECTIONS` environment variables. Furthermore, to
run unit tests for the :mod:`openmc.data` module, it is necessary to have
ENDF/B-VII.1 data available and pointed to by the :envvar:`OPENMC_ENDF_DATA`
environment variable. All data sources can be obtained using the
``tools/ci/travis-before-script.sh`` script.
pip install -e .[test]
- The test suite requires a specific set of cross section data in order for
tests to pass. A download URL for the data that OpenMC expects can be found
within ``tools/ci/download-xs.sh``.
- In addition to the HDF5 data, some tests rely on ENDF files. A download URL
for those can also be found in ``tools/ci/download-xs.sh``.
- Some tests require `NJOY <https://www.njoy21.io/NJOY2016>`_ to preprocess
cross section data. The test suite assumes that you have an ``njoy``
executable available on your :envvar:`PATH`.
Running Tests
-------------
To execute the test suite, go to the ``tests/`` directory and run::
@ -46,6 +51,17 @@ installed and run::
pytest --cov=../openmc --cov-report=html
Generating XML Inputs
---------------------
Many of the regression tests rely on the Python API to build an appropriate
model. However, it can sometimes be desirable to work directly with the XML
input files rather than having to run a script in order to run the problem/test.
To build the input files for a test without actually running the test, you can
run::
pytest --build-inputs <name-of-test>
Adding Tests to the Regression Suite
------------------------------------

View file

@ -411,7 +411,7 @@ class Library(EqualityMixin):
# after it). If it's too short, then we apply the ENDF float regular
# expression. We don't do this by default because it's expensive!
if xss.size != nxs[1] + 1:
datastr = ENDF_FLOAT_RE.sub(r'\1e\2', datastr)
datastr = ENDF_FLOAT_RE.sub(r'\1e\2\3', datastr)
xss = np.fromstring(datastr, sep=' ')
assert xss.size == nxs[1] + 1

View file

@ -32,7 +32,8 @@ _CURRENT_NAMES = (
'z-min out', 'z-min in', 'z-max out', 'z-max in'
)
_PARTICLE_IDS = {'neutron': 1, 'photon': 2, 'electron': 3, 'positron': 4}
_PARTICLES = {'neutron', 'photon', 'electron', 'positron'}
class FilterMeta(ABCMeta):
def __new__(cls, name, bases, namespace, **kwargs):
@ -547,10 +548,9 @@ class ParticleFilter(Filter):
Parameters
----------
bins : str, int, or iterable of Integral
The Particles to tally. Either str with particle type or their
ID numbers can be used ('neutron' = 1, 'photon' = 2, 'electron' = 3,
'positron' = 4).
bins : str, or iterable of str
The particles to tally represented as strings ('neutron', 'photon',
'electron', 'positron').
filter_id : int
Unique identifier for the filter
@ -571,16 +571,22 @@ class ParticleFilter(Filter):
@bins.setter
def bins(self, bins):
bins = np.atleast_1d(bins)
cv.check_iterable_type('filter bins', bins, (Integral, str))
cv.check_iterable_type('filter bins', bins, str)
for edge in bins:
if isinstance(edge, Integral):
cv.check_value('filter bin', edge, _PARTICLE_IDS.values())
else:
cv.check_value('filter bin', edge, _PARTICLE_IDS.keys())
bins = np.atleast_1d([b if isinstance(b, Integral) else _PARTICLE_IDS[b]
for b in bins])
cv.check_value('filter bin', edge, _PARTICLES)
self._bins = bins
@classmethod
def from_hdf5(cls, group, **kwargs):
if group['type'][()].decode() != cls.short_name.lower():
raise ValueError("Expected HDF5 data for filter type '"
+ cls.short_name.lower() + "' but got '"
+ group['type'][()].decode() + " instead")
particles = [b.decode() for b in group['bins'][()]]
filter_id = int(group.name.split('/')[-1].lstrip('filter '))
return cls(particles, filter_id=filter_id)
class MeshFilter(Filter):
"""Bins tally event locations onto a regular, rectangular mesh.

View file

@ -7,12 +7,20 @@ namespace openmc {
void
ParticleFilter::from_xml(pugi::xml_node node)
{
auto particles = get_node_array<int>(node, "bins");
auto particles = get_node_array<std::string>(node, "bins");
// Convert to vector of Particle::Type
std::vector<Particle::Type> types;
for (auto& p : particles) {
types.push_back(static_cast<Particle::Type>(p - 1));
if (p == "neutron") {
types.push_back(Particle::Type::neutron);
} else if (p == "photon") {
types.push_back(Particle::Type::photon);
} else if (p == "electron") {
types.push_back(Particle::Type::electron);
} else if (p == "positron") {
types.push_back(Particle::Type::positron);
}
}
this->set_particles(types);
}
@ -47,9 +55,22 @@ void
ParticleFilter::to_statepoint(hid_t filter_group) const
{
Filter::to_statepoint(filter_group);
std::vector<int> particles;
std::vector<std::string> particles;
for (auto p : particles_) {
particles.push_back(static_cast<int>(p) + 1);
switch (p) {
case Particle::Type::neutron:
particles.push_back("neutron");
break;
case Particle::Type::photon:
particles.push_back("photon");
break;
case Particle::Type::electron:
particles.push_back("electron");
break;
case Particle::Type::positron:
particles.push_back("positron");
break;
}
}
write_dataset(filter_group, "bins", particles);
}

View file

@ -41,7 +41,7 @@
<bins>9</bins>
</filter>
<filter id="2" type="particle">
<bins>2</bins>
<bins>photon</bins>
</filter>
<tally id="1">
<filters>1 2</filters>

View file

@ -36,7 +36,7 @@
<?xml version='1.0' encoding='utf-8'?>
<tallies>
<filter id="1" type="particle">
<bins>2</bins>
<bins>photon</bins>
</filter>
<tally id="1">
<filters>1</filters>