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

openmc-dev / openmc / 12954288577

24 Jan 2025 05:13PM UTC coverage: 84.833% (-0.1%) from 84.928%
12954288577

Pull #2671

github

web-flow
Merge d2ca87df5 into 560bd22bc
Pull Request #2671: Adding methods to automatically apply results to existing Tally objects.

53 of 65 new or added lines in 7 files covered. (81.54%)

59 existing lines in 20 files now uncovered.

50089 of 59044 relevant lines covered (84.83%)

34992387.74 hits per line

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

81.27
/openmc/statepoint.py
1
from datetime import datetime
12✔
2
import glob
12✔
3
import re
12✔
4
import os
12✔
5
import warnings
12✔
6

7
import h5py
12✔
8
import numpy as np
12✔
9
from uncertainties import ufloat
12✔
10

11
import openmc
12✔
12
import openmc.checkvalue as cv
12✔
13

14
_VERSION_STATEPOINT = 18
12✔
15

16

17
class StatePoint:
12✔
18
    """State information on a simulation at a certain point in time (at the end
19
    of a given batch). Statepoints can be used to analyze tally results as well
20
    as restart a simulation.
21

22
    Parameters
23
    ----------
24
    filepath : str or Path
25
        Path to file to load
26
    autolink : bool, optional
27
        Whether to automatically link in metadata from a summary.h5 file and
28
        stochastic volume calculation results from volume_*.h5 files. Defaults
29
        to True.
30

31
    Attributes
32
    ----------
33
    cmfd_on : bool
34
        Indicate whether CMFD is active
35
    cmfd_balance : numpy.ndarray
36
        Residual neutron balance for each batch
37
    cmfd_dominance
38
        Dominance ratio for each batch
39
    cmfd_entropy : numpy.ndarray
40
        Shannon entropy of CMFD fission source for each batch
41
    cmfd_indices : numpy.ndarray
42
        Number of CMFD mesh cells and energy groups. The first three indices
43
        correspond to the x-, y-, and z- spatial directions and the fourth index
44
        is the number of energy groups.
45
    cmfd_srccmp : numpy.ndarray
46
        Root-mean-square difference between OpenMC and CMFD fission source for
47
        each batch
48
    cmfd_src : numpy.ndarray
49
        CMFD fission source distribution over all mesh cells and energy groups.
50
    current_batch : int
51
        Number of batches simulated
52
    date_and_time : datetime.datetime
53
        Date and time at which statepoint was written
54
    entropy : numpy.ndarray
55
        Shannon entropy of fission source at each batch
56
    filters : dict
57
        Dictionary whose keys are filter IDs and whose values are Filter
58
        objects
59
    generations_per_batch : int
60
        Number of fission generations per batch
61
    global_tallies : numpy.ndarray of compound datatype
62
        Global tallies for k-effective estimates and leakage. The compound
63
        datatype has fields 'name', 'sum', 'sum_sq', 'mean', and 'std_dev'.
64
    k_combined : uncertainties.UFloat
65
        Combined estimator for k-effective
66

67
        .. deprecated:: 0.13.1
68
    k_col_abs : float
69
        Cross-product of collision and absorption estimates of k-effective
70
    k_col_tra : float
71
        Cross-product of collision and tracklength estimates of k-effective
72
    k_abs_tra : float
73
        Cross-product of absorption and tracklength estimates of k-effective
74
    k_generation : numpy.ndarray
75
        Estimate of k-effective for each batch/generation
76
    keff : uncertainties.UFloat
77
        Combined estimator for k-effective
78

79
        .. versionadded:: 0.13.1
80
    meshes : dict
81
        Dictionary whose keys are mesh IDs and whose values are MeshBase objects
82
    n_batches : int
83
        Number of batches
84
    n_inactive : int
85
        Number of inactive batches
86
    n_particles : int
87
        Number of particles per generation
88
    n_realizations : int
89
        Number of tally realizations
90
    path : str
91
        Working directory for simulation
92
    photon_transport : bool
93
        Indicate whether photon transport is active
94
    run_mode : str
95
        Simulation run mode, e.g. 'eigenvalue'
96
    runtime : dict
97
        Dictionary whose keys are strings describing various runtime metrics
98
        and whose values are time values in seconds.
99
    seed : int
100
        Pseudorandom number generator seed
101
    source : numpy.ndarray of compound datatype
102
        Array of source sites. The compound datatype has fields 'r', 'u',
103
        'E', 'wgt', 'delayed_group', 'surf_id', and 'particle', corresponding to
104
        the position, direction, energy, weight, delayed group, surface ID and
105
        particle type of the source site, respectively.
106
    source_present : bool
107
        Indicate whether source sites are present
108
    sparse : bool
109
        Whether or not the tallies uses SciPy's LIL sparse matrix format for
110
        compressed data storage
111
    tallies : dict
112
        Dictionary whose keys are tally IDs and whose values are Tally objects
113
    tallies_present : bool
114
        Indicate whether user-defined tallies are present
115
    tally_derivatives : dict
116
        Dictionary whose keys are tally derivative IDs and whose values are
117
        TallyDerivative objects
118
    version: tuple of Integral
119
        Version of OpenMC
120
    summary : None or openmc.Summary
121
        A summary object if the statepoint has been linked with a summary file
122

123
    """
124

125
    def __init__(self, filepath, autolink=True):
12✔
126
        filename = str(filepath)  # in case it's a Path
12✔
127
        self._f = h5py.File(filename, 'r')
12✔
128
        self._meshes = {}
12✔
129
        self._filters = {}
12✔
130
        self._tallies = {}
12✔
131
        self._derivs = {}
12✔
132

133
        # Check filetype and version
134
        cv.check_filetype_version(self._f, 'statepoint', _VERSION_STATEPOINT)
12✔
135

136
        # Set flags for what data has been read
137
        self._meshes_read = False
12✔
138
        self._filters_read = False
12✔
139
        self._tallies_read = False
12✔
140
        self._summary = None
12✔
141
        self._global_tallies = None
12✔
142
        self._sparse = False
12✔
143
        self._derivs_read = False
12✔
144

145
        # Automatically link in a summary file if one exists
146
        if autolink:
12✔
147
            path_summary = os.path.join(os.path.dirname(filename), 'summary.h5')
12✔
148
            if os.path.exists(path_summary):
12✔
149
                su = openmc.Summary(path_summary)
12✔
150
                self.link_with_summary(su)
12✔
151

152
            path_volume = os.path.join(os.path.dirname(filename), 'volume_*.h5')
12✔
153
            for path_i in glob.glob(path_volume):
12✔
154
                if re.search(r'volume_\d+\.h5', path_i):
×
155
                    vol = openmc.VolumeCalculation.from_hdf5(path_i)
×
156
                    self.add_volume_information(vol)
×
157

158
    def __enter__(self):
12✔
159
        return self
12✔
160

161
    def __exit__(self, *exc):
12✔
162
        self.close()
12✔
163

164
    @property
12✔
165
    def cmfd_on(self):
12✔
166
        return self._f.attrs['cmfd_on'] > 0
×
167

168
    @property
12✔
169
    def cmfd_balance(self):
12✔
170
        return self._f['cmfd/cmfd_balance'][()] if self.cmfd_on else None
×
171

172
    @property
12✔
173
    def cmfd_dominance(self):
12✔
174
        return self._f['cmfd/cmfd_dominance'][()] if self.cmfd_on else None
×
175

176
    @property
12✔
177
    def cmfd_entropy(self):
12✔
178
        return self._f['cmfd/cmfd_entropy'][()] if self.cmfd_on else None
×
179

180
    @property
12✔
181
    def cmfd_indices(self):
12✔
182
        return self._f['cmfd/indices'][()] if self.cmfd_on else None
×
183

184
    @property
12✔
185
    def cmfd_src(self):
12✔
186
        if self.cmfd_on:
×
187
            data = self._f['cmfd/cmfd_src'][()]
×
188
            return np.reshape(data, tuple(self.cmfd_indices), order='F')
×
189
        else:
190
            return None
×
191

192
    @property
12✔
193
    def cmfd_srccmp(self):
12✔
194
        return self._f['cmfd/cmfd_srccmp'][()] if self.cmfd_on else None
×
195

196
    @property
12✔
197
    def current_batch(self):
12✔
198
        return self._f['current_batch'][()]
12✔
199

200
    @property
12✔
201
    def date_and_time(self):
12✔
202
        s = self._f.attrs['date_and_time'].decode()
×
203
        return datetime.strptime(s, '%Y-%m-%d %H:%M:%S')
×
204

205
    @property
12✔
206
    def entropy(self):
12✔
207
        if self.run_mode == 'eigenvalue':
12✔
208
            return self._f['entropy'][()]
12✔
209
        else:
210
            return None
×
211

212
    @property
12✔
213
    def filters(self):
12✔
214
        if not self._filters_read:
12✔
215
            filters_group = self._f['tallies/filters']
12✔
216

217
            # Iterate over all Filters
218
            for group in filters_group.values():
12✔
219
                new_filter = openmc.Filter.from_hdf5(group, meshes=self.meshes)
12✔
220
                self._filters[new_filter.id] = new_filter
12✔
221

222
            self._filters_read = True
12✔
223

224
        return self._filters
12✔
225

226
    @property
12✔
227
    def generations_per_batch(self):
12✔
228
        if self.run_mode == 'eigenvalue':
×
229
            return self._f['generations_per_batch'][()]
×
230
        else:
231
            return None
×
232

233
    @property
12✔
234
    def global_tallies(self):
12✔
235
        if self._global_tallies is None:
12✔
236
            data = self._f['global_tallies'][()]
12✔
237
            gt = np.zeros(data.shape[0], dtype=[
12✔
238
                ('name', 'S14'), ('sum', 'f8'), ('sum_sq', 'f8'),
239
                ('mean', 'f8'), ('std_dev', 'f8')])
240
            gt['name'] = ['k-collision', 'k-absorption', 'k-tracklength',
12✔
241
                          'leakage']
242
            gt['sum'] = data[:,1]
12✔
243
            gt['sum_sq'] = data[:,2]
12✔
244

245
            # Calculate mean and sample standard deviation of mean
246
            n = self.n_realizations
12✔
247
            gt['mean'] = gt['sum']/n
12✔
248
            gt['std_dev'] = np.sqrt((gt['sum_sq']/n - gt['mean']**2)/(n - 1))
12✔
249

250
            self._global_tallies = gt
12✔
251

252
        return self._global_tallies
12✔
253

254
    @property
12✔
255
    def k_cmfd(self):
12✔
256
        if self.cmfd_on:
×
257
            return self._f['cmfd/k_cmfd'][()]
×
258
        else:
259
            return None
×
260

261
    @property
12✔
262
    def k_generation(self):
12✔
263
        if self.run_mode == 'eigenvalue':
×
264
            return self._f['k_generation'][()]
×
265
        else:
266
            return None
×
267

268
    @property
12✔
269
    def keff(self):
12✔
270
        if self.run_mode == 'eigenvalue':
12✔
271
            return ufloat(*self._f['k_combined'][()])
12✔
272
        else:
273
            return None
×
274

275
    @property
12✔
276
    def k_combined(self):
12✔
277
        warnings.warn(
×
278
            "The 'k_combined' property has been renamed to 'keff' and will be "
279
            "removed in a future version of OpenMC.", FutureWarning
280
        )
281
        return self.keff
×
282

283
    @property
12✔
284
    def k_col_abs(self):
12✔
285
        if self.run_mode == 'eigenvalue':
×
286
            return self._f['k_col_abs'][()]
×
287
        else:
288
            return None
×
289

290
    @property
