Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
104 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
d3e2953
Documentation updates
paulromano May 28, 2026
8b83aa2
Remove unnecessary docstrings on __init__
paulromano May 28, 2026
b8e2148
Reorder settings
paulromano May 28, 2026
8a86e7f
Ensure values are written when the mesh is shared
JoffreyDorville Jun 15, 2026
2a0ecf1
Add openmc_temperature_field_set_temperature to the C API
JoffreyDorville Jun 15, 2026
d696229
Clean docstring for get_temperature(int)
JoffreyDorville Jun 15, 2026
376c2c8
Add settings documentation for temperature_field
JoffreyDorville Jun 15, 2026
7ff1402
Add consistency checks in field Python classes
JoffreyDorville Jun 16, 2026
98401f6
Merge branch 'develop' into temperate_from_mesh
JoffreyDorville Jun 16, 2026
c46c859
Update regression test because of the fix on get_index_direction for …
JoffreyDorville Jun 29, 2026
e517af4
Remove verification scripts and relocate them in a new repo
JoffreyDorville Jun 29, 2026
b05aeac
Update DAGMC test models
JoffreyDorville Jul 2, 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 @@ -350,6 +350,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
11 changes: 11 additions & 0 deletions docs/source/pythonapi/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,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 @@ -376,6 +376,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_CROSS_SURFACE = 1;
const int EVENT_COLLIDE = 2;
const int EVENT_CROSS_TEMPERATURE_MESH = 3;
const int EVENT_TIME_CUTOFF = 4;

} // namespace openmc

#endif // OPENMC_CONSTANTS_H
94 changes: 94 additions & 0 deletions include/openmc/field.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#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 gien 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] r Position of the particle
//! \param[in] u Direction of the particle
//! \return The distance in cm to the next mesh boundary
double distance_to_next_boundary(const Position& r, const Direction& d);

//----------------------------------------------------------------------------
// 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 the given position.
//
//! \param[in] r Position of the particle
//! \return Temperature in Kelvin
double get_temperature(const Position& r);

//! Returns the square root of the temperature multiplied by the Boltzmann
//! constant in eV for the given position.
//
//! \param[in] r Position of the particle
//! \return Sqrt(k_Boltzmann * temperature) in eV
double get_sqrtkT(const Position& r);

//! Update the temperature of a particle based on its position and direction.
//! If the particle is inside the temperature field, its temperature is
//! updated. If outside, the particle takes the temperature value
//! associated with the current cell instance.
//
//! \param[inout] p Particle
void update_particle_temperature(Particle& p);
};

} // namespace openmc
#endif // OPENMC_FIELD_H
14 changes: 14 additions & 0 deletions include/openmc/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ 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] r Position of the particle
//! \param[in] u Particle direction
//! \return Distance to the next boundary
virtual double distance_to_next_boundary(Position r, Direction u) const = 0;

//! Get bin at a given position in space
//
//! \param[in] r Position to get bin for
Expand Down Expand Up @@ -302,6 +312,8 @@ 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(Position r, Direction u) 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 @@ -684,6 +696,8 @@ class UnstructuredMesh : public Mesh {
UnstructuredMesh(pugi::xml_node node);
UnstructuredMesh(hid_t group);

double distance_to_next_boundary(Position r, Direction u) const override;

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

Expand Down
1 change: 1 addition & 0 deletions include/openmc/particle.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Particle : public ParticleData {
void event_calculate_xs();
void event_advance();
void event_cross_surface();
void event_cross_temperature_mesh();
void event_collide();
void event_revive_from_secondary();
void event_death();
Expand Down
6 changes: 6 additions & 0 deletions include/openmc/particle_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,8 @@ class ParticleData : public GeometryState {

int64_t n_progeny_ {0};

int next_event_ {0};

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

// Next event identifier for history-based transport
int next_event() const { return next_event_; }
int& next_event() { 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
1 change: 1 addition & 0 deletions openmc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from openmc.source import *
from openmc.settings import *
from openmc.lattice import *
from openmc.field import *
from openmc.filter import *
from openmc.filter_expansion import *
from openmc.trigger import *
Expand Down
67 changes: 67 additions & 0 deletions openmc/field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from abc import ABC, abstractmethod

import openmc


class ScalarField(ABC):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that ScalarField inherit from ABC but right now it doesn't have any abstract methods. Were you planning on making this class have a defined interface that subclasses would have to implement?

Also, right now these classes don't really have much "behavior" (methods), which calls into question if they are needed as classes in the first place, but I understand that they are likely to be expanded in the future. Can you elaborate on what you see these classes providing beyond what we could achieve with built-in type? i.e., why should it not just be:

settings.temperature_field = (mesh, values)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally had plans to add more features for the Python API like standardized I/O mechanisms for the values, values generators, and potentially visualization functions. With the changes I made in PR #3944, I realized that it would make more sense to expand the Python capabilities in PR #3944 so this is why the interface is rather minimal here.

I would still keep custom classes over built-in type, even if they are very minimalist for now, just because we will add more features in the future.

"""Scalar field defined on a geometric mesh.

Attributes
----------
mesh : Mesh
Spatial mesh associated with the field
values : iterable of float
List of values associated with each mesh cell

"""
def __init__(self, mesh, values):
"""Initialization.

Parameters
----------
mesh : Mesh
Spatial mesh associated with the field
values : iterable of float
List of values associated with each mesh cell

"""
self.mesh = mesh
self.values = values

@classmethod
def from_exodus_file(cls, filepath):
"""Construct a ScalarField from an Exodus mesh file

Parameters
----------
filepath : path-like or str
Path to the Exodus mesh file

"""
#TODO
raise NotImplementedError("Constructor not yet implemented.")


class TemperatureField(ScalarField):
"""Temperature field.

Attributes
----------
mesh : Mesh
Spatial mesh associated with the field
values : iterable of float
List of values associated with each mesh cell

"""
def __init__(self, mesh, values):
"""Initialization.

Parameters
----------
mesh : Mesh
Spatial mesh associated with the field
values : iterable of float
List of values associated with each mesh cell

"""
super().__init__(mesh, values)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have some validation here to check for cases that are not yet supported (unstructured mesh and, if I'm not mistaken, cylindrical/spherical mesh). Additionally, there could be some basic checks for consistency (number of values matches number of mesh elements, temperature values are positive).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Loading
Loading