Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
282ba43
First prototype for temperature field
JoffreyDorville Dec 15, 2025
cf19709
Clean event identifiers for history-based transport
JoffreyDorville Dec 15, 2025
032275a
New particle attribute for the next event
JoffreyDorville Dec 15, 2025
8a138da
Cleaning
JoffreyDorville Dec 15, 2025
d29e700
Common update function for the particle temperature
JoffreyDorville Dec 15, 2025
2e5e0c9
Cleaning
JoffreyDorville Dec 15, 2025
ba02d46
Cleaning
JoffreyDorville Dec 15, 2025
5c52c5f
Add temperature values during the initialization for thermal scatteri…
JoffreyDorville Dec 17, 2025
06f27c7
Clean Python API
JoffreyDorville Dec 19, 2025
d20e3ea
Regression test
JoffreyDorville Dec 19, 2025
6c9b918
Update documentation
JoffreyDorville Dec 20, 2025
4b660d6
Create a main C++ ScalarField class
JoffreyDorville Dec 20, 2025
3b3b32f
Check that size of mesh and size of values are consistent in the fiel…
JoffreyDorville Dec 20, 2025
6dd684d
Formatting
JoffreyDorville Dec 20, 2025
76cdf20
Manage incompatibility with event-based mode
JoffreyDorville Dec 20, 2025
49bfb76
Unit test for the distance to next boundary method
JoffreyDorville Dec 20, 2025
5e79b7b
Missing init file in new regression test
JoffreyDorville Jan 15, 2026
0c67016
Formatting
JoffreyDorville Jan 15, 2026
2ee8edb
First attempt to enable event-based mode
JoffreyDorville Mar 24, 2026
cd4443b
Revert error message for incompatibility with event-based mode
JoffreyDorville Mar 24, 2026
aef0709
Formatting
JoffreyDorville Mar 24, 2026
091925a
Cleaning
JoffreyDorville Mar 24, 2026
b0b28ba
Add distance_to_next_boundary() tests for rectilinear, cylindrical, a…
JoffreyDorville Mar 31, 2026
d886d44
Initialize coord_ with an element to be compatible with p.r() at Part…
JoffreyDorville Mar 31, 2026
cf903c8
C++ unit tests for temperature fields
JoffreyDorville Mar 31, 2026
b1e4fee
C API interface to update temperature values in the temperature field
JoffreyDorville Mar 31, 2026
68d8d9c
C API documentation update
JoffreyDorville Apr 1, 2026
614564b
Remove unused function in Python API
JoffreyDorville Apr 1, 2026
7bee829
Test that the number of temperature values given is consistent with t…
JoffreyDorville Apr 1, 2026
78529b5
Fix XML reader
JoffreyDorville Apr 1, 2026
d91a64d
Define equality function for ScalarFields
JoffreyDorville Apr 1, 2026
068b92b
Unit test for temperature field - Python API
JoffreyDorville Apr 1, 2026
027c35c
Change fatal_error to throw
JoffreyDorville Apr 1, 2026
1bd1b5c
Unit test temperature field - C++ side
JoffreyDorville Apr 1, 2026
9bd31c1
Merge branch 'develop' into temperate_from_mesh
JoffreyDorville Apr 1, 2026
242a842
Temporarily disable part of temperature field c++ unit tests
JoffreyDorville Apr 2, 2026
967090c
Revert initialization of coord_ and declare n_coord_levels in test in…
JoffreyDorville Apr 2, 2026
a8ddf99
Allow c++ test to be compiled with the DAGMC flag
JoffreyDorville Apr 2, 2026
3420117
Restore c++ unit test
JoffreyDorville Apr 2, 2026
5ddfca2
Formatting
JoffreyDorville Apr 2, 2026
d73f0cf
Change where the temperature update is performed for a field
JoffreyDorville Apr 21, 2026
1e104a9
Add unit test corresponding to the failing case
JoffreyDorville Apr 21, 2026
5e6b409
First attempt to solve the coincidence test case
JoffreyDorville Apr 21, 2026
c954785
Update unit tests
JoffreyDorville Apr 21, 2026
7f79940
Cleaning
JoffreyDorville Apr 23, 2026
d6c7a26
Cleaner minimun distance selection
JoffreyDorville Apr 23, 2026
7b7c80a
More robust search of the distance to the next boundary in structured…
JoffreyDorville Apr 23, 2026
6eaef71
Correction
JoffreyDorville Apr 23, 2026
2c51de4
Add a new attribute to particles to store information on the next tra…
JoffreyDorville Apr 30, 2026
a6f6617
Refactor history-based transport to only have one cross surface event
JoffreyDorville Apr 30, 2026
5e88589
Refactor event-based transport to only have one cross surface event
JoffreyDorville Apr 30, 2026
3bde460
Add temperature field bin and bin next
JoffreyDorville Apr 30, 2026
a5f63bf
Cleaning
JoffreyDorville Apr 30, 2026
7ca5f8f
Temporary function to calculate distance to a regular mesh when the p…
JoffreyDorville Apr 30, 2026
bcd208a
Change signature of distance_to_next_boundary to get bins information
JoffreyDorville Apr 30, 2026
92271f9
Update distance_to_next_boundary
JoffreyDorville Apr 30, 2026
0150a02
Remove unused functions
JoffreyDorville Apr 30, 2026
2311beb
Update particle temperature after locating the new cell
JoffreyDorville Apr 30, 2026
e020118
Manage temperature field bins with boundary conditions
JoffreyDorville May 1, 2026
9949c56
Clean the temperature field interface
JoffreyDorville May 1, 2026
de054db
Update DAGMC part of transport
JoffreyDorville May 1, 2026
6a9bd74
Update field cpp unit tests
JoffreyDorville May 4, 2026
b4954d1
Update regular mesh unit test with new distance to next boundary inte…
JoffreyDorville May 4, 2026
9cf6057
Add distance to mesh boundary from outside for rectilinear meshes
JoffreyDorville May 4, 2026
3c9a810
Update unit tests for rectilinear meshes
JoffreyDorville May 4, 2026
07ad591
Remove tests from features that are no longer available
JoffreyDorville May 5, 2026
d4b2140
Find the temperature field cell of secondary particles for pulse-heig…
JoffreyDorville May 5, 2026
f397a9a
Fix reflective boundary conditions with temperature field
JoffreyDorville May 5, 2026
cd906d7
Regression test - box with reflective BC
JoffreyDorville May 6, 2026
6a8f4a8
Regression test - box with vacuum BC
JoffreyDorville May 6, 2026
549beb0
Simplify the implementation and remove tf_bin_last
JoffreyDorville May 6, 2026
a9fff5a
Fix regular mesh index calculation when point is on the lower boundary
JoffreyDorville May 6, 2026
2e10a5d
Formatting
JoffreyDorville May 6, 2026
8f9f44a
Regression test - box with periodic BC
JoffreyDorville May 6, 2026
1ed498a
Regression test - surrounding box with reflective BC
JoffreyDorville May 6, 2026
2966590
Regression test - surrounding box with vacuum BC
JoffreyDorville May 6, 2026
2155926
Regression test - surrounding box with periodic BC
JoffreyDorville May 6, 2026
1901a85
Cleaning
JoffreyDorville May 14, 2026
f2e1948
Reset DAGMC history after crossing the temperature field only
JoffreyDorville May 14, 2026
6009008
Define next event in random ray transport
JoffreyDorville May 14, 2026
bd6a64f
Warn that the temperature field is ignored with random ray
JoffreyDorville May 14, 2026
0af48ac
Update test results because of the fix on regular mesh index when the…
JoffreyDorville May 15, 2026
24e3659
Manage lattices
JoffreyDorville May 15, 2026
ded9baa
Reorganize regular single cube regression tests
JoffreyDorville May 18, 2026
7f2fd78
Reorganize regular nested cubes regression tests
JoffreyDorville May 18, 2026
22f4eb1
Cleaning
JoffreyDorville May 18, 2026
edb6fb9
Reorganize regular verification scripts
JoffreyDorville May 18, 2026
f48b085
DAGMC regression tests + verification scripts
JoffreyDorville May 18, 2026
0edb912
Lattice verification scripts - nested cubes
JoffreyDorville May 19, 2026
a5952fb
Lattice verification scripts - single cube
JoffreyDorville May 19, 2026
7f96b45
Regression tests - lattices
JoffreyDorville May 19, 2026
c2bb44d
README file for temperature field regression tests
JoffreyDorville May 19, 2026
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 @@ -374,6 +374,7 @@ list(APPEND libopenmc_SOURCES
src/endf.cpp
src/error.cpp
src/event.cpp
src/field.cpp
src/file_utils.cpp
src/finalize.cpp
src/geometry.cpp
Expand Down
9 changes: 9 additions & 0 deletions docs/source/capi/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1030,3 +1030,12 @@ Functions
:type scores: const int*
:return: Return status (negative if an error occurred)
:rtype: int

.. c:function:: int openmc_temperature_field_set_temperature(int32_t index, double temperature)

Set the temperature value of a given cell in the temperature field

:param int32_t index: Index in the tempererature mesh
:param double temperature: Temperature in Kelvin
:return: Return status (negative if an error occurred)
:rtype: int
11 changes: 11 additions & 0 deletions docs/source/pythonapi/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ Meshes
openmc.SphericalMesh
openmc.UnstructuredMesh

Fields
------

.. autosummary::
:toctree: generated
:nosignatures:
:template: myclassinherit.rst

openmc.ScalarField
openmc.TemperatureField

Geometry Plotting
-----------------

Expand Down
31 changes: 31 additions & 0 deletions docs/source/usersguide/materials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,37 @@ attribute, e.g.,
:attr:`Material.temperature` or :attr:`Cell.temperature`
attributes, respectively.

Alternatively, temperatures can be specified using a temperature field composed
of a geometric mesh and a map that associates a temperature value to each mesh
cell. During the simulation, temperatures associated with particles are also
updated every time a temperature field cell surface is crossed. While a particle
is contained inside the temperature mesh, temperatures from the temperature field
take precedence over temperature declared for a cell, a material or globally.

The following example shows how to specify temperatures using a temperarature
field based on a regular mesh:

.. code-block:: python

# Define a mesh (regular mesh)
dim = 5
mesh = openmc.RegularMesh()
mesh.lower_left = (0., 0., 0.)
mesh.upper_right = (10.0, 10.0, 10.0)
mesh.dimension = (dim, dim, dim)

# Define temperature values for each cell
temperature_values = [273.0 + i * 10 for i in range(dim**3)]

# Create a temperature field
temperature_field = openmc.TemperatureField(mesh, temperature_values)

# Register the temperature field in the settings
settings = openmc.Settings()
settings.temperature_field = temperature_field

.. note:: Temperature fields are currently limited to structured meshes only.

-----------------
Material Mixtures
-----------------
Expand Down
8 changes: 8 additions & 0 deletions include/openmc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,14 @@ enum class GeometryType { CSG, DAG };
// representations. This value represents no surface.
constexpr int32_t SURFACE_NONE {0};

//==============================================================================
// EVENT IDENTIFIER IN HISTORY-BASED TRANSPORT

const int EVENT_UNDEFINED = 0;
const int EVENT_CROSS_SURFACE = 1;
const int EVENT_COLLIDE = 2;
const int EVENT_TIME_CUTOFF = 3;

} // namespace openmc

