• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmc-dev / openmc / 4961885432

pending completion
4961885432

push

github

GitHub
skip test that fails if VTK is missing (#2517)

42592 of 50894 relevant lines covered (83.69%)

82950838.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/include/openmc/plot.h
1
#ifndef OPENMC_PLOT_H
2
#define OPENMC_PLOT_H
3

4
#include <sstream>
5
#include <unordered_map>
6

7
#include "pugixml.hpp"
8
#include "xtensor/xarray.hpp"
9

10
#include "hdf5.h"
11
#include "openmc/cell.h"
12
#include "openmc/constants.h"
13
#include "openmc/error.h"
14
#include "openmc/geometry.h"
15
#include "openmc/particle.h"
16
#include "openmc/position.h"
17
#include "openmc/random_lcg.h"
18
#include "openmc/xml_interface.h"
19

20
namespace openmc {
21

22
//===============================================================================
23
// Global variables
24
//===============================================================================
25

26
class PlottableInterface;
27

28
namespace model {
29

30
extern std::unordered_map<int, int> plot_map; //!< map of plot ids to index
31
extern vector<std::unique_ptr<PlottableInterface>>
32
  plots; //!< Plot instance container
33

34
extern uint64_t plotter_seed; // Stream index used by the plotter
35

36
} // namespace model
37

38
//===============================================================================
39
// RGBColor holds color information for plotted objects
40
//===============================================================================
41

42
struct RGBColor {
43
  // Constructors
44
  RGBColor() : red(0), green(0), blue(0) {};
45
  RGBColor(const int v[3]) : red(v[0]), green(v[1]), blue(v[2]) {};
46
  RGBColor(int r, int g, int b) : red(r), green(g), blue(b) {};
×
47

48
  RGBColor(const vector<int>& v)
49
  {
50
    if (v.size() != 3) {
51
      throw std::out_of_range("Incorrect vector size for RGBColor.");
52
    }
53
    red = v[0];
54
    green = v[1];
55
    blue = v[2];
56
  }
57

58
  bool operator==(const RGBColor& other)
59
  {
60
    return red == other.red && green == other.green && blue == other.blue;
61
  }
62

63
  // Members
64
  uint8_t red, green, blue;
65
};
66

67
// some default colors
68
const RGBColor WHITE {255, 255, 255};
69
const RGBColor RED {255, 0, 0};
70
const RGBColor BLACK {0, 0, 0};
71

72
/*
73
 * PlottableInterface classes just have to have a unique ID in the plots.xml
74
 * file, and guarantee being able to create output in some way.
75
 */
76
class PlottableInterface {
77
private:
78
  void set_id(pugi::xml_node plot_node);
79
  int id_; // unique plot ID
80

81
  void set_bg_color(pugi::xml_node plot_node);
82
  void set_universe(pugi::xml_node plot_node);
83
  void set_default_colors(pugi::xml_node plot_node);
84
  void set_user_colors(pugi::xml_node plot_node);
85
  void set_overlap_color(pugi::xml_node plot_node);
86
  void set_mask(pugi::xml_node plot_node);
87

88
protected:
89
  // Plot output filename, derived classes have logic to set it
90
  std::string path_plot_;
91

92
public:
93
  enum class PlotColorBy { cells = 0, mats = 1 };
94

95
  // Creates the output image named path_plot_
96
  virtual void create_output() const = 0;
97

98
  // Print useful info to the terminal
99
  virtual void print_info() const = 0;
100

101
  const std::string& path_plot() const { return path_plot_; }
1,036✔
102
  const int id() const { return id_; }
2,210✔
103
  const int level() const { return level_; }
350✔
104

105
  // Public color-related data
106
  PlottableInterface(pugi::xml_node plot_node);
107
  int level_;                    // Universe level to plot
108
  bool color_overlaps_;          // Show overlapping cells?
109
  PlotColorBy color_by_;         // Plot coloring (cell/material)
110
  RGBColor not_found_ {WHITE};   // Plot background color
111
  RGBColor overlap_color_ {RED}; // Plot overlap color
112
  vector<RGBColor> colors_;      // Plot colors
113
};
114

115
typedef xt::xtensor<RGBColor, 2> ImageData;
116

117
struct IdData {
118
  // Constructor
119
  IdData(size_t h_res, size_t v_res);
120

121
  // Methods
122
  void set_value(size_t y, size_t x, const Particle& p, int level);
123
  void set_overlap(size_t y, size_t x);
124

125
  // Members
126
  xt::xtensor<int32_t, 3> data_; //!< 2D array of cell & material ids
127
};
128

129
struct PropertyData {
130
  // Constructor
131
  PropertyData(size_t h_res, size_t v_res);
132

133
  // Methods
134
  void set_value(size_t y, size_t x, const Particle& p, int level);
135
  void set_overlap(size_t y, size_t x);
136

137
  // Members
138
  xt::xtensor<double, 3> data_; //!< 2D array of temperature & density data
139
};
140

141
//===============================================================================
142
// Plot class
143
//===============================================================================
144

145
class SlicePlotBase {
146
public:
147
  template<class T>
148
  T get_map() const;
149

150
  enum class PlotBasis { xy = 1, xz = 2, yz = 3 };
151

152
  // Members
153
public:
154
  Position origin_;         //!< Plot origin in geometry
155
  Position width_;          //!< Plot width in geometry
156
  PlotBasis basis_;         //!< Plot basis (XY/XZ/YZ)
157
  array<size_t, 3> pixels_; //!< Plot size in pixels
158
  bool slice_color_overlaps_; //!< Show overlapping cells?
159
  int slice_level_ {-1};      //!< Plot universe level
160
private:
161
};
162

163
template<class T>
164
T SlicePlotBase::get_map() const
165
{
166

167
  size_t width = pixels_[0];
168
  size_t height = pixels_[1];
169

170
  // get pixel size
171
  double in_pixel = (width_[0]) / static_cast<double>(width);
172
  double out_pixel = (width_[1]) / static_cast<double>(height);
173

174
  // size data array
175
  T data(width, height);
176

177
  // setup basis indices and initial position centered on pixel
178
  int in_i, out_i;
179
  Position xyz = origin_;
180
  switch (basis_) {
181
  case PlotBasis::xy:
182
    in_i = 0;
183
    out_i = 1;
184
    break;
185
  case PlotBasis::xz:
186
    in_i = 0;
187
    out_i = 2;
188
    break;
189
  case PlotBasis::yz:
190
    in_i = 1;
191
    out_i = 2;
192
    break;
193
  default:
194
    UNREACHABLE();
195
  }
196

197
  // set initial position
198
  xyz[in_i] = origin_[in_i] - width_[0] / 2. + in_pixel / 2.;
199
  xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.;
200

201
  // arbitrary direction
202
  Direction dir = {0.7071, 0.7071, 0.0};
203

204
#pragma omp parallel
205
  {
206
    Particle p;
207
    p.r() = xyz;
208
    p.u() = dir;
209
    p.coord(0).universe = model::root_universe;
210
    int level = slice_level_;
211
    int j {};
212

213
#pragma omp for
214
    for (int y = 0; y < height; y++) {
215
      p.r()[out_i] = xyz[out_i] - out_pixel * y;
216
      for (int x = 0; x < width; x++) {
217
        p.r()[in_i] = xyz[in_i] + in_pixel * x;
218
        p.n_coord() = 1;
219
        // local variables
220
        bool found_cell = exhaustive_find_cell(p);
221
        j = p.n_coord() - 1;
222
        if (level >= 0) {
223
          j = level;
224
        }
225
        if (found_cell) {
226
          data.set_value(y, x, p, j);
227
        }
228
        if (slice_color_overlaps_ && check_cell_overlap(p, false)) {
229
          data.set_overlap(y, x);
230
        }
231
      } // inner for
232
    }   // outer for
233
  }     // omp parallel
234

235
  return data;
236
}
237

238
// Represents either a voxel or pixel plot
239
class Plot : public PlottableInterface, public SlicePlotBase {
240

241
public:
242
  enum class PlotType { slice = 1, voxel = 2 };
243

244
  Plot(pugi::xml_node plot, PlotType type);
245

246
private:
247
  void set_output_path(pugi::xml_node plot_node);
248
  void set_basis(pugi::xml_node plot_node);
249
  void set_origin(pugi::xml_node plot_node);
250
  void set_width(pugi::xml_node plot_node);
251
  void set_meshlines(pugi::xml_node plot_node);
252

253
public:
254
  // Add mesh lines to ImageData
255
  void draw_mesh_lines(ImageData& data) const;
256
  void create_image() const;
257
  void create_voxel() const;
258

259
  virtual void create_output() const;
260
  virtual void print_info() const;
261

262
  PlotType type_;                 //!< Plot type (Slice/Voxel)
263
  int meshlines_width_;           //!< Width of lines added to the plot
264
  int index_meshlines_mesh_ {-1}; //!< Index of the mesh to draw on the plot
265
  RGBColor meshlines_color_;      //!< Color of meshlines on the plot
266
};
267

268
class ProjectionPlot : public PlottableInterface {
269

270
public:
271
  ProjectionPlot(pugi::xml_node plot);
272

273
  virtual void create_output() const;
274
  virtual void print_info() const;
275

276
private:
277
  void set_output_path(pugi::xml_node plot_node);
278
  void set_look_at(pugi::xml_node node);
279
  void set_camera_position(pugi::xml_node node);
280
  void set_field_of_view(pugi::xml_node node);
281
  void set_pixels(pugi::xml_node node);
282
  void set_opacities(pugi::xml_node node);
283
  void set_orthographic_width(pugi::xml_node node);
284
  void set_wireframe_thickness(pugi::xml_node node);
285
  void set_wireframe_ids(pugi::xml_node node);
286
  void set_wireframe_color(pugi::xml_node node);
287

288
  /* If starting the particle from outside the geometry, we have to
289
   * find a distance to the boundary in a non-standard surface intersection
290
   * check. It's an exhaustive search over surfaces in the top-level universe.
291
   */
292
  static int advance_to_boundary_from_void(Particle& p);
293

294
  /* Checks if a vector of two TrackSegments is equivalent. We define this
295
   * to mean not having matching intersection lengths, but rather having
296
   * a matching sequence of surface/cell/material intersections.
297
   */
298
  struct TrackSegment;
299
  bool trackstack_equivalent(const vector<TrackSegment>& track1,
300
    const vector<TrackSegment>& track2) const;
301

302
  /* Used for drawing wireframe and colors. We record the list of
303
   * surface/cell/material intersections and the corresponding lengths as a ray
304
   * traverses the geometry, then color by iterating in reverse.
305
   */
306
  struct TrackSegment {
307
    int id;        // material or cell ID (which is being colored)
308
    double length; // length of this track intersection
309

310
    /* Recording this allows us to draw edges on the wireframe. For instance
311
     * if two surfaces bound a single cell, it allows drawing that sharp edge
312
     * where the surfaces intersect.
313
     */
314
    int surface; // last surface ID intersected in this segment
315
    TrackSegment(int id_a, double length_a, int surface_a)
316
      : id(id_a), length(length_a), surface(surface_a)
317
    {}
318
  };
319

320
  // Max intersections before we assume ray tracing is caught in an infinite
321
  // loop:
322
  static const int MAX_INTERSECTIONS = 1000000;
323

324
  std::array<int, 2> pixels_;       // pixel dimension of resulting image
325
  double horizontal_field_of_view_ {70.0}; // horiz. f.o.v. in degrees
326
  Position camera_position_;        // where camera is
327
  Position look_at_;                // point camera is centered looking at
328
  Direction up_ {0.0, 0.0, 1.0};    // which way is up
329

330
  // which color IDs should be wireframed. If empty, all cells are wireframed.
331
  vector<int> wireframe_ids_;
332

333
  /* The horizontal thickness, if using an orthographic projection.
334
   * If set to zero, we assume using a perspective projection.
335
   */
336
  double orthographic_width_ {0.0};
337

338
  // Thickness of the wireframe lines. Can set to zero for no wireframe.
339
  int wireframe_thickness_ {1};
340

341
  RGBColor wireframe_color_ {BLACK}; // wireframe color
342
  vector<double> xs_; // macro cross section values for cell volume rendering
343
};
344

345
//===============================================================================
346
// Non-member functions
347
//===============================================================================
348

349
/* Write a PPM image
350
 * filename - name of output file
351
 * data - image data to write
352
 */
353
void output_ppm(const std::string& filename, const ImageData& data);
354

355
#ifdef USE_LIBPNG
356
/* Write a PNG image
357
 * filename - name of output file
358
 * data - image data to write
359
 */
360
void output_png(const std::string& filename, const ImageData& data);
361
#endif
362

363
//! Initialize a voxel file
364
//! \param[in] id of an open hdf5 file
365
//! \param[in] dimensions of the voxel file (dx, dy, dz)
366
//! \param[out] dataspace pointer to voxel data
367
//! \param[out] dataset pointer to voxesl data
368
//! \param[out] pointer to memory space of voxel data
369
void voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, hid_t* dset,
370
  hid_t* memspace);
371

372
//! Write a section of the voxel data to hdf5
373
//! \param[in] voxel slice
374
//! \param[out] dataspace pointer to voxel data
375
//! \param[out] dataset pointer to voxesl data
376
//! \param[out] pointer to data to write
377
void voxel_write_slice(
378
  int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf);
379

380
//! Close voxel file entities
381
//! \param[in] data space to close
382
//! \param[in] dataset to close
383
//! \param[in] memory space to close
384
void voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace);
385

386
//===============================================================================
387
// External functions
388
//===============================================================================
389

390
//! Read plot specifications from a plots.xml file
391
void read_plots_xml();
392

393
//! Read plot specifications from an XML Node
394
//! \param[in] XML node containing plot info
395
void read_plots_xml(pugi::xml_node root);
396

397
//! Clear memory
398
void free_memory_plot();
399

400
//! Create a randomly generated RGB color
401
//! \return RGBColor with random value
402
RGBColor random_color();
403

404
} // namespace openmc
405
#endif // OPENMC_PLOT_H
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc