|
3 | 3 | from math import pi, cos |
4 | 4 | from numbers import Real |
5 | 5 | from xml.etree import ElementTree as ET |
| 6 | +from xmlrpc.client import boolean |
6 | 7 |
|
7 | 8 | import numpy as np |
8 | 9 |
|
9 | 10 | import openmc.checkvalue as cv |
10 | 11 | from .._xml import get_text |
11 | 12 | from .univariate import Univariate, Uniform, PowerLaw |
| 13 | +from ..mesh import MeshBase |
12 | 14 |
|
13 | 15 |
|
14 | 16 | class UnitSphere(ABC): |
@@ -269,6 +271,8 @@ def from_xml_element(cls, elem): |
269 | 271 | return CylindricalIndependent.from_xml_element(elem) |
270 | 272 | elif distribution == 'spherical': |
271 | 273 | return SphericalIndependent.from_xml_element(elem) |
| 274 | + elif distribution == 'mesh': |
| 275 | + return MeshIndependent.from_xml_element(elem) |
272 | 276 | elif distribution == 'box' or distribution == 'fission': |
273 | 277 | return Box.from_xml_element(elem) |
274 | 278 | elif distribution == 'point': |
@@ -616,6 +620,120 @@ def from_xml_element(cls, elem): |
616 | 620 | origin = [float(x) for x in elem.get('origin').split()] |
617 | 621 | return cls(r, phi, z, origin=origin) |
618 | 622 |
|
| 623 | +class MeshIndependent(Spatial): |
| 624 | + """Spatial distribution for a mesh. |
| 625 | +
|
| 626 | + This distribution allows one to specify a mesh to sample over and the scheme to sample over the entire mesh. |
| 627 | +
|
| 628 | + .. versionadded:: 0.13 |
| 629 | +
|
| 630 | + Parameters |
| 631 | + ---------- |
| 632 | + elem_weight_scheme : str, optional |
| 633 | + The scheme for weighting and sampling elements from the mesh. Options are 'file' and 'volume' based weights. |
| 634 | + mesh : openmc.MeshBase |
| 635 | + The mesh instance used for sampling, mesh is written into settings.xml, mesh.id is written into the source distribution |
| 636 | + weights_from_file : Iterable of Real, optional |
| 637 | + A list of values which represent the weights of each element |
| 638 | +
|
| 639 | +
|
| 640 | + Attributes |
| 641 | + ---------- |
| 642 | + elem_weight_scheme : str, optional |
| 643 | + Weighting scheme for sampling element from mesh, defaults to volume |
| 644 | + mesh : openmc.MeshBase |
| 645 | + The mesh instance used for sampling, mesh is written into settings.xml, mesh.id is written into the source distribution |
| 646 | + weights_from_file : Iterable of Real, optional |
| 647 | + A list of values which represent the weights of each element |
| 648 | +
|
| 649 | + """ |
| 650 | + |
| 651 | + def __init__(self, mesh, weights_from_file=None, volume_weighting=False): |
| 652 | + self.mesh = mesh |
| 653 | + self.weights_from_file = weights_from_file |
| 654 | + self.volume_weighting = volume_weighting |
| 655 | + |
| 656 | + @property |
| 657 | + def mesh(self): |
| 658 | + return self._mesh |
| 659 | + |
| 660 | + @mesh.setter |
| 661 | + def mesh(self, mesh): |
| 662 | + if mesh != None: |
| 663 | + cv.check_type('Unstructured Mesh', mesh, MeshBase) |
| 664 | + self._mesh = mesh |
| 665 | + |
| 666 | + @property |
| 667 | + def volume_weighting(self): |
| 668 | + return self._volume_weighting |
| 669 | + |
| 670 | + @volume_weighting.setter |
| 671 | + def volume_weighting(self, volume_weighting): |
| 672 | + cv.check_type('Scheme for sampling an element from the mesh', volume_weighting, bool) |
| 673 | + self._volume_weighting = volume_weighting |
| 674 | + |
| 675 | + @property |
| 676 | + def weights_from_file(self): |
| 677 | + return self._weights_from_file |
| 678 | + |
| 679 | + @weights_from_file.setter |
| 680 | + def weights_from_file(self, given_weights): |
| 681 | + if given_weights is not None: |
| 682 | + self._weights_from_file = (np.array(given_weights, dtype=float)).flatten() |
| 683 | + else: |
| 684 | + self._weights_from_file = None |
| 685 | + |
| 686 | + @property |
| 687 | + def num_weight_bins(self): |
| 688 | + if self.weights_from_file == None: |
| 689 | + raise ValueError('Weight bins are not set') |
| 690 | + return self.weights_from_file.size |
| 691 | + |
| 692 | + def to_xml_element(self): |
| 693 | + """Return XML representation of the spatial distribution |
| 694 | +
|
| 695 | + Returns |
| 696 | + ------- |
| 697 | + element : xml.etree.ElementTree.Element |
| 698 | + XML element containing spatial distribution data |
| 699 | +
|
| 700 | + """ |
| 701 | + element = ET.Element('space') |
| 702 | + element.set('type', 'mesh') |
| 703 | + element.set("mesh_id", str(self.mesh.id)) |
| 704 | + element.set("volume_weighting", str(self.volume_weighting)) |
| 705 | + |
| 706 | + if self.weights_from_file is not None: |
| 707 | + subelement = ET.SubElement(element, 'weights_from_file') |
| 708 | + subelement.text = ' '.join(str(e) for e in self.weights_from_file) |
| 709 | + |
| 710 | + return element |
| 711 | + |
| 712 | + @classmethod |
| 713 | + def from_xml_element(cls, elem): |
| 714 | + """Generate spatial distribution from an XML element |
| 715 | +
|
| 716 | + Parameters |
| 717 | + ---------- |
| 718 | + elem : xml.etree.ElementTree.Element |
| 719 | + XML element |
| 720 | +
|
| 721 | + Returns |
| 722 | + ------- |
| 723 | + openmc.stats.MeshIndependent |
| 724 | + Spatial distribution generated from XML element |
| 725 | +
|
| 726 | + """ |
| 727 | + |
| 728 | + mesh_id = int(elem.get('mesh_id')) |
| 729 | + volume_weighting = elem.get("volume_weighting") |
| 730 | + volume_weighting = get_text(elem, 'volume_weighting').lower() == 'true' |
| 731 | + if elem.get('weights_from_file') is not None: |
| 732 | + weights_from_file = [float(b) for b in get_text(elem, 'weights_from_file').split()] |
| 733 | + else: |
| 734 | + weights_from_file = None |
| 735 | + return cls(volume_weighting, mesh_id, weights_from_file) |
| 736 | + |
619 | 737 |
|
620 | 738 | class Box(Spatial): |
621 | 739 | """Uniform distribution of coordinates in a rectangular cuboid. |
|
0 commit comments