#endif // OPENMC_CONSTANTS_H
4 changes: 4 additions & 0 deletions include/openmc/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ void process_surface_crossing_events();
//! Execute the collision event for all particles in this event's buffer
void process_collision_events();

//! Execute the temperature mesh crossing event for all particles in this
//! event's buffer
void process_temperature_mesh_crossing_events();

//! Execute the death event for all particles
//
//! \param n_particles The number of particles in the particle buffer
Expand Down
96 changes: 96 additions & 0 deletions include/openmc/field.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#ifndef OPENMC_FIELD_H
#define OPENMC_FIELD_H

#include "openmc/mesh.h"
#include "openmc/vector.h"

namespace openmc {

class ScalarField {
public:
//----------------------------------------------------------------------------
// Constructors
ScalarField() = default;
ScalarField(
Mesh* mesh_ptr, vector<double> values, const std::string& field_name);
ScalarField(Mesh* mesh_ptr, vector<double> values)
: ScalarField(mesh_ptr, values, "ScalarField") {};

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

//! Returns the distance to the next mesh boundary given a particle position
//! and direction. If the particle is initially outside, the distance will
//! correspond to the nearest distance to the outer boundaries of the mesh.
//
//! \param[in] current_bin Current bin number
//! \param[in] r Position of the particle
//! \param[in] u Direction of the particle
//! \param[out] bin_next Next bin number
//! \return The distance in cm to the next mesh boundary
double distance_to_next_boundary(
int current_bin, const Position& r, const Direction& d, int& bin_next);

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

// Field type
const std::string& field_type() const { return this->field_type_; }

// Mesh pointer
Mesh* mesh_ptr() const
{
if (this->mesh_ptr_ == nullptr) {
fatal_error(fmt::format("No mesh found for {}!", this->field_type_));
} else {
return this->mesh_ptr_;
}
}

// Values
double& value(int i) { return values_[i]; }
const double& value(int i) const { return values_[i]; }
const vector<double>& values() const { return values_; }

private:
//----------------------------------------------------------------------------
// Data members
std::string field_type_; //! Name of field type
Mesh* mesh_ptr_; //!< Pointer to the geometric mesh
vector<double> values_; //!< Values associated with each mesh cell
};

class TemperatureField : public ScalarField {
public:
//----------------------------------------------------------------------------
// Constructors
TemperatureField() = default;
TemperatureField(Mesh* mesh_ptr, vector<double> values)
: ScalarField(mesh_ptr, values, "TemperatureField") {};

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

//! Returns the temperature in Kelvin corresponding to a given bin number
//! relative to the mesh.
//
//! \param[in] r Position of the particle
//! \return Temperature in Kelvin
double get_temperature(int bin);

//! Returns the square root of the temperature multiplied by the Boltzmann
//! constant in eV for a given bin number relative to the mesh.
//
//! \param[in] bin Bin number
//! \return Sqrt(k_Boltzmann * temperature) in eV
double get_sqrtkT(int bin);

//! Returns the bin number corresponding to the location of the particle.
//
//! \param[in] r Position of the particle
//! \return Corresponding bin number or -1 if outside the mesh
int get_bin(const Position& r);
};

} // namespace openmc
#endif // OPENMC_FIELD_H
43 changes: 43 additions & 0 deletions include/openmc/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,19 @@ class Mesh {
virtual void surface_bins_crossed(
Position r0, Position r1, const Direction& u, vector<int>& bins) const = 0;

//! Distance to the next boundary.
//! If the initial position is outside the mesh, the distance
//! will be from the initial position to the external boundary
//! of the mesh if hit.
//
//! \param[in] current_bin Current bin number
//! \param[in] r Position of the particle
//! \param[in] u Direction of the particle
//! \param[out] bin_next Next bin number
//! \return Distance to the next boundary
virtual double distance_to_next_boundary(
int current_bin, Position r, Direction u, int& bin_next) const = 0;

//! Get bin at a given position in space
//
//! \param[in] r Position to get bin for
Expand Down Expand Up @@ -333,6 +346,9 @@ class StructuredMesh : public Mesh {
void surface_bins_crossed(Position r0, Position r1, const Direction& u,
vector<int>& bins) const override;

double distance_to_next_boundary(
int current_bin, Position r, Direction u, int& bin_next) const override;

//! Determine which cell or surface bins were crossed by a particle
//
//! \param[in] r0 Previous position of the particle
Expand Down Expand Up @@ -416,6 +432,17 @@ class StructuredMesh : public Mesh {
virtual MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i,
const Position& r0, const Direction& u, double l) const = 0;

//! Find the closest distance from a point to the mesh boundaries that are
//! aligned with the k direction. The point has to be located outside the
//! mesh.
//!
//! \param[in] k direction index of grid surface
//! \param[in] r position, from where to calculate the distance
//! \param[in] u direction of flight
//! \return distance to the mesh boundary
virtual double distance_to_mesh_boundary_from_outside(
int k, const Position& r, const Direction& u) const = 0;

//! Get a label for the mesh bin
std::string bin_label(int bin) const override;

Expand Down Expand Up @@ -468,6 +495,13 @@ class PeriodicStructuredMesh : public StructuredMesh {
return r - origin_;
};

double distance_to_mesh_boundary_from_outside(
int k, const Position& r, const Direction& u) const override
{
fatal_error("Not implemented");
return -1.0;
}

// Data members
Position origin_ {0.0, 0.0, 0.0}; //!< Origin of the mesh
};
Expand All @@ -493,6 +527,9 @@ class RegularMesh : public StructuredMesh {
MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i,
const Position& r0, const Direction& u, double l) const override;

double distance_to_mesh_boundary_from_outside(
int k, const Position& r, const Direction& u) const override;

std::pair<vector<double>, vector<double>> plot(
Position plot_ll, Position plot_ur) const override;

Expand Down Expand Up @@ -546,6 +583,9 @@ class RectilinearMesh : public StructuredMesh {
MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i,
const Position& r0, const Direction& u, double l) const override;

double distance_to_mesh_boundary_from_outside(
int k, const Position& r, const Direction& u) const override;

std::pair<vector<double>, vector<double>> plot(
Position plot_ll, Position plot_ur) const override;

Expand Down Expand Up @@ -715,6 +755,9 @@ class UnstructuredMesh : public Mesh {
UnstructuredMesh(pugi::xml_node node);
UnstructuredMesh(hid_t group);

double distance_to_next_boundary(
int current_bin, Position r, Direction u, int& bin_next) const override;

static const std::string mesh_type;
virtual std::string get_mesh_type() const override;

Expand Down
37 changes: 35 additions & 2 deletions include/openmc/particle_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,24 @@ class BoundaryInfo {
0, 0, 0}; //!< which way lattice indices will change
};

struct TransportEvent {
int event_type = EVENT_UNDEFINED; //!< Type of transport event (crossing
//!< surface, collision, time cutoff)
bool cross_surface_geometry =
false; //!< if a surface of the geometry has been crossed during the event
bool cross_surface_temperature_field =
false; //!< if a surface of the temperature field has been crossed during
//!< the event

// resets all information
void clear()
{
event_type = EVENT_UNDEFINED;
cross_surface_geometry = false;
cross_surface_temperature_field = false;
}
};

/*
* Contains all geometry state information for a particle.
*/
Expand Down Expand Up @@ -412,6 +430,12 @@ class GeometryState {
const double& density_mult() const { return density_mult_; }
double& density_mult_last() { return density_mult_last_; }

// Temperature field related information
int& tf_bin() { return tf_bin_; }
const int& tf_bin() const { return tf_bin_; }
int& tf_bin_next() { return tf_bin_next_; }
const int& tf_bin_next() const { return tf_bin_next_; }

private:
int64_t id_ {-1}; //!< Unique ID

Expand All @@ -437,12 +461,15 @@ class GeometryState {
int material_ {-1}; //!< index for current material
int material_last_ {-1}; //!< index for last material

double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV
double sqrtkT_last_ {0.0}; //!< last temperature
double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV
double sqrtkT_last_ {-1.0}; //!< last temperature

double density_mult_ {1.0}; //!< density multiplier
double density_mult_last_ {1.0}; //!< last density multiplier

int tf_bin_ = C_NONE; //!< Current temperature field bin
int tf_bin_next_ = C_NONE; //!< Next temperature field bin

#ifdef OPENMC_DAGMC_ENABLED
moab::DagMC::RayHistory history_;
Direction last_dir_;
Expand Down Expand Up @@ -568,6 +595,8 @@ class ParticleData : public GeometryState {

int64_t n_progeny_ {0};

TransportEvent next_event_ = TransportEvent();

public:
//----------------------------------------------------------------------------
// Constructors
Expand Down Expand Up @@ -784,6 +813,10 @@ class ParticleData : public GeometryState {
d = 0;
}
}

// Next event in transport
TransportEvent& next_event() { return next_event_; }
const TransportEvent& next_event() const { return next_event_; }
};

} // namespace openmc
Expand Down
5 changes: 3 additions & 2 deletions include/openmc/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ extern bool
delayed_photon_scaling; //!< Scale fission photon yield to include delayed
extern "C" bool entropy_on; //!< calculate Shannon entropy?
extern "C" bool
event_based; //!< use event-based mode (instead of history-based)
extern bool ifp_on; //!< Use IFP for kinetics parameters?
event_based; //!< use event-based mode (instead of history-based)
extern bool temperature_field_on; //!< Is there a temperature field defined?
extern bool ifp_on; //!< Use IFP for kinetics parameters?
extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular?
extern bool material_cell_offsets; //!< create material cells offsets?
extern "C" bool output_summary; //!< write summary.h5?
Expand Down
3 changes: 3 additions & 0 deletions include/openmc/simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#ifndef OPENMC_SIMULATION_H
#define OPENMC_SIMULATION_H

#include "openmc/field.h"
#include "openmc/mesh.h"
#include "openmc/particle.h"
#include "openmc/vector.h"
Expand Down Expand Up @@ -46,6 +47,8 @@ extern int64_t work_per_rank; //!< number of particles per MPI rank
extern const RegularMesh* entropy_mesh;
extern const RegularMesh* ufs_mesh;

extern TemperatureField temperature_field;

extern vector<double> k_generation;
extern vector<int64_t> work_index;

Expand Down
Loading
Loading