Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
24ed018
add TimedMeshFilter Python API
ilhamv Aug 2, 2024
75aa798
autopep8
ilhamv Aug 2, 2024
319d2a1
add timed_mesh_filter.cpp
ilhamv Aug 2, 2024
46beb54
add timed_mesh_filter.cpp (previously didn't get added...)
ilhamv Aug 2, 2024
19d4594
fix MG timing for fission secondaries
ilhamv Aug 2, 2024
ddde280
fix minor bug
ilhamv Aug 2, 2024
cc7c75b
add MG speed getter
ilhamv Aug 2, 2024
9280e10
fix bug in tracklength tallying at time-cutoff crossing
ilhamv Aug 2, 2024
7cb5469
remove time filters from src/lib/filter.py
ilhamv Aug 3, 2024
4f5542f
Merge branch 'develop' into timed_mesh_filter
ilhamv Sep 19, 2024
a8f7521
also generate mesh xml element for timed mesh filter
ilhamv Sep 22, 2024
4c86e6e
fix a mistake in instance checking
ilhamv Oct 5, 2024
7a6b967
Merge branch 'develop' into timed_mesh_filter
ilhamv Oct 5, 2024
50d5207
Merge branch 'develop' into timed_mesh_filter
ilhamv Nov 11, 2024
1e0994d
Merge branch 'timed_mesh_filter' of https://github.com/ilhamv/openmc …
ilhamv Nov 11, 2024
3b30ffa
update timed mesh filter
ilhamv Nov 11, 2024
b3b76b6
Merge branch 'openmc-dev:develop' into timed_mesh_filter
ilhamv Dec 11, 2024
a33da5c
Merge branch 'develop' into timed_mesh_filter
ilhamv May 29, 2025
36321b9
add a unit test
ilhamv Jun 2, 2025
5ec152f
fix gsl::span
ilhamv Jun 2, 2025
0d7ba71
add a unit test
ilhamv Jun 2, 2025
fcd8460
remove debugging prints
ilhamv Jun 12, 2025
fa9db2e
skip timed-mesh filtering if zero time interval
ilhamv Jun 12, 2025
0bd95c0
Merge branch 'develop' into timed_mesh_filter
ilhamv Jul 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ list(APPEND libopenmc_SOURCES
src/tallies/filter_sptl_legendre.cpp
src/tallies/filter_surface.cpp
src/tallies/filter_time.cpp
src/tallies/filter_timed_mesh.cpp
src/tallies/filter_universe.cpp
src/tallies/filter_weight.cpp
src/tallies/filter_zernike.cpp
Expand Down
1 change: 1 addition & 0 deletions docs/source/pythonapi/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ Constructing Tallies
openmc.SpatialLegendreFilter
openmc.SphericalHarmonicsFilter
openmc.TimeFilter
openmc.TimedMeshFilter
openmc.WeightFilter
openmc.ZernikeFilter
openmc.ZernikeRadialFilter
Expand Down
1 change: 1 addition & 0 deletions include/openmc/tallies/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class FilterType {
SPATIAL_LEGENDRE,
SURFACE,
TIME,
TIMED_MESH,
UNIVERSE,
WEIGHT,
ZERNIKE,
Expand Down
75 changes: 75 additions & 0 deletions include/openmc/tallies/filter_timed_mesh.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef OPENMC_TALLIES_FILTER_TIMED_MESH_H
#define OPENMC_TALLIES_FILTER_TIMED_MESH_H

#include <cstdint>

#include "openmc/constants.h"
#include "openmc/position.h"
#include "openmc/span.h"
#include "openmc/tallies/filter.h"

namespace openmc {

//==============================================================================
//! Indexes the time-location of particle events to a time gridn and a regular
// mesh. For tracklength tallies, it will produce multiple valid bins and the
// bin weight will correspond to the fraction of the track length that lies in
//! that bin.
//==============================================================================

class TimedMeshFilter : public Filter {
public:
//----------------------------------------------------------------------------
// Constructors, destructors

~TimedMeshFilter() = default;

//----------------------------------------------------------------------------
// Methods

std::string type_str() const override { return "timedmesh"; }
FilterType type() const override { return FilterType::TIMED_MESH; }

void from_xml(pugi::xml_node node) override;

void get_all_bins(const Particle& p, TallyEstimator estimator,
FilterMatch& match) const override;

void to_statepoint(hid_t filter_group) const override;

std::string text_label(int bin) const override;

//----------------------------------------------------------------------------
// Accessors

int32_t mesh() const { return mesh_; }

void set_mesh(int32_t mesh);

void set_translation(const Position& translation);

void set_translation(const double translation[3]);

const Position& translation() const { return translation_; }

bool translated() const { return translated_; }

const vector<double>& time_grid() const { return time_grid_; }

void set_time_grid(span<const double> time_grid);

void reset_bins();

protected:
//----------------------------------------------------------------------------
// Data members

int32_t mesh_; //!< Index of the mesh
int mesh_n_bins_;
bool translated_ {false}; //!< Whether or not the filter is translated
Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation
vector<double> time_grid_ {0.0, INFTY};
};

} // namespace openmc
#endif // OPENMC_TALLIES_FILTER_TIMED_MESH_H
153 changes: 152 additions & 1 deletion openmc/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
'energyfunction', 'cellfrom', 'materialfrom', 'legendre', 'spatiallegendre',
'sphericalharmonics', 'zernike', 'zernikeradial', 'particle', 'cellinstance',
'collision', 'time', 'parentnuclide', 'weight', 'meshborn', 'meshsurface',
'meshmaterial',
'meshmaterial', 'timedmesh',
)

_CURRENT_NAMES = (
Expand Down Expand Up @@ -1326,6 +1326,157 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs):
return pd.concat([df, pd.DataFrame(filter_dict)])


class TimedMeshFilter(Filter):
"""Bins tally event locations by mesh elements and time grids.

Parameters
----------
mesh : openmc.MeshBase
The mesh object that events will be tallied onto
time_grid : iterable of float
A list of values for which each successive pair constitutes a range of
time in [s] for a single time bin
filter_id : int
Unique identifier for the filter

Attributes
----------
mesh : openmc.MeshBase
The mesh object that events will be tallied onto
time_grid : numpy.ndarray
An array of values for which each successive pair constitutes a range of
time in [s] for a single time bin
id : int
Unique identifier for the filter
translation : Iterable of float
This array specifies a vector that is used to translate (shift) the mesh
for this filter
bins : list of tuple
A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1),
...]
num_bins : Integral
The number of filter bins

"""

def __init__(self, mesh, time_grid, filter_id=None):
self._time_grid = np.array([0.0, np.inf]) # Temporary
self.mesh = mesh
self.time_grid = time_grid
self.id = filter_id
self._translation = None

def __hash__(self):
string = type(self).__name__ + '\n'
string += '{: <16}=\t{}\n'.format('\tMesh ID', self.mesh.id)
string += '{: <16}=\t{}\n'.format('\tTime grid', self.time_grid)
return hash(string)

def __repr__(self):
string = type(self).__name__ + '\n'
string += '{: <16}=\t{}\n'.format('\tMesh ID', self.mesh.id)
string += '{: <16}=\t{}\n'.format('\tTime grid', self.time_grid)
string += '{: <16}=\t{}\n'.format('\tID', self.id)
string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation)
return string

@classmethod
def from_hdf5(cls, group, **kwargs):
if group['type'][()].decode() != cls.short_name.lower():
raise ValueError("Expected HDF5 data for filter type '"
+ cls.short_name.lower() + "' but got '"
+ group['type'][()].decode() + " instead")

if 'meshes' not in kwargs:
raise ValueError(cls.__name__ + " requires a 'meshes' keyword "
"argument.")

mesh_id = group['mesh_bins'][()]
mesh_obj = kwargs['meshes'][mesh_id]
filter_id = int(group.name.split('/')[-1].lstrip('filter '))

time_grid = group['time_bins'][()]

out = cls(mesh_obj, time_grid, filter_id=filter_id)

translation = group.get('translation')
if translation:
out.translation = translation[()]

return out

@property
def mesh(self):
return self._mesh

@property
def time_grid(self):
return self._time_grid

@mesh.setter
def mesh(self, mesh):
cv.check_type('filter mesh', mesh, openmc.MeshBase)
self._mesh = mesh
self._reset_bins()

@time_grid.setter
def time_grid(self, time_grid):
self._time_grid = time_grid
self._reset_bins()

def _reset_bins(self):
mesh = self._mesh
time_grid = self._time_grid

# Mesh bins
if isinstance(mesh, openmc.UnstructuredMesh):
if mesh.has_statepoint_data:
mesh_bins = list(range(len(mesh.volumes)))
else:
mesh_bins = []
else:
mesh_bins = list(mesh.indices)

# Reset bins
self.bins = []
for i in range(len(self._time_grid) - 1):
for j in range(len(mesh_bins)):
new_bin = ()
new_bin += ([float(time_grid[i]), float(time_grid[i+1])],)
new_bin += (mesh_bins[j],)
self.bins.append(new_bin)

@property
def shape(self):
return (len(self.time_grid) - 1,) + self.mesh.dimension

@property
def translation(self):
return self._translation

@translation.setter
def translation(self, t):
cv.check_type('mesh filter translation', t, Iterable, Real)
cv.check_length('mesh filter translation', t, 3)
self._translation = np.asarray(t)

def can_merge(self, other):
return False

def to_xml_element(self):
element = super().to_xml_element()
element[0].text = None

time_bins = ET.SubElement(element[0], 'time_bins')
mesh_bins = ET.SubElement(element[0], 'mesh_bins')

time_bins.text = ' '.join(str(x) for x in self.time_grid)
mesh_bins.text = str(self.mesh.id)
if self.translation is not None:
element.set('translation', ' '.join(map(str, self.translation)))
return element


class CollisionFilter(Filter):
"""Bins tally events based on the number of collisions.

Expand Down
2 changes: 1 addition & 1 deletion openmc/tallies.py
Original file line number Diff line number Diff line change
Expand Up @@ -3285,7 +3285,7 @@ def _create_mesh_subelements(self, root_element, memo=None):
already_written = memo if memo else set()
for tally in self:
for f in tally.filters:
if isinstance(f, openmc.MeshFilter):
if type(f) in {openmc.MeshFilter, openmc.TimedMeshFilter}:
if f.mesh.id in already_written:
continue
if len(f.mesh.name) > 0:
Expand Down
12 changes: 12 additions & 0 deletions src/particle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ namespace openmc {

double Particle::speed() const
{
// Multigroup speed?
if (!settings::run_CE) {
auto& macro_xs = data::mg.macro_xs_[this->material()];
int macro_t = this->mg_xs_cache().t;
int macro_a = macro_xs.get_angle_index(this->u());
return 1.0 / macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, this->g(), nullptr,
nullptr, nullptr, macro_t, macro_a);
}

// Determine mass in eV/c^2
double mass;
switch (this->type()) {
Expand Down Expand Up @@ -265,6 +274,9 @@ void Particle::event_advance()
double push_back_distance = speed() * dt;
this->move_distance(-push_back_distance);
hit_time_boundary = true;

// Reduce the distance traveled for tallying
distance -= push_back_distance;
}

// Score track-length tallies
Expand Down
1 change: 1 addition & 0 deletions src/physics_mg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ void create_fission_sites(Particle& p)
SourceSite site;
site.r = p.r();
site.particle = ParticleType::neutron;
site.time = p.time();
site.wgt = 1. / weight;
site.parent_id = p.id();
site.progeny_id = p.n_progeny()++;
Expand Down
3 changes: 3 additions & 0 deletions src/tallies/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "openmc/tallies/filter_sptl_legendre.h"
#include "openmc/tallies/filter_surface.h"
#include "openmc/tallies/filter_time.h"
#include "openmc/tallies/filter_timed_mesh.h"
#include "openmc/tallies/filter_universe.h"
#include "openmc/tallies/filter_weight.h"
#include "openmc/tallies/filter_zernike.h"
Expand Down Expand Up @@ -156,6 +157,8 @@ Filter* Filter::create(const std::string& type, int32_t id)
return Filter::create<SphericalHarmonicsFilter>(id);
} else if (type == "time") {
return Filter::create<TimeFilter>(id);
} else if (type == "timedmesh") {
return Filter::create<TimedMeshFilter>(id);
} else if (type == "universe") {
return Filter::create<UniverseFilter>(id);
} else if (type == "weight") {
Expand Down
Loading