12✔
291
    def k_col_tra(self):
12✔
292
        if self.run_mode == 'eigenvalue':
×
293
            return self._f['k_col_tra'][()]
×
294
        else:
295
            return None
×
296

297
    @property
12✔
298
    def k_abs_tra(self):
12✔
299
        if self.run_mode == 'eigenvalue':
×
300
            return self._f['k_abs_tra'][()]
×
301
        else:
302
            return None
×
303

304
    @property
12✔
305
    def meshes(self):
12✔
306
        if not self._meshes_read:
12✔
307
            mesh_group = self._f['tallies/meshes']
12✔
308

309
            # Iterate over all meshes
310
            for group in mesh_group.values():
12✔
311
                mesh = openmc.MeshBase.from_hdf5(group)
12✔
312
                self._meshes[mesh.id] = mesh
12✔
313

314
            self._meshes_read = True
12✔
315

316
        return self._meshes
12✔
317

318
    @property
12✔
319
    def n_batches(self):
12✔
320
        return self._f['n_batches'][()]
12✔
321

322
    @property
12✔
323
    def n_inactive(self):
12✔
324
        if self.run_mode == 'eigenvalue':
12✔
325
            return self._f['n_inactive'][()]
12✔
326
        else:
327
            return None
×
328

329
    @property
12✔
330
    def n_particles(self):
12✔
331
        return self._f['n_particles'][()]
×
332

333
    @property
12✔
334
    def n_realizations(self):
12✔
335
        return self._f['n_realizations'][()]
12✔
336

337
    @property
12✔
338
    def path(self):
12✔
339
        return self._f.attrs['path'].decode()
×
340

341
    @property
12✔
342
    def photon_transport(self):
12✔
343
        return self._f.attrs['photon_transport'] > 0
×
344

345
    @property
12✔
346
    def run_mode(self):
12✔
347
        return self._f['run_mode'][()].decode()
12✔
348

349
    @property
12✔
350
    def runtime(self):
12✔
351
        return {name: dataset[()]
12✔
352
                for name, dataset in self._f['runtime'].items()}
353

354
    @property
12✔
355
    def seed(self):
12✔
356
        return self._f['seed'][()]
×
357

358
    @property
12✔
359
    def source(self):
12✔
360
        return self._f['source_bank'][()] if self.source_present else None
12✔
361

362
    @property
12✔
363
    def source_present(self):
12✔
364
        return self._f.attrs['source_present'] > 0
12✔
365

366
    @property
12✔
367
    def sparse(self):
12✔
368
        return self._sparse
12✔
369

370
    @sparse.setter
12✔
371
    def sparse(self, sparse):
12✔
372
        """Convert tally data from NumPy arrays to SciPy list of lists (LIL)
373
        sparse matrices, and vice versa.
374

375
        This property may be used to reduce the amount of data in memory during
376
        tally data processing. The tally data will be stored as SciPy LIL
377
        matrices internally within each Tally object. All tally data access
378
        properties and methods will return data as a dense NumPy array.
379

380
        """
381

382
        cv.check_type('sparse', sparse, bool)
×
383
        self._sparse = sparse
×
384

385
        # Update tally sparsities
386
        if self._tallies_read:
×
387
            for tally_id in self.tallies:
×
388
                self.tallies[tally_id].sparse = self.sparse
×
389

390
    @property
12✔
391
    def tallies(self):
12✔
392
        if self.tallies_present and not self._tallies_read:
12✔
393
            # Read the number of tallies
394
            tallies_group = self._f['tallies']
12✔
395
            n_tallies = tallies_group.attrs['n_tallies']
12✔
396

397
            # Read a list of the IDs for each Tally
398
            if n_tallies > 0:
12✔
399
                # Tally user-defined IDs
400
                tally_ids = tallies_group.attrs['ids']
12✔
401
            else:
402
                tally_ids = []
×
403

404
            # Ignore warnings about duplicate IDs
405
            with warnings.catch_warnings():
12✔
406
                warnings.simplefilter('ignore', openmc.IDWarning)
12✔
407

408
                # Iterate over all tallies
409
                for tally_id in tally_ids:
12✔
410
                    group = tallies_group[f'tally {tally_id}']
12✔
411

412
                    # Check if tally is internal and therefore has no data
413
                    if group.attrs.get("internal"):
12✔
414
                        continue
12✔
415

416
                    # Create Tally object and assign basic properties
417
                    tally = openmc.Tally(tally_id)
12✔
418
                    tally._sp_filename = self._f.filename
12✔
419
                    tally.name = group['name'][()].decode() if 'name' in group else ''
12✔
420

421
                    # Check if tally has multiply_density attribute
422
                    if "multiply_density" in group.attrs:
12✔
423
                        tally.multiply_density = group.attrs["multiply_density"].item() > 0
12✔
424

425
                    # Read the number of realizations
426
                    n_realizations = group['n_realizations'][()]
12✔
427

428
                    tally.estimator = group['estimator'][()].decode()
12✔
429
                    tally.num_realizations = n_realizations
12✔
430

431
                    # Read derivative information.
432
                    if 'derivative' in group:
12✔
433
                        deriv_id = group['derivative'][()]
12✔
434
                        tally.derivative = self.tally_derivatives[deriv_id]
12✔
435

436
                    # Read all filters
437
                    n_filters = group['n_filters'][()]
12✔
438
                    if n_filters > 0:
12✔
439
                        filter_ids = group['filters'][()]
12✔
440
                        filters_group = self._f['tallies/filters']
12✔
441
                        for filter_id in filter_ids:
12✔
442
                            filter_group = filters_group[f'filter {filter_id}']
12✔
443
                            new_filter = openmc.Filter.from_hdf5(
12✔
444
                                filter_group, meshes=self.meshes)
445
                            tally.filters.append(new_filter)
12✔
446

447
                    # Read nuclide bins
448
                    nuclide_names = group['nuclides'][()]
12✔
449

450
                    # Add all nuclides to the Tally
451
                    tally.nuclides = [name.decode().strip() for name in nuclide_names]
12✔
452

453
                    # Add the scores to the Tally
454
                    scores = group['score_bins'][()]
12✔
455
                    tally.scores = [score.decode() for score in scores]
12✔
456

457
                    # Add Tally to the global dictionary of all Tallies
458
                    tally.sparse = self.sparse
12✔
459
                    self._tallies[tally_id] = tally
12✔
460

461
            self._tallies_read = True
12✔
462

463
        return self._tallies
12✔
464

465
    @property
12✔
466
    def tallies_present(self):
12✔
467
        return self._f.attrs['tallies_present'] > 0
12✔
468

469
    @property
12✔
470
    def tally_derivatives(self):
12✔
471
        if not self._derivs_read:
12✔
472
            # Populate the dictionary if any derivatives are present.
473
            if 'derivatives' in self._f['tallies']:
12✔
474
                # Read the derivative ids.
475
                base = 'tallies/derivatives'
12✔
476
                deriv_ids = [int(k.split(' ')[1]) for k in self._f[base]]
12✔
477

478
                # Create each derivative object and add it to the dictionary.
479
                for d_id in deriv_ids:
12✔
480
                    group = self._f[f'tallies/derivatives/derivative {d_id}']
12✔
481
                    deriv = openmc.TallyDerivative(derivative_id=d_id)
12✔
482
                    deriv.variable = group['independent variable'][()].decode()
12✔
483
                    if deriv.variable == 'density':
12✔
484
                        deriv.material = group['material'][()]
12✔
485
                    elif deriv.variable == 'nuclide_density':
12✔
486
                        deriv.material = group['material'][()]
12✔
487
                        deriv.nuclide = group['nuclide'][()].decode()
12✔
488
                    elif deriv.variable == 'temperature':
12✔
489
                        deriv.material = group['material'][()]
12✔
490
                    self._derivs[d_id] = deriv
12✔
491

492
            self._derivs_read = True
12✔
493

494
        return self._derivs
12✔
495

496
    @property
12✔
497
    def version(self):
12✔
498
        return tuple(self._f.attrs['openmc_version'])
×
499

500
    @property
12✔
501
    def summary(self):
12✔
502
        return self._summary
12✔
503

504
    def close(self):
12✔
505
        """Close the statepoint HDF5 file and the corresponding
506
        summary HDF5 file if present.
507
        """
508
        self._f.close()
12✔
509
        if self._summary is not None:
12✔
510
            self._summary._f.close()
12✔
511

512
    def add_volume_information(self, volume_calc):
12✔
513
        """Add volume information to the geometry within the file
514

515
        Parameters
516
        ----------
517
        volume_calc : openmc.VolumeCalculation
518
            Results from a stochastic volume calculation
519

520
        """
521
        if self.summary is not None:
×
522
            self.summary.add_volume_information(volume_calc)
×
523

524
    def get_tally(self, scores=[], filters=[], nuclides=[],
12✔
525
                  name=None, id=None, estimator=None, exact_filters=False,
526
                  exact_nuclides=False, exact_scores=False,
527
                  multiply_density=None, derivative=None):
528
        """Finds and returns a Tally object with certain properties.
529

530
        This routine searches the list of Tallies and returns the first Tally
531
        found which satisfies all of the input parameters.
532

533
        NOTE: If any of the "exact" parameters are False (default), the input
534
        parameters do not need to match the complete Tally specification and may
535
        only represent a subset of the Tally's properties. If an "exact"
536
        parameter is True then number of scores, filters, or nuclides in the
537
        parameters must precisely match those of any matching Tally.
538

539
        Parameters
540
        ----------
541
        scores : list, optional
542
            A list of one or more score strings (default is []).
543
        filters : list, optional
544
            A list of Filter objects (default is []).
545
        nuclides : list, optional
546
            A list of Nuclide objects (default is []).
547
        name : str, optional
548
            The name specified for the Tally (default is None).
549
        id : Integral, optional
550
            The id specified for the Tally (default is None).
551
        estimator: str, optional
552
            The type of estimator ('tracklength', 'analog'; default is None).
553
        exact_filters : bool
554
            If True, the number of filters in the parameters must be identical
555
            to those in the matching Tally. If False (default), the filters in
556
            the parameters may be a subset of those in the matching Tally.
557
        exact_nuclides : bool
558
            If True, the number of nuclides in the parameters must be identical
559
            to those in the matching Tally. If False (default), the nuclides in
560
            the parameters may be a subset of those in the matching Tally.
561
        exact_scores : bool
562
            If True, the number of scores in the parameters must be identical to
563
            those in the matching Tally. If False (default), the scores in the
564
            parameters may be a subset of those in the matching Tally. Default
565
            is None (no check).
566
        multiply_density : bool, optional
567
            If not None, the Tally must have the multiply_density attribute set
568
            to the same value as this parameter.
569
        derivative : openmc.TallyDerivative, optional
570
            TallyDerivative object to match.
571

572
        Returns
573
        -------
574
        tally : openmc.Tally
575
            A tally matching the specified criteria
576

577
        Raises
578
        ------
579
        LookupError
580
            If a Tally meeting all of the input parameters cannot be found in
581
            the statepoint.
582

583
        """
584

585
        tally = None
12✔
586

587
        # Iterate over all tallies to find the appropriate one
588
        for test_tally in self.tallies.values():
12✔
589

590
            # Determine if Tally has queried name
591
            if name and name != test_tally.name:
12✔
592
                continue
12✔
593

594
            # Determine if Tally has queried id
595
            if id and id != test_tally.id:
12✔
596
                continue
12✔
597

598
            # Determine if Tally has queried estimator, only move on to next tally
599
            # if the estimator is both specified and the tally estimtor does not
600
            # match
601
            if estimator is not None and estimator != test_tally.estimator:
12✔
602
                continue
12✔
603

604
            # The number of filters, nuclides and scores must exactly match
605
            if exact_scores and len(scores) != test_tally.num_scores:
12✔
606
                continue
×
607
            if exact_nuclides and nuclides and len(nuclides) != test_tally.num_nuclides:
12✔
NEW
608
                continue
×
609
            if exact_nuclides and not nuclides and test_tally.nuclides != ['total']:
12✔
UNCOV
610
                continue
×
611
            if exact_filters and len(filters) != test_tally.num_filters:
12✔
612
                continue
12✔
613
            if derivative is not None and derivative != test_tally.derivative:
12✔
NEW
614
                continue
×
615
            if multiply_density is not None and multiply_density != test_tally.multiply_density:
12✔
NEW
616
                continue
×
617

618
            # Determine if Tally has the queried score(s)
619
            if scores:
12✔
620
                if not all(score in test_tally.scores for score in scores):
12✔
621
                    continue
12✔
622

623
            # Determine if Tally has the queried Filter(s)
624
            if filters:
12✔
625
                contains_filters = True
12✔
626

627
                # Iterate over the Filters requested by the user
628
                for outer_filter in filters:
12✔
629
                    contains_filters = False
12✔
630

631
                    # Test if requested filter is a subset of any of the test
632
                    # tally's filters and if so continue to next filter
633
                    for inner_filter in test_tally.filters:
12✔
634
                        if inner_filter.is_subset(outer_filter):
12✔
635
                            contains_filters = True
12✔
636
                            break
12✔
637

638
                    if not contains_filters:
12✔
639
                        break
12✔
640

641
                if not contains_filters:
12✔
642
                    continue
12✔
643

644
            # Determine if Tally has the queried Nuclide(s)
645
            if nuclides:
12✔
646
                if not all(nuclide in test_tally.nuclides for nuclide in nuclides):
12✔
647
                    continue
×
648

649
            # If the current Tally met user's request, break loop and return it
650
            tally = test_tally
12✔
651
            break
12✔
652

653
        # If we did not find the Tally, return an error message
654
        if tally is None:
12✔
655
            raise LookupError('Unable to get Tally')
×
656

657
        return tally
12✔
658

659
    def link_with_summary(self, summary):
12✔
660
        """Links Tallies and Filters with Summary model information.
661

662
        This routine retrieves model information (materials, geometry) from a
663
        Summary object populated with an HDF5 'summary.h5' file and inserts it
664
        into the Tally objects. This can be helpful when viewing and
665
        manipulating large scale Tally data. Note that it is necessary to link
666
        against a summary to populate the Tallies with any user-specified "name"
667
        XML tags.
668

669
        Parameters
670
        ----------
671
        summary : openmc.Summary
672
             A Summary object.
673

674
        Raises
675
        ------
676
        ValueError
677
            An error when the argument passed to the 'summary' parameter is not
678
            an openmc.Summary object.
679

680
        """
681

682
        if self.summary is not None:
12✔
683
            warnings.warn('A Summary object has already been linked.',
×
684
                          RuntimeWarning)
685
            return
×
686

687
        if not isinstance(summary, openmc.Summary):
12✔
688
            msg = f'Unable to link statepoint with "{summary}" which is not a' \
×
689
                  'Summary object'
690
            raise ValueError(msg)
×
691

692
        cells = summary.geometry.get_all_cells()
12✔
693

694
        for tally in self.tallies.values():
12✔
695
            tally.with_summary = True
12✔
696

697
            for tally_filter in tally.filters:
12✔
698
                if isinstance(tally_filter, (openmc.DistribcellFilter)):
12✔
699
                    cell_id = tally_filter.bins[0]
12✔
700
                    cell = cells[cell_id]
12✔
701
                    if not cell._paths:
12✔
702
                        summary.geometry.determine_paths()
12✔
703
                    tally_filter.paths = cell.paths
12✔
704

705
        self._summary = summary
12✔
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