├── .gitignore ├── src └── openmc_cad_adapter │ ├── __init__.py │ ├── cubit_util.py │ ├── geom_util.py │ ├── gqs.py │ ├── surfaces.py │ └── to_cubit_journal.py ├── test ├── __init__.py ├── pincell_cell1.jou ├── xcylinder.jou ├── ycylinder.jou ├── tallies.xml ├── cylinder.jou ├── gold │ ├── pincell_cell1.jou │ ├── z_torus.jou │ ├── ellipsoid.jou │ ├── cylinder.jou │ ├── xcylinder.jou │ ├── ycylinder.jou │ ├── x_torus.jou │ ├── y_torus.jou │ ├── z_cone.jou │ ├── x_cone.jou │ ├── y_cone.jou │ ├── pincell_cell2.jou │ ├── pincell_cell3.jou │ ├── nested_spheres.jou │ ├── pincell_cell4.jou │ ├── pincell.jou │ ├── plane.jou │ └── lattice-hexagonal.jou ├── plots.xml ├── pincell_cell2.jou ├── pincell_cell3.jou ├── conftest.py ├── settings.xml ├── materials.xml ├── local_tests.py ├── test_utilities.py ├── pincell_cell4.jou ├── geometry.xml ├── pincell.jou ├── test_examples.py ├── test_quadric.py ├── test_local.py ├── assembly.jou └── lattice-hexagonal.jou ├── .github ├── environment.yml └── workflows │ └── ci.yml ├── LICENSE ├── README.md └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | __pycache__ 3 | *.egg-info 4 | -------------------------------------------------------------------------------- /src/openmc_cad_adapter/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .to_cubit_journal import to_cubit_journal 3 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .conftest import test_config, run_in_tmpdir 3 | from .test_utilities import * -------------------------------------------------------------------------------- /.github/environment.yml: -------------------------------------------------------------------------------- 1 | name: test-env 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python>=3.8 6 | - numpy 7 | - pytest 8 | - openmc==0.15.0 -------------------------------------------------------------------------------- /test/pincell_cell1.jou: -------------------------------------------------------------------------------- 1 | #CELL 1 2 | cylinder height 500 radius 0.39218 3 | #{ id1 = Id("body") } 4 | body { id1 } name "Cell_1" 5 | group "Material_1" add body { id1 } 6 | -------------------------------------------------------------------------------- /test/xcylinder.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 1 4 | cylinder height 500 radius 1.0 5 | #{ id1 = Id("body") } 6 | rotate body { id1 } about y angle 90 7 | body { id1 } move 0 10.0 5.0 8 | body { id1 } name "Cell_1" 9 | -------------------------------------------------------------------------------- /test/ycylinder.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 2 4 | cylinder height 500 radius 1.0 5 | #{ id1 = Id("body") } 6 | rotate body { id1 } about x angle 90 7 | body { id1 } move 10.0 0 5.0 8 | body { id1 } name "Cell_2" 9 | -------------------------------------------------------------------------------- /test/tallies.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 101 5 | 6 | 7 | 1 8 | total 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/cylinder.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 3 4 | cylinder height 500 radius 6.0 5 | #{ id1 = Id("body") } 6 | body { id1 } rotate 0.0 about Z 7 | body { id1 } rotate 45.0 about Y 8 | body { id1 } rotate 35.264389682754654 about X 9 | body { id1 } move 5.0 5.0 5.0 10 | body { id1 } name "Cell_3" 11 | -------------------------------------------------------------------------------- /test/gold/pincell_cell1.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | cylinder height 500 radius 0.39218 9 | #{ id1 = Id("body") } 10 | body { id1 } name "Cell_1" 11 | group "mat:UO2 fuel at 2.4% wt enrichme" add body { id1 } 12 | graphics flush 13 | set default autosize on 14 | zoom reset 15 | set echo on 16 | set info on 17 | set warning on 18 | set journal on 19 | -------------------------------------------------------------------------------- /test/plots.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 400 400 5 | 0 0 0 6 | 6 6 7 | 8 | 9 | 400 400 10 | 0 0 0 11 | 8 8 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/pincell_cell2.jou: -------------------------------------------------------------------------------- 1 | #CELL 2 2 | cylinder height 500 radius 0.39218 3 | #{ id2 = Id("body") } 4 | brick x 500 y 500 z 500 5 | #{ id3 = Id("body") } 6 | subtract body { id2 } from body { id3 } 7 | cylinder height 500 radius 0.40005 8 | #{ id4 = Id("body") } 9 | #{ id5 = Id("body") } 10 | intersect body { id3 } { id4 } 11 | #{ id6 = Id("body") } 12 | #{id7 = ( id5 == id6 ) ? id4 : id6} 13 | body { id7 } name "Cell_2" 14 | group "Material_2" add body { id7 } 15 | -------------------------------------------------------------------------------- /test/gold/z_torus.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | torus major radius 5.0 minor radius 2.0 9 | #{ id1 = Id("body") } 10 | body { id1 } move 50.0 50.0 50.0 11 | body { id1 } name "Cell_1" 12 | group "mat:void" add body { id1 } 13 | graphics flush 14 | set default autosize on 15 | zoom reset 16 | set echo on 17 | set info on 18 | set warning on 19 | set journal on 20 | -------------------------------------------------------------------------------- /test/pincell_cell3.jou: -------------------------------------------------------------------------------- 1 | #CELL 3 2 | cylinder height 500 radius 0.40005 3 | #{ id8 = Id("body") } 4 | brick x 500 y 500 z 500 5 | #{ id9 = Id("body") } 6 | subtract body { id8 } from body { id9 } 7 | cylinder height 500 radius 0.4572 8 | #{ id10 = Id("body") } 9 | #{ id11 = Id("body") } 10 | intersect body { id9 } { id10 } 11 | #{ id12 = Id("body") } 12 | #{id13 = ( id11 == id12 ) ? id10 : id12} 13 | body { id13 } name "Cell_3" 14 | group "Material_3" add body { id13 } 15 | -------------------------------------------------------------------------------- /test/gold/ellipsoid.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | sphere radius 1 9 | #{ id1 = Id("body") } 10 | body { id1 } scale x 1.0 y 0.7071067811865476 z 0.5773502691896257 11 | body { None } name "Cell_1" 12 | group "mat:void" add body { None } 13 | graphics flush 14 | set default autosize on 15 | zoom reset 16 | set echo on 17 | set info on 18 | set warning on 19 | set journal on 20 | -------------------------------------------------------------------------------- /test/gold/cylinder.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | cylinder height 500 radius 6.0 9 | #{ id1 = Id("body") } 10 | body { id1 } rotate 90.0 about Y 11 | body { id1 } rotate 45.0 about Z 12 | body { id1 } name "Cell_1" 13 | group "mat:void" add body { id1 } 14 | graphics flush 15 | set default autosize on 16 | zoom reset 17 | set echo on 18 | set info on 19 | set warning on 20 | set journal on 21 | -------------------------------------------------------------------------------- /test/gold/xcylinder.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | cylinder height 500 radius 1.0 9 | #{ id1 = Id("body") } 10 | rotate body { id1 } about y angle 90 11 | body { id1 } move 0 10.0 5.0 12 | body { id1 } name "Cell_1" 13 | group "mat:void" add body { id1 } 14 | graphics flush 15 | set default autosize on 16 | zoom reset 17 | set echo on 18 | set info on 19 | set warning on 20 | set journal on 21 | -------------------------------------------------------------------------------- /test/gold/ycylinder.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | cylinder height 500 radius 1.0 9 | #{ id1 = Id("body") } 10 | rotate body { id1 } about x angle 90 11 | body { id1 } move 10.0 0 5.0 12 | body { id1 } name "Cell_1" 13 | group "mat:void" add body { id1 } 14 | graphics flush 15 | set default autosize on 16 | zoom reset 17 | set echo on 18 | set info on 19 | set warning on 20 | set journal on 21 | -------------------------------------------------------------------------------- /test/gold/x_torus.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | torus major radius 5.0 minor radius 2.0 9 | #{ id1 = Id("body") } 10 | rotate body { id1 } about y angle 90 11 | body { id1 } move 10.0 10.0 10.0 12 | body { id1 } name "Cell_1" 13 | group "mat:void" add body { id1 } 14 | graphics flush 15 | set default autosize on 16 | zoom reset 17 | set echo on 18 | set info on 19 | set warning on 20 | set journal on 21 | -------------------------------------------------------------------------------- /test/gold/y_torus.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | torus major radius 5.0 minor radius 2.0 9 | #{ id1 = Id("body") } 10 | rotate body { id1 } about x angle 90 11 | body { id1 } move -10.0 -10.0 -10.0 12 | body { id1 } name "Cell_1" 13 | group "mat:void" add body { id1 } 14 | graphics flush 15 | set default autosize on 16 | zoom reset 17 | set echo on 18 | set info on 19 | set warning on 20 | set journal on 21 | -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | test_config = {'update': False} 4 | 5 | 6 | def pytest_addoption(parser): 7 | parser.addoption('--update', action='store_true') 8 | 9 | 10 | def pytest_configure(config): 11 | opts = ['update'] 12 | for opt in opts: 13 | if config.getoption(opt) is not None: 14 | test_config[opt] = config.getoption(opt) 15 | 16 | 17 | @pytest.fixture 18 | def run_in_tmpdir(tmpdir): 19 | orig = tmpdir.chdir() 20 | try: 21 | yield 22 | finally: 23 | orig.chdir() 24 | -------------------------------------------------------------------------------- /test/gold/z_cone.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | create frustum height 500 radius 250.0 top 0 9 | #{ id1 = Id("body") } 10 | body { id1 } move 0 0 -250.0 11 | body { id1 } copy reflect z 12 | #{ id2 = Id("body") } 13 | unite body { id1 } { id2 } 14 | body { id1 } move 50.0 10.0 2.0 15 | body { id1 } name "Cell_1" 16 | group "mat:void" add body { id1 } 17 | graphics flush 18 | set default autosize on 19 | zoom reset 20 | set echo on 21 | set info on 22 | set warning on 23 | set journal on 24 | -------------------------------------------------------------------------------- /src/openmc_cad_adapter/cubit_util.py: -------------------------------------------------------------------------------- 1 | _CUBIT_ID = 1 2 | 3 | 4 | def reset_cubit_ids(): 5 | global _CUBIT_ID 6 | _CUBIT_ID = 1 7 | 8 | 9 | def lastid(): 10 | global _CUBIT_ID 11 | id_out = _CUBIT_ID 12 | _CUBIT_ID += 1 13 | return id_out 14 | 15 | 16 | def new_variable(): 17 | idn = lastid() 18 | return f"id{idn}" 19 | 20 | 21 | def emit_get_last_id(type="body", cmds=None): 22 | idn = lastid() 23 | ids = f"id{idn}" 24 | if cmds is not None: 25 | cmds.append(f'#{{ {ids} = Id("{type}") }}') 26 | else: 27 | print('Warning: cmds is None') 28 | return ids 29 | -------------------------------------------------------------------------------- /test/gold/x_cone.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | create frustum height 500 radius 1118.033988749895 top 0 9 | #{ id1 = Id("body") } 10 | body { id1 } move 0 0 -250.0 11 | body { id1 } copy reflect z 12 | #{ id2 = Id("body") } 13 | unite body { id1 } { id2 } 14 | rotate body { id1 } about y angle 90 15 | body { id1 } move 30.0 3.0 5.0 16 | body { id1 } name "Cell_1" 17 | group "mat:void" add body { id1 } 18 | graphics flush 19 | set default autosize on 20 | zoom reset 21 | set echo on 22 | set info on 23 | set warning on 24 | set journal on 25 | -------------------------------------------------------------------------------- /test/gold/y_cone.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | create frustum height 500 radius 707.1067811865476 top 0 9 | #{ id1 = Id("body") } 10 | body { id1 } move 0 0 -250.0 11 | body { id1 } copy reflect z 12 | #{ id2 = Id("body") } 13 | unite body { id1 } { id2 } 14 | rotate body { id1 } about x angle 90 15 | body { id1 } move 40.0 20.0 7.0 16 | body { id1 } name "Cell_1" 17 | group "mat:void" add body { id1 } 18 | graphics flush 19 | set default autosize on 20 | zoom reset 21 | set echo on 22 | set info on 23 | set warning on 24 | set journal on 25 | -------------------------------------------------------------------------------- /test/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | eigenvalue 4 | 10000 5 | 20 6 | 10 7 | 8 | 0.0005 9 | std_dev 10 | 11 | 12 | 13 | -1 -1 -1 1 1 1 14 | 15 | 16 | true 17 | 18 | 19 | 20 | true 21 | 100 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/gold/pincell_cell2.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 2 8 | cylinder height 500 radius 0.39218 9 | #{ id2 = Id("body") } 10 | brick x 500 y 500 z 500 11 | #{ id3 = Id("body") } 12 | subtract body { id2 } from body { id3 } 13 | cylinder height 500 radius 0.40005 14 | #{ id4 = Id("body") } 15 | #{ id5 = Id("body") } 16 | intersect body { id3 } { id4 } 17 | #{ id6 = Id("body") } 18 | #{id7 = ( id5 == id6 ) ? id4 : id6} 19 | body { id7 } name "Cell_2" 20 | group "mat:Helium for gap" add body { id7 } 21 | graphics flush 22 | set default autosize on 23 | zoom reset 24 | set echo on 25 | set info on 26 | set warning on 27 | set journal on 28 | -------------------------------------------------------------------------------- /test/gold/pincell_cell3.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 3 8 | cylinder height 500 radius 0.40005 9 | #{ id8 = Id("body") } 10 | brick x 500 y 500 z 500 11 | #{ id9 = Id("body") } 12 | subtract body { id8 } from body { id9 } 13 | cylinder height 500 radius 0.4572 14 | #{ id10 = Id("body") } 15 | #{ id11 = Id("body") } 16 | intersect body { id9 } { id10 } 17 | #{ id12 = Id("body") } 18 | #{id13 = ( id11 == id12 ) ? id10 : id12} 19 | body { id13 } name "Cell_3" 20 | group "mat:Zircaloy 4" add body { id13 } 21 | graphics flush 22 | set default autosize on 23 | zoom reset 24 | set echo on 25 | set info on 26 | set warning on 27 | set journal on 28 | -------------------------------------------------------------------------------- /test/materials.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/local_tests.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | import openmc 4 | 5 | from openmc_cad_adapter import to_cubit_journal 6 | 7 | from .test_utilities import diff_gold_file 8 | 9 | 10 | def openmc_reset(func): 11 | @functools.wraps(func) 12 | def wrapper(*args, **kwargs): 13 | openmc.reset_auto_ids() 14 | func(*args, **kwargs) 15 | return wrapper 16 | 17 | 18 | @openmc_reset 19 | def test_xcylinder(request): 20 | x_cyl = openmc.XCylinder(r=1.0, y0=10.0, z0=5.0) 21 | g = openmc.Geometry([openmc.Cell(region=-x_cyl)]) 22 | to_cubit_journal(g, world=(500, 500, 500), filename='xcylinder.jou') 23 | diff_gold_file('xcylinder.jou') 24 | 25 | 26 | @openmc_reset 27 | def test_ycylinder(request): 28 | y_cyl = openmc.YCylinder(r=1.0, x0=10.0, z0=5.0) 29 | g = openmc.Geometry([openmc.Cell(region=-y_cyl)]) 30 | to_cubit_journal(g, world=(500, 500, 500), filename='ycylinder.jou') 31 | diff_gold_file('ycylinder.jou') 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/test_utilities.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import difflib 4 | import filecmp 5 | 6 | from test import test_config 7 | 8 | def diff_files(test_output, gold_file): 9 | 10 | if test_config['update']: 11 | os.makedirs(os.path.dirname(gold_file), exist_ok=True) 12 | shutil.copy(test_output, gold_file) 13 | 14 | if not filecmp.cmp(test_output, gold_file): 15 | print(''.join(difflib.unified_diff(open(gold_file, 'r').readlines(), 16 | open(test_output, 'r').readlines()))) 17 | raise RuntimeError(f'{gold_file} and {test_output} are different') 18 | 19 | 20 | def diff_gold_file(gold_file, request=None): 21 | if request is not None: 22 | gold_file = request.path.parent / gold_file 23 | b = request.path.parent / 'gold' / gold_file.name 24 | else: 25 | b = os.path.join(os.path.dirname(__file__), 'gold', os.path.basename(gold_file)) 26 | diff_files(gold_file, b) -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | CI: 12 | runs-on: ubuntu-latest 13 | defaults: 14 | run: 15 | shell: bash -leo pipefail {0} 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | 21 | - uses: mamba-org/setup-micromamba@v1 22 | with: 23 | environment-file: .github/environment.yml 24 | init-shell: bash 25 | 26 | - name: Clone OpenMC 27 | run: | 28 | git clone https://github.com/openmc-dev/openmc --branch v0.15.0 $HOME/openmc 29 | 30 | - name: Install 31 | run: | 32 | python -m pip install . 33 | 34 | - name: Test examples 35 | run: | 36 | micromamba activate test-env 37 | OPENMC_EXAMPLES_DIR=$HOME/openmc/examples pytest -v ./test 38 | 39 | - name: Setup tmate session 40 | if: ${{ failure() }} 41 | uses: mxschmitt/action-tmate@v3 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 UChicago Argonne, LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /test/gold/nested_spheres.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 3 8 | sphere radius 20.0 9 | #{ id1 = Id("body") } 10 | brick x 500 y 500 z 500 11 | #{ id2 = Id("body") } 12 | subtract body { id1 } from body { id2 } 13 | sphere radius 30.0 14 | #{ id3 = Id("body") } 15 | #{ id4 = Id("body") } 16 | intersect body { id2 } { id3 } 17 | #{ id5 = Id("body") } 18 | #{id6 = ( id4 == id5 ) ? id3 : id5} 19 | body { id6 } name "Cell_3" 20 | group "mat:void" add body { id6 } 21 | #CELL 2 22 | sphere radius 10.0 23 | #{ id7 = Id("body") } 24 | brick x 500 y 500 z 500 25 | #{ id8 = Id("body") } 26 | subtract body { id7 } from body { id8 } 27 | sphere radius 20.0 28 | #{ id9 = Id("body") } 29 | #{ id10 = Id("body") } 30 | intersect body { id8 } { id9 } 31 | #{ id11 = Id("body") } 32 | #{id12 = ( id10 == id11 ) ? id9 : id11} 33 | body { id12 } name "Cell_2" 34 | group "mat:void" add body { id12 } 35 | #CELL 1 36 | sphere radius 10.0 37 | #{ id13 = Id("body") } 38 | body { id13 } name "Cell_1" 39 | group "mat:void" add body { id13 } 40 | graphics flush 41 | set default autosize on 42 | zoom reset 43 | set echo on 44 | set info on 45 | set warning on 46 | set journal on 47 | -------------------------------------------------------------------------------- /test/pincell_cell4.jou: -------------------------------------------------------------------------------- 1 | #CELL 4 2 | cylinder height 500 radius 0.4572 3 | #{ id14 = Id("body") } 4 | brick x 500 y 500 z 500 5 | #{ id15 = Id("body") } 6 | subtract body { id14 } from body { id15 } 7 | brick x 500 y 500 z 500 8 | #{ id16 = Id("body") } 9 | section body { id16 } with xplane offset -0.62992 10 | #{ id17 = Id("body") } 11 | intersect body { id15 } { id16 } 12 | #{ id18 = Id("body") } 13 | #{id19 = ( id17 == id18 ) ? id16 : id18} 14 | brick x 500 y 500 z 500 15 | #{ id20 = Id("body") } 16 | section body { id20 } with xplane offset 0.62992 reverse 17 | #{ id21 = Id("body") } 18 | intersect body { id19 } { id20 } 19 | #{ id22 = Id("body") } 20 | #{id23 = ( id21 == id22 ) ? id20 : id22} 21 | brick x 500 y 500 z 500 22 | #{ id24 = Id("body") } 23 | section body { id24 } with yplane offset -0.62992 24 | #{ id25 = Id("body") } 25 | intersect body { id23 } { id24 } 26 | #{ id26 = Id("body") } 27 | #{id27 = ( id25 == id26 ) ? id24 : id26} 28 | brick x 500 y 500 z 500 29 | #{ id28 = Id("body") } 30 | section body { id28 } with yplane offset 0.62992 reverse 31 | #{ id29 = Id("body") } 32 | intersect body { id27 } { id28 } 33 | #{ id30 = Id("body") } 34 | #{id31 = ( id29 == id30 ) ? id28 : id30} 35 | body { id31 } name "Cell_4" 36 | group "Material_4" add body { id31 } 37 | -------------------------------------------------------------------------------- /src/openmc_cad_adapter/geom_util.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | 4 | def vector_to_euler_xyz(v): 5 | v = np.asarray(v) 6 | v /= np.linalg.norm(v) 7 | 8 | x, y, z = v 9 | 10 | xy_norm = math.sqrt(x**2 + y**2) 11 | 12 | theta = np.arctan2(z, xy_norm) 13 | # if z component is zero, vector is in the xy plane 14 | if z == 0: 15 | theta = np.pi / 2 16 | phi = np.arctan2(y, x) 17 | 18 | # Ensure angles are within [0, 2*pi] range 19 | phi %= (2 * math.pi) 20 | theta %= (2 * math.pi) 21 | 22 | oe = 180 / math.pi 23 | return phi * oe, theta * oe, 0.0 24 | 25 | 26 | def rotate(id, x, y, z, cmds): 27 | if nonzero(x, y, z): 28 | phi, theta, psi = vector_to_euler_xyz((x, y, z)) 29 | cmds.append(f"body {{ {id} }} rotate {theta} about Y") 30 | cmds.append(f"body {{ {id} }} rotate {phi} about Z") 31 | # cmds.append(f"body {{ {id} }} rotate {phi} about Z") 32 | # cmds.append(f"body {{ {id} }} rotate {theta} about Y") 33 | # cmds.append(f"body {{ {id} }} rotate {psi} about X") 34 | 35 | 36 | def nonzero(*args): 37 | return any(arg != 0 for arg in args) 38 | 39 | 40 | def move( id, x, y, z, cmds): 41 | if nonzero( x, y, z ): 42 | cmds.append(f"body {{ {id} }} move {x} {y} {z}") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Conversion of OpenMC Geometry Components to CAD 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT) 4 | 5 | 6 | This project converts OpenMC models from XML files to a Cubit journal file for import as CAD geometry. 7 | 8 | ## Installation 9 | 10 | To install this tool run: 11 | 12 | ```shell 13 | python -m pip install git+https://github.com/openmc-dev/openmc_cad_adapter.git 14 | ``` 15 | 16 | This will make the `openmc_to_cad` script available for use. To convert an OpenMC model, run: 17 | 18 | ```shell 19 | openmc_to_cad /path/to/openmc/model.xml 20 | ``` 21 | 22 | ## Disclaimer 23 | 24 | There has been no methodical V&V on this converter; use at your own risk! 25 | 26 | 27 | ## Dependencies 28 | 29 | - [NumPy](https://numpy.org/) 30 | - [OpenMC](https://docs.openmc.org/en/stable/) (>= v0.14.0) 31 | 32 | ## Limitations 33 | 34 | There are several known and many unknown limitations of this tool. It is in a 35 | preliminary state and subject to considerable redesign, including the addition 36 | of a backend for other CAD engines. 37 | 38 | Specific Limitations: 39 | 40 | - general Cones are not handled 41 | - Torii are required to have a single minor radius, OpenMC allows for different minor radii orthogonal to the toroidal axis -------------------------------------------------------------------------------- /test/geometry.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 1.0 2.0 11 | 3 12 |
0.0 0.0 0.0
13 | 14 | 3 15 | 4 4 16 | 4 3 4 17 | 4 4 18 | 4 4 4 19 | 4 4 20 | 4 4 4 21 | 4 4 22 | 4 23 | 3 24 | 1 1 25 | 1 3 1 26 | 1 1 27 | 1 1 1 28 | 1 1 29 | 1 1 1 30 | 1 1 31 | 1 32 | 3 33 | 4 4 34 | 4 3 4 35 | 4 4 36 | 4 4 4 37 | 4 4 38 | 4 4 4 39 | 4 4 40 | 4 41 |
42 | 43 | 44 | 45 | 46 | 47 |
48 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [project] 6 | name = "openmc_cad_adapter" 7 | version = "0.1.0" 8 | description = "Tool to convert OpenMC Geometry input file to CAD" 9 | readme = "README.md" 10 | authors = [ 11 | { name = "Kevin Tew", email = "kevin@coreform.com" }, 12 | { name = "Patrick Shriwise", email = "pshriwise@gmail.com"} 13 | ] 14 | license = { file = "LICENSE" } 15 | requires-python = ">=3.7" 16 | 17 | dependencies = [ 18 | "numpy" 19 | ] 20 | 21 | classifiers = [ 22 | "Development Status :: 3 - Alpha", 23 | "Intended Audience :: Developers", 24 | "Intended Audience :: End Users/Desktop", 25 | "Intended Audience :: Science/Research", 26 | "License :: OSI Approved :: MIT License", 27 | "Natural Language :: English", 28 | "Operating System :: OS Independent", 29 | "Programming Language :: Python :: 3 :: Only", 30 | "Programming Language :: Python :: 3.7", 31 | "Programming Language :: Python :: 3.8", 32 | "Programming Language :: Python :: 3.9", 33 | "Programming Language :: Python :: 3.10", 34 | "Topic :: Scientific/Engineering :: Physics", 35 | ] 36 | 37 | [project.urls] 38 | "Bug Tracker" = "https://github.com/openmc-dev/openmc_cad_adapter/issues" 39 | Discussions = "https://openmc.discourse.org" 40 | "Source Code" = "https://github.com/openmc-dev/openmc_cad_adapter" 41 | 42 | [project.scripts] 43 | openmc_to_cad = "openmc_cad_adapter.to_cubit_journal:openmc_to_cad" 44 | -------------------------------------------------------------------------------- /test/gold/pincell_cell4.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 4 8 | cylinder height 500 radius 0.4572 9 | #{ id14 = Id("body") } 10 | brick x 500 y 500 z 500 11 | #{ id15 = Id("body") } 12 | subtract body { id14 } from body { id15 } 13 | brick x 500 y 500 z 500 14 | #{ id16 = Id("body") } 15 | section body { id16 } with xplane offset -0.62992 16 | #{ id17 = Id("body") } 17 | intersect body { id15 } { id16 } 18 | #{ id18 = Id("body") } 19 | #{id19 = ( id17 == id18 ) ? id16 : id18} 20 | brick x 500 y 500 z 500 21 | #{ id20 = Id("body") } 22 | section body { id20 } with xplane offset 0.62992 reverse 23 | #{ id21 = Id("body") } 24 | intersect body { id19 } { id20 } 25 | #{ id22 = Id("body") } 26 | #{id23 = ( id21 == id22 ) ? id20 : id22} 27 | brick x 500 y 500 z 500 28 | #{ id24 = Id("body") } 29 | section body { id24 } with yplane offset -0.62992 30 | #{ id25 = Id("body") } 31 | intersect body { id23 } { id24 } 32 | #{ id26 = Id("body") } 33 | #{id27 = ( id25 == id26 ) ? id24 : id26} 34 | brick x 500 y 500 z 500 35 | #{ id28 = Id("body") } 36 | section body { id28 } with yplane offset 0.62992 reverse 37 | #{ id29 = Id("body") } 38 | intersect body { id27 } { id28 } 39 | #{ id30 = Id("body") } 40 | #{id31 = ( id29 == id30 ) ? id28 : id30} 41 | body { id31 } name "Cell_4" 42 | group "mat:Borated water" add body { id31 } 43 | graphics flush 44 | set default autosize on 45 | zoom reset 46 | set echo on 47 | set info on 48 | set warning on 49 | set journal on 50 | -------------------------------------------------------------------------------- /test/pincell.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 1 4 | cylinder height 500 radius 0.39218 5 | #{ id1 = Id("body") } 6 | body { id1 } name "Cell_1" 7 | group "Material_1" add body { id1 } 8 | #CELL 2 9 | cylinder height 500 radius 0.39218 10 | #{ id2 = Id("body") } 11 | brick x 500 y 500 z 500 12 | #{ id3 = Id("body") } 13 | subtract body { id2 } from body { id3 } 14 | cylinder height 500 radius 0.40005 15 | #{ id4 = Id("body") } 16 | #{ id5 = Id("body") } 17 | intersect body { id3 } { id4 } 18 | #{ id6 = Id("body") } 19 | #{id7 = ( id5 == id6 ) ? id4 : id6} 20 | body { id7 } name "Cell_2" 21 | group "Material_2" add body { id7 } 22 | #CELL 3 23 | cylinder height 500 radius 0.40005 24 | #{ id8 = Id("body") } 25 | brick x 500 y 500 z 500 26 | #{ id9 = Id("body") } 27 | subtract body { id8 } from body { id9 } 28 | cylinder height 500 radius 0.4572 29 | #{ id10 = Id("body") } 30 | #{ id11 = Id("body") } 31 | intersect body { id9 } { id10 } 32 | #{ id12 = Id("body") } 33 | #{id13 = ( id11 == id12 ) ? id10 : id12} 34 | body { id13 } name "Cell_3" 35 | group "Material_3" add body { id13 } 36 | #CELL 4 37 | cylinder height 500 radius 0.4572 38 | #{ id14 = Id("body") } 39 | brick x 500 y 500 z 500 40 | #{ id15 = Id("body") } 41 | subtract body { id14 } from body { id15 } 42 | brick x 500 y 500 z 500 43 | #{ id16 = Id("body") } 44 | section body { id16 } with xplane offset -0.62992 45 | #{ id17 = Id("body") } 46 | intersect body { id15 } { id16 } 47 | #{ id18 = Id("body") } 48 | #{id19 = ( id17 == id18 ) ? id16 : id18} 49 | brick x 500 y 500 z 500 50 | #{ id20 = Id("body") } 51 | section body { id20 } with xplane offset 0.62992 reverse 52 | #{ id21 = Id("body") } 53 | intersect body { id19 } { id20 } 54 | #{ id22 = Id("body") } 55 | #{id23 = ( id21 == id22 ) ? id20 : id22} 56 | brick x 500 y 500 z 500 57 | #{ id24 = Id("body") } 58 | section body { id24 } with yplane offset -0.62992 59 | #{ id25 = Id("body") } 60 | intersect body { id23 } { id24 } 61 | #{ id26 = Id("body") } 62 | #{id27 = ( id25 == id26 ) ? id24 : id26} 63 | brick x 500 y 500 z 500 64 | #{ id28 = Id("body") } 65 | section body { id28 } with yplane offset 0.62992 reverse 66 | #{ id29 = Id("body") } 67 | intersect body { id27 } { id28 } 68 | #{ id30 = Id("body") } 69 | #{id31 = ( id29 == id30 ) ? id28 : id30} 70 | body { id31 } name "Cell_4" 71 | group "Material_4" add body { id31 } 72 | -------------------------------------------------------------------------------- /test/gold/pincell.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | cylinder height 500 radius 0.39218 9 | #{ id1 = Id("body") } 10 | body { id1 } name "Cell_1" 11 | group "mat:UO2 fuel at 2.4% wt enrichme" add body { id1 } 12 | #CELL 2 13 | cylinder height 500 radius 0.39218 14 | #{ id2 = Id("body") } 15 | brick x 500 y 500 z 500 16 | #{ id3 = Id("body") } 17 | subtract body { id2 } from body { id3 } 18 | cylinder height 500 radius 0.40005 19 | #{ id4 = Id("body") } 20 | #{ id5 = Id("body") } 21 | intersect body { id3 } { id4 } 22 | #{ id6 = Id("body") } 23 | #{id7 = ( id5 == id6 ) ? id4 : id6} 24 | body { id7 } name "Cell_2" 25 | group "mat:Helium for gap" add body { id7 } 26 | #CELL 3 27 | cylinder height 500 radius 0.40005 28 | #{ id8 = Id("body") } 29 | brick x 500 y 500 z 500 30 | #{ id9 = Id("body") } 31 | subtract body { id8 } from body { id9 } 32 | cylinder height 500 radius 0.4572 33 | #{ id10 = Id("body") } 34 | #{ id11 = Id("body") } 35 | intersect body { id9 } { id10 } 36 | #{ id12 = Id("body") } 37 | #{id13 = ( id11 == id12 ) ? id10 : id12} 38 | body { id13 } name "Cell_3" 39 | group "mat:Zircaloy 4" add body { id13 } 40 | #CELL 4 41 | cylinder height 500 radius 0.4572 42 | #{ id14 = Id("body") } 43 | brick x 500 y 500 z 500 44 | #{ id15 = Id("body") } 45 | subtract body { id14 } from body { id15 } 46 | brick x 500 y 500 z 500 47 | #{ id16 = Id("body") } 48 | section body { id16 } with xplane offset -0.62992 49 | #{ id17 = Id("body") } 50 | intersect body { id15 } { id16 } 51 | #{ id18 = Id("body") } 52 | #{id19 = ( id17 == id18 ) ? id16 : id18} 53 | brick x 500 y 500 z 500 54 | #{ id20 = Id("body") } 55 | section body { id20 } with xplane offset 0.62992 reverse 56 | #{ id21 = Id("body") } 57 | intersect body { id19 } { id20 } 58 | #{ id22 = Id("body") } 59 | #{id23 = ( id21 == id22 ) ? id20 : id22} 60 | brick x 500 y 500 z 500 61 | #{ id24 = Id("body") } 62 | section body { id24 } with yplane offset -0.62992 63 | #{ id25 = Id("body") } 64 | intersect body { id23 } { id24 } 65 | #{ id26 = Id("body") } 66 | #{id27 = ( id25 == id26 ) ? id24 : id26} 67 | brick x 500 y 500 z 500 68 | #{ id28 = Id("body") } 69 | section body { id28 } with yplane offset 0.62992 reverse 70 | #{ id29 = Id("body") } 71 | intersect body { id27 } { id28 } 72 | #{ id30 = Id("body") } 73 | #{id31 = ( id29 == id30 ) ? id28 : id30} 74 | body { id31 } name "Cell_4" 75 | group "mat:Borated water" add body { id31 } 76 | graphics flush 77 | set default autosize on 78 | zoom reset 79 | set echo on 80 | set info on 81 | set warning on 82 | set journal on 83 | -------------------------------------------------------------------------------- /test/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | import difflib 3 | import filecmp 4 | from pathlib import Path 5 | 6 | import subprocess 7 | 8 | import pytest 9 | 10 | from openmc_cad_adapter import to_cubit_journal 11 | import openmc 12 | 13 | from test import diff_files 14 | 15 | 16 | examples = ["pincell/build_xml.py", 17 | "lattice/hexagonal/build_xml.py", 18 | "assembly/assembly.py"] 19 | 20 | 21 | if 'OPENMC_EXAMPLES_DIR' not in os.environ: 22 | raise EnvironmentError('Variable OPENMC_EXAMPLES_DIR is required') 23 | 24 | 25 | OPENMC_EXAMPLES_DIR = Path(os.environ['OPENMC_EXAMPLES_DIR']).resolve() 26 | 27 | 28 | def example_name(example): 29 | return '-'.join(example.split('/')[:-1]) 30 | 31 | 32 | def generate_example_xml(example): 33 | if 'assembly' in example: 34 | subprocess.Popen(['python', str(OPENMC_EXAMPLES_DIR / example), '--generate']).wait() 35 | else: 36 | exec(open(OPENMC_EXAMPLES_DIR / example).read()) 37 | 38 | 39 | @pytest.mark.parametrize("example", examples, ids=example_name) 40 | def test_examples(example, request, run_in_tmpdir): 41 | 42 | openmc.reset_auto_ids() 43 | generate_example_xml(example) 44 | 45 | openmc.reset_auto_ids() 46 | model = openmc.Model.from_xml() 47 | 48 | world = [500, 500, 500] 49 | output = example_name(example) + '.jou' 50 | to_cubit_journal(model.geometry, world=world, filename=output) 51 | 52 | gold_file = request.path.parent / Path('gold') / Path(output) 53 | diff_files(output, gold_file) 54 | 55 | 56 | def test_cell_by_cell_conversion(request, run_in_tmpdir): 57 | openmc.reset_auto_ids() 58 | exec(open(OPENMC_EXAMPLES_DIR / "pincell/build_xml.py").read()) 59 | 60 | openmc.reset_auto_ids() 61 | model = openmc.Model.from_xml() 62 | 63 | cell_ids = list(model.geometry.get_all_cells().keys()) 64 | 65 | world = [500, 500, 500] 66 | output = 'pincell' 67 | to_cubit_journal(model.geometry, world=world, cells=cell_ids, filename=output) 68 | 69 | for cell_id in cell_ids: 70 | output = f'pincell_cell{cell_id}.jou' 71 | gold_file = request.path.parent / Path('gold') / Path(output) 72 | diff_files(output, gold_file) 73 | 74 | 75 | @pytest.mark.parametrize("example", examples, ids=example_name) 76 | def test_examples_cli(example, request, run_in_tmpdir): 77 | 78 | openmc.reset_auto_ids() 79 | generate_example_xml(example) 80 | 81 | openmc.reset_auto_ids() 82 | world = [500, 500, 500] 83 | output = example_name(example) + '.jou' 84 | cmd = ['openmc_to_cad', '.', '-o', output, '--world'] + [str(w) for w in world] 85 | pipe = subprocess.Popen(cmd) 86 | pipe.wait() 87 | if pipe.returncode != 0: 88 | raise RuntimeError(f'Command {" ".join(cmd)} failed') 89 | 90 | gold_file = request.path.parent / Path('gold') / Path(output) 91 | diff_files(output, gold_file) -------------------------------------------------------------------------------- /test/gold/plane.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | brick x 1000 y 1000 z 1000 9 | #{ id1 = Id("body") } 10 | body { id1 } move 0.0 0.0 -500 11 | Rotate body { id1 } about 0 0 0 direction -0.7071067811865476 0.7071067811865476 0.0 Angle 90.0 12 | body { id1 } move -2.4999999999999996 -2.4999999999999996 -0.0 13 | brick x 500 y 500 z 500 14 | #{ id2 = Id("body") } 15 | subtract body { id1 } from body { id2 } 16 | brick x 1000 y 1000 z 1000 17 | #{ id3 = Id("body") } 18 | body { id3 } move 0.0 0.0 -500 19 | Rotate body { id3 } about 0 0 0 direction -0.7071067811865476 0.7071067811865476 0.0 Angle 90.0 20 | body { id3 } move 2.4999999999999996 2.4999999999999996 0.0 21 | brick x 500 y 500 z 500 22 | #{ id4 = Id("body") } 23 | intersect body { id3 } { id4 } 24 | #{ id5 = Id("body") } 25 | intersect body { id2 } { id4 } 26 | #{ id6 = Id("body") } 27 | #{id7 = ( id5 == id6 ) ? id4 : id6} 28 | brick x 1000 y 1000 z 1000 29 | #{ id8 = Id("body") } 30 | body { id8 } move 0.0 0.0 -500 31 | Rotate body { id8 } about 0 0 0 direction -1.0 0.0 0.0 Angle 45.00000000000001 32 | body { id8 } move -0.0 -2.4999999999999996 -2.4999999999999996 33 | brick x 500 y 500 z 500 34 | #{ id9 = Id("body") } 35 | subtract body { id8 } from body { id9 } 36 | #{ id10 = Id("body") } 37 | intersect body { id7 } { id9 } 38 | #{ id11 = Id("body") } 39 | #{id12 = ( id10 == id11 ) ? id9 : id11} 40 | brick x 1000 y 1000 z 1000 41 | #{ id13 = Id("body") } 42 | body { id13 } move 0.0 0.0 -500 43 | Rotate body { id13 } about 0 0 0 direction -1.0 0.0 0.0 Angle 45.00000000000001 44 | body { id13 } move 0.0 2.4999999999999996 2.4999999999999996 45 | brick x 500 y 500 z 500 46 | #{ id14 = Id("body") } 47 | intersect body { id13 } { id14 } 48 | #{ id15 = Id("body") } 49 | intersect body { id12 } { id14 } 50 | #{ id16 = Id("body") } 51 | #{id17 = ( id15 == id16 ) ? id14 : id16} 52 | brick x 1000 y 1000 z 1000 53 | #{ id18 = Id("body") } 54 | body { id18 } move 0.0 0.0 -500 55 | Rotate body { id18 } about 0 0 0 direction 0.0 1.0 0.0 Angle 45.00000000000001 56 | body { id18 } move -2.4999999999999996 -0.0 -2.4999999999999996 57 | brick x 500 y 500 z 500 58 | #{ id19 = Id("body") } 59 | subtract body { id18 } from body { id19 } 60 | #{ id20 = Id("body") } 61 | intersect body { id17 } { id19 } 62 | #{ id21 = Id("body") } 63 | #{id22 = ( id20 == id21 ) ? id19 : id21} 64 | brick x 1000 y 1000 z 1000 65 | #{ id23 = Id("body") } 66 | body { id23 } move 0.0 0.0 -500 67 | Rotate body { id23 } about 0 0 0 direction 0.0 1.0 0.0 Angle 45.00000000000001 68 | body { id23 } move 2.4999999999999996 0.0 2.4999999999999996 69 | brick x 500 y 500 z 500 70 | #{ id24 = Id("body") } 71 | intersect body { id23 } { id24 } 72 | #{ id25 = Id("body") } 73 | intersect body { id22 } { id24 } 74 | #{ id26 = Id("body") } 75 | #{id27 = ( id25 == id26 ) ? id24 : id26} 76 | body { id27 } name "Cell_1" 77 | group "mat:void" add body { id27 } 78 | graphics flush 79 | set default autosize on 80 | zoom reset 81 | set echo on 82 | set info on 83 | set warning on 84 | set journal on 85 | -------------------------------------------------------------------------------- /test/test_quadric.py: -------------------------------------------------------------------------------- 1 | 2 | import pytest 3 | 4 | import openmc 5 | 6 | from openmc_cad_adapter import to_cubit_journal 7 | from openmc_cad_adapter.gqs import * 8 | 9 | 10 | def test_ellipsoid_classification(): 11 | # ELLIPSOID 12 | testEllip = openmc.Quadric(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0) 13 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testEllip) 14 | assert quadric_type == ELLIPSOID 15 | 16 | 17 | def test_one_sheet_hyperboloid_classification(): 18 | # ONE_SHEET_HYPERBOLOID 19 | testOneSheet = openmc.Quadric(1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0) 20 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testOneSheet) 21 | assert quadric_type == ONE_SHEET_HYPERBOLOID 22 | 23 | 24 | def test_two_sheet_hyperboloid_classification(): 25 | # TWO_SHEET_HYPERBOLOID 26 | testTwoSheet = openmc.Quadric(-1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0) 27 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testTwoSheet) 28 | assert quadric_type == TWO_SHEET_HYPERBOLOID 29 | 30 | 31 | def test_elliptic_cone_classification(): 32 | # ELLIPTIC_CONE 33 | testEllCone = openmc.Quadric(1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) 34 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testEllCone) 35 | assert quadric_type == ELLIPTIC_CONE 36 | 37 | 38 | def test_elliptic_paraboloid_classification(): 39 | # ELLIPTIC_PARABOLOID 40 | testEllPara = openmc.Quadric(1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0) 41 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testEllPara) 42 | assert quadric_type == ELLIPTIC_PARABOLOID 43 | 44 | 45 | def test_hyperbolic_paraboloid_classification(): 46 | # HYPERBOLIC_PARABOLOID 47 | testHypPara = openmc.Quadric(1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0) 48 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testHypPara) 49 | assert quadric_type == HYPERBOLIC_PARABOLOID 50 | 51 | 52 | def test_elliptic_cyl_classification(): 53 | # ELLIPTIC_CYL 54 | testEllCyl = openmc.Quadric(1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0) 55 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testEllCyl) 56 | assert quadric_type == ELLIPTIC_CYLINDER 57 | 58 | 59 | def test_hyperbolic_cyl_classification(): 60 | # HYPERBOLIC_CYL 61 | testHypCyl = openmc.Quadric(1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0) 62 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testHypCyl) 63 | assert quadric_type == HYPERBOLIC_CYLINDER 64 | 65 | 66 | def test_parabolic_cyl_classification(): 67 | # PARABOLIC_CYL 68 | testParaCyl = openmc.Quadric(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0) 69 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testParaCyl) 70 | assert quadric_type == PARABOLIC_CYLINDER 71 | 72 | 73 | # Transformation Tests 74 | def test_ellipsoid_classification(): 75 | # ELLIPSOID 76 | testRotEllip = openmc.Quadric(103, 125, 66, -48, -12, -60, 0, 0, 0, -294) 77 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testRotEllip) 78 | assert quadric_type == ELLIPSOID 79 | 80 | 81 | def test_elliptic_cone_classification(): 82 | # ELLIPTIC_CONE 83 | testRotCone = openmc.Quadric(3, 3, -1, 2, 0, 0, 0, 0, 0, 0) 84 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testRotCone) 85 | assert quadric_type == ELLIPTIC_CONE 86 | 87 | 88 | def test_elliptic_paraboloid_classification(): 89 | # ELLIPTIC_PARABOLOID 90 | testRotEllParab = openmc.Quadric(1, 3, 1, 2, 2, 2, -2, 4, 2, 12) 91 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testRotEllParab) 92 | assert quadric_type == ELLIPTIC_PARABOLOID 93 | 94 | 95 | def test_elliptic_cylinder_classification(): 96 | # ELLIPTIC_CYLINDER 97 | testRotEllCyl = openmc.Quadric(5, 2, 5, -4, -4, -2, 6, -12, 18, -3) 98 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testRotEllCyl) 99 | assert quadric_type == ELLIPTIC_CYLINDER 100 | 101 | 102 | def test_parabolic_cylinder_classification(): 103 | # PARABOLIC CYLINDER 104 | testRotParaCyl = openmc.Quadric(9, 36, 4, -36, -24, 12, -16, -24, -48, 56) 105 | quadric_type, A, B, C, K, _, _ = characterize_general_quadratic(testRotParaCyl) 106 | assert quadric_type == PARABOLIC_CYLINDER -------------------------------------------------------------------------------- /src/openmc_cad_adapter/gqs.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numpy.linalg import matrix_rank 3 | 4 | UNKNOWN_QUADRIC = -1 5 | ELLIPSOID = 1 6 | ONE_SHEET_HYPERBOLOID = 2 7 | TWO_SHEET_HYPERBOLOID = 3 8 | ELLIPTIC_CONE = 4 9 | ELLIPTIC_PARABOLOID = 5 10 | HYPERBOLIC_PARABOLOID = 6 11 | ELLIPTIC_CYLINDER = 7 12 | HYPERBOLIC_CYLINDER = 8 13 | PARABOLIC_CYLINDER = 9 14 | 15 | 16 | def characterize_general_quadratic( surface ): #s surface 17 | gq_tol = 1e-6 18 | equivalence_tol = 1e-8 19 | a = surface.coefficients['a'] 20 | b = surface.coefficients['b'] 21 | c = surface.coefficients['c'] 22 | d = surface.coefficients['d'] 23 | e = surface.coefficients['e'] 24 | f = surface.coefficients['f'] 25 | g = surface.coefficients['g'] 26 | h = surface.coefficients['h'] 27 | j = surface.coefficients['j'] 28 | k = surface.coefficients['k'] 29 | #coefficient matrix 30 | Aa = np.asarray([[a, d/2, f/2], 31 | [d/2, b, e/2], 32 | [f/2, e/2, c]]) 33 | #hessian matrix 34 | Ac = np.asarray([[a, d/2, f/2, g/2], 35 | [d/2, b, e/2, h/2], 36 | [f/2, e/2, c, j/2], 37 | [g/2, h/2, j/2, k]]) 38 | rank_Aa = matrix_rank( Aa ) 39 | rank_Ac = matrix_rank( Ac ) 40 | 41 | det_Ac = np.linalg.det(Ac) 42 | if np.abs( det_Ac ) < gq_tol: 43 | delta = 0 44 | else: 45 | delta = -1 if det_Ac < 0 else 1 46 | 47 | eigenvalues, eigenvectors = np.linalg.eig(Aa) 48 | signs = np.array([0, 0, 0]) 49 | for i in range(0, 3): 50 | if eigenvalues[i] > -1 * gq_tol: 51 | signs[i] = 1 52 | else: 53 | signs[i] = -1 54 | 55 | S = 1 if np.abs( signs.sum() ) == 3 else -1 56 | 57 | B = np.array([[ -g/2], [-h/2], [-j/2 ]]) 58 | 59 | Aai = np.linalg.pinv( Aa ) 60 | 61 | C = np.dot(Aai, B) 62 | 63 | dx = C[0] 64 | dy = C[1] 65 | dz = C[2] 66 | 67 | #Update the constant using the resulting translation 68 | K_ = k + (g/2)*dx + (h/2)*dy + (j/2)*dz 69 | K_ = K_[0] 70 | 71 | if rank_Aa == 2 and rank_Ac == 3 and S == 1: 72 | delta = -1 if K_ * signs[0] < 0 else 1 73 | 74 | D = -1 if K_ * signs[0] else 1 75 | 76 | 77 | def find_type( rAa, rAc, delta, S, D ): 78 | quadric_type = UNKNOWN_QUADRIC 79 | if 3 == rAa and 4 == rAc and -1 == delta and 1 == S: 80 | quadric_type = ELLIPSOID 81 | elif 3 == rAa and 4 == rAc and 1 == delta and -1 == S: 82 | quadric_type = ONE_SHEET_HYPERBOLOID 83 | elif 3 == rAa and 4 == rAc and -1 == delta and -1 == S: 84 | quadric_type = TWO_SHEET_HYPERBOLOID 85 | elif 3 == rAa and 3 == rAc and 0 == delta and -1 == S: 86 | quadric_type = ELLIPTIC_CONE 87 | elif 2 == rAa and 4 == rAc and -1 == delta and 1 == S: 88 | quadric_type = ELLIPTIC_PARABOLOID 89 | elif 2 == rAa and 4 == rAc and 1 == delta and -1 == S: 90 | quadric_type = HYPERBOLIC_PARABOLOID 91 | elif 2 == rAa and 3 == rAc and -1 == delta and 1 == S: 92 | quadric_type = ELLIPTIC_CYLINDER 93 | elif 2 == rAa and 3 == rAc and 0 == delta and -1 == S: 94 | quadric_type = HYPERBOLIC_CYLINDER 95 | elif 1 == rAa and 3 == rAc and 0 == delta and 1 == S: 96 | quadric_type = PARABOLIC_CYLINDER 97 | else: 98 | quadric_type = UNKNOWN_QUADRIC 99 | 100 | # special case, replace delta with D 101 | if 2 == rAa and 3 == rAc and 1 == S and D != 0 : 102 | quadric_type = find_type( rAa, rAc, D, S, 0 ) 103 | 104 | 105 | if quadric_type == UNKNOWN_QUADRIC: 106 | msg = f'UNKNOWN QUADRIC: rAa={rAa}, rAc={rAc}, delta={delta}, S={S}, D={D}' 107 | raise ValueError(msg) 108 | 109 | return quadric_type 110 | 111 | gq_type = find_type(rank_Aa, rank_Ac, delta, S, D) 112 | 113 | #set the translation 114 | translation = C 115 | 116 | rotation_matrix = eigenvectors 117 | 118 | for i in range( 0, 3 ): 119 | if abs(eigenvalues[i]) < gq_tol: 120 | eigenvalues[i] = 0 121 | 122 | A_ = eigenvalues[0] 123 | B_ = eigenvalues[1] 124 | C_ = eigenvalues[2]; 125 | D_ = 0; E_ = 0; F_ = 0; 126 | G_ = 0; H_ = 0; J_ = 0; 127 | 128 | # alter type and coefficients for special cases 129 | # where coefficients are near-zero 130 | if gq_type == ONE_SHEET_HYPERBOLOID: 131 | if abs(K_) < equivalence_tol: 132 | K_ = 0 133 | gq_type = ELLIPTIC_CONE 134 | if gq_type == TWO_SHEET_HYPERBOLOID: 135 | if abs(K_) < equivalence_tol: 136 | K_ = 0 137 | gq_type = ELLIPTIC_CONE 138 | if gq_type == ELLIPSOID: 139 | if abs(A_) < equivalence_tol: 140 | A_ = 0 141 | gq_type = ELLIPTIC_CYLINDER 142 | elif abs( B_) < equivalence_tol: 143 | B_ = 0 144 | gq_type = ELLIPTIC_CYLINDER 145 | elif abs( C_) < equivalence_tol: 146 | C_ = 0 147 | gq_type = ELLIPTIC_CYLINDER 148 | 149 | return (gq_type, A_, B_, C_, K_, translation, rotation_matrix) 150 | 151 | 152 | __all__ = ["characterize_general_quadratic", 153 | "ELLIPSOID", 154 | "ONE_SHEET_HYPERBOLOID", 155 | "TWO_SHEET_HYPERBOLOID", 156 | "ELLIPTIC_CONE", 157 | "ELLIPTIC_PARABOLOID", 158 | "HYPERBOLIC_PARABOLOID", 159 | "ELLIPTIC_CYLINDER", 160 | "HYPERBOLIC_CYLINDER", 161 | "PARABOLIC_CYLINDER"] 162 | -------------------------------------------------------------------------------- /test/test_local.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | import pytest 4 | 5 | import openmc 6 | 7 | from openmc_cad_adapter import to_cubit_journal 8 | 9 | from .test_utilities import diff_gold_file 10 | from test import run_in_tmpdir 11 | 12 | 13 | def reset_openmc_ids(func): 14 | """ 15 | Decorator to reset the auto-generated IDs in OpenMC before running a test 16 | """ 17 | @wraps(func) 18 | def wrapper(*args, **kwargs): 19 | openmc.reset_auto_ids() 20 | func(*args, **kwargs) 21 | return wrapper 22 | 23 | 24 | @reset_openmc_ids 25 | def test_planes(request, run_in_tmpdir): 26 | plane1 = openmc.Plane(a=1.0, b=1.0, c=0.0, d=-5.0) 27 | plane2 = openmc.Plane(a=1.0, b=1.0, c=0.0, d=5.0) 28 | plane3 = openmc.Plane(a=0.0, b=1.0, c=1.0, d=-5.0) 29 | plane4 = openmc.Plane(a=0.0, b=1.0, c=1.0, d=5.0) 30 | plane5 = openmc.Plane(a=1.0, b=0.0, c=1.0, d=-5.0) 31 | plane6 = openmc.Plane(a=1.0, b=0.0, c=1.0, d=5.0) 32 | g = openmc.Geometry([openmc.Cell(region=+plane1 & -plane2 & +plane3 & -plane4 & +plane5 & -plane6)]) 33 | to_cubit_journal(g, world=(500, 500, 500), filename='plane.jou') 34 | diff_gold_file('plane.jou') 35 | 36 | 37 | @reset_openmc_ids 38 | def test_nested_spheres(request, run_in_tmpdir): 39 | inner_sphere = openmc.Sphere(r=10.0) 40 | middle_sphere = openmc.Sphere(r=20.0) 41 | outer_sphere = openmc.Sphere(r=30.0) 42 | 43 | inner_cell = openmc.Cell(region=-inner_sphere) 44 | middle_cell = openmc.Cell(region=+inner_sphere & -middle_sphere) 45 | outer_cell = openmc.Cell(region=+middle_sphere & -outer_sphere) 46 | 47 | g = openmc.Geometry([outer_cell, middle_cell, inner_cell]) 48 | to_cubit_journal(g, world=(500, 500, 500), filename='nested_spheres.jou') 49 | diff_gold_file('nested_spheres.jou') 50 | 51 | 52 | # Test the XCylinder and YCylinder classes, the ZCylinder surface is tested 53 | # extensively in the OpenMC example tests 54 | @reset_openmc_ids 55 | def test_xcylinder(request, run_in_tmpdir): 56 | x_cyl = openmc.XCylinder(r=1.0, y0=10.0, z0=5.0) 57 | g = openmc.Geometry([openmc.Cell(region=-x_cyl)]) 58 | to_cubit_journal(g, world=(500, 500, 500), filename='xcylinder.jou') 59 | diff_gold_file('xcylinder.jou') 60 | 61 | 62 | @reset_openmc_ids 63 | def test_ycylinder(request, run_in_tmpdir): 64 | y_cyl = openmc.YCylinder(r=1.0, x0=10.0, z0=5.0) 65 | g = openmc.Geometry([openmc.Cell(region=-y_cyl)]) 66 | to_cubit_journal(g, world=(500, 500, 500), filename='ycylinder.jou') 67 | diff_gold_file('ycylinder.jou') 68 | 69 | 70 | @reset_openmc_ids 71 | def test_cylinder(request, run_in_tmpdir): 72 | cyl = openmc.Cylinder(x0=0.0, y0=0.0, z0=0.0, r=6.0, dx=0.7071, dy=0.7071, dz=0.0) 73 | g = openmc.Geometry([openmc.Cell(region=-cyl)]) 74 | to_cubit_journal(g, world=(500, 500, 500), filename='cylinder.jou') 75 | diff_gold_file('cylinder.jou') 76 | 77 | 78 | @reset_openmc_ids 79 | def test_x_cone(request, run_in_tmpdir): 80 | x_cone = openmc.XCone(x0=30.0, y0=3.0, z0=5.0, r2=5.0) 81 | g = openmc.Geometry([openmc.Cell(region=-x_cone)]) 82 | to_cubit_journal(g, world=(500, 500, 500), filename='x_cone.jou') 83 | diff_gold_file('x_cone.jou') 84 | 85 | 86 | @reset_openmc_ids 87 | def test_y_cone(request, run_in_tmpdir): 88 | y_cone = openmc.YCone(x0=40.0, y0=20.0, z0=7.0, r2=2.0) 89 | g = openmc.Geometry([openmc.Cell(region=-y_cone)]) 90 | to_cubit_journal(g, world=(500, 500, 500), filename='y_cone.jou') 91 | diff_gold_file('y_cone.jou') 92 | 93 | 94 | @reset_openmc_ids 95 | def test_z_cone(request, run_in_tmpdir): 96 | z_cone = openmc.ZCone(x0=50.0, y0=10.0, z0=2.0, r2=0.25) 97 | g = openmc.Geometry([openmc.Cell(region=-z_cone)]) 98 | to_cubit_journal(g, world=(500, 500, 500), filename='z_cone.jou') 99 | diff_gold_file('z_cone.jou') 100 | 101 | 102 | @reset_openmc_ids 103 | def test_x_torus(request, run_in_tmpdir): 104 | x_torus = openmc.XTorus(x0=10.0, y0=10.0, z0=10.0, a=5.0, b=2.0, c=2.0) 105 | g = openmc.Geometry([openmc.Cell(region=-x_torus)]) 106 | to_cubit_journal(g, world=(500, 500, 500), filename='x_torus.jou') 107 | diff_gold_file('x_torus.jou') 108 | 109 | 110 | @reset_openmc_ids 111 | def test_y_torus(request, run_in_tmpdir): 112 | y_torus = openmc.YTorus(x0=-10.0, y0=-10.0, z0=-10.0, a=5.0, b=2.0, c=2.0) 113 | g = openmc.Geometry([openmc.Cell(region=-y_torus)]) 114 | to_cubit_journal(g, world=(500, 500, 500), filename='y_torus.jou') 115 | diff_gold_file('y_torus.jou') 116 | 117 | 118 | @reset_openmc_ids 119 | def test_z_torus(request, run_in_tmpdir): 120 | z_torus = openmc.ZTorus(x0=50.0, y0=50.0, z0=50.0, a=5.0, b=2.0, c=2.0) 121 | g = openmc.Geometry([openmc.Cell(region=-z_torus)]) 122 | to_cubit_journal(g, world=(500, 500, 500), filename='z_torus.jou') 123 | diff_gold_file('z_torus.jou') 124 | 125 | 126 | @reset_openmc_ids 127 | def test_torus_diff_radii(request, run_in_tmpdir): 128 | with pytest.raises(ValueError): 129 | z_torus = openmc.ZTorus(x0=50.0, y0=50.0, z0=50.0, a=5.0, b=2.0, c=3.0) 130 | g = openmc.Geometry([openmc.Cell(region=-z_torus)]) 131 | to_cubit_journal(g, world=(500, 500, 500), filename='a_torus.jou') 132 | 133 | 134 | @reset_openmc_ids 135 | def test_general_cone(request, run_in_tmpdir): 136 | with pytest.raises(NotImplementedError): 137 | cone = openmc.Cone(x0=0.0, y0=0.0, z0=0.0, r2=6.0, dx=1, dy=1, dz=1) 138 | g = openmc.Geometry([openmc.Cell(region=-cone)]) 139 | to_cubit_journal(g, world=(500, 500, 500), filename='cone.jou') 140 | 141 | @reset_openmc_ids 142 | def test_gq_ellipsoid(request, run_in_tmpdir): 143 | ellipsoid = openmc.Quadric(1, 2, 3, k=-1) 144 | g = openmc.Geometry([openmc.Cell(region=-ellipsoid)]) 145 | to_cubit_journal(g, world=(500, 500, 500), filename='ellipsoid.jou') 146 | diff_gold_file('ellipsoid.jou') 147 | -------------------------------------------------------------------------------- /src/openmc_cad_adapter/surfaces.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | import sys 3 | import math 4 | import warnings 5 | 6 | import numpy as np 7 | import openmc 8 | 9 | from .cubit_util import emit_get_last_id, lastid 10 | from .geom_util import move, rotate 11 | 12 | def indent(indent_size): 13 | return ' ' * (2*indent_size) 14 | 15 | 16 | class CADSurface(ABC): 17 | 18 | def to_cubit_surface(self, ent_type, node, extents, inner_world=None, hex=False): 19 | ids, cmds = self.to_cubit_surface_inner(ent_type, node, extents, inner_world, hex) 20 | # TODO: Add boundary condition to the correct surface(s) 21 | # cmds += self.boundary_condition(ids) 22 | return ids, cmds 23 | 24 | @abstractmethod 25 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 26 | raise NotImplementedError 27 | 28 | def boundary_condition(self, cad_surface_ids): 29 | if self.boundary_type == 'transmission': 30 | return [] 31 | cmds = [] 32 | cmds.append(f'group \"boundary:{self.boundary_type}\" add surface {cad_surface_ids[2:]}') 33 | return cmds 34 | 35 | @classmethod 36 | def from_openmc_surface(cls, surface): 37 | with warnings.catch_warnings() as w: 38 | warnings.simplefilter("ignore") 39 | return cls.from_openmc_surface_inner(surface) 40 | 41 | @classmethod 42 | @abstractmethod 43 | def from_openmc_surface_inner(cls, surface): 44 | raise NotImplementedError 45 | 46 | 47 | class CADPlane(CADSurface, openmc.Plane): 48 | 49 | @staticmethod 50 | def lreverse(node): 51 | return "" if node.side == '-' else "reverse" 52 | 53 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 54 | cmds = [] 55 | 56 | n = np.array([self.coefficients[k] for k in ('a', 'b', 'c')]) 57 | distance = self.coefficients['d'] / np.linalg.norm(n) 58 | 59 | # Create cutter block larger than the world and rotate/translate it so 60 | # the +z plane of the block is coincident with this general plane 61 | max_extent = np.max(extents) 62 | cmds.append(f"brick x {2*max_extent} y {2*max_extent} z {2*max_extent}" ) 63 | ids = emit_get_last_id( ent_type, cmds) 64 | cmds.append(f"body {{ { ids } }} move 0.0 0.0 {-max_extent}") 65 | 66 | nhat = n / np.linalg.norm(n) 67 | rhat = np.array([0.0, 0.0, 1.0]) 68 | angle = math.degrees(math.acos(np.dot(nhat, rhat))) 69 | 70 | if not math.isclose(angle, 0.0, abs_tol=1e-6): 71 | rot_axis = np.cross(rhat, nhat) 72 | rot_axis /= np.linalg.norm(rot_axis) 73 | axis = f"{rot_axis[0]} {rot_axis[1]} {rot_axis[2]}" 74 | cmds.append(f"Rotate body {{ {ids} }} about 0 0 0 direction {axis} Angle {angle}") 75 | 76 | tvec = distance*nhat 77 | cmds.append(f"body {{ { ids } }} move {tvec[0]} {tvec[1]} {tvec[2]}") 78 | 79 | cmds.append(f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 80 | wid = emit_get_last_id( ent_type, cmds) 81 | # if positive half space we subtract the cutter block from the world 82 | if node.side != '-': 83 | cmds.append(f"subtract body {{ { ids } }} from body {{ { wid } }}") 84 | # if negative half space we intersect the cutter block with the world 85 | else: 86 | cmds.append(f"intersect body {{ { ids } }} {{ { wid } }}") 87 | 88 | return wid, cmds 89 | 90 | @classmethod 91 | def from_openmc_surface_inner(cls, plane): 92 | return cls(a=plane.a, b=plane.b, c=plane.c, d=plane.d, boundary_type=plane.boundary_type, albedo=plane.albedo, name=plane.name, surface_id=plane.id) 93 | 94 | 95 | class CADXPlane(CADSurface, openmc.XPlane): 96 | 97 | @staticmethod 98 | def reverse(node): 99 | return "reverse" if node.side == '-' else "" 100 | 101 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 102 | cad_cmds = [] 103 | cad_cmds.append(f"brick x {extents[0]} y {extents[1]} z {extents[2]}") 104 | ids = emit_get_last_id( ent_type, cad_cmds) 105 | cad_cmds.append(f"section body {{ {ids} }} with xplane offset {self.coefficients['x0']} {self.reverse(node)}") 106 | return ids, cad_cmds 107 | 108 | @classmethod 109 | def from_openmc_surface_inner(cls, plane): 110 | return cls(x0=plane.x0, boundary_type=plane.boundary_type, albedo=plane.albedo, name=plane.name, surface_id=plane.id) 111 | 112 | 113 | class CADYPlane(CADSurface, openmc.YPlane): 114 | 115 | @staticmethod 116 | def reverse(node): 117 | return "reverse" if node.side == '-' else "" 118 | 119 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 120 | cad_cmds = [] 121 | cad_cmds.append(f"brick x {extents[0]} y {extents[1]} z {extents[2]}") 122 | ids = emit_get_last_id( ent_type, cad_cmds) 123 | cad_cmds.append(f"section body {{ {ids} }} with yplane offset {self.coefficients['y0']} {self.reverse(node)}") 124 | return ids, cad_cmds 125 | 126 | @classmethod 127 | def from_openmc_surface_inner(cls, plane): 128 | return cls(y0=plane.y0, boundary_type=plane.boundary_type, albedo=plane.albedo, name=plane.name, surface_id=plane.id) 129 | 130 | 131 | class CADZPlane(CADSurface, openmc.ZPlane): 132 | 133 | @staticmethod 134 | def reverse(node): 135 | return "reverse" if node.side == '-' else "" 136 | 137 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 138 | cad_cmds = [] 139 | cad_cmds.append(f"brick x {extents[0]} y {extents[1]} z {extents[2]}") 140 | ids = emit_get_last_id( ent_type, cad_cmds) 141 | cad_cmds.append(f"section body {{ {ids} }} with zplane offset {self.coefficients['z0']} {self.reverse(node)}") 142 | return ids, cad_cmds 143 | 144 | @classmethod 145 | def from_openmc_surface_inner(cls, plane): 146 | return cls(z0=plane.z0, boundary_type=plane.boundary_type, albedo=plane.albedo, name=plane.name, surface_id=plane.id) 147 | 148 | class CADCylinder(CADSurface, openmc.Cylinder): 149 | 150 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 151 | print('XCADCylinder to cubit surface') 152 | cad_cmds = [] 153 | h = inner_world[2] if inner_world else extents[2] 154 | cad_cmds.append(f"cylinder height {h} radius {self.r}") 155 | ids = emit_get_last_id(cmds=cad_cmds) 156 | if node.side != '-': 157 | wid = 0 158 | if inner_world: 159 | if hex: 160 | cad_cmds.append(f"create prism height {inner_world[2]} sides 6 radius { ( inner_world[0] / 2 ) }") 161 | wid = emit_get_last_id(ent_type, cad_cmds) 162 | cad_cmds.append(f"rotate body {{ {wid} }} about z angle 30") 163 | else: 164 | cad_cmds.append(f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}") 165 | wid = emit_get_last_id(ent_type, cad_cmds) 166 | else: 167 | cad_cmds.append( f"brick x {w[0]} y {w[1]} z {w[2]}" ) 168 | wid = emit_get_last_id(ent_type, cad_cmds) 169 | cad_cmds.append( f"subtract body {{ { ids } }} from body {{ { wid } }}" ) 170 | rotate( wid, self.dx, self.dy, self.dz, cad_cmds) 171 | move( wid, self.x0, self.y0, self.z0, cad_cmds) 172 | return wid, cad_cmds 173 | rotate( ids, self.dx, self.dy, self.dz, cad_cmds) 174 | move( ids, self.x0, self.y0, self.z0, cad_cmds) 175 | return ids, cad_cmds 176 | 177 | @classmethod 178 | def from_openmc_surface_inner(cls, cyl): 179 | return cls(r=cyl.r, x0=cyl.x0, y0=cyl.y0, z0=cyl.z0, dx=cyl.dx, dy=cyl.dy, dz=cyl.dz, 180 | boundary_type=cyl.boundary_type, albedo=cyl.albedo, name=cyl.name, surface_id=cyl.id) 181 | 182 | class CADXCylinder(CADSurface, openmc.XCylinder): 183 | 184 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 185 | cad_cmds = [] 186 | h = inner_world[0] if inner_world else extents[0] 187 | cad_cmds.append( f"cylinder height {h} radius {self.r}") 188 | ids = emit_get_last_id( ent_type , cad_cmds) 189 | cad_cmds.append(f"rotate body {{ {ids} }} about y angle 90") 190 | if node.side != '-': 191 | wid = 0 192 | if inner_world: 193 | if hex: 194 | cad_cmds.append(f"create prism height {inner_world[2]} sides 6 radius { ( inner_world[0] / 2 ) }") 195 | wid = emit_get_last_id(ent_type, cad_cmds) 196 | cad_cmds.append(f"rotate body {{ {wid} }} about z angle 30") 197 | cad_cmds.append(f"rotate body {{ {wid} }} about y angle 90") 198 | else: 199 | cad_cmds.append(f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}") 200 | wid = emit_get_last_id(ent_type, cad_cmds) 201 | else: 202 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 203 | wid = emit_get_last_id( ent_type , cad_cmds) 204 | cad_cmds.append(f"subtract body {{ { ids } }} from body {{ { wid } }}") 205 | move(wid, 0, self.y0, self.z0, cad_cmds) 206 | return wid, cad_cmds 207 | move(ids, 0, self.y0, self.z0, cad_cmds) 208 | return ids, cad_cmds 209 | 210 | @classmethod 211 | def from_openmc_surface_inner(cls, cyl): 212 | return cls(r=cyl.r, y0=cyl.y0, z0=cyl.z0, boundary_type=cyl.boundary_type, albedo=cyl.albedo, name=cyl.name, surface_id=cyl.id) 213 | 214 | 215 | class CADYCylinder(CADSurface, openmc.YCylinder): 216 | 217 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 218 | cad_cmds = [] 219 | h = inner_world[1] if inner_world else extents[1] 220 | cad_cmds.append( f"cylinder height {h} radius {self.r}") 221 | ids = emit_get_last_id( ent_type , cad_cmds) 222 | cad_cmds.append(f"rotate body {{ {ids} }} about x angle 90") 223 | if node.side != '-': 224 | wid = 0 225 | if inner_world: 226 | if hex: 227 | cad_cmds.append(f"create prism height {inner_world[2]} sides 6 radius { ( inner_world[0] / 2 ) }") 228 | wid = emit_get_last_id(ent_type, cad_cmds) 229 | cad_cmds.append(f"rotate body {{ {wid} }} about z angle 30") 230 | cad_cmds.append(f"rotate body {{ {wid} }} about x angle 90") 231 | else: 232 | cad_cmds.append(f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}") 233 | wid = emit_get_last_id(ent_type, cad_cmds) 234 | else: 235 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 236 | wid = emit_get_last_id( ent_type , cad_cmds) 237 | cad_cmds.append(f"subtract body {{ { ids } }} from body {{ { wid } }}") 238 | move(wid, self.x0, 0, self.z0, cad_cmds) 239 | return wid, cad_cmds 240 | move(ids, self.x0, 0, self.z0, cad_cmds) 241 | return ids, cad_cmds 242 | 243 | @classmethod 244 | def from_openmc_surface_inner(cls, cyl): 245 | return cls(r=cyl.r, x0=cyl.x0, z0=cyl.z0, boundary_type=cyl.boundary_type, albedo=cyl.albedo, name=cyl.name, surface_id=cyl.id) 246 | 247 | 248 | class CADZCylinder(CADSurface, openmc.ZCylinder): 249 | 250 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 251 | cad_cmds = [] 252 | h = inner_world[2] if inner_world else extents[2] 253 | cad_cmds.append( f"cylinder height {h} radius {self.r}") 254 | ids = emit_get_last_id( ent_type , cad_cmds) 255 | if node.side != '-': 256 | wid = 0 257 | if inner_world: 258 | if hex: 259 | cad_cmds.append(f"create prism height {inner_world[2]} sides 6 radius { ( inner_world[0] / 2 ) }") 260 | wid = emit_get_last_id(ent_type, cad_cmds) 261 | cad_cmds.append(f"rotate body {{ {wid} }} about z angle 30") 262 | else: 263 | cad_cmds.append(f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}") 264 | wid = emit_get_last_id(ent_type, cad_cmds) 265 | else: 266 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 267 | wid = emit_get_last_id( ent_type , cad_cmds) 268 | cad_cmds.append(f"subtract body {{ { ids } }} from body {{ { wid } }}") 269 | move(wid, self.x0, self.y0, 0, cad_cmds) 270 | return wid, cad_cmds 271 | move(ids, self.x0, self.y0, 0, cad_cmds) 272 | return ids, cad_cmds 273 | 274 | @classmethod 275 | def from_openmc_surface_inner(cls, cyl): 276 | return cls(r=cyl.r, x0=cyl.x0, y0=cyl.y0, boundary_type=cyl.boundary_type, albedo=cyl.albedo, name=cyl.name, surface_id=cyl.id) 277 | 278 | 279 | class CADSphere(CADSurface, openmc.Sphere): 280 | 281 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 282 | cad_cmds = [] 283 | cad_cmds.append( f"sphere radius {self.r}") 284 | ids = emit_get_last_id(ent_type, cad_cmds) 285 | move(ids, self.x0, self.y0, self.z0, cad_cmds) 286 | if node.side != '-': 287 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 288 | wid = emit_get_last_id( ent_type , cad_cmds) 289 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 290 | ids = wid 291 | return ids, cad_cmds 292 | 293 | @classmethod 294 | def from_openmc_surface_inner(cls, sphere): 295 | return cls(r=sphere.r, x0=sphere.x0, y0=sphere.y0, z0=sphere.z0, boundary_type=sphere.boundary_type, albedo=sphere.albedo, name=sphere.name, surface_id=sphere.id) 296 | 297 | class CADCone(CADSurface): 298 | 299 | def to_cubit_surface(self, ent_type, node, extents, inner_world=None, hex=False): 300 | raise NotImplementedError('General Cones are not yet supported') 301 | 302 | @classmethod 303 | def from_openmc_surface(cls, surface): 304 | raise NotImplementedError('General Cones are not yet supported') 305 | 306 | class CADXCone(CADSurface, openmc.XCone): 307 | 308 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 309 | cad_cmds = [] 310 | cad_cmds.append( f"create frustum height {extents[0]} radius {math.sqrt(self.coefficients['r2'])*extents[0]} top 0") 311 | ids = emit_get_last_id(ent_type, cad_cmds) 312 | cad_cmds.append(f"body {{ {ids} }} move 0 0 -{extents[0]/2.0}") 313 | cad_cmds.append(f"body {{ {ids} }} copy reflect z") 314 | ids2 = emit_get_last_id(ent_type, cad_cmds) 315 | cad_cmds.append(f"unite body {{ {ids} }} {{ {ids2} }}") 316 | cad_cmds.append( f"rotate body {{ {ids} }} about y angle 90") 317 | x0, y0, z0 = self.coefficients['x0'], self.coefficients['y0'], self.coefficients['z0'] 318 | cad_cmds.append(f"body {{ {ids} }} move {x0} {y0} {z0}") 319 | 320 | if node.side != '-': 321 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 322 | wid = emit_get_last_id(ent_type , cad_cmds) 323 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 324 | ids = wid 325 | return ids, cad_cmds 326 | 327 | @classmethod 328 | def from_openmc_surface_inner(cls, surface): 329 | return cls(x0=surface.x0, y0=surface.y0, z0=surface.z0, r2=surface.r2, boundary_type=surface.boundary_type, albedo=surface.albedo, name=surface.name, surface_id=surface.id) 330 | 331 | 332 | class CADYCone(CADSurface, openmc.YCone): 333 | 334 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 335 | cad_cmds = [] 336 | cad_cmds.append( f"create frustum height {extents[1]} radius {math.sqrt(self.coefficients['r2'])*extents[1]} top 0") 337 | ids = emit_get_last_id(ent_type, cad_cmds) 338 | cad_cmds.append(f"body {{ {ids} }} move 0 0 -{extents[1]/2.0}") 339 | cad_cmds.append(f"body {{ {ids} }} copy reflect z") 340 | ids2 = emit_get_last_id(ent_type, cad_cmds) 341 | cad_cmds.append(f"unite body {{ {ids} }} {{ {ids2} }}") 342 | cad_cmds.append( f"rotate body {{ {ids} }} about x angle 90") 343 | x0, y0, z0 = self.coefficients['x0'], self.coefficients['y0'], self.coefficients['z0'] 344 | cad_cmds.append(f"body {{ {ids} }} move {x0} {y0} {z0}") 345 | 346 | if node.side != '-': 347 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 348 | wid = emit_get_last_id(ent_type , cad_cmds) 349 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 350 | ids = wid 351 | return ids, cad_cmds 352 | 353 | @classmethod 354 | def from_openmc_surface_inner(cls, surface): 355 | return cls(x0=surface.x0, y0=surface.y0, z0=surface.z0, r2=surface.r2, boundary_type=surface.boundary_type, albedo=surface.albedo, name=surface.name, surface_id=surface.id) 356 | 357 | 358 | class CADZCone(CADSurface, openmc.ZCone): 359 | 360 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 361 | cad_cmds = [] 362 | cad_cmds.append( f"create frustum height {extents[2]} radius {math.sqrt(self.coefficients['r2'])*extents[2]} top 0") 363 | ids = emit_get_last_id(ent_type, cad_cmds) 364 | cad_cmds.append(f"body {{ {ids} }} move 0 0 -{extents[2]/2.0}") 365 | cad_cmds.append(f"body {{ {ids} }} copy reflect z") 366 | ids2 = emit_get_last_id(ent_type, cad_cmds) 367 | cad_cmds.append(f"unite body {{ {ids} }} {{ {ids2} }}") 368 | x0, y0, z0 = self.coefficients['x0'], self.coefficients['y0'], self.coefficients['z0'] 369 | cad_cmds.append(f"body {{ {ids} }} move {x0} {y0} {z0}") 370 | 371 | if node.side != '-': 372 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 373 | wid = emit_get_last_id(ent_type , cad_cmds) 374 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 375 | ids = wid 376 | return ids, cad_cmds 377 | 378 | @classmethod 379 | def from_openmc_surface_inner(cls, surface): 380 | return cls(x0=surface.x0, y0=surface.y0, z0=surface.z0, r2=surface.r2, boundary_type=surface.boundary_type, albedo=surface.albedo, name=surface.name, surface_id=surface.id) 381 | 382 | 383 | class CADTorus(CADSurface): 384 | 385 | def check_coeffs(self): 386 | if self.b != self.c: 387 | raise ValueError("Only torri with constant minor radii are supported") 388 | 389 | @classmethod 390 | def from_openmc_surface_inner(cls, surface): 391 | return cls(x0=surface.x0, y0=surface.y0, z0=surface.z0, a=surface.a, b=surface.b, c=surface.c, boundary_type=surface.boundary_type, albedo=surface.albedo, name=surface.name, surface_id=surface.id) 392 | 393 | class CADXTorus(CADTorus, openmc.XTorus): 394 | 395 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 396 | self.check_coeffs() 397 | cad_cmds = [] 398 | cad_cmds.append( f"torus major radius {self.a} minor radius {self.b}" ) 399 | ids = emit_get_last_id(ent_type, cad_cmds) 400 | cad_cmds.append( f"rotate body {{ {ids} }} about y angle 90") 401 | if node.side != '-': 402 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 403 | wid = emit_get_last_id(ent_type, cad_cmds) 404 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 405 | move(wid, self.x0, self.y0, self.z0, cad_cmds) 406 | ids = wid 407 | else: 408 | move(ids, self.x0, self.y0, self.z0, cad_cmds) 409 | return ids, cad_cmds 410 | 411 | 412 | 413 | class CADYTorus(CADTorus, openmc.YTorus): 414 | 415 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 416 | self.check_coeffs() 417 | cad_cmds = [] 418 | cad_cmds.append( f"torus major radius {self.a} minor radius {self.b}" ) 419 | ids = emit_get_last_id(ent_type, cad_cmds) 420 | cad_cmds.append( f"rotate body {{ {ids} }} about x angle 90") 421 | if node.side != '-': 422 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 423 | wid = emit_get_last_id(ent_type, cad_cmds) 424 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 425 | move(wid, self.x0, self.y0, self.z0, cad_cmds) 426 | ids = wid 427 | else: 428 | move(ids, self.x0, self.y0, self.z0, cad_cmds) 429 | return ids, cad_cmds 430 | 431 | 432 | class CADZTorus(CADTorus, openmc.ZTorus): 433 | 434 | def to_cubit_surface_inner(self, ent_type, node, extents, inner_world=None, hex=False): 435 | self.check_coeffs() 436 | cad_cmds = [] 437 | cad_cmds.append( f"torus major radius {self.a} minor radius {self.b}" ) 438 | ids = emit_get_last_id(ent_type, cad_cmds) 439 | if node.side != '-': 440 | cad_cmds.append( f"brick x {extents[0]} y {extents[1]} z {extents[2]}" ) 441 | wid = emit_get_last_id(ent_type, cad_cmds) 442 | cad_cmds.append(f"subtract body {{ {ids} }} from body {{ {wid} }}") 443 | move(wid, self.x0, self.y0, self.z0, cad_cmds) 444 | ids = wid 445 | else: 446 | move(ids, self.x0, self.y0, self.z0, cad_cmds) 447 | return ids, cad_cmds 448 | 449 | 450 | _CAD_SURFACES = [CADPlane, CADXPlane, CADYPlane, CADZPlane, CADCylinder, CADXCylinder, CADYCylinder, CADZCylinder, CADSphere, CADXCone, CADYCone, CADZCone, CADXTorus, CADYTorus, CADZTorus] 451 | 452 | _CAD_SURFACE_DICTIONARY = {s._type: s for s in _CAD_SURFACES} 453 | -------------------------------------------------------------------------------- /test/assembly.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 1 4 | create prism height 2.0 sides 6 radius 0.5 5 | #{ id1 = Id("body") } 6 | rotate body { id1 } about z angle 30 7 | body { id1 } name "cell 4" 8 | move body { id1 } midpoint location 0.0 1.7320508075688772 0.0 9 | cylinder height 2.0 radius 0.4 10 | #{ id2 = Id("body") } 11 | body { id2 } name "cell 5" 12 | move body { id2 } midpoint location 0.75 1.299038105676658 0.0 13 | cylinder height 2.0 radius 0.4 14 | #{ id3 = Id("body") } 15 | create prism height 2.0 sides 6 radius 0.5 16 | #{ id4 = Id("body") } 17 | rotate body { id4 } about z angle 30 18 | subtract body { id3 } from body { id4 } 19 | body { id4 } name "cell 6" 20 | move body { id4 } midpoint location 0.75 1.299038105676658 0.0 21 | cylinder height 2.0 radius 0.4 22 | #{ id5 = Id("body") } 23 | body { id5 } name "cell 5" 24 | move body { id5 } midpoint location 1.5 0.8660254037844386 0.0 25 | cylinder height 2.0 radius 0.4 26 | #{ id6 = Id("body") } 27 | create prism height 2.0 sides 6 radius 0.5 28 | #{ id7 = Id("body") } 29 | rotate body { id7 } about z angle 30 30 | subtract body { id6 } from body { id7 } 31 | body { id7 } name "cell 6" 32 | move body { id7 } midpoint location 1.5 0.8660254037844386 0.0 33 | cylinder height 2.0 radius 0.4 34 | #{ id8 = Id("body") } 35 | body { id8 } name "cell 5" 36 | move body { id8 } midpoint location 1.5 0.0 0.0 37 | cylinder height 2.0 radius 0.4 38 | #{ id9 = Id("body") } 39 | create prism height 2.0 sides 6 radius 0.5 40 | #{ id10 = Id("body") } 41 | rotate body { id10 } about z angle 30 42 | subtract body { id9 } from body { id10 } 43 | body { id10 } name "cell 6" 44 | move body { id10 } midpoint location 1.5 0.0 0.0 45 | cylinder height 2.0 radius 0.4 46 | #{ id11 = Id("body") } 47 | body { id11 } name "cell 5" 48 | move body { id11 } midpoint location 1.5 -0.8660254037844386 0.0 49 | cylinder height 2.0 radius 0.4 50 | #{ id12 = Id("body") } 51 | create prism height 2.0 sides 6 radius 0.5 52 | #{ id13 = Id("body") } 53 | rotate body { id13 } about z angle 30 54 | subtract body { id12 } from body { id13 } 55 | body { id13 } name "cell 6" 56 | move body { id13 } midpoint location 1.5 -0.8660254037844386 0.0 57 | cylinder height 2.0 radius 0.4 58 | #{ id14 = Id("body") } 59 | body { id14 } name "cell 5" 60 | move body { id14 } midpoint location 0.75 -1.299038105676658 0.0 61 | cylinder height 2.0 radius 0.4 62 | #{ id15 = Id("body") } 63 | create prism height 2.0 sides 6 radius 0.5 64 | #{ id16 = Id("body") } 65 | rotate body { id16 } about z angle 30 66 | subtract body { id15 } from body { id16 } 67 | body { id16 } name "cell 6" 68 | move body { id16 } midpoint location 0.75 -1.299038105676658 0.0 69 | cylinder height 2.0 radius 0.4 70 | #{ id17 = Id("body") } 71 | body { id17 } name "cell 5" 72 | move body { id17 } midpoint location 0.0 -1.7320508075688772 0.0 73 | cylinder height 2.0 radius 0.4 74 | #{ id18 = Id("body") } 75 | create prism height 2.0 sides 6 radius 0.5 76 | #{ id19 = Id("body") } 77 | rotate body { id19 } about z angle 30 78 | subtract body { id18 } from body { id19 } 79 | body { id19 } name "cell 6" 80 | move body { id19 } midpoint location 0.0 -1.7320508075688772 0.0 81 | cylinder height 2.0 radius 0.4 82 | #{ id20 = Id("body") } 83 | body { id20 } name "cell 5" 84 | move body { id20 } midpoint location -0.75 -1.299038105676658 0.0 85 | cylinder height 2.0 radius 0.4 86 | #{ id21 = Id("body") } 87 | create prism height 2.0 sides 6 radius 0.5 88 | #{ id22 = Id("body") } 89 | rotate body { id22 } about z angle 30 90 | subtract body { id21 } from body { id22 } 91 | body { id22 } name "cell 6" 92 | move body { id22 } midpoint location -0.75 -1.299038105676658 0.0 93 | cylinder height 2.0 radius 0.4 94 | #{ id23 = Id("body") } 95 | body { id23 } name "cell 5" 96 | move body { id23 } midpoint location -1.5 -0.8660254037844386 0.0 97 | cylinder height 2.0 radius 0.4 98 | #{ id24 = Id("body") } 99 | create prism height 2.0 sides 6 radius 0.5 100 | #{ id25 = Id("body") } 101 | rotate body { id25 } about z angle 30 102 | subtract body { id24 } from body { id25 } 103 | body { id25 } name "cell 6" 104 | move body { id25 } midpoint location -1.5 -0.8660254037844386 0.0 105 | cylinder height 2.0 radius 0.4 106 | #{ id26 = Id("body") } 107 | body { id26 } name "cell 5" 108 | move body { id26 } midpoint location -1.5 0.0 0.0 109 | cylinder height 2.0 radius 0.4 110 | #{ id27 = Id("body") } 111 | create prism height 2.0 sides 6 radius 0.5 112 | #{ id28 = Id("body") } 113 | rotate body { id28 } about z angle 30 114 | subtract body { id27 } from body { id28 } 115 | body { id28 } name "cell 6" 116 | move body { id28 } midpoint location -1.5 0.0 0.0 117 | cylinder height 2.0 radius 0.4 118 | #{ id29 = Id("body") } 119 | body { id29 } name "cell 5" 120 | move body { id29 } midpoint location -1.5 0.8660254037844386 0.0 121 | cylinder height 2.0 radius 0.4 122 | #{ id30 = Id("body") } 123 | create prism height 2.0 sides 6 radius 0.5 124 | #{ id31 = Id("body") } 125 | rotate body { id31 } about z angle 30 126 | subtract body { id30 } from body { id31 } 127 | body { id31 } name "cell 6" 128 | move body { id31 } midpoint location -1.5 0.8660254037844386 0.0 129 | cylinder height 2.0 radius 0.4 130 | #{ id32 = Id("body") } 131 | body { id32 } name "cell 5" 132 | move body { id32 } midpoint location -0.75 1.299038105676658 0.0 133 | cylinder height 2.0 radius 0.4 134 | #{ id33 = Id("body") } 135 | create prism height 2.0 sides 6 radius 0.5 136 | #{ id34 = Id("body") } 137 | rotate body { id34 } about z angle 30 138 | subtract body { id33 } from body { id34 } 139 | body { id34 } name "cell 6" 140 | move body { id34 } midpoint location -0.75 1.299038105676658 0.0 141 | create prism height 2.0 sides 6 radius 0.5 142 | #{ id35 = Id("body") } 143 | rotate body { id35 } about z angle 30 144 | body { id35 } name "cell 4" 145 | move body { id35 } midpoint location 5.302876193624534e-17 0.8660254037844386 0.0 146 | cylinder height 2.0 radius 0.4 147 | #{ id36 = Id("body") } 148 | body { id36 } name "cell 5" 149 | move body { id36 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 150 | cylinder height 2.0 radius 0.4 151 | #{ id37 = Id("body") } 152 | create prism height 2.0 sides 6 radius 0.5 153 | #{ id38 = Id("body") } 154 | rotate body { id38 } about z angle 30 155 | subtract body { id37 } from body { id38 } 156 | body { id38 } name "cell 6" 157 | move body { id38 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 158 | cylinder height 2.0 radius 0.4 159 | #{ id39 = Id("body") } 160 | body { id39 } name "cell 5" 161 | move body { id39 } midpoint location 0.75 -0.43301270189221913 0.0 162 | cylinder height 2.0 radius 0.4 163 | #{ id40 = Id("body") } 164 | create prism height 2.0 sides 6 radius 0.5 165 | #{ id41 = Id("body") } 166 | rotate body { id41 } about z angle 30 167 | subtract body { id40 } from body { id41 } 168 | body { id41 } name "cell 6" 169 | move body { id41 } midpoint location 0.75 -0.43301270189221913 0.0 170 | cylinder height 2.0 radius 0.4 171 | #{ id42 = Id("body") } 172 | body { id42 } name "cell 5" 173 | move body { id42 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 174 | cylinder height 2.0 radius 0.4 175 | #{ id43 = Id("body") } 176 | create prism height 2.0 sides 6 radius 0.5 177 | #{ id44 = Id("body") } 178 | rotate body { id44 } about z angle 30 179 | subtract body { id43 } from body { id44 } 180 | body { id44 } name "cell 6" 181 | move body { id44 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 182 | cylinder height 2.0 radius 0.4 183 | #{ id45 = Id("body") } 184 | body { id45 } name "cell 5" 185 | move body { id45 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 186 | cylinder height 2.0 radius 0.4 187 | #{ id46 = Id("body") } 188 | create prism height 2.0 sides 6 radius 0.5 189 | #{ id47 = Id("body") } 190 | rotate body { id47 } about z angle 30 191 | subtract body { id46 } from body { id47 } 192 | body { id47 } name "cell 6" 193 | move body { id47 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 194 | cylinder height 2.0 radius 0.4 195 | #{ id48 = Id("body") } 196 | body { id48 } name "cell 5" 197 | move body { id48 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 198 | cylinder height 2.0 radius 0.4 199 | #{ id49 = Id("body") } 200 | create prism height 2.0 sides 6 radius 0.5 201 | #{ id50 = Id("body") } 202 | rotate body { id50 } about z angle 30 203 | subtract body { id49 } from body { id50 } 204 | body { id50 } name "cell 6" 205 | move body { id50 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 206 | cylinder height 2.0 radius 0.4 207 | #{ id51 = Id("body") } 208 | body { id51 } name "cell 5" 209 | move body { id51 } midpoint location 0.0 0.0 0.0 210 | cylinder height 2.0 radius 0.4 211 | #{ id52 = Id("body") } 212 | create prism height 2.0 sides 6 radius 0.5 213 | #{ id53 = Id("body") } 214 | rotate body { id53 } about z angle 30 215 | subtract body { id52 } from body { id53 } 216 | body { id53 } name "cell 6" 217 | move body { id53 } midpoint location 0.0 0.0 0.0 218 | create prism height 2.0 sides 6 radius 0.5 219 | #{ id54 = Id("body") } 220 | rotate body { id54 } about z angle 30 221 | body { id54 } name "cell 4" 222 | move body { id54 } midpoint location 0.0 1.7320508075688772 2.0 223 | cylinder height 2.0 radius 0.4 224 | #{ id55 = Id("body") } 225 | body { id55 } name "cell 2" 226 | move body { id55 } midpoint location 0.75 1.299038105676658 2.0 227 | cylinder height 2.0 radius 0.4 228 | #{ id56 = Id("body") } 229 | create prism height 2.0 sides 6 radius 0.5 230 | #{ id57 = Id("body") } 231 | rotate body { id57 } about z angle 30 232 | subtract body { id56 } from body { id57 } 233 | body { id57 } name "cell 3" 234 | move body { id57 } midpoint location 0.75 1.299038105676658 2.0 235 | cylinder height 2.0 radius 0.4 236 | #{ id58 = Id("body") } 237 | body { id58 } name "cell 2" 238 | move body { id58 } midpoint location 1.5 0.8660254037844386 2.0 239 | cylinder height 2.0 radius 0.4 240 | #{ id59 = Id("body") } 241 | create prism height 2.0 sides 6 radius 0.5 242 | #{ id60 = Id("body") } 243 | rotate body { id60 } about z angle 30 244 | subtract body { id59 } from body { id60 } 245 | body { id60 } name "cell 3" 246 | move body { id60 } midpoint location 1.5 0.8660254037844386 2.0 247 | cylinder height 2.0 radius 0.4 248 | #{ id61 = Id("body") } 249 | body { id61 } name "cell 2" 250 | move body { id61 } midpoint location 1.5 0.0 2.0 251 | cylinder height 2.0 radius 0.4 252 | #{ id62 = Id("body") } 253 | create prism height 2.0 sides 6 radius 0.5 254 | #{ id63 = Id("body") } 255 | rotate body { id63 } about z angle 30 256 | subtract body { id62 } from body { id63 } 257 | body { id63 } name "cell 3" 258 | move body { id63 } midpoint location 1.5 0.0 2.0 259 | cylinder height 2.0 radius 0.4 260 | #{ id64 = Id("body") } 261 | body { id64 } name "cell 2" 262 | move body { id64 } midpoint location 1.5 -0.8660254037844386 2.0 263 | cylinder height 2.0 radius 0.4 264 | #{ id65 = Id("body") } 265 | create prism height 2.0 sides 6 radius 0.5 266 | #{ id66 = Id("body") } 267 | rotate body { id66 } about z angle 30 268 | subtract body { id65 } from body { id66 } 269 | body { id66 } name "cell 3" 270 | move body { id66 } midpoint location 1.5 -0.8660254037844386 2.0 271 | cylinder height 2.0 radius 0.4 272 | #{ id67 = Id("body") } 273 | body { id67 } name "cell 2" 274 | move body { id67 } midpoint location 0.75 -1.299038105676658 2.0 275 | cylinder height 2.0 radius 0.4 276 | #{ id68 = Id("body") } 277 | create prism height 2.0 sides 6 radius 0.5 278 | #{ id69 = Id("body") } 279 | rotate body { id69 } about z angle 30 280 | subtract body { id68 } from body { id69 } 281 | body { id69 } name "cell 3" 282 | move body { id69 } midpoint location 0.75 -1.299038105676658 2.0 283 | cylinder height 2.0 radius 0.4 284 | #{ id70 = Id("body") } 285 | body { id70 } name "cell 2" 286 | move body { id70 } midpoint location 0.0 -1.7320508075688772 2.0 287 | cylinder height 2.0 radius 0.4 288 | #{ id71 = Id("body") } 289 | create prism height 2.0 sides 6 radius 0.5 290 | #{ id72 = Id("body") } 291 | rotate body { id72 } about z angle 30 292 | subtract body { id71 } from body { id72 } 293 | body { id72 } name "cell 3" 294 | move body { id72 } midpoint location 0.0 -1.7320508075688772 2.0 295 | cylinder height 2.0 radius 0.4 296 | #{ id73 = Id("body") } 297 | body { id73 } name "cell 2" 298 | move body { id73 } midpoint location -0.75 -1.299038105676658 2.0 299 | cylinder height 2.0 radius 0.4 300 | #{ id74 = Id("body") } 301 | create prism height 2.0 sides 6 radius 0.5 302 | #{ id75 = Id("body") } 303 | rotate body { id75 } about z angle 30 304 | subtract body { id74 } from body { id75 } 305 | body { id75 } name "cell 3" 306 | move body { id75 } midpoint location -0.75 -1.299038105676658 2.0 307 | cylinder height 2.0 radius 0.4 308 | #{ id76 = Id("body") } 309 | body { id76 } name "cell 2" 310 | move body { id76 } midpoint location -1.5 -0.8660254037844386 2.0 311 | cylinder height 2.0 radius 0.4 312 | #{ id77 = Id("body") } 313 | create prism height 2.0 sides 6 radius 0.5 314 | #{ id78 = Id("body") } 315 | rotate body { id78 } about z angle 30 316 | subtract body { id77 } from body { id78 } 317 | body { id78 } name "cell 3" 318 | move body { id78 } midpoint location -1.5 -0.8660254037844386 2.0 319 | cylinder height 2.0 radius 0.4 320 | #{ id79 = Id("body") } 321 | body { id79 } name "cell 2" 322 | move body { id79 } midpoint location -1.5 0.0 2.0 323 | cylinder height 2.0 radius 0.4 324 | #{ id80 = Id("body") } 325 | create prism height 2.0 sides 6 radius 0.5 326 | #{ id81 = Id("body") } 327 | rotate body { id81 } about z angle 30 328 | subtract body { id80 } from body { id81 } 329 | body { id81 } name "cell 3" 330 | move body { id81 } midpoint location -1.5 0.0 2.0 331 | cylinder height 2.0 radius 0.4 332 | #{ id82 = Id("body") } 333 | body { id82 } name "cell 2" 334 | move body { id82 } midpoint location -1.5 0.8660254037844386 2.0 335 | cylinder height 2.0 radius 0.4 336 | #{ id83 = Id("body") } 337 | create prism height 2.0 sides 6 radius 0.5 338 | #{ id84 = Id("body") } 339 | rotate body { id84 } about z angle 30 340 | subtract body { id83 } from body { id84 } 341 | body { id84 } name "cell 3" 342 | move body { id84 } midpoint location -1.5 0.8660254037844386 2.0 343 | cylinder height 2.0 radius 0.4 344 | #{ id85 = Id("body") } 345 | body { id85 } name "cell 2" 346 | move body { id85 } midpoint location -0.75 1.299038105676658 2.0 347 | cylinder height 2.0 radius 0.4 348 | #{ id86 = Id("body") } 349 | create prism height 2.0 sides 6 radius 0.5 350 | #{ id87 = Id("body") } 351 | rotate body { id87 } about z angle 30 352 | subtract body { id86 } from body { id87 } 353 | body { id87 } name "cell 3" 354 | move body { id87 } midpoint location -0.75 1.299038105676658 2.0 355 | create prism height 2.0 sides 6 radius 0.5 356 | #{ id88 = Id("body") } 357 | rotate body { id88 } about z angle 30 358 | body { id88 } name "cell 4" 359 | move body { id88 } midpoint location 5.302876193624534e-17 0.8660254037844386 2.0 360 | cylinder height 2.0 radius 0.4 361 | #{ id89 = Id("body") } 362 | body { id89 } name "cell 2" 363 | move body { id89 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 364 | cylinder height 2.0 radius 0.4 365 | #{ id90 = Id("body") } 366 | create prism height 2.0 sides 6 radius 0.5 367 | #{ id91 = Id("body") } 368 | rotate body { id91 } about z angle 30 369 | subtract body { id90 } from body { id91 } 370 | body { id91 } name "cell 3" 371 | move body { id91 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 372 | cylinder height 2.0 radius 0.4 373 | #{ id92 = Id("body") } 374 | body { id92 } name "cell 2" 375 | move body { id92 } midpoint location 0.75 -0.43301270189221913 2.0 376 | cylinder height 2.0 radius 0.4 377 | #{ id93 = Id("body") } 378 | create prism height 2.0 sides 6 radius 0.5 379 | #{ id94 = Id("body") } 380 | rotate body { id94 } about z angle 30 381 | subtract body { id93 } from body { id94 } 382 | body { id94 } name "cell 3" 383 | move body { id94 } midpoint location 0.75 -0.43301270189221913 2.0 384 | cylinder height 2.0 radius 0.4 385 | #{ id95 = Id("body") } 386 | body { id95 } name "cell 2" 387 | move body { id95 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 388 | cylinder height 2.0 radius 0.4 389 | #{ id96 = Id("body") } 390 | create prism height 2.0 sides 6 radius 0.5 391 | #{ id97 = Id("body") } 392 | rotate body { id97 } about z angle 30 393 | subtract body { id96 } from body { id97 } 394 | body { id97 } name "cell 3" 395 | move body { id97 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 396 | cylinder height 2.0 radius 0.4 397 | #{ id98 = Id("body") } 398 | body { id98 } name "cell 2" 399 | move body { id98 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 400 | cylinder height 2.0 radius 0.4 401 | #{ id99 = Id("body") } 402 | create prism height 2.0 sides 6 radius 0.5 403 | #{ id100 = Id("body") } 404 | rotate body { id100 } about z angle 30 405 | subtract body { id99 } from body { id100 } 406 | body { id100 } name "cell 3" 407 | move body { id100 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 408 | cylinder height 2.0 radius 0.4 409 | #{ id101 = Id("body") } 410 | body { id101 } name "cell 2" 411 | move body { id101 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 412 | cylinder height 2.0 radius 0.4 413 | #{ id102 = Id("body") } 414 | create prism height 2.0 sides 6 radius 0.5 415 | #{ id103 = Id("body") } 416 | rotate body { id103 } about z angle 30 417 | subtract body { id102 } from body { id103 } 418 | body { id103 } name "cell 3" 419 | move body { id103 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 420 | cylinder height 2.0 radius 0.4 421 | #{ id104 = Id("body") } 422 | body { id104 } name "cell 2" 423 | move body { id104 } midpoint location 0.0 0.0 2.0 424 | cylinder height 2.0 radius 0.4 425 | #{ id105 = Id("body") } 426 | create prism height 2.0 sides 6 radius 0.5 427 | #{ id106 = Id("body") } 428 | rotate body { id106 } about z angle 30 429 | subtract body { id105 } from body { id106 } 430 | body { id106 } name "cell 3" 431 | move body { id106 } midpoint location 0.0 0.0 2.0 432 | create prism height 2.0 sides 6 radius 0.5 433 | #{ id107 = Id("body") } 434 | rotate body { id107 } about z angle 30 435 | body { id107 } name "cell 4" 436 | move body { id107 } midpoint location 0.0 1.7320508075688772 4.0 437 | cylinder height 2.0 radius 0.4 438 | #{ id108 = Id("body") } 439 | body { id108 } name "cell 5" 440 | move body { id108 } midpoint location 0.75 1.299038105676658 4.0 441 | cylinder height 2.0 radius 0.4 442 | #{ id109 = Id("body") } 443 | create prism height 2.0 sides 6 radius 0.5 444 | #{ id110 = Id("body") } 445 | rotate body { id110 } about z angle 30 446 | subtract body { id109 } from body { id110 } 447 | body { id110 } name "cell 6" 448 | move body { id110 } midpoint location 0.75 1.299038105676658 4.0 449 | cylinder height 2.0 radius 0.4 450 | #{ id111 = Id("body") } 451 | body { id111 } name "cell 5" 452 | move body { id111 } midpoint location 1.5 0.8660254037844386 4.0 453 | cylinder height 2.0 radius 0.4 454 | #{ id112 = Id("body") } 455 | create prism height 2.0 sides 6 radius 0.5 456 | #{ id113 = Id("body") } 457 | rotate body { id113 } about z angle 30 458 | subtract body { id112 } from body { id113 } 459 | body { id113 } name "cell 6" 460 | move body { id113 } midpoint location 1.5 0.8660254037844386 4.0 461 | cylinder height 2.0 radius 0.4 462 | #{ id114 = Id("body") } 463 | body { id114 } name "cell 5" 464 | move body { id114 } midpoint location 1.5 0.0 4.0 465 | cylinder height 2.0 radius 0.4 466 | #{ id115 = Id("body") } 467 | create prism height 2.0 sides 6 radius 0.5 468 | #{ id116 = Id("body") } 469 | rotate body { id116 } about z angle 30 470 | subtract body { id115 } from body { id116 } 471 | body { id116 } name "cell 6" 472 | move body { id116 } midpoint location 1.5 0.0 4.0 473 | cylinder height 2.0 radius 0.4 474 | #{ id117 = Id("body") } 475 | body { id117 } name "cell 5" 476 | move body { id117 } midpoint location 1.5 -0.8660254037844386 4.0 477 | cylinder height 2.0 radius 0.4 478 | #{ id118 = Id("body") } 479 | create prism height 2.0 sides 6 radius 0.5 480 | #{ id119 = Id("body") } 481 | rotate body { id119 } about z angle 30 482 | subtract body { id118 } from body { id119 } 483 | body { id119 } name "cell 6" 484 | move body { id119 } midpoint location 1.5 -0.8660254037844386 4.0 485 | cylinder height 2.0 radius 0.4 486 | #{ id120 = Id("body") } 487 | body { id120 } name "cell 5" 488 | move body { id120 } midpoint location 0.75 -1.299038105676658 4.0 489 | cylinder height 2.0 radius 0.4 490 | #{ id121 = Id("body") } 491 | create prism height 2.0 sides 6 radius 0.5 492 | #{ id122 = Id("body") } 493 | rotate body { id122 } about z angle 30 494 | subtract body { id121 } from body { id122 } 495 | body { id122 } name "cell 6" 496 | move body { id122 } midpoint location 0.75 -1.299038105676658 4.0 497 | cylinder height 2.0 radius 0.4 498 | #{ id123 = Id("body") } 499 | body { id123 } name "cell 5" 500 | move body { id123 } midpoint location 0.0 -1.7320508075688772 4.0 501 | cylinder height 2.0 radius 0.4 502 | #{ id124 = Id("body") } 503 | create prism height 2.0 sides 6 radius 0.5 504 | #{ id125 = Id("body") } 505 | rotate body { id125 } about z angle 30 506 | subtract body { id124 } from body { id125 } 507 | body { id125 } name "cell 6" 508 | move body { id125 } midpoint location 0.0 -1.7320508075688772 4.0 509 | cylinder height 2.0 radius 0.4 510 | #{ id126 = Id("body") } 511 | body { id126 } name "cell 5" 512 | move body { id126 } midpoint location -0.75 -1.299038105676658 4.0 513 | cylinder height 2.0 radius 0.4 514 | #{ id127 = Id("body") } 515 | create prism height 2.0 sides 6 radius 0.5 516 | #{ id128 = Id("body") } 517 | rotate body { id128 } about z angle 30 518 | subtract body { id127 } from body { id128 } 519 | body { id128 } name "cell 6" 520 | move body { id128 } midpoint location -0.75 -1.299038105676658 4.0 521 | cylinder height 2.0 radius 0.4 522 | #{ id129 = Id("body") } 523 | body { id129 } name "cell 5" 524 | move body { id129 } midpoint location -1.5 -0.8660254037844386 4.0 525 | cylinder height 2.0 radius 0.4 526 | #{ id130 = Id("body") } 527 | create prism height 2.0 sides 6 radius 0.5 528 | #{ id131 = Id("body") } 529 | rotate body { id131 } about z angle 30 530 | subtract body { id130 } from body { id131 } 531 | body { id131 } name "cell 6" 532 | move body { id131 } midpoint location -1.5 -0.8660254037844386 4.0 533 | cylinder height 2.0 radius 0.4 534 | #{ id132 = Id("body") } 535 | body { id132 } name "cell 5" 536 | move body { id132 } midpoint location -1.5 0.0 4.0 537 | cylinder height 2.0 radius 0.4 538 | #{ id133 = Id("body") } 539 | create prism height 2.0 sides 6 radius 0.5 540 | #{ id134 = Id("body") } 541 | rotate body { id134 } about z angle 30 542 | subtract body { id133 } from body { id134 } 543 | body { id134 } name "cell 6" 544 | move body { id134 } midpoint location -1.5 0.0 4.0 545 | cylinder height 2.0 radius 0.4 546 | #{ id135 = Id("body") } 547 | body { id135 } name "cell 5" 548 | move body { id135 } midpoint location -1.5 0.8660254037844386 4.0 549 | cylinder height 2.0 radius 0.4 550 | #{ id136 = Id("body") } 551 | create prism height 2.0 sides 6 radius 0.5 552 | #{ id137 = Id("body") } 553 | rotate body { id137 } about z angle 30 554 | subtract body { id136 } from body { id137 } 555 | body { id137 } name "cell 6" 556 | move body { id137 } midpoint location -1.5 0.8660254037844386 4.0 557 | cylinder height 2.0 radius 0.4 558 | #{ id138 = Id("body") } 559 | body { id138 } name "cell 5" 560 | move body { id138 } midpoint location -0.75 1.299038105676658 4.0 561 | cylinder height 2.0 radius 0.4 562 | #{ id139 = Id("body") } 563 | create prism height 2.0 sides 6 radius 0.5 564 | #{ id140 = Id("body") } 565 | rotate body { id140 } about z angle 30 566 | subtract body { id139 } from body { id140 } 567 | body { id140 } name "cell 6" 568 | move body { id140 } midpoint location -0.75 1.299038105676658 4.0 569 | create prism height 2.0 sides 6 radius 0.5 570 | #{ id141 = Id("body") } 571 | rotate body { id141 } about z angle 30 572 | body { id141 } name "cell 4" 573 | move body { id141 } midpoint location 5.302876193624534e-17 0.8660254037844386 4.0 574 | cylinder height 2.0 radius 0.4 575 | #{ id142 = Id("body") } 576 | body { id142 } name "cell 5" 577 | move body { id142 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 578 | cylinder height 2.0 radius 0.4 579 | #{ id143 = Id("body") } 580 | create prism height 2.0 sides 6 radius 0.5 581 | #{ id144 = Id("body") } 582 | rotate body { id144 } about z angle 30 583 | subtract body { id143 } from body { id144 } 584 | body { id144 } name "cell 6" 585 | move body { id144 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 586 | cylinder height 2.0 radius 0.4 587 | #{ id145 = Id("body") } 588 | body { id145 } name "cell 5" 589 | move body { id145 } midpoint location 0.75 -0.43301270189221913 4.0 590 | cylinder height 2.0 radius 0.4 591 | #{ id146 = Id("body") } 592 | create prism height 2.0 sides 6 radius 0.5 593 | #{ id147 = Id("body") } 594 | rotate body { id147 } about z angle 30 595 | subtract body { id146 } from body { id147 } 596 | body { id147 } name "cell 6" 597 | move body { id147 } midpoint location 0.75 -0.43301270189221913 4.0 598 | cylinder height 2.0 radius 0.4 599 | #{ id148 = Id("body") } 600 | body { id148 } name "cell 5" 601 | move body { id148 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 602 | cylinder height 2.0 radius 0.4 603 | #{ id149 = Id("body") } 604 | create prism height 2.0 sides 6 radius 0.5 605 | #{ id150 = Id("body") } 606 | rotate body { id150 } about z angle 30 607 | subtract body { id149 } from body { id150 } 608 | body { id150 } name "cell 6" 609 | move body { id150 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 610 | cylinder height 2.0 radius 0.4 611 | #{ id151 = Id("body") } 612 | body { id151 } name "cell 5" 613 | move body { id151 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 614 | cylinder height 2.0 radius 0.4 615 | #{ id152 = Id("body") } 616 | create prism height 2.0 sides 6 radius 0.5 617 | #{ id153 = Id("body") } 618 | rotate body { id153 } about z angle 30 619 | subtract body { id152 } from body { id153 } 620 | body { id153 } name "cell 6" 621 | move body { id153 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 622 | cylinder height 2.0 radius 0.4 623 | #{ id154 = Id("body") } 624 | body { id154 } name "cell 5" 625 | move body { id154 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 626 | cylinder height 2.0 radius 0.4 627 | #{ id155 = Id("body") } 628 | create prism height 2.0 sides 6 radius 0.5 629 | #{ id156 = Id("body") } 630 | rotate body { id156 } about z angle 30 631 | subtract body { id155 } from body { id156 } 632 | body { id156 } name "cell 6" 633 | move body { id156 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 634 | cylinder height 2.0 radius 0.4 635 | #{ id157 = Id("body") } 636 | body { id157 } name "cell 5" 637 | move body { id157 } midpoint location 0.0 0.0 4.0 638 | cylinder height 2.0 radius 0.4 639 | #{ id158 = Id("body") } 640 | create prism height 2.0 sides 6 radius 0.5 641 | #{ id159 = Id("body") } 642 | rotate body { id159 } about z angle 30 643 | subtract body { id158 } from body { id159 } 644 | body { id159 } name "cell 6" 645 | move body { id159 } midpoint location 0.0 0.0 4.0 646 | -------------------------------------------------------------------------------- /test/lattice-hexagonal.jou: -------------------------------------------------------------------------------- 1 | set graphics off 2 | set journal off 3 | #CELL 1 4 | create prism height 2.0 sides 6 radius 0.5 5 | #{ id1 = Id("body") } 6 | rotate body { id1 } about z angle 30 7 | body { id1 } name "cell 4" 8 | move body { id1 } midpoint location 0.0 1.7320508075688772 0.0 9 | cylinder height 2.0 radius 0.4 10 | #{ id2 = Id("body") } 11 | body { id2 } name "cell 5" 12 | move body { id2 } midpoint location 0.75 1.299038105676658 0.0 13 | cylinder height 2.0 radius 0.4 14 | #{ id3 = Id("body") } 15 | create prism height 2.0 sides 6 radius 0.5 16 | #{ id4 = Id("body") } 17 | rotate body { id4 } about z angle 30 18 | subtract body { id3 } from body { id4 } 19 | body { id4 } name "cell 6" 20 | move body { id4 } midpoint location 0.75 1.299038105676658 0.0 21 | cylinder height 2.0 radius 0.4 22 | #{ id5 = Id("body") } 23 | body { id5 } name "cell 5" 24 | move body { id5 } midpoint location 1.5 0.8660254037844386 0.0 25 | cylinder height 2.0 radius 0.4 26 | #{ id6 = Id("body") } 27 | create prism height 2.0 sides 6 radius 0.5 28 | #{ id7 = Id("body") } 29 | rotate body { id7 } about z angle 30 30 | subtract body { id6 } from body { id7 } 31 | body { id7 } name "cell 6" 32 | move body { id7 } midpoint location 1.5 0.8660254037844386 0.0 33 | cylinder height 2.0 radius 0.4 34 | #{ id8 = Id("body") } 35 | body { id8 } name "cell 5" 36 | move body { id8 } midpoint location 1.5 0.0 0.0 37 | cylinder height 2.0 radius 0.4 38 | #{ id9 = Id("body") } 39 | create prism height 2.0 sides 6 radius 0.5 40 | #{ id10 = Id("body") } 41 | rotate body { id10 } about z angle 30 42 | subtract body { id9 } from body { id10 } 43 | body { id10 } name "cell 6" 44 | move body { id10 } midpoint location 1.5 0.0 0.0 45 | cylinder height 2.0 radius 0.4 46 | #{ id11 = Id("body") } 47 | body { id11 } name "cell 5" 48 | move body { id11 } midpoint location 1.5 -0.8660254037844386 0.0 49 | cylinder height 2.0 radius 0.4 50 | #{ id12 = Id("body") } 51 | create prism height 2.0 sides 6 radius 0.5 52 | #{ id13 = Id("body") } 53 | rotate body { id13 } about z angle 30 54 | subtract body { id12 } from body { id13 } 55 | body { id13 } name "cell 6" 56 | move body { id13 } midpoint location 1.5 -0.8660254037844386 0.0 57 | cylinder height 2.0 radius 0.4 58 | #{ id14 = Id("body") } 59 | body { id14 } name "cell 5" 60 | move body { id14 } midpoint location 0.75 -1.299038105676658 0.0 61 | cylinder height 2.0 radius 0.4 62 | #{ id15 = Id("body") } 63 | create prism height 2.0 sides 6 radius 0.5 64 | #{ id16 = Id("body") } 65 | rotate body { id16 } about z angle 30 66 | subtract body { id15 } from body { id16 } 67 | body { id16 } name "cell 6" 68 | move body { id16 } midpoint location 0.75 -1.299038105676658 0.0 69 | cylinder height 2.0 radius 0.4 70 | #{ id17 = Id("body") } 71 | body { id17 } name "cell 5" 72 | move body { id17 } midpoint location 0.0 -1.7320508075688772 0.0 73 | cylinder height 2.0 radius 0.4 74 | #{ id18 = Id("body") } 75 | create prism height 2.0 sides 6 radius 0.5 76 | #{ id19 = Id("body") } 77 | rotate body { id19 } about z angle 30 78 | subtract body { id18 } from body { id19 } 79 | body { id19 } name "cell 6" 80 | move body { id19 } midpoint location 0.0 -1.7320508075688772 0.0 81 | cylinder height 2.0 radius 0.4 82 | #{ id20 = Id("body") } 83 | body { id20 } name "cell 5" 84 | move body { id20 } midpoint location -0.75 -1.299038105676658 0.0 85 | cylinder height 2.0 radius 0.4 86 | #{ id21 = Id("body") } 87 | create prism height 2.0 sides 6 radius 0.5 88 | #{ id22 = Id("body") } 89 | rotate body { id22 } about z angle 30 90 | subtract body { id21 } from body { id22 } 91 | body { id22 } name "cell 6" 92 | move body { id22 } midpoint location -0.75 -1.299038105676658 0.0 93 | cylinder height 2.0 radius 0.4 94 | #{ id23 = Id("body") } 95 | body { id23 } name "cell 5" 96 | move body { id23 } midpoint location -1.5 -0.8660254037844386 0.0 97 | cylinder height 2.0 radius 0.4 98 | #{ id24 = Id("body") } 99 | create prism height 2.0 sides 6 radius 0.5 100 | #{ id25 = Id("body") } 101 | rotate body { id25 } about z angle 30 102 | subtract body { id24 } from body { id25 } 103 | body { id25 } name "cell 6" 104 | move body { id25 } midpoint location -1.5 -0.8660254037844386 0.0 105 | cylinder height 2.0 radius 0.4 106 | #{ id26 = Id("body") } 107 | body { id26 } name "cell 5" 108 | move body { id26 } midpoint location -1.5 0.0 0.0 109 | cylinder height 2.0 radius 0.4 110 | #{ id27 = Id("body") } 111 | create prism height 2.0 sides 6 radius 0.5 112 | #{ id28 = Id("body") } 113 | rotate body { id28 } about z angle 30 114 | subtract body { id27 } from body { id28 } 115 | body { id28 } name "cell 6" 116 | move body { id28 } midpoint location -1.5 0.0 0.0 117 | cylinder height 2.0 radius 0.4 118 | #{ id29 = Id("body") } 119 | body { id29 } name "cell 5" 120 | move body { id29 } midpoint location -1.5 0.8660254037844386 0.0 121 | cylinder height 2.0 radius 0.4 122 | #{ id30 = Id("body") } 123 | create prism height 2.0 sides 6 radius 0.5 124 | #{ id31 = Id("body") } 125 | rotate body { id31 } about z angle 30 126 | subtract body { id30 } from body { id31 } 127 | body { id31 } name "cell 6" 128 | move body { id31 } midpoint location -1.5 0.8660254037844386 0.0 129 | cylinder height 2.0 radius 0.4 130 | #{ id32 = Id("body") } 131 | body { id32 } name "cell 5" 132 | move body { id32 } midpoint location -0.75 1.299038105676658 0.0 133 | cylinder height 2.0 radius 0.4 134 | #{ id33 = Id("body") } 135 | create prism height 2.0 sides 6 radius 0.5 136 | #{ id34 = Id("body") } 137 | rotate body { id34 } about z angle 30 138 | subtract body { id33 } from body { id34 } 139 | body { id34 } name "cell 6" 140 | move body { id34 } midpoint location -0.75 1.299038105676658 0.0 141 | create prism height 2.0 sides 6 radius 0.5 142 | #{ id35 = Id("body") } 143 | rotate body { id35 } about z angle 30 144 | body { id35 } name "cell 4" 145 | move body { id35 } midpoint location 5.302876193624534e-17 0.8660254037844386 0.0 146 | cylinder height 2.0 radius 0.4 147 | #{ id36 = Id("body") } 148 | body { id36 } name "cell 5" 149 | move body { id36 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 150 | cylinder height 2.0 radius 0.4 151 | #{ id37 = Id("body") } 152 | create prism height 2.0 sides 6 radius 0.5 153 | #{ id38 = Id("body") } 154 | rotate body { id38 } about z angle 30 155 | subtract body { id37 } from body { id38 } 156 | body { id38 } name "cell 6" 157 | move body { id38 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 158 | cylinder height 2.0 radius 0.4 159 | #{ id39 = Id("body") } 160 | body { id39 } name "cell 5" 161 | move body { id39 } midpoint location 0.75 -0.43301270189221913 0.0 162 | cylinder height 2.0 radius 0.4 163 | #{ id40 = Id("body") } 164 | create prism height 2.0 sides 6 radius 0.5 165 | #{ id41 = Id("body") } 166 | rotate body { id41 } about z angle 30 167 | subtract body { id40 } from body { id41 } 168 | body { id41 } name "cell 6" 169 | move body { id41 } midpoint location 0.75 -0.43301270189221913 0.0 170 | cylinder height 2.0 radius 0.4 171 | #{ id42 = Id("body") } 172 | body { id42 } name "cell 5" 173 | move body { id42 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 174 | cylinder height 2.0 radius 0.4 175 | #{ id43 = Id("body") } 176 | create prism height 2.0 sides 6 radius 0.5 177 | #{ id44 = Id("body") } 178 | rotate body { id44 } about z angle 30 179 | subtract body { id43 } from body { id44 } 180 | body { id44 } name "cell 6" 181 | move body { id44 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 182 | cylinder height 2.0 radius 0.4 183 | #{ id45 = Id("body") } 184 | body { id45 } name "cell 5" 185 | move body { id45 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 186 | cylinder height 2.0 radius 0.4 187 | #{ id46 = Id("body") } 188 | create prism height 2.0 sides 6 radius 0.5 189 | #{ id47 = Id("body") } 190 | rotate body { id47 } about z angle 30 191 | subtract body { id46 } from body { id47 } 192 | body { id47 } name "cell 6" 193 | move body { id47 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 194 | cylinder height 2.0 radius 0.4 195 | #{ id48 = Id("body") } 196 | body { id48 } name "cell 5" 197 | move body { id48 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 198 | cylinder height 2.0 radius 0.4 199 | #{ id49 = Id("body") } 200 | create prism height 2.0 sides 6 radius 0.5 201 | #{ id50 = Id("body") } 202 | rotate body { id50 } about z angle 30 203 | subtract body { id49 } from body { id50 } 204 | body { id50 } name "cell 6" 205 | move body { id50 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 206 | cylinder height 2.0 radius 0.4 207 | #{ id51 = Id("body") } 208 | body { id51 } name "cell 5" 209 | move body { id51 } midpoint location 0.0 0.0 0.0 210 | cylinder height 2.0 radius 0.4 211 | #{ id52 = Id("body") } 212 | create prism height 2.0 sides 6 radius 0.5 213 | #{ id53 = Id("body") } 214 | rotate body { id53 } about z angle 30 215 | subtract body { id52 } from body { id53 } 216 | body { id53 } name "cell 6" 217 | move body { id53 } midpoint location 0.0 0.0 0.0 218 | create prism height 2.0 sides 6 radius 0.5 219 | #{ id54 = Id("body") } 220 | rotate body { id54 } about z angle 30 221 | body { id54 } name "cell 4" 222 | move body { id54 } midpoint location 0.0 1.7320508075688772 2.0 223 | cylinder height 2.0 radius 0.4 224 | #{ id55 = Id("body") } 225 | body { id55 } name "cell 2" 226 | move body { id55 } midpoint location 0.75 1.299038105676658 2.0 227 | cylinder height 2.0 radius 0.4 228 | #{ id56 = Id("body") } 229 | create prism height 2.0 sides 6 radius 0.5 230 | #{ id57 = Id("body") } 231 | rotate body { id57 } about z angle 30 232 | subtract body { id56 } from body { id57 } 233 | body { id57 } name "cell 3" 234 | move body { id57 } midpoint location 0.75 1.299038105676658 2.0 235 | cylinder height 2.0 radius 0.4 236 | #{ id58 = Id("body") } 237 | body { id58 } name "cell 2" 238 | move body { id58 } midpoint location 1.5 0.8660254037844386 2.0 239 | cylinder height 2.0 radius 0.4 240 | #{ id59 = Id("body") } 241 | create prism height 2.0 sides 6 radius 0.5 242 | #{ id60 = Id("body") } 243 | rotate body { id60 } about z angle 30 244 | subtract body { id59 } from body { id60 } 245 | body { id60 } name "cell 3" 246 | move body { id60 } midpoint location 1.5 0.8660254037844386 2.0 247 | cylinder height 2.0 radius 0.4 248 | #{ id61 = Id("body") } 249 | body { id61 } name "cell 2" 250 | move body { id61 } midpoint location 1.5 0.0 2.0 251 | cylinder height 2.0 radius 0.4 252 | #{ id62 = Id("body") } 253 | create prism height 2.0 sides 6 radius 0.5 254 | #{ id63 = Id("body") } 255 | rotate body { id63 } about z angle 30 256 | subtract body { id62 } from body { id63 } 257 | body { id63 } name "cell 3" 258 | move body { id63 } midpoint location 1.5 0.0 2.0 259 | cylinder height 2.0 radius 0.4 260 | #{ id64 = Id("body") } 261 | body { id64 } name "cell 2" 262 | move body { id64 } midpoint location 1.5 -0.8660254037844386 2.0 263 | cylinder height 2.0 radius 0.4 264 | #{ id65 = Id("body") } 265 | create prism height 2.0 sides 6 radius 0.5 266 | #{ id66 = Id("body") } 267 | rotate body { id66 } about z angle 30 268 | subtract body { id65 } from body { id66 } 269 | body { id66 } name "cell 3" 270 | move body { id66 } midpoint location 1.5 -0.8660254037844386 2.0 271 | cylinder height 2.0 radius 0.4 272 | #{ id67 = Id("body") } 273 | body { id67 } name "cell 2" 274 | move body { id67 } midpoint location 0.75 -1.299038105676658 2.0 275 | cylinder height 2.0 radius 0.4 276 | #{ id68 = Id("body") } 277 | create prism height 2.0 sides 6 radius 0.5 278 | #{ id69 = Id("body") } 279 | rotate body { id69 } about z angle 30 280 | subtract body { id68 } from body { id69 } 281 | body { id69 } name "cell 3" 282 | move body { id69 } midpoint location 0.75 -1.299038105676658 2.0 283 | cylinder height 2.0 radius 0.4 284 | #{ id70 = Id("body") } 285 | body { id70 } name "cell 2" 286 | move body { id70 } midpoint location 0.0 -1.7320508075688772 2.0 287 | cylinder height 2.0 radius 0.4 288 | #{ id71 = Id("body") } 289 | create prism height 2.0 sides 6 radius 0.5 290 | #{ id72 = Id("body") } 291 | rotate body { id72 } about z angle 30 292 | subtract body { id71 } from body { id72 } 293 | body { id72 } name "cell 3" 294 | move body { id72 } midpoint location 0.0 -1.7320508075688772 2.0 295 | cylinder height 2.0 radius 0.4 296 | #{ id73 = Id("body") } 297 | body { id73 } name "cell 2" 298 | move body { id73 } midpoint location -0.75 -1.299038105676658 2.0 299 | cylinder height 2.0 radius 0.4 300 | #{ id74 = Id("body") } 301 | create prism height 2.0 sides 6 radius 0.5 302 | #{ id75 = Id("body") } 303 | rotate body { id75 } about z angle 30 304 | subtract body { id74 } from body { id75 } 305 | body { id75 } name "cell 3" 306 | move body { id75 } midpoint location -0.75 -1.299038105676658 2.0 307 | cylinder height 2.0 radius 0.4 308 | #{ id76 = Id("body") } 309 | body { id76 } name "cell 2" 310 | move body { id76 } midpoint location -1.5 -0.8660254037844386 2.0 311 | cylinder height 2.0 radius 0.4 312 | #{ id77 = Id("body") } 313 | create prism height 2.0 sides 6 radius 0.5 314 | #{ id78 = Id("body") } 315 | rotate body { id78 } about z angle 30 316 | subtract body { id77 } from body { id78 } 317 | body { id78 } name "cell 3" 318 | move body { id78 } midpoint location -1.5 -0.8660254037844386 2.0 319 | cylinder height 2.0 radius 0.4 320 | #{ id79 = Id("body") } 321 | body { id79 } name "cell 2" 322 | move body { id79 } midpoint location -1.5 0.0 2.0 323 | cylinder height 2.0 radius 0.4 324 | #{ id80 = Id("body") } 325 | create prism height 2.0 sides 6 radius 0.5 326 | #{ id81 = Id("body") } 327 | rotate body { id81 } about z angle 30 328 | subtract body { id80 } from body { id81 } 329 | body { id81 } name "cell 3" 330 | move body { id81 } midpoint location -1.5 0.0 2.0 331 | cylinder height 2.0 radius 0.4 332 | #{ id82 = Id("body") } 333 | body { id82 } name "cell 2" 334 | move body { id82 } midpoint location -1.5 0.8660254037844386 2.0 335 | cylinder height 2.0 radius 0.4 336 | #{ id83 = Id("body") } 337 | create prism height 2.0 sides 6 radius 0.5 338 | #{ id84 = Id("body") } 339 | rotate body { id84 } about z angle 30 340 | subtract body { id83 } from body { id84 } 341 | body { id84 } name "cell 3" 342 | move body { id84 } midpoint location -1.5 0.8660254037844386 2.0 343 | cylinder height 2.0 radius 0.4 344 | #{ id85 = Id("body") } 345 | body { id85 } name "cell 2" 346 | move body { id85 } midpoint location -0.75 1.299038105676658 2.0 347 | cylinder height 2.0 radius 0.4 348 | #{ id86 = Id("body") } 349 | create prism height 2.0 sides 6 radius 0.5 350 | #{ id87 = Id("body") } 351 | rotate body { id87 } about z angle 30 352 | subtract body { id86 } from body { id87 } 353 | body { id87 } name "cell 3" 354 | move body { id87 } midpoint location -0.75 1.299038105676658 2.0 355 | create prism height 2.0 sides 6 radius 0.5 356 | #{ id88 = Id("body") } 357 | rotate body { id88 } about z angle 30 358 | body { id88 } name "cell 4" 359 | move body { id88 } midpoint location 5.302876193624534e-17 0.8660254037844386 2.0 360 | cylinder height 2.0 radius 0.4 361 | #{ id89 = Id("body") } 362 | body { id89 } name "cell 2" 363 | move body { id89 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 364 | cylinder height 2.0 radius 0.4 365 | #{ id90 = Id("body") } 366 | create prism height 2.0 sides 6 radius 0.5 367 | #{ id91 = Id("body") } 368 | rotate body { id91 } about z angle 30 369 | subtract body { id90 } from body { id91 } 370 | body { id91 } name "cell 3" 371 | move body { id91 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 372 | cylinder height 2.0 radius 0.4 373 | #{ id92 = Id("body") } 374 | body { id92 } name "cell 2" 375 | move body { id92 } midpoint location 0.75 -0.43301270189221913 2.0 376 | cylinder height 2.0 radius 0.4 377 | #{ id93 = Id("body") } 378 | create prism height 2.0 sides 6 radius 0.5 379 | #{ id94 = Id("body") } 380 | rotate body { id94 } about z angle 30 381 | subtract body { id93 } from body { id94 } 382 | body { id94 } name "cell 3" 383 | move body { id94 } midpoint location 0.75 -0.43301270189221913 2.0 384 | cylinder height 2.0 radius 0.4 385 | #{ id95 = Id("body") } 386 | body { id95 } name "cell 2" 387 | move body { id95 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 388 | cylinder height 2.0 radius 0.4 389 | #{ id96 = Id("body") } 390 | create prism height 2.0 sides 6 radius 0.5 391 | #{ id97 = Id("body") } 392 | rotate body { id97 } about z angle 30 393 | subtract body { id96 } from body { id97 } 394 | body { id97 } name "cell 3" 395 | move body { id97 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 396 | cylinder height 2.0 radius 0.4 397 | #{ id98 = Id("body") } 398 | body { id98 } name "cell 2" 399 | move body { id98 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 400 | cylinder height 2.0 radius 0.4 401 | #{ id99 = Id("body") } 402 | create prism height 2.0 sides 6 radius 0.5 403 | #{ id100 = Id("body") } 404 | rotate body { id100 } about z angle 30 405 | subtract body { id99 } from body { id100 } 406 | body { id100 } name "cell 3" 407 | move body { id100 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 408 | cylinder height 2.0 radius 0.4 409 | #{ id101 = Id("body") } 410 | body { id101 } name "cell 2" 411 | move body { id101 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 412 | cylinder height 2.0 radius 0.4 413 | #{ id102 = Id("body") } 414 | create prism height 2.0 sides 6 radius 0.5 415 | #{ id103 = Id("body") } 416 | rotate body { id103 } about z angle 30 417 | subtract body { id102 } from body { id103 } 418 | body { id103 } name "cell 3" 419 | move body { id103 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 420 | cylinder height 2.0 radius 0.4 421 | #{ id104 = Id("body") } 422 | body { id104 } name "cell 2" 423 | move body { id104 } midpoint location 0.0 0.0 2.0 424 | cylinder height 2.0 radius 0.4 425 | #{ id105 = Id("body") } 426 | create prism height 2.0 sides 6 radius 0.5 427 | #{ id106 = Id("body") } 428 | rotate body { id106 } about z angle 30 429 | subtract body { id105 } from body { id106 } 430 | body { id106 } name "cell 3" 431 | move body { id106 } midpoint location 0.0 0.0 2.0 432 | create prism height 2.0 sides 6 radius 0.5 433 | #{ id107 = Id("body") } 434 | rotate body { id107 } about z angle 30 435 | body { id107 } name "cell 4" 436 | move body { id107 } midpoint location 0.0 1.7320508075688772 4.0 437 | cylinder height 2.0 radius 0.4 438 | #{ id108 = Id("body") } 439 | body { id108 } name "cell 5" 440 | move body { id108 } midpoint location 0.75 1.299038105676658 4.0 441 | cylinder height 2.0 radius 0.4 442 | #{ id109 = Id("body") } 443 | create prism height 2.0 sides 6 radius 0.5 444 | #{ id110 = Id("body") } 445 | rotate body { id110 } about z angle 30 446 | subtract body { id109 } from body { id110 } 447 | body { id110 } name "cell 6" 448 | move body { id110 } midpoint location 0.75 1.299038105676658 4.0 449 | cylinder height 2.0 radius 0.4 450 | #{ id111 = Id("body") } 451 | body { id111 } name "cell 5" 452 | move body { id111 } midpoint location 1.5 0.8660254037844386 4.0 453 | cylinder height 2.0 radius 0.4 454 | #{ id112 = Id("body") } 455 | create prism height 2.0 sides 6 radius 0.5 456 | #{ id113 = Id("body") } 457 | rotate body { id113 } about z angle 30 458 | subtract body { id112 } from body { id113 } 459 | body { id113 } name "cell 6" 460 | move body { id113 } midpoint location 1.5 0.8660254037844386 4.0 461 | cylinder height 2.0 radius 0.4 462 | #{ id114 = Id("body") } 463 | body { id114 } name "cell 5" 464 | move body { id114 } midpoint location 1.5 0.0 4.0 465 | cylinder height 2.0 radius 0.4 466 | #{ id115 = Id("body") } 467 | create prism height 2.0 sides 6 radius 0.5 468 | #{ id116 = Id("body") } 469 | rotate body { id116 } about z angle 30 470 | subtract body { id115 } from body { id116 } 471 | body { id116 } name "cell 6" 472 | move body { id116 } midpoint location 1.5 0.0 4.0 473 | cylinder height 2.0 radius 0.4 474 | #{ id117 = Id("body") } 475 | body { id117 } name "cell 5" 476 | move body { id117 } midpoint location 1.5 -0.8660254037844386 4.0 477 | cylinder height 2.0 radius 0.4 478 | #{ id118 = Id("body") } 479 | create prism height 2.0 sides 6 radius 0.5 480 | #{ id119 = Id("body") } 481 | rotate body { id119 } about z angle 30 482 | subtract body { id118 } from body { id119 } 483 | body { id119 } name "cell 6" 484 | move body { id119 } midpoint location 1.5 -0.8660254037844386 4.0 485 | cylinder height 2.0 radius 0.4 486 | #{ id120 = Id("body") } 487 | body { id120 } name "cell 5" 488 | move body { id120 } midpoint location 0.75 -1.299038105676658 4.0 489 | cylinder height 2.0 radius 0.4 490 | #{ id121 = Id("body") } 491 | create prism height 2.0 sides 6 radius 0.5 492 | #{ id122 = Id("body") } 493 | rotate body { id122 } about z angle 30 494 | subtract body { id121 } from body { id122 } 495 | body { id122 } name "cell 6" 496 | move body { id122 } midpoint location 0.75 -1.299038105676658 4.0 497 | cylinder height 2.0 radius 0.4 498 | #{ id123 = Id("body") } 499 | body { id123 } name "cell 5" 500 | move body { id123 } midpoint location 0.0 -1.7320508075688772 4.0 501 | cylinder height 2.0 radius 0.4 502 | #{ id124 = Id("body") } 503 | create prism height 2.0 sides 6 radius 0.5 504 | #{ id125 = Id("body") } 505 | rotate body { id125 } about z angle 30 506 | subtract body { id124 } from body { id125 } 507 | body { id125 } name "cell 6" 508 | move body { id125 } midpoint location 0.0 -1.7320508075688772 4.0 509 | cylinder height 2.0 radius 0.4 510 | #{ id126 = Id("body") } 511 | body { id126 } name "cell 5" 512 | move body { id126 } midpoint location -0.75 -1.299038105676658 4.0 513 | cylinder height 2.0 radius 0.4 514 | #{ id127 = Id("body") } 515 | create prism height 2.0 sides 6 radius 0.5 516 | #{ id128 = Id("body") } 517 | rotate body { id128 } about z angle 30 518 | subtract body { id127 } from body { id128 } 519 | body { id128 } name "cell 6" 520 | move body { id128 } midpoint location -0.75 -1.299038105676658 4.0 521 | cylinder height 2.0 radius 0.4 522 | #{ id129 = Id("body") } 523 | body { id129 } name "cell 5" 524 | move body { id129 } midpoint location -1.5 -0.8660254037844386 4.0 525 | cylinder height 2.0 radius 0.4 526 | #{ id130 = Id("body") } 527 | create prism height 2.0 sides 6 radius 0.5 528 | #{ id131 = Id("body") } 529 | rotate body { id131 } about z angle 30 530 | subtract body { id130 } from body { id131 } 531 | body { id131 } name "cell 6" 532 | move body { id131 } midpoint location -1.5 -0.8660254037844386 4.0 533 | cylinder height 2.0 radius 0.4 534 | #{ id132 = Id("body") } 535 | body { id132 } name "cell 5" 536 | move body { id132 } midpoint location -1.5 0.0 4.0 537 | cylinder height 2.0 radius 0.4 538 | #{ id133 = Id("body") } 539 | create prism height 2.0 sides 6 radius 0.5 540 | #{ id134 = Id("body") } 541 | rotate body { id134 } about z angle 30 542 | subtract body { id133 } from body { id134 } 543 | body { id134 } name "cell 6" 544 | move body { id134 } midpoint location -1.5 0.0 4.0 545 | cylinder height 2.0 radius 0.4 546 | #{ id135 = Id("body") } 547 | body { id135 } name "cell 5" 548 | move body { id135 } midpoint location -1.5 0.8660254037844386 4.0 549 | cylinder height 2.0 radius 0.4 550 | #{ id136 = Id("body") } 551 | create prism height 2.0 sides 6 radius 0.5 552 | #{ id137 = Id("body") } 553 | rotate body { id137 } about z angle 30 554 | subtract body { id136 } from body { id137 } 555 | body { id137 } name "cell 6" 556 | move body { id137 } midpoint location -1.5 0.8660254037844386 4.0 557 | cylinder height 2.0 radius 0.4 558 | #{ id138 = Id("body") } 559 | body { id138 } name "cell 5" 560 | move body { id138 } midpoint location -0.75 1.299038105676658 4.0 561 | cylinder height 2.0 radius 0.4 562 | #{ id139 = Id("body") } 563 | create prism height 2.0 sides 6 radius 0.5 564 | #{ id140 = Id("body") } 565 | rotate body { id140 } about z angle 30 566 | subtract body { id139 } from body { id140 } 567 | body { id140 } name "cell 6" 568 | move body { id140 } midpoint location -0.75 1.299038105676658 4.0 569 | create prism height 2.0 sides 6 radius 0.5 570 | #{ id141 = Id("body") } 571 | rotate body { id141 } about z angle 30 572 | body { id141 } name "cell 4" 573 | move body { id141 } midpoint location 5.302876193624534e-17 0.8660254037844386 4.0 574 | cylinder height 2.0 radius 0.4 575 | #{ id142 = Id("body") } 576 | body { id142 } name "cell 5" 577 | move body { id142 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 578 | cylinder height 2.0 radius 0.4 579 | #{ id143 = Id("body") } 580 | create prism height 2.0 sides 6 radius 0.5 581 | #{ id144 = Id("body") } 582 | rotate body { id144 } about z angle 30 583 | subtract body { id143 } from body { id144 } 584 | body { id144 } name "cell 6" 585 | move body { id144 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 586 | cylinder height 2.0 radius 0.4 587 | #{ id145 = Id("body") } 588 | body { id145 } name "cell 5" 589 | move body { id145 } midpoint location 0.75 -0.43301270189221913 4.0 590 | cylinder height 2.0 radius 0.4 591 | #{ id146 = Id("body") } 592 | create prism height 2.0 sides 6 radius 0.5 593 | #{ id147 = Id("body") } 594 | rotate body { id147 } about z angle 30 595 | subtract body { id146 } from body { id147 } 596 | body { id147 } name "cell 6" 597 | move body { id147 } midpoint location 0.75 -0.43301270189221913 4.0 598 | cylinder height 2.0 radius 0.4 599 | #{ id148 = Id("body") } 600 | body { id148 } name "cell 5" 601 | move body { id148 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 602 | cylinder height 2.0 radius 0.4 603 | #{ id149 = Id("body") } 604 | create prism height 2.0 sides 6 radius 0.5 605 | #{ id150 = Id("body") } 606 | rotate body { id150 } about z angle 30 607 | subtract body { id149 } from body { id150 } 608 | body { id150 } name "cell 6" 609 | move body { id150 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 610 | cylinder height 2.0 radius 0.4 611 | #{ id151 = Id("body") } 612 | body { id151 } name "cell 5" 613 | move body { id151 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 614 | cylinder height 2.0 radius 0.4 615 | #{ id152 = Id("body") } 616 | create prism height 2.0 sides 6 radius 0.5 617 | #{ id153 = Id("body") } 618 | rotate body { id153 } about z angle 30 619 | subtract body { id152 } from body { id153 } 620 | body { id153 } name "cell 6" 621 | move body { id153 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 622 | cylinder height 2.0 radius 0.4 623 | #{ id154 = Id("body") } 624 | body { id154 } name "cell 5" 625 | move body { id154 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 626 | cylinder height 2.0 radius 0.4 627 | #{ id155 = Id("body") } 628 | create prism height 2.0 sides 6 radius 0.5 629 | #{ id156 = Id("body") } 630 | rotate body { id156 } about z angle 30 631 | subtract body { id155 } from body { id156 } 632 | body { id156 } name "cell 6" 633 | move body { id156 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 634 | cylinder height 2.0 radius 0.4 635 | #{ id157 = Id("body") } 636 | body { id157 } name "cell 5" 637 | move body { id157 } midpoint location 0.0 0.0 4.0 638 | cylinder height 2.0 radius 0.4 639 | #{ id158 = Id("body") } 640 | create prism height 2.0 sides 6 radius 0.5 641 | #{ id159 = Id("body") } 642 | rotate body { id159 } about z angle 30 643 | subtract body { id158 } from body { id159 } 644 | body { id159 } name "cell 6" 645 | move body { id159 } midpoint location 0.0 0.0 4.0 646 | -------------------------------------------------------------------------------- /test/gold/lattice-hexagonal.jou: -------------------------------------------------------------------------------- 1 | set echo off 2 | set info off 3 | set warning off 4 | graphics pause 5 | set journal off 6 | set default autosize off 7 | #CELL 1 8 | create prism height 2.0 sides 6 radius 0.5 9 | #{ id1 = Id("body") } 10 | rotate body { id1 } about z angle 30 11 | body { id1 } name "cell 4" 12 | move body { id1 } midpoint location 0.0 1.7320508075688772 0.0 13 | cylinder height 2.0 radius 0.4 14 | #{ id2 = Id("body") } 15 | body { id2 } name "cell 5" 16 | move body { id2 } midpoint location 0.75 1.299038105676658 0.0 17 | cylinder height 2.0 radius 0.4 18 | #{ id3 = Id("body") } 19 | create prism height 2.0 sides 6 radius 0.5 20 | #{ id4 = Id("body") } 21 | rotate body { id4 } about z angle 30 22 | subtract body { id3 } from body { id4 } 23 | body { id4 } name "cell 6" 24 | move body { id4 } midpoint location 0.75 1.299038105676658 0.0 25 | cylinder height 2.0 radius 0.4 26 | #{ id5 = Id("body") } 27 | body { id5 } name "cell 5" 28 | move body { id5 } midpoint location 1.5 0.8660254037844386 0.0 29 | cylinder height 2.0 radius 0.4 30 | #{ id6 = Id("body") } 31 | create prism height 2.0 sides 6 radius 0.5 32 | #{ id7 = Id("body") } 33 | rotate body { id7 } about z angle 30 34 | subtract body { id6 } from body { id7 } 35 | body { id7 } name "cell 6" 36 | move body { id7 } midpoint location 1.5 0.8660254037844386 0.0 37 | cylinder height 2.0 radius 0.4 38 | #{ id8 = Id("body") } 39 | body { id8 } name "cell 5" 40 | move body { id8 } midpoint location 1.5 0.0 0.0 41 | cylinder height 2.0 radius 0.4 42 | #{ id9 = Id("body") } 43 | create prism height 2.0 sides 6 radius 0.5 44 | #{ id10 = Id("body") } 45 | rotate body { id10 } about z angle 30 46 | subtract body { id9 } from body { id10 } 47 | body { id10 } name "cell 6" 48 | move body { id10 } midpoint location 1.5 0.0 0.0 49 | cylinder height 2.0 radius 0.4 50 | #{ id11 = Id("body") } 51 | body { id11 } name "cell 5" 52 | move body { id11 } midpoint location 1.5 -0.8660254037844386 0.0 53 | cylinder height 2.0 radius 0.4 54 | #{ id12 = Id("body") } 55 | create prism height 2.0 sides 6 radius 0.5 56 | #{ id13 = Id("body") } 57 | rotate body { id13 } about z angle 30 58 | subtract body { id12 } from body { id13 } 59 | body { id13 } name "cell 6" 60 | move body { id13 } midpoint location 1.5 -0.8660254037844386 0.0 61 | cylinder height 2.0 radius 0.4 62 | #{ id14 = Id("body") } 63 | body { id14 } name "cell 5" 64 | move body { id14 } midpoint location 0.75 -1.299038105676658 0.0 65 | cylinder height 2.0 radius 0.4 66 | #{ id15 = Id("body") } 67 | create prism height 2.0 sides 6 radius 0.5 68 | #{ id16 = Id("body") } 69 | rotate body { id16 } about z angle 30 70 | subtract body { id15 } from body { id16 } 71 | body { id16 } name "cell 6" 72 | move body { id16 } midpoint location 0.75 -1.299038105676658 0.0 73 | cylinder height 2.0 radius 0.4 74 | #{ id17 = Id("body") } 75 | body { id17 } name "cell 5" 76 | move body { id17 } midpoint location 0.0 -1.7320508075688772 0.0 77 | cylinder height 2.0 radius 0.4 78 | #{ id18 = Id("body") } 79 | create prism height 2.0 sides 6 radius 0.5 80 | #{ id19 = Id("body") } 81 | rotate body { id19 } about z angle 30 82 | subtract body { id18 } from body { id19 } 83 | body { id19 } name "cell 6" 84 | move body { id19 } midpoint location 0.0 -1.7320508075688772 0.0 85 | cylinder height 2.0 radius 0.4 86 | #{ id20 = Id("body") } 87 | body { id20 } name "cell 5" 88 | move body { id20 } midpoint location -0.75 -1.299038105676658 0.0 89 | cylinder height 2.0 radius 0.4 90 | #{ id21 = Id("body") } 91 | create prism height 2.0 sides 6 radius 0.5 92 | #{ id22 = Id("body") } 93 | rotate body { id22 } about z angle 30 94 | subtract body { id21 } from body { id22 } 95 | body { id22 } name "cell 6" 96 | move body { id22 } midpoint location -0.75 -1.299038105676658 0.0 97 | cylinder height 2.0 radius 0.4 98 | #{ id23 = Id("body") } 99 | body { id23 } name "cell 5" 100 | move body { id23 } midpoint location -1.5 -0.8660254037844386 0.0 101 | cylinder height 2.0 radius 0.4 102 | #{ id24 = Id("body") } 103 | create prism height 2.0 sides 6 radius 0.5 104 | #{ id25 = Id("body") } 105 | rotate body { id25 } about z angle 30 106 | subtract body { id24 } from body { id25 } 107 | body { id25 } name "cell 6" 108 | move body { id25 } midpoint location -1.5 -0.8660254037844386 0.0 109 | cylinder height 2.0 radius 0.4 110 | #{ id26 = Id("body") } 111 | body { id26 } name "cell 5" 112 | move body { id26 } midpoint location -1.5 0.0 0.0 113 | cylinder height 2.0 radius 0.4 114 | #{ id27 = Id("body") } 115 | create prism height 2.0 sides 6 radius 0.5 116 | #{ id28 = Id("body") } 117 | rotate body { id28 } about z angle 30 118 | subtract body { id27 } from body { id28 } 119 | body { id28 } name "cell 6" 120 | move body { id28 } midpoint location -1.5 0.0 0.0 121 | cylinder height 2.0 radius 0.4 122 | #{ id29 = Id("body") } 123 | body { id29 } name "cell 5" 124 | move body { id29 } midpoint location -1.5 0.8660254037844386 0.0 125 | cylinder height 2.0 radius 0.4 126 | #{ id30 = Id("body") } 127 | create prism height 2.0 sides 6 radius 0.5 128 | #{ id31 = Id("body") } 129 | rotate body { id31 } about z angle 30 130 | subtract body { id30 } from body { id31 } 131 | body { id31 } name "cell 6" 132 | move body { id31 } midpoint location -1.5 0.8660254037844386 0.0 133 | cylinder height 2.0 radius 0.4 134 | #{ id32 = Id("body") } 135 | body { id32 } name "cell 5" 136 | move body { id32 } midpoint location -0.75 1.299038105676658 0.0 137 | cylinder height 2.0 radius 0.4 138 | #{ id33 = Id("body") } 139 | create prism height 2.0 sides 6 radius 0.5 140 | #{ id34 = Id("body") } 141 | rotate body { id34 } about z angle 30 142 | subtract body { id33 } from body { id34 } 143 | body { id34 } name "cell 6" 144 | move body { id34 } midpoint location -0.75 1.299038105676658 0.0 145 | create prism height 2.0 sides 6 radius 0.5 146 | #{ id35 = Id("body") } 147 | rotate body { id35 } about z angle 30 148 | body { id35 } name "cell 4" 149 | move body { id35 } midpoint location 5.302876193624534e-17 0.8660254037844386 0.0 150 | cylinder height 2.0 radius 0.4 151 | #{ id36 = Id("body") } 152 | body { id36 } name "cell 5" 153 | move body { id36 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 154 | cylinder height 2.0 radius 0.4 155 | #{ id37 = Id("body") } 156 | create prism height 2.0 sides 6 radius 0.5 157 | #{ id38 = Id("body") } 158 | rotate body { id38 } about z angle 30 159 | subtract body { id37 } from body { id38 } 160 | body { id38 } name "cell 6" 161 | move body { id38 } midpoint location 0.7499999999999999 0.4330127018922193 0.0 162 | cylinder height 2.0 radius 0.4 163 | #{ id39 = Id("body") } 164 | body { id39 } name "cell 5" 165 | move body { id39 } midpoint location 0.75 -0.43301270189221913 0.0 166 | cylinder height 2.0 radius 0.4 167 | #{ id40 = Id("body") } 168 | create prism height 2.0 sides 6 radius 0.5 169 | #{ id41 = Id("body") } 170 | rotate body { id41 } about z angle 30 171 | subtract body { id40 } from body { id41 } 172 | body { id41 } name "cell 6" 173 | move body { id41 } midpoint location 0.75 -0.43301270189221913 0.0 174 | cylinder height 2.0 radius 0.4 175 | #{ id42 = Id("body") } 176 | body { id42 } name "cell 5" 177 | move body { id42 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 178 | cylinder height 2.0 radius 0.4 179 | #{ id43 = Id("body") } 180 | create prism height 2.0 sides 6 radius 0.5 181 | #{ id44 = Id("body") } 182 | rotate body { id44 } about z angle 30 183 | subtract body { id43 } from body { id44 } 184 | body { id44 } name "cell 6" 185 | move body { id44 } midpoint location 5.302876193624534e-17 -0.8660254037844386 0.0 186 | cylinder height 2.0 radius 0.4 187 | #{ id45 = Id("body") } 188 | body { id45 } name "cell 5" 189 | move body { id45 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 190 | cylinder height 2.0 radius 0.4 191 | #{ id46 = Id("body") } 192 | create prism height 2.0 sides 6 radius 0.5 193 | #{ id47 = Id("body") } 194 | rotate body { id47 } about z angle 30 195 | subtract body { id46 } from body { id47 } 196 | body { id47 } name "cell 6" 197 | move body { id47 } midpoint location -0.7499999999999998 -0.4330127018922196 0.0 198 | cylinder height 2.0 radius 0.4 199 | #{ id48 = Id("body") } 200 | body { id48 } name "cell 5" 201 | move body { id48 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 202 | cylinder height 2.0 radius 0.4 203 | #{ id49 = Id("body") } 204 | create prism height 2.0 sides 6 radius 0.5 205 | #{ id50 = Id("body") } 206 | rotate body { id50 } about z angle 30 207 | subtract body { id49 } from body { id50 } 208 | body { id50 } name "cell 6" 209 | move body { id50 } midpoint location -0.7499999999999999 0.4330127018922194 0.0 210 | cylinder height 2.0 radius 0.4 211 | #{ id51 = Id("body") } 212 | body { id51 } name "cell 5" 213 | move body { id51 } midpoint location 0.0 0.0 0.0 214 | cylinder height 2.0 radius 0.4 215 | #{ id52 = Id("body") } 216 | create prism height 2.0 sides 6 radius 0.5 217 | #{ id53 = Id("body") } 218 | rotate body { id53 } about z angle 30 219 | subtract body { id52 } from body { id53 } 220 | body { id53 } name "cell 6" 221 | move body { id53 } midpoint location 0.0 0.0 0.0 222 | create prism height 2.0 sides 6 radius 0.5 223 | #{ id54 = Id("body") } 224 | rotate body { id54 } about z angle 30 225 | body { id54 } name "cell 4" 226 | move body { id54 } midpoint location 0.0 1.7320508075688772 2.0 227 | cylinder height 2.0 radius 0.4 228 | #{ id55 = Id("body") } 229 | body { id55 } name "cell 2" 230 | move body { id55 } midpoint location 0.75 1.299038105676658 2.0 231 | cylinder height 2.0 radius 0.4 232 | #{ id56 = Id("body") } 233 | create prism height 2.0 sides 6 radius 0.5 234 | #{ id57 = Id("body") } 235 | rotate body { id57 } about z angle 30 236 | subtract body { id56 } from body { id57 } 237 | body { id57 } name "cell 3" 238 | move body { id57 } midpoint location 0.75 1.299038105676658 2.0 239 | cylinder height 2.0 radius 0.4 240 | #{ id58 = Id("body") } 241 | body { id58 } name "cell 2" 242 | move body { id58 } midpoint location 1.5 0.8660254037844386 2.0 243 | cylinder height 2.0 radius 0.4 244 | #{ id59 = Id("body") } 245 | create prism height 2.0 sides 6 radius 0.5 246 | #{ id60 = Id("body") } 247 | rotate body { id60 } about z angle 30 248 | subtract body { id59 } from body { id60 } 249 | body { id60 } name "cell 3" 250 | move body { id60 } midpoint location 1.5 0.8660254037844386 2.0 251 | cylinder height 2.0 radius 0.4 252 | #{ id61 = Id("body") } 253 | body { id61 } name "cell 2" 254 | move body { id61 } midpoint location 1.5 0.0 2.0 255 | cylinder height 2.0 radius 0.4 256 | #{ id62 = Id("body") } 257 | create prism height 2.0 sides 6 radius 0.5 258 | #{ id63 = Id("body") } 259 | rotate body { id63 } about z angle 30 260 | subtract body { id62 } from body { id63 } 261 | body { id63 } name "cell 3" 262 | move body { id63 } midpoint location 1.5 0.0 2.0 263 | cylinder height 2.0 radius 0.4 264 | #{ id64 = Id("body") } 265 | body { id64 } name "cell 2" 266 | move body { id64 } midpoint location 1.5 -0.8660254037844386 2.0 267 | cylinder height 2.0 radius 0.4 268 | #{ id65 = Id("body") } 269 | create prism height 2.0 sides 6 radius 0.5 270 | #{ id66 = Id("body") } 271 | rotate body { id66 } about z angle 30 272 | subtract body { id65 } from body { id66 } 273 | body { id66 } name "cell 3" 274 | move body { id66 } midpoint location 1.5 -0.8660254037844386 2.0 275 | cylinder height 2.0 radius 0.4 276 | #{ id67 = Id("body") } 277 | body { id67 } name "cell 2" 278 | move body { id67 } midpoint location 0.75 -1.299038105676658 2.0 279 | cylinder height 2.0 radius 0.4 280 | #{ id68 = Id("body") } 281 | create prism height 2.0 sides 6 radius 0.5 282 | #{ id69 = Id("body") } 283 | rotate body { id69 } about z angle 30 284 | subtract body { id68 } from body { id69 } 285 | body { id69 } name "cell 3" 286 | move body { id69 } midpoint location 0.75 -1.299038105676658 2.0 287 | cylinder height 2.0 radius 0.4 288 | #{ id70 = Id("body") } 289 | body { id70 } name "cell 2" 290 | move body { id70 } midpoint location 0.0 -1.7320508075688772 2.0 291 | cylinder height 2.0 radius 0.4 292 | #{ id71 = Id("body") } 293 | create prism height 2.0 sides 6 radius 0.5 294 | #{ id72 = Id("body") } 295 | rotate body { id72 } about z angle 30 296 | subtract body { id71 } from body { id72 } 297 | body { id72 } name "cell 3" 298 | move body { id72 } midpoint location 0.0 -1.7320508075688772 2.0 299 | cylinder height 2.0 radius 0.4 300 | #{ id73 = Id("body") } 301 | body { id73 } name "cell 2" 302 | move body { id73 } midpoint location -0.75 -1.299038105676658 2.0 303 | cylinder height 2.0 radius 0.4 304 | #{ id74 = Id("body") } 305 | create prism height 2.0 sides 6 radius 0.5 306 | #{ id75 = Id("body") } 307 | rotate body { id75 } about z angle 30 308 | subtract body { id74 } from body { id75 } 309 | body { id75 } name "cell 3" 310 | move body { id75 } midpoint location -0.75 -1.299038105676658 2.0 311 | cylinder height 2.0 radius 0.4 312 | #{ id76 = Id("body") } 313 | body { id76 } name "cell 2" 314 | move body { id76 } midpoint location -1.5 -0.8660254037844386 2.0 315 | cylinder height 2.0 radius 0.4 316 | #{ id77 = Id("body") } 317 | create prism height 2.0 sides 6 radius 0.5 318 | #{ id78 = Id("body") } 319 | rotate body { id78 } about z angle 30 320 | subtract body { id77 } from body { id78 } 321 | body { id78 } name "cell 3" 322 | move body { id78 } midpoint location -1.5 -0.8660254037844386 2.0 323 | cylinder height 2.0 radius 0.4 324 | #{ id79 = Id("body") } 325 | body { id79 } name "cell 2" 326 | move body { id79 } midpoint location -1.5 0.0 2.0 327 | cylinder height 2.0 radius 0.4 328 | #{ id80 = Id("body") } 329 | create prism height 2.0 sides 6 radius 0.5 330 | #{ id81 = Id("body") } 331 | rotate body { id81 } about z angle 30 332 | subtract body { id80 } from body { id81 } 333 | body { id81 } name "cell 3" 334 | move body { id81 } midpoint location -1.5 0.0 2.0 335 | cylinder height 2.0 radius 0.4 336 | #{ id82 = Id("body") } 337 | body { id82 } name "cell 2" 338 | move body { id82 } midpoint location -1.5 0.8660254037844386 2.0 339 | cylinder height 2.0 radius 0.4 340 | #{ id83 = Id("body") } 341 | create prism height 2.0 sides 6 radius 0.5 342 | #{ id84 = Id("body") } 343 | rotate body { id84 } about z angle 30 344 | subtract body { id83 } from body { id84 } 345 | body { id84 } name "cell 3" 346 | move body { id84 } midpoint location -1.5 0.8660254037844386 2.0 347 | cylinder height 2.0 radius 0.4 348 | #{ id85 = Id("body") } 349 | body { id85 } name "cell 2" 350 | move body { id85 } midpoint location -0.75 1.299038105676658 2.0 351 | cylinder height 2.0 radius 0.4 352 | #{ id86 = Id("body") } 353 | create prism height 2.0 sides 6 radius 0.5 354 | #{ id87 = Id("body") } 355 | rotate body { id87 } about z angle 30 356 | subtract body { id86 } from body { id87 } 357 | body { id87 } name "cell 3" 358 | move body { id87 } midpoint location -0.75 1.299038105676658 2.0 359 | create prism height 2.0 sides 6 radius 0.5 360 | #{ id88 = Id("body") } 361 | rotate body { id88 } about z angle 30 362 | body { id88 } name "cell 4" 363 | move body { id88 } midpoint location 5.302876193624534e-17 0.8660254037844386 2.0 364 | cylinder height 2.0 radius 0.4 365 | #{ id89 = Id("body") } 366 | body { id89 } name "cell 2" 367 | move body { id89 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 368 | cylinder height 2.0 radius 0.4 369 | #{ id90 = Id("body") } 370 | create prism height 2.0 sides 6 radius 0.5 371 | #{ id91 = Id("body") } 372 | rotate body { id91 } about z angle 30 373 | subtract body { id90 } from body { id91 } 374 | body { id91 } name "cell 3" 375 | move body { id91 } midpoint location 0.7499999999999999 0.4330127018922193 2.0 376 | cylinder height 2.0 radius 0.4 377 | #{ id92 = Id("body") } 378 | body { id92 } name "cell 2" 379 | move body { id92 } midpoint location 0.75 -0.43301270189221913 2.0 380 | cylinder height 2.0 radius 0.4 381 | #{ id93 = Id("body") } 382 | create prism height 2.0 sides 6 radius 0.5 383 | #{ id94 = Id("body") } 384 | rotate body { id94 } about z angle 30 385 | subtract body { id93 } from body { id94 } 386 | body { id94 } name "cell 3" 387 | move body { id94 } midpoint location 0.75 -0.43301270189221913 2.0 388 | cylinder height 2.0 radius 0.4 389 | #{ id95 = Id("body") } 390 | body { id95 } name "cell 2" 391 | move body { id95 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 392 | cylinder height 2.0 radius 0.4 393 | #{ id96 = Id("body") } 394 | create prism height 2.0 sides 6 radius 0.5 395 | #{ id97 = Id("body") } 396 | rotate body { id97 } about z angle 30 397 | subtract body { id96 } from body { id97 } 398 | body { id97 } name "cell 3" 399 | move body { id97 } midpoint location 5.302876193624534e-17 -0.8660254037844386 2.0 400 | cylinder height 2.0 radius 0.4 401 | #{ id98 = Id("body") } 402 | body { id98 } name "cell 2" 403 | move body { id98 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 404 | cylinder height 2.0 radius 0.4 405 | #{ id99 = Id("body") } 406 | create prism height 2.0 sides 6 radius 0.5 407 | #{ id100 = Id("body") } 408 | rotate body { id100 } about z angle 30 409 | subtract body { id99 } from body { id100 } 410 | body { id100 } name "cell 3" 411 | move body { id100 } midpoint location -0.7499999999999998 -0.4330127018922196 2.0 412 | cylinder height 2.0 radius 0.4 413 | #{ id101 = Id("body") } 414 | body { id101 } name "cell 2" 415 | move body { id101 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 416 | cylinder height 2.0 radius 0.4 417 | #{ id102 = Id("body") } 418 | create prism height 2.0 sides 6 radius 0.5 419 | #{ id103 = Id("body") } 420 | rotate body { id103 } about z angle 30 421 | subtract body { id102 } from body { id103 } 422 | body { id103 } name "cell 3" 423 | move body { id103 } midpoint location -0.7499999999999999 0.4330127018922194 2.0 424 | cylinder height 2.0 radius 0.4 425 | #{ id104 = Id("body") } 426 | body { id104 } name "cell 2" 427 | move body { id104 } midpoint location 0.0 0.0 2.0 428 | cylinder height 2.0 radius 0.4 429 | #{ id105 = Id("body") } 430 | create prism height 2.0 sides 6 radius 0.5 431 | #{ id106 = Id("body") } 432 | rotate body { id106 } about z angle 30 433 | subtract body { id105 } from body { id106 } 434 | body { id106 } name "cell 3" 435 | move body { id106 } midpoint location 0.0 0.0 2.0 436 | create prism height 2.0 sides 6 radius 0.5 437 | #{ id107 = Id("body") } 438 | rotate body { id107 } about z angle 30 439 | body { id107 } name "cell 4" 440 | move body { id107 } midpoint location 0.0 1.7320508075688772 4.0 441 | cylinder height 2.0 radius 0.4 442 | #{ id108 = Id("body") } 443 | body { id108 } name "cell 5" 444 | move body { id108 } midpoint location 0.75 1.299038105676658 4.0 445 | cylinder height 2.0 radius 0.4 446 | #{ id109 = Id("body") } 447 | create prism height 2.0 sides 6 radius 0.5 448 | #{ id110 = Id("body") } 449 | rotate body { id110 } about z angle 30 450 | subtract body { id109 } from body { id110 } 451 | body { id110 } name "cell 6" 452 | move body { id110 } midpoint location 0.75 1.299038105676658 4.0 453 | cylinder height 2.0 radius 0.4 454 | #{ id111 = Id("body") } 455 | body { id111 } name "cell 5" 456 | move body { id111 } midpoint location 1.5 0.8660254037844386 4.0 457 | cylinder height 2.0 radius 0.4 458 | #{ id112 = Id("body") } 459 | create prism height 2.0 sides 6 radius 0.5 460 | #{ id113 = Id("body") } 461 | rotate body { id113 } about z angle 30 462 | subtract body { id112 } from body { id113 } 463 | body { id113 } name "cell 6" 464 | move body { id113 } midpoint location 1.5 0.8660254037844386 4.0 465 | cylinder height 2.0 radius 0.4 466 | #{ id114 = Id("body") } 467 | body { id114 } name "cell 5" 468 | move body { id114 } midpoint location 1.5 0.0 4.0 469 | cylinder height 2.0 radius 0.4 470 | #{ id115 = Id("body") } 471 | create prism height 2.0 sides 6 radius 0.5 472 | #{ id116 = Id("body") } 473 | rotate body { id116 } about z angle 30 474 | subtract body { id115 } from body { id116 } 475 | body { id116 } name "cell 6" 476 | move body { id116 } midpoint location 1.5 0.0 4.0 477 | cylinder height 2.0 radius 0.4 478 | #{ id117 = Id("body") } 479 | body { id117 } name "cell 5" 480 | move body { id117 } midpoint location 1.5 -0.8660254037844386 4.0 481 | cylinder height 2.0 radius 0.4 482 | #{ id118 = Id("body") } 483 | create prism height 2.0 sides 6 radius 0.5 484 | #{ id119 = Id("body") } 485 | rotate body { id119 } about z angle 30 486 | subtract body { id118 } from body { id119 } 487 | body { id119 } name "cell 6" 488 | move body { id119 } midpoint location 1.5 -0.8660254037844386 4.0 489 | cylinder height 2.0 radius 0.4 490 | #{ id120 = Id("body") } 491 | body { id120 } name "cell 5" 492 | move body { id120 } midpoint location 0.75 -1.299038105676658 4.0 493 | cylinder height 2.0 radius 0.4 494 | #{ id121 = Id("body") } 495 | create prism height 2.0 sides 6 radius 0.5 496 | #{ id122 = Id("body") } 497 | rotate body { id122 } about z angle 30 498 | subtract body { id121 } from body { id122 } 499 | body { id122 } name "cell 6" 500 | move body { id122 } midpoint location 0.75 -1.299038105676658 4.0 501 | cylinder height 2.0 radius 0.4 502 | #{ id123 = Id("body") } 503 | body { id123 } name "cell 5" 504 | move body { id123 } midpoint location 0.0 -1.7320508075688772 4.0 505 | cylinder height 2.0 radius 0.4 506 | #{ id124 = Id("body") } 507 | create prism height 2.0 sides 6 radius 0.5 508 | #{ id125 = Id("body") } 509 | rotate body { id125 } about z angle 30 510 | subtract body { id124 } from body { id125 } 511 | body { id125 } name "cell 6" 512 | move body { id125 } midpoint location 0.0 -1.7320508075688772 4.0 513 | cylinder height 2.0 radius 0.4 514 | #{ id126 = Id("body") } 515 | body { id126 } name "cell 5" 516 | move body { id126 } midpoint location -0.75 -1.299038105676658 4.0 517 | cylinder height 2.0 radius 0.4 518 | #{ id127 = Id("body") } 519 | create prism height 2.0 sides 6 radius 0.5 520 | #{ id128 = Id("body") } 521 | rotate body { id128 } about z angle 30 522 | subtract body { id127 } from body { id128 } 523 | body { id128 } name "cell 6" 524 | move body { id128 } midpoint location -0.75 -1.299038105676658 4.0 525 | cylinder height 2.0 radius 0.4 526 | #{ id129 = Id("body") } 527 | body { id129 } name "cell 5" 528 | move body { id129 } midpoint location -1.5 -0.8660254037844386 4.0 529 | cylinder height 2.0 radius 0.4 530 | #{ id130 = Id("body") } 531 | create prism height 2.0 sides 6 radius 0.5 532 | #{ id131 = Id("body") } 533 | rotate body { id131 } about z angle 30 534 | subtract body { id130 } from body { id131 } 535 | body { id131 } name "cell 6" 536 | move body { id131 } midpoint location -1.5 -0.8660254037844386 4.0 537 | cylinder height 2.0 radius 0.4 538 | #{ id132 = Id("body") } 539 | body { id132 } name "cell 5" 540 | move body { id132 } midpoint location -1.5 0.0 4.0 541 | cylinder height 2.0 radius 0.4 542 | #{ id133 = Id("body") } 543 | create prism height 2.0 sides 6 radius 0.5 544 | #{ id134 = Id("body") } 545 | rotate body { id134 } about z angle 30 546 | subtract body { id133 } from body { id134 } 547 | body { id134 } name "cell 6" 548 | move body { id134 } midpoint location -1.5 0.0 4.0 549 | cylinder height 2.0 radius 0.4 550 | #{ id135 = Id("body") } 551 | body { id135 } name "cell 5" 552 | move body { id135 } midpoint location -1.5 0.8660254037844386 4.0 553 | cylinder height 2.0 radius 0.4 554 | #{ id136 = Id("body") } 555 | create prism height 2.0 sides 6 radius 0.5 556 | #{ id137 = Id("body") } 557 | rotate body { id137 } about z angle 30 558 | subtract body { id136 } from body { id137 } 559 | body { id137 } name "cell 6" 560 | move body { id137 } midpoint location -1.5 0.8660254037844386 4.0 561 | cylinder height 2.0 radius 0.4 562 | #{ id138 = Id("body") } 563 | body { id138 } name "cell 5" 564 | move body { id138 } midpoint location -0.75 1.299038105676658 4.0 565 | cylinder height 2.0 radius 0.4 566 | #{ id139 = Id("body") } 567 | create prism height 2.0 sides 6 radius 0.5 568 | #{ id140 = Id("body") } 569 | rotate body { id140 } about z angle 30 570 | subtract body { id139 } from body { id140 } 571 | body { id140 } name "cell 6" 572 | move body { id140 } midpoint location -0.75 1.299038105676658 4.0 573 | create prism height 2.0 sides 6 radius 0.5 574 | #{ id141 = Id("body") } 575 | rotate body { id141 } about z angle 30 576 | body { id141 } name "cell 4" 577 | move body { id141 } midpoint location 5.302876193624534e-17 0.8660254037844386 4.0 578 | cylinder height 2.0 radius 0.4 579 | #{ id142 = Id("body") } 580 | body { id142 } name "cell 5" 581 | move body { id142 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 582 | cylinder height 2.0 radius 0.4 583 | #{ id143 = Id("body") } 584 | create prism height 2.0 sides 6 radius 0.5 585 | #{ id144 = Id("body") } 586 | rotate body { id144 } about z angle 30 587 | subtract body { id143 } from body { id144 } 588 | body { id144 } name "cell 6" 589 | move body { id144 } midpoint location 0.7499999999999999 0.4330127018922193 4.0 590 | cylinder height 2.0 radius 0.4 591 | #{ id145 = Id("body") } 592 | body { id145 } name "cell 5" 593 | move body { id145 } midpoint location 0.75 -0.43301270189221913 4.0 594 | cylinder height 2.0 radius 0.4 595 | #{ id146 = Id("body") } 596 | create prism height 2.0 sides 6 radius 0.5 597 | #{ id147 = Id("body") } 598 | rotate body { id147 } about z angle 30 599 | subtract body { id146 } from body { id147 } 600 | body { id147 } name "cell 6" 601 | move body { id147 } midpoint location 0.75 -0.43301270189221913 4.0 602 | cylinder height 2.0 radius 0.4 603 | #{ id148 = Id("body") } 604 | body { id148 } name "cell 5" 605 | move body { id148 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 606 | cylinder height 2.0 radius 0.4 607 | #{ id149 = Id("body") } 608 | create prism height 2.0 sides 6 radius 0.5 609 | #{ id150 = Id("body") } 610 | rotate body { id150 } about z angle 30 611 | subtract body { id149 } from body { id150 } 612 | body { id150 } name "cell 6" 613 | move body { id150 } midpoint location 5.302876193624534e-17 -0.8660254037844386 4.0 614 | cylinder height 2.0 radius 0.4 615 | #{ id151 = Id("body") } 616 | body { id151 } name "cell 5" 617 | move body { id151 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 618 | cylinder height 2.0 radius 0.4 619 | #{ id152 = Id("body") } 620 | create prism height 2.0 sides 6 radius 0.5 621 | #{ id153 = Id("body") } 622 | rotate body { id153 } about z angle 30 623 | subtract body { id152 } from body { id153 } 624 | body { id153 } name "cell 6" 625 | move body { id153 } midpoint location -0.7499999999999998 -0.4330127018922196 4.0 626 | cylinder height 2.0 radius 0.4 627 | #{ id154 = Id("body") } 628 | body { id154 } name "cell 5" 629 | move body { id154 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 630 | cylinder height 2.0 radius 0.4 631 | #{ id155 = Id("body") } 632 | create prism height 2.0 sides 6 radius 0.5 633 | #{ id156 = Id("body") } 634 | rotate body { id156 } about z angle 30 635 | subtract body { id155 } from body { id156 } 636 | body { id156 } name "cell 6" 637 | move body { id156 } midpoint location -0.7499999999999999 0.4330127018922194 4.0 638 | cylinder height 2.0 radius 0.4 639 | #{ id157 = Id("body") } 640 | body { id157 } name "cell 5" 641 | move body { id157 } midpoint location 0.0 0.0 4.0 642 | cylinder height 2.0 radius 0.4 643 | #{ id158 = Id("body") } 644 | create prism height 2.0 sides 6 radius 0.5 645 | #{ id159 = Id("body") } 646 | rotate body { id159 } about z angle 30 647 | subtract body { id158 } from body { id159 } 648 | body { id159 } name "cell 6" 649 | move body { id159 } midpoint location 0.0 0.0 4.0 650 | graphics flush 651 | set default autosize on 652 | zoom reset 653 | set echo on 654 | set info on 655 | set warning on 656 | set journal on 657 | -------------------------------------------------------------------------------- /src/openmc_cad_adapter/to_cubit_journal.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | from collections.abc import Iterable 3 | import math 4 | from numbers import Real 5 | from pathlib import Path 6 | import sys 7 | import warnings 8 | 9 | import numpy as np 10 | 11 | try: 12 | import openmc 13 | except ImportError as e: 14 | raise type(e)("Please install OpenMC's Python API to use the CAD conversion tool") 15 | 16 | from openmc.region import Region, Complement, Intersection, Union 17 | from openmc.surface import Halfspace, Quadric 18 | from openmc.lattice import Lattice, HexLattice 19 | 20 | from .gqs import * 21 | from .cubit_util import emit_get_last_id, reset_cubit_ids, new_variable 22 | from .geom_util import rotate, move 23 | from .cubit_util import emit_get_last_id, reset_cubit_ids, new_variable 24 | from .geom_util import rotate, move 25 | from .cubit_util import emit_get_last_id, reset_cubit_ids, new_variable 26 | from .geom_util import rotate, move 27 | 28 | from .surfaces import _CAD_SURFACE_DICTIONARY 29 | 30 | def flatten(S): 31 | if S == []: 32 | return S 33 | if isinstance(S[0], list): 34 | return flatten(S[0]) + flatten(S[1:]) 35 | return S[:1] + flatten(S[1:]) 36 | 37 | 38 | def to_cubit_journal(geometry : openmc.Geometry, world : Iterable[Real] = None, 39 | cells: Iterable[int, openmc.Cell] = None, 40 | filename: str = "openmc.jou", 41 | to_cubit: bool = False, 42 | seen: set = set()): 43 | """Convert an OpenMC geometry to a Cubit journal. 44 | 45 | Parameters 46 | ---------- 47 | geometry : openmc.Geometry 48 | The geometry to convert to a Cubit journal. 49 | world : Iterable[Real], optional 50 | Extents of the model in X, Y, and Z. Defaults to None. 51 | cells : Iterable[int, openmc.Cell], optional 52 | List of cells or cell IDs to write to individual journal files. If None, 53 | all cells will be written to the same journal file. Defaults to None. 54 | filename : str, optional 55 | Output filename. Defaults to "openmc.jou". 56 | to_cubit : bool, optional 57 | Uses the cubit Python module to write the model as a .cub5 file. 58 | Defaults to False. 59 | seen : set, optional 60 | Internal parameter. 61 | 62 | """ 63 | reset_cubit_ids() 64 | 65 | if not filename.endswith('.jou'): 66 | filename += '.jou' 67 | 68 | if isinstance(geometry, openmc.Model): 69 | geometry = geometry.geometry 70 | 71 | if cells is not None: 72 | cells = [c if not isinstance(c, openmc.Cell) else c.id for c in cells] 73 | 74 | if to_cubit: 75 | try: 76 | import cubit 77 | except ImportError: 78 | raise ImportError("Cubit Python API not found. Please install Cubit to use this feature.") 79 | 80 | geom = geometry 81 | 82 | if world is None: 83 | bbox = geometry.bounding_box 84 | if not all(np.isfinite(bbox[0])) or not all(np.isfinite(bbox[1])): 85 | raise RuntimeError('Model bounds were not provided and the bounding box determined by OpenMC is not finite.' 86 | ' Please provide a world size argument to proceed') 87 | # to ensure that the box 88 | box_max = np.max(np.abs(bbox[0], bbox[1]).T) 89 | world = (2 * box_max, 2 * box_max, 2 * box_max) 90 | 91 | if world is None: 92 | raise RuntimeError("Model extents could not be determined automatically and must be provided manually") 93 | 94 | w = world 95 | 96 | cmds = [] 97 | cmds.extend( [ 98 | #"set undo off", 99 | #"set default autosizing off", # especially when the CAD is complex (contains many spline surfaces) this can have a massive effect 100 | #"set info off", 101 | #"set warning off", 102 | ]) 103 | def cubit_cmd(s): 104 | cmds.append(s) 105 | 106 | 107 | def surface_to_cubit_journal(node, w, indent = 0, inner_world = None, hex = False, ent_type = "body", materials='group'): 108 | def ind(): 109 | return ' ' * (2*indent) 110 | if isinstance(node, Halfspace): 111 | seen.add( node.surface ) 112 | surface = node.surface 113 | 114 | nonlocal cmds 115 | 116 | def reverse(): 117 | return "reverse" if node.side == '-' else "" 118 | 119 | if cad_surface := _CAD_SURFACE_DICTIONARY.get(surface._type): 120 | cad_surface = cad_surface.from_openmc_surface(surface) 121 | ids, cad_cmds = cad_surface.to_cubit_surface(ent_type, node, w, inner_world, hex) 122 | cmds += cad_cmds 123 | return ids 124 | elif surface._type == "quadric": 125 | (gq_type, A_, B_, C_, K_, translation, rotation_matrix) = characterize_general_quadratic(surface) 126 | 127 | def rotation_to_axis_angle( mat ): 128 | x = mat[2, 1]-mat[1, 2] 129 | y = mat[0, 2]-mat[2, 0] 130 | z = mat[1, 0]-mat[0, 1] 131 | r = math.hypot( x, math.hypot( y,z )) 132 | t = mat[0,0] + mat[1,1] + mat[2,2] 133 | theta = math.atan2(r,t-1) 134 | 135 | if abs(theta) <= np.finfo(np.float64).eps: 136 | return ( np.array([ 0, 0, 0 ]), 0 ) 137 | elif abs( theta - math.pi ) <= np.finfo(np.float64).eps: 138 | # theta is pi (180 degrees) or extremely close to it 139 | # find the column of mat with the largest diagonal 140 | col = 0 141 | if mat[1,1] > mat[col,col]: col = 1 142 | if mat[2,2] > mat[col,col]: col = 2 143 | 144 | axis = np.array([ 0, 0, 0 ]) 145 | 146 | axis[col] = math.sqrt( (mat[col,col]+1)/2 ) 147 | denom = 2*axis[col] 148 | axis[(col+1)%3] = mat[col,(col+1)%3] / denom 149 | axis[(col+2)%3] = mat[col,(col+2)%3] / denom 150 | return ( axis, theta ) 151 | else: 152 | axis = np.array([ x/r, y/r, z/r ]) 153 | return ( axis, theta ) 154 | (r_axis, r_theta ) = rotation_to_axis_angle( rotation_matrix ) 155 | #compensate for cubits insertion of a negative 156 | r_degs = - math.degrees( r_theta ) 157 | print( r_axis, math.degrees( r_theta ), r_degs ) 158 | if gq_type == ELLIPSOID : #1 159 | r1 = math.sqrt( abs( -K_/A_ ) ) 160 | r2 = math.sqrt( abs( -K_/B_ ) ) 161 | r3 = math.sqrt( abs( -K_/C_ ) ) 162 | cmds.append( f"sphere radius 1") 163 | ids = emit_get_last_id( ent_type , cmds) 164 | cmds.append( f"body {{ { ids } }} scale x { r1 } y { r2 } z { r3 }") 165 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 166 | elif gq_type == ELLIPTIC_CYLINDER : #7 167 | if A_ == 0: 168 | print( "X", gq_type, A_, B_, C_, K_, r_axis, r_degs ) 169 | h = inner_world[0] if inner_world else w[0] 170 | r1 = math.sqrt( abs( K_/C_ ) ) 171 | r2 = math.sqrt( abs( K_/B_ ) ) 172 | cmds.append( f"cylinder height {h} Major Radius {r1} Minor Radius {r2}") 173 | ids = emit_get_last_id( ent_type , cmds) 174 | cmds.append( f"rotate body {{ { ids } }} about y angle 90") 175 | if node.side != '-': 176 | wid = 0 177 | if inner_world: 178 | if hex: 179 | cmds.append( f"create prism height {inner_world[2]} sides 6 radius { inner_world[0] / 2 } " ) 180 | wid = emit_get_last_id( ent_type , cmds) 181 | cmds.append( f"rotate body {{ {wid} }} about z angle 30" ) 182 | cmds.append( f"rotate body {{ {wid} }} about y angle 90") 183 | else: 184 | cmds.append( f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}" ) 185 | wid = emit_get_last_id( ent_type , cmds) 186 | else: 187 | cmds.append( f"brick x {w[0]} y {w[1]} z {w[2]}" ) 188 | wid = emit_get_last_id( ent_type , cmds) 189 | cmds.append( f"subtract body {{ { ids } }} from body {{ { wid } }}" ) 190 | cmds.append( f"Rotate body {{ {wid } }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 191 | move( wid, translation[0,0], translation[1,0], translation[2,0], cmds) 192 | return wid 193 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 194 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 195 | return ids 196 | if B_ == 0: 197 | print( "Y", gq_type, A_, B_, C_, K_ ) 198 | h = inner_world[1] if inner_world else w[1] 199 | r1 = math.sqrt( abs( K_/A_ ) ) 200 | r2 = math.sqrt( abs( K_/C_ ) ) 201 | cmds.append( f"cylinder height {h} Major Radius {r1} Minor Radius {r2}") 202 | ids = emit_get_last_id( ent_type , cmds) 203 | cmds.append( f"rotate body {{ { ids } }} about x angle 90") 204 | if node.side != '-': 205 | wid = 0 206 | if inner_world: 207 | if hex: 208 | cmds.append( f"create prism height {inner_world[2]} sides 6 radius { inner_world[0] / 2 } " ) 209 | wid = emit_get_last_id( ent_type , cmds) 210 | cmds.append( f"rotate body {{ {wid} }} about z angle 30" ) 211 | cmds.append( f"rotate body {{ {wid} }} about y angle 90") 212 | else: 213 | cmds.append( f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}" ) 214 | wid = emit_get_last_id( ent_type , cmds) 215 | else: 216 | cmds.append( f"brick x {w[0]} y {w[1]} z {w[2]}" ) 217 | wid = emit_get_last_id( ent_type , cmds) 218 | cmds.append( f"subtract body {{ { ids } }} from body {{ { wid } }}" ) 219 | cmds.append( f"Rotate body {{ {wid } }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 220 | move( wid, translation[0,0], translation[1,0], translation[2,0], cmds) 221 | return wid 222 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 223 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 224 | return ids 225 | if C_ == 0: 226 | print( "Z", gq_type, A_, B_, C_, K_ ) 227 | h = inner_world[2] if inner_world else w[2] 228 | r1 = math.sqrt( abs( K_/A_ ) ) 229 | r2 = math.sqrt( abs( K_/B_ ) ) 230 | cmds.append( f"cylinder height {h} Major Radius {r1} Minor Radius {r2}") 231 | ids = emit_get_last_id( ent_type , cmds) 232 | if node.side != '-': 233 | wid = 0 234 | if inner_world: 235 | if hex: 236 | cmds.append( f"create prism height {inner_world[2]} sides 6 radius { inner_world[0] / 2 } " ) 237 | wid = emit_get_last_id( ent_type , cmds) 238 | cmds.append( f"rotate body {{ {wid} }} about z angle 30" ) 239 | cmds.append( f"rotate body {{ {wid} }} about y angle 90") 240 | else: 241 | cmds.append( f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}" ) 242 | wid = emit_get_last_id( ent_type , cmds) 243 | else: 244 | cmds.append( f"brick x {w[0]} y {w[1]} z {w[2]}" ) 245 | wid = emit_get_last_id( ent_type , cmds) 246 | cmds.append( f"subtract body {{ { ids } }} from body {{ { wid } }}" ) 247 | cmds.append( f"Rotate body {{ {wid } }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 248 | move( wid, translation[0,0], translation[1,0], translation[2,0], cmds) 249 | return wid 250 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 251 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 252 | return ids 253 | elif gq_type == ELLIPTIC_CONE : #3 254 | if A_ == 0: 255 | h = inner_world[0] if inner_world else w[0] 256 | minor = math.sqrt( abs( -A_/C_ ) ) 257 | major = math.sqrt( abs( -A_/B_ ) ) 258 | rot_angle = - 90 259 | rot_axis = 1 260 | cmds.append( f"create frustum height {h} Major Radius {major} Minor Radius {minor} top 0") 261 | ids = emit_get_last_id( ent_type , cmds) 262 | cmds.append( f"rotate body {{ { ids } }} about y angle -90") 263 | cmds.append( f"copy body {{ { ids } }}") 264 | mirror = emit_get_last_id( ent_type , cmds) 265 | cmds.append( f"rotate body {{ { mirror } }} about 0 0 0 angle 180") 266 | cmds.append( f"unit body {{ { ids } }} {{ { mirror } }}") 267 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 268 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 269 | return ids 270 | if B_ == 0: 271 | h = inner_world[1] if inner_world else w[1] 272 | minor = math.sqrt( abs( -B_/A_ ) ) 273 | major = math.sqrt( abs( -B_/C_ ) ) 274 | rot_angle = 90 275 | rot_axis = 0 276 | cmds.append( f"create frustum height {h} Major Radius {major} Minor Radius {minor} top 0") 277 | ids = emit_get_last_id( ent_type , cmds) 278 | cmds.append( f"rotate body {{ { ids } }} about x angle 90") 279 | cmds.append( f"copy body {{ { ids } }}") 280 | mirror = emit_get_last_id( ent_type , cmds) 281 | cmds.append( f"rotate body {{ { mirror } }} about 0 0 0 angle 180") 282 | cmds.append( f"unit body {{ { ids } }} {{ { mirror } }}") 283 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 284 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 285 | return ids 286 | if C_ == 0: 287 | h = inner_world[2] if inner_world else w[2] 288 | minor = math.sqrt( abs( -C_/A_ ) ) 289 | major = math.sqrt( abs( -C_/B_ ) ) 290 | rot_angle = 180 291 | rot_axis = 0 292 | cmds.append( f"create frustum height {h} Major Radius {major} Minor Radius {minor} top 0") 293 | ids = emit_get_last_id( ent_type , cmds) 294 | cmds.append( f"copy body {{ { ids } }}") 295 | mirror = emit_get_last_id( ent_type , cmds) 296 | cmds.append( f"rotate body {{ { mirror } }} about 0 0 0 angle 180") 297 | cmds.append( f"unit body {{ { ids } }} {{ { mirror } }}") 298 | cmds.append( f"Rotate body {{ {ids} }} about 0 0 0 direction {r_axis[0]} {r_axis[1]} {r_axis[2]} Angle {r_degs}") 299 | move( ids, translation[0,0], translation[1,0], translation[2,0], cmds) 300 | return ids 301 | else: 302 | raise NotImplementedError(f"{surface.type} not implemented") 303 | else: 304 | raise NotImplementedError(f"{surface.type} not implemented") 305 | elif isinstance(node, Complement): 306 | print( "Complement:" ) 307 | id = surface_to_cubit_journal(node.node, w, indent + 1, inner_world, ent_type = ent_type ) 308 | cmds.append( f"brick x {w[0]} y {w[1]} z {w[2]}" ) 309 | wid = emit_get_last_id( ent_type , cmds) 310 | cmds.append( f"subtract body {{ {id} }} from body {{ {wid} }}" ) 311 | return emit_get_last_id( ent_type , cmds) 312 | elif isinstance(node, Intersection): 313 | last = 0 314 | if len( node ) > 0: 315 | last = surface_to_cubit_journal( node[0], w, indent + 1, inner_world, ent_type = ent_type ,) 316 | for subnode in node[1:]: 317 | s = surface_to_cubit_journal( subnode, w, indent + 1, inner_world, ent_type = ent_type ,) 318 | before = emit_get_last_id(cmds=cmds) 319 | cmds.append( f"intersect {ent_type} {{ {last} }} {{ {s} }}" ) 320 | after = emit_get_last_id(cmds=cmds) 321 | last = new_variable() 322 | cmds.append( f"#{{{last} = ( {before} == {after} ) ? {s} : {after}}}" ) 323 | if inner_world: 324 | cmds.append( f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}" ) 325 | iwid = emit_get_last_id( ent_type , cmds) 326 | cmds.append( f"intersect {ent_type} {{ {last} }} {{ {iwid} }}" ) 327 | return emit_get_last_id( ent_type , cmds) 328 | return last 329 | elif isinstance(node, Union): 330 | if len( node ) > 0: 331 | local_ent_type = "body" 332 | first = surface_to_cubit_journal( node[0], w, indent + 1, inner_world, ent_type = local_ent_type ) 333 | for subnode in node[1:]: 334 | s = surface_to_cubit_journal( subnode, w, indent + 1, inner_world, ent_type = local_ent_type ) 335 | cmds.append( f"unite {local_ent_type} {{ {first} }} {{ {s} }}" ) 336 | if inner_world: 337 | cmds.append( f"brick x {inner_world[0]} y {inner_world[1]} z {inner_world[2]}" ) 338 | iwid = emit_get_last_id( local_ent_type , cmds) 339 | cmds.append( f"intersect {ent_type} {{ {last} }} {{ {iwid} }}" ) 340 | return first 341 | return first 342 | elif isinstance(node, Quadric): 343 | pass 344 | else: 345 | raise NotImplementedError(f"{node} not implemented") 346 | 347 | def process_node_or_fill( node, w, indent = 0, offset = [0, 0], inner_world = None, outer_ll = None, ent_type = "body", hex = False ): 348 | def ind(): 349 | return ' ' * (2*indent) 350 | seen.add( node ) 351 | results = [] 352 | if hasattr( node, "region" ) and not ( hasattr( node, "fill" ) and isinstance(node.fill, Lattice) ): 353 | if node.region != None: 354 | id = surface_to_cubit_journal( node.region, w, indent, inner_world, hex = hex ) 355 | results.append( id ) 356 | elif hex: 357 | cmds.append( f"create prism height {inner_world[2]} sides 6 radius { ( inner_world[0] / 2) }" ) 358 | wid = emit_get_last_id( ent_type , cmds) 359 | cmds.append( f"rotate body {{ {wid} }} about z angle 30" ) 360 | results.append( wid ) 361 | 362 | if hasattr( node, "fill" ) and isinstance(node.fill, Lattice): 363 | id = process_node_or_fill( node.fill, w, indent + 1, offset, inner_world ) 364 | results.append( id ) 365 | if hasattr( node, "universes" ): 366 | pitch = node._pitch 367 | if isinstance( node, HexLattice ) : 368 | three_d_hex_lattice = len( node._pitch ) > 1 369 | #three_d_hex_lattice = len( node.center ) > 2 370 | #3d hex lattice 371 | if three_d_hex_lattice: 372 | center = [ node.center[0], node.center[1], node.center[1] ] 373 | ii = 0 374 | for uss in node.universes: 375 | z = ii * pitch[1] 376 | j = 0 377 | for us in uss: 378 | k = 0 379 | ring_id = ( len( uss ) - j -1 ) 380 | #print( "RING_ID", ring_id ) 381 | def draw_hex_cell( n, cell, x, y ): 382 | #print( i, j, k, len( node.universes ), len( uss), len( us ), x, y ) 383 | id = process_node_or_fill( cell, [ w[0], w[1], w[2] ], indent + 1, offset = [x,y,z], inner_world=[ pitch[0], pitch[0], pitch[1] ], outer_ll=outer_ll if outer_ll else [ node.center[0], node.center[1] ], hex = True ) 384 | ids = str( id ) 385 | if isinstance( id, list ): 386 | ids = ' '.join( map(str, id) ) 387 | else: 388 | pass 389 | if ids != '': 390 | cmds.append( f"move body {{ {ids} }} midpoint location {x} {y} {z}" ) 391 | side_to_side_diameter = pitch[0]/2 * math.sqrt( 3 ) 392 | center_to_mid_side_diameter = ( ( pitch[0] / 2 ) * math.sin( math.pi / 6 ) ) + pitch[0] / 2 393 | if ring_id < 2: 394 | for u in us: 395 | for n, cell in u._cells.items(): 396 | #print( n, cell ) 397 | theta = 2 * math.pi * -k / len( us ) + math.pi / 2 398 | r = ( len( uss ) - j -1 ) * side_to_side_diameter 399 | x = r * math.cos( theta ) 400 | y = r * math.sin( theta ) 401 | draw_hex_cell( n, cell, x, y ) 402 | k = k + 1 403 | else: 404 | x = 0 405 | x_pos = 0 406 | y_pos = 0 407 | r = ring_id 408 | for i in range( r, 0, -1 ): 409 | x_pos = x * center_to_mid_side_diameter 410 | y_pos = ring_id * side_to_side_diameter - ( x ) * 0.5 * side_to_side_diameter 411 | for n, cell in us[k]._cells.items(): 412 | draw_hex_cell( n, cell, x_pos, y_pos ) 413 | #print( r, k, x, x_pos, y_pos ) 414 | k = k + 1 415 | x = x + 1 416 | y_pos = ring_id * side_to_side_diameter - ( x ) * 0.5 * side_to_side_diameter 417 | for i in range( r, 0, -1 ): 418 | x_pos = x * center_to_mid_side_diameter 419 | for n, cell in us[k]._cells.items(): 420 | draw_hex_cell( n, cell, x_pos, y_pos ) 421 | #print( r, k, x, x_pos, y_pos ) 422 | y_pos = y_pos - side_to_side_diameter 423 | k = k + 1 424 | for i in range( r, 0, -1 ): 425 | x_pos = x * center_to_mid_side_diameter 426 | y_pos = - ring_id * side_to_side_diameter + ( x ) * 0.5 * side_to_side_diameter 427 | for n, cell in us[k]._cells.items(): 428 | draw_hex_cell( n, cell, x_pos, y_pos ) 429 | #print( r, k, x, x_pos, y_pos ) 430 | k = k + 1 431 | x = x - 1 432 | for i in range( r, 0, -1 ): 433 | x_pos = x * center_to_mid_side_diameter 434 | y_pos = - ring_id * side_to_side_diameter - ( x ) * 0.5 * side_to_side_diameter 435 | for n, cell in us[k]._cells.items(): 436 | draw_hex_cell( n, cell, x_pos, y_pos ) 437 | #print( r, k, x, x_pos, y_pos ) 438 | k = k + 1 439 | x = x - 1 440 | y_pos = - ring_id * side_to_side_diameter - ( x ) * 0.5 * side_to_side_diameter 441 | for i in range( r, 0, -1 ): 442 | x_pos = x * center_to_mid_side_diameter 443 | for n, cell in us[k]._cells.items(): 444 | draw_hex_cell( n, cell, x_pos, y_pos ) 445 | #print( r, k, x, x_pos, y_pos ) 446 | y_pos = y_pos + side_to_side_diameter 447 | k = k + 1 448 | for i in range( r, 0, -1 ): 449 | x_pos = x * center_to_mid_side_diameter 450 | y_pos = ring_id * side_to_side_diameter + ( x ) * 0.5 * side_to_side_diameter 451 | for n, cell in us[k]._cells.items(): 452 | draw_hex_cell( n, cell, x_pos, y_pos ) 453 | #print( r, k, x, x_pos, y_pos ) 454 | k = k + 1 455 | x = x + 1 456 | j = j + 1 457 | ii = ii + 1 458 | #2d hex lattice 459 | else: 460 | center = [ node.center[0], node.center[1] ] 461 | i = 0 462 | for us in node.universes: 463 | j = 0 464 | for u in us: 465 | for n, cell in u._cells.items(): 466 | #print( n, cell ) 467 | theta = 2 * math.pi * -j / len( us ) + math.pi / 2 468 | r = ( len( uss ) - i -1 ) * pitch[0] 469 | x = r * math.cos( theta ) 470 | y = r * math.sin( theta ) 471 | #print( n, i, j, k, len( node.universes ), len( uss), len( us ), x, y, theta ) 472 | id = process_node_or_fill( cell, [ w[0], w[1], w[2] ], indent + 1, offset = [x,y], inner_world=[ pitch[0], pitch[0], pitch[1] ], outer_ll=outer_ll if outer_ll else [ node.center[0], node.center[1] ], hex = True ) 473 | ids = str( id ) 474 | if isinstance( id, list ): 475 | ids = ' '.join( map(str, id) ) 476 | #results.extend( id ) 477 | else: 478 | #results.append( id ) 479 | pass 480 | if ids != '': 481 | cmds.append( f"move body {{ {ids} }} midpoint location {x} {y} {z}" ) 482 | j = j + 1 483 | i = i + 1 484 | 485 | elif isinstance( node, Lattice ): 486 | ll = [ node.lower_left[0], node.lower_left[1] ] 487 | if outer_ll: 488 | ll = outer_ll 489 | ll[0] = ll[0] + pitch[0] / 2 490 | ll[1] = ll[1] + pitch[1] / 2 491 | i = 0 492 | for us in node.universes: 493 | j = 0 494 | for u in us: 495 | for n, cell in u._cells.items(): 496 | x = ll[0] + j * pitch[0] + offset[0] 497 | y = ll[1] + i * pitch[1] + offset[1] 498 | #print( ind(), "UCell:", n, cell ) 499 | id = process_node_or_fill( cell, [ w[0], w[1], w[2] ], indent + 1, offset = [x,y], inner_world=[ pitch[0], pitch[1], w[2] ], outer_ll=outer_ll if outer_ll else [ node.lower_left[0], node.lower_left[1] ] ) 500 | ids = str( id ) 501 | if isinstance( id, list ): 502 | ids = ' '.join( map(str, id) ) 503 | #results.extend( id ) 504 | else: 505 | #results.append( id ) 506 | pass 507 | if ids != '': 508 | cmds.append( f"move body {{ {ids} }} midpoint location {x} {y} 0 except z" ) 509 | j = j + 1 510 | i = i + 1 511 | #FIXME rotate and tranlate 512 | r = flatten( results ) 513 | if len( r ) > 0: 514 | if node.name: 515 | cmds.append( f"body {{ {r[0]} }} name \"{node.name}\"" ) 516 | else: 517 | cmds.append( f"body {{ {r[0]} }} name \"Cell_{node.id}\"" ) 518 | return r 519 | 520 | def do_cell(cell, cell_ids: Iterable[int] = None): 521 | before = len( cmds ) 522 | cmds.append( f"#CELL {cell.id}" ) 523 | vol_or_body = process_node_or_fill( cell, w ) 524 | if cell.fill is None: 525 | cmds.append(f'group "mat:void" add body {{ { vol_or_body[0] } }} ') 526 | elif cell.fill_type == "material": 527 | mat_identifier = f"mat:{cell.fill.id}" 528 | # use material names when possible 529 | if cell.fill.name is not None and cell.fill.name: 530 | mat_identifier = f"mat:{cell.fill.name}" 531 | if len(mat_identifier) > 32: 532 | mat_identifier = mat_identifier[:32] 533 | warnings.warn(f'Truncating material name {mat_identifier} to 32 characters') 534 | cmds.append( f'group \"{mat_identifier}\" add body {{ { vol_or_body[0] } }} ' ) 535 | after = len( cmds ) 536 | 537 | if cell_ids is not None and cell.id in cell_ids: 538 | if filename.endswith(".jou"): 539 | cell_filename = filename[:-4] + f"_cell{cell.id}.jou" 540 | else: 541 | cell_filename = filename + f"_cell{cell.id}" 542 | write_journal_file(cell_filename, cmds[before:after]) 543 | 544 | for cell in geom.root_universe._cells.values(): 545 | if cells is not None and cell.id in cells: 546 | do_cell( cell, cell_ids=cells) 547 | else: 548 | do_cell( cell ) 549 | 550 | if filename: 551 | write_journal_file(filename, cmds) 552 | 553 | if to_cubit: 554 | cubit.cmd( "reset" ) 555 | for x in cmds: 556 | cubit.cmd( x ) 557 | cubit.cmd(f"save as {filename[:-4]}.cub overwrite") 558 | 559 | 560 | def write_journal_file(filename, cmds, verbose_journal=False): 561 | with open(filename, "w") as f: 562 | if not verbose_journal: 563 | f.write("set echo off\n") 564 | f.write("set info off\n") 565 | f.write("set warning off\n") 566 | f.write("graphics pause\n") 567 | f.write("set journal off\n") 568 | f.write("set default autosize off\n") 569 | for x in cmds: 570 | f.write(x + "\n") 571 | if not verbose_journal: 572 | f.write("graphics flush\n") 573 | f.write("set default autosize on\n") 574 | f.write("zoom reset\n") 575 | f.write("set echo on\n") 576 | f.write("set info on\n") 577 | f.write("set warning on\n") 578 | f.write("set journal on\n") 579 | 580 | 581 | def material_assignment(cell, geom_id, assignment_type='group'): 582 | if cell.fill is None: 583 | mat_identifier = "mat:void" 584 | elif cell.fill_type == "material": 585 | mat_identifier = f"mat:{cell.fill.id}" 586 | # use material names when possible 587 | if cell.fill.name is not None and cell.fill.name: 588 | mat_identifier = f"mat:{cell.fill.name}" 589 | else: 590 | return [] 591 | 592 | if len(mat_identifier) > 32: 593 | mat_identifier = mat_identifier[:32] 594 | warnings.warn(f'Truncating material name {mat_identifier} to 32 characters') 595 | 596 | cmds = [] 597 | if assignment_type == 'group': 598 | cmds.append(f'group \"{mat_identifier}\" add body {{ { geom_id } }}') 599 | else: 600 | raise ValueError(f"Unknown material assignment type requested: {assignment_type}") 601 | 602 | return cmds 603 | 604 | 605 | def openmc_to_cad(): 606 | """Command-line interface for OpenMC to CAD model conversion""" 607 | parser = ArgumentParser() 608 | parser.add_argument('input', help='Path to a OpenMC model.xml file or path to a directory containing OpenMC XMLs') 609 | parser.add_argument('-o', '--output', help='Output filename', default='openmc.jou') 610 | parser.add_argument('-w', '--world-size', help='Maximum width of the geometry in X, Y, and Z', nargs=3, type=int) 611 | parser.add_argument('-c', '--cells', help='List of cell IDs to convert', nargs='+', type=int) 612 | parser.add_argument('--to-cubit', help='Run Cubit', default=False, action='store_true') 613 | parser.add_argument('--cubit-path', help='Path to Cubit bin directory', default=None, type=str) 614 | args = parser.parse_args() 615 | 616 | model_path = Path(args.input) 617 | 618 | if model_path.is_dir(): 619 | if not (model_path / 'settings.xml').exists(): 620 | raise IOError(f'Unable to locate settings.xml in {model_path}') 621 | model = openmc.Model.from_xml(*[model_path / f for f in ('geometry.xml', 'materials.xml', 'settings.xml')]) 622 | else: 623 | model = openmc.Model.from_model_xml(model_path) 624 | 625 | if args.cubit_path is not None: 626 | sys.path.append(args.cubit_path) 627 | 628 | to_cubit_journal(model.geometry, world=args.world_size, filename=args.output, cells=args.cells, to_cubit=args.to_cubit) 629 | 630 | 631 | __all__ = ['CADPlane', 'CADXPlane', 'CADYPlane', 'CADZPlane', 632 | 'CADCylinder', 'CADXCylinder', 'CADYCylinder', 'CADZCylinder', 633 | 'CADSphere', 'CADXCone', 'CADYCone', 'CADZCone', 'CADXTorus', 'CADYTorus', 'CADZTorus'] --------------------------------------------------------------------------------