mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 21:55:41 -04:00
Merge pull request #1825 from pshriwise/dagmc_universe
DAGMC CAD-based geometry as universes
This commit is contained in:
commit
99d5bdb27d
46 changed files with 1568 additions and 850 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -116,3 +116,6 @@ CMakeSettings.json
|
|||
|
||||
# Visual Studio Code configuration files
|
||||
.vscode/
|
||||
|
||||
# Python pickle files
|
||||
*.pkl
|
||||
|
|
@ -19,7 +19,7 @@ Each ``<surface>`` element can have the following attributes or sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the surface in summary output
|
||||
files. This string is limited to 52 characters for formatting purposes.
|
||||
files.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
@ -122,7 +122,6 @@ Each ``<cell>`` element can have the following attributes or sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the cell in summary output files.
|
||||
This string is limmited to 52 characters for formatting purposes.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
@ -235,7 +234,7 @@ the following attributes or sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the lattice in summary output
|
||||
files. This string is limited to 52 characters for formatting purposes.
|
||||
files.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
@ -301,7 +300,7 @@ the following attributes or sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the hex_lattice in summary output
|
||||
files. This string is limited to 52 characters for formatting purposes.
|
||||
files.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
@ -370,3 +369,40 @@ Here is an example of a properly defined 2d hexagonal lattice:
|
|||
202
|
||||
</universes>
|
||||
</hex_lattice>
|
||||
|
||||
|
||||
.. _dagmc_element:
|
||||
|
||||
----------------------------
|
||||
``<dagmc_universe>`` Element
|
||||
----------------------------
|
||||
|
||||
Each ``<dagmc_universe>`` element can have the following attributes or sub-elements:
|
||||
|
||||
:id:
|
||||
A unique integer used to identify the universe.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:name:
|
||||
An optional string name to identify the surface in summary output
|
||||
files.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:auto_geom_ids:
|
||||
Boolean value indicating whether the existing geometry IDs will be used or appended
|
||||
to the existing ID space of natively defined OpenMC geometry entities.
|
||||
|
||||
*Default*: false
|
||||
|
||||
:auto_mat_ids:
|
||||
Boolean value indicating whether the existing material IDs will be used or appended
|
||||
to the existing ID space of natively defined OpenMC materials.
|
||||
|
||||
*Default*: false
|
||||
|
||||
:filename:
|
||||
A required string indicating the file to be loaded representing the DAGMC universe.
|
||||
|
||||
*Default*: None
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Each ``material`` element can have the following attributes or sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the material in summary output
|
||||
files. This string is limited to 52 characters for formatting purposes.
|
||||
files.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
|
|||
|
|
@ -88,14 +88,6 @@ you care. This element has the following attributes/sub-elements:
|
|||
|
||||
*Default*: 0.0
|
||||
|
||||
--------------------------------
|
||||
``<dagmc>`` Element
|
||||
--------------------------------
|
||||
|
||||
When the DAGMC mode is enabled, the OpenMC geometry will be read from the file
|
||||
``dagmc.h5m``. If a :ref:`geometry.xml <io_geometry>` file is present with
|
||||
``dagmc`` set to ``true``, it will be ignored.
|
||||
|
||||
----------------------------
|
||||
``<delayed_photon_scaling>``
|
||||
----------------------------
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ The current version of the summary file format is 6.0.
|
|||
- **n_universes** (*int*) -- Number of unique universes in the
|
||||
problem.
|
||||
- **n_lattices** (*int*) -- Number of lattices in the problem.
|
||||
- **dagmc** (*int*) -- Indicates that a DAGMC geometry was used
|
||||
if present.
|
||||
|
||||
**/geometry/cells/cell <uid>/**
|
||||
|
||||
|
|
@ -49,6 +47,8 @@ The current version of the summary file format is 6.0.
|
|||
- **lattice** (*int*) -- Unique ID of the lattice which fills the
|
||||
cell. Only present if fill_type is set to 'lattice'.
|
||||
- **region** (*char[]*) -- Region specification for the cell.
|
||||
- **geom_type** (*char[]*) -- Type of geometry used to create the cell.
|
||||
Either 'csg' or 'dagmc'.
|
||||
|
||||
**/geometry/surfaces/surface <uid>/**
|
||||
|
||||
|
|
@ -62,12 +62,27 @@ The current version of the summary file format is 6.0.
|
|||
- **boundary_condition** (*char[]*) -- Boundary condition applied to
|
||||
the surface. Can be 'transmission', 'vacuum', 'reflective', or
|
||||
'periodic'.
|
||||
- **geom_type** (*char[]*) -- Type of geometry used to create the cell.
|
||||
Either 'csg' or 'dagmc'.
|
||||
|
||||
|
||||
**/geometry/universes/universe <uid>/**
|
||||
|
||||
:Datasets:
|
||||
- **cells** (*int[]*) -- Array of unique IDs of cells that appear in
|
||||
the universe.
|
||||
- **geom_type** (*char[]*) -- Type of geometry used to create the cell.
|
||||
Either 'csg' or 'dagmc'.
|
||||
- **filename** (*char[]*) -- Name of the DAGMC file representing this universe.
|
||||
Only present for DAGMC Universes.
|
||||
:Attributes:
|
||||
- **auto_geom_ids** (*int*) -- ``1`` if geometry IDs of the DAGMC
|
||||
model will be appended to the ID space of the natively defined
|
||||
CSG geometry, ``0`` if the existing DAGMC IDs will be used.
|
||||
- **auto_mat_ids** (*int*) -- ``1`` if UWUW material IDs of the DAGMC
|
||||
model will be appended to the ID space of the natively defined
|
||||
OpenMC materials, ``0`` if the existing UWUW IDs will be used.
|
||||
|
||||
|
||||
**/geometry/lattices/lattice <uid>/**
|
||||
|
||||
|
|
@ -119,8 +134,8 @@ The current version of the summary file format is 6.0.
|
|||
:Attributes: - **volume** (*double[]*) -- Volume of this material [cm^3]. Only
|
||||
present if ``volume`` supplied
|
||||
- **temperature** (*double[]*) -- Temperature of this material [K].
|
||||
Only present in ``temperature`` supplied
|
||||
- **depletable** (*int[]*) -- ``1`` if the material can be depleted,
|
||||
Only present if ``temperature`` is supplied
|
||||
- **depletable** (*int*) -- ``1`` if the material can be depleted,
|
||||
``0`` otherwise. Always present
|
||||
|
||||
**/nuclides/**
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
|
||||
:name:
|
||||
An optional string name to identify the tally in summary output
|
||||
files. This string is limited to 52 characters for formatting purposes.
|
||||
files.
|
||||
|
||||
*Default*: ""
|
||||
|
||||
|
|
|
|||
|
|
@ -433,30 +433,64 @@ will handle creating the unverse::
|
|||
Using CAD-based Geometry
|
||||
--------------------------
|
||||
|
||||
OpenMC relies on the Direct Accelerated Geometry Monte Carlo toolkit (`DAGMC
|
||||
<https://svalinn.github.io/DAGMC/>`_) to represent CAD-based geometry in a
|
||||
surface mesh format. A DAGMC run can be enabled in OpenMC by setting the
|
||||
``dagmc`` property to ``True`` in the model Settings either via the Python
|
||||
:class:`openmc.settings` Python class::
|
||||
Defining Geometry
|
||||
-----------------
|
||||
|
||||
settings = openmc.Settings()
|
||||
settings.dagmc = True
|
||||
OpenMC relies on the `Direct Accelerated Geometry Monte Carlo`_ (DAGMC)
|
||||
to represent CAD-based geometry in a surface mesh format. DAGMC geometries are
|
||||
applied as universes in the OpenMC geometry file. A geometry represented
|
||||
entirely by a DAGMC geometry will contain only the DAGMC universe. Using a
|
||||
:class:`openmc.DAGMCUniverse` looks like the following::
|
||||
|
||||
or in the :ref:`settings.xml <io_settings>` file::
|
||||
dag_univ = openmc.DAGMCUniverse(filename='dagmc.h5m')
|
||||
geometry = openmc.Geometry(dag_univ)
|
||||
geometry.export_to_xml()
|
||||
|
||||
<dagmc>true</dagmc>
|
||||
The resulting ``geometry.xml`` file will be:
|
||||
|
||||
With ``dagmc`` set to true, OpenMC will load the DAGMC model (from a local file
|
||||
named ``dagmc.h5m``) when initializing a simulation. If a `geometry.xml
|
||||
<../io_formats/geometry.html>`_ is present as well, it will be ignored.
|
||||
.. code-block:: xml
|
||||
|
||||
**Note:** DAGMC geometries used in OpenMC are currently required to be clean,
|
||||
meaning that all surfaces have been `imprinted and merged
|
||||
<https://svalinn.github.io/DAGMC/usersguide/trelis_workflow.html>`_
|
||||
successfully and that the model is `watertight
|
||||
<https://svalinn.github.io/DAGMC/usersguide/tools.html#make-watertight>`_. Future
|
||||
implementations of DAGMC geometry will support small volume overlaps and
|
||||
un-merged surfaces.
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<geometry>
|
||||
<dagmc auto_ids="false" filename="dagmc.h5m" id="1" name="" />
|
||||
</geometry>
|
||||
|
||||
DAGMC universes can also be used to fill CSG cells or lattice cells in a geometry::
|
||||
|
||||
cell.fill = dagmc_univ
|
||||
|
||||
It is important in these cases to understand the DAGMC model's position
|
||||
with respect to the CSG geometry. DAGMC geometries can be plotted with
|
||||
OpenMC to verify that the model matches one's expectations.
|
||||
|
||||
**Note:** DAGMC geometries used in OpenMC are currently required to be clean,
|
||||
meaning that all surfaces have been `imprinted and merged
|
||||
<https://svalinn.github.io/DAGMC/usersguide/trelis_workflow.html>`_
|
||||
successfully and that the model is `watertight
|
||||
<https://svalinn.github.io/DAGMC/usersguide/tools.html#make-watertight>`_. Future
|
||||
implementations of DAGMC geometry will support small volume overlaps and
|
||||
un-merged surfaces.
|
||||
|
||||
Cell, Surface, and Material IDs
|
||||
-------------------------------
|
||||
|
||||
By default, DAGMC applies cell and surface IDs defined by the CAD engine that
|
||||
the model originated in. If these IDs overlap with IDs in the CSG ID space,
|
||||
this will result in an error. However, the ``auto_ids`` property of a DAGMC
|
||||
universe can be set to set DAGMC cell and surface IDs by appending to the
|
||||
existing CSG cell ID space in the OpenMC model.
|
||||
|
||||
Similar options exist for the material IDs of DAGMC models. If DAGMC material
|
||||
assignments are based on natively defined OpenMC materials, no further work is
|
||||
required. If DAGMC materials are assigned using the `University of Wisconsin
|
||||
Unified Workflow`_ (UWUW), however, material IDs in the UWUW material library
|
||||
may overlap with those used in the CSG geometry. In this case, overlaps in the
|
||||
UWUW and OpenMC material ID space will cause an error. To automatically resolve
|
||||
these ID overlaps, ``auto_ids`` can be set to ``True`` to append the UWUW
|
||||
material IDs to the OpenMC material ID space.
|
||||
|
||||
.. _Direct Accelerated Geometry Monte Carlo: https://svalinn.github.io/DAGMC/
|
||||
.. _University of Wisconsin Unified Workflow: https://svalinn.github.io/DAGMC/usersguide/uw2.html
|
||||
|
||||
-------------------------
|
||||
Calculating Atoms Content
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"OpenMC expects that the model has the name \"dagmc.h5m\" so we'll name the file that and indicate to OpenMC that a DAGMC geometry is being used by setting the `settings.dagmc` attribute to `True`."
|
||||
"To create a geometry where DAGMC represents the entire model, we'll make a DAGMC universe and use it as the root universe of the model."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -149,9 +149,19 @@
|
|||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dagmc_univ = openmc.DAGMCUniverse(filename=\"dagmc.h5m\")\n",
|
||||
"geometry = openmc.Geometry(root=dagmc_univ)\n",
|
||||
"geometry.export_to_xml()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"settings = openmc.Settings()\n",
|
||||
"settings.dagmc = True\n",
|
||||
"settings.batches = 10\n",
|
||||
"settings.inactive = 2\n",
|
||||
"settings.particles = 5000\n",
|
||||
|
|
@ -169,12 +179,12 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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\n",
|
||||
"image/png": "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\n",
|
||||
"text/plain": [
|
||||
"<IPython.core.display.Image object>"
|
||||
]
|
||||
|
|
@ -201,7 +211,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -219,7 +229,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -246,7 +256,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
|
|
@ -283,15 +293,16 @@
|
|||
" Copyright | 2011-2021 MIT and OpenMC contributors\n",
|
||||
" License | https://docs.openmc.org/en/latest/license.html\n",
|
||||
" Version | 0.13.0-dev\n",
|
||||
" Git SHA1 | 3dd81a1316ac3b5a0633e4b7a290f3bc97a066d9\n",
|
||||
" Date/Time | 2021-06-26 11:58:36\n",
|
||||
" Git SHA1 | 0aafa81907ac79b9bdb4a86aede0b63fee3a9a9b\n",
|
||||
" Date/Time | 2021-06-30 09:01:58\n",
|
||||
" OpenMP Threads | 2\n",
|
||||
"\n",
|
||||
" Reading settings XML file...\n",
|
||||
" Reading cross sections XML file...\n",
|
||||
" Reading materials XML file...\n",
|
||||
" Reading DAGMC geometry...\n",
|
||||
"Using the DOUBLE-DOWN interface to Embree.\n",
|
||||
" Reading geometry XML file...\n",
|
||||
"Set overlap thickness = 0\n",
|
||||
"Set numerical precision = 0.001\n",
|
||||
"Loading file dagmc.h5m\n",
|
||||
"Initializing the GeomQueryTool...\n",
|
||||
"Using faceting tolerance: 0.0001\n",
|
||||
|
|
@ -327,21 +338,21 @@
|
|||
"\n",
|
||||
" =======================> TIMING STATISTICS <=======================\n",
|
||||
"\n",
|
||||
" Total time for initialization = 1.4751e-01 seconds\n",
|
||||
" Reading cross sections = 1.0076e-01 seconds\n",
|
||||
" Total time in simulation = 3.0461e-01 seconds\n",
|
||||
" Time in transport only = 2.9733e-01 seconds\n",
|
||||
" Time in inactive batches = 5.7728e-02 seconds\n",
|
||||
" Time in active batches = 2.4689e-01 seconds\n",
|
||||
" Time synchronizing fission bank = 2.9442e-03 seconds\n",
|
||||
" Sampling source sites = 2.6400e-03 seconds\n",
|
||||
" SEND/RECV source sites = 3.0032e-04 seconds\n",
|
||||
" Time accumulating tallies = 4.2046e-05 seconds\n",
|
||||
" Time writing statepoints = 3.0596e-03 seconds\n",
|
||||
" Total time for finalization = 8.3508e-05 seconds\n",
|
||||
" Total time elapsed = 4.5681e-01 seconds\n",
|
||||
" Calculation Rate (inactive) = 173226.0 particles/second\n",
|
||||
" Calculation Rate (active) = 162018.0 particles/second\n",
|
||||
" Total time for initialization = 2.0815e-01 seconds\n",
|
||||
" Reading cross sections = 9.2095e-02 seconds\n",
|
||||
" Total time in simulation = 1.5220e+00 seconds\n",
|
||||
" Time in transport only = 1.5148e+00 seconds\n",
|
||||
" Time in inactive batches = 2.9113e-01 seconds\n",
|
||||
" Time in active batches = 1.2309e+00 seconds\n",
|
||||
" Time synchronizing fission bank = 3.1554e-03 seconds\n",
|
||||
" Sampling source sites = 2.7998e-03 seconds\n",
|
||||
" SEND/RECV source sites = 3.4967e-04 seconds\n",
|
||||
" Time accumulating tallies = 3.0953e-05 seconds\n",
|
||||
" Time writing statepoints = 2.7201e-03 seconds\n",
|
||||
" Total time for finalization = 2.3371e-04 seconds\n",
|
||||
" Total time elapsed = 1.7509e+00 seconds\n",
|
||||
" Calculation Rate (inactive) = 34348.7 particles/second\n",
|
||||
" Calculation Rate (active) = 32497.7 particles/second\n",
|
||||
"\n",
|
||||
" ============================> RESULTS <============================\n",
|
||||
"\n",
|
||||
|
|
@ -374,7 +385,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -383,7 +394,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -393,7 +404,7 @@
|
|||
"<IPython.core.display.Image object>"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"execution_count": 13,
|
||||
"metadata": {
|
||||
"image/jpeg": {
|
||||
"width": 600
|
||||
|
|
@ -415,7 +426,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -438,12 +449,12 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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\n",
|
||||
"image/png": "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\n",
|
||||
"text/plain": [
|
||||
"<IPython.core.display.Image object>"
|
||||
]
|
||||
|
|
@ -472,12 +483,12 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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\n",
|
||||
"image/png": "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\n",
|
||||
"text/plain": [
|
||||
"<IPython.core.display.Image object>"
|
||||
]
|
||||
|
|
@ -504,12 +515,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"settings = openmc.Settings()\n",
|
||||
"settings.dagmc = True\n",
|
||||
"settings.batches = 10\n",
|
||||
"settings.particles = 5000\n",
|
||||
"settings.run_mode = \"fixed source\"\n",
|
||||
|
|
@ -543,12 +553,12 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"...and setup a couple mesh tallies. One for the kettle, and one for the water inside."
|
||||
"...and setup a couple of mesh tallies. One for the kettle, and one for the water inside."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -576,7 +586,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -611,15 +621,16 @@
|
|||
" Copyright | 2011-2021 MIT and OpenMC contributors\n",
|
||||
" License | https://docs.openmc.org/en/latest/license.html\n",
|
||||
" Version | 0.13.0-dev\n",
|
||||
" Git SHA1 | 3dd81a1316ac3b5a0633e4b7a290f3bc97a066d9\n",
|
||||
" Date/Time | 2021-06-26 11:58:41\n",
|
||||
" Git SHA1 | 0aafa81907ac79b9bdb4a86aede0b63fee3a9a9b\n",
|
||||
" Date/Time | 2021-06-30 09:02:13\n",
|
||||
" OpenMP Threads | 2\n",
|
||||
"\n",
|
||||
" Reading settings XML file...\n",
|
||||
" Reading cross sections XML file...\n",
|
||||
" Reading materials XML file...\n",
|
||||
" Reading DAGMC geometry...\n",
|
||||
"Using the DOUBLE-DOWN interface to Embree.\n",
|
||||
" Reading geometry XML file...\n",
|
||||
"Set overlap thickness = 0\n",
|
||||
"Set numerical precision = 0.001\n",
|
||||
"Loading file dagmc.h5m\n",
|
||||
"Initializing the GeomQueryTool...\n",
|
||||
"Using faceting tolerance: 0.001\n",
|
||||
|
|
@ -655,16 +666,16 @@
|
|||
"\n",
|
||||
" =======================> TIMING STATISTICS <=======================\n",
|
||||
"\n",
|
||||
" Total time for initialization = 9.0900e-01 seconds\n",
|
||||
" Reading cross sections = 4.7368e-01 seconds\n",
|
||||
" Total time in simulation = 4.5284e+00 seconds\n",
|
||||
" Time in transport only = 4.5248e+00 seconds\n",
|
||||
" Time in active batches = 4.5284e+00 seconds\n",
|
||||
" Time accumulating tallies = 2.4557e-04 seconds\n",
|
||||
" Time writing statepoints = 3.1711e-03 seconds\n",
|
||||
" Total time for finalization = 1.4047e-02 seconds\n",
|
||||
" Total time elapsed = 5.4540e+00 seconds\n",
|
||||
" Calculation Rate (active) = 11041.4 particles/second\n",
|
||||
" Total time for initialization = 4.8117e+00 seconds\n",
|
||||
" Reading cross sections = 4.6543e-01 seconds\n",
|
||||
" Total time in simulation = 1.4498e+01 seconds\n",
|
||||
" Time in transport only = 1.4493e+01 seconds\n",
|
||||
" Time in active batches = 1.4498e+01 seconds\n",
|
||||
" Time accumulating tallies = 3.1628e-04 seconds\n",
|
||||
" Time writing statepoints = 4.8840e-03 seconds\n",
|
||||
" Total time for finalization = 1.5489e-02 seconds\n",
|
||||
" Total time elapsed = 1.9328e+01 seconds\n",
|
||||
" Calculation Rate (active) = 3448.64 particles/second\n",
|
||||
"\n",
|
||||
" ============================> RESULTS <============================\n",
|
||||
"\n",
|
||||
|
|
@ -686,34 +697,37 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with openmc.StatePoint(\"statepoint.10.h5\") as sp:\n",
|
||||
" water_tally = sp.get_tally(scores=['flux'], id=water_tally.id)\n",
|
||||
" water_flux = water_tally.mean\n",
|
||||
" water_flux.shape = (40, 120)\n",
|
||||
" water_flux = water_flux[::-1, :]\n",
|
||||
"sp = openmc.StatePoint(\"statepoint.10.h5\")\n",
|
||||
"\n",
|
||||
" pot_tally = sp.get_tally(scores=['flux'], id=pot_tally.id)\n",
|
||||
" pot_flux = pot_tally.mean\n",
|
||||
" pot_flux.shape = (40, 120)\n",
|
||||
" pot_flux = pot_flux[::-1, :]"
|
||||
"water_tally = sp.get_tally(scores=['flux'], id=water_tally.id)\n",
|
||||
"water_flux = water_tally.mean\n",
|
||||
"water_flux.shape = (40, 120)\n",
|
||||
"water_flux = water_flux[::-1, :]\n",
|
||||
"\n",
|
||||
"pot_tally = sp.get_tally(scores=['flux'], id=pot_tally.id)\n",
|
||||
"pot_flux = pot_tally.mean\n",
|
||||
"pot_flux.shape = (40, 120)\n",
|
||||
"pot_flux = pot_flux[::-1, :]\n",
|
||||
"\n",
|
||||
"del sp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<matplotlib.image.AxesImage at 0x7fdea0a40b70>"
|
||||
"<matplotlib.image.AxesImage at 0x7f05093e09e8>"
|
||||
]
|
||||
},
|
||||
"execution_count": 20,
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -181,14 +181,15 @@
|
|||
"\n",
|
||||
"settings.run_mode = \"fixed source\"\n",
|
||||
"settings.batches = 10\n",
|
||||
"settings.particles = 100"
|
||||
"settings.particles = 100\n",
|
||||
"settings.export_to_xml()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And we'll indicate that we're using a CAD-based geometry."
|
||||
"Next we'll apply the DAGMC model as the root universe of the geometry."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -197,9 +198,9 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"settings.dagmc = True\n",
|
||||
"\n",
|
||||
"settings.export_to_xml()"
|
||||
"dagmc_univ = openmc.DAGMCUniverse(filename='dagmc.h5m')\n",
|
||||
"geometry = openmc.Geometry(root=dagmc_univ)\n",
|
||||
"geometry.export_to_xml()"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -246,15 +247,15 @@
|
|||
" Copyright | 2011-2020 MIT and OpenMC contributors\n",
|
||||
" License | https://docs.openmc.org/en/latest/license.html\n",
|
||||
" Version | 0.12.1-dev\n",
|
||||
" Git SHA1 | 8ae407c90e927af62bfdc8f150e96bfd5d7b2ec2\n",
|
||||
" Date/Time | 2021-01-06 09:17:05\n",
|
||||
" Git SHA1 | 9fb298b039bcd447c1a745cd9fea47f0d04eebdf\n",
|
||||
" Date/Time | 2021-03-04 13:34:25\n",
|
||||
" MPI Processes | 1\n",
|
||||
" OpenMP Threads | 2\n",
|
||||
" OpenMP Threads | 4\n",
|
||||
"\n",
|
||||
" Reading settings XML file...\n",
|
||||
" Reading cross sections XML file...\n",
|
||||
" Reading materials XML file...\n",
|
||||
" Reading DAGMC geometry...\n",
|
||||
" Reading geometry XML file...\n",
|
||||
"Set overlap thickness = 0\n",
|
||||
"Set numerical precision = 0.001\n",
|
||||
"Loading file dagmc.h5m\n",
|
||||
|
|
@ -317,16 +318,16 @@
|
|||
"\n",
|
||||
" =======================> TIMING STATISTICS <=======================\n",
|
||||
"\n",
|
||||
" Total time for initialization = 2.4196e+01 seconds\n",
|
||||
" Reading cross sections = 2.1428e+00 seconds\n",
|
||||
" Total time in simulation = 1.9512e-01 seconds\n",
|
||||
" Time in transport only = 1.9269e-01 seconds\n",
|
||||
" Time in active batches = 1.9512e-01 seconds\n",
|
||||
" Time accumulating tallies = 2.0220e-06 seconds\n",
|
||||
" Time writing statepoints = 2.2461e-03 seconds\n",
|
||||
" Total time for finalization = 1.8940e-06 seconds\n",
|
||||
" Total time elapsed = 2.4401e+01 seconds\n",
|
||||
" Calculation Rate (active) = 5125.02 particles/second\n",
|
||||
" Total time for initialization = 1.7970e+02 seconds\n",
|
||||
" Reading cross sections = 1.8083e+00 seconds\n",
|
||||
" Total time in simulation = 7.2061e-01 seconds\n",
|
||||
" Time in transport only = 7.1887e-01 seconds\n",
|
||||
" Time in active batches = 7.2061e-01 seconds\n",
|
||||
" Time accumulating tallies = 2.7050e-06 seconds\n",
|
||||
" Time writing statepoints = 1.5381e-03 seconds\n",
|
||||
" Total time for finalization = 1.1780e-06 seconds\n",
|
||||
" Total time elapsed = 1.8043e+02 seconds\n",
|
||||
" Calculation Rate (active) = 1387.71 particles/second\n",
|
||||
"\n",
|
||||
" ============================> RESULTS <============================\n",
|
||||
"\n",
|
||||
|
|
@ -352,7 +353,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"unstructured_mesh = openmc.UnstructuredMesh(\"manifold.h5m\", library='moab')\n",
|
||||
"unstructured_mesh = openmc.UnstructuredMesh(\"manifold.h5m\")\n",
|
||||
"\n",
|
||||
"mesh_filter = openmc.MeshFilter(unstructured_mesh)\n",
|
||||
"\n",
|
||||
|
|
@ -496,7 +497,7 @@
|
|||
"text": [
|
||||
"<?xml version='1.0' encoding='utf-8'?>\r\n",
|
||||
"<tallies>\r\n",
|
||||
" <mesh id=\"1\" library=\"moab\" type=\"unstructured\">\r\n",
|
||||
" <mesh id=\"1\" type=\"unstructured\">\r\n",
|
||||
" <filename>manifold.h5m</filename>\r\n",
|
||||
" </mesh>\r\n",
|
||||
" <filter id=\"1\" type=\"mesh\">\r\n",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <gsl/gsl>
|
||||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "dagmc.h"
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/memory.h" // for unique_ptr
|
||||
|
|
@ -63,16 +62,25 @@ namespace model {
|
|||
class Universe
|
||||
{
|
||||
public:
|
||||
|
||||
int32_t id_; //!< Unique ID
|
||||
vector<int32_t> cells_; //!< Cells within this universe
|
||||
|
||||
//! \brief Write universe information to an HDF5 group.
|
||||
//! \param group_id An HDF5 group id.
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
virtual void to_hdf5(hid_t group_id) const;
|
||||
|
||||
virtual bool find_cell(Particle &p) const;
|
||||
|
||||
BoundingBox bounding_box() const;
|
||||
|
||||
const GeometryType& geom_type() const { return geom_type_; }
|
||||
GeometryType& geom_type() { return geom_type_; }
|
||||
|
||||
unique_ptr<UniversePartitioner> partitioner_;
|
||||
|
||||
private:
|
||||
GeometryType geom_type_ = GeometryType::CSG;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -118,7 +126,9 @@ public:
|
|||
|
||||
//! Write all information needed to reconstruct the cell to an HDF5 group.
|
||||
//! \param group_id An HDF5 group id.
|
||||
virtual void to_hdf5(hid_t group_id) const = 0;
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
virtual void to_hdf5_inner(hid_t group_id) const = 0;
|
||||
|
||||
//! Get the BoundingBox for this cell.
|
||||
virtual BoundingBox bounding_box() const = 0;
|
||||
|
|
@ -164,10 +174,11 @@ public:
|
|||
|
||||
int32_t id_; //!< Unique ID
|
||||
std::string name_; //!< User-defined name
|
||||
Fill type_; //!< Material, universe, or lattice
|
||||
Fill type_; //!< Material, universe, or lattice
|
||||
int32_t universe_; //!< Universe # this cell is in
|
||||
int32_t fill_; //!< Universe # filling this cell
|
||||
int32_t n_instances_{0}; //!< Number of instances of this cell
|
||||
GeometryType geom_type_; //!< Geometric representation type (CSG, DAGMC)
|
||||
|
||||
//! \brief Index corresponding to this cell in distribcell arrays
|
||||
int distribcell_index_{C_NONE};
|
||||
|
|
@ -225,7 +236,7 @@ public:
|
|||
std::pair<double, int32_t>
|
||||
distance(Position r, Direction u, int32_t on_surface, Particle* p) const;
|
||||
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
void to_hdf5_inner(hid_t group_id) const override;
|
||||
|
||||
BoundingBox bounding_box() const;
|
||||
|
||||
|
|
@ -254,28 +265,6 @@ protected:
|
|||
vector<int32_t>::iterator start, const vector<int32_t>& rpn);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
||||
#ifdef DAGMC
|
||||
class DAGCell : public Cell
|
||||
{
|
||||
public:
|
||||
DAGCell();
|
||||
|
||||
bool contains(Position r, Direction u, int32_t on_surface) const;
|
||||
|
||||
std::pair<double, int32_t>
|
||||
distance(Position r, Direction u, int32_t on_surface, Particle* p) const;
|
||||
|
||||
BoundingBox bounding_box() const;
|
||||
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
moab::DagMC* dagmc_ptr_; //!< Pointer to DagMC instance
|
||||
int32_t dag_index_; //!< DagMC index of cell
|
||||
};
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
//! Speeds up geometry searches by grouping cells in a search tree.
|
||||
//
|
||||
|
|
@ -342,8 +331,9 @@ struct CellInstanceHash {
|
|||
|
||||
void read_cells(pugi::xml_node node);
|
||||
|
||||
|
||||
#ifdef DAGMC
|
||||
int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed);
|
||||
class DAGUniverse;
|
||||
#endif
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -379,6 +379,15 @@ enum class RunMode {
|
|||
// For non-accelerated regions on coarse mesh overlay
|
||||
constexpr int CMFD_NOACCEL {-1};
|
||||
|
||||
//==============================================================================
|
||||
// Geometry Constants
|
||||
|
||||
enum class GeometryType {
|
||||
CSG,
|
||||
DAG
|
||||
};
|
||||
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // OPENMC_CONSTANTS_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#ifndef OPENMC_DAGMC_H
|
||||
#define OPENMC_DAGMC_H
|
||||
|
||||
|
|
@ -6,27 +5,146 @@ namespace openmc {
|
|||
extern "C" const bool DAGMC_ENABLED;
|
||||
}
|
||||
|
||||
#ifdef DAGMC
|
||||
|
||||
#include "DagMC.hpp"
|
||||
// always include the XML interface header
|
||||
#include "openmc/xml_interface.h"
|
||||
#include "openmc/position.h"
|
||||
|
||||
//==============================================================================
|
||||
// Functions that are always defined
|
||||
//==============================================================================
|
||||
|
||||
namespace openmc {
|
||||
|
||||
namespace model {
|
||||
extern moab::DagMC* DAG;
|
||||
void read_dagmc_universes(pugi::xml_node node);
|
||||
void check_dagmc_root_univ();
|
||||
|
||||
}
|
||||
|
||||
#ifdef DAGMC
|
||||
|
||||
#include "DagMC.hpp"
|
||||
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/particle.h"
|
||||
#include "openmc/position.h"
|
||||
#include "openmc/surface.h"
|
||||
|
||||
class UWUW;
|
||||
|
||||
namespace openmc {
|
||||
|
||||
class DAGSurface : public Surface {
|
||||
public:
|
||||
DAGSurface(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx);
|
||||
|
||||
double evaluate(Position r) const override;
|
||||
double distance(Position r, Direction u, bool coincident) const override;
|
||||
Direction normal(Position r) const override;
|
||||
Direction reflect(Position r, Direction u, Particle* p) const override;
|
||||
|
||||
inline void to_hdf5_inner(hid_t group_id) const override {};
|
||||
|
||||
// Accessor methods
|
||||
const std::shared_ptr<moab::DagMC>& dagmc_ptr() const { return dagmc_ptr_; }
|
||||
int32_t dag_index() const { return dag_index_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<moab::DagMC> dagmc_ptr_; //!< Pointer to DagMC instance
|
||||
int32_t dag_index_; //!< DagMC index of surface
|
||||
};
|
||||
|
||||
class DAGCell : public Cell {
|
||||
public:
|
||||
DAGCell(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx);
|
||||
|
||||
bool contains(Position r, Direction u, int32_t on_surface) const override;
|
||||
|
||||
std::pair<double, int32_t>
|
||||
distance(Position r, Direction u, int32_t on_surface, Particle* p) const override;
|
||||
|
||||
BoundingBox bounding_box() const override;
|
||||
|
||||
void to_hdf5_inner(hid_t group_id) const override;
|
||||
|
||||
// Accessor methods
|
||||
const std::shared_ptr<moab::DagMC>& dagmc_ptr() const { return dagmc_ptr_; }
|
||||
int32_t dag_index() const { return dag_index_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<moab::DagMC> dagmc_ptr_; //!< Pointer to DagMC instance
|
||||
int32_t dag_index_; //!< DagMC index of cell
|
||||
};
|
||||
|
||||
class DAGUniverse : public Universe {
|
||||
|
||||
public:
|
||||
|
||||
explicit DAGUniverse(pugi::xml_node node);
|
||||
|
||||
//! Create a new DAGMC universe
|
||||
//! \param[in] filename Name of the DAGMC file
|
||||
//! \param[in] auto_geom_ids Whether or not to automatically assign cell and surface IDs
|
||||
//! \param[in] auto_mat_ids Whether or not to automatically assign material IDs
|
||||
explicit DAGUniverse(const std::string& filename,
|
||||
bool auto_geom_ids = false,
|
||||
bool auto_mat_ids = false);
|
||||
|
||||
//! Initialize the DAGMC accel. data structures, indices, material assignments, etc.
|
||||
void initialize();
|
||||
|
||||
//! Reads UWUW materials and returns an ID map
|
||||
void read_uwuw_materials();
|
||||
//! Indicates whether or not UWUW materials are present
|
||||
//! \return True if UWUW materials are present, False if not
|
||||
bool uses_uwuw() const;
|
||||
|
||||
//! Returns the index to the implicit complement's index in OpenMC for this DAGMC universe
|
||||
int32_t implicit_complement_idx() const;
|
||||
|
||||
//! Transform UWUW materials into an OpenMC-readable XML format
|
||||
//! \return A string representing a materials.xml file of the UWUW materials in this universe
|
||||
std::string get_uwuw_materials_xml() const;
|
||||
|
||||
//! Writes the UWUW material file to XML (for debugging purposes)
|
||||
void write_uwuw_materials_xml(const std::string& outfile = "uwuw_materials.xml") const;
|
||||
|
||||
//! Assign a material to a cell based
|
||||
//! \param[in] mat_string The DAGMC material assignment string
|
||||
//! \param[in] c The OpenMC cell to which the material is assigned
|
||||
void legacy_assign_material(std::string mat_string,
|
||||
std::unique_ptr<DAGCell>& c) const;
|
||||
|
||||
//! Generate a string representing the ranges of IDs present in the DAGMC model.
|
||||
//! Contiguous chunks of IDs are represented as a range (i.e. 1-10). If there is
|
||||
//! a single ID a chunk, it will be represented as a single number (i.e. 2, 4, 6, 8).
|
||||
//! \param[in] dim Dimension of the entities
|
||||
//! \return A string of the ID ranges for entities of dimension \p dim
|
||||
std::string dagmc_ids_for_dim(int dim) const;
|
||||
|
||||
bool find_cell(Particle &p) const override;
|
||||
|
||||
void to_hdf5(hid_t universes_group) const override;
|
||||
|
||||
// Data Members
|
||||
std::shared_ptr<moab::DagMC> dagmc_instance_; //!< DAGMC Instance for this universe
|
||||
int32_t cell_idx_offset_; //!< An offset to the start of the cells in this universe in OpenMC's cell vector
|
||||
int32_t surf_idx_offset_; //!< An offset to the start of the surfaces in this universe in OpenMC's surface vector
|
||||
|
||||
// Accessors
|
||||
bool has_graveyard() const { return has_graveyard_; }
|
||||
|
||||
private:
|
||||
std::string filename_; //!< Name of the DAGMC file used to create this universe
|
||||
std::shared_ptr<UWUW> uwuw_; //!< Pointer to the UWUW instance for this universe
|
||||
bool adjust_geometry_ids_; //!< Indicates whether or not to automatically generate new cell and surface IDs for the universe
|
||||
bool adjust_material_ids_; //!< Indicates whether or not to automatically generate new material IDs for the universe
|
||||
bool has_graveyard_; //!< Indicates if the DAGMC geometry has a "graveyard" volume
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void load_dagmc_geometry();
|
||||
void free_memory_dagmc();
|
||||
void read_geometry_dagmc();
|
||||
bool read_uwuw_materials(pugi::xml_document& doc);
|
||||
bool get_uwuw_materials_xml(std::string& s);
|
||||
int32_t next_cell(DAGUniverse* dag_univ, DAGCell* cur_cell, DAGSurface* surf_xed);
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ extern bool check_overlaps; //!< check overlaps in geometry?
|
|||
extern bool confidence_intervals; //!< use confidence intervals for results?
|
||||
extern bool create_fission_neutrons; //!< create fission neutrons (fixed source)?
|
||||
extern "C" bool cmfd_run; //!< is a CMFD run?
|
||||
extern "C" bool dagmc; //!< indicator of DAGMC geometry
|
||||
extern bool delayed_photon_scaling; //!< Scale fission photon yield to include delayed
|
||||
extern "C" bool entropy_on; //!< calculate Shannon entropy?
|
||||
extern bool event_based; //!< use event-based mode (instead of history-based)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "dagmc.h"
|
||||
#include "openmc/boundary_condition.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/memory.h" // for unique_ptr
|
||||
|
|
@ -30,7 +29,7 @@ namespace model {
|
|||
} // namespace model
|
||||
|
||||
//==============================================================================
|
||||
//! Coordinates for an axis-aligned cuboid bounding a geometric object.
|
||||
//! Coordinates for an axis-aligned cuboid that bounds a geometric object.
|
||||
//==============================================================================
|
||||
|
||||
struct BoundingBox
|
||||
|
|
@ -88,6 +87,7 @@ public:
|
|||
int id_; //!< Unique ID
|
||||
std::string name_; //!< User-defined name
|
||||
std::shared_ptr<BoundaryCondition> bc_ {nullptr}; //!< Boundary condition
|
||||
GeometryType geom_type_; //!< Geometry type indicator (CSG or DAGMC)
|
||||
bool surf_source_ {false}; //!< Activate source banking for the surface?
|
||||
|
||||
explicit Surface(pugi::xml_node surf_node);
|
||||
|
|
@ -134,10 +134,13 @@ public:
|
|||
|
||||
//! Write all information needed to reconstruct the surface to an HDF5 group.
|
||||
//! \param group_id An HDF5 group id.
|
||||
virtual void to_hdf5(hid_t group_id) const = 0;
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
//! Get the BoundingBox for this surface.
|
||||
virtual BoundingBox bounding_box(bool /*pos_side*/) const { return {}; }
|
||||
|
||||
protected:
|
||||
virtual void to_hdf5_inner(hid_t group_id) const = 0;
|
||||
};
|
||||
|
||||
class CSGSurface : public Surface
|
||||
|
|
@ -146,33 +149,10 @@ public:
|
|||
explicit CSGSurface(pugi::xml_node surf_node);
|
||||
CSGSurface();
|
||||
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
protected:
|
||||
virtual void to_hdf5_inner(hid_t group_id) const = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
//! A `Surface` representing a DAGMC-based surface in DAGMC.
|
||||
//==============================================================================
|
||||
#ifdef DAGMC
|
||||
class DAGSurface : public Surface
|
||||
{
|
||||
public:
|
||||
DAGSurface();
|
||||
|
||||
double evaluate(Position r) const;
|
||||
double distance(Position r, Direction u, bool coincident) const;
|
||||
Direction normal(Position r) const;
|
||||
Direction reflect(Position r, Direction u, Particle* p) const;
|
||||
|
||||
void to_hdf5(hid_t group_id) const;
|
||||
|
||||
moab::DagMC* dagmc_ptr_; //!< Pointer to DagMC instance
|
||||
int32_t dag_index_; //!< DagMC index of surface
|
||||
};
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
//! A plane perpendicular to the x-axis.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class Cell(IDManagerMixin):
|
|||
automatically be assigned.
|
||||
name : str, optional
|
||||
Name of the cell. If not specified, the name is the empty string.
|
||||
fill : openmc.Material or openmc.Universe or openmc.Lattice or None or iterable of openmc.Material, optional
|
||||
fill : openmc.Material or openmc.UniverseBase or openmc.Lattice or None or iterable of openmc.Material, optional
|
||||
Indicates what the region of space is filled with
|
||||
region : openmc.Region, optional
|
||||
Region of space that is assigned to the cell.
|
||||
|
|
@ -38,7 +38,7 @@ class Cell(IDManagerMixin):
|
|||
Unique identifier for the cell
|
||||
name : str
|
||||
Name of the cell
|
||||
fill : openmc.Material or openmc.Universe or openmc.Lattice or None or iterable of openmc.Material
|
||||
fill : openmc.Material or openmc.UniverseBase or openmc.Lattice or None or iterable of openmc.Material
|
||||
Indicates what the region of space is filled with. If None, the cell is
|
||||
treated as a void. An iterable of materials is used to fill repeated
|
||||
instances of a cell with different materials.
|
||||
|
|
@ -156,7 +156,7 @@ class Cell(IDManagerMixin):
|
|||
def fill_type(self):
|
||||
if isinstance(self.fill, openmc.Material):
|
||||
return 'material'
|
||||
elif isinstance(self.fill, openmc.Universe):
|
||||
elif isinstance(self.fill, openmc.UniverseBase):
|
||||
return 'universe'
|
||||
elif isinstance(self.fill, openmc.Lattice):
|
||||
return 'lattice'
|
||||
|
|
@ -278,11 +278,10 @@ class Cell(IDManagerMixin):
|
|||
cv.check_type('cell.fill[i]', f, openmc.Material)
|
||||
|
||||
elif not isinstance(fill, (openmc.Material, openmc.Lattice,
|
||||
openmc.Universe)):
|
||||
openmc.UniverseBase)):
|
||||
msg = ('Unable to set Cell ID="{0}" to use a non-Material or '
|
||||
'Universe fill "{1}"'.format(self._id, fill))
|
||||
raise ValueError(msg)
|
||||
|
||||
self._fill = fill
|
||||
|
||||
# Info about atom content can now be invalid
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from .cell import Cell
|
|||
from .material import Material
|
||||
from .mixin import IDManagerMixin
|
||||
from .surface import Surface
|
||||
from .universe import Universe
|
||||
from .universe import UniverseBase
|
||||
|
||||
|
||||
_FILTER_TYPES = (
|
||||
|
|
@ -408,8 +408,8 @@ class UniverseFilter(WithIDFilter):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
bins : openmc.Universe, int, or iterable thereof
|
||||
The Universes to tally. Either openmc.Universe objects or their
|
||||
bins : openmc.UniverseBase, int, or iterable thereof
|
||||
The Universes to tally. Either openmc.UniverseBase objects or their
|
||||
Integral ID numbers can be used.
|
||||
filter_id : int
|
||||
Unique identifier for the filter
|
||||
|
|
@ -417,14 +417,14 @@ class UniverseFilter(WithIDFilter):
|
|||
Attributes
|
||||
----------
|
||||
bins : Iterable of Integral
|
||||
openmc.Universe IDs.
|
||||
openmc.UniverseBase IDs.
|
||||
id : int
|
||||
Unique identifier for the filter
|
||||
num_bins : Integral
|
||||
The number of filter bins
|
||||
|
||||
"""
|
||||
expected_type = Universe
|
||||
expected_type = UniverseBase
|
||||
|
||||
|
||||
class MaterialFilter(WithIDFilter):
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ class Geometry:
|
|||
|
||||
Parameters
|
||||
----------
|
||||
root : openmc.Universe or Iterable of openmc.Cell, optional
|
||||
root : openmc.UniverseBase or Iterable of openmc.Cell, optional
|
||||
Root universe which contains all others, or an iterable of cells that
|
||||
should be used to create a root universe.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
root_universe : openmc.Universe
|
||||
root_universe : openmc.UniverseBase
|
||||
Root universe which contains all others
|
||||
bounding_box : 2-tuple of numpy.array
|
||||
Lower-left and upper-right coordinates of an axis-aligned bounding box
|
||||
|
|
@ -32,7 +32,7 @@ class Geometry:
|
|||
self._root_universe = None
|
||||
self._offsets = {}
|
||||
if root is not None:
|
||||
if isinstance(root, openmc.Universe):
|
||||
if isinstance(root, openmc.UniverseBase):
|
||||
self.root_universe = root
|
||||
else:
|
||||
univ = openmc.Universe()
|
||||
|
|
@ -50,7 +50,7 @@ class Geometry:
|
|||
|
||||
@root_universe.setter
|
||||
def root_universe(self, root_universe):
|
||||
check_type('root universe', root_universe, openmc.Universe)
|
||||
check_type('root universe', root_universe, openmc.UniverseBase)
|
||||
self._root_universe = root_universe
|
||||
|
||||
def add_volume_information(self, volume_calc):
|
||||
|
|
@ -159,6 +159,11 @@ class Geometry:
|
|||
for s1, s2 in periodic.items():
|
||||
surfaces[s1].periodic_surface = surfaces[s2]
|
||||
|
||||
# Add any DAGMC universes
|
||||
for elem in root.findall('dagmc_universe'):
|
||||
dag_univ = openmc.DAGMCUniverse.from_xml_element(elem)
|
||||
universes[dag_univ.id] = dag_univ
|
||||
|
||||
# Dictionary that maps each universe to a list of cells/lattices that
|
||||
# contain it (needed to determine which universe is the root)
|
||||
child_of = defaultdict(list)
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ class RectLattice(Lattice):
|
|||
|
||||
@Lattice.universes.setter
|
||||
def universes(self, universes):
|
||||
cv.check_iterable_type('lattice universes', universes, openmc.Universe,
|
||||
cv.check_iterable_type('lattice universes', universes, openmc.UniverseBase,
|
||||
min_depth=2, max_depth=3)
|
||||
self._universes = np.asarray(universes)
|
||||
|
||||
|
|
|
|||
|
|
@ -179,8 +179,7 @@ class Model:
|
|||
d.mkdir(parents=True)
|
||||
|
||||
self.settings.export_to_xml(d)
|
||||
if not self.settings.dagmc:
|
||||
self.geometry.export_to_xml(d)
|
||||
self.geometry.export_to_xml(d)
|
||||
|
||||
# If a materials collection was specified, export it. Otherwise, look
|
||||
# for all materials in the geometry and use that to automatically build
|
||||
|
|
|
|||
|
|
@ -44,8 +44,6 @@ class Settings:
|
|||
weight assigned to particles that are not killed after Russian
|
||||
roulette. Value of energy should be a float indicating energy in eV
|
||||
below which particle type will be killed.
|
||||
dagmc : bool
|
||||
Indicate that a CAD-based DAGMC geometry will be used.
|
||||
delayed_photon_scaling : bool
|
||||
Indicate whether to scale the fission photon yield by (EGP + EGD)/EGP
|
||||
where EGP is the energy release of prompt photons and EGD is the energy
|
||||
|
|
@ -269,8 +267,6 @@ class Settings:
|
|||
self._material_cell_offsets = None
|
||||
self._log_grid_bins = None
|
||||
|
||||
self._dagmc = False
|
||||
|
||||
self._event_based = None
|
||||
self._max_particles_in_flight = None
|
||||
|
||||
|
|
@ -434,10 +430,6 @@ class Settings:
|
|||
def log_grid_bins(self):
|
||||
return self._log_grid_bins
|
||||
|
||||
@property
|
||||
def dagmc(self):
|
||||
return self._dagmc
|
||||
|
||||
@property
|
||||
def event_based(self):
|
||||
return self._event_based
|
||||
|
|
@ -633,11 +625,6 @@ class Settings:
|
|||
cv.check_type('photon transport', photon_transport, bool)
|
||||
self._photon_transport = photon_transport
|
||||
|
||||
@dagmc.setter
|
||||
def dagmc(self, dagmc):
|
||||
cv.check_type('dagmc geometry', dagmc, bool)
|
||||
self._dagmc = dagmc
|
||||
|
||||
@ptables.setter
|
||||
def ptables(self, ptables):
|
||||
cv.check_type('probability tables', ptables, bool)
|
||||
|
|
@ -1125,11 +1112,6 @@ class Settings:
|
|||
elem = ET.SubElement(root, "log_grid_bins")
|
||||
elem.text = str(self._log_grid_bins)
|
||||
|
||||
def _create_dagmc_subelement(self, root):
|
||||
if self._dagmc:
|
||||
elem = ET.SubElement(root, "dagmc")
|
||||
elem.text = str(self._dagmc).lower()
|
||||
|
||||
def _eigenvalue_from_xml_element(self, root):
|
||||
elem = root.find('eigenvalue')
|
||||
if elem is not None:
|
||||
|
|
@ -1407,11 +1389,6 @@ class Settings:
|
|||
if text is not None:
|
||||
self.log_grid_bins = int(text)
|
||||
|
||||
def _dagmc_from_xml_element(self, root):
|
||||
text = get_text(root, 'dagmc')
|
||||
if text is not None:
|
||||
self.dagmc = text in ('true', '1')
|
||||
|
||||
def export_to_xml(self, path='settings.xml'):
|
||||
"""Export simulation settings to an XML file.
|
||||
|
||||
|
|
@ -1465,7 +1442,6 @@ class Settings:
|
|||
self._create_max_particles_in_flight_subelement(root_element)
|
||||
self._create_material_cell_offsets_subelement(root_element)
|
||||
self._create_log_grid_bins_subelement(root_element)
|
||||
self._create_dagmc_subelement(root_element)
|
||||
|
||||
# Clean the indentation in the file to be user-readable
|
||||
clean_indentation(root_element)
|
||||
|
|
@ -1539,7 +1515,6 @@ class Settings:
|
|||
settings._max_particles_in_flight_from_xml_element(root)
|
||||
settings._material_cell_offsets_from_xml_element(root)
|
||||
settings._log_grid_bins_from_xml_element(root)
|
||||
settings._dagmc_from_xml_element(root)
|
||||
|
||||
# TODO: Get volume calculations
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,9 @@ class Summary:
|
|||
def _read_surfaces(self):
|
||||
for group in self._f['geometry/surfaces'].values():
|
||||
surface = openmc.Surface.from_hdf5(group)
|
||||
self._fast_surfaces[surface.id] = surface
|
||||
# surface may be None for DAGMC surfaces
|
||||
if surface:
|
||||
self._fast_surfaces[surface.id] = surface
|
||||
|
||||
def _read_cells(self):
|
||||
|
||||
|
|
@ -176,7 +178,11 @@ class Summary:
|
|||
|
||||
def _read_universes(self):
|
||||
for group in self._f['geometry/universes'].values():
|
||||
universe = openmc.Universe.from_hdf5(group, self._fast_cells)
|
||||
geom_type = group.get('geom_type')
|
||||
if geom_type and geom_type[()].decode() == 'dagmc':
|
||||
universe = openmc.DAGMCUniverse.from_hdf5(group)
|
||||
else:
|
||||
universe = openmc.Universe.from_hdf5(group, self._fast_cells)
|
||||
self._fast_universes[universe.id] = universe
|
||||
|
||||
def _read_lattices(self):
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ class Surface(IDManagerMixin, ABC):
|
|||
kwargs = {}
|
||||
kwargs['surface_id'] = int(elem.get('id'))
|
||||
kwargs['boundary_type'] = elem.get('boundary', 'transmission')
|
||||
kwargs['name'] = elem.get('name')
|
||||
coeffs = [float(x) for x in elem.get('coeffs').split()]
|
||||
kwargs.update(dict(zip(cls._coeff_keys, coeffs)))
|
||||
|
||||
|
|
@ -453,13 +454,19 @@ class Surface(IDManagerMixin, ABC):
|
|||
|
||||
"""
|
||||
|
||||
# If this is a DAGMC surface, do nothing for now
|
||||
geom_type = group.get('geom_type')
|
||||
if geom_type and geom_type[()].decode() == 'dagmc':
|
||||
return
|
||||
|
||||
surface_id = int(group.name.split('/')[-1].lstrip('surface '))
|
||||
name = group['name'][()].decode() if 'name' in group else ''
|
||||
surf_type = group['type'][()].decode()
|
||||
|
||||
bc = group['boundary_type'][()].decode()
|
||||
coeffs = group['coefficients'][...]
|
||||
kwargs = {'boundary_type': bc, 'name': name, 'surface_id': surface_id}
|
||||
|
||||
surf_type = group['type'][()].decode()
|
||||
cls = _SURFACE_CLASSES[surf_type]
|
||||
|
||||
return cls(*coeffs, **kwargs)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,154 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Iterable
|
||||
from copy import copy, deepcopy
|
||||
from numbers import Real
|
||||
import random
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
from ._xml import get_text
|
||||
from .mixin import IDManagerMixin
|
||||
from .plots import _SVG_COLORS
|
||||
|
||||
|
||||
class Universe(IDManagerMixin):
|
||||
class UniverseBase(ABC, IDManagerMixin):
|
||||
"""A collection of cells that can be repeated.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
Unique identifier of the universe
|
||||
name : str
|
||||
Name of the universe
|
||||
"""
|
||||
|
||||
next_id = 1
|
||||
used_ids = set()
|
||||
|
||||
def __init__(self, universe_id=None, name=''):
|
||||
# Initialize Universe class attributes
|
||||
self.id = universe_id
|
||||
self.name = name
|
||||
self._volume = None
|
||||
self._atoms = {}
|
||||
|
||||
# Keys - Cell IDs
|
||||
# Values - Cells
|
||||
self._cells = OrderedDict()
|
||||
|
||||
def __repr__(self):
|
||||
string = 'Universe\n'
|
||||
string += '{: <16}=\t{}\n'.format('\tID', self._id)
|
||||
string += '{: <16}=\t{}\n'.format('\tName', self._name)
|
||||
return string
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('universe name', name, str)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
if volume is not None:
|
||||
cv.check_type('universe volume', volume, Real)
|
||||
self._volume = volume
|
||||
|
||||
def add_volume_information(self, volume_calc):
|
||||
"""Add volume information to a universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
volume_calc : openmc.VolumeCalculation
|
||||
Results from a stochastic volume calculation
|
||||
|
||||
"""
|
||||
if volume_calc.domain_type == 'universe':
|
||||
if self.id in volume_calc.volumes:
|
||||
self._volume = volume_calc.volumes[self.id].n
|
||||
self._atoms = volume_calc.atoms[self.id]
|
||||
else:
|
||||
raise ValueError('No volume information found for this universe.')
|
||||
else:
|
||||
raise ValueError('No volume information found for this universe.')
|
||||
|
||||
@abstractmethod
|
||||
def create_xml_subelement(self, xml_element, memo=None):
|
||||
"""Add the universe xml representation to an incoming xml element
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xml_element : xml.etree.ElementTree.Element
|
||||
XML element to be added to
|
||||
|
||||
memo : set or None
|
||||
A set of object id's representing geometry entities already
|
||||
written to the xml_element. This parameter is used internally
|
||||
and should not be specified by users.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
"""
|
||||
|
||||
def clone(self, clone_materials=True, clone_regions=True, memo=None):
|
||||
"""Create a copy of this universe with a new unique ID, and clones
|
||||
all cells within this universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
clone_materials : bool
|
||||
Whether to create separates copies of the materials filling cells
|
||||
contained in this universe.
|
||||
clone_regions : bool
|
||||
Whether to create separates copies of the regions bounding cells
|
||||
contained in this universe.
|
||||
memo : dict or None
|
||||
A nested dictionary of previously cloned objects. This parameter
|
||||
is used internally and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
clone : openmc.Universe
|
||||
The clone of this universe
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
# If no memoize'd clone exists, instantiate one
|
||||
if self not in memo:
|
||||
clone = deepcopy(self)
|
||||
clone.id = None
|
||||
|
||||
# Clone all cells for the universe clone
|
||||
clone._cells = OrderedDict()
|
||||
for cell in self._cells.values():
|
||||
clone.add_cell(cell.clone(clone_materials, clone_regions,
|
||||
memo))
|
||||
|
||||
# Memoize the clone
|
||||
memo[self] = clone
|
||||
|
||||
return memo[self]
|
||||
|
||||
|
||||
class Universe(UniverseBase):
|
||||
"""A collection of cells that can be repeated.
|
||||
|
||||
Parameters
|
||||
|
|
@ -44,42 +180,22 @@ class Universe(IDManagerMixin):
|
|||
|
||||
"""
|
||||
|
||||
next_id = 1
|
||||
used_ids = set()
|
||||
|
||||
def __init__(self, universe_id=None, name='', cells=None):
|
||||
# Initialize Cell class attributes
|
||||
self.id = universe_id
|
||||
self.name = name
|
||||
self._volume = None
|
||||
self._atoms = {}
|
||||
|
||||
# Keys - Cell IDs
|
||||
# Values - Cells
|
||||
self._cells = OrderedDict()
|
||||
super().__init__(universe_id, name)
|
||||
|
||||
if cells is not None:
|
||||
self.add_cells(cells)
|
||||
|
||||
def __repr__(self):
|
||||
string = 'Universe\n'
|
||||
string += '{: <16}=\t{}\n'.format('\tID', self._id)
|
||||
string += '{: <16}=\t{}\n'.format('\tName', self._name)
|
||||
string = super().__repr__()
|
||||
string += '{: <16}=\t{}\n'.format('\tGeom', 'CSG')
|
||||
string += '{: <16}=\t{}\n'.format('\tCells', list(self._cells.keys()))
|
||||
return string
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def cells(self):
|
||||
return self._cells
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@property
|
||||
def bounding_box(self):
|
||||
regions = [c.region for c in self.cells.values()
|
||||
|
|
@ -90,20 +206,6 @@ class Universe(IDManagerMixin):
|
|||
# Infinite bounding box
|
||||
return openmc.Intersection([]).bounding_box
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('universe name', name, str)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
if volume is not None:
|
||||
cv.check_type('universe volume', volume, Real)
|
||||
self._volume = volume
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, group, cells):
|
||||
"""Create universe from HDF5 group
|
||||
|
|
@ -133,24 +235,6 @@ class Universe(IDManagerMixin):
|
|||
|
||||
return universe
|
||||
|
||||
def add_volume_information(self, volume_calc):
|
||||
"""Add volume information to a universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
volume_calc : openmc.VolumeCalculation
|
||||
Results from a stochastic volume calculation
|
||||
|
||||
"""
|
||||
if volume_calc.domain_type == 'universe':
|
||||
if self.id in volume_calc.volumes:
|
||||
self._volume = volume_calc.volumes[self.id].n
|
||||
self._atoms = volume_calc.atoms[self.id]
|
||||
else:
|
||||
raise ValueError('No volume information found for this universe.')
|
||||
else:
|
||||
raise ValueError('No volume information found for this universe.')
|
||||
|
||||
def find(self, point):
|
||||
"""Find cells/universes/lattices which contain a given point
|
||||
|
||||
|
|
@ -480,66 +564,7 @@ class Universe(IDManagerMixin):
|
|||
|
||||
return universes
|
||||
|
||||
def clone(self, clone_materials=True, clone_regions=True, memo=None):
|
||||
"""Create a copy of this universe with a new unique ID, and clones
|
||||
all cells within this universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
clone_materials : bool
|
||||
Whether to create separates copies of the materials filling cells
|
||||
contained in this universe.
|
||||
clone_regions : bool
|
||||
Whether to create separates copies of the regions bounding cells
|
||||
contained in this universe.
|
||||
memo : dict or None
|
||||
A nested dictionary of previously cloned objects. This parameter
|
||||
is used internally and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
clone : openmc.Universe
|
||||
The clone of this universe
|
||||
|
||||
"""
|
||||
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
# If no nemoize'd clone exists, instantiate one
|
||||
if self not in memo:
|
||||
clone = deepcopy(self)
|
||||
clone.id = None
|
||||
|
||||
# Clone all cells for the universe clone
|
||||
clone._cells = OrderedDict()
|
||||
for cell in self._cells.values():
|
||||
clone.add_cell(cell.clone(clone_materials, clone_regions,
|
||||
memo))
|
||||
|
||||
# Memoize the clone
|
||||
memo[self] = clone
|
||||
|
||||
return memo[self]
|
||||
|
||||
def create_xml_subelement(self, xml_element, memo=None):
|
||||
"""Add the universe xml representation to an incoming xml element
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xml_element : xml.etree.ElementTree.Element
|
||||
XML element to be added to
|
||||
|
||||
memo : set or None
|
||||
A set of object id's representing geometry entities already
|
||||
written to the xml_element. This parameter is used internally
|
||||
and should not be specified by users.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
"""
|
||||
# Iterate over all Cells
|
||||
for cell in self._cells.values():
|
||||
|
||||
|
|
@ -600,3 +625,163 @@ class Universe(IDManagerMixin):
|
|||
cell._num_instances += 1
|
||||
if not instances_only:
|
||||
cell._paths.append(cell_path)
|
||||
|
||||
|
||||
class DAGMCUniverse(UniverseBase):
|
||||
"""A reference to a DAGMC file to be used in the model.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to the DAGMC file used to represent this universe.
|
||||
universe_id : int, optional
|
||||
Unique identifier of the universe. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
name : str, optional
|
||||
Name of the universe. If not specified, the name is the empty string.
|
||||
auto_geom_ids : bool
|
||||
Set IDs automatically on initialization (True) or report overlaps
|
||||
in ID space between CSG and DAGMC (False)
|
||||
auto_mat_ids : bool
|
||||
Set IDs automatically on initialization (True) or report overlaps
|
||||
in ID space between OpenMC and UWUW materials (False)
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
Unique identifier of the universe
|
||||
name : str
|
||||
Name of the universe
|
||||
filename : str
|
||||
Path to the DAGMC file used to represent this universe.
|
||||
auto_geom_ids : bool
|
||||
Set IDs automatically on initialization (True) or report overlaps
|
||||
in ID space between CSG and DAGMC (False)
|
||||
auto_mat_ids : bool
|
||||
Set IDs automatically on initialization (True) or report overlaps
|
||||
in ID space between OpenMC and UWUW materials (False)
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
filename,
|
||||
universe_id=None,
|
||||
name='',
|
||||
auto_geom_ids=False,
|
||||
auto_mat_ids=False):
|
||||
super().__init__(universe_id, name)
|
||||
# Initialize class attributes
|
||||
self.filename = filename
|
||||
self.auto_geom_ids = auto_geom_ids
|
||||
self.auto_mat_ids = auto_mat_ids
|
||||
|
||||
def __repr__(self):
|
||||
string = super().__repr__()
|
||||
string += '{: <16}=\t{}\n'.format('\tGeom', 'DAGMC')
|
||||
string += '{: <16}=\t{}\n'.format('\tFile', self.filename)
|
||||
return string
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._filename
|
||||
|
||||
@filename.setter
|
||||
def filename(self, val):
|
||||
cv.check_type('DAGMC filename', val, str)
|
||||
self._filename = val
|
||||
|
||||
@property
|
||||
def auto_geom_ids(self):
|
||||
return self._auto_geom_ids
|
||||
|
||||
@auto_geom_ids.setter
|
||||
def auto_geom_ids(self, val):
|
||||
cv.check_type('DAGMC automatic geometry ids', val, bool)
|
||||
self._auto_geom_ids = val
|
||||
|
||||
@property
|
||||
def auto_mat_ids(self):
|
||||
return self._auto_mat_ids
|
||||
|
||||
@auto_mat_ids.setter
|
||||
def auto_mat_ids(self, val):
|
||||
cv.check_type('DAGMC automatic material ids', val, bool)
|
||||
self._auto_mat_ids = val
|
||||
|
||||
def get_all_cells(self, memo=None):
|
||||
return OrderedDict()
|
||||
|
||||
def get_all_materials(self, memo=None):
|
||||
return OrderedDict()
|
||||
|
||||
def create_xml_subelement(self, xml_element, memo=None):
|
||||
if memo and self in memo:
|
||||
return
|
||||
|
||||
if memo is not None:
|
||||
memo.add(self)
|
||||
|
||||
# Set xml element values
|
||||
dagmc_element = ET.Element('dagmc_universe')
|
||||
dagmc_element.set('id', str(self.id))
|
||||
|
||||
if self.auto_geom_ids:
|
||||
dagmc_element.set('auto_geom_ids', 'true')
|
||||
if self.auto_mat_ids:
|
||||
dagmc_element.set('auto_mat_ids', 'true')
|
||||
dagmc_element.set('filename', self.filename)
|
||||
xml_element.append(dagmc_element)
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, group):
|
||||
"""Create DAGMC universe from HDF5 group
|
||||
|
||||
Parameters
|
||||
----------
|
||||
group : h5py.Group
|
||||
Group in HDF5 file
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.DAGMCUniverse
|
||||
DAGMCUniverse instance
|
||||
|
||||
"""
|
||||
id = int(group.name.split('/')[-1].lstrip('universe '))
|
||||
fname = group['filename'][()].decode()
|
||||
name = group['name'][()].decode() if 'name' in group else None
|
||||
|
||||
out = cls(fname, universe_id=id, name=name)
|
||||
|
||||
out.auto_geom_ids = bool(group.attrs['auto_geom_ids'])
|
||||
out.auto_mat_ids = bool(group.attrs['auto_mat_ids'])
|
||||
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def from_xml_element(cls, elem):
|
||||
"""Generate DAGMC universe from XML element
|
||||
|
||||
Parameters
|
||||
----------
|
||||
elem : xml.etree.ElementTree.Element
|
||||
`<dagmc_universe>` element
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.DAGMCUniverse
|
||||
DAGMCUniverse instance
|
||||
|
||||
"""
|
||||
id = int(get_text(elem, 'id'))
|
||||
fname = get_text(elem, 'filename')
|
||||
|
||||
out = cls(fname, universe_id=id)
|
||||
|
||||
name = get_text(elem, 'name')
|
||||
if name is not None:
|
||||
out.name = name
|
||||
|
||||
out.auto_geom_ids = bool(elem.get('auto_geom_ids'))
|
||||
out.auto_mat_ids = bool(elem.get('auto_mat_ids'))
|
||||
|
||||
return out
|
||||
|
|
|
|||
238
src/cell.cpp
238
src/cell.cpp
|
|
@ -22,7 +22,6 @@
|
|||
#include "openmc/material.h"
|
||||
#include "openmc/nuclide.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/surface.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -194,6 +193,9 @@ Universe::to_hdf5(hid_t universes_group) const
|
|||
// Create a group for this universe.
|
||||
auto group = create_group(universes_group, fmt::format("universe {}", id_));
|
||||
|
||||
// Write the geometry representation type.
|
||||
write_string(group, "geom_type", "csg", false);
|
||||
|
||||
// Write the contained cells.
|
||||
if (cells_.size() > 0) {
|
||||
vector<int32_t> cell_ids;
|
||||
|
|
@ -204,6 +206,31 @@ Universe::to_hdf5(hid_t universes_group) const
|
|||
close_group(group);
|
||||
}
|
||||
|
||||
bool
|
||||
Universe::find_cell(Particle& p) const {
|
||||
const auto& cells {
|
||||
!partitioner_
|
||||
? cells_
|
||||
: partitioner_->get_cells(p.r_local(), p.u_local())
|
||||
};
|
||||
|
||||
for (auto it = cells.begin(); it != cells.end(); it++) {
|
||||
int32_t i_cell = *it;
|
||||
int32_t i_univ = p.coord(p.n_coord()-1).universe;
|
||||
if (model::cells[i_cell]->universe_ != i_univ) continue;
|
||||
|
||||
// Check if this cell contains the particle;
|
||||
Position r {p.r_local()};
|
||||
Direction u {p.u_local()};
|
||||
auto surf = p.surface();
|
||||
if (model::cells[i_cell]->contains(r, u, surf)) {
|
||||
p.coord(p.n_coord()-1).cell = i_cell;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BoundingBox Universe::bounding_box() const {
|
||||
BoundingBox bbox = {INFTY, -INFTY, INFTY, -INFTY, INFTY, -INFTY};
|
||||
if (cells_.size() == 0) {
|
||||
|
|
@ -282,14 +309,78 @@ Cell::set_temperature(double T, int32_t instance, bool set_contained)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::to_hdf5(hid_t cell_group) const {
|
||||
|
||||
// Create a group for this cell.
|
||||
auto group = create_group(cell_group, fmt::format("cell {}", id_));
|
||||
|
||||
if (!name_.empty()) {
|
||||
write_string(group, "name", name_, false);
|
||||
}
|
||||
|
||||
write_dataset(group, "universe", model::universes[universe_]->id_);
|
||||
|
||||
to_hdf5_inner(group);
|
||||
|
||||
// Write fill information.
|
||||
if (type_ == Fill::MATERIAL) {
|
||||
write_dataset(group, "fill_type", "material");
|
||||
std::vector<int32_t> mat_ids;
|
||||
for (auto i_mat : material_) {
|
||||
if (i_mat != MATERIAL_VOID) {
|
||||
mat_ids.push_back(model::materials[i_mat]->id_);
|
||||
} else {
|
||||
mat_ids.push_back(MATERIAL_VOID);
|
||||
}
|
||||
}
|
||||
if (mat_ids.size() == 1) {
|
||||
write_dataset(group, "material", mat_ids[0]);
|
||||
} else {
|
||||
write_dataset(group, "material", mat_ids);
|
||||
}
|
||||
|
||||
std::vector<double> temps;
|
||||
for (auto sqrtkT_val : sqrtkT_)
|
||||
temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN);
|
||||
write_dataset(group, "temperature", temps);
|
||||
|
||||
} else if (type_ == Fill::UNIVERSE) {
|
||||
write_dataset(group, "fill_type", "universe");
|
||||
write_dataset(group, "fill", model::universes[fill_]->id_);
|
||||
if (translation_ != Position(0, 0, 0)) {
|
||||
write_dataset(group, "translation", translation_);
|
||||
}
|
||||
if (!rotation_.empty()) {
|
||||
if (rotation_.size() == 12) {
|
||||
std::array<double, 3> rot {rotation_[9], rotation_[10], rotation_[11]};
|
||||
write_dataset(group, "rotation", rot);
|
||||
} else {
|
||||
write_dataset(group, "rotation", rotation_);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (type_ == Fill::LATTICE) {
|
||||
write_dataset(group, "fill_type", "lattice");
|
||||
write_dataset(group, "lattice", model::lattices[fill_]->id_);
|
||||
}
|
||||
|
||||
close_group(group);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// CSGCell implementation
|
||||
//==============================================================================
|
||||
|
||||
CSGCell::CSGCell() {} // empty constructor
|
||||
// default constructor
|
||||
CSGCell::CSGCell() {
|
||||
geom_type_ = GeometryType::CSG;
|
||||
}
|
||||
|
||||
CSGCell::CSGCell(pugi::xml_node cell_node)
|
||||
{
|
||||
geom_type_ = GeometryType::CSG;
|
||||
|
||||
if (check_for_node(cell_node, "id")) {
|
||||
id_ = std::stoi(get_node_value(cell_node, "id"));
|
||||
} else {
|
||||
|
|
@ -526,16 +617,10 @@ CSGCell::distance(Position r, Direction u, int32_t on_surface, Particle* p) cons
|
|||
//==============================================================================
|
||||
|
||||
void
|
||||
CSGCell::to_hdf5(hid_t cell_group) const
|
||||
CSGCell::to_hdf5_inner(hid_t group_id) const
|
||||
{
|
||||
// Create a group for this cell.
|
||||
auto group = create_group(cell_group, fmt::format("cell {}", id_));
|
||||
|
||||
if (!name_.empty()) {
|
||||
write_string(group, "name", name_, false);
|
||||
}
|
||||
|
||||
write_dataset(group, "universe", model::universes[universe_]->id_);
|
||||
write_string(group_id, "geom_type", "csg", false);
|
||||
|
||||
// Write the region specification.
|
||||
if (!region_.empty()) {
|
||||
|
|
@ -556,52 +641,9 @@ CSGCell::to_hdf5(hid_t cell_group) const
|
|||
region_spec << " " << ((token > 0) ? surf_id : -surf_id);
|
||||
}
|
||||
}
|
||||
write_string(group, "region", region_spec.str(), false);
|
||||
write_string(group_id, "region", region_spec.str(), false);
|
||||
}
|
||||
|
||||
// Write fill information.
|
||||
if (type_ == Fill::MATERIAL) {
|
||||
write_dataset(group, "fill_type", "material");
|
||||
vector<int32_t> mat_ids;
|
||||
for (auto i_mat : material_) {
|
||||
if (i_mat != MATERIAL_VOID) {
|
||||
mat_ids.push_back(model::materials[i_mat]->id_);
|
||||
} else {
|
||||
mat_ids.push_back(MATERIAL_VOID);
|
||||
}
|
||||
}
|
||||
if (mat_ids.size() == 1) {
|
||||
write_dataset(group, "material", mat_ids[0]);
|
||||
} else {
|
||||
write_dataset(group, "material", mat_ids);
|
||||
}
|
||||
|
||||
vector<double> temps;
|
||||
for (auto sqrtkT_val : sqrtkT_)
|
||||
temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN);
|
||||
write_dataset(group, "temperature", temps);
|
||||
|
||||
} else if (type_ == Fill::UNIVERSE) {
|
||||
write_dataset(group, "fill_type", "universe");
|
||||
write_dataset(group, "fill", model::universes[fill_]->id_);
|
||||
if (translation_ != Position(0, 0, 0)) {
|
||||
write_dataset(group, "translation", translation_);
|
||||
}
|
||||
if (!rotation_.empty()) {
|
||||
if (rotation_.size() == 12) {
|
||||
array<double, 3> rot {rotation_[9], rotation_[10], rotation_[11]};
|
||||
write_dataset(group, "rotation", rot);
|
||||
} else {
|
||||
write_dataset(group, "rotation", rotation_);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (type_ == Fill::LATTICE) {
|
||||
write_dataset(group, "fill_type", "lattice");
|
||||
write_dataset(group, "lattice", model::lattices[fill_]->id_);
|
||||
}
|
||||
|
||||
close_group(group);
|
||||
}
|
||||
|
||||
BoundingBox CSGCell::bounding_box_simple() const {
|
||||
|
|
@ -776,70 +818,6 @@ CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// DAGMC Cell implementation
|
||||
//==============================================================================
|
||||
#ifdef DAGMC
|
||||
DAGCell::DAGCell() : Cell{} { simple_ = true; };
|
||||
|
||||
std::pair<double, int32_t>
|
||||
DAGCell::distance(Position r, Direction u, int32_t on_surface, Particle* p) const
|
||||
{
|
||||
Expects(p);
|
||||
// if we've changed direction or we're not on a surface,
|
||||
// reset the history and update last direction
|
||||
if (u != p->last_dir() || on_surface == 0) {
|
||||
p->history().reset();
|
||||
p->last_dir() = u;
|
||||
}
|
||||
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
moab::EntityHandle hit_surf;
|
||||
double dist;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
int surf_idx;
|
||||
if (hit_surf != 0) {
|
||||
surf_idx = dagmc_ptr_->index_by_handle(hit_surf);
|
||||
} else {
|
||||
// indicate that particle is lost
|
||||
surf_idx = -1;
|
||||
dist = INFINITY;
|
||||
}
|
||||
|
||||
return {dist, surf_idx};
|
||||
}
|
||||
|
||||
bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
|
||||
int result = 0;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DAGCell::to_hdf5(hid_t group_id) const { return; }
|
||||
|
||||
BoundingBox DAGCell::bounding_box() const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
double min[3], max[3];
|
||||
rval = dagmc_ptr_->getobb(vol, min, max);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return {min[0], max[0], min[1], max[1], min[2], max[2]};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// UniversePartitioner implementation
|
||||
//==============================================================================
|
||||
|
|
@ -992,9 +970,6 @@ void read_cells(pugi::xml_node node)
|
|||
// Count the number of cells.
|
||||
int n_cells = 0;
|
||||
for (pugi::xml_node cell_node: node.children("cell")) {n_cells++;}
|
||||
if (n_cells == 0) {
|
||||
fatal_error("No cells found in geometry.xml!");
|
||||
}
|
||||
|
||||
// Loop over XML cell elements and populate the array.
|
||||
model::cells.reserve(n_cells);
|
||||
|
|
@ -1013,6 +988,8 @@ void read_cells(pugi::xml_node node)
|
|||
}
|
||||
}
|
||||
|
||||
read_dagmc_universes(node);
|
||||
|
||||
// Populate the Universe vector and map.
|
||||
for (int i = 0; i < model::cells.size(); i++) {
|
||||
int32_t uid = model::cells[i]->universe_;
|
||||
|
|
@ -1032,6 +1009,10 @@ void read_cells(pugi::xml_node node)
|
|||
if (settings::check_overlaps) {
|
||||
model::overlap_check_count.resize(model::cells.size(), 0);
|
||||
}
|
||||
|
||||
if (model::cells.size() == 0) {
|
||||
fatal_error("No cells were found in the geometry.xml file");
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1290,21 +1271,6 @@ openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DAGMC
|
||||
int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed)
|
||||
{
|
||||
moab::EntityHandle surf =
|
||||
surf_xed->dagmc_ptr_->entity_by_index(2, surf_xed->dag_index_);
|
||||
moab::EntityHandle vol =
|
||||
cur_cell->dagmc_ptr_->entity_by_index(3, cur_cell->dag_index_);
|
||||
|
||||
moab::EntityHandle new_vol;
|
||||
cur_cell->dagmc_ptr_->next_vol(surf, vol, new_vol);
|
||||
|
||||
return cur_cell->dagmc_ptr_->index_by_handle(new_vol);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" int cells_size() { return model::cells.size(); }
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
#include "openmc/capi.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/container_util.h"
|
||||
#ifdef DAGMC
|
||||
#include "openmc/dagmc.h"
|
||||
#endif
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/geometry_aux.h"
|
||||
#include "openmc/file_utils.h"
|
||||
|
|
@ -96,27 +93,12 @@ void read_cross_sections_xml()
|
|||
{
|
||||
pugi::xml_document doc;
|
||||
std::string filename = settings::path_input + "materials.xml";
|
||||
#ifdef DAGMC
|
||||
std::string s;
|
||||
bool found_uwuw_mats = false;
|
||||
if (settings::dagmc) {
|
||||
found_uwuw_mats = get_uwuw_materials_xml(s);
|
||||
}
|
||||
|
||||
if (found_uwuw_mats) {
|
||||
// if we found uwuw materials, load those
|
||||
doc.load_file(s.c_str());
|
||||
} else {
|
||||
#endif
|
||||
// Check if materials.xml exists
|
||||
if (!file_exists(filename)) {
|
||||
fatal_error("Material XML file '" + filename + "' does not exist.");
|
||||
}
|
||||
// Parse materials.xml file
|
||||
doc.load_file(filename.c_str());
|
||||
#ifdef DAGMC
|
||||
}
|
||||
#endif
|
||||
|
||||
auto root = doc.document_element();
|
||||
|
||||
|
|
|
|||
678
src/dagmc.cpp
678
src/dagmc.cpp
|
|
@ -1,16 +1,15 @@
|
|||
#include "openmc/dagmc.h"
|
||||
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/container_util.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/file_utils.h"
|
||||
#include "openmc/geometry.h"
|
||||
#include "openmc/geometry_aux.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/material.h"
|
||||
#include "openmc/string_utils.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/surface.h"
|
||||
|
||||
#ifdef DAGMC
|
||||
#include "uwuw.hpp"
|
||||
|
|
@ -37,189 +36,135 @@ const bool DAGMC_ENABLED = false;
|
|||
|
||||
namespace openmc {
|
||||
|
||||
const std::string DAGMC_FILENAME = "dagmc.h5m";
|
||||
//==============================================================================
|
||||
// DAGMC Universe implementation
|
||||
//==============================================================================
|
||||
|
||||
namespace model {
|
||||
|
||||
moab::DagMC* DAG;
|
||||
|
||||
} // namespace model
|
||||
|
||||
|
||||
std::string dagmc_file() {
|
||||
std::string filename = settings::path_input + DAGMC_FILENAME;
|
||||
if (!file_exists(filename)) {
|
||||
fatal_error("Geometry DAGMC file '" + filename + "' does not exist!");
|
||||
DAGUniverse::DAGUniverse(pugi::xml_node node) {
|
||||
if (check_for_node(node, "id")) {
|
||||
id_ = std::stoi(get_node_value(node, "id"));
|
||||
} else {
|
||||
fatal_error("Must specify the id of the DAGMC universe");
|
||||
}
|
||||
return filename;
|
||||
|
||||
if (check_for_node(node, "filename")) {
|
||||
filename_ = get_node_value(node, "filename");
|
||||
} else {
|
||||
fatal_error("Must specify a file for the DAGMC universe");
|
||||
}
|
||||
|
||||
adjust_geometry_ids_ = false;
|
||||
if (check_for_node(node, "auto_geom_ids")) {
|
||||
adjust_geometry_ids_ = get_node_value_bool(node, "auto_geom_ids");
|
||||
}
|
||||
|
||||
adjust_material_ids_ = false;
|
||||
if (check_for_node(node, "auto_mat_ids")) {
|
||||
adjust_material_ids_ = get_node_value_bool(node, "auto_mat_ids");
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
bool get_uwuw_materials_xml(std::string& s) {
|
||||
std::string filename = dagmc_file();
|
||||
UWUW uwuw(filename.c_str());
|
||||
|
||||
std::stringstream ss;
|
||||
bool uwuw_mats_present = false;
|
||||
if (uwuw.material_library.size() != 0) {
|
||||
uwuw_mats_present = true;
|
||||
// write header
|
||||
ss << "<?xml version=\"1.0\"?>\n";
|
||||
ss << "<materials>\n";
|
||||
const auto& mat_lib = uwuw.material_library;
|
||||
// write materials
|
||||
for (auto mat : mat_lib) { ss << mat.second->openmc("atom"); }
|
||||
// write footer
|
||||
ss << "</materials>";
|
||||
s = ss.str();
|
||||
DAGUniverse::DAGUniverse(const std::string& filename,
|
||||
bool auto_geom_ids,
|
||||
bool auto_mat_ids)
|
||||
: filename_(filename), adjust_geometry_ids_(auto_geom_ids), adjust_material_ids_(auto_mat_ids) {
|
||||
// determine the next universe id
|
||||
int32_t next_univ_id = 0;
|
||||
for (const auto& u : model::universes) {
|
||||
if (u->id_ > next_univ_id) next_univ_id = u->id_;
|
||||
}
|
||||
next_univ_id++;
|
||||
|
||||
return uwuw_mats_present;
|
||||
// set the universe id
|
||||
id_ = next_univ_id;
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
bool read_uwuw_materials(pugi::xml_document& doc) {
|
||||
std::string s;
|
||||
bool found_uwuw_mats = get_uwuw_materials_xml(s);
|
||||
if (found_uwuw_mats) {
|
||||
pugi::xml_parse_result result = doc.load_string(s.c_str());
|
||||
if (!result) {
|
||||
throw std::runtime_error{"Error reading UWUW materials"};
|
||||
}
|
||||
}
|
||||
return found_uwuw_mats;
|
||||
}
|
||||
void
|
||||
DAGUniverse::initialize() {
|
||||
geom_type() = GeometryType::DAG;
|
||||
|
||||
bool write_uwuw_materials_xml() {
|
||||
std::string s;
|
||||
bool found_uwuw_mats = get_uwuw_materials_xml(s);
|
||||
// if there is a material library in the file
|
||||
if (found_uwuw_mats) {
|
||||
// write a material.xml file
|
||||
std::ofstream mats_xml("materials.xml");
|
||||
mats_xml << s;
|
||||
mats_xml.close();
|
||||
// determine the next cell id
|
||||
int32_t next_cell_id = 0;
|
||||
for (const auto& c : model::cells) {
|
||||
if (c->id_ > next_cell_id) next_cell_id = c->id_;
|
||||
}
|
||||
cell_idx_offset_ = model::cells.size();
|
||||
next_cell_id++;
|
||||
|
||||
return found_uwuw_mats;
|
||||
}
|
||||
|
||||
void legacy_assign_material(std::string mat_string, DAGCell* c)
|
||||
{
|
||||
bool mat_found_by_name = false;
|
||||
// attempt to find a material with a matching name
|
||||
to_lower(mat_string);
|
||||
for (const auto& m : model::materials) {
|
||||
std::string m_name = m->name();
|
||||
to_lower(m_name);
|
||||
if (mat_string == m_name) {
|
||||
// assign the material with that name
|
||||
if (!mat_found_by_name) {
|
||||
mat_found_by_name = true;
|
||||
c->material_.push_back(m->id_);
|
||||
// report error if more than one material is found
|
||||
} else {
|
||||
fatal_error(fmt::format(
|
||||
"More than one material found with name {}. Please ensure materials "
|
||||
"have unique names if using this property to assign materials.",
|
||||
mat_string));
|
||||
}
|
||||
}
|
||||
// determine the next surface id
|
||||
int32_t next_surf_id = 0;
|
||||
for (const auto& s : model::surfaces) {
|
||||
if (s->id_ > next_surf_id) next_surf_id = s->id_;
|
||||
}
|
||||
surf_idx_offset_ = model::surfaces.size();
|
||||
next_surf_id++;
|
||||
|
||||
// if no material was set using a name, assign by id
|
||||
if (!mat_found_by_name) {
|
||||
try {
|
||||
auto id = std::stoi(mat_string);
|
||||
c->material_.emplace_back(id);
|
||||
} catch (const std::invalid_argument&) {
|
||||
fatal_error(fmt::format(
|
||||
"No material {} found for volume (cell) {}", mat_string, c->id_));
|
||||
}
|
||||
}
|
||||
|
||||
if (settings::verbosity >= 10) {
|
||||
const auto& m = model::materials[model::material_map.at(c->material_[0])];
|
||||
std::stringstream msg;
|
||||
msg << "DAGMC material " << mat_string << " was assigned";
|
||||
if (mat_found_by_name) {
|
||||
msg << " using material name: " << m->name_;
|
||||
} else {
|
||||
msg << " using material id: " << m->id_;
|
||||
}
|
||||
write_message(msg.str(), 10);
|
||||
}
|
||||
}
|
||||
|
||||
void load_dagmc_geometry()
|
||||
{
|
||||
if (!model::DAG) {
|
||||
model::DAG = new moab::DagMC();
|
||||
}
|
||||
// create a new DAGMC instance
|
||||
dagmc_instance_ = std::make_shared<moab::DagMC>();
|
||||
|
||||
// --- Materials ---
|
||||
|
||||
// create uwuw instance
|
||||
auto filename = dagmc_file();
|
||||
UWUW uwuw(filename.c_str());
|
||||
// read any UWUW materials from the file
|
||||
read_uwuw_materials();
|
||||
|
||||
// check for uwuw material definitions
|
||||
bool using_uwuw = !uwuw.material_library.empty();
|
||||
bool using_uwuw = uses_uwuw();
|
||||
|
||||
// notify user if UWUW materials are going to be used
|
||||
if (using_uwuw) {
|
||||
write_message("Found UWUW Materials in the DAGMC geometry file.", 6);
|
||||
}
|
||||
|
||||
int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC runs
|
||||
|
||||
// load the DAGMC geometry
|
||||
moab::ErrorCode rval = model::DAG->load_file(filename.c_str());
|
||||
filename_ = settings::path_input + filename_;
|
||||
if (!file_exists(filename_)) {
|
||||
fatal_error("Geometry DAGMC file '" + filename_ + "' does not exist!");
|
||||
}
|
||||
moab::ErrorCode rval = dagmc_instance_->load_file(filename_.c_str());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
|
||||
// initialize acceleration data structures
|
||||
rval = model::DAG->init_OBBTree();
|
||||
rval = dagmc_instance_->init_OBBTree();
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
|
||||
// parse model metadata
|
||||
dagmcMetaData DMD(model::DAG, false, false);
|
||||
dagmcMetaData DMD(dagmc_instance_.get(), false, false);
|
||||
DMD.load_property_data();
|
||||
|
||||
vector<std::string> keywords {"temp"};
|
||||
std::vector<std::string> keywords {"temp"};
|
||||
std::map<std::string, std::string> dum;
|
||||
std::string delimiters = ":/";
|
||||
rval = model::DAG->parse_properties(keywords, dum, delimiters.c_str());
|
||||
rval = dagmc_instance_->parse_properties(keywords, dum, delimiters.c_str());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
|
||||
// --- Cells (Volumes) ---
|
||||
|
||||
// initialize cell objects
|
||||
int n_cells = model::DAG->num_entities(3);
|
||||
int n_cells = dagmc_instance_->num_entities(3);
|
||||
moab::EntityHandle graveyard = 0;
|
||||
for (int i = 0; i < n_cells; i++) {
|
||||
moab::EntityHandle vol_handle = model::DAG->entity_by_index(3, i+1);
|
||||
moab::EntityHandle vol_handle = dagmc_instance_->entity_by_index(3, i + 1);
|
||||
|
||||
// set cell ids using global IDs
|
||||
DAGCell* c = new DAGCell();
|
||||
c->dag_index_ = i+1;
|
||||
c->id_ = model::DAG->id_by_index(3, c->dag_index_);
|
||||
c->dagmc_ptr_ = model::DAG;
|
||||
c->universe_ = dagmc_univ_id; // set to zero for now
|
||||
auto c = std::make_unique<DAGCell>(dagmc_instance_, i + 1);
|
||||
c->id_ = adjust_geometry_ids_ ? next_cell_id++ : dagmc_instance_->id_by_index(3, c->dag_index());
|
||||
c->universe_ = this->id_;
|
||||
c->fill_ = C_NONE; // no fill, single universe
|
||||
|
||||
model::cells.emplace_back(c);
|
||||
model::cell_map[c->id_] = i;
|
||||
|
||||
// Populate the Universe vector and dict
|
||||
auto it = model::universe_map.find(dagmc_univ_id);
|
||||
if (it == model::universe_map.end()) {
|
||||
model::universes.push_back(make_unique<Universe>());
|
||||
model::universes.back()->id_ = dagmc_univ_id;
|
||||
model::universes.back()->cells_.push_back(i);
|
||||
model::universe_map[dagmc_univ_id] = model::universes.size() - 1;
|
||||
auto in_map = model::cell_map.find(c->id_);
|
||||
if (in_map == model::cell_map.end()) {
|
||||
model::cell_map[c->id_] = model::cells.size();
|
||||
} else {
|
||||
model::universes[it->second]->cells_.push_back(i);
|
||||
warning(fmt::format("DAGMC Cell IDs: {}", dagmc_ids_for_dim(3)));
|
||||
fatal_error(fmt::format("Cell ID {} exists in both DAGMC Universe {} "
|
||||
"and the CSG geometry.", c->id_, this->id_));
|
||||
}
|
||||
|
||||
// MATERIALS
|
||||
// --- Materials ---
|
||||
|
||||
// determine volume material assignment
|
||||
std::string mat_str = DMD.get_volume_property("material", vol_handle);
|
||||
|
|
@ -241,12 +186,12 @@ void load_dagmc_geometry()
|
|||
if (using_uwuw) {
|
||||
// lookup material in uwuw if present
|
||||
std::string uwuw_mat = DMD.volume_material_property_data_eh[vol_handle];
|
||||
if (uwuw.material_library.count(uwuw_mat) != 0) {
|
||||
if (uwuw_->material_library.count(uwuw_mat) != 0) {
|
||||
// Note: material numbers are set by UWUW
|
||||
int mat_number = uwuw.material_library.get_material(uwuw_mat).metadata["mat_number"].asInt();
|
||||
int mat_number = uwuw_->material_library.get_material(uwuw_mat).metadata["mat_number"].asInt();
|
||||
c->material_.push_back(mat_number);
|
||||
} else {
|
||||
fatal_error(fmt::format("Material with value {} not found in the "
|
||||
fatal_error(fmt::format("Material with value '{}' not found in the "
|
||||
"UWUW material library", mat_str));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -258,19 +203,25 @@ void load_dagmc_geometry()
|
|||
std::string temp_value;
|
||||
|
||||
// no temperature if void
|
||||
if (c->material_[0] == MATERIAL_VOID) continue;
|
||||
if (c->material_[0] == MATERIAL_VOID) {
|
||||
model::cells.emplace_back(std::move(c));
|
||||
continue;
|
||||
}
|
||||
|
||||
// assign cell temperature
|
||||
const auto& mat = model::materials[model::material_map.at(c->material_[0])];
|
||||
if (model::DAG->has_prop(vol_handle, "temp")) {
|
||||
rval = model::DAG->prop_value(vol_handle, "temp", temp_value);
|
||||
if (dagmc_instance_->has_prop(vol_handle, "temp")) {
|
||||
rval = dagmc_instance_->prop_value(vol_handle, "temp", temp_value);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
double temp = std::stod(temp_value);
|
||||
c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp));
|
||||
} else {
|
||||
} else if (mat->temperature() > 0.0) {
|
||||
c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature()));
|
||||
} else {
|
||||
c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * settings::temperature_default));
|
||||
}
|
||||
|
||||
model::cells.emplace_back(std::move(c));
|
||||
}
|
||||
|
||||
// allocate the cell overlap count if necessary
|
||||
|
|
@ -278,40 +229,28 @@ void load_dagmc_geometry()
|
|||
model::overlap_check_count.resize(model::cells.size(), 0);
|
||||
}
|
||||
|
||||
if (!graveyard) {
|
||||
warning("No graveyard volume found in the DagMC model."
|
||||
"This may result in lost particles and rapid simulation failure.");
|
||||
}
|
||||
has_graveyard_ = graveyard;
|
||||
|
||||
// --- Surfaces ---
|
||||
|
||||
// initialize surface objects
|
||||
int n_surfaces = model::DAG->num_entities(2);
|
||||
|
||||
int n_surfaces = dagmc_instance_->num_entities(2);
|
||||
for (int i = 0; i < n_surfaces; i++) {
|
||||
moab::EntityHandle surf_handle = model::DAG->entity_by_index(2, i+1);
|
||||
moab::EntityHandle surf_handle = dagmc_instance_->entity_by_index(2, i+1);
|
||||
|
||||
// set cell ids using global IDs
|
||||
DAGSurface* s = new DAGSurface();
|
||||
s->dag_index_ = i+1;
|
||||
s->id_ = model::DAG->id_by_index(2, s->dag_index_);
|
||||
s->dagmc_ptr_ = model::DAG;
|
||||
|
||||
if (contains(settings::source_write_surf_id, s->id_)) {
|
||||
s->surf_source_ = true;
|
||||
}
|
||||
auto s = std::make_unique<DAGSurface>(dagmc_instance_, i+1);
|
||||
s->id_ = adjust_geometry_ids_ ? next_surf_id++ : dagmc_instance_->id_by_index(2, i+1);
|
||||
|
||||
// set BCs
|
||||
std::string bc_value = DMD.get_surface_property("boundary", surf_handle);
|
||||
to_lower(bc_value);
|
||||
if (bc_value.empty() || bc_value == "transmit" || bc_value == "transmission") {
|
||||
// Leave the bc_ a nullptr
|
||||
// set to transmission by default (nullptr)
|
||||
} else if (bc_value == "vacuum") {
|
||||
s->bc_ = std::make_shared<VacuumBC>();
|
||||
} else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") {
|
||||
s->bc_ = std::make_shared<ReflectiveBC>();
|
||||
} else if (bc_value == "white") {
|
||||
fatal_error("White boundary condition not supported in DAGMC.");
|
||||
} else if (bc_value == "periodic") {
|
||||
fatal_error("Periodic boundary condition not supported in DAGMC.");
|
||||
} else {
|
||||
|
|
@ -321,7 +260,7 @@ void load_dagmc_geometry()
|
|||
|
||||
// graveyard check
|
||||
moab::Range parent_vols;
|
||||
rval = model::DAG->moab_instance()->get_parent_meshsets(surf_handle, parent_vols);
|
||||
rval = dagmc_instance_->moab_instance()->get_parent_meshsets(surf_handle, parent_vols);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
|
||||
// if this surface belongs to the graveyard
|
||||
|
|
@ -331,26 +270,417 @@ void load_dagmc_geometry()
|
|||
}
|
||||
|
||||
// add to global array and map
|
||||
model::surfaces.emplace_back(s);
|
||||
model::surface_map[s->id_] = i;
|
||||
|
||||
auto in_map = model::surface_map.find(s->id_);
|
||||
if (in_map == model::surface_map.end()) {
|
||||
model::surface_map[s->id_] = model::surfaces.size();
|
||||
} else {
|
||||
warning(fmt::format("DAGMC Surface IDs: {}", dagmc_ids_for_dim(2)));
|
||||
fatal_error(fmt::format("Surface ID {} exists in both Universe {} "
|
||||
"and the CSG geometry.", s->id_, this->id_));
|
||||
}
|
||||
|
||||
model::surfaces.emplace_back(std::move(s));
|
||||
} // end surface loop
|
||||
}
|
||||
|
||||
std::string
|
||||
DAGUniverse::dagmc_ids_for_dim(int dim) const
|
||||
{
|
||||
// generate a vector of ids
|
||||
std::vector<int> id_vec;
|
||||
int n_ents = dagmc_instance_->num_entities(dim);
|
||||
for (int i = 1; i <= n_ents; i++) {
|
||||
id_vec.push_back(dagmc_instance_->id_by_index(dim, i));
|
||||
}
|
||||
|
||||
return;
|
||||
// sort the vector of ids
|
||||
std::sort(id_vec.begin(), id_vec.end());
|
||||
|
||||
// generate a string representation of the ID range(s)
|
||||
std::stringstream out;
|
||||
|
||||
int i = 0;
|
||||
int start_id = id_vec[0]; // initialize with first ID
|
||||
int stop_id;
|
||||
// loop over all cells in the universe
|
||||
while (i < n_ents) {
|
||||
|
||||
stop_id = id_vec[i];
|
||||
|
||||
// if the next ID is not in this contiguous set of IDS,
|
||||
// figure out how to write the string representing this set
|
||||
if (id_vec[i + 1] > stop_id + 1) {
|
||||
|
||||
if (start_id != stop_id) {
|
||||
// there are several IDs in a row, print condensed version (i.e. 1-10, 12-20)
|
||||
out << start_id << "-" << stop_id;
|
||||
} else {
|
||||
// only one ID in this contiguous block (i.e. 3, 5, 7, 9)
|
||||
out << start_id;
|
||||
}
|
||||
// insert a comma as long as we aren't in the last ID set
|
||||
if (i < n_ents - 1) { out << ", "; }
|
||||
|
||||
// if we are at the end of a set, set the start ID to the first value
|
||||
// in the next set.
|
||||
start_id = id_vec[++i];
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void read_geometry_dagmc()
|
||||
int32_t
|
||||
DAGUniverse::implicit_complement_idx() const {
|
||||
moab::EntityHandle ic;
|
||||
moab::ErrorCode rval = dagmc_instance_->geom_tool()->get_implicit_complement(ic);
|
||||
MB_CHK_SET_ERR_CONT(rval, "Failed to get implicit complement");
|
||||
// off-by-one: DAGMC indices start at one
|
||||
return cell_idx_offset_ + dagmc_instance_->index_by_handle(ic) - 1;
|
||||
}
|
||||
|
||||
bool
|
||||
DAGUniverse::find_cell(Particle &p) const {
|
||||
// if the particle isn't in any of the other DagMC
|
||||
// cells, place it in the implicit complement
|
||||
bool found = Universe::find_cell(p);
|
||||
if (!found && model::universe_map[this->id_] != model::root_universe) {
|
||||
p.coord(p.n_coord() - 1).cell = implicit_complement_idx();
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void
|
||||
DAGUniverse::to_hdf5(hid_t universes_group) const {
|
||||
// Create a group for this universe.
|
||||
auto group = create_group(universes_group, fmt::format("universe {}", id_));
|
||||
|
||||
// Write the geometry representation type.
|
||||
write_string(group, "geom_type", "dagmc", false);
|
||||
|
||||
// Write other properties of the DAGMC Universe
|
||||
write_string(group, "filename", filename_, false);
|
||||
write_attribute(group, "auto_geom_ids", static_cast<int>(adjust_geometry_ids_));
|
||||
write_attribute(group, "auto_mat_ids", static_cast<int>(adjust_material_ids_));
|
||||
|
||||
close_group(group);
|
||||
}
|
||||
|
||||
bool
|
||||
DAGUniverse::uses_uwuw() const
|
||||
{
|
||||
write_message("Reading DAGMC geometry...", 5);
|
||||
load_dagmc_geometry();
|
||||
|
||||
model::root_universe = find_root_universe();
|
||||
return !uwuw_->material_library.empty();
|
||||
}
|
||||
|
||||
void free_memory_dagmc()
|
||||
std::string
|
||||
DAGUniverse::get_uwuw_materials_xml() const
|
||||
{
|
||||
delete model::DAG;
|
||||
if (!uses_uwuw()) {
|
||||
throw std::runtime_error("This DAGMC Universe does not use UWUW materials");
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
// write header
|
||||
ss << "<?xml version=\"1.0\"?>\n";
|
||||
ss << "<materials>\n";
|
||||
const auto& mat_lib = uwuw_->material_library;
|
||||
// write materials
|
||||
for (auto mat : mat_lib) { ss << mat.second->openmc("atom"); }
|
||||
// write footer
|
||||
ss << "</materials>";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void
|
||||
DAGUniverse::write_uwuw_materials_xml(const std::string& outfile) const
|
||||
{
|
||||
if (!uses_uwuw()) {
|
||||
throw std::runtime_error("This DAGMC universe does not use UWUW materials.");
|
||||
}
|
||||
|
||||
std::string xml_str = get_uwuw_materials_xml();
|
||||
// if there is a material library in the file
|
||||
std::ofstream mats_xml(outfile);
|
||||
mats_xml << xml_str;
|
||||
mats_xml.close();
|
||||
}
|
||||
|
||||
void
|
||||
DAGUniverse::legacy_assign_material(std::string mat_string,
|
||||
std::unique_ptr<DAGCell>& c) const
|
||||
{
|
||||
bool mat_found_by_name = false;
|
||||
// attempt to find a material with a matching name
|
||||
to_lower(mat_string);
|
||||
for (const auto& m : model::materials) {
|
||||
std::string m_name = m->name();
|
||||
to_lower(m_name);
|
||||
if (mat_string == m_name) {
|
||||
// assign the material with that name
|
||||
if (!mat_found_by_name) {
|
||||
mat_found_by_name = true;
|
||||
c->material_.push_back(m->id_);
|
||||
// report error if more than one material is found
|
||||
} else {
|
||||
fatal_error(fmt::format(
|
||||
"More than one material found with name '{}'. Please ensure materials "
|
||||
"have unique names if using this property to assign materials.",
|
||||
mat_string));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no material was set using a name, assign by id
|
||||
if (!mat_found_by_name) {
|
||||
try {
|
||||
auto id = std::stoi(mat_string);
|
||||
c->material_.emplace_back(id);
|
||||
} catch (const std::invalid_argument&) {
|
||||
fatal_error(fmt::format(
|
||||
"No material '{}' found for volume (cell) {}", mat_string, c->id_));
|
||||
}
|
||||
}
|
||||
|
||||
if (settings::verbosity >= 10) {
|
||||
const auto& m = model::materials[model::material_map.at(c->material_[0])];
|
||||
std::stringstream msg;
|
||||
msg << "DAGMC material " << mat_string << " was assigned";
|
||||
if (mat_found_by_name) {
|
||||
msg << " using material name: " << m->name_;
|
||||
} else {
|
||||
msg << " using material id: " << m->id_;
|
||||
}
|
||||
write_message(msg.str(), 10);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DAGUniverse::read_uwuw_materials() {
|
||||
|
||||
int32_t next_material_id = 0;
|
||||
for (const auto& m : model::materials) {
|
||||
next_material_id = std::max(m->id_, next_material_id);
|
||||
}
|
||||
next_material_id++;
|
||||
|
||||
uwuw_ = std::make_shared<UWUW>(filename_.c_str());
|
||||
const auto& mat_lib = uwuw_->material_library;
|
||||
if (mat_lib.size() == 0) return;
|
||||
|
||||
// if we're using automatic IDs, update the UWUW material metadata
|
||||
if (adjust_material_ids_) {
|
||||
for (auto& mat : uwuw_->material_library) {
|
||||
mat.second->metadata["mat_number"] = next_material_id++;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "<?xml version=\"1.0\"?>\n";
|
||||
ss << "<materials>\n";
|
||||
for (auto mat : mat_lib) { ss << mat.second->openmc("atom"); }
|
||||
ss << "</materials>";
|
||||
std::string mat_xml_string = ss.str();
|
||||
|
||||
// create a pugi XML document from this string
|
||||
pugi::xml_document doc;
|
||||
auto result = doc.load_string(mat_xml_string.c_str());
|
||||
if (!result) {
|
||||
fatal_error("Error processing XML created using DAGMC UWUW materials.");
|
||||
}
|
||||
pugi::xml_node root = doc.document_element();
|
||||
for (pugi::xml_node material_node : root.children("material")) {
|
||||
model::materials.push_back(std::make_unique<Material>(material_node));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// DAGMC Cell implementation
|
||||
//==============================================================================
|
||||
|
||||
DAGCell::DAGCell(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx)
|
||||
: Cell{}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) {
|
||||
geom_type_ = GeometryType::DAG;
|
||||
simple_ = true;
|
||||
};
|
||||
|
||||
std::pair<double, int32_t>
|
||||
DAGCell::distance(Position r, Direction u, int32_t on_surface, Particle* p) const
|
||||
{
|
||||
Expects(p);
|
||||
// if we've changed direction or we're not on a surface,
|
||||
// reset the history and update last direction
|
||||
if (u != p->last_dir()) { p->last_dir() = u; p->history().reset(); }
|
||||
if (on_surface == 0) { p->history().reset(); }
|
||||
|
||||
const auto& univ = model::universes[p->coord(p->n_coord() - 1).universe];
|
||||
|
||||
DAGUniverse* dag_univ = static_cast<DAGUniverse*>(univ.get());
|
||||
if (!dag_univ) fatal_error("DAGMC call made for particle in a non-DAGMC universe");
|
||||
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
moab::EntityHandle hit_surf;
|
||||
double dist;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
int surf_idx;
|
||||
if (hit_surf != 0) {
|
||||
surf_idx = dag_univ->surf_idx_offset_ + dagmc_ptr_->index_by_handle(hit_surf);
|
||||
} else {
|
||||
// indicate that particle is lost
|
||||
surf_idx = -1;
|
||||
dist = INFINITY;
|
||||
if (!dagmc_ptr_->is_implicit_complement(vol) || model::universe_map[dag_univ->id_] == model::root_universe) {
|
||||
p->mark_as_lost(fmt::format("No intersection found with DAGMC cell {}", id_));
|
||||
}
|
||||
}
|
||||
|
||||
return {dist, surf_idx};
|
||||
}
|
||||
|
||||
bool
|
||||
DAGCell::contains(Position r, Direction u, int32_t on_surface) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
|
||||
int result = 0;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
DAGCell::to_hdf5_inner(hid_t group_id) const {
|
||||
write_string(group_id, "geom_type", "dagmc", false);
|
||||
|
||||
}
|
||||
|
||||
BoundingBox
|
||||
DAGCell::bounding_box() const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
|
||||
double min[3], max[3];
|
||||
rval = dagmc_ptr_->getobb(vol, min, max);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return {min[0], max[0], min[1], max[1], min[2], max[2]};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// DAGSurface implementation
|
||||
//==============================================================================
|
||||
|
||||
DAGSurface::DAGSurface(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx)
|
||||
: Surface{}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx)
|
||||
{
|
||||
geom_type_ = GeometryType::DAG;
|
||||
} // empty constructor
|
||||
|
||||
double
|
||||
DAGSurface::evaluate(Position r) const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double
|
||||
DAGSurface::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
moab::EntityHandle hit_surf;
|
||||
double dist;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
if (dist < 0.0) dist = INFTY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
Direction
|
||||
DAGSurface::normal(Position r) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3];
|
||||
rval = dagmc_ptr_->get_angle(surf, pnt, dir);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return dir;
|
||||
}
|
||||
|
||||
Direction
|
||||
DAGSurface::reflect(Position r, Direction u, Particle* p) const
|
||||
{
|
||||
Expects(p);
|
||||
p->history().reset_to_last_intersection();
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3];
|
||||
rval = dagmc_ptr_->get_angle(surf, pnt, dir, &p->history());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
p->last_dir() = u.reflect(dir);
|
||||
return p->last_dir();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Non-member functions
|
||||
//==============================================================================
|
||||
|
||||
void read_dagmc_universes(pugi::xml_node node) {
|
||||
for (pugi::xml_node dag_node : node.children("dagmc_universe")) {
|
||||
model::universes.push_back(std::make_unique<DAGUniverse>(dag_node));
|
||||
model::universe_map[model::universes.back()->id_] = model::universes.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void check_dagmc_root_univ() {
|
||||
const auto& ru = model::universes[model::root_universe];
|
||||
if (ru->geom_type() == GeometryType::DAG) {
|
||||
// if the root universe contains DAGMC geometry, warn the user
|
||||
// if it does not contain a graveyard volume
|
||||
auto dag_univ = dynamic_cast<DAGUniverse*>(ru.get());
|
||||
if (dag_univ && !dag_univ->has_graveyard()) {
|
||||
warning("No graveyard volume found in the DagMC model. "
|
||||
"This may result in lost particles and rapid simulation failure.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t next_cell(DAGUniverse* dag_univ, DAGCell* cur_cell, DAGSurface* surf_xed)
|
||||
{
|
||||
moab::EntityHandle surf =
|
||||
surf_xed->dagmc_ptr()->entity_by_index(2, surf_xed->dag_index());
|
||||
moab::EntityHandle vol =
|
||||
cur_cell->dagmc_ptr()->entity_by_index(3, cur_cell->dag_index());
|
||||
|
||||
moab::EntityHandle new_vol;
|
||||
cur_cell->dagmc_ptr()->next_vol(surf, vol, new_vol);
|
||||
|
||||
return cur_cell->dagmc_ptr()->index_by_handle(new_vol) + dag_univ->cell_idx_offset_;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
} // namespace openmc
|
||||
|
||||
#else
|
||||
|
||||
namespace openmc {
|
||||
|
||||
void read_dagmc_universes(pugi::xml_node node) {};
|
||||
void check_dagmc_root_univ() {};
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif // DAGMC
|
||||
|
|
|
|||
|
|
@ -51,9 +51,6 @@ void free_memory()
|
|||
if (settings::event_based) {
|
||||
free_event_queues();
|
||||
}
|
||||
#ifdef DAGMC
|
||||
free_memory_dagmc();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -74,7 +71,6 @@ int openmc_finalize()
|
|||
settings::confidence_intervals = false;
|
||||
settings::create_fission_neutrons = true;
|
||||
settings::electron_treatment = ElectronTreatment::LED;
|
||||
settings::dagmc = false;
|
||||
settings::delayed_photon_scaling = true;
|
||||
settings::energy_cutoff = {0.0, 1000.0, 0.0, 0.0};
|
||||
settings::entropy_on = false;
|
||||
|
|
|
|||
|
|
@ -112,35 +112,13 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list)
|
|||
// that.
|
||||
if (i_cell == C_NONE) {
|
||||
int i_universe = p.coord(p.n_coord() - 1).universe;
|
||||
const auto& univ {*model::universes[i_universe]};
|
||||
const auto& cells {
|
||||
!univ.partitioner_
|
||||
? model::universes[i_universe]->cells_
|
||||
: univ.partitioner_->get_cells(p.r_local(), p.u_local())
|
||||
};
|
||||
|
||||
for (auto it = cells.cbegin(); it != cells.cend(); it++) {
|
||||
i_cell = *it;
|
||||
|
||||
// Make sure the search cell is in the same universe.
|
||||
int i_universe = p.coord(p.n_coord() - 1).universe;
|
||||
if (model::cells[i_cell]->universe_ != i_universe) continue;
|
||||
|
||||
// Check if this cell contains the particle.
|
||||
Position r {p.r_local()};
|
||||
Direction u {p.u_local()};
|
||||
auto surf = p.surface();
|
||||
if (model::cells[i_cell]->contains(r, u, surf)) {
|
||||
p.coord(p.n_coord() - 1).cell = i_cell;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return found;
|
||||
const auto& univ {model::universes[i_universe]};
|
||||
found = univ->find_cell(p);
|
||||
}
|
||||
|
||||
if (!found) { return found; }
|
||||
i_cell = p.coord(p.n_coord() - 1).cell;
|
||||
|
||||
// Announce the cell that the particle is entering.
|
||||
if (found && (settings::verbosity >= 10 || p.trace())) {
|
||||
auto msg = fmt::format(" Entering cell {}", model::cells[i_cell]->id_);
|
||||
|
|
|
|||
|
|
@ -42,13 +42,6 @@ void update_universe_cell_count(int32_t a, int32_t b) {
|
|||
|
||||
void read_geometry_xml()
|
||||
{
|
||||
#ifdef DAGMC
|
||||
if (settings::dagmc) {
|
||||
read_geometry_dagmc();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Display output message
|
||||
write_message("Reading geometry XML file...", 5);
|
||||
|
||||
|
|
@ -73,8 +66,25 @@ void read_geometry_xml()
|
|||
read_cells(root);
|
||||
read_lattices(root);
|
||||
|
||||
// Check to make sure a boundary condition was applied to at least one
|
||||
// surface
|
||||
bool boundary_exists = false;
|
||||
for (const auto& surf : model::surfaces) {
|
||||
if (surf->bc_) {
|
||||
boundary_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings::run_mode != RunMode::PLOTTING && !boundary_exists) {
|
||||
fatal_error("No boundary conditions were applied to any surfaces!");
|
||||
}
|
||||
|
||||
// Allocate universes, universe cell arrays, and assign base universe
|
||||
model::root_universe = find_root_universe();
|
||||
|
||||
// if the root universe is DAGMC geometry, make sure the model is well-formed
|
||||
check_dagmc_root_univ();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include "openmc/capi.h"
|
||||
#include "openmc/cross_sections.h"
|
||||
#include "openmc/container_util.h"
|
||||
#include "openmc/dagmc.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/file_utils.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
|
|
@ -1223,24 +1222,14 @@ void read_materials_xml()
|
|||
|
||||
pugi::xml_document doc;
|
||||
|
||||
bool using_dagmc_mats = false;
|
||||
#ifdef DAGMC
|
||||
if (settings::dagmc) {
|
||||
using_dagmc_mats = read_uwuw_materials(doc);
|
||||
// Check if materials.xml exists
|
||||
std::string filename = settings::path_input + "materials.xml";
|
||||
if (!file_exists(filename)) {
|
||||
fatal_error("Material XML file '" + filename + "' does not exist!");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!using_dagmc_mats) {
|
||||
// Check if materials.xml exists
|
||||
std::string filename = settings::path_input + "materials.xml";
|
||||
if (!file_exists(filename)) {
|
||||
fatal_error("Material XML file '" + filename + "' does not exist!");
|
||||
}
|
||||
|
||||
// Parse materials.xml file and get root element
|
||||
doc.load_file(filename.c_str());
|
||||
}
|
||||
// Parse materials.xml file and get root element
|
||||
doc.load_file(filename.c_str());
|
||||
|
||||
// Loop over XML material elements and populate the array.
|
||||
pugi::xml_node root = doc.document_element();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "openmc/capi.h"
|
||||
#include "openmc/cell.h"
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/dagmc.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/geometry.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
|
|
@ -285,6 +286,10 @@ Particle::event_collide()
|
|||
|
||||
// Score flux derivative accumulators for differential tallies.
|
||||
if (!model::active_tallies.empty()) score_collision_derivative(*this);
|
||||
|
||||
#ifdef DAGMC
|
||||
history().reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -318,9 +323,8 @@ void
|
|||
Particle::event_death()
|
||||
{
|
||||
#ifdef DAGMC
|
||||
if (settings::dagmc)
|
||||
history().reset();
|
||||
#endif
|
||||
history().reset();
|
||||
#endif
|
||||
|
||||
// Finish particle track output.
|
||||
if (write_track()) {
|
||||
|
|
@ -377,6 +381,11 @@ Particle::cross_surface()
|
|||
int64_t idx = simulation::surf_source_bank.thread_safe_append(site);
|
||||
}
|
||||
|
||||
// if we're crossing a CSG surface, make sure the DAG history is reset
|
||||
#ifdef DAGMC
|
||||
if (surf->geom_type_ == GeometryType::CSG) history().reset();
|
||||
#endif
|
||||
|
||||
// Handle any applicable boundary conditions.
|
||||
if (surf->bc_ && settings::run_mode != RunMode::PLOTTING) {
|
||||
surf->bc_->handle_particle(*this, *surf);
|
||||
|
|
@ -387,17 +396,18 @@ Particle::cross_surface()
|
|||
// SEARCH NEIGHBOR LISTS FOR NEXT CELL
|
||||
|
||||
#ifdef DAGMC
|
||||
if (settings::dagmc) {
|
||||
auto cellp = dynamic_cast<DAGCell*>(model::cells[cell_last(0)].get());
|
||||
// TODO: off-by-one
|
||||
auto surfp =
|
||||
dynamic_cast<DAGSurface*>(model::surfaces[std::abs(surface()) - 1].get());
|
||||
int32_t i_cell = next_cell(cellp, surfp) - 1;
|
||||
// in DAGMC, we know what the next cell should be
|
||||
if (surf->geom_type_ == GeometryType::DAG) {
|
||||
auto surfp = dynamic_cast<DAGSurface*>(surf);
|
||||
auto cellp = dynamic_cast<DAGCell*>(model::cells[cell_last(n_coord() - 1)].get());
|
||||
auto univp = static_cast<DAGUniverse*>(model::universes[coord(n_coord() - 1).universe].get());
|
||||
// determine the next cell for this crossing
|
||||
int32_t i_cell = next_cell(univp, cellp, surfp) - 1;
|
||||
// save material and temp
|
||||
material_last() = material();
|
||||
sqrtkT_last() = sqrtkT();
|
||||
// set new cell value
|
||||
coord(0).cell = i_cell;
|
||||
coord(n_coord() - 1).cell = i_cell;
|
||||
cell_instance() = 0;
|
||||
material() = model::cells[i_cell]->material_[0];
|
||||
sqrtkT() = model::cells[i_cell]->sqrtkT_[0];
|
||||
|
|
@ -503,13 +513,11 @@ Particle::cross_reflective_bc(const Surface& surf, Direction new_u)
|
|||
// boundary, it is necessary to redetermine the particle's coordinates in
|
||||
// the lower universes.
|
||||
// (unless we're using a dagmc model, which has exactly one universe)
|
||||
if (!settings::dagmc) {
|
||||
n_coord() = 1;
|
||||
if (!neighbor_list_find_cell(*this)) {
|
||||
mark_as_lost("Couldn't find particle after reflecting from surface " +
|
||||
std::to_string(surf.id_) + ".");
|
||||
return;
|
||||
}
|
||||
n_coord() = 1;
|
||||
if (surf.geom_type_ != GeometryType::DAG && !neighbor_list_find_cell(*this)) {
|
||||
this->mark_as_lost("Couldn't find particle after reflecting from surface "
|
||||
+ std::to_string(surf.id_) + ".");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set previous coordinate going slightly past surface crossing
|
||||
|
|
|
|||
|
|
@ -89,14 +89,6 @@ void write_geometry(hid_t file)
|
|||
{
|
||||
auto geom_group = create_group(file, "geometry");
|
||||
|
||||
#ifdef DAGMC
|
||||
if (settings::dagmc) {
|
||||
write_attribute(geom_group, "dagmc", 1);
|
||||
close_group(geom_group);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
write_attribute(geom_group, "n_cells", model::cells.size());
|
||||
write_attribute(geom_group, "n_surfaces", model::surfaces.size());
|
||||
write_attribute(geom_group, "n_universes", model::universes.size());
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "openmc/array.h"
|
||||
#include "openmc/container_util.h"
|
||||
#include "openmc/dagmc.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/hdf5_interface.h"
|
||||
#include "openmc/math_functions.h"
|
||||
|
|
@ -198,21 +197,21 @@ Surface::diffuse_reflect(Position r, Direction u, uint64_t* seed) const
|
|||
return u/u.norm();
|
||||
}
|
||||
|
||||
CSGSurface::CSGSurface() : Surface{} {};
|
||||
CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface{surf_node} {};
|
||||
|
||||
void
|
||||
CSGSurface::to_hdf5(hid_t group_id) const
|
||||
Surface::to_hdf5(hid_t group_id) const
|
||||
{
|
||||
std::string group_name {"surface "};
|
||||
group_name += std::to_string(id_);
|
||||
hid_t surf_group = create_group(group_id, fmt::format("surface {}", id_));
|
||||
|
||||
hid_t surf_group = create_group(group_id, group_name);
|
||||
if (geom_type_ == GeometryType::DAG) {
|
||||
write_string(surf_group, "geom_type", "dagmc", false);
|
||||
} else if (geom_type_ == GeometryType::CSG) {
|
||||
write_string(surf_group, "geom_type", "csg", false);
|
||||
|
||||
if (bc_) {
|
||||
write_string(surf_group, "boundary_type", bc_->type(), false);
|
||||
} else {
|
||||
write_string(surf_group, "boundary_type", "transmission", false);
|
||||
if (bc_) {
|
||||
write_string(surf_group, "boundary_type", bc_->type(), false);
|
||||
} else {
|
||||
write_string(surf_group, "boundary_type", "transmission", false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!name_.empty()) {
|
||||
|
|
@ -224,60 +223,12 @@ CSGSurface::to_hdf5(hid_t group_id) const
|
|||
close_group(surf_group);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// DAGSurface implementation
|
||||
//==============================================================================
|
||||
#ifdef DAGMC
|
||||
DAGSurface::DAGSurface() : Surface{} {} // empty constructor
|
||||
|
||||
double DAGSurface::evaluate(Position r) const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double
|
||||
DAGSurface::distance(Position r, Direction u, bool coincident) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
moab::EntityHandle hit_surf;
|
||||
double dist;
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3] = {u.x, u.y, u.z};
|
||||
rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
if (dist < 0.0) dist = INFTY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
Direction DAGSurface::normal(Position r) const
|
||||
{
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3];
|
||||
rval = dagmc_ptr_->get_angle(surf, pnt, dir);
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
return dir;
|
||||
}
|
||||
|
||||
Direction DAGSurface::reflect(Position r, Direction u, Particle* p) const
|
||||
{
|
||||
Expects(p);
|
||||
p->history().reset_to_last_intersection();
|
||||
moab::ErrorCode rval;
|
||||
moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
|
||||
double pnt[3] = {r.x, r.y, r.z};
|
||||
double dir[3];
|
||||
rval = dagmc_ptr_->get_angle(surf, pnt, dir, &p->history());
|
||||
MB_CHK_ERR_CONT(rval);
|
||||
p->last_dir() = u.reflect(dir);
|
||||
return p->last_dir();
|
||||
}
|
||||
|
||||
void DAGSurface::to_hdf5(hid_t group_id) const {}
|
||||
|
||||
#endif
|
||||
CSGSurface::CSGSurface() : Surface{} {
|
||||
geom_type_ = GeometryType::CSG;
|
||||
};
|
||||
CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface{surf_node} {
|
||||
geom_type_ = GeometryType::CSG;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Generic functions for x-, y-, and z-, planes.
|
||||
|
|
@ -1036,9 +987,6 @@ void read_surfaces(pugi::xml_node node)
|
|||
// Count the number of surfaces
|
||||
int n_surfaces = 0;
|
||||
for (pugi::xml_node surf_node : node.children("surface")) {n_surfaces++;}
|
||||
if (n_surfaces == 0) {
|
||||
fatal_error("No surfaces found in geometry.xml!");
|
||||
}
|
||||
|
||||
// Loop over XML surface elements and populate the array. Keep track of
|
||||
// periodic surfaces.
|
||||
|
|
@ -1183,19 +1131,6 @@ void read_surfaces(pugi::xml_node node)
|
|||
surf2.bc_ = surf1.bc_;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to make sure a boundary condition was applied to at least one
|
||||
// surface
|
||||
bool boundary_exists = false;
|
||||
for (const auto& surf : model::surfaces) {
|
||||
if (surf->bc_) {
|
||||
boundary_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (settings::run_mode != RunMode::PLOTTING && !boundary_exists) {
|
||||
fatal_error("No boundary conditions were applied to any surfaces!");
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory_surfaces()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<geometry>
|
||||
<dagmc_universe filename="dagmc.h5m" id="1" />
|
||||
</geometry>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<materials>
|
||||
<material depletable="true" id="40" name="no-void fuel">
|
||||
<density units="g/cc" value="11" />
|
||||
|
|
@ -22,7 +26,6 @@
|
|||
<parameters>-4 -4 -4 4 4 4</parameters>
|
||||
</space>
|
||||
</source>
|
||||
<dagmc>true</dagmc>
|
||||
</settings>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<tallies>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ def model():
|
|||
|
||||
model.settings.dagmc = True
|
||||
|
||||
# geometry
|
||||
dag_univ = openmc.DAGMCUniverse("dagmc.h5m")
|
||||
model.geometry = openmc.Geometry(dag_univ)
|
||||
|
||||
# tally
|
||||
tally = openmc.Tally()
|
||||
tally.scores = ['total']
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<geometry>
|
||||
<dagmc_universe auto_geom_ids="true" filename="dagmc.h5m" id="9" />
|
||||
</geometry>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<materials>
|
||||
</materials>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<settings>
|
||||
<run_mode>eigenvalue</run_mode>
|
||||
<particles>100</particles>
|
||||
|
|
@ -9,12 +16,11 @@
|
|||
<parameters>-4 -4 -4 4 4 4</parameters>
|
||||
</space>
|
||||
</source>
|
||||
<dagmc>true</dagmc>
|
||||
</settings>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<tallies>
|
||||
<filter id="1" type="cell">
|
||||
<bins>1</bins>
|
||||
<bins>2</bins>
|
||||
</filter>
|
||||
<tally id="1">
|
||||
<filters>1</filters>
|
||||
|
|
|
|||
|
|
@ -27,13 +27,18 @@ class UWUWTest(PyAPITestHarness):
|
|||
|
||||
model.settings.export_to_xml()
|
||||
|
||||
# geometry
|
||||
dag_univ = openmc.DAGMCUniverse("dagmc.h5m", auto_geom_ids=True)
|
||||
model.geometry = openmc.Geometry(dag_univ)
|
||||
|
||||
# tally
|
||||
tally = openmc.Tally()
|
||||
tally.scores = ['total']
|
||||
tally.filters = [openmc.CellFilter(1)]
|
||||
tally.filters = [openmc.CellFilter(2)]
|
||||
model.tallies = [tally]
|
||||
|
||||
model.tallies.export_to_xml()
|
||||
model.export_to_xml()
|
||||
|
||||
def test_refl():
|
||||
harness = UWUWTest('statepoint.5.h5')
|
||||
|
|
|
|||
0
tests/regression_tests/dagmc/universes/__init__.py
Normal file
0
tests/regression_tests/dagmc/universes/__init__.py
Normal file
BIN
tests/regression_tests/dagmc/universes/dagmc.h5m
Normal file
BIN
tests/regression_tests/dagmc/universes/dagmc.h5m
Normal file
Binary file not shown.
55
tests/regression_tests/dagmc/universes/inputs_true.dat
Normal file
55
tests/regression_tests/dagmc/universes/inputs_true.dat
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<geometry>
|
||||
<cell fill="10" id="13" region="9 -10 11 -12 13 -14" universe="11" />
|
||||
<dagmc_universe auto_geom_ids="true" filename="dagmc.h5m" id="9" />
|
||||
<lattice id="10">
|
||||
<pitch>24.0 24.0</pitch>
|
||||
<dimension>2 2</dimension>
|
||||
<lower_left>-24.0 -24.0</lower_left>
|
||||
<universes>
|
||||
9 9
|
||||
9 9 </universes>
|
||||
</lattice>
|
||||
<surface boundary="reflective" coeffs="-24.0" id="9" name="left" type="x-plane" />
|
||||
<surface boundary="reflective" coeffs="24.0" id="10" name="right" type="x-plane" />
|
||||
<surface boundary="reflective" coeffs="-24.0" id="11" name="front" type="y-plane" />
|
||||
<surface boundary="reflective" coeffs="24.0" id="12" name="back" type="y-plane" />
|
||||
<surface boundary="reflective" coeffs="-10.0" id="13" name="bottom" type="z-plane" />
|
||||
<surface boundary="reflective" coeffs="10.0" id="14" name="top" type="z-plane" />
|
||||
</geometry>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<materials>
|
||||
<material depletable="true" id="13" name="no-void fuel">
|
||||
<density units="g/cc" value="10.29769" />
|
||||
<nuclide ao="0.93120485" name="U234" />
|
||||
<nuclide ao="0.00055815" name="U235" />
|
||||
<nuclide ao="0.022408" name="U238" />
|
||||
<nuclide ao="0.045829" name="O16" />
|
||||
</material>
|
||||
<material id="14" name="clad">
|
||||
<density units="g/cc" value="6.55" />
|
||||
<nuclide ao="0.021827" name="Zr90" />
|
||||
<nuclide ao="0.00476" name="Zr91" />
|
||||
<nuclide ao="0.0072758" name="Zr92" />
|
||||
<nuclide ao="0.0073734" name="Zr94" />
|
||||
<nuclide ao="0.0011879" name="Zr96" />
|
||||
</material>
|
||||
<material id="15" name="water">
|
||||
<density units="g/cc" value="0.740582" />
|
||||
<nuclide ao="0.049457" name="H1" />
|
||||
<nuclide ao="0.024672" name="O16" />
|
||||
<nuclide ao="8.0042e-06" name="B10" />
|
||||
<nuclide ao="3.2218e-05" name="B11" />
|
||||
<sab name="c_H_in_H2O" />
|
||||
</material>
|
||||
</materials>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<settings>
|
||||
<run_mode>eigenvalue</run_mode>
|
||||
<particles>100</particles>
|
||||
<batches>10</batches>
|
||||
<inactive>2</inactive>
|
||||
<output>
|
||||
<summary>false</summary>
|
||||
</output>
|
||||
</settings>
|
||||
2
tests/regression_tests/dagmc/universes/results_true.dat
Normal file
2
tests/regression_tests/dagmc/universes/results_true.dat
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
9.436168E-01 2.905559E-02
|
||||
80
tests/regression_tests/dagmc/universes/test.py
Normal file
80
tests/regression_tests/dagmc/universes/test.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.lib
|
||||
|
||||
import pytest
|
||||
from tests.testing_harness import PyAPITestHarness
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not openmc.lib._dagmc_enabled(),
|
||||
reason="DAGMC CAD geometry is not enabled.")
|
||||
|
||||
|
||||
class DAGMCUniverseTest(PyAPITestHarness):
|
||||
|
||||
def _build_inputs(self):
|
||||
model = openmc.model.Model()
|
||||
|
||||
### MATERIALS ###
|
||||
fuel = openmc.Material(name='no-void fuel')
|
||||
fuel.set_density('g/cc', 10.29769)
|
||||
fuel.add_nuclide('U234', 0.93120485)
|
||||
fuel.add_nuclide('U235', 0.00055815)
|
||||
fuel.add_nuclide('U238', 0.022408)
|
||||
fuel.add_nuclide('O16', 0.045829)
|
||||
|
||||
cladding = openmc.Material(name='clad')
|
||||
cladding.set_density('g/cc', 6.55)
|
||||
cladding.add_nuclide('Zr90', 0.021827)
|
||||
cladding.add_nuclide('Zr91', 0.00476)
|
||||
cladding.add_nuclide('Zr92', 0.0072758)
|
||||
cladding.add_nuclide('Zr94', 0.0073734)
|
||||
cladding.add_nuclide('Zr96', 0.0011879)
|
||||
|
||||
water = openmc.Material(name='water')
|
||||
water.set_density('g/cc', 0.740582)
|
||||
water.add_nuclide('H1', 0.049457)
|
||||
water.add_nuclide('O16', 0.024672)
|
||||
water.add_nuclide('B10', 8.0042e-06)
|
||||
water.add_nuclide('B11', 3.2218e-05)
|
||||
water.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
model.materials = openmc.Materials([fuel, cladding, water])
|
||||
|
||||
### GEOMETRY ###
|
||||
# create the DAGMC universe
|
||||
pincell_univ = openmc.DAGMCUniverse(filename='dagmc.h5m', auto_geom_ids=True)
|
||||
|
||||
# create a 2 x 2 lattice using the DAGMC pincell
|
||||
pitch = np.asarray((24.0, 24.0))
|
||||
lattice = openmc.RectLattice()
|
||||
lattice.pitch = pitch
|
||||
lattice.universes = [[pincell_univ] * 2] * 2
|
||||
lattice.lower_left = -pitch
|
||||
|
||||
left = openmc.XPlane(x0=-pitch[0], name='left', boundary_type='reflective')
|
||||
right = openmc.XPlane(x0=pitch[0], name='right', boundary_type='reflective')
|
||||
front = openmc.YPlane(y0=-pitch[1], name='front', boundary_type='reflective')
|
||||
back = openmc.YPlane(y0=pitch[1], name='back', boundary_type='reflective')
|
||||
# clip the DAGMC geometry at +/- 10 cm w/ CSG planes
|
||||
bottom = openmc.ZPlane(z0=-10.0, name='bottom', boundary_type='reflective')
|
||||
top = openmc.ZPlane(z0=10.0, name='top', boundary_type='reflective')
|
||||
|
||||
bounding_region = +left & -right & +front & -back & +bottom & -top
|
||||
bounding_cell = openmc.Cell(fill=lattice, region=bounding_region)
|
||||
|
||||
model.geometry = openmc.Geometry([bounding_cell])
|
||||
|
||||
# settings
|
||||
model.settings.particles = 100
|
||||
model.settings.batches = 10
|
||||
model.settings.inactive = 2
|
||||
model.settings.output = {'summary' : False}
|
||||
|
||||
model.export_to_xml()
|
||||
|
||||
|
||||
def test_univ():
|
||||
harness = DAGMCUniverseTest('statepoint.10.h5')
|
||||
harness.main()
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<geometry>
|
||||
<dagmc_universe filename="dagmc.h5m" id="9" />
|
||||
</geometry>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<materials>
|
||||
</materials>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<settings>
|
||||
<run_mode>eigenvalue</run_mode>
|
||||
<particles>100</particles>
|
||||
|
|
@ -9,7 +16,6 @@
|
|||
<parameters>-4 -4 -4 4 4 4</parameters>
|
||||
</space>
|
||||
</source>
|
||||
<dagmc>true</dagmc>
|
||||
</settings>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<tallies>
|
||||
|
|
|
|||
|
|
@ -27,13 +27,17 @@ class UWUWTest(PyAPITestHarness):
|
|||
|
||||
model.settings.export_to_xml()
|
||||
|
||||
# geometry
|
||||
dag_univ = openmc.DAGMCUniverse("dagmc.h5m")
|
||||
model.geometry = openmc.Geometry(root=dag_univ)
|
||||
|
||||
# tally
|
||||
tally = openmc.Tally()
|
||||
tally.scores = ['total']
|
||||
tally.filters = [openmc.CellFilter(1)]
|
||||
model.tallies = [tally]
|
||||
|
||||
model.tallies.export_to_xml()
|
||||
model.export_to_xml()
|
||||
|
||||
def test_uwuw():
|
||||
harness = UWUWTest('statepoint.5.h5')
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ def dagmc_model(request):
|
|||
source = openmc.Source(space=source_box)
|
||||
model.settings.source = source
|
||||
|
||||
model.settings.dagmc = True
|
||||
# geometry
|
||||
dagmc_universe = openmc.DAGMCUniverse('dagmc.h5m')
|
||||
model.geometry = openmc.Geometry(dagmc_universe)
|
||||
|
||||
# tally
|
||||
tally = openmc.Tally()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ def test_export_to_xml(run_in_tmpdir):
|
|||
s.log_grid_bins = 2000
|
||||
s.photon_transport = False
|
||||
s.electron_treatment = 'led'
|
||||
s.dagmc = False
|
||||
|
||||
# Make sure exporting XML works
|
||||
s.export_to_xml()
|
||||
|
|
@ -111,4 +110,3 @@ def test_export_to_xml(run_in_tmpdir):
|
|||
assert s.log_grid_bins == 2000
|
||||
assert not s.photon_transport
|
||||
assert s.electron_treatment == 'led'
|
||||
assert not s.dagmc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue