Merge branch 'master' into raster3d

This commit is contained in:
nhorelik 2013-04-13 22:15:54 -04:00
commit 3af332318c
15 changed files with 663 additions and 269 deletions

33
data/readme.rst Normal file
View file

@ -0,0 +1,33 @@
========================
cross_sections.xml Files
========================
As a reminder, in order to run a simulation with OpenMC, you will need cross
section data for each nuclide in your problem. OpenMC is not currently
distributed with cross section data, so you will have to obtain cross section
data by other means. The `user's guide`_ offers some helpful advice on how you
can obtain cross sections.
When OpenMC starts up, it needs a cross_sections.xml file that tells it where to
find ACE format cross sections. The files in this directory are configured to
work with a few common cross section sources.
- **cross_sections_ascii.xml** -- This file matches ENDF/B-VII.0 cross sections
distributed with MCNP5 / MCNP6 beta.
- **cross_sections_serpent.xml** -- This file matches ENDF/B-VII.0 cross
sections distributed with Serpent 1.1.7.
- **cross_sections.xml** - This file matches ENDF/B-VII.0 cross sections
distributed with MCNP5 / MCNP6 beta *that have been converted to binary*.
To use any of these files, you need to follow two steps:
1. Change the path on the ``<directory>`` element in the cross_sections.xml file
to the directory containing the ACE files.
2. Enter the absolute path of the cross_sections.xml on the ``<cross_sections>``
element in your settings.xml, or set the CROSS_SECTIONS environment variable to
the full path of the cross_sections.xml file.
.. _user's guide: http://mit-crpg.github.io/openmc/usersguide/install.html#cross-section-configuration

View file

@ -72,6 +72,8 @@ Do not use old-style character/array length (e.g. character*80, real*8).
Integer values being used to indicate a certain state should be defined as named
constants (see the constants.F90 module for many examples).
Always use a double colon :: when declaring a variable.
Yes:
.. code-block:: fortran

View file

@ -755,7 +755,8 @@ filters can be used for a tally. The following types of filter are available:
cell, universe, material, surface, birth region, pre-collision energy,
post-collision energy, and an arbitrary structured mesh.
The two valid elements in the tallies.xml file are ``<tally>`` and ``<mesh>``.
The three valid elements in the tallies.xml file are ``<tally>``, ``<mesh>``,
and ``<assume_separate>``.
``<tally>`` Element
-------------------
@ -767,12 +768,58 @@ The ``<tally>`` element accepts the following sub-elements:
for output purposes. This string is limited to 52 characters for formatting
purposes.
:filters:
A list of filters to specify what region of phase space should contribute to
the tally. See below for full details on what filters are available.
:filter:
Specify a filter that restricts contributions to the tally to particles
within certain regions of phase space. This element and its
attributes/sub-elements are described below.
.. note::
You may specify zero, one, or multiple filters to apply to the tally. To
specify multiple filters, you must use multiple ``<filter>`` elements.
The ``filter`` element has the following attributes/sub-elements:
:type:
The type of the filter. Accepted options are "cell", "cellborn", "material",
"universe", "energy", "energyout", and "mesh".
:bins:
For each filter type, the corresponding ``bins`` entry is given as follows:
:cell:
A list of cells in which the tally should be accumulated.
:cellborn:
This filter allows the tally to be scored to only when particles were
originally born in a specified cell.
:surface:
A list of surfaces for which the tally should be accumulated.
:material:
A list of materials for which the tally should be accumulated.
:universe:
A list of universes for which the tally should be accumulated.
:energy:
A monotonically increasing list of bounding **pre-collision** energies
for a number of groups. For example, if this filter is specified as
``<filter type="energy" bins="0.0 1.0 20.0" />``, then two energy bins
will be created, one with energies between 0 and 1 MeV and the other
with energies between 1 and 20 MeV.
:energyout:
A monotonically increasing list of bounding **post-collision**
energies for a number of groups. For example, if this filter is
specified as ``<filter type="energyout" bins="0.0 1.0 20.0" />``, then
two post-collision energy bins will be created, one with energies
between 0 and 1 MeV and the other with energies between 1 and 20 MeV.
:mesh:
The ``id`` of a structured mesh to be tallied over.
:nuclides:
If specified, the scores listed will be for particular nuclides, not the
summation of reactions from all nuclides. The format for nuclides should be
[Atomic symbol]-[Mass number], e.g. "U-235". The reaction rate for all
@ -787,92 +834,69 @@ The ``<tally>`` element accepts the following sub-elements:
*Default*: total
:scores:
The desired responses to be accumulated. See below for full details on the
responses which be tallied.
A space-separated list of the desired responses to be accumulated. Accepted
options are "flux", "total", "scatter", "nu-scatter", "scatter-N",
"scatter-PN", "absorption", "fission", "nu-fission", "kappa-fission",
"current", and "events". These corresponding to the following physical
quantities.
The following filters can be specified for a tally:
:flux:
Total flux
:cell:
A list of cells in which the tally should be accumulated.
:total:
Total reaction rate
:cellborn:
This filter allows the tally to be scored to only when particles were
originally born in a specified cell.
:scatter:
Total scattering rate. Can also be identified with the ``scatter-0``
response type.
:surface:
A list of surfaces for which the tally should be accumulated.
:nu-scatter:
Total production of neutrons due to scattering. This accounts for
multiplicity from (n,2n), (n,3n), and (n,4n) reactions and should be
slightly higher than the scattering rate.
:material:
A list of materials for which the tally should be accumulated.
:universe:
A list of universes for which the tally should be accumulated.
:energy:
A monotonically increasing list of bounding **pre-collision** energies for a
number of groups. For example, if this filter is specified as ``<energy>0.0
1.0 20.0</energy>``, then two energy bins will be created, one with energies
between 0 and 1 MeV and the other with energies between 1 and 20 MeV.
:energyout:
A monotonically increasing list of bounding **post-collision** energies for
a number of groups. For example, if this filter is specified as
``<energyout>0.0 1.0 20.0</energyout>``, then two post-collision energy bins
will be created, one with energies between 0 and 1 MeV and the other with
energies between 1 and 20 MeV.
:mesh:
The ``id`` of a structured mesh to be tallied over.
The following responses can be tallied.
:flux:
Total flux
:total:
Total reaction rate
:scatter:
Total scattering rate. Can also be identified with the ``scatter-0``
response type.
:nu-scatter:
Total production of neutrons due to scattering. This accounts for
multiplicity from (n,2n), (n,3n), and (n,4n) reactions and should be
slightly higher than the scattering rate.
:scatter-N:
Tally the N\ :sup:`th` \ scattering moment, where N is the Legendre expansion order.
N must be between 0 and 10. As an example, tallying the 2\ :sup:`nd` \ scattering
moment would be specified as ``<scores> scatter-2 </scores>``.
:scatter-N:
Tally the N\ :sup:`th` \ scattering moment, where N is the Legendre
expansion order. N must be between 0 and 10. As an example, tallying the
2\ :sup:`nd` \ scattering moment would be specified as ``<scores>
scatter-2 </scores>``.
:scatter-PN:
Tally all of the scattering moments from order 0 to N, where N is
the Legendre expansion order. That is, ``scatter-P1`` is equivalent
to requesting tallies of ``scatter-0`` and ``scatter-1``.
N must be between 0 and 10. As an example, tallying up to the 2\ :sup:`nd` \
scattering moment would be specified as ``<scores> scatter-P2 </scores>``.
:scatter-PN:
Tally all of the scattering moments from order 0 to N, where N is the
Legendre expansion order. That is, ``scatter-P1`` is equivalent to
requesting tallies of ``scatter-0`` and ``scatter-1``. N must be between
0 and 10. As an example, tallying up to the 2\ :sup:`nd` \ scattering
moment would be specified as ``<scores> scatter-P2 </scores>``.
:absorption:
Total absorption rate. This accounts for all reactions which do not produce
secondary neutrons.
:absorption:
Total absorption rate. This accounts for all reactions which do not
produce secondary neutrons.
:fission:
Total fission rate
:fission:
Total fission rate
:nu-fission:
Total production of neutrons due to fission
:nu-fission:
Total production of neutrons due to fission
:kappa-fission:
The recoverable energy production rate due to fission. The recoverable
energy is defined as the fission product kinetic energy, prompt and delayed neutron
kinetic energies, prompt and delayed :math:`\gamma`-ray total energies,
and the total energy released by the delayed :math:`\beta` particles. The
neutrino energy does not contribute to this response. The prompt and delayed
:math:`\gamma`-rays are assumed to deposit their energy locally.
:kappa-fission:
The recoverable energy production rate due to fission. The recoverable
energy is defined as the fission product kinetic energy, prompt and
delayed neutron kinetic energies, prompt and delayed :math:`\gamma`-ray
total energies, and the total energy released by the delayed :math:`\beta`
particles. The neutrino energy does not contribute to this response. The
prompt and delayed :math:`\gamma`-rays are assumed to deposit their energy
locally.
:events:
Number of scoring events
:current:
Partial currents on the boundaries of each cell in a mesh.
.. note::
This score can only be used if a mesh filter has been
specified. Furthermore, it may not be used in conjunction with any
other score.
:events:
Number of scoring events
``<mesh>`` Element
------------------
@ -885,16 +909,24 @@ attributes/sub-elements:
The type of structured mesh. Valid options include "rectangular" and
"hexagonal".
:lower_left:
The lower-left corner of the structured mesh. If only two coordinate are
given, it is assumed that the mesh is an x-y mesh.
:dimension:
The number of mesh cells in each direction.
:lower_left:
The lower-left corner of the structured mesh. If only two coordinates are
given, it is assumed that the mesh is an x-y mesh.
:upper_right:
The upper-right corner of the structured mesh. If only two coordinates are
given, it is assumed that the mesh is an x-y mesh.
:width:
The width of mesh cells in each direction.
.. note::
One of ``<upper_right>`` or ``<width>`` must be specified, but not both
(even if they are consistent with one another).
``<assume_separate>`` Element
-----------------------------
@ -902,7 +934,7 @@ In cases where the user needs to specify many different tallies each of which
are spatially separate, this tag can be used to cut down on some of the tally
overhead. The effect of assuming all tallies are spatially separate is that once
one tally is scored to, the same event is assumed not to score to any other
tallies. This element should be followed by "true" or "false"
tallies. This element should be followed by "true" or "false".
.. warning:: If used incorrectly, the assumption that all tallies are spatially
separate can lead to incorrect results.

View file

@ -83,7 +83,7 @@ Prerequisites
.. _gfortran: http://gcc.gnu.org/wiki/GFortran
.. _OpenMPI: http://www.open-mpi.org
.. _MPICH2: http://www.mpich.org
.. _MPICH: http://www.mpich.org
.. _HDF5: http://www.hdfgroup.org/HDF5/
.. _PETSc: http://www.mcs.anl.gov/petsc/

View file

@ -11,8 +11,8 @@ Problems with Compilation
If you are experiencing problems trying to compile OpenMC, first check if the
error you are receiving is among the following options.
undefined reference to `_vtab$...
*********************************
undefined reference to \`_vtab$...
**********************************
If you see this message when trying to compile, the most likely cause is that
you are using a compiler that does not support type-bound procedures from

View file

@ -8,9 +8,9 @@ continuous-energy transport code that uses ACE format cross sections. The
project started under the Computational Reactor Physics Group at MIT.
Complete documentation on the usage of OpenMC is hosted on GitHub at
http://mit-crpg.github.com/openmc/. If you are interested in the project or
would like to help and contribute, please send a message to the OpenMC User's
Group `mailing list`_.
http://mit-crpg.github.io/openmc/. If you are interested in the project or would
like to help and contribute, please send a message to the OpenMC User's Group
`mailing list`_.
------------
Installation
@ -46,7 +46,7 @@ License
OpenMC is distributed under the MIT/X license_.
.. _mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-users
.. _installation instructions: http://mit-crpg.github.com/openmc/usersguide/install.html
.. _Troubleshooting section: http://mit-crpg.github.com/openmc/usersguide/troubleshoot.html
.. _installation instructions: http://mit-crpg.github.io/openmc/usersguide/install.html
.. _Troubleshooting section: http://mit-crpg.github.io/openmc/usersguide/troubleshoot.html
.. _Issues: https://github.com/mit-crpg/openmc/issues
.. _license: http://mit-crpg.github.com/openmc/license.html
.. _license: http://mit-crpg.github.io/openmc/license.html

View file

@ -332,15 +332,14 @@ source.o: output.o
source.o: particle_header.o
source.o: physics.o
source.o: random_lcg.o
source.o: state_point.o
source.o: string.o
state_point.o: error.o
state_point.o: global.o
state_point.o: math.o
state_point.o: output.o
state_point.o: source.o
state_point.o: string.o
state_point.o: tally.o
state_point.o: tally_header.o
string.o: constants.o

View file

@ -1195,6 +1195,7 @@ contains
dims(1) = restart_batch
call h5ltread_dataset_double_f(hdf5_state_point, "k_batch", &
k_batch(1:restart_batch), dims, hdf5_err)
dims(1) = restart_batch*gen_per_batch
call h5ltread_dataset_double_f(hdf5_state_point, "entropy", &
entropy(1:restart_batch*gen_per_batch), dims, hdf5_err)
call hdf5_read_double(hdf5_state_point, "k_col_abs", k_col_abs)

View file

@ -9,6 +9,7 @@ module source
use particle_header, only: deallocate_coord
use physics, only: maxwell_spectrum, watt_spectrum
use random_lcg, only: prn, set_particle_seed
use state_point, only: read_source_binary
use string, only: to_str
#ifdef MPI
@ -229,175 +230,4 @@ contains
end subroutine initialize_particle
!===============================================================================
! WRITE_SOURCE writes out the final source distribution to a binary file that
! can be used as a starting source in a new simulation
!===============================================================================
subroutine write_source_binary()
#ifdef MPI
integer :: fh ! file handle
integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file)
! ==========================================================================
! PARALLEL I/O USING MPI-2 ROUTINES
! Open binary source file for reading
call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_CREATE + &
MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpi_err)
if (master) then
offset = 0
call MPI_FILE_WRITE_AT(fh, offset, n_particles, 1, MPI_INTEGER8, &
MPI_STATUS_IGNORE, mpi_err)
end if
! Set proper offset for source data on this processor
offset = 8*(1 + rank*maxwork*8)
! Write all source sites
call MPI_FILE_WRITE_AT(fh, offset, source_bank(1), work, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Close binary source file
call MPI_FILE_CLOSE(fh, mpi_err)
#else
! ==========================================================================
! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES
! Open binary source file for writing
open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='replace', &
ACCESS='stream')
! Write the number of particles
write(UNIT=UNIT_SOURCE) n_particles
! Write information from the source bank
write(UNIT=UNIT_SOURCE) source_bank(1:work)
! Close binary source file
close(UNIT=UNIT_SOURCE)
#endif
end subroutine write_source_binary
!===============================================================================
! READ_SOURCE_BINARY reads a source distribution from a source.binary file and
! initializes the source bank
!===============================================================================
subroutine read_source_binary()
integer :: i ! loop over repeating sites
integer(8) :: n_sites ! number of sites in binary file
integer :: n_repeat ! number of times to repeat a site
#ifdef MPI
integer :: fh ! file handle
integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file)
integer :: n_read ! number of sites to read on a single process
#endif
#ifdef MPI
! ==========================================================================
! PARALLEL I/O USING MPI-2 ROUTINES
! Open binary source file for reading
call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_RDONLY, &
MPI_INFO_NULL, fh, mpi_err)
! Read number of source sites in file
offset = 0
call MPI_FILE_READ_AT(fh, offset, n_sites, 1, MPI_INTEGER8, &
MPI_STATUS_IGNORE, mpi_err)
if (n_particles > n_sites) then
! Determine number of sites to read and offset
if (rank <= mod(n_sites,int(n_procs,8)) - 1) then
n_read = int(n_sites/n_procs) + 1
offset = 8*(1 + rank*n_read*8)
else
n_read = int(n_sites/n_procs)
offset = 8*(1 + (rank*n_read + mod(n_sites,int(n_procs,8)))*8)
end if
! Read source sites
call MPI_FILE_READ_AT(fh, offset, source_bank(1), n_read, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Let's say we have 30 sites and we need to fill in 200. This do loop
! will fill in sites 31 - 180.
n_repeat = int(work / n_read)
do i = 1, n_repeat - 1
source_bank(i*n_read + 1:(i+1)*n_read) = &
source_bank((i-1)*n_read + 1:i*n_read)
end do
! This final statement would fill sites 181 - 200 in the above example.
if (mod(work, int(n_repeat*n_read,8)) > 0) then
source_bank(n_repeat*n_read + 1:work) = &
source_bank(1:work - n_repeat * n_read)
end if
else
! Set proper offset for source data on this processor
offset = 8*(1 + rank*maxwork*8)
! Read all source sites
call MPI_FILE_READ_AT(fh, offset, source_bank(1), work, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Close binary source file
call MPI_FILE_CLOSE(fh, mpi_err)
end if
#else
! ==========================================================================
! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES
! Open binary source file for reading
open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='old', &
ACCESS='stream')
! Read number of source sites in file
read(UNIT=UNIT_SOURCE) n_sites
if (n_particles > n_sites) then
! The size of the source file is smaller than the number of particles we
! need. Thus, read all sites and then duplicate sites as necessary.
read(UNIT=UNIT_SOURCE) source_bank(1:n_sites)
! Let's say we have 300 sites and we need to fill in 1000. This do loop
! will fill in sites 301 - 900.
n_repeat = int(n_particles / n_sites)
do i = 1, n_repeat - 1
source_bank(i*n_sites + 1:(i+1)*n_sites) = &
source_bank((i-1)*n_sites + 1:i*n_sites)
end do
! This final statement would fill sites 901 - 1000 in the above example.
source_bank(n_repeat*n_sites + 1:n_particles) = &
source_bank(1:n_particles - n_repeat * n_sites)
else
! The size of the source file is bigger than or equal to the number of
! particles we need for one generation. Thus, we can just read as many
! sites as we need.
read(UNIT=UNIT_SOURCE) source_bank(1:n_particles)
end if
! Close binary source file
close(UNIT=UNIT_SOURCE)
#endif
end subroutine read_source_binary
end module source

View file

@ -22,10 +22,8 @@ module state_point
use global
use math, only: t_percentile
use output, only: write_message, print_batch_keff, time_stamp
use source, only: write_source_binary
use string, only: to_str
use tally_header, only: TallyObject
use tally, only: setup_active_usertallies
#ifdef MPI
use mpi
@ -1113,4 +1111,175 @@ contains
end subroutine replay_batch_history
!===============================================================================
! WRITE_SOURCE writes out the final source distribution to a binary file that
! can be used as a starting source in a new simulation
!===============================================================================
subroutine write_source_binary()
#ifdef MPI
integer :: fh ! file handle
integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file)
! ==========================================================================
! PARALLEL I/O USING MPI-2 ROUTINES
! Open binary source file for reading
call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_CREATE + &
MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpi_err)
if (master) then
offset = 0
call MPI_FILE_WRITE_AT(fh, offset, n_particles, 1, MPI_INTEGER8, &
MPI_STATUS_IGNORE, mpi_err)
end if
! Set proper offset for source data on this processor
offset = 8*(1 + rank*maxwork*8)
! Write all source sites
call MPI_FILE_WRITE_AT(fh, offset, source_bank(1), work, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Close binary source file
call MPI_FILE_CLOSE(fh, mpi_err)
#else
! ==========================================================================
! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES
! Open binary source file for writing
open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='replace', &
ACCESS='stream')
! Write the number of particles
write(UNIT=UNIT_SOURCE) n_particles
! Write information from the source bank
write(UNIT=UNIT_SOURCE) source_bank(1:work)
! Close binary source file
close(UNIT=UNIT_SOURCE)
#endif
end subroutine write_source_binary
!===============================================================================
! READ_SOURCE_BINARY reads a source distribution from a source.binary file and
! initializes the source bank
!===============================================================================
subroutine read_source_binary()
integer :: i ! loop over repeating sites
integer(8) :: n_sites ! number of sites in binary file
integer :: n_repeat ! number of times to repeat a site
#ifdef MPI
integer :: fh ! file handle
integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file)
integer :: n_read ! number of sites to read on a single process
#endif
#ifdef MPI
! ==========================================================================
! PARALLEL I/O USING MPI-2 ROUTINES
! Open binary source file for reading
call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_RDONLY, &
MPI_INFO_NULL, fh, mpi_err)
! Read number of source sites in file
offset = 0
call MPI_FILE_READ_AT(fh, offset, n_sites, 1, MPI_INTEGER8, &
MPI_STATUS_IGNORE, mpi_err)
if (n_particles > n_sites) then
! Determine number of sites to read and offset
if (rank <= mod(n_sites,int(n_procs,8)) - 1) then
n_read = int(n_sites/n_procs) + 1
offset = 8*(1 + rank*n_read*8)
else
n_read = int(n_sites/n_procs)
offset = 8*(1 + (rank*n_read + mod(n_sites,int(n_procs,8)))*8)
end if
! Read source sites
call MPI_FILE_READ_AT(fh, offset, source_bank(1), n_read, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Let's say we have 30 sites and we need to fill in 200. This do loop
! will fill in sites 31 - 180.
n_repeat = int(work / n_read)
do i = 1, n_repeat - 1
source_bank(i*n_read + 1:(i+1)*n_read) = &
source_bank((i-1)*n_read + 1:i*n_read)
end do
! This final statement would fill sites 181 - 200 in the above example.
if (mod(work, int(n_repeat*n_read,8)) > 0) then
source_bank(n_repeat*n_read + 1:work) = &
source_bank(1:work - n_repeat * n_read)
end if
else
! Set proper offset for source data on this processor
offset = 8*(1 + rank*maxwork*8)
! Read all source sites
call MPI_FILE_READ_AT(fh, offset, source_bank(1), work, MPI_BANK, &
MPI_STATUS_IGNORE, mpi_err)
! Close binary source file
call MPI_FILE_CLOSE(fh, mpi_err)
end if
#else
! ==========================================================================
! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES
! Open binary source file for reading
open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='old', &
ACCESS='stream')
! Read number of source sites in file
read(UNIT=UNIT_SOURCE) n_sites
if (n_particles > n_sites) then
! The size of the source file is smaller than the number of particles we
! need. Thus, read all sites and then duplicate sites as necessary.
read(UNIT=UNIT_SOURCE) source_bank(1:n_sites)
! Let's say we have 300 sites and we need to fill in 1000. This do loop
! will fill in sites 301 - 900.
n_repeat = int(n_particles / n_sites)
do i = 1, n_repeat - 1
source_bank(i*n_sites + 1:(i+1)*n_sites) = &
source_bank((i-1)*n_sites + 1:i*n_sites)
end do
! This final statement would fill sites 901 - 1000 in the above example.
source_bank(n_repeat*n_sites + 1:n_particles) = &
source_bank(1:n_particles - n_repeat * n_sites)
else
! The size of the source file is bigger than or equal to the number of
! particles we need for one generation. Thus, we can just read as many
! sites as we need.
read(UNIT=UNIT_SOURCE) source_bank(1:n_particles)
end if
! Close binary source file
close(UNIT=UNIT_SOURCE)
#endif
end subroutine read_source_binary
end module state_point

296
src/utils/plot_mesh_tally.py Executable file
View file

@ -0,0 +1,296 @@
#!/usr/bin/env python
'''Python script to plot tally data generated by OpenMC.'''
import sys
from statepoint import *
# Color intensity dependent on individual score?
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import numpy as np
class AppForm(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
# Read data from source or leakage fraction file
self.get_file_data()
self.main_frame = QWidget()
self.setCentralWidget(self.main_frame)
# Create the Figure, Canvas, and Axes
self.dpi = 100
self.fig = Figure((5.0, 15.0), dpi=self.dpi)
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.axes = self.fig.add_subplot(111)
# Create the navigation toolbar, tied to the canvas
self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
# Grid layout at bottom
self.grid = QGridLayout()
# Overall layout
self.vbox = QVBoxLayout()
self.vbox.addWidget(self.canvas)
self.vbox.addWidget(self.mpl_toolbar)
self.vbox.addLayout(self.grid)
self.main_frame.setLayout(self.vbox)
# Tally selections
label_tally = QLabel("Tally:")
self.tally = QComboBox()
self.tally.addItems([(str(i + 1)) for i in range(self.n_tallies)])
self.connect(self.tally, SIGNAL('activated(int)'),
self._update)
self.connect(self.tally, SIGNAL('activated(int)'),
self.populate_boxes)
self.connect(self.tally, SIGNAL('activated(int)'),
self.on_draw)
# Planar basis
label_basis = QLabel("Basis:")
self.basis = QComboBox()
self.basis.addItems(['xy', 'yz', 'xz'])
# Update window when 'Basis' selection is changed
self.connect(self.basis, SIGNAL('activated(int)'),
self._update)
self.connect(self.basis, SIGNAL('activated(int)'),
self.populate_boxes)
self.connect(self.basis, SIGNAL('activated(int)'),
self.on_draw)
# Axial level within selected basis
label_axial_level = QLabel("Axial Level:")
self.axial_level = QComboBox()
self.connect(self.axial_level, SIGNAL('activated(int)'),
self.on_draw)
self.label_filters = QLabel("Filter options:")
# Labels for all possible filters
self.labels = {'cell': 'Cell: ', 'cellborn': 'Cell born: ',
'surface': 'Surface: ', 'material': 'Material',
'universe': 'Universe: ', 'energyin': 'Energy in: ',
'energyout': 'Energy out: '}
# Empty reusable labels
self.qlabels = {}
for j in range(8):
self.nextLabel = QLabel
self.qlabels[j] = self.nextLabel
# Reusable comboboxes labelled with filter names
self.boxes = {}
for key in self.labels.keys():
self.nextBox = QComboBox()
self.connect(self.nextBox, SIGNAL('activated(int)'),
self.on_draw)
self.boxes[key] = self.nextBox
# Combobox to select among scores
self.score_label = QLabel("Score:")
self.scoreBox = QComboBox()
for item in self.tally_scores[0]:
self.scoreBox.addItems(str(item))
self.connect(self.scoreBox, SIGNAL('activated(int)'),
self.on_draw)
# Fill layout
self.grid.addWidget(label_tally, 0, 0)
self.grid.addWidget(self.tally, 0, 1)
self.grid.addWidget(label_basis, 1, 0)
self.grid.addWidget(self.basis, 1, 1)
self.grid.addWidget(label_axial_level, 2, 0)
self.grid.addWidget(self.axial_level, 2, 1)
self.grid.addWidget(self.label_filters, 3, 0)
self._update()
self.populate_boxes()
self.on_draw()
def get_file_data(self):
# Get data file name from "open file" browser
filename = QFileDialog.getOpenFileName(self, 'Select statepoint file', '.')
# Create StatePoint object and read in data
self.datafile = StatePoint(str(filename))
self.datafile.read_results()
self.datafile.generate_stdev()
self.setWindowTitle('Core Map Tool : ' + str(self.datafile.path))
# Set maximum colorbar value by maximum tally data value
self.maxvalue = self.datafile.tallies[0].results.max()
self.labelList = []
# Read mesh dimensions
# for mesh in self.datafile.meshes:
# self.nx, self.ny, self.nz = mesh.dimension
# Read filter types from statepoint file
self.n_tallies = len(self.datafile.tallies)
self.tally_list = []
for tally in self.datafile.tallies:
self.filter_types = []
for f in tally.filters:
self.filter_types.append(f)
self.tally_list.append(self.filter_types)
# Read score types from statepoint file
self.tally_scores = []
for tally in self.datafile.tallies:
self.score_types = []
for s in tally.scores:
self.score_types.append(s)
self.tally_scores.append(self.score_types)
# print 'self.tally_scores = ', self.tally_scores
def on_draw(self):
""" Redraws the figure
"""
# print 'Calling on_draw...'
# Get selected basis, axial_level and stage
basis = self.basis.currentIndex() + 1
axial_level = self.axial_level.currentIndex() + 1
# Create spec_list
spec_list = []
for tally in self.datafile.tallies[self.tally.currentIndex()].filters.values():
if tally.type == 'mesh':
continue
index = self.boxes[tally.type].currentIndex()
spec_list.append((tally.type, index))
if self.basis.currentText() == 'xy':
matrix = np.zeros((self.nx, self.ny))
for i in range(self.nx):
for j in range(self.ny):
matrix[i,j] = self.datafile.get_value(self.tally.currentIndex(), spec_list + [('mesh', (i, j, axial_level))], self.scoreBox.currentIndex())[0]
elif self.basis.currentText() == 'yz':
matrix = np.zeros((self.ny, self.nz))
for i in range(self.ny):
for j in range(self.nz):
matrix[i,j] = self.datafile.get_value(self.tally.currentIndex(), spec_list + [('mesh', (axial_level, i, j))], self.scoreBox.currentIndex())[0]
else:
matrix = np.zeros((self.nx, self.nz))
for i in range(self.nx):
for j in range(self.nz):
matrix[i,j] = self.datafile.get_value(self.tally.currentIndex(), spec_list + [('mesh', (i, axial_level, j))], self.scoreBox.currentIndex())[0]
# print spec_list
# Clear the figure
self.fig.clear()
# Make figure, set up color bar
self.axes = self.fig.add_subplot(111)
cax = self.axes.imshow(matrix, vmin=0.0, vmax=matrix.max(), interpolation="nearest")
self.fig.colorbar(cax)
self.axes.set_xticks([])
self.axes.set_yticks([])
self.axes.set_aspect('equal')
# Draw canvas
self.canvas.draw()
def _update(self):
'''Updates widget to display new relevant comboboxes and figure data
'''
# print 'Calling _update...'
self.mesh = self.datafile.meshes[self.datafile.tallies[self.tally.currentIndex()].filters['mesh'].bins[0] - 1]
self.nx, self.ny, self.nz = self.mesh.dimension
# Clear axial level combobox
self.axial_level.clear()
# Repopulate axial level combobox based on current basis selection
if (self.basis.currentText() == 'xy'):
self.axial_level.addItems([str(i+1) for i in range(self.nz)])
elif (self.basis.currentText() == 'yz'):
self.axial_level.addItems([str(i+1) for i in range(self.nx)])
else:
self.axial_level.addItems([str(i+1) for i in range(self.ny)])
# Determine maximum value from current tally data set
self.maxvalue = self.datafile.tallies[self.tally.currentIndex()].results.max()
# print self.maxvalue
# Clear and hide old filter labels
for item in self.labelList:
item.clear()
# Clear and hide old filter boxes
for j in self.labels:
self.boxes[j].clear()
self.boxes[j].setParent(None)
self.update()
def populate_boxes(self):
# print 'Calling populate_boxes...'
n = 4
labels = {'cell': 'Cell : ',
'cellborn': 'Cell born: ',
'surface': 'Surface: ',
'material': 'Material: ',
'universe': 'Universe: '}
# For each filter in newly-selected tally, name a label and fill the
# relevant combobox with options
for element in self.tally_list[self.tally.currentIndex()]:
nextFilter = self.datafile.tallies[self.tally.currentIndex()].filters[element]
if element == 'mesh':
continue
label = QLabel(self.labels[element])
self.labelList.append(label)
combobox = self.boxes[element]
self.grid.addWidget(label, n, 0)
self.grid.addWidget(combobox, n, 1)
n += 1
# print element
if element in ['cell', 'cellborn', 'surface', 'material', 'universe']:
combobox.addItems([str(i) for i in nextFilter.bins])
# for i in nextFilter.bins:
# print i
elif element == 'energyin' or element == 'energyout':
for i in range(nextFilter.length):
text = str(nextFilter.bins[i]) + ' to ' + str(nextFilter.bins[i+1])
combobox.addItem(text)
self.scoreBox.clear()
for item in self.tally_scores[self.tally.currentIndex()]:
self.scoreBox.addItem(str(item))
self.grid.addWidget(self.score_label, n, 0)
self.grid.addWidget(self.scoreBox, n, 1)
def main():
app = QApplication(sys.argv)
form = AppForm()
form.show()
app.exec_()
if __name__ == "__main__":
main()

32
tests/readme.rst Normal file
View file

@ -0,0 +1,32 @@
=================
OpenMC Test Suite
=================
The purpose of this test suite is to ensure that OpenMC compiles using various
combinations of compiler flags and options and that all user input options can
be used successfully without breaking the code. The test suite is by no means
complete and should not be viewed as a comprehensive unit test suite will full
coverage. Until more effort can be put into actual unit testing, this suite is a
simple means of making sure that new features added into the code don't break
existing features.
The test suite is designed to run with the third-party Python package
nose_. Running the test suite is as simple as going to the tests/ directory and
running:
.. sh::
nosetests
However, usually testing is split into two parts: compilation and running. To
run the compilation tests, use:
.. sh::
nosetests test_compile
Then, to run all the normal tests (which require that an OpenMC executable is
already built):
.. sh::
nosetests --exclude-dir=test_compile
.. _nose: https://nose.readthedocs.org