mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Finish improving Material interface
This commit is contained in:
parent
bbf529bef0
commit
0c32470551
6 changed files with 125 additions and 56 deletions
|
|
@ -48,7 +48,7 @@ extern "C" {
|
|||
int openmc_legendre_filter_set_order(int32_t index, int order);
|
||||
int openmc_load_nuclide(const char* name);
|
||||
int openmc_material_add_nuclide(int32_t index, const char name[], double density);
|
||||
int openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n);
|
||||
int openmc_material_get_densities(int32_t index, const int** nuclides, const double** densities, int* n);
|
||||
int openmc_material_get_id(int32_t index, int32_t* id);
|
||||
int openmc_material_get_fissionable(int32_t index, bool* fissionable);
|
||||
int openmc_material_get_density(int32_t index, double* density);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,34 @@ public:
|
|||
//! \param[in] units Units of density
|
||||
void set_density(double density, gsl::cstring_span units);
|
||||
|
||||
//! Get nuclides in material
|
||||
//! \return Indices into the global nuclides vector
|
||||
gsl::span<const int> nuclides() const { return {nuclide_.data(), nuclide_.size()}; }
|
||||
|
||||
//! Get densities of each nuclide in material
|
||||
//! \return Densities in [atom/b-cm]
|
||||
gsl::span<const double> densities() const { return {atom_density_.data(), atom_density_.size()}; }
|
||||
|
||||
//! Set atom densities for the material
|
||||
//
|
||||
//! \param[in] name Name of each nuclide
|
||||
//! \param[in] density Density of each nuclide in [atom/b-cm]
|
||||
void set_densities(const std::vector<std::string>& name,
|
||||
const std::vector<double>& density);
|
||||
|
||||
//! Get ID of material
|
||||
//! \return ID of material
|
||||
int32_t id() const { return id_; }
|
||||
|
||||
//! Assign a unique ID to the material
|
||||
//! \param[in] Unique ID to assign. A value of -1 indicates that an ID
|
||||
//! should be automatically assigned.
|
||||
void set_id(int32_t id);
|
||||
|
||||
//! Get whether material is fissionable
|
||||
//! \return Whether material is fissionable
|
||||
bool fissionable() const { return fissionable_; }
|
||||
|
||||
//! Get volume of material
|
||||
//! \return Volume in [cm^3]
|
||||
double volume() const;
|
||||
|
|
@ -128,6 +156,9 @@ private:
|
|||
|
||||
void calculate_neutron_xs(Particle& p) const;
|
||||
void calculate_photon_xs(Particle& p) const;
|
||||
|
||||
// Data members
|
||||
gsl::index index_;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ public:
|
|||
get_all_bins(const Particle* p, int estimator, FilterMatch& match) const = 0;
|
||||
|
||||
//! Assign a unique ID to the filter
|
||||
//
|
||||
//! \param[in] Unique ID to assign
|
||||
//! \param[in] Unique ID to assign. A value of -1 indicates that an ID should
|
||||
//! be automatically assigned
|
||||
void set_id(int32_t id);
|
||||
|
||||
gsl::index index() const { return index_; }
|
||||
|
|
|
|||
|
|
@ -36,4 +36,6 @@ def _error_handler(err, func, args):
|
|||
elif err == errcode('OPENMC_E_WARNING'):
|
||||
warn(msg)
|
||||
elif err < 0:
|
||||
raise exc.OpenMCError("Unknown error encountered (code {}).".format(err))
|
||||
if not msg:
|
||||
msg = "Unknown error encountered (code {}).".format(err)
|
||||
raise exc.OpenMCError(msg)
|
||||
|
|
|
|||
138
src/material.cpp
138
src/material.cpp
|
|
@ -47,9 +47,10 @@ std::unordered_map<int32_t, int32_t> material_map;
|
|||
//==============================================================================
|
||||
|
||||
Material::Material(pugi::xml_node node)
|
||||
: index_{model::materials.size()}
|
||||
{
|
||||
if (check_for_node(node, "id")) {
|
||||
id_ = std::stoi(get_node_value(node, "id"));
|
||||
this->set_id(std::stoi(get_node_value(node, "id")));
|
||||
} else {
|
||||
fatal_error("Must specify id of material in materials XML file.");
|
||||
}
|
||||
|
|
@ -849,8 +850,39 @@ void Material::calculate_photon_xs(Particle& p) const
|
|||
}
|
||||
}
|
||||
|
||||
void Material::set_id(int32_t id)
|
||||
{
|
||||
Expects(id >= -1);
|
||||
|
||||
// Clear entry in material map if an ID was already assigned before
|
||||
if (id_ != -1) {
|
||||
model::material_map.erase(id_);
|
||||
id_ = -1;
|
||||
}
|
||||
|
||||
// Make sure no other material has same ID
|
||||
if (model::material_map.find(id) != model::material_map.end()) {
|
||||
throw std::runtime_error{"Two materials have the same ID: " + std::to_string(id)};
|
||||
}
|
||||
|
||||
// If no ID specified, auto-assign next ID in sequence
|
||||
if (id == -1) {
|
||||
id = 0;
|
||||
for (const auto& f : model::materials) {
|
||||
id = std::max(id, f->id_);
|
||||
}
|
||||
++id;
|
||||
}
|
||||
|
||||
// Update ID and entry in material map
|
||||
id_ = id;
|
||||
model::material_map[id] = index_;
|
||||
}
|
||||
|
||||
void Material::set_density(double density, gsl::cstring_span units)
|
||||
{
|
||||
Expects(density >= 0.0);
|
||||
|
||||
if (nuclide_.empty()) {
|
||||
throw std::runtime_error{"No nuclides exist in material yet."};
|
||||
}
|
||||
|
|
@ -888,6 +920,39 @@ void Material::set_density(double density, gsl::cstring_span units)
|
|||
}
|
||||
}
|
||||
|
||||
void Material::set_densities(const std::vector<std::string>& name,
|
||||
const std::vector<double>& density)
|
||||
{
|
||||
auto n = name.size();
|
||||
Expects(n > 0);
|
||||
Expects(n == density.size());
|
||||
|
||||
if (n != nuclide_.size()) {
|
||||
nuclide_.resize(n);
|
||||
atom_density_ = xt::zeros<double>({n});
|
||||
}
|
||||
|
||||
double sum_density = 0.0;
|
||||
for (gsl::index i = 0; i < n; ++i) {
|
||||
const auto& nuc {name[i]};
|
||||
if (data::nuclide_map.find(nuc) == data::nuclide_map.end()) {
|
||||
int err = openmc_load_nuclide(nuc.c_str());
|
||||
if (err < 0) throw std::runtime_error{openmc_err_msg};
|
||||
}
|
||||
|
||||
nuclide_[i] = data::nuclide_map.at(nuc);
|
||||
Expects(density[i] > 0.0);
|
||||
atom_density_(i) = density[i];
|
||||
sum_density += density[i];
|
||||
}
|
||||
|
||||
// Set total density to the sum of the vector
|
||||
this->set_density(sum_density, "atom/b-cm");
|
||||
|
||||
// Assign S(a,b) tables
|
||||
this->init_thermal();
|
||||
}
|
||||
|
||||
double Material::volume() const
|
||||
{
|
||||
if (volume_ < 0.0) {
|
||||
|
|
@ -969,9 +1034,7 @@ void Material::add_nuclide(const std::string& name, double density)
|
|||
|
||||
// If nuclide wasn't found, extend nuclide/density arrays
|
||||
int err = openmc_load_nuclide(name.c_str());
|
||||
if (err < 0) {
|
||||
throw std::runtime_error{openmc_err_msg};
|
||||
}
|
||||
if (err < 0) throw std::runtime_error{openmc_err_msg};
|
||||
|
||||
// Append new nuclide/density
|
||||
int i_nuc = data::nuclide_map[name];
|
||||
|
|
@ -1143,19 +1206,6 @@ void read_materials_xml()
|
|||
model::materials.push_back(std::make_unique<Material>(material_node));
|
||||
}
|
||||
model::materials.shrink_to_fit();
|
||||
|
||||
// Populate the material map.
|
||||
for (int i = 0; i < model::materials.size(); i++) {
|
||||
int32_t mid = model::materials[i]->id_;
|
||||
auto search = model::material_map.find(mid);
|
||||
if (search == model::material_map.end()) {
|
||||
model::material_map[mid] = i;
|
||||
} else {
|
||||
std::stringstream err_msg;
|
||||
err_msg << "Two or more materials use the same unique ID: " << mid;
|
||||
fatal_error(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory_material()
|
||||
|
|
@ -1199,14 +1249,14 @@ openmc_material_add_nuclide(int32_t index, const char* name, double density)
|
|||
}
|
||||
|
||||
extern "C" int
|
||||
openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n)
|
||||
openmc_material_get_densities(int32_t index, const int** nuclides, const double** densities, int* n)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
auto& mat = model::materials[index];
|
||||
if (!mat->nuclide_.empty()) {
|
||||
*nuclides = mat->nuclide_.data();
|
||||
*densities = mat->atom_density_.data();
|
||||
*n = mat->nuclide_.size();
|
||||
if (!mat->nuclides().empty()) {
|
||||
*nuclides = mat->nuclides().data();
|
||||
*densities = mat->densities().data();
|
||||
*n = mat->nuclides().size();
|
||||
return 0;
|
||||
} else {
|
||||
set_errmsg("Material atom density array has not been allocated.");
|
||||
|
|
@ -1235,7 +1285,7 @@ extern "C" int
|
|||
openmc_material_get_fissionable(int32_t index, bool* fissionable)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
*fissionable = model::materials[index]->fissionable_;
|
||||
*fissionable = model::materials[index]->fissionable();
|
||||
return 0;
|
||||
} else {
|
||||
set_errmsg("Index in materials array is out of bounds.");
|
||||
|
|
@ -1247,7 +1297,7 @@ extern "C" int
|
|||
openmc_material_get_id(int32_t index, int32_t* id)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
*id = model::materials[index]->id_;
|
||||
*id = model::materials[index]->id();
|
||||
return 0;
|
||||
} else {
|
||||
set_errmsg("Index in materials array is out of bounds.");
|
||||
|
|
@ -1293,48 +1343,34 @@ extern "C" int
|
|||
openmc_material_set_densities(int32_t index, int n, const char** name, const double* density)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
auto& mat {model::materials[index]};
|
||||
if (n != mat->nuclide_.size()) {
|
||||
mat->nuclide_.resize(n);
|
||||
mat->atom_density_ = xt::zeros<double>({n});
|
||||
try {
|
||||
model::materials[index]->set_densities({name, name + n}, {density, density + n});
|
||||
} catch (const std::exception& e) {
|
||||
set_errmsg(e.what());
|
||||
return OPENMC_E_UNASSIGNED;
|
||||
}
|
||||
|
||||
double sum_density = 0.0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
std::string nuc {name[i]};
|
||||
if (data::nuclide_map.find(nuc) == data::nuclide_map.end()) {
|
||||
int err = openmc_load_nuclide(nuc.c_str());
|
||||
if (err < 0) return err;
|
||||
}
|
||||
|
||||
mat->nuclide_[i] = data::nuclide_map[nuc];
|
||||
mat->atom_density_(i) = density[i];
|
||||
sum_density += density[i];
|
||||
}
|
||||
|
||||
// Set total density to the sum of the vector
|
||||
mat->set_density(sum_density, "atom/b-cm");
|
||||
|
||||
// Assign S(a,b) tables
|
||||
mat->init_thermal();
|
||||
return 0;
|
||||
} else {
|
||||
set_errmsg("Index in materials array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
openmc_material_set_id(int32_t index, int32_t id)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
model::materials[index]->id_ = id;
|
||||
model::material_map[id] = index;
|
||||
return 0;
|
||||
try {
|
||||
model::materials.at(index)->set_id(id);
|
||||
} catch (const std::exception& e) {
|
||||
set_errmsg(e.what());
|
||||
return OPENMC_E_UNASSIGNED;
|
||||
}
|
||||
} else {
|
||||
set_errmsg("Index in materials array is out of bounds.");
|
||||
return OPENMC_E_OUT_OF_BOUNDS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ def test_material(capi_init):
|
|||
m.volume = 10.0
|
||||
assert m.volume == 10.0
|
||||
|
||||
with pytest.raises(exc.InvalidArgumentError):
|
||||
with pytest.raises(exc.OpenMCError):
|
||||
m.set_density(1.0, 'goblins')
|
||||
|
||||
rho = 2.25e-2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue