Skip to content

Commit 0b7075b

Browse files
pshriwiseclaude
andcommitted
Refactor cell XML parsing into shared free functions
Extract parse_cell_material_xml() and parse_cell_temperature_xml() from CSGCell::CSGCell() into free functions in cell.h/cell.cpp so that DAGUniverse can reuse the same logic when parsing <cell> override sub-elements. Both handle void/material-id conversion, empty-array validation, and non-negative temperature validation. Each call site retains its own higher-level policy (fill/material exclusivity in CSGCell, forbidden-attribute guards and duplicate detection in DAGUniverse). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8606420 commit 0b7075b

3 files changed

Lines changed: 62 additions & 57 deletions

File tree

include/openmc/cell.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,23 @@ class Region {
145145
bool simple_; //!< Does the region contain only intersections?
146146
};
147147

148+
//==============================================================================
149+
// XML parsing helpers for <cell> nodes
150+
//==============================================================================
151+
152+
//! Parse material IDs from a <cell> XML node.
153+
//! \param node XML node containing a "material" attribute or child element
154+
//! \param cell_id Cell ID used in error messages
155+
//! \return Vector of material IDs (MATERIAL_VOID for "void")
156+
vector<int32_t> parse_cell_material_xml(pugi::xml_node node, int32_t cell_id);
157+
158+
//! Parse temperatures (in Kelvin) from a <cell> XML node.
159+
//! Validates that all values are non-negative and the list is non-empty.
160+
//! \param node XML node containing a "temperature" attribute or child element
161+
//! \param cell_id Cell ID used in error messages
162+
//! \return Vector of temperatures in Kelvin
163+
vector<double> parse_cell_temperature_xml(pugi::xml_node node, int32_t cell_id);
164+
148165
//==============================================================================
149166

150167
class Cell {

src/cell.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,45 @@ void Cell::to_hdf5(hid_t cell_group) const
340340
close_group(group);
341341
}
342342

343+
//==============================================================================
344+
// XML parsing helpers for <cell> nodes
345+
//==============================================================================
346+
347+
vector<int32_t> parse_cell_material_xml(pugi::xml_node node, int32_t cell_id)
348+
{
349+
vector<std::string> mats {get_node_array<std::string>(node, "material", true)};
350+
if (mats.empty()) {
351+
fatal_error(fmt::format(
352+
"An empty material element was specified for cell {}", cell_id));
353+
}
354+
vector<int32_t> material;
355+
material.reserve(mats.size());
356+
for (const auto& mat : mats) {
357+
if (mat == "void") {
358+
material.push_back(MATERIAL_VOID);
359+
} else {
360+
material.push_back(std::stoi(mat));
361+
}
362+
}
363+
return material;
364+
}
365+
366+
vector<double> parse_cell_temperature_xml(pugi::xml_node node, int32_t cell_id)
367+
{
368+
auto temperatures = get_node_array<double>(node, "temperature");
369+
if (temperatures.empty()) {
370+
fatal_error(fmt::format(
371+
"An empty temperature element was specified for cell {}", cell_id));
372+
}
373+
for (auto T : temperatures) {
374+
if (T < 0) {
375+
fatal_error(fmt::format(
376+
"Cell {} was specified with a negative temperature", cell_id));
377+
}
378+
}
379+
return temperatures;
380+
}
381+
343382
//==============================================================================
344383
// CSGCell implementation
345384
//==============================================================================
@@ -390,26 +429,12 @@ CSGCell::CSGCell(pugi::xml_node cell_node)
390429
// universe), more than one material (distribmats), and some materials may
391430
// be "void".
392431
if (material_present) {
393-
vector<std::string> mats {
394-
get_node_array<std::string>(cell_node, "material", true)};
395-
if (mats.size() > 0) {
396-
material_.reserve(mats.size());
397-
for (std::string mat : mats) {
398-
if (mat.compare("void") == 0) {
399-
material_.push_back(MATERIAL_VOID);
400-
} else {
401-
material_.push_back(std::stoi(mat));
402-
}
403-
}
404-
} else {
405-
fatal_error(fmt::format(
406-
"An empty material element was specified for cell {}", id_));
407-
}
432+
material_ = parse_cell_material_xml(cell_node, id_);
408433
}
409434

410435
// Read the temperature element which may be distributed like materials.
411436
if (check_for_node(cell_node, "temperature")) {
412-
sqrtkT_ = get_node_array<double>(cell_node, "temperature");
437+
sqrtkT_ = parse_cell_temperature_xml(cell_node, id_);
413438
sqrtkT_.shrink_to_fit();
414439

415440
// Make sure this is a material-filled cell.
@@ -420,14 +445,6 @@ CSGCell::CSGCell(pugi::xml_node cell_node)
420445
id_));
421446
}
422447

423-
// Make sure all temperatures are non-negative.
424-
for (auto T : sqrtkT_) {
425-
if (T < 0) {
426-
fatal_error(fmt::format(
427-
"Cell {} was specified with a negative temperature", id_));
428-
}
429-
}
430-
431448
// Convert to sqrt(k*T).
432449
for (auto& T : sqrtkT_) {
433450
T = std::sqrt(K_BOLTZMANN * T);

src/dagmc.cpp

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -115,45 +115,16 @@ DAGUniverse::DAGUniverse(pugi::xml_node node)
115115
"DAGMC cell {} override must specify material.", cell_id));
116116
}
117117

118-
vector<std::string> mats =
119-
get_node_array<std::string>(cell_node, "material", true);
120-
if (mats.empty()) {
121-
fatal_error(fmt::format(
122-
"DAGMC cell {} override has an empty material specification.",
123-
cell_id));
124-
}
125-
126-
vector<int32_t> override_mats;
127-
override_mats.reserve(mats.size());
128-
for (const auto& mat : mats) {
129-
if (mat == "void") {
130-
override_mats.push_back(MATERIAL_VOID);
131-
} else {
132-
override_mats.push_back(std::stoi(mat));
133-
}
134-
}
135-
136-
auto inserted = material_overrides.emplace(cell_id, override_mats);
118+
auto inserted = material_overrides.emplace(
119+
cell_id, parse_cell_material_xml(cell_node, cell_id));
137120
if (!inserted.second) {
138121
fatal_error(fmt::format(
139122
"Duplicate DAGMC cell override specified for cell {}", cell_id));
140123
}
141124

142125
if (check_for_node(cell_node, "temperature")) {
143-
auto temperatures = get_node_array<double>(cell_node, "temperature");
144-
if (temperatures.empty()) {
145-
fatal_error(fmt::format(
146-
"DAGMC cell {} override has an empty temperature specification.",
147-
cell_id));
148-
}
149-
for (auto T : temperatures) {
150-
if (T < 0.0) {
151-
fatal_error(fmt::format(
152-
"DAGMC cell {} was specified with a negative temperature",
153-
cell_id));
154-
}
155-
}
156-
temperature_overrides.emplace(cell_id, temperatures);
126+
temperature_overrides.emplace(
127+
cell_id, parse_cell_temperature_xml(cell_node, cell_id));
157128
}
158129
}
159130
} else if (check_for_node(node, "material_overrides")) {

0 commit comments

Comments
 (0)