mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
Introduce new C API function for slice plots (#3806)
Some checks are pending
Tests and Coverage / filter-changes (push) Waiting to run
Tests and Coverage / Python 3.13 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14t (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=, event=y (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=y, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / coverage (push) Blocked by required conditions
Tests and Coverage / Check CI status (push) Blocked by required conditions
dockerhub-publish-develop / main (push) Waiting to run
dockerhub-publish-develop-dagmc-libmesh / main (push) Waiting to run
dockerhub-publish-develop-dagmc / main (push) Waiting to run
dockerhub-publish-develop-libmesh / main (push) Waiting to run
Some checks are pending
Tests and Coverage / filter-changes (push) Waiting to run
Tests and Coverage / Python 3.13 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14t (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=, event=y (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=y, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / coverage (push) Blocked by required conditions
Tests and Coverage / Check CI status (push) Blocked by required conditions
dockerhub-publish-develop / main (push) Waiting to run
dockerhub-publish-develop-dagmc-libmesh / main (push) Waiting to run
dockerhub-publish-develop-dagmc / main (push) Waiting to run
dockerhub-publish-develop-libmesh / main (push) Waiting to run
This commit is contained in:
parent
db322f2c5d
commit
4f6a25e00a
7 changed files with 755 additions and 283 deletions
|
|
@ -18,6 +18,8 @@
|
|||
#include "openmc/position.h"
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/ray.h"
|
||||
#include "openmc/tallies/filter.h"
|
||||
#include "openmc/tallies/filter_match.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -148,10 +150,11 @@ public:
|
|||
|
||||
struct IdData {
|
||||
// Constructor
|
||||
IdData(size_t h_res, size_t v_res);
|
||||
IdData(size_t h_res, size_t v_res, bool include_filter = false);
|
||||
|
||||
// Methods
|
||||
void set_value(size_t y, size_t x, const GeometryState& p, int level);
|
||||
void set_value(size_t y, size_t x, const Particle& p, int level,
|
||||
Filter* filter = nullptr, FilterMatch* match = nullptr);
|
||||
void set_overlap(size_t y, size_t x);
|
||||
|
||||
// Members
|
||||
|
|
@ -160,16 +163,34 @@ struct IdData {
|
|||
|
||||
struct PropertyData {
|
||||
// Constructor
|
||||
PropertyData(size_t h_res, size_t v_res);
|
||||
PropertyData(size_t h_res, size_t v_res, bool include_filter = false);
|
||||
|
||||
// Methods
|
||||
void set_value(size_t y, size_t x, const GeometryState& p, int level);
|
||||
void set_value(size_t y, size_t x, const Particle& p, int level,
|
||||
Filter* filter = nullptr, FilterMatch* match = nullptr);
|
||||
void set_overlap(size_t y, size_t x);
|
||||
|
||||
// Members
|
||||
tensor::Tensor<double> data_; //!< 2D array of temperature & density data
|
||||
};
|
||||
|
||||
struct RasterData {
|
||||
// Constructor
|
||||
RasterData(size_t h_res, size_t v_res, bool include_filter = false);
|
||||
|
||||
// Methods
|
||||
void set_value(size_t y, size_t x, const Particle& p, int level,
|
||||
Filter* filter = nullptr, FilterMatch* match = nullptr);
|
||||
void set_overlap(size_t y, size_t x);
|
||||
|
||||
// Members
|
||||
tensor::Tensor<int32_t>
|
||||
id_data_; //!< [v_res, h_res, 3 or 4]: cell, instance, mat, [filter_bin]
|
||||
tensor::Tensor<double>
|
||||
property_data_; //!< [v_res, h_res, 2]: temperature, density
|
||||
bool include_filter_; //!< Whether filter bin index is included
|
||||
};
|
||||
|
||||
//===============================================================================
|
||||
// Plot class
|
||||
//===============================================================================
|
||||
|
|
@ -177,7 +198,7 @@ struct PropertyData {
|
|||
class SlicePlotBase {
|
||||
public:
|
||||
template<class T>
|
||||
T get_map() const;
|
||||
T get_map(int32_t filter_index = -1) const;
|
||||
|
||||
enum class PlotBasis { xy = 1, xz = 2, yz = 3 };
|
||||
|
||||
|
|
@ -188,70 +209,65 @@ public:
|
|||
|
||||
// Members
|
||||
public:
|
||||
Position origin_; //!< Plot origin in geometry
|
||||
Position width_; //!< Plot width in geometry
|
||||
PlotBasis basis_; //!< Plot basis (XY/XZ/YZ)
|
||||
array<size_t, 3> pixels_; //!< Plot size in pixels
|
||||
bool slice_color_overlaps_; //!< Show overlapping cells?
|
||||
int slice_level_ {-1}; //!< Plot universe level
|
||||
Position origin_; //!< Plot origin in geometry
|
||||
Direction u_span_; //!< Full-width span vector in geometry
|
||||
Direction v_span_; //!< Full-height span vector in geometry
|
||||
array<size_t, 3> pixels_; //!< Plot size in pixels
|
||||
bool show_overlaps_; //!< Show overlapping cells?
|
||||
int slice_level_ {-1}; //!< Plot universe level
|
||||
private:
|
||||
};
|
||||
|
||||
template<class T>
|
||||
T SlicePlotBase::get_map() const
|
||||
T SlicePlotBase::get_map(int32_t filter_index) const
|
||||
{
|
||||
|
||||
size_t width = pixels_[0];
|
||||
size_t height = pixels_[1];
|
||||
|
||||
// get pixel size
|
||||
double in_pixel = (width_[0]) / static_cast<double>(width);
|
||||
double out_pixel = (width_[1]) / static_cast<double>(height);
|
||||
|
||||
// size data array
|
||||
T data(width, height);
|
||||
|
||||
// setup basis indices and initial position centered on pixel
|
||||
int in_i, out_i;
|
||||
Position xyz = origin_;
|
||||
switch (basis_) {
|
||||
case PlotBasis::xy:
|
||||
in_i = 0;
|
||||
out_i = 1;
|
||||
break;
|
||||
case PlotBasis::xz:
|
||||
in_i = 0;
|
||||
out_i = 2;
|
||||
break;
|
||||
case PlotBasis::yz:
|
||||
in_i = 1;
|
||||
out_i = 2;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
// Determine if filter is being used
|
||||
bool include_filter = (filter_index >= 0);
|
||||
Filter* filter = nullptr;
|
||||
if (include_filter) {
|
||||
filter = model::tally_filters[filter_index].get();
|
||||
}
|
||||
|
||||
// set initial position
|
||||
xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.;
|
||||
xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.;
|
||||
// size data array
|
||||
T data(width, height, include_filter);
|
||||
|
||||
// arbitrary direction
|
||||
Direction dir = {1. / std::sqrt(2.), 1. / std::sqrt(2.), 0.0};
|
||||
// compute pixel steps and top-left pixel center
|
||||
Direction u_step = u_span_ / static_cast<double>(width);
|
||||
Direction v_step = v_span_ / static_cast<double>(height);
|
||||
|
||||
Position start =
|
||||
origin_ - 0.5 * u_span_ + 0.5 * v_span_ + 0.5 * u_step - 0.5 * v_step;
|
||||
|
||||
// Validate that span vectors define a valid plane
|
||||
Position cross = u_span_.cross(v_span_);
|
||||
if (cross.norm() == 0.0) {
|
||||
fatal_error("Slice span vectors are invalid (zero area).");
|
||||
}
|
||||
|
||||
// Use an arbitrary direction that is not aligned with any coordinate axis.
|
||||
// The direction has no physical meaning for plotting but is used by
|
||||
// Surface::sense() to break ties when a pixel is coincident with a surface.
|
||||
Direction dir = {1.0 / std::sqrt(2.0), 1.0 / std::sqrt(2.0), 0.0};
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
GeometryState p;
|
||||
p.r() = xyz;
|
||||
Particle p;
|
||||
p.r() = start;
|
||||
p.u() = dir;
|
||||
p.coord(0).universe() = model::root_universe;
|
||||
int level = slice_level_;
|
||||
int j {};
|
||||
FilterMatch match;
|
||||
|
||||
#pragma omp for
|
||||
for (int y = 0; y < height; y++) {
|
||||
p.r()[out_i] = xyz[out_i] - out_pixel * y;
|
||||
Position row = start - v_step * static_cast<double>(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
p.r()[in_i] = xyz[in_i] + in_pixel * x;
|
||||
p.r() = row + u_step * static_cast<double>(x);
|
||||
p.n_coord() = 1;
|
||||
// local variables
|
||||
bool found_cell = exhaustive_find_cell(p);
|
||||
|
|
@ -260,9 +276,9 @@ T SlicePlotBase::get_map() const
|
|||
j = level;
|
||||
}
|
||||
if (found_cell) {
|
||||
data.set_value(y, x, p, j);
|
||||
data.set_value(y, x, p, j, filter, &match);
|
||||
}
|
||||
if (slice_color_overlaps_ && check_cell_overlap(p, false)) {
|
||||
if (show_overlaps_ && check_cell_overlap(p, false)) {
|
||||
data.set_overlap(y, x);
|
||||
}
|
||||
} // inner for
|
||||
|
|
@ -297,6 +313,8 @@ public:
|
|||
void print_info() const override;
|
||||
|
||||
PlotType type_; //!< Plot type (Slice/Voxel)
|
||||
Position width_; //!< Axis-aligned width from plot.xml
|
||||
PlotBasis basis_; //!< Basis from plot.xml for slice plots
|
||||
int meshlines_width_; //!< Width of lines added to the plot
|
||||
int index_meshlines_mesh_ {-1}; //!< Index of the mesh to draw on the plot
|
||||
RGBColor meshlines_color_; //!< Color of meshlines on the plot
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue