mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 06:25:30 -04:00
Add distributed cell densities (#3546)
Co-authored-by: Patrick Shriwise <pshriwise@gmail.com> Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
parent
afd9d06074
commit
607f6babe5
32 changed files with 607 additions and 52 deletions
|
|
@ -84,6 +84,17 @@ Functions
|
|||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_cell_get_density(int32_t index, const int32_t* instance, double* density)
|
||||
|
||||
Get the density of a cell
|
||||
|
||||
:param int32_t index: Index in the cells array
|
||||
:param int32_t* instance: Which instance of the cell. If a null pointer is passed, the density
|
||||
multiplier of the first instance is returned.
|
||||
:param double* density: Density of the cell in [g/cm3]
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_cell_set_fill(int32_t index, int type, int32_t n, const int32_t* indices)
|
||||
|
||||
Set the fill for a cell
|
||||
|
|
@ -113,8 +124,22 @@ Functions
|
|||
:param double T: Temperature in Kelvin
|
||||
:param instance: Which instance of the cell. To set the temperature for all
|
||||
instances, pass a null pointer.
|
||||
:param set_contained: If the cell is not filled by a material, whether to set the temperatures
|
||||
of all filled cells
|
||||
:param bool set_contained: If the cell is not filled by a material, whether
|
||||
to set the temperatures of all filled cells
|
||||
:type instance: const int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_cell_set_density(index index, double density, const int32_t* instance, bool set_contained)
|
||||
|
||||
Set the density of a cell.
|
||||
|
||||
:param int32_t index: Index in the cells array
|
||||
:param double density: Density of the cell in [g/cm3]
|
||||
:param instance: Which instance of the cell. To set the density multiplier for all
|
||||
instances, pass a null pointer.
|
||||
:param bool set_contained: If the cell is not filled by a material, whether
|
||||
to set the density multiplier of all filled cells
|
||||
:type instance: const int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Properties File Format
|
||||
======================
|
||||
|
||||
The current version of the properties file format is 1.0.
|
||||
The current version of the properties file format is 1.1.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -25,6 +25,7 @@ The current version of the properties file format is 1.0.
|
|||
**/geometry/cells/cell <uid>/**
|
||||
|
||||
:Datasets: - **temperature** (*double[]*) -- Temperature of the cell in [K].
|
||||
- **density** (*double[]*) -- Density of the cell in [g/cm3].
|
||||
|
||||
**/materials/**
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Summary File Format
|
||||
===================
|
||||
|
||||
The current version of the summary file format is 6.0.
|
||||
The current version of the summary file format is 6.1.
|
||||
|
||||
**/**
|
||||
|
||||
|
|
@ -38,6 +38,7 @@ The current version of the summary file format is 6.0.
|
|||
is an array if the cell uses distributed materials, otherwise it is
|
||||
a scalar.
|
||||
- **temperature** (*double[]*) -- Temperature of the cell in Kelvin.
|
||||
- **density** (*double[]*) -- Density of the cell in [g/cm3].
|
||||
- **translation** (*double[3]*) -- Translation applied to the fill
|
||||
universe. This dataset is present only if fill_type is set to
|
||||
'universe'.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ int openmc_cell_get_fill(
|
|||
int openmc_cell_get_id(int32_t index, int32_t* id);
|
||||
int openmc_cell_get_temperature(
|
||||
int32_t index, const int32_t* instance, double* T);
|
||||
int openmc_cell_get_density(
|
||||
int32_t index, const int32_t* instance, double* rho);
|
||||
int openmc_cell_get_translation(int32_t index, double xyz[]);
|
||||
int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n);
|
||||
int openmc_cell_get_name(int32_t index, const char** name);
|
||||
|
|
@ -27,6 +29,8 @@ int openmc_cell_set_fill(
|
|||
int openmc_cell_set_id(int32_t index, int32_t id);
|
||||
int openmc_cell_set_temperature(
|
||||
int32_t index, double T, const int32_t* instance, bool set_contained = false);
|
||||
int openmc_cell_set_density(int32_t index, double rho, const int32_t* instance,
|
||||
bool set_contained = false);
|
||||
int openmc_cell_set_translation(int32_t index, const double xyz[]);
|
||||
int openmc_cell_set_rotation(int32_t index, const double rot[], size_t rot_len);
|
||||
int openmc_dagmc_universe_get_cell_ids(
|
||||
|
|
|
|||
|
|
@ -216,6 +216,18 @@ public:
|
|||
//! \return Temperature in [K]
|
||||
double temperature(int32_t instance = -1) const;
|
||||
|
||||
//! Get the density multiplier of a cell instance
|
||||
//! \param[in] instance Instance index. If -1 is given, the density multiplier
|
||||
//! for the first instance is returned.
|
||||
//! \return Density multiplier
|
||||
double density_mult(int32_t instance = -1) const;
|
||||
|
||||
//! Get the density of a cell instance in g/cm3
|
||||
//! \param[in] instance Instance index. If -1 is given, the density
|
||||
//! for the first instance is returned.
|
||||
//! \return Density in [g/cm3]
|
||||
double density(int32_t instance = -1) const;
|
||||
|
||||
//! Set the temperature of a cell instance
|
||||
//! \param[in] T Temperature in [K]
|
||||
//! \param[in] instance Instance index. If -1 is given, the temperature for
|
||||
|
|
@ -226,6 +238,16 @@ public:
|
|||
void set_temperature(
|
||||
double T, int32_t instance = -1, bool set_contained = false);
|
||||
|
||||
//! Set the density of a cell instance
|
||||
//! \param[in] density Density [g/cm3]
|
||||
//! \param[in] instance Instance index. If -1 is given, the density
|
||||
//! for all instances is set.
|
||||
//! \param[in] set_contained If this cell is not filled with a material,
|
||||
//! collect all contained cells with material fills and set their
|
||||
//! densities.
|
||||
void set_density(
|
||||
double density, int32_t instance = -1, bool set_contained = false);
|
||||
|
||||
int32_t n_instances() const;
|
||||
|
||||
//! Set the rotation matrix of a cell instance
|
||||
|
|
@ -334,6 +356,9 @@ public:
|
|||
//! T. The units are sqrt(eV).
|
||||
vector<double> sqrtkT_;
|
||||
|
||||
//! \brief Unitless density multiplier(s) within this cell.
|
||||
vector<double> density_mult_;
|
||||
|
||||
//! \brief Neighboring cells in the same universe.
|
||||
NeighborList neighbors_;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ constexpr int HDF5_VERSION[] {3, 0};
|
|||
constexpr array<int, 2> VERSION_STATEPOINT {18, 1};
|
||||
constexpr array<int, 2> VERSION_PARTICLE_RESTART {2, 0};
|
||||
constexpr array<int, 2> VERSION_TRACK {3, 0};
|
||||
constexpr array<int, 2> VERSION_SUMMARY {6, 0};
|
||||
constexpr array<int, 2> VERSION_SUMMARY {6, 1};
|
||||
constexpr array<int, 2> VERSION_VOLUME {1, 0};
|
||||
constexpr array<int, 2> VERSION_VOXEL {2, 0};
|
||||
constexpr array<int, 2> VERSION_MGXS_LIBRARY {1, 0};
|
||||
constexpr array<int, 2> VERSION_PROPERTIES {1, 0};
|
||||
constexpr array<int, 2> VERSION_PROPERTIES {1, 1};
|
||||
constexpr array<int, 2> VERSION_WEIGHT_WINDOWS {1, 0};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@ void adjust_indices();
|
|||
|
||||
void assign_temperatures();
|
||||
|
||||
//==============================================================================
|
||||
//! Finalize densities (compute density multipliers).
|
||||
//==============================================================================
|
||||
|
||||
void finalize_cell_densities();
|
||||
|
||||
//==============================================================================
|
||||
//! \brief Obtain a list of temperatures that each nuclide/thermal scattering
|
||||
//! table appears at in the model. Later, this list is used to determine the
|
||||
|
|
|
|||
|
|
@ -99,6 +99,13 @@ public:
|
|||
//----------------------------------------------------------------------------
|
||||
// Accessors
|
||||
|
||||
//! Get the atom density in [atom/b-cm]
|
||||
//! \return Density in [atom/b-cm]
|
||||
double atom_density(int32_t i, double rho_multiplier = 1.0) const
|
||||
{
|
||||
return atom_density_(i) * rho_multiplier;
|
||||
}
|
||||
|
||||
//! Get density in [atom/b-cm]
|
||||
//! \return Density in [atom/b-cm]
|
||||
double density() const { return density_; }
|
||||
|
|
|
|||
|
|
@ -389,6 +389,11 @@ public:
|
|||
const double& sqrtkT() const { return sqrtkT_; }
|
||||
double& sqrtkT_last() { return sqrtkT_last_; }
|
||||
|
||||
// density multiplier of the current and last cell
|
||||
double& density_mult() { return density_mult_; }
|
||||
const double& density_mult() const { return density_mult_; }
|
||||
double& density_mult_last() { return density_mult_last_; }
|
||||
|
||||
private:
|
||||
int64_t id_ {-1}; //!< Unique ID
|
||||
|
||||
|
|
@ -417,6 +422,9 @@ private:
|
|||
double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV
|
||||
double sqrtkT_last_ {0.0}; //!< last temperature
|
||||
|
||||
double density_mult_ {1.0}; //!< density multiplier
|
||||
double density_mult_last_ {1.0}; //!< last density multiplier
|
||||
|
||||
#ifdef OPENMC_DAGMC_ENABLED
|
||||
moab::DagMC::RayHistory history_;
|
||||
Direction last_dir_;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ class Cell(IDManagerMixin):
|
|||
temperature : float or iterable of float
|
||||
Temperature of the cell in Kelvin. Multiple temperatures can be given
|
||||
to give each distributed cell instance a unique temperature.
|
||||
density : float or iterable of float
|
||||
Density of the cell in [g/cm3]. Multiple densities can be given to give
|
||||
each distributed cell instance a unique density. Densities set here will
|
||||
override the density set on materials used to fill the cell.
|
||||
translation : Iterable of float
|
||||
If the cell is filled with a universe, this array specifies a vector
|
||||
that is used to translate (shift) the universe.
|
||||
|
|
@ -109,6 +113,7 @@ class Cell(IDManagerMixin):
|
|||
self._rotation = None
|
||||
self._rotation_matrix = None
|
||||
self._temperature = None
|
||||
self._density = None
|
||||
self._translation = None
|
||||
self._paths = None
|
||||
self._num_instances = None
|
||||
|
|
@ -141,6 +146,7 @@ class Cell(IDManagerMixin):
|
|||
if self.fill_type == 'material':
|
||||
string += '\t{0: <15}=\t{1}\n'.format('Temperature',
|
||||
self.temperature)
|
||||
string += '\t{0: <15}=\t{1}\n'.format('Density', self.density)
|
||||
string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation)
|
||||
string += '{: <16}=\t{}\n'.format('\tVolume', self.volume)
|
||||
|
||||
|
|
@ -257,6 +263,30 @@ class Cell(IDManagerMixin):
|
|||
else:
|
||||
self._temperature = temperature
|
||||
|
||||
@property
|
||||
def density(self):
|
||||
return self._density
|
||||
|
||||
@density.setter
|
||||
def density(self, density):
|
||||
# Make sure densities are greater than zero
|
||||
cv.check_type('cell density', density, (Iterable, Real), none_ok=True)
|
||||
if isinstance(density, Iterable):
|
||||
cv.check_type('cell density', density, Iterable, Real)
|
||||
for rho in density:
|
||||
cv.check_greater_than('cell density', rho, 0.0, True)
|
||||
elif isinstance(density, Real):
|
||||
cv.check_greater_than('cell density', density, 0.0, True)
|
||||
|
||||
# If this cell is filled with a universe or lattice, propagate
|
||||
# densities to all cells contained. Otherwise, simply assign it.
|
||||
if self.fill_type in ('universe', 'lattice'):
|
||||
for c in self.get_all_cells().values():
|
||||
if c.fill_type == 'material':
|
||||
c._density = density
|
||||
else:
|
||||
self._density = density
|
||||
|
||||
@property
|
||||
def translation(self):
|
||||
return self._translation
|
||||
|
|
@ -525,6 +555,8 @@ class Cell(IDManagerMixin):
|
|||
clone.volume = self.volume
|
||||
if self.temperature is not None:
|
||||
clone.temperature = self.temperature
|
||||
if self.density is not None:
|
||||
clone.density = self.density
|
||||
if self.translation is not None:
|
||||
clone.translation = self.translation
|
||||
if self.rotation is not None:
|
||||
|
|
@ -650,6 +682,12 @@ class Cell(IDManagerMixin):
|
|||
else:
|
||||
element.set("temperature", str(self.temperature))
|
||||
|
||||
if self.density is not None:
|
||||
if isinstance(self.density, Iterable):
|
||||
element.set("density", ' '.join(str(t) for t in self.density))
|
||||
else:
|
||||
element.set("density", str(self.density))
|
||||
|
||||
if self.translation is not None:
|
||||
element.set("translation", ' '.join(map(str, self.translation)))
|
||||
|
||||
|
|
@ -711,10 +749,13 @@ class Cell(IDManagerMixin):
|
|||
c.temperature = temperature
|
||||
else:
|
||||
c.temperature = temperature[0]
|
||||
density = get_elem_list(elem, 'density', float)
|
||||
if density is not None:
|
||||
c.density = density if len(density) > 1 else density[0]
|
||||
v = get_text(elem, 'volume')
|
||||
if v is not None:
|
||||
c.volume = float(v)
|
||||
for key in ('temperature', 'rotation', 'translation'):
|
||||
for key in ('temperature', 'density', 'rotation', 'translation'):
|
||||
values = get_elem_list(elem, key, float)
|
||||
if values is not None:
|
||||
if key == 'rotation' and len(values) == 9:
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ _dll.openmc_cell_get_temperature.argtypes = [
|
|||
c_int32, POINTER(c_int32), POINTER(c_double)]
|
||||
_dll.openmc_cell_get_temperature.restype = c_int
|
||||
_dll.openmc_cell_get_temperature.errcheck = _error_handler
|
||||
_dll.openmc_cell_get_density.argtypes = [
|
||||
c_int32, POINTER(c_int32), POINTER(c_double)]
|
||||
_dll.openmc_cell_get_density.restype = c_int
|
||||
_dll.openmc_cell_get_density.errcheck = _error_handler
|
||||
_dll.openmc_cell_get_name.argtypes = [c_int32, POINTER(c_char_p)]
|
||||
_dll.openmc_cell_get_name.restype = c_int
|
||||
_dll.openmc_cell_get_name.errcheck = _error_handler
|
||||
|
|
@ -58,6 +62,10 @@ _dll.openmc_cell_set_temperature.argtypes = [
|
|||
c_int32, c_double, POINTER(c_int32), c_bool]
|
||||
_dll.openmc_cell_set_temperature.restype = c_int
|
||||
_dll.openmc_cell_set_temperature.errcheck = _error_handler
|
||||
_dll.openmc_cell_set_density.argtypes = [
|
||||
c_int32, c_double, POINTER(c_int32), c_bool]
|
||||
_dll.openmc_cell_set_density.restype = c_int
|
||||
_dll.openmc_cell_set_density.errcheck = _error_handler
|
||||
_dll.openmc_cell_set_translation.argtypes = [c_int32, POINTER(c_double)]
|
||||
_dll.openmc_cell_set_translation.restype = c_int
|
||||
_dll.openmc_cell_set_translation.errcheck = _error_handler
|
||||
|
|
@ -236,6 +244,44 @@ class Cell(_FortranObjectWithID):
|
|||
|
||||
_dll.openmc_cell_set_temperature(self._index, T, instance, set_contained)
|
||||
|
||||
def get_density(self, instance: int | None = None):
|
||||
"""Get the density of a cell in [g/cm3]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
instance : int or None
|
||||
Which instance of the cell
|
||||
|
||||
"""
|
||||
|
||||
if instance is not None:
|
||||
instance = c_int32(instance)
|
||||
|
||||
rho = c_double()
|
||||
_dll.openmc_cell_get_density(self._index, instance, rho)
|
||||
return rho.value
|
||||
|
||||
def set_density(self, rho: float, instance: int | None = None,
|
||||
set_contained: bool = False):
|
||||
"""Set the density of a cell
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rho : float
|
||||
Density of the cell in [g/cm3]
|
||||
instance : int or None
|
||||
Which instance of the cell
|
||||
set_contained : bool
|
||||
If cell is not filled by a material, whether to set the density
|
||||
of all filled cells
|
||||
|
||||
"""
|
||||
|
||||
if instance is not None:
|
||||
instance = c_int32(instance)
|
||||
|
||||
_dll.openmc_cell_set_density(self._index, rho, instance, set_contained)
|
||||
|
||||
@property
|
||||
def translation(self):
|
||||
translation = np.zeros(3)
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ class Model:
|
|||
raise ValueError("Number of cells in properties file doesn't "
|
||||
"match current model.")
|
||||
|
||||
# Update temperatures for cells filled with materials
|
||||
# Update temperatures and densities for cells filled with materials
|
||||
for name, group in cells_group.items():
|
||||
cell_id = int(name.split()[1])
|
||||
cell = cells[cell_id]
|
||||
|
|
@ -648,6 +648,20 @@ class Model:
|
|||
else:
|
||||
lib_cell.set_temperature(temperature[0])
|
||||
|
||||
if group['density']:
|
||||
density = group['density'][()]
|
||||
if density.size > 1:
|
||||
cell.density = [rho for rho in density]
|
||||
else:
|
||||
cell.density = density
|
||||
if self.is_initialized:
|
||||
lib_cell = openmc.lib.cells[cell_id]
|
||||
if density.size > 1:
|
||||
for i, rho in enumerate(density):
|
||||
lib_cell.set_density(rho, i)
|
||||
else:
|
||||
lib_cell.set_density(density[0])
|
||||
|
||||
# Make sure number of materials matches
|
||||
mats_group = fh['materials']
|
||||
n_cells = mats_group.attrs['n_materials']
|
||||
|
|
|
|||
178
src/cell.cpp
178
src/cell.cpp
|
|
@ -101,6 +101,25 @@ double Cell::temperature(int32_t instance) const
|
|||
}
|
||||
}
|
||||
|
||||
double Cell::density_mult(int32_t instance) const
|
||||
{
|
||||
if (instance >= 0) {
|
||||
return density_mult_.size() == 1 ? density_mult_.at(0)
|
||||
: density_mult_.at(instance);
|
||||
} else {
|
||||
return density_mult_[0];
|
||||
}
|
||||
}
|
||||
|
||||
double Cell::density(int32_t instance) const
|
||||
{
|
||||
const int32_t mat_index = material(instance);
|
||||
if (mat_index == MATERIAL_VOID)
|
||||
return 0.0;
|
||||
|
||||
return density_mult(instance) * model::materials[mat_index]->density_gpcc();
|
||||
}
|
||||
|
||||
void Cell::set_temperature(double T, int32_t instance, bool set_contained)
|
||||
{
|
||||
if (settings::temperature_method == TemperatureMethod::INTERPOLATION) {
|
||||
|
|
@ -151,6 +170,47 @@ void Cell::set_temperature(double T, int32_t instance, bool set_contained)
|
|||
}
|
||||
}
|
||||
|
||||
void Cell::set_density(double density, int32_t instance, bool set_contained)
|
||||
{
|
||||
if (type_ != Fill::MATERIAL && !set_contained) {
|
||||
fatal_error(
|
||||
fmt::format("Attempted to set the density multiplier of cell {} "
|
||||
"which is not filled by a material.",
|
||||
id_));
|
||||
}
|
||||
|
||||
if (type_ == Fill::MATERIAL) {
|
||||
const int32_t mat_index = material(instance);
|
||||
if (mat_index == MATERIAL_VOID)
|
||||
return;
|
||||
|
||||
if (instance >= 0) {
|
||||
// If density multiplier vector is not big enough, resize it first
|
||||
if (density_mult_.size() != n_instances())
|
||||
density_mult_.resize(n_instances(), density_mult_[0]);
|
||||
|
||||
// Set density multiplier for the corresponding instance
|
||||
density_mult_.at(instance) =
|
||||
density / model::materials[mat_index]->density_gpcc();
|
||||
} else {
|
||||
// Set density multiplier for all instances
|
||||
for (auto& x : density_mult_) {
|
||||
x = density / model::materials[mat_index]->density_gpcc();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto contained_cells = this->get_contained_cells(instance);
|
||||
for (const auto& entry : contained_cells) {
|
||||
auto& cell = model::cells[entry.first];
|
||||
assert(cell->type_ == Fill::MATERIAL);
|
||||
auto& instances = entry.second;
|
||||
for (auto instance : instances) {
|
||||
cell->set_density(density, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cell::export_properties_hdf5(hid_t group) const
|
||||
{
|
||||
// Create a group for this cell.
|
||||
|
|
@ -162,6 +222,15 @@ void Cell::export_properties_hdf5(hid_t group) const
|
|||
temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN);
|
||||
write_dataset(cell_group, "temperature", temps);
|
||||
|
||||
// Write density for one or more cell instances
|
||||
if (type_ == Fill::MATERIAL && material_.size() > 0) {
|
||||
vector<double> density;
|
||||
for (int32_t i = 0; i < density_mult_.size(); ++i)
|
||||
density.push_back(this->density(i));
|
||||
|
||||
write_dataset(cell_group, "density", density);
|
||||
}
|
||||
|
||||
close_group(cell_group);
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +245,7 @@ void Cell::import_properties_hdf5(hid_t group)
|
|||
// Ensure number of temperatures makes sense
|
||||
auto n_temps = temps.size();
|
||||
if (n_temps > 1 && n_temps != n_instances()) {
|
||||
throw std::runtime_error(fmt::format(
|
||||
fatal_error(fmt::format(
|
||||
"Number of temperatures for cell {} doesn't match number of instances",
|
||||
id_));
|
||||
}
|
||||
|
|
@ -188,6 +257,25 @@ void Cell::import_properties_hdf5(hid_t group)
|
|||
this->set_temperature(temps[i], i);
|
||||
}
|
||||
|
||||
// Read densities
|
||||
if (object_exists(cell_group, "density")) {
|
||||
vector<double> density;
|
||||
read_dataset(cell_group, "density", density);
|
||||
|
||||
// Ensure number of densities makes sense
|
||||
auto n_density = density.size();
|
||||
if (n_density > 1 && n_density != n_instances()) {
|
||||
fatal_error(fmt::format("Number of densities for cell {} "
|
||||
"doesn't match number of instances",
|
||||
id_));
|
||||
}
|
||||
|
||||
// Set densities.
|
||||
for (int32_t i = 0; i < n_density; ++i) {
|
||||
this->set_density(density[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
close_group(cell_group);
|
||||
}
|
||||
|
||||
|
|
@ -227,6 +315,8 @@ void Cell::to_hdf5(hid_t cell_group) const
|
|||
temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN);
|
||||
write_dataset(group, "temperature", temps);
|
||||
|
||||
write_dataset(group, "density_mult", density_mult_);
|
||||
|
||||
} else if (type_ == Fill::UNIVERSE) {
|
||||
write_dataset(group, "fill_type", "universe");
|
||||
write_dataset(group, "fill", model::universes[fill_]->id_);
|
||||
|
|
@ -344,6 +434,44 @@ CSGCell::CSGCell(pugi::xml_node cell_node)
|
|||
}
|
||||
}
|
||||
|
||||
// Read the density element which can be distributed similar to temperature.
|
||||
// These get assigned to the density multiplier, requiring a division by
|
||||
// the material density.
|
||||
// Note: calculating the actual density multiplier is deferred until materials
|
||||
// are finalized. density_mult_ contains the true density in the meantime.
|
||||
if (check_for_node(cell_node, "density")) {
|
||||
density_mult_ = get_node_array<double>(cell_node, "density");
|
||||
density_mult_.shrink_to_fit();
|
||||
|
||||
// Make sure this is a material-filled cell.
|
||||
if (material_.size() == 0) {
|
||||
fatal_error(fmt::format(
|
||||
"Cell {} was specified with a density but no material. Density"
|
||||
"specification is only valid for cells filled with a material.",
|
||||
id_));
|
||||
}
|
||||
|
||||
// Make sure this is a non-void material.
|
||||
for (auto mat_id : material_) {
|
||||
if (mat_id == MATERIAL_VOID) {
|
||||
fatal_error(fmt::format(
|
||||
"Cell {} was specified with a density, but contains a void "
|
||||
"material. Density specification is only valid for cells "
|
||||
"filled with a non-void material.",
|
||||
id_));
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all densities are non-negative and greater than zero.
|
||||
for (auto rho : density_mult_) {
|
||||
if (rho <= 0) {
|
||||
fatal_error(fmt::format(
|
||||
"Cell {} was specified with a density less than or equal to zero",
|
||||
id_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read the region specification.
|
||||
std::string region_spec;
|
||||
if (check_for_node(cell_node, "region")) {
|
||||
|
|
@ -1129,6 +1257,24 @@ extern "C" int openmc_cell_set_temperature(
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int openmc_cell_set_density(
|
||||
int32_t index, double density, const int32_t* instance, bool set_contained)
|
||||
{
|
||||
if (index < 0 || index >= model::cells.size()) {
|
||||
strcpy(openmc_err_msg, "Index in cells array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
int32_t instance_index = instance ? *instance : -1;
|
||||
try {
|
||||
model::cells[index]->set_density(density, instance_index, set_contained);
|
||||
} catch (const std::exception& e) {
|
||||
set_errmsg(e.what());
|
||||
return OPENMC_E_UNASSIGNED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int openmc_cell_get_temperature(
|
||||
int32_t index, const int32_t* instance, double* T)
|
||||
{
|
||||
|
|
@ -1147,6 +1293,36 @@ extern "C" int openmc_cell_get_temperature(
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int openmc_cell_get_density(
|
||||
int32_t index, const int32_t* instance, double* density)
|
||||
{
|
||||
if (index < 0 || index >= model::cells.size()) {
|
||||
strcpy(openmc_err_msg, "Index in cells array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
int32_t instance_index = instance ? *instance : -1;
|
||||
try {
|
||||
if (model::cells[index]->type_ != Fill::MATERIAL) {
|
||||
fatal_error(
|
||||
fmt::format("Cell {}, instance {} is not filled with a material.",
|
||||
model::cells[index]->id_, instance_index));
|
||||
}
|
||||
|
||||
int32_t mat_index = model::cells[index]->material(instance_index);
|
||||
if (mat_index == MATERIAL_VOID) {
|
||||
*density = 0.0;
|
||||
} else {
|
||||
*density = model::cells[index]->density_mult(instance_index) *
|
||||
model::materials[mat_index]->density_gpcc();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
set_errmsg(e.what());
|
||||
return OPENMC_E_UNASSIGNED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Get the bounding box of a cell
|
||||
extern "C" int openmc_cell_bounding_box(
|
||||
const int32_t index, double* llc, double* urc)
|
||||
|
|
|
|||
|
|
@ -172,11 +172,13 @@ bool find_cell_inner(
|
|||
p.cell_instance() = cell_instance_at_level(p, p.n_coord() - 1);
|
||||
}
|
||||
|
||||
// Set the material and temperature.
|
||||
// Set the material, temperature and density multiplier.
|
||||
p.material_last() = p.material();
|
||||
p.material() = c.material(p.cell_instance());
|
||||
p.sqrtkT_last() = p.sqrtkT();
|
||||
p.sqrtkT() = c.sqrtkT(p.cell_instance());
|
||||
p.density_mult_last() = p.density_mult();
|
||||
p.density_mult() = c.density_mult(p.cell_instance());
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,24 @@ void assign_temperatures()
|
|||
|
||||
//==============================================================================
|
||||
|
||||
void finalize_cell_densities()
|
||||
{
|
||||
for (auto& c : model::cells) {
|
||||
// Convert to density multipliers.
|
||||
if (!c->density_mult_.empty()) {
|
||||
for (int32_t instance = 0; instance < c->density_mult_.size();
|
||||
++instance) {
|
||||
c->density_mult_[instance] /=
|
||||
model::materials[c->material(instance)]->density_gpcc();
|
||||
}
|
||||
} else {
|
||||
c->density_mult_ = {1.0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void get_temperatures(
|
||||
vector<vector<double>>& nuc_temps, vector<vector<double>>& thermal_temps)
|
||||
{
|
||||
|
|
@ -362,6 +380,17 @@ void prepare_distribcell(const std::vector<int32_t>* user_distribcells)
|
|||
c.id_, c.sqrtkT_.size(), c.n_instances()));
|
||||
}
|
||||
}
|
||||
|
||||
if (c.density_mult_.size() > 1) {
|
||||
if (c.density_mult_.size() != c.n_instances()) {
|
||||
fatal_error(fmt::format("Cell {} was specified with {} density "
|
||||
"multipliers but has {} distributed "
|
||||
"instances. The number of density multipliers "
|
||||
"must equal one or the number "
|
||||
"of instances.",
|
||||
c.id_, c.density_mult_.size(), c.n_instances()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search through universes for material cells and assign each one a
|
||||
|
|
|
|||
|
|
@ -401,6 +401,10 @@ bool read_model_xml()
|
|||
// Finalize cross sections having assigned temperatures
|
||||
finalize_cross_sections();
|
||||
|
||||
// Compute cell density multipliers now that material densities
|
||||
// have been finalized (from geometry_aux.h)
|
||||
finalize_cell_densities();
|
||||
|
||||
if (check_for_node(root, "tallies"))
|
||||
read_tallies_xml(root.child("tallies"));
|
||||
|
||||
|
|
@ -441,6 +445,11 @@ void read_separate_xml_files()
|
|||
|
||||
// Finalize cross sections having assigned temperatures
|
||||
finalize_cross_sections();
|
||||
|
||||
// Compute cell density multipliers now that material densities
|
||||
// have been finalized (from geometry_aux.h)
|
||||
finalize_cell_densities();
|
||||
|
||||
read_tallies_xml();
|
||||
|
||||
// Initialize distribcell_filters
|
||||
|
|
|
|||
|
|
@ -890,7 +890,7 @@ void Material::calculate_neutron_xs(Particle& p) const
|
|||
// ADD TO MACROSCOPIC CROSS SECTION
|
||||
|
||||
// Copy atom density of nuclide in material
|
||||
double atom_density = atom_density_(i);
|
||||
double atom_density = this->atom_density(i, p.density_mult());
|
||||
|
||||
// Add contributions to cross sections
|
||||
p.macro_xs().total += atom_density * micro.total;
|
||||
|
|
@ -925,7 +925,7 @@ void Material::calculate_photon_xs(Particle& p) const
|
|||
// ADD TO MACROSCOPIC CROSS SECTION
|
||||
|
||||
// Copy atom density of nuclide in material
|
||||
double atom_density = atom_density_(i);
|
||||
double atom_density = this->atom_density(i, p.density_mult());
|
||||
|
||||
// Add contributions to material macroscopic cross sections
|
||||
p.macro_xs().total += atom_density * micro.total;
|
||||
|
|
|
|||
|
|
@ -617,10 +617,12 @@ void Mgxs::calculate_xs(Particle& p)
|
|||
}
|
||||
int temperature = p.mg_xs_cache().t;
|
||||
int angle = p.mg_xs_cache().a;
|
||||
p.macro_xs().total = xs[temperature].total(angle, p.g());
|
||||
p.macro_xs().absorption = xs[temperature].absorption(angle, p.g());
|
||||
p.macro_xs().total = xs[temperature].total(angle, p.g()) * p.density_mult();
|
||||
p.macro_xs().absorption =
|
||||
xs[temperature].absorption(angle, p.g()) * p.density_mult();
|
||||
p.macro_xs().nu_fission =
|
||||
fissionable ? xs[temperature].nu_fission(angle, p.g()) : 0.;
|
||||
fissionable ? xs[temperature].nu_fission(angle, p.g()) * p.density_mult()
|
||||
: 0.;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -200,7 +200,8 @@ void Particle::event_calculate_xs()
|
|||
// Calculate microscopic and macroscopic cross sections
|
||||
if (material() != MATERIAL_VOID) {
|
||||
if (settings::run_CE) {
|
||||
if (material() != material_last() || sqrtkT() != sqrtkT_last()) {
|
||||
if (material() != material_last() || sqrtkT() != sqrtkT_last() ||
|
||||
density_mult() != density_mult_last()) {
|
||||
// If the material is the same as the last material and the
|
||||
// temperature hasn't changed, we don't need to lookup cross
|
||||
// sections again.
|
||||
|
|
@ -564,9 +565,10 @@ void Particle::cross_surface(const Surface& surf)
|
|||
int32_t i_cell = next_cell(surface_index(), cell_last(n_coord() - 1),
|
||||
lowest_coord().universe()) -
|
||||
1;
|
||||
// save material and temp
|
||||
// save material, temperature, and density multiplier
|
||||
material_last() = material();
|
||||
sqrtkT_last() = sqrtkT();
|
||||
density_mult_last() = density_mult();
|
||||
// set new cell value
|
||||
lowest_coord().cell() = i_cell;
|
||||
auto& cell = model::cells[i_cell];
|
||||
|
|
@ -577,6 +579,7 @@ void Particle::cross_surface(const Surface& surf)
|
|||
|
||||
material() = cell->material(cell_instance());
|
||||
sqrtkT() = cell->sqrtkT(cell_instance());
|
||||
density_mult() = cell->density_mult(cell_instance());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ int sample_nuclide(Particle& p)
|
|||
for (int i = 0; i < n; ++i) {
|
||||
// Get atom density
|
||||
int i_nuclide = mat->nuclide_[i];
|
||||
double atom_density = mat->atom_density_[i];
|
||||
double atom_density = mat->atom_density(i, p.density_mult());
|
||||
|
||||
// Increment probability to compare to cutoff
|
||||
prob += atom_density * p.neutron_xs(i_nuclide).total;
|
||||
|
|
@ -521,7 +521,7 @@ int sample_element(Particle& p)
|
|||
for (int i = 0; i < mat->element_.size(); ++i) {
|
||||
// Find atom density
|
||||
int i_element = mat->element_[i];
|
||||
double atom_density = mat->atom_density_[i];
|
||||
double atom_density = mat->atom_density(i, p.density_mult());
|
||||
|
||||
// Determine microscopic cross section
|
||||
double sigma = atom_density * p.photon_xs(i_element).total;
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ double score_fission_q(const Particle& p, int score_bin, const Tally& tally,
|
|||
double score {0.0};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
const Nuclide& nuc {*data::nuclides[j_nuclide]};
|
||||
score += get_nuc_fission_q(nuc, p, score_bin) * atom_density *
|
||||
p.neutron_xs(j_nuclide).fission;
|
||||
|
|
@ -696,7 +696,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
score += p.neutron_xs(j_nuclide).fission *
|
||||
data::nuclides[j_nuclide]->nu(
|
||||
E, ReactionProduct::EmissionMode::prompt) *
|
||||
|
|
@ -743,7 +743,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
// Tally each delayed group bin individually
|
||||
for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) {
|
||||
auto d = filt.groups()[d_bin];
|
||||
|
|
@ -763,7 +763,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
score += p.neutron_xs(j_nuclide).fission *
|
||||
data::nuclides[j_nuclide]->nu(
|
||||
E, ReactionProduct::EmissionMode::delayed) *
|
||||
|
|
@ -824,7 +824,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
const auto& nuc {*data::nuclides[j_nuclide]};
|
||||
if (nuc.fissionable_) {
|
||||
const auto& rxn {*nuc.fission_rx_[0]};
|
||||
|
|
@ -849,7 +849,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
const auto& nuc {*data::nuclides[j_nuclide]};
|
||||
if (nuc.fissionable_) {
|
||||
const auto& rxn {*nuc.fission_rx_[0]};
|
||||
|
|
@ -893,7 +893,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
const auto& nuc {*data::nuclides[j_nuclide]};
|
||||
if (nuc.fissionable_) {
|
||||
const auto& rxn {*nuc.fission_rx_[0]};
|
||||
|
|
@ -924,7 +924,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
if (p.neutron_xs(j_nuclide).elastic == CACHE_INVALID)
|
||||
data::nuclides[j_nuclide]->calculate_elastic_xs(p);
|
||||
score += p.neutron_xs(j_nuclide).elastic * atom_density * flux;
|
||||
|
|
@ -1025,7 +1025,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
score += p.neutron_xs(j_nuclide).reaction[m] * atom_density * flux;
|
||||
}
|
||||
}
|
||||
|
|
@ -1079,7 +1079,7 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index,
|
|||
const Material& material {*model::materials[p.material()]};
|
||||
for (auto i = 0; i < material.nuclide_.size(); ++i) {
|
||||
auto j_nuclide = material.nuclide_[i];
|
||||
auto atom_density = material.atom_density_(i);
|
||||
auto atom_density = material.atom_density(i, p.density_mult());
|
||||
score +=
|
||||
get_nuclide_xs(p, j_nuclide, score_bin) * atom_density * flux;
|
||||
}
|
||||
|
|
@ -2383,7 +2383,8 @@ void score_analog_tally_mg(Particle& p)
|
|||
model::materials[p.material()]->mat_nuclide_index_[i_nuclide];
|
||||
if (j == C_NONE)
|
||||
continue;
|
||||
atom_density = model::materials[p.material()]->atom_density_(j);
|
||||
atom_density =
|
||||
model::materials[p.material()]->atom_density(j, p.density_mult());
|
||||
}
|
||||
|
||||
score_general_mg(p, i_tally, i * tally.scores_.size(), filter_index,
|
||||
|
|
@ -2449,8 +2450,9 @@ void score_tracklength_tally_general(
|
|||
atom_density = 1.0;
|
||||
}
|
||||
} else {
|
||||
atom_density =
|
||||
tally.multiply_density() ? mat->atom_density_(j) : 1.0;
|
||||
atom_density = tally.multiply_density()
|
||||
? mat->atom_density(j, p.density_mult())
|
||||
: 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2579,8 +2581,9 @@ void score_collision_tally(Particle& p)
|
|||
atom_density = 1.0;
|
||||
}
|
||||
} else {
|
||||
atom_density =
|
||||
tally.multiply_density() ? mat->atom_density_(j) : 1.0;
|
||||
atom_density = tally.multiply_density()
|
||||
? mat->atom_density(j, p.density_mult())
|
||||
: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,14 +15,16 @@
|
|||
|
||||
using namespace openmc;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
#ifdef OPENMC_MPI
|
||||
MPI_Comm world {MPI_COMM_WORLD};
|
||||
int err = openmc_init(argc, argv, &world);
|
||||
#else
|
||||
int err = openmc_init(argc, argv, nullptr);
|
||||
#endif
|
||||
if (err) fatal_error(openmc_err_msg);
|
||||
if (err)
|
||||
fatal_error(openmc_err_msg);
|
||||
|
||||
// create a new cell filter
|
||||
auto cell_filter = Filter::create<CellFilter>();
|
||||
|
|
@ -30,7 +32,7 @@ int main(int argc, char** argv) {
|
|||
// add all cells to the cell filter
|
||||
std::vector<int32_t> cell_indices;
|
||||
for (auto& entry : openmc::model::cell_map) {
|
||||
cell_indices.push_back(entry.second);
|
||||
cell_indices.push_back(entry.second);
|
||||
}
|
||||
// enable distribcells offsets for all cells
|
||||
prepare_distribcell(&cell_indices);
|
||||
|
|
@ -39,7 +41,6 @@ int main(int argc, char** argv) {
|
|||
std::sort(cell_indices.begin(), cell_indices.end());
|
||||
cell_filter->set_cells(cell_indices);
|
||||
|
||||
|
||||
// create a new tally
|
||||
auto tally = Tally::create();
|
||||
std::vector<Filter*> filters = {cell_filter};
|
||||
|
|
@ -60,14 +61,19 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// set a higher temperature for only one of the lattice cells (ID is 4 in the model)
|
||||
// set a higher temperature for only one of the lattice cells (ID is 4 in the
|
||||
// model)
|
||||
model::cells[model::cell_map[4]]->set_temperature(400.0, 3, true);
|
||||
|
||||
// set the density of another lattice cell to 2
|
||||
model::cells[model::cell_map[4]]->set_density(2.0, 2, true);
|
||||
|
||||
// the summary file will be used to check that
|
||||
// temperatures were set correctly so clear
|
||||
// error output can be provided
|
||||
#ifdef OPENMC_MPI
|
||||
if (openmc::mpi::master) openmc::write_summary();
|
||||
if (openmc::mpi::master)
|
||||
openmc::write_summary();
|
||||
#else
|
||||
openmc::write_summary();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
k-combined:
|
||||
1.933305E+00 1.300360E-02
|
||||
1.953962E+00 1.828426E-02
|
||||
tally 1:
|
||||
9.552846E+01
|
||||
1.019358E+03
|
||||
2.887973E+01
|
||||
9.308509E+01
|
||||
9.732441E+01
|
||||
1.059022E+03
|
||||
2.217326E+02
|
||||
5.486892E+03
|
||||
2.217326E+02
|
||||
5.486892E+03
|
||||
9.607953E+01
|
||||
1.031898E+03
|
||||
2.853683E+01
|
||||
9.085469E+01
|
||||
9.745011E+01
|
||||
1.058928E+03
|
||||
2.220665E+02
|
||||
5.496813E+03
|
||||
2.220665E+02
|
||||
5.496813E+03
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
// Finalize cell densities
|
||||
openmc::finalize_cell_densities();
|
||||
|
||||
// Run OpenMC
|
||||
openmc_err = openmc_run();
|
||||
if (openmc_err)
|
||||
|
|
|
|||
0
tests/regression_tests/lattice_distribrho/__init__.py
Normal file
0
tests/regression_tests/lattice_distribrho/__init__.py
Normal file
40
tests/regression_tests/lattice_distribrho/inputs_true.dat
Normal file
40
tests/regression_tests/lattice_distribrho/inputs_true.dat
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<model>
|
||||
<materials>
|
||||
<material id="1" name="UO2" depletable="true">
|
||||
<density value="10.0" units="g/cm3"/>
|
||||
<nuclide name="U235" ao="1.0"/>
|
||||
<nuclide name="O16" ao="2.0"/>
|
||||
</material>
|
||||
<material id="2" name="light water">
|
||||
<density value="1.0" units="g/cm3"/>
|
||||
<nuclide name="H1" ao="2.0"/>
|
||||
<nuclide name="O16" ao="1.0"/>
|
||||
<sab name="c_H_in_H2O"/>
|
||||
</material>
|
||||
</materials>
|
||||
<geometry>
|
||||
<cell id="1" material="1" region="-1" density="10.0 20.0 10.0 20.0" universe="1"/>
|
||||
<cell id="2" material="2" region="1" universe="1"/>
|
||||
<cell id="3" fill="2" region="2 -3 4 -5" universe="3"/>
|
||||
<lattice id="2">
|
||||
<pitch>1.0 1.0</pitch>
|
||||
<dimension>2 2</dimension>
|
||||
<lower_left>-1.0 -1.0</lower_left>
|
||||
<universes>
|
||||
1 1
|
||||
1 1 </universes>
|
||||
</lattice>
|
||||
<surface id="1" type="z-cylinder" coeffs="0.0 0.0 0.4"/>
|
||||
<surface id="2" name="minimum x" type="x-plane" boundary="reflective" coeffs="-1.0"/>
|
||||
<surface id="3" name="maximum x" type="x-plane" boundary="reflective" coeffs="1.0"/>
|
||||
<surface id="4" name="minimum y" type="y-plane" boundary="reflective" coeffs="-1.0"/>
|
||||
<surface id="5" name="maximum y" type="y-plane" boundary="reflective" coeffs="1.0"/>
|
||||
</geometry>
|
||||
<settings>
|
||||
<run_mode>eigenvalue</run_mode>
|
||||
<particles>1000</particles>
|
||||
<batches>10</batches>
|
||||
<inactive>5</inactive>
|
||||
</settings>
|
||||
</model>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
1.904471E+00 5.255549E-03
|
||||
51
tests/regression_tests/lattice_distribrho/test.py
Normal file
51
tests/regression_tests/lattice_distribrho/test.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.testing_harness import PyAPITestHarness
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def model():
|
||||
model = openmc.Model()
|
||||
|
||||
uo2 = openmc.Material(name='UO2')
|
||||
uo2.set_density('g/cm3', 10.0)
|
||||
uo2.add_nuclide('U235', 1.0)
|
||||
uo2.add_nuclide('O16', 2.0)
|
||||
water = openmc.Material(name='light water')
|
||||
water.add_nuclide('H1', 2.0)
|
||||
water.add_nuclide('O16', 1.0)
|
||||
water.set_density('g/cm3', 1.0)
|
||||
water.add_s_alpha_beta('c_H_in_H2O')
|
||||
model.materials.extend([uo2, water])
|
||||
|
||||
cyl = openmc.ZCylinder(r=0.4)
|
||||
pin = openmc.model.pin([cyl], [uo2, water])
|
||||
d = 1.0
|
||||
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.lower_left = (-d, -d)
|
||||
lattice.pitch = (d, d)
|
||||
lattice.universes = [[pin, pin],
|
||||
[pin, pin]]
|
||||
box = openmc.model.RectangularPrism(
|
||||
2.0 * d, 2.0 * d,
|
||||
origin=(0.0, 0.0),
|
||||
boundary_type='reflective'
|
||||
)
|
||||
|
||||
pin.cells[1].density = [10.0, 20.0, 10.0, 20.0]
|
||||
|
||||
model.geometry = openmc.Geometry([openmc.Cell(fill=lattice, region=-box)])
|
||||
model.geometry.merge_surfaces = True
|
||||
|
||||
model.settings.batches = 10
|
||||
model.settings.inactive = 5
|
||||
model.settings.particles = 1000
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def test_lattice_checkerboard(model):
|
||||
harness = PyAPITestHarness('statepoint.10.h5', model)
|
||||
harness.main()
|
||||
|
|
@ -38,5 +38,6 @@ Cell
|
|||
Region = -1
|
||||
Rotation = None
|
||||
Temperature = [500. 700. 0. 800.]
|
||||
Density = None
|
||||
Translation = None
|
||||
Volume = None
|
||||
|
|
|
|||
|
|
@ -126,6 +126,29 @@ def test_temperature(cell_with_lattice):
|
|||
c.temperature = (300., 600., 900.)
|
||||
|
||||
|
||||
def test_densities(cell_with_lattice):
|
||||
# Make sure density propagates through universes
|
||||
m = openmc.Material()
|
||||
s = openmc.XPlane()
|
||||
c1 = openmc.Cell(fill=m, region=+s)
|
||||
c2 = openmc.Cell(fill=m, region=-s)
|
||||
u1 = openmc.Universe(cells=[c1, c2])
|
||||
c = openmc.Cell(fill=u1)
|
||||
|
||||
c.density = 1.
|
||||
assert c1.density == 1.
|
||||
assert c2.density == 1.
|
||||
with pytest.raises(ValueError):
|
||||
c.density = -1.
|
||||
c.density = None
|
||||
assert c1.density == None
|
||||
assert c2.density == None
|
||||
|
||||
# distributed density
|
||||
cells, _, _, _ = cell_with_lattice
|
||||
c = cells[0]
|
||||
c.density = (1., 2., 3.)
|
||||
|
||||
def test_rotation():
|
||||
u = openmc.Universe()
|
||||
c = openmc.Cell(fill=u)
|
||||
|
|
|
|||
|
|
@ -159,6 +159,29 @@ def test_properties_temperature(lib_init):
|
|||
assert cell.get_temperature() == pytest.approx(200.0)
|
||||
|
||||
|
||||
def test_cell_density(lib_init):
|
||||
cell = openmc.lib.cells[1]
|
||||
cell.set_density(1.5, 0)
|
||||
assert cell.get_density(0) == pytest.approx(1.5)
|
||||
cell.set_density(2.0)
|
||||
assert cell.get_density() == pytest.approx(2.0)
|
||||
|
||||
|
||||
def test_properties_cell_density(lib_init):
|
||||
# Cell density should be 2.0 from above test
|
||||
cell = openmc.lib.cells[1]
|
||||
assert cell.get_density() == pytest.approx(2.0)
|
||||
|
||||
# Export properties and change density
|
||||
openmc.lib.export_properties('properties.h5')
|
||||
cell.set_density(3.0)
|
||||
assert cell.get_density() == pytest.approx(3.0)
|
||||
|
||||
# Import properties and check that density is restored
|
||||
openmc.lib.import_properties('properties.h5')
|
||||
assert cell.get_density() == pytest.approx(2.0)
|
||||
|
||||
|
||||
def test_new_cell(lib_init):
|
||||
with pytest.raises(exc.AllocationError):
|
||||
openmc.lib.Cell(1)
|
||||
|
|
|
|||
|
|
@ -251,10 +251,11 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
model = openmc.examples.pwr_pin_cell()
|
||||
model.init_lib(output=False, intracomm=mpi_intracomm)
|
||||
|
||||
# Change fuel temperature and density and export properties
|
||||
# Change cell fuel temperature, density, material density and export properties
|
||||
cell = openmc.lib.cells[1]
|
||||
cell.set_temperature(600.0)
|
||||
cell.fill.set_density(5.0, 'g/cm3')
|
||||
cell.set_density(10.0)
|
||||
openmc.lib.export_properties(output=False)
|
||||
|
||||
# Import properties to existing model
|
||||
|
|
@ -264,9 +265,11 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
# First python
|
||||
cell = model.geometry.get_all_cells()[1]
|
||||
assert cell.temperature == [600.0]
|
||||
assert cell.density == [pytest.approx(10.0, 1e-5)]
|
||||
assert cell.fill.get_mass_density() == pytest.approx(5.0)
|
||||
# Now C
|
||||
assert openmc.lib.cells[1].get_temperature() == 600.
|
||||
assert openmc.lib.cells[1].get_density() == pytest.approx(10.0, 1e-5)
|
||||
assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0)
|
||||
|
||||
# Clear the C API
|
||||
|
|
@ -283,6 +286,7 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
)
|
||||
cell = model_with_properties.geometry.get_all_cells()[1]
|
||||
assert cell.temperature == [600.0]
|
||||
assert cell.density == [pytest.approx(10.0, 1e-5)]
|
||||
assert cell.fill.get_mass_density() == pytest.approx(5.0)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue