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

openmc-dev / openmc / 22070080915

16 Feb 2026 04:15PM UTC coverage: 81.702% (-0.02%) from 81.72%
22070080915

Pull #3806

github

web-flow
Merge 4824efac8 into c6ef84d1d
Pull Request #3806: Introduce new C API function for slice plots

17579 of 24709 branches covered (71.14%)

Branch coverage included in aggregate %.

197 of 245 new or added lines in 4 files covered. (80.41%)

336 existing lines in 26 files now uncovered.

57190 of 66805 relevant lines covered (85.61%)

50553675.8 hits per line

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

87.28
/openmc/lib/plot.py
1
from collections.abc import Mapping
10✔
2
from ctypes import (c_bool, c_int, c_size_t, c_int32,
10✔
3
                    c_double, c_uint8, Structure, POINTER)
4
from weakref import WeakValueDictionary
10✔
5

6
from ..exceptions import AllocationError, InvalidIDError
10✔
7
from . import _dll
10✔
8
from .core import _FortranObjectWithID
10✔
9
from .error import _error_handler
10✔
10

11
import numpy as np
10✔
12

13

14
class _Position(Structure):
10✔
15
    """Definition of an xyz location in space with underlying c-types
16

17
    C-type Attributes
18
    -----------------
19
    x : c_double
20
        Position's x value (default: 0.0)
21
    y : c_double
22
        Position's y value (default: 0.0)
23
    z : c_double
24
        Position's z value (default: 0.0)
25
    """
26
    _fields_ = [('x', c_double),
10✔
27
                ('y', c_double),
28
                ('z', c_double)]
29

30
    def __getitem__(self, idx):
10✔
31
        if idx == 0:
10✔
32
            return self.x
10✔
33
        elif idx == 1:
10✔
34
            return self.y
10✔
35
        elif idx == 2:
10✔
36
            return self.z
10✔
37
        else:
38
            raise IndexError(f"{idx} index is invalid for _Position")
10✔
39

40
    def __setitem__(self, idx, val):
10✔
41
        if idx == 0:
10✔
42
            self.x = val
10✔
43
        elif idx == 1:
10✔
44
            self.y = val
10✔
45
        elif idx == 2:
10✔
46
            self.z = val
10✔
47
        else:
48
            raise IndexError(f"{idx} index is invalid for _Position")
×
49

50
    def __repr__(self):
10✔
51
        return f"({self.x}, {self.y}, {self.z})"
×
52

53

54
class _PlotBase(Structure):
10✔
55
    """A structure defining a 2-D geometry slice with underlying c-types
56

57
    C-Type Attributes
58
    -----------------
59
    origin_ : openmc.lib.plot._Position
60
        A position defining the origin of the plot.
61
    u_span_ : openmc.lib.plot._Position
62
        Full-width span vector defining the plot's horizontal axis.
63
    v_span_ : openmc.lib.plot._Position
64
        Full-height span vector defining the plot's vertical axis.
65
    width_ : openmc.lib.plot._Position
66
        The width of the plot along the x, y, and z axes, respectively
67
    basis_ : c_int
68
        The axes basis of the plot view.
69
    pixels_ : c_size_t[3]
70
        The resolution of the plot in the horizontal and vertical dimensions
71
    color_overlaps_ : c_bool
72
        Whether to assign unique IDs (-3) to overlapping regions.
73
    level_ : c_int
74
        The universe level for the plot view
75

76
    Attributes
77
    ----------
78
    origin : tuple or list of ndarray
79
        Origin (center) of the plot
80
    width : float
81
        The horizontal dimension of the plot in geometry units (cm)
82
    height : float
83
        The vertical dimension of the plot in geometry units (cm)
84
    basis : string
85
        One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical
86
        axes of the plot.
87
    h_res : int
88
        The horizontal resolution of the plot in pixels
89
    v_res : int
90
        The vertical resolution of the plot in pixels
91
    level : int
92
        The universe level for the plot (default: -1 -> all universes shown)
93
    """
94
    _fields_ = [('origin_', _Position),
10✔
95
                ('u_span_', _Position),
96
                ('v_span_', _Position),
97
                ('width_', _Position),
98
                ('basis_', c_int),
99
                ('pixels_', 3*c_size_t),
100
                ('color_overlaps_', c_bool),
101
                ('level_', c_int)]
102

103
    def __init__(self):
10✔
104
        self.level_ = -1
10✔
105
        self.basis_ = 1
10✔
106
        self.color_overlaps_ = False
10✔
107
        self._update_spans()
10✔
108

109
    def _update_spans(self):
10✔
110
        if self.basis_ == 1:
10✔
111
            self.u_span_.x = self.width_.x
10✔
112
            self.u_span_.y = 0.0
10✔
113
            self.u_span_.z = 0.0
10✔
114
            self.v_span_.x = 0.0
10✔
115
            self.v_span_.y = self.width_.y
10✔
116
            self.v_span_.z = 0.0
10✔
117
        elif self.basis_ == 2:
10✔
118
            self.u_span_.x = self.width_.x
10✔
119
            self.u_span_.y = 0.0
10✔
120
            self.u_span_.z = 0.0
10✔
121
            self.v_span_.x = 0.0
10✔
122
            self.v_span_.y = 0.0
10✔
123
            self.v_span_.z = self.width_.y
10✔
124
        elif self.basis_ == 3:
10✔
125
            self.u_span_.x = 0.0
10✔
126
            self.u_span_.y = self.width_.x
10✔
127
            self.u_span_.z = 0.0
10✔
128
            self.v_span_.x = 0.0
10✔
129
            self.v_span_.y = 0.0
10✔
130
            self.v_span_.z = self.width_.y
10✔
131

132
    @property
10✔
133
    def origin(self):
10✔
134
        return self.origin_
×
135

136
    @origin.setter
10✔
137
    def origin(self, origin):
10✔
138
        self.origin_.x = origin[0]
10✔
139
        self.origin_.y = origin[1]
10✔
140
        self.origin_.z = origin[2]
10✔
141

142
    @property
10✔
143
    def width(self):
10✔
144
        return self.width_.x
×
145

146
    @width.setter
10✔
147
    def width(self, width):
10✔
148
        self.width_.x = width
10✔
149
        self._update_spans()
10✔
150

151
    @property
10✔
152
    def height(self):
10✔
153
        return self.width_.y
×
154

155
    @height.setter
10✔
156
    def height(self, height):
10✔
157
        self.width_.y = height
10✔
158
        self._update_spans()
10✔
159

160
    @property
10✔
161
    def basis(self):
10✔
162
        if self.basis_ == 1:
×
163
            return 'xy'
×
164
        elif self.basis_ == 2:
×
165
            return 'xz'
×
166
        elif self.basis_ == 3:
×
167
            return 'yz'
×
168

169
        raise ValueError(f"Plot basis {self.basis_} is invalid")
×
170

171
    @basis.setter
10✔
172
    def basis(self, basis):
10✔
173
        if isinstance(basis, str):
10✔
174
            valid_bases = ('xy', 'xz', 'yz')
10✔
175
            basis = basis.lower()
10✔
176
            if basis not in valid_bases:
10✔
177
                raise ValueError(f"{basis} is not a valid plot basis.")
×
178

179
            if basis == 'xy':
10✔
180
                self.basis_ = 1
10✔
181
            elif basis == 'xz':
10✔
182
                self.basis_ = 2
10✔
183
            elif basis == 'yz':
10✔
184
                self.basis_ = 3
10✔
185
            self._update_spans()
10✔
186
            return
10✔
187

188
        if isinstance(basis, int):
×
189
            valid_bases = (1, 2, 3)
×
190
            if basis not in valid_bases:
×
191
                raise ValueError(f"{basis} is not a valid plot basis.")
×
192
            self.basis_ = basis
×
NEW
193
            self._update_spans()
×
UNCOV
194
            return
×
195

196
        raise ValueError(f"{basis} of type {type(basis)} is an invalid plot basis")
×
197

198
    @property
10✔
199
    def h_res(self):
10✔
200
        return self.pixels_[0]
10✔
201

202
    @h_res.setter
10✔
203
    def h_res(self, h_res):
10✔
204
        self.pixels_[0] = h_res
10✔
205

206
    @property
10✔
207
    def v_res(self):
10✔
208
        return self.pixels_[1]
10✔
209

210
    @v_res.setter
10✔
211
    def v_res(self, v_res):
10✔
212
        self.pixels_[1] = v_res
10✔
213

214
    @property
10✔
215
    def level(self):
10✔
216
        return int(self.level_)
×
217

218
    @level.setter
10✔
219
    def level(self, level):
10✔
220
        self.level_ = level
10✔
221

222
    @property
10✔
223
    def color_overlaps(self):
10✔
224
        return self.color_overlaps_
×
225

226
    @color_overlaps.setter
10✔
227
    def color_overlaps(self, color_overlaps):
10✔
228
        self.color_overlaps_ = color_overlaps
10✔
229

230
    def __repr__(self):
10✔
231
        out_str = ["-----",
×
232
                   "Plot:",
233
                   "-----",
234
                   f"Origin: {self.origin}",
235
                   f"Width: {self.width}",
236
                   f"Height: {self.height}",
237
                   f"Basis: {self.basis}",
238
                   f"HRes: {self.h_res}",
239
                   f"VRes: {self.v_res}",
240
                   f"Color Overlaps: {self.color_overlaps}",
241
                   f"Level: {self.level}"]
242
        return '\n'.join(out_str)
×
243

244

245
_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_int32)]
10✔
246
_dll.openmc_id_map.restype = c_int
10✔
247
_dll.openmc_id_map.errcheck = _error_handler
10✔
248

249

250
def id_map(plot):
10✔
251
    """
252
    Generate a 2-D map of cell and material IDs. Used for in-memory image
253
    generation.
254

255
    Parameters
256
    ----------
257
    plot : openmc.lib.plot._PlotBase
258
        Object describing the slice of the model to be generated
259

260
    Returns
261
    -------
262
    id_map : numpy.ndarray
263
        A NumPy array with shape (vertical pixels, horizontal pixels, 3) of
264
        OpenMC property ids with dtype int32. The last dimension of the array
265
        contains, in order, cell IDs, cell instances, and material IDs.
266

267
    """
268
    img_data = np.zeros((plot.v_res, plot.h_res, 3), dtype=np.int32)
10✔
269
    _dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32)))
10✔
270
    return img_data
10✔
271

272

273
_dll.openmc_property_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)]
10✔
274
_dll.openmc_property_map.restype = c_int
10✔
275
_dll.openmc_property_map.errcheck = _error_handler
10✔
276

277

278
def property_map(plot):
10✔
279
    """
280
    Generate a 2-D map of cell temperatures and material densities. Used for
281
    in-memory image generation.
282

283
    Parameters
284
    ----------
285
    plot : openmc.lib.plot._PlotBase
286
        Object describing the slice of the model to be generated
287

288
    Returns
289
    -------
290
    property_map : numpy.ndarray
291
        A NumPy array with shape (vertical pixels, horizontal pixels, 2) of
292
        OpenMC property ids with dtype float
293

294
    """
295
    prop_data = np.zeros((plot.v_res, plot.h_res, 2))
10✔
296
    _dll.openmc_property_map(plot, prop_data.ctypes.data_as(POINTER(c_double)))
10✔
297
    return prop_data
10✔
298

299

300
_dll.openmc_slice_plot.argtypes = [
10✔
301
    POINTER(c_double * 3),   # origin
302
    POINTER(c_double * 3),   # u_span
303
    POINTER(c_double * 3),   # v_span
304
    POINTER(c_size_t * 2),   # pixels
305
    c_bool,                  # color_overlaps
306
    c_int,                   # level
307
    c_int32,                 # filter_index
308
    POINTER(c_int32),        # geom_data
309
    POINTER(c_double),       # property_data (can be None)
310
]
311
_dll.openmc_slice_plot.restype = c_int
10✔
312
_dll.openmc_slice_plot.errcheck = _error_handler
10✔
313

314

315
def slice_plot(origin, width=None, basis='xy', u_span=None, v_span=None,
10✔
316
                pixels=None, color_overlaps=False, level=-1, filter=None,
317
                include_properties=True):
318
    """Generate a 2D raster of geometry and property data for plotting.
319

320
    Parameters
321
    ----------
322
    origin : sequence of float
323
        Center position of the plot [x, y, z]
324
    width : sequence of float
325
        Width of the plot [horizontal, vertical]. Mutually exclusive with
326
        u_span/v_span.
327
    basis : {'xy', 'xz', 'yz'} or int
328
        Plot basis. Ignored if u_span/v_span are provided.
329
    u_span : sequence of float, optional
330
        Full-width span vector for the horizontal axis (3 values). Mutually
331
        exclusive with width.
332
    v_span : sequence of float, optional
333
        Full-height span vector for the vertical axis (3 values). Mutually
334
        exclusive with width.
335
    pixels : sequence of int
336
        Number of pixels [horizontal, vertical]
337
    color_overlaps : bool, optional
338
        Whether to detect overlapping cells
339
    level : int, optional
340
        Universe level (-1 for deepest)
341
    filter : openmc.lib.Filter, optional
342
        Filter for bin index lookup
343
    include_properties : bool, optional
344
        Whether to compute temperature/density
345
    Returns
346
    -------
347
    geom_data : numpy.ndarray
348
        Array of shape (v_res, h_res, 3) or (v_res, h_res, 4) with int32 dtype.
349
        Contains [cell_id, cell_instance, material_id] when no filter is provided,
350
        or [cell_id, cell_instance, material_id, filter_bin] when a filter is provided.
351
    property_data : numpy.ndarray or None
352
        Array of shape (v_res, h_res, 2) with float64 dtype containing
353
        [temperature, density], or None if include_properties=False
354
    """
355
    if pixels is None:
10✔
NEW
356
        raise ValueError("pixels must be specified.")
×
357
    if len(pixels) != 2:
10✔
NEW
358
        raise ValueError("pixels must be a length-2 sequence.")
×
359

360
    if width is not None and (u_span is not None or v_span is not None):
10✔
NEW
361
        raise ValueError("width is mutually exclusive with u_span/v_span.")
×
362

363
    if u_span is not None or v_span is not None:
10✔
364
        if u_span is None or v_span is None:
10✔
NEW
365
            raise ValueError("Both u_span and v_span must be provided.")
×
366
        u_span = np.asarray(u_span, dtype=float)
10✔
367
        v_span = np.asarray(v_span, dtype=float)
10✔
368
        if u_span.shape != (3,) or v_span.shape != (3,):
10✔
NEW
369
            raise ValueError("u_span and v_span must be length-3 sequences.")
×
370
        u_norm = np.linalg.norm(u_span)
10✔
371
        v_norm = np.linalg.norm(v_span)
10✔
372
        if u_norm == 0.0 or v_norm == 0.0:
10✔
NEW
373
            raise ValueError("u_span and v_span must be non-zero vectors.")
×
374
        dot = float(np.dot(u_span, v_span))
10✔
375
        ortho_tol = 1.0e-10 * u_norm * v_norm
10✔
376
        if abs(dot) > ortho_tol:
10✔
NEW
377
            raise ValueError("u_span and v_span must be orthogonal.")
×
378
    else:
379
        if width is None:
10✔
NEW
380
            raise ValueError("width must be provided when u_span/v_span are not set.")
×
381
        if len(width) != 2:
10✔
NEW
382
            raise ValueError("width must be a length-2 sequence.")
×
383
        basis_map = {'xy': 1, 'xz': 2, 'yz': 3}
10✔
384
        if isinstance(basis, str):
10✔
385
            basis = basis.lower()
10✔
386
            if basis not in basis_map:
10✔
NEW
387
                raise ValueError(f"{basis} is not a valid plot basis.")
×
388
            basis = basis_map[basis]
10✔
NEW
389
        elif isinstance(basis, int):
×
NEW
390
            if basis not in basis_map.values():
×
NEW
391
                raise ValueError(f"{basis} is not a valid plot basis.")
×
392
        else:
NEW
393
            raise ValueError(f"{basis} is not a valid plot basis.")
×
394

395
        if basis == 1:
10✔
396
            u_span = np.array([width[0], 0.0, 0.0], dtype=float)
10✔
397
            v_span = np.array([0.0, width[1], 0.0], dtype=float)
10✔
398
        elif basis == 2:
10✔
399
            u_span = np.array([width[0], 0.0, 0.0], dtype=float)
10✔
400
            v_span = np.array([0.0, 0.0, width[1]], dtype=float)
10✔
401
        else:
402
            u_span = np.array([0.0, width[0], 0.0], dtype=float)
10✔
403
            v_span = np.array([0.0, 0.0, width[1]], dtype=float)
10✔
404

405
    origin = np.asarray(origin, dtype=float)
10✔
406
    if origin.shape != (3,):
10✔
NEW
407
        raise ValueError("origin must be a length-3 sequence.")
×
408

409
    # Prepare ctypes arrays
410
    origin_arr = (c_double * 3)(*origin)
10✔
411
    u_span_arr = (c_double * 3)(*u_span)
10✔
412
    v_span_arr = (c_double * 3)(*v_span)
10✔
413
    pixels_arr = (c_size_t * 2)(*pixels)
10✔
414

415
    # Get internal filter index from filter ID if filter is provided
416
    if filter is not None:
10✔
417
        filter_index = c_int32()
10✔
418
        _dll.openmc_get_filter_index(filter.id, filter_index)
10✔
419
        filter_index = filter_index.value
10✔
420
    else:
421
        filter_index = -1
10✔
422

423
    # Allocate output arrays with dynamic size based on filter
424
    n_geom_fields = 4 if filter is not None else 3
10✔
425
    geom_data = np.zeros((pixels[1], pixels[0], n_geom_fields), dtype=np.int32)
10✔
426
    if include_properties:
10✔
427
        property_data = np.zeros((pixels[1], pixels[0], 2), dtype=np.float64)
10✔
428
        prop_ptr = property_data.ctypes.data_as(POINTER(c_double))
10✔
429
    else:
430
        property_data = None
10✔
431
        prop_ptr = None
10✔
432

433
    _dll.openmc_slice_plot(
10✔
434
        origin_arr,
435
        u_span_arr,
436
        v_span_arr,
437
        pixels_arr,
438
        color_overlaps,
439
        level,
440
        filter_index,
441
        geom_data.ctypes.data_as(POINTER(c_int32)),
442
        prop_ptr
443
    )
444

445
    return geom_data, property_data
10✔
446

447

448
_dll.openmc_get_plot_index.argtypes = [c_int32, POINTER(c_int32)]
10✔
449
_dll.openmc_get_plot_index.restype = c_int
10✔
450
_dll.openmc_get_plot_index.errcheck = _error_handler
10✔
451

452
_dll.openmc_plot_get_id.argtypes = [c_int32, POINTER(c_int32)]
10✔
453
_dll.openmc_plot_get_id.restype = c_int
10✔
454
_dll.openmc_plot_get_id.errcheck = _error_handler
10✔
455

456
_dll.openmc_plot_set_id.argtypes = [c_int32, c_int32]
10✔
457
_dll.openmc_plot_set_id.restype = c_int
10✔
458
_dll.openmc_plot_set_id.errcheck = _error_handler
10✔
459

460
_dll.openmc_plots_size.restype = c_size_t
10✔
461

462
_dll.openmc_solidraytrace_plot_create.argtypes = [POINTER(c_int32)]
10✔
463
_dll.openmc_solidraytrace_plot_create.restype = c_int
10✔
464
_dll.openmc_solidraytrace_plot_create.errcheck = _error_handler
10✔
465

466
_dll.openmc_solidraytrace_plot_get_pixels.argtypes = [
10✔
467
    c_int32, POINTER(c_int32), POINTER(c_int32)]
468
_dll.openmc_solidraytrace_plot_get_pixels.restype = c_int
10✔
469
_dll.openmc_solidraytrace_plot_get_pixels.errcheck = _error_handler
10✔
470

471
_dll.openmc_solidraytrace_plot_set_pixels.argtypes = [c_int32, c_int32, c_int32]
10✔
472
_dll.openmc_solidraytrace_plot_set_pixels.restype = c_int
10✔
473
_dll.openmc_solidraytrace_plot_set_pixels.errcheck = _error_handler
10✔
474

475
_dll.openmc_solidraytrace_plot_get_color_by.argtypes = [c_int32, POINTER(c_int32)]
10✔
476
_dll.openmc_solidraytrace_plot_get_color_by.restype = c_int
10✔
477
_dll.openmc_solidraytrace_plot_get_color_by.errcheck = _error_handler
10✔
478

479
_dll.openmc_solidraytrace_plot_set_color_by.argtypes = [c_int32, c_int32]
10✔
480
_dll.openmc_solidraytrace_plot_set_color_by.restype = c_int
10✔
481
_dll.openmc_solidraytrace_plot_set_color_by.errcheck = _error_handler
10✔
482

483
_dll.openmc_solidraytrace_plot_set_default_colors.argtypes = [c_int32]
10✔
484
_dll.openmc_solidraytrace_plot_set_default_colors.restype = c_int
10✔
485
_dll.openmc_solidraytrace_plot_set_default_colors.errcheck = _error_handler
10✔
486

487
_dll.openmc_solidraytrace_plot_set_all_opaque.argtypes = [c_int32]
10✔
488
_dll.openmc_solidraytrace_plot_set_all_opaque.restype = c_int
10✔
489
_dll.openmc_solidraytrace_plot_set_all_opaque.errcheck = _error_handler
10✔
490

491
_dll.openmc_solidraytrace_plot_set_opaque.argtypes = [c_int32, c_int32, c_bool]
10✔
492
_dll.openmc_solidraytrace_plot_set_opaque.restype = c_int
10✔
493
_dll.openmc_solidraytrace_plot_set_opaque.errcheck = _error_handler
10✔
494

495
_dll.openmc_solidraytrace_plot_set_color.argtypes = [c_int32, c_int32, c_uint8, c_uint8, c_uint8]
10✔
496
_dll.openmc_solidraytrace_plot_set_color.restype = c_int
10✔
497
_dll.openmc_solidraytrace_plot_set_color.errcheck = _error_handler
10✔
498

499
_dll.openmc_solidraytrace_plot_get_camera_position.argtypes = [
10✔
500
    c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)]
501
_dll.openmc_solidraytrace_plot_get_camera_position.restype = c_int
10✔
502
_dll.openmc_solidraytrace_plot_get_camera_position.errcheck = _error_handler
10✔
503

504
_dll.openmc_solidraytrace_plot_set_camera_position.argtypes = [c_int32, c_double, c_double, c_double]
10✔
505
_dll.openmc_solidraytrace_plot_set_camera_position.restype = c_int
10✔
506
_dll.openmc_solidraytrace_plot_set_camera_position.errcheck = _error_handler
10✔
507

508
_dll.openmc_solidraytrace_plot_get_look_at.argtypes = [
10✔
509
    c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)]
510
_dll.openmc_solidraytrace_plot_get_look_at.restype = c_int
10✔
511
_dll.openmc_solidraytrace_plot_get_look_at.errcheck = _error_handler
10✔
512

513
_dll.openmc_solidraytrace_plot_set_look_at.argtypes = [c_int32, c_double, c_double, c_double]
10✔
514
_dll.openmc_solidraytrace_plot_set_look_at.restype = c_int
10✔
515
_dll.openmc_solidraytrace_plot_set_look_at.errcheck = _error_handler
10✔
516

517
_dll.openmc_solidraytrace_plot_get_up.argtypes = [
10✔
518
    c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)]
519
_dll.openmc_solidraytrace_plot_get_up.restype = c_int
10✔
520
_dll.openmc_solidraytrace_plot_get_up.errcheck = _error_handler
10✔
521

522
_dll.openmc_solidraytrace_plot_set_up.argtypes = [c_int32, c_double, c_double, c_double]
10✔
523
_dll.openmc_solidraytrace_plot_set_up.restype = c_int
10✔
524
_dll.openmc_solidraytrace_plot_set_up.errcheck = _error_handler
10✔
525

526
_dll.openmc_solidraytrace_plot_get_light_position.argtypes = [
10✔
527
    c_int32, POINTER(c_double), POINTER(c_double), POINTER(c_double)]
528
_dll.openmc_solidraytrace_plot_get_light_position.restype = c_int
10✔
529
_dll.openmc_solidraytrace_plot_get_light_position.errcheck = _error_handler
10✔
530

531
_dll.openmc_solidraytrace_plot_set_light_position.argtypes = [c_int32, c_double, c_double, c_double]
10✔
532
_dll.openmc_solidraytrace_plot_set_light_position.restype = c_int
10✔
533
_dll.openmc_solidraytrace_plot_set_light_position.errcheck = _error_handler
10✔
534

535
_dll.openmc_solidraytrace_plot_get_fov.argtypes = [c_int32, POINTER(c_double)]
10✔
536
_dll.openmc_solidraytrace_plot_get_fov.restype = c_int
10✔
537
_dll.openmc_solidraytrace_plot_get_fov.errcheck = _error_handler
10✔
538

539
_dll.openmc_solidraytrace_plot_set_fov.argtypes = [c_int32, c_double]
10✔
540
_dll.openmc_solidraytrace_plot_set_fov.restype = c_int
10✔
541
_dll.openmc_solidraytrace_plot_set_fov.errcheck = _error_handler
10✔
542

543
_dll.openmc_solidraytrace_plot_update_view.argtypes = [c_int32]
10✔
544
_dll.openmc_solidraytrace_plot_update_view.restype = c_int
10✔
545
_dll.openmc_solidraytrace_plot_update_view.errcheck = _error_handler
10✔
546

547
_dll.openmc_solidraytrace_plot_create_image.argtypes = [c_int32, POINTER(c_uint8), c_int32, c_int32]
10✔
548
_dll.openmc_solidraytrace_plot_create_image.restype = c_int
10✔
549
_dll.openmc_solidraytrace_plot_create_image.errcheck = _error_handler
10✔
550

551
_dll.openmc_solidraytrace_plot_get_color.argtypes = [c_int32, c_int32,
10✔
552
                                             POINTER(c_uint8), POINTER(c_uint8), POINTER(c_uint8)]
553
_dll.openmc_solidraytrace_plot_get_color.restype = c_int
10✔
554
_dll.openmc_solidraytrace_plot_get_color.errcheck = _error_handler
10✔
555

556
_dll.openmc_solidraytrace_plot_get_diffuse_fraction.argtypes = [
10✔
557
    c_int32, POINTER(c_double)]
558
_dll.openmc_solidraytrace_plot_get_diffuse_fraction.restype = c_int
10✔
559
_dll.openmc_solidraytrace_plot_get_diffuse_fraction.errcheck = _error_handler
10✔
560

561
_dll.openmc_solidraytrace_plot_set_diffuse_fraction.argtypes = [c_int32, c_double]
10✔
562
_dll.openmc_solidraytrace_plot_set_diffuse_fraction.restype = c_int
10✔
563
_dll.openmc_solidraytrace_plot_set_diffuse_fraction.errcheck = _error_handler
10✔
564

565

566
class SolidRayTracePlot(_FortranObjectWithID):
10✔
567
    """Solid ray-traced plot stored internally.
568

569
    This class exposes a solid ray-traced plot that is stored internally in
570
    the OpenMC library. To obtain a view of an existing plot with a given ID,
571
    use the :data:`openmc.lib.plots` mapping.
572

573
    Parameters
574
    ----------
575
    uid : int or None
576
        Unique ID of the plot
577
    new : bool
578
        When `index` is None, this argument controls whether a new object is
579
        created or a view of an existing object is returned.
580
    index : int or None
581
        Index in the internal plots array.
582

583
    Attributes
584
    ----------
585
    id : int
586
        Unique ID of the plot.
587
    pixels : tuple of int
588
        Plot image dimensions as ``(width, height)``.
589
    color_by : int
590
        Coloring mode. Use :attr:`COLOR_BY_MATERIAL` or
591
        :attr:`COLOR_BY_CELL`.
592
    camera_position : tuple of float
593
        Camera position as ``(x, y, z)``.
594
    look_at : tuple of float
595
        Point the camera is aimed at as ``(x, y, z)``.
596
    up : tuple of float
597
        Up direction as ``(x, y, z)``.
598
    light_position : tuple of float
599
        Position of the light source as ``(x, y, z)``.
600
    fov : float
601
        Horizontal field-of-view angle in degrees.
602
    diffuse_fraction : float
603
        Fraction of reflected light treated as diffuse (0 to 1).
604
    """
605

606
    COLOR_BY_MATERIAL = 0
10✔
607
    COLOR_BY_CELL = 1
10✔
608
    __instances = WeakValueDictionary()
10✔
609

610
    def __new__(cls, uid=None, new=True, index=None):
10✔
611
        mapping = plots
10✔
612
        if index is None:
10✔
613
            if new:
10✔
614
                if uid is not None and uid in mapping:
10✔
615
                    raise AllocationError(
×
616
                        f'A plot with ID={uid} has already been allocated.'
617
                    )
618
                index = c_int32()
10✔
619
                _dll.openmc_solidraytrace_plot_create(index)
10✔
620
                index = index.value
10✔
621
            else:
622
                index = mapping[uid]._index
×
623

624
        if index not in cls.__instances:
10✔
625
            instance = super().__new__(cls)
10✔
626
            instance._index = index
10✔
627
            if uid is not None:
10✔
628
                instance.id = uid
×
629
            cls.__instances[index] = instance
10✔
630

631
        return cls.__instances[index]
10✔
632

633
    def __init__(self, uid=None, new=True, index=None):
10✔
634
        super().__init__(uid, new, index)
10✔
635

636
    @property
10✔
637
    def id(self):
10✔
638
        plot_id = c_int32()
10✔
639
        _dll.openmc_plot_get_id(self._index, plot_id)
10✔
640
        return plot_id.value
10✔
641

642
    @id.setter
10✔
643
    def id(self, plot_id):
10✔
644
        _dll.openmc_plot_set_id(self._index, plot_id)
×
645

646
    @staticmethod
10✔
647
    def _get_xyz(getter, index):
10✔
648
        x = c_double()
10✔
649
        y = c_double()
10✔
650
        z = c_double()
10✔
651
        getter(index, x, y, z)
10✔
652
        return (x.value, y.value, z.value)
10✔
653

654
    @staticmethod
10✔
655
    def _set_xyz(setter, index, xyz):
10✔
656
        x, y, z = xyz
10✔
657
        setter(index, float(x), float(y), float(z))
10✔
658

659
    @property
10✔
660
    def pixels(self):
10✔
661
        width = c_int32()
10✔
662
        height = c_int32()
10✔
663
        _dll.openmc_solidraytrace_plot_get_pixels(self._index, width, height)
10✔
664
        return (width.value, height.value)
10✔
665

666
    @pixels.setter
10✔
667
    def pixels(self, pixels):
10✔
668
        width, height = pixels
10✔
669
        _dll.openmc_solidraytrace_plot_set_pixels(
10✔
670
            self._index, int(width), int(height))
671

672
    @property
10✔
673
    def color_by(self):
10✔
674
        color_by = c_int32()
10✔
675
        _dll.openmc_solidraytrace_plot_get_color_by(self._index, color_by)
10✔
676
        return color_by.value
10✔
677

678
    @color_by.setter
10✔
679
    def color_by(self, color_by):
10✔
680
        _dll.openmc_solidraytrace_plot_set_color_by(self._index, int(color_by))
10✔
681

682
    def set_default_colors(self):
10✔
683
        _dll.openmc_solidraytrace_plot_set_default_colors(self._index)
10✔
684

685
    def set_all_opaque(self):
10✔
686
        _dll.openmc_solidraytrace_plot_set_all_opaque(self._index)
×
687

688
    def set_visibility(self, domain_id, visible):
10✔
689
        _dll.openmc_solidraytrace_plot_set_opaque(
10✔
690
            self._index, int(domain_id), bool(visible)
691
        )
692

693
    def set_color(self, domain_id, color):
10✔
694
        r, g, b = [int(c) for c in color]
10✔
695
        _dll.openmc_solidraytrace_plot_set_color(
10✔
696
            self._index, int(domain_id), r, g, b)
697

698
    @property
10✔
699
    def camera_position(self):
10✔
700
        return self._get_xyz(_dll.openmc_solidraytrace_plot_get_camera_position,
10✔
701
                             self._index)
702

703
    @camera_position.setter
10✔
704
    def camera_position(self, position):
10✔
705
        self._set_xyz(_dll.openmc_solidraytrace_plot_set_camera_position,
10✔
706
                      self._index, position)
707

708
    @property
10✔
709
    def look_at(self):
10✔
710
        return self._get_xyz(_dll.openmc_solidraytrace_plot_get_look_at,
10✔
711
                             self._index)
712

713
    @look_at.setter
10✔
714
    def look_at(self, position):
10✔
715
        self._set_xyz(_dll.openmc_solidraytrace_plot_set_look_at,
10✔
716
                      self._index, position)
717

718
    @property
10✔
719
    def up(self):
10✔
720
        return self._get_xyz(_dll.openmc_solidraytrace_plot_get_up, self._index)
10✔
721

722
    @up.setter
10✔
723
    def up(self, direction):
10✔
724
        self._set_xyz(_dll.openmc_solidraytrace_plot_set_up, self._index,
10✔
725
                      direction)
726

727
    @property
10✔
728
    def light_position(self):
10✔
729
        return self._get_xyz(_dll.openmc_solidraytrace_plot_get_light_position,
10✔
730
                             self._index)
731

732
    @light_position.setter
10✔
733
    def light_position(self, position):
10✔
734
        self._set_xyz(_dll.openmc_solidraytrace_plot_set_light_position,
10✔
735
                      self._index, position)
736

737
    @property
10✔
738
    def fov(self):
10✔
739
        fov = c_double()
10✔
740
        _dll.openmc_solidraytrace_plot_get_fov(self._index, fov)
10✔
741
        return fov.value
10✔
742

743
    @fov.setter
10✔
744
    def fov(self, fov):
10✔
745
        _dll.openmc_solidraytrace_plot_set_fov(self._index, float(fov))
10✔
746

747
    def update_view(self):
10✔
748
        _dll.openmc_solidraytrace_plot_update_view(self._index)
10✔
749

750
    def create_image(self):
10✔
751
        width, height = self.pixels
10✔
752
        image = np.zeros((height, width, 3), dtype=np.uint8)
10✔
753
        _dll.openmc_solidraytrace_plot_create_image(
10✔
754
            self._index,
755
            image.ctypes.data_as(POINTER(c_uint8)),
756
            width,
757
            height
758
        )
759
        return image
10✔
760

761
    def get_color(self, domain_id):
10✔
762
        r = c_uint8()
10✔
763
        g = c_uint8()
10✔
764
        b = c_uint8()
10✔
765
        _dll.openmc_solidraytrace_plot_get_color(
10✔
766
            self._index, int(domain_id), r, g, b)
767
        return int(r.value), int(g.value), int(b.value)
10✔
768

769
    @property
10✔
770
    def diffuse_fraction(self):
10✔
771
        value = c_double()
10✔
772
        _dll.openmc_solidraytrace_plot_get_diffuse_fraction(self._index, value)
10✔
773
        return value.value
10✔
774

775
    @diffuse_fraction.setter
10✔
776
    def diffuse_fraction(self, value):
10✔
777
        _dll.openmc_solidraytrace_plot_set_diffuse_fraction(
10✔
778
            self._index, float(value))
779

780
    # Backward-compatible setter aliases
781
    def set_pixels(self, width, height):
10✔
782
        self.pixels = (width, height)
×
783

784
    def set_color_by(self, color_by):
10✔
785
        self.color_by = color_by
×
786

787
    def set_camera_position(self, x, y, z):
10✔
788
        self.camera_position = (x, y, z)
×
789

790
    def set_look_at(self, x, y, z):
10✔
791
        self.look_at = (x, y, z)
×
792

793
    def set_up(self, x, y, z):
10✔
794
        self.up = (x, y, z)
×
795

796
    def set_light_position(self, x, y, z):
10✔
797
        self.light_position = (x, y, z)
×
798

799
    def set_fov(self, fov):
10✔
800
        self.fov = fov
×
801

802
    def set_diffuse_fraction(self, value):
10✔
803
        self.diffuse_fraction = value
×
804

805

806
class _PlotMapping(Mapping):
10✔
807
    def __getitem__(self, key):
10✔
808
        index = c_int32()
10✔
809
        try:
10✔
810
            _dll.openmc_get_plot_index(key, index)
10✔
811
        except (AllocationError, InvalidIDError) as e:
×
812
            raise KeyError(str(e))
×
813
        return SolidRayTracePlot(index=index.value)
10✔
814

815
    def __iter__(self):
10✔
816
        for i in range(len(self)):
×
817
            yield SolidRayTracePlot(index=i).id
×
818

819
    def __len__(self):
10✔
820
        return _dll.openmc_plots_size()
10✔
821

822
    def __repr__(self):
10✔
823
        return repr(dict(self))
×
824

825

826
plots = _PlotMapping()
10✔
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

© 2026 Coveralls, Inc