Skip to content

Commit d6d41c9

Browse files
cn-skywalkerclaude
andcommitted
perf: use compact array format for TRISO particle HDF5 I/O
Replace per-particle HDF5 group writing with a compact array format that stores only (x, y, z, radius) + IDs per TRISO particle. This eliminates the massive HDF5 group metadata overhead and supports multiple TRISO groups with different layer structures or background materials. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a657bcb commit d6d41c9

2 files changed

Lines changed: 186 additions & 4 deletions

File tree

openmc/summary.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ def _read_geometry(self):
112112
if "dagmc" not in self._f['geometry'].attrs.keys():
113113
self._read_surfaces()
114114
cell_fills = self._read_cells()
115+
# Read compact TRISO particle data if present
116+
if 'geometry/triso_particles' in self._f:
117+
triso_fills = self._read_triso_particles()
118+
cell_fills.update(triso_fills)
115119
self._read_universes()
116120
self._read_lattices()
117121
self._finalize_geometry(cell_fills)
@@ -194,6 +198,69 @@ def _read_cells(self):
194198

195199
return cell_fills
196200

201+
def _read_triso_particles(self):
202+
"""Read compact TRISO particle data from HDF5 and reconstruct objects.
203+
204+
Returns
205+
-------
206+
dict
207+
Cell fill information for all TRISO and background cells
208+
"""
209+
triso_grp = self._f['geometry/triso_particles']
210+
n_triso = int(triso_grp.attrs['n_triso'])
211+
if n_triso == 0:
212+
return {}
213+
214+
# Batch-read all arrays
215+
positions = triso_grp['positions'][()] # (N, 4) array
216+
surface_ids = triso_grp['surface_ids'][()] # (N,) array
217+
cell_ids = triso_grp['cell_ids'][()] # (N,) array
218+
fill_universes = triso_grp['fill_universes'][()] # (N,) array
219+
group_offsets = triso_grp['group_offsets'][()] # (n_groups+1,) array
220+
221+
cell_fills = {}
222+
223+
# Create all TRISO Sphere surfaces in batch
224+
for i in range(n_triso):
225+
x0, y0, z0, r = positions[i]
226+
sid = int(surface_ids[i])
227+
surf = openmc.Sphere(x0=float(x0), y0=float(y0),
228+
z0=float(z0), r=float(r),
229+
surface_id=sid)
230+
self._fast_surfaces[sid] = surf
231+
232+
# Create all TRISO Cell objects in batch
233+
for i in range(n_triso):
234+
cid = int(cell_ids[i])
235+
sid = int(surface_ids[i])
236+
fill_univ_id = int(fill_universes[i])
237+
x0, y0, z0, _ = positions[i]
238+
239+
cell = openmc.Cell(cell_id=cid)
240+
cell.region = -self._fast_surfaces[sid]
241+
cell.translation = np.array([x0, y0, z0], dtype=np.float64)
242+
cell_fills[cid] = ('universe', fill_univ_id)
243+
self._fast_cells[cid] = cell
244+
245+
# Create background cells for each group
246+
n_groups = len(group_offsets) - 1
247+
groups_grp = triso_grp['groups']
248+
for g in range(n_groups):
249+
grp = groups_grp[str(g)]
250+
bg_cell_id = int(grp['background_cell_id'][()])
251+
bg_material_id = int(grp['background_material_id'][()])
252+
bg_universe_id = int(grp['background_universe_id'][()])
253+
254+
bg_cell = openmc.Cell(cell_id=bg_cell_id)
255+
bg_cell.virtual_lattice = True
256+
bg_cell.lower_left = list(grp['vl_lower_left'][()])
257+
bg_cell.pitch = list(grp['vl_pitch'][()])
258+
bg_cell.shape = list(grp['vl_shape'][()])
259+
cell_fills[bg_cell_id] = ('material', bg_material_id)
260+
self._fast_cells[bg_cell_id] = bg_cell
261+
262+
return cell_fills
263+
197264
def _read_universes(self):
198265
for group in self._f['geometry/universes'].values():
199266
geom_type = group.get('geom_type')

src/summary.cpp

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "openmc/summary.h"
22

33
#include <fmt/core.h>
4+
#include <map>
45

56
#include "openmc/capi.h"
67
#include "openmc/cell.h"
@@ -93,25 +94,139 @@ void write_nuclides(hid_t file)
9394
close_group(macro_group);
9495
}
9596

97+
void write_triso_particles(hid_t geom_group)
98+
{
99+
// Collect all TRISO surfaces and group by background cell ID
100+
std::map<int32_t, vector<int32_t>> bg_to_surfs;
101+
for (int i = 0; i < model::surfaces.size(); ++i) {
102+
const auto& surf = model::surfaces[i];
103+
if (surf->is_triso_surface_) {
104+
bg_to_surfs[surf->triso_base_index_].push_back(i);
105+
}
106+
}
107+
108+
int n_groups = bg_to_surfs.size();
109+
if (n_groups == 0)
110+
return;
111+
112+
// Count total TRISO particles
113+
int n_triso = 0;
114+
for (const auto& [bg_id, surfs] : bg_to_surfs) {
115+
n_triso += surfs.size();
116+
}
117+
118+
// Build flat arrays
119+
vector<double> positions(n_triso * 4);
120+
vector<int32_t> surface_ids(n_triso);
121+
vector<int32_t> cell_ids(n_triso);
122+
vector<int32_t> fill_universes(n_triso);
123+
vector<int32_t> group_offsets(n_groups + 1);
124+
125+
int idx = 0;
126+
int g = 0;
127+
group_offsets[0] = 0;
128+
129+
for (const auto& [bg_cell_id, surfs] : bg_to_surfs) {
130+
for (const auto& i_surf : surfs) {
131+
const auto& surf = model::surfaces[i_surf];
132+
vector<double> center = surf->get_center();
133+
double radius = surf->get_radius();
134+
positions[idx * 4 + 0] = center[0];
135+
positions[idx * 4 + 1] = center[1];
136+
positions[idx * 4 + 2] = center[2];
137+
positions[idx * 4 + 3] = radius;
138+
surface_ids[idx] = surf->id_;
139+
// Get TRISO particle cell via triso_particle_index_
140+
int32_t i_cell = model::cell_map.at(surf->triso_particle_index_);
141+
const auto& cell = model::cells[i_cell];
142+
cell_ids[idx] = cell->id_;
143+
fill_universes[idx] = model::universes[cell->fill_]->id_;
144+
++idx;
145+
}
146+
group_offsets[g + 1] = idx;
147+
++g;
148+
}
149+
150+
// Write compact TRISO data to HDF5
151+
hid_t triso_group = create_group(geom_group, "triso_particles");
152+
write_attribute(triso_group, "n_groups", n_groups);
153+
write_attribute(triso_group, "n_triso", n_triso);
154+
155+
// Write positions as 2D dataset [n_triso, 4]
156+
hsize_t pos_dims[] = {static_cast<hsize_t>(n_triso), 4};
157+
write_dataset_lowlevel(triso_group, 2, pos_dims, "positions",
158+
H5TypeMap<double>::type_id, H5S_ALL, false, positions.data());
159+
160+
write_dataset(triso_group, "surface_ids", surface_ids);
161+
write_dataset(triso_group, "cell_ids", cell_ids);
162+
write_dataset(triso_group, "fill_universes", fill_universes);
163+
write_dataset(triso_group, "group_offsets", group_offsets);
164+
165+
// Write per-group metadata (background cell info)
166+
hid_t groups_group = create_group(triso_group, "groups");
167+
g = 0;
168+
for (const auto& [bg_cell_id, surfs] : bg_to_surfs) {
169+
auto grp = create_group(groups_group, std::to_string(g));
170+
171+
int32_t i_bg_cell = model::cell_map.at(bg_cell_id);
172+
const auto& bg_cell = model::cells[i_bg_cell];
173+
174+
write_dataset(grp, "background_cell_id", bg_cell->id_);
175+
write_dataset(grp, "background_material_id",
176+
model::materials[bg_cell->material_[0]]->id_);
177+
write_dataset(grp, "background_universe_id",
178+
model::universes[bg_cell->universe_]->id_);
179+
write_dataset(grp, "vl_lower_left", bg_cell->vl_lower_left_);
180+
write_dataset(grp, "vl_pitch", bg_cell->vl_pitch_);
181+
write_dataset(grp, "vl_shape", bg_cell->vl_shape_);
182+
183+
close_group(grp);
184+
++g;
185+
}
186+
close_group(groups_group);
187+
close_group(triso_group);
188+
}
189+
96190
void write_geometry(hid_t file)
97191
{
98192
auto geom_group = create_group(file, "geometry");
99193

100-
write_attribute(geom_group, "n_cells", model::cells.size());
101-
write_attribute(geom_group, "n_surfaces", model::surfaces.size());
194+
// Count non-TRISO cells and surfaces for accurate counts
195+
int n_cells = 0;
196+
int n_surfaces = 0;
197+
for (const auto& c : model::cells) {
198+
if (!c->triso_particle_ && !c->virtual_lattice_)
199+
++n_cells;
200+
}
201+
for (const auto& surf : model::surfaces) {
202+
if (!surf->is_triso_surface_)
203+
++n_surfaces;
204+
}
205+
206+
write_attribute(geom_group, "n_cells", n_cells);
207+
write_attribute(geom_group, "n_surfaces", n_surfaces);
102208
write_attribute(geom_group, "n_universes", model::universes.size());
103209
write_attribute(geom_group, "n_lattices", model::lattices.size());
104210

105211
auto cells_group = create_group(geom_group, "cells");
106-
for (const auto& c : model::cells)
212+
for (const auto& c : model::cells) {
213+
if (c->triso_particle_ || c->virtual_lattice_)
214+
continue;
107215
c->to_hdf5(cells_group);
216+
}
108217
close_group(cells_group);
109218

110219
auto surfaces_group = create_group(geom_group, "surfaces");
111-
for (const auto& surf : model::surfaces)
220+
for (const auto& surf : model::surfaces) {
221+
if (surf->is_triso_surface_)
222+
continue;
112223
surf->to_hdf5(surfaces_group);
224+
}
113225
close_group(surfaces_group);
114226

227+
// Write compact TRISO particle data
228+
write_triso_particles(geom_group);
229+
115230
auto universes_group = create_group(geom_group, "universes");
116231
for (const auto& u : model::universes)
117232
u->to_hdf5(universes_group);

0 commit comments

Comments
 (0)