diff --git a/.github/workflows/black_lint.yml b/.github/workflows/black_lint.yml index 4e9b32639..ab4b875f6 100644 --- a/.github/workflows/black_lint.yml +++ b/.github/workflows/black_lint.yml @@ -1,7 +1,6 @@ name: Black Style Check on: - push: pull_request: jobs: diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index f479fc7b6..767380f6e 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -1,30 +1,36 @@ name: Test Build the Docs -on: [push, pull_request, workflow_dispatch] +on: + pull_request: + workflow_dispatch: jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: ["ubuntu-22.04"] + build-docs: + runs-on: "ubuntu-22.04" + timeout-minutes: 60 + steps: - - uses: actions/checkout@v3 - - name: Set up python 3.11 - uses: actions/setup-python@v3 - with: - python-version: "3.11" - - name: debug - run: | - pwd - ls - - uses: mpi4py/setup-mpi@v1 - - name: Install dependencies - run: | - pip install --user . mcdc[docs] - pip list - - name: Build the Docs - run: | - cd docs - make html + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + + - name: Set up MPI + uses: mpi4py/setup-mpi@v1 + + - name: Install docs dependencies + run: | + python -m pip install --upgrade pip + # If you have extras for docs, use this: + python -m pip install ".[docs]" + # Otherwise, something like: + # python -m pip install . sphinx sphinx-autodoc-typehints ... + python -m pip list + + - name: Build the docs + working-directory: docs + run: make html diff --git a/.github/workflows/regression_test-numba_gpu.yml b/.github/workflows/regression_test-gpu.yml similarity index 97% rename from .github/workflows/regression_test-numba_gpu.yml rename to .github/workflows/regression_test-gpu.yml index 2b1281c04..704b65919 100644 --- a/.github/workflows/regression_test-numba_gpu.yml +++ b/.github/workflows/regression_test-gpu.yml @@ -1,8 +1,7 @@ name: GPU regression test on: - push: - pull_request: + workflow_dispatch: jobs: build: diff --git a/.github/workflows/regression_test.yml b/.github/workflows/regression_test.yml index dba11f5b7..a54cc73cd 100644 --- a/.github/workflows/regression_test.yml +++ b/.github/workflows/regression_test.yml @@ -1,7 +1,6 @@ name: Regression Tests on: - push: pull_request: jobs: @@ -37,12 +36,14 @@ jobs: - name: Install MC/DC run: | - pip install -e . + pip install -e .[dev] pip list - name: Run Python regression tests (serial) working-directory: test/regression - run: python run.py + run: | + git clone https://github.com/CEMeNT-PSAAP/MCDC-regression_test_data.git + python run.py --include_native_physics python-regression-mpi: name: Python regression (MPI) @@ -76,14 +77,15 @@ jobs: - name: Install MC/DC run: | - pip install -e . + pip install -e .[dev] pip list - name: Run Python regression tests (MPI) working-directory: test/regression run: | - python run.py --mpiexec=4 - python run.py --mpiexec=16 --name=slab_reed_dd_3d + git clone https://github.com/CEMeNT-PSAAP/MCDC-regression_test_data.git + python run.py --include_native_physics --mpiexec=4 + python run.py --include_native_physics --mpiexec=16 --name=slab_reed_dd_3d numba-regression-serial: name: Numba regression (serial) @@ -117,12 +119,14 @@ jobs: - name: Install MC/DC run: | - pip install -e . + pip install -e .[dev] pip list - name: Run Numba regression tests (serial) working-directory: test/regression - run: python run.py --mode numba + run: | + git clone https://github.com/CEMeNT-PSAAP/MCDC-regression_test_data.git + python run.py --include_native_physics --mode numba numba-regression-mpi: name: Numba regression (MPI) @@ -156,11 +160,12 @@ jobs: - name: Install MC/DC run: | - pip install -e . + pip install -e .[dev] pip list - name: Run Numba regression tests (MPI) working-directory: test/regression run: | - python run.py --mode numba --mpiexec=4 - python run.py --mode numba --mpiexec=16 --name=slab_reed_dd_3d + git clone https://github.com/CEMeNT-PSAAP/MCDC-regression_test_data.git + python run.py --include_native_physics --mode numba --mpiexec=4 + python run.py --include_native_physics --mode numba --mpiexec=16 --name=slab_reed_dd_3d diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index e98e9c44d..e3c7a78c2 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -1,7 +1,6 @@ name: Unit Tests on: - push: pull_request: jobs: @@ -37,7 +36,7 @@ jobs: - name: Install MC/DC run: | - pip install -e . + pip install -e .[dev] pip list - name: Run unit tests diff --git a/config_cont_energy.sh b/config_cont_energy.sh deleted file mode 100644 index 600d6c21e..000000000 --- a/config_cont_energy.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -echo "WARNING: Seamless continous energy functionality" -echo "is only avlible to CEMeNT members." -echo " " - -# downloading library from zenodo -git clone git@github.com:CEMeNT-PSAAP/MCDC-Xsec.git - -cd MCDC-Xsec - -# untaring file -tar -xvzf mcdc_xs.tar.gz - -# going into the cross section library directory -cd mcdc_xs - -# getting the present working direcotry -xsec_dir=$(pwd) - -# exporting the needed enviroment variable for current enviroment -export MCDC_XSLIB="${xsec_dir}" - -# adding that enviroment variable to bashrc for future runs -export MCDC_XSLIB="${xsec_dir}">> ~/.bashrc - -# printing a complete message -echo "MCDC_XSLIB set as $MCDC_XSLIB in ~/.bashrc" diff --git a/examples/c5g7/2d/k-eigenvalue-iqmc/input.py b/examples/c5g7/2d/k-eigenvalue-iqmc/input.py deleted file mode 100644 index b1f74e027..000000000 --- a/examples/c5g7/2d/k-eigenvalue-iqmc/input.py +++ /dev/null @@ -1,194 +0,0 @@ -import h5py -import numpy as np - -import mcdc - -# ============================================================================= -# Materials -# ============================================================================= - -# Load material data -lib = h5py.File("../../MGXS-C5G7.h5", "r") - - -# Materials -def set_mat(mat): - return mcdc.material( - capture=mat["capture"][:], - scatter=mat["scatter"][:], - fission=mat["fission"][:], - nu_p=mat["nu"][:], - chi_p=mat["chi"][:], - ) - - -mat_uo2 = set_mat(lib["uo2"]) -mat_mox43 = set_mat(lib["mox43"]) -mat_mox7 = set_mat(lib["mox70"]) -mat_mox87 = set_mat(lib["mox87"]) -mat_gt = set_mat(lib["gt"]) -mat_fc = set_mat(lib["fc"]) -mat_mod = set_mat(lib["mod"]) - -# ============================================================================= -# Pin cells -# ============================================================================= - -pitch = 1.26 -radius = 0.54 - -# Surfaces -cy = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=radius) - -# Cells -uo2 = mcdc.cell(-cy, mat_uo2) -mox4 = mcdc.cell(-cy, mat_mox43) -mox7 = mcdc.cell(-cy, mat_mox7) -mox8 = mcdc.cell(-cy, mat_mox87) -gt = mcdc.cell(-cy, mat_gt) -fc = mcdc.cell(-cy, mat_fc) -mod = mcdc.cell(+cy, mat_mod) -modi = mcdc.cell(-cy, mat_mod) # For all-water lattice - -# Universes -u = mcdc.universe([uo2, mod]) -l = mcdc.universe([mox4, mod]) -m = mcdc.universe([mox7, mod]) -n = mcdc.universe([mox8, mod]) -g = mcdc.universe([gt, mod]) -f = mcdc.universe([fc, mod]) -w = mcdc.universe([modi, mod]) - -# ============================================================================= -# Assemblies -# ============================================================================= - -# Lattices -lattice_uo2 = mcdc.lattice( - x=[-pitch * 17 / 2, pitch, 17], - y=[-pitch * 17 / 2, pitch, 17], - universes=[ - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u], - [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, f, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u], - [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - ], -) - -lattice_mox = mcdc.lattice( - x=[-pitch * 17 / 2, pitch, 17], - y=[-pitch * 17 / 2, pitch, 17], - universes=[ - [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], - [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], - [l, m, m, m, m, g, m, m, g, m, m, g, m, m, m, m, l], - [l, m, m, g, m, n, n, n, n, n, n, n, m, g, m, m, l], - [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], - [l, m, g, n, n, g, n, n, g, n, n, g, n, n, g, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, g, n, n, g, n, n, f, n, n, g, n, n, g, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, g, n, n, g, n, n, g, n, n, g, n, n, g, m, l], - [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], - [l, m, m, g, m, n, n, n, n, n, n, n, m, g, m, m, l], - [l, m, m, m, m, g, m, m, g, m, m, g, m, m, m, m, l], - [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], - [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], - ], -) - -lattice_mod = mcdc.lattice( - x=[-pitch * 17 / 2, pitch * 17, 1], - y=[-pitch * 17 / 2, pitch * 17, 1], - universes=[[w]], -) - -# Assembly cells -# Surfaces -x0 = mcdc.surface("plane-x", x=-pitch * 17 / 2) -x1 = mcdc.surface("plane-x", x=pitch * 17 / 2) -y0 = mcdc.surface("plane-y", y=-pitch * 17 / 2) -y1 = mcdc.surface("plane-y", y=pitch * 17 / 2) -# Cells -assembly_uo2 = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_uo2) -assembly_mox = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mox) -assembly_mod = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mod) - -# Set assemblies in their respective universes -u_ = mcdc.universe([assembly_uo2]) -m_ = mcdc.universe([assembly_mox]) -w_ = mcdc.universe([assembly_mod]) - -# ============================================================================= -# Root universe: core -# ============================================================================= - -# Lattice -lattice_core = mcdc.lattice( - x=[-pitch * 17 * 3 / 2, pitch * 17, 3], - y=[-pitch * 17 * 3 / 2, pitch * 17, 3], - universes=[[u_, m_, w_], [m_, u_, w_], [w_, w_, w_]], -) - -# Core cell -# Surfaces -x0_ = mcdc.surface("plane-x", x=0.0, bc="reflective") -x1_ = mcdc.surface("plane-x", x=pitch * 17 * 3, bc="vacuum") -y0_ = mcdc.surface("plane-y", y=-pitch * 17 * 3, bc="vacuum") -y1_ = mcdc.surface("plane-y", y=0.0, bc="reflective") -# Cell -core = mcdc.cell( - +x0_ & -x1_ & +y0_ & -y1_, - lattice_core, - translation=[pitch * 17 * 3 / 2, -pitch * 17 * 3 / 2, 0.0], -) - -# Root universe -mcdc.universe([core], root=True) - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 1e4 -Nx = 17 * 3 * 2 -Ny = 17 * 3 * 2 -G = 7 -x_grid = np.linspace(0.0, pitch * 17 * 3, Nx + 1) -y_grid = np.linspace(-pitch * 17 * 3, 0.0, Ny + 1) - -phi0 = np.ones((G, Nx, Ny)) - -mcdc.iQMC( - x=x_grid, - y=y_grid, - g=np.ones(G), - phi0=phi0, - mode="batched", - scores=["source-x", "source-y"], -) - -# ============================================================================= -# run mcdc -# ============================================================================= - -# Setting -mcdc.setting(N_particle=N) -mcdc.eigenmode(N_inactive=40, N_active=10) - -# Run -mcdc.run() diff --git a/examples/c5g7/2d/k-eigenvalue-iqmc/process.py b/examples/c5g7/2d/k-eigenvalue-iqmc/process.py deleted file mode 100644 index 440793b18..000000000 --- a/examples/c5g7/2d/k-eigenvalue-iqmc/process.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py - - -# ============================================================================= -# Plot results -# ============================================================================= - -# Load iqmc result -with h5py.File("output.h5", "r") as f: - x = f["iqmc/grid/x"][:] - y = f["iqmc/grid/y"][:] - phi_avg = f["iqmc/tally/flux"][:] - f.close() - - -dx = x[1] - x[0] -x_mid = 0.5 * (x[1:] + x[:-1]) -y_mid = 0.5 * (y[1:] + y[:-1]) -Y, X = np.meshgrid(x_mid, y_mid) - -norm = np.sum(phi_avg) -phi_tot = phi_avg.sum(axis=0) / norm - -phi_fast = phi_avg[:5, :, :].sum(axis=0) -norm = np.sum(phi_fast) -phi_fast /= norm - -phi_slow = phi_avg[5:7, :, :].sum(axis=0) -norm = np.sum(phi_slow) -phi_slow /= norm - - -plt.figure(dpi=300, figsize=(8, 4)) -plt.pcolormesh(X, Y, phi_tot, shading="nearest") -plt.colorbar().set_label(r"Normalized Scalar Flux", rotation=270, labelpad=15) -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Total Neutron Flux") -plt.show() -plt.tight_layout() - - -plt.figure(dpi=300) -plt.pcolormesh(X, Y, phi_fast, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Fast Neutron Flux") -plt.show() - - -plt.figure(dpi=300) -plt.pcolormesh(X, Y, phi_slow, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Thermal Neutron Flux") -plt.show() diff --git a/examples/c5g7/2d/k-eigenvalue/input.py b/examples/c5g7/2d/k-eigenvalue/input.py deleted file mode 100644 index 227194d17..000000000 --- a/examples/c5g7/2d/k-eigenvalue/input.py +++ /dev/null @@ -1,189 +0,0 @@ -import h5py -import numpy as np - -import mcdc - -# ============================================================================= -# Materials -# ============================================================================= - -# Load material data -lib = h5py.File("../../MGXS-C5G7.h5", "r") - - -# Materials -def set_mat(mat): - return mcdc.material( - capture=mat["capture"][:], - scatter=mat["scatter"][:], - fission=mat["fission"][:], - nu_p=mat["nu"][:], - chi_p=mat["chi"][:], - ) - - -mat_uo2 = set_mat(lib["uo2"]) -mat_mox43 = set_mat(lib["mox43"]) -mat_mox7 = set_mat(lib["mox70"]) -mat_mox87 = set_mat(lib["mox87"]) -mat_gt = set_mat(lib["gt"]) -mat_fc = set_mat(lib["fc"]) -mat_mod = set_mat(lib["mod"]) - -# ============================================================================= -# Pin cells -# ============================================================================= - -pitch = 1.26 -radius = 0.54 - -# Surfaces -cy = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=radius) - -# Cells -uo2 = mcdc.cell(-cy, mat_uo2) -mox4 = mcdc.cell(-cy, mat_mox43) -mox7 = mcdc.cell(-cy, mat_mox7) -mox8 = mcdc.cell(-cy, mat_mox87) -gt = mcdc.cell(-cy, mat_gt) -fc = mcdc.cell(-cy, mat_fc) -mod = mcdc.cell(+cy, mat_mod) -modi = mcdc.cell(-cy, mat_mod) # For all-water lattice - -# Universes -u = mcdc.universe([uo2, mod]) -l = mcdc.universe([mox4, mod]) -m = mcdc.universe([mox7, mod]) -n = mcdc.universe([mox8, mod]) -g = mcdc.universe([gt, mod]) -f = mcdc.universe([fc, mod]) -w = mcdc.universe([modi, mod]) - -# ============================================================================= -# Assemblies -# ============================================================================= - -# Lattices -lattice_uo2 = mcdc.lattice( - x=[-pitch * 17 / 2, pitch, 17], - y=[-pitch * 17 / 2, pitch, 17], - universes=[ - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u], - [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, f, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u], - [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], - ], -) - -lattice_mox = mcdc.lattice( - x=[-pitch * 17 / 2, pitch, 17], - y=[-pitch * 17 / 2, pitch, 17], - universes=[ - [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], - [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], - [l, m, m, m, m, g, m, m, g, m, m, g, m, m, m, m, l], - [l, m, m, g, m, n, n, n, n, n, n, n, m, g, m, m, l], - [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], - [l, m, g, n, n, g, n, n, g, n, n, g, n, n, g, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, g, n, n, g, n, n, f, n, n, g, n, n, g, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], - [l, m, g, n, n, g, n, n, g, n, n, g, n, n, g, m, l], - [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], - [l, m, m, g, m, n, n, n, n, n, n, n, m, g, m, m, l], - [l, m, m, m, m, g, m, m, g, m, m, g, m, m, m, m, l], - [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], - [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], - ], -) - -lattice_mod = mcdc.lattice( - x=[-pitch * 17 / 2, pitch * 17, 1], - y=[-pitch * 17 / 2, pitch * 17, 1], - universes=[[w]], -) - -# Assembly cells -# Surfaces -x0 = mcdc.surface("plane-x", x=-pitch * 17 / 2) -x1 = mcdc.surface("plane-x", x=pitch * 17 / 2) -y0 = mcdc.surface("plane-y", y=-pitch * 17 / 2) -y1 = mcdc.surface("plane-y", y=pitch * 17 / 2) -# Cells -assembly_uo2 = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_uo2) -assembly_mox = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mox) -assembly_mod = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mod) - -# Set assemblies in their respective universes -u_ = mcdc.universe([assembly_uo2]) -m_ = mcdc.universe([assembly_mox]) -w_ = mcdc.universe([assembly_mod]) - -# ============================================================================= -# Root universe: core -# ============================================================================= - -# Lattice -lattice_core = mcdc.lattice( - x=[-pitch * 17 * 3 / 2, pitch * 17, 3], - y=[-pitch * 17 * 3 / 2, pitch * 17, 3], - universes=[[u_, m_, w_], [m_, u_, w_], [w_, w_, w_]], -) - -# Core cell -# Surfaces -x0_ = mcdc.surface("plane-x", x=0.0, bc="reflective") -x1_ = mcdc.surface("plane-x", x=pitch * 17 * 3, bc="vacuum") -y0_ = mcdc.surface("plane-y", y=-pitch * 17 * 3, bc="vacuum") -y1_ = mcdc.surface("plane-y", y=0.0, bc="reflective") -# Cell -core = mcdc.cell( - +x0_ & -x1_ & +y0_ & -y1_, - lattice_core, - translation=[pitch * 17 * 3 / 2, -pitch * 17 * 3 / 2, 0.0], -) - -# Root universe -mcdc.universe([core], root=True) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform in energy - -source = mcdc.source( - x=[0.0, pitch * 17 * 2], y=[-pitch * 17 * 2, 0.0], energy=np.ones(7) -) - -# ============================================================================= -# Set tally and parameter, and then run mcdc -# ============================================================================= - -# Tally -x_grid = np.linspace(0.0, pitch * 17 * 3, 17 * 3 + 1) -y_grid = np.linspace(-pitch * 17 * 3, 0.0, 17 * 3 + 1) -mcdc.tally.mesh_tally(scores=["flux"], x=x_grid, y=y_grid, g="all") - -# Setting -mcdc.setting(N_particle=1e3) - -mcdc.eigenmode(N_inactive=10, N_active=30, gyration_radius="infinite-z") -mcdc.population_control() - -# Run -mcdc.run() diff --git a/examples/c5g7/2d/k-eigenvalue/process.py b/examples/c5g7/2d/k-eigenvalue/process.py deleted file mode 100644 index 3d55044ad..000000000 --- a/examples/c5g7/2d/k-eigenvalue/process.py +++ /dev/null @@ -1,102 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py - - -# ============================================================================= -# Plot results -# ============================================================================= - -# Results -with h5py.File("output.h5", "r") as f: - phi_avg = f["tallies/mesh_tally_0/flux/mean"][:] - phi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] - k = f["k_cycle"][:] - k_avg = f["k_mean"][()] - k_sd = f["k_sdev"][()] - rg = f["gyration_radius"][:] - x = f["tallies/mesh_tally_0/grid/x"][:] - y = f["tallies/mesh_tally_0/grid/y"][:] - -dx = x[1] - x[0] -x_mid = 0.5 * (x[1:] + x[:-1]) -y_mid = 0.5 * (y[1:] + y[:-1]) -Y, X = np.meshgrid(x_mid, y_mid) - -norm = np.sum(phi_avg) -phi_avg = phi_avg / norm / dx**2 -phi_sd = phi_sd / norm / dx**2 - -phi_fast = np.zeros_like(phi_avg[0]) -phi_thermal = np.zeros_like(phi_avg[0]) -phi_fast_sd = np.zeros_like(phi_avg[0]) -phi_thermal_sd = np.zeros_like(phi_avg[0]) - -for i in range(5): - phi_fast += phi_avg[i] - phi_fast_sd += np.square(phi_sd[i]) -phi_fast_sd = np.sqrt(phi_fast_sd) / phi_fast -for i in range(5, 7): - phi_thermal += phi_avg[i] - phi_thermal_sd += np.square(phi_sd[i]) -phi_thermal_sd = np.sqrt(phi_thermal_sd) / phi_thermal - -print("k = %.5f +- %.5f" % (k_avg, k_sd)) -# Plot -N_iter = len(k) -(p1,) = plt.plot(np.arange(1, N_iter + 1), k, "-b", label="MC") -(p2,) = plt.plot( - np.arange(1, N_iter + 1), np.ones(N_iter) * k_avg, ":r", label="MC-avg" -) -plt.fill_between( - np.arange(1, N_iter + 1), - np.ones(N_iter) * (k_avg - k_sd), - np.ones(N_iter) * (k_avg + k_sd), - alpha=0.2, - color="r", -) -plt.xlabel("Iteration #") -plt.ylabel(r"$k$") -plt.grid() -ax2 = plt.gca().twinx() -(p3,) = ax2.plot(np.arange(1, N_iter + 1), rg, "g--", label="GyRad") -plt.ylabel(r"Gyration radius [cm]") -lines = [p1, p2, p3] -plt.legend(lines, [l.get_label() for l in lines]) -plt.show() - -plt.pcolormesh(X, Y, phi_fast, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Fast neutron flux") -plt.show() - -plt.pcolormesh(X, Y, phi_fast_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Fast neutron flux stdev") -plt.show() - -plt.pcolormesh(X, Y, phi_thermal, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Thermal neutron flux") -plt.show() - -plt.pcolormesh(X, Y, phi_thermal_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Thermal neutron flux stdev") -plt.show() diff --git a/examples/c5g7/3d/TDX/process.py b/examples/c5g7/3d/TDX/process.py deleted file mode 100644 index a96527d39..000000000 --- a/examples/c5g7/3d/TDX/process.py +++ /dev/null @@ -1,82 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py -from matplotlib import cm -from matplotlib import colors - - -# ============================================================================= -# Plot results -# ============================================================================= - -# Get results -with h5py.File("output.h5", "r") as f: - fis_avg = f["tallies/mesh_tally_0/fission/mean"][:] - fis_sd = f["tallies/mesh_tally_0/fission/sdev"][:] - t = f["tallies/mesh_tally_0/grid/t"][:] -t_mid = 0.5 * (t[:-1] + t[1:]) -dt = t[1:] - t[:-1] - -# Get reference -with h5py.File("reference.h5", "r") as f: - fis_ref = f["tally/fission/mean"][:] - fis_ref_sd = f["tally/fission/sdev"][:] - -# Normalize -norm = fis_ref[0] / dt[0] -fis_avg /= norm * dt -fis_sd /= norm * dt -fis_ref /= norm * dt -fis_ref_sd /= norm * dt - -# Plot -plt.plot(t_mid, fis_ref, "-m", fillstyle="none", label="Ref. (MC)") -plt.fill_between( - t_mid, fis_ref - fis_ref_sd, fis_ref + fis_ref_sd, alpha=0.2, color="m" -) -plt.plot(t_mid, fis_avg, "ok", fillstyle="none", label="MC") -plt.fill_between(t_mid, fis_avg - fis_sd, fis_avg + fis_sd, alpha=0.2, color="k") -plt.yscale("log") -plt.ylabel("Normalized fission rate") -plt.xlabel("time [s]") -plt.axvspan(0, 5, facecolor="gray", alpha=0.2) -plt.axvspan(5, 10, facecolor="green", alpha=0.2) -plt.axvspan(10, 15, facecolor="red", alpha=0.2) -plt.axvspan(15, 20, facecolor="blue", alpha=0.2) -plt.annotate( - "Phase 1", - (2.5, 0.3), - color="black", - ha="center", - va="center", - backgroundcolor="white", -) -plt.annotate( - "Phase 2", - (7.5, 0.3), - color="black", - ha="center", - va="center", - backgroundcolor="white", -) -plt.annotate( - "Phase 3", - (12.5, 0.3), - color="black", - ha="center", - va="center", - backgroundcolor="white", -) -plt.annotate( - "Phase 4", - (17.5, 4.0), - color="black", - ha="center", - va="center", - backgroundcolor="white", -) -plt.xlim([0.0, 20.0]) -plt.ylim([0.09, 200.0]) -plt.grid(which="both") -plt.legend() -plt.show() diff --git a/examples/c5g7/3d/TDX/reference.h5 b/examples/c5g7/3d/TDX/reference.h5 deleted file mode 100644 index 50acc19df..000000000 Binary files a/examples/c5g7/3d/TDX/reference.h5 and /dev/null differ diff --git a/examples/c5g7/3d/k-eigenvalue/process.py b/examples/c5g7/3d/k-eigenvalue/process.py deleted file mode 100644 index f47bb87e5..000000000 --- a/examples/c5g7/3d/k-eigenvalue/process.py +++ /dev/null @@ -1,190 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py -from matplotlib import cm -from matplotlib import colors - - -# ============================================================================= -# Plot results -# ============================================================================= - -# Results -with h5py.File("output.h5", "r") as f: - phi_avg = f["tally/flux/mean"][:] - phi_sd = f["tally/flux/sdev"][:] - k = f["k_cycle"][:] - k_avg = f["k_mean"][()] - k_sd = f["k_sdev"][()] - rg = f["gyration_radius"][:] - x = f["tally/grid/x"][:] - y = f["tally/grid/y"][:] - z = f["tally/grid/z"][:] - -dx = x[1] - x[0] -dz = z[1] - z[0] -dV = dx * dx * dz - -phi_avg /= dV -phi_sd /= dV - -phi_fast = phi_avg[0] -phi_thermal = phi_avg[1] -phi_fast_sd = phi_sd[0] -phi_thermal_sd = phi_sd[1] - -print("k = %.5f +- %.5f" % (k_avg, k_sd)) - -# Plot -N_iter = len(k) -(p1,) = plt.plot(np.arange(1, N_iter + 1), k, "-b", label="MC") -(p2,) = plt.plot( - np.arange(1, N_iter + 1), np.ones(N_iter) * k_avg, ":r", label="MC-avg" -) -plt.fill_between( - np.arange(1, N_iter + 1), - np.ones(N_iter) * (k_avg - k_sd), - np.ones(N_iter) * (k_avg + k_sd), - alpha=0.2, - color="r", -) -plt.xlabel("Iteration #") -plt.ylabel(r"$k$") -plt.grid() -ax2 = plt.gca().twinx() -(p3,) = ax2.plot(np.arange(1, N_iter + 1), rg, "g--", label="GyRad") -plt.ylabel(r"Gyration radius [cm]") -lines = [p1, p2, p3] -plt.legend(lines, [l.get_label() for l in lines]) -plt.show() - -# X-Y plane -x_mid = 0.5 * (x[1:] + x[:-1]) -Y, X = np.meshgrid(x_mid, x_mid) -phi_fast_xy = np.sum(phi_fast, axis=2) -phi_thermal_xy = np.sum(phi_thermal, axis=2) -phi_fast_xy_sd = np.sqrt(np.sum(np.square(phi_fast_sd), axis=2)) / phi_fast_xy -phi_thermal_xy_sd = np.sqrt(np.sum(np.square(phi_thermal_sd), axis=2)) / phi_thermal_xy - -plt.pcolormesh(X, Y, phi_fast_xy, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Fast neutron flux") -plt.show() - -plt.pcolormesh(X, Y, phi_fast_xy_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Fast neutron flux stdev") -plt.show() - -plt.pcolormesh(X, Y, phi_thermal_xy, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Thermal neutron flux") -plt.show() - -plt.pcolormesh(X, Y, phi_thermal_xy_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$y$ [cm]") -plt.title(r"Thermal neutron flux stdev") -plt.show() - -# X-Z plane -z_mid = 0.5 * (z[1:] + z[:-1]) -X, Z = np.meshgrid(z_mid, x_mid) -phi_fast_xz = np.sum(phi_fast, axis=1) -phi_thermal_xz = np.sum(phi_thermal, axis=1) -phi_fast_xz_sd = np.sqrt(np.sum(np.square(phi_fast_sd), axis=1)) / phi_fast_xz -phi_thermal_xz_sd = np.sqrt(np.sum(np.square(phi_thermal_sd), axis=1)) / phi_thermal_xz - -plt.pcolormesh(Z, X, phi_fast_xz, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Fast neutron flux") -plt.show() - -plt.pcolormesh(Z, X, phi_fast_xz_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Fast neutron flux stdev") -plt.show() - -plt.pcolormesh(Z, X, phi_thermal_xz, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Thermal neutron flux") -plt.show() - -plt.pcolormesh(Z, X, phi_thermal_xz_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$x$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Thermal neutron flux stdev") -plt.show() - -# Y-Z plane -X, Z = np.meshgrid(z_mid, x_mid) -phi_fast_xz = np.sum(phi_fast, axis=0) -phi_thermal_xz = np.sum(phi_thermal, axis=0) -phi_fast_xz_sd = np.sqrt(np.sum(np.square(phi_fast_sd), axis=0)) / phi_fast_xz -phi_thermal_xz_sd = np.sqrt(np.sum(np.square(phi_thermal_sd), axis=0)) / phi_thermal_xz - -plt.pcolormesh(Z, X, phi_fast_xz, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$y$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Fast neutron flux") -plt.show() - -plt.pcolormesh(Z, X, phi_fast_xz_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$y$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Fast neutron flux stdev") -plt.show() - -plt.pcolormesh(Z, X, phi_thermal_xz, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$y$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Thermal neutron flux") -plt.show() - -plt.pcolormesh(Z, X, phi_thermal_xz_sd, shading="nearest") -plt.colorbar() -ax = plt.gca() -ax.set_aspect("equal") -plt.xlabel(r"$y$ [cm]") -plt.ylabel(r"$z$ [cm]") -plt.title(r"Thermal neutron flux stdev") -plt.show() diff --git a/examples/c5g7/MGXS-C5G7.h5 b/examples/c5g7/MGXS-C5G7.h5 deleted file mode 100644 index 909465123..000000000 Binary files a/examples/c5g7/MGXS-C5G7.h5 and /dev/null differ diff --git a/examples/c5g7/3d/TDX/input.py b/examples/c5g7/k-eigenvalue/input.py similarity index 63% rename from examples/c5g7/3d/TDX/input.py rename to examples/c5g7/k-eigenvalue/input.py index 531787f54..174eae2c6 100644 --- a/examples/c5g7/3d/TDX/input.py +++ b/examples/c5g7/k-eigenvalue/input.py @@ -3,18 +3,17 @@ import mcdc - # ============================================================================= # Materials # ============================================================================= # Load material data -lib = h5py.File("../../MGXS-C5G7-TD.h5", "r") +lib = h5py.File("../MGXS-C5G7-TD.h5", "r") # Setter def set_mat(mat): - return mcdc.material( + return mcdc.MaterialMG( capture=mat["capture"][:], scatter=mat["scatter"][:], fission=mat["fission"][:], @@ -22,11 +21,12 @@ def set_mat(mat): nu_d=mat["nu_d"][:], chi_p=mat["chi_p"][:], chi_d=mat["chi_d"][:], - speed=mat["speed"], - decay=mat["decay"], + speed=mat["speed"][:], + decay_rate=mat["decay"][:], ) +# Materials mat_uo2 = set_mat(lib["uo2"]) # Fuel: UO2 mat_mox43 = set_mat(lib["mox43"]) # Fuel: MOX 4.3% mat_mox7 = set_mat(lib["mox7"]) # Fuel: MOX 7.0% @@ -48,83 +48,53 @@ def set_mat(mat): # Control rod banks fractions # All out: 0.0 # All in : 1.0 -cr1 = np.array([1.0, 1.0, 1.0, 0.889, 1.0]) -cr1_t = np.array([0.0, 5.0, 10.0, 15.0, 15.0 + 1.0 - cr1[-2]]) - -cr2 = np.array([1.0, 1.0, 0.0, 0.0, 0.8]) -cr2_t = np.array([0.0, 5.0, 10.0, 15.0, 15.8]) - -cr3 = np.array([0.75, 0.75, 1.0]) -cr3_t = np.array([0.0, 15.0, 15.25]) - -cr4 = np.array([1.0, 1.0, 0.5, 0.5, 1.0]) -cr4_t = np.array([0.0, 5.0, 7.5, 15.0, 15.5]) - -# Tips of the control rod banks +cr1 = 0.0 +cr2 = 0.0 +cr3 = 0.0 +cr4 = 0.0 +# Control rod banks interfaces cr1 = core_height * (0.5 - cr1) cr2 = core_height * (0.5 - cr2) cr3 = core_height * (0.5 - cr3) cr4 = core_height * (0.5 - cr4) -# Durations of the moving tips -cr1_durations = cr1_t[1:] - cr1_t[:-1] -cr2_durations = cr2_t[1:] - cr2_t[:-1] -cr3_durations = cr3_t[1:] - cr3_t[:-1] -cr4_durations = cr4_t[1:] - cr4_t[:-1] - -# Velocities of the moving tips -cr1_velocities = np.zeros((len(cr1) - 1, 3)) -cr2_velocities = np.zeros((len(cr2) - 1, 3)) -cr3_velocities = np.zeros((len(cr3) - 1, 3)) -cr4_velocities = np.zeros((len(cr4) - 1, 3)) -cr1_velocities[:, 2] = (cr1[1:] - cr1[:-1]) / cr1_durations -cr2_velocities[:, 2] = (cr2[1:] - cr2[:-1]) / cr2_durations -cr3_velocities[:, 2] = (cr3[1:] - cr3[:-1]) / cr3_durations -cr4_velocities[:, 2] = (cr4[1:] - cr4[:-1]) / cr4_durations - # Surfaces -cy = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=radius) -z1 = mcdc.surface("plane-z", z=cr1[0]) # Control rod banks interfaces -z2 = mcdc.surface("plane-z", z=cr2[0]) -z3 = mcdc.surface("plane-z", z=cr3[0]) -z4 = mcdc.surface("plane-z", z=cr4[0]) -zf = mcdc.surface("plane-z", z=core_height / 2) - -# Move the control bank tips -z1.move(cr1_velocities, cr1_durations) -z2.move(cr2_velocities, cr2_durations) -z3.move(cr3_velocities, cr3_durations) -z4.move(cr4_velocities, cr4_durations) +cy = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=radius) +z1 = mcdc.Surface.PlaneZ(z=cr1) # Control rod banks interfaces +z2 = mcdc.Surface.PlaneZ(z=cr2) +z3 = mcdc.Surface.PlaneZ(z=cr3) +z4 = mcdc.Surface.PlaneZ(z=cr4) +zf = mcdc.Surface.PlaneZ(z=core_height / 2) # Fission chamber -fc = mcdc.cell(-cy, mat_fc) -mod = mcdc.cell(+cy, mat_mod) -fission_chamber = mcdc.universe([fc, mod]) +fc = mcdc.Cell(-cy, mat_fc) +mod = mcdc.Cell(+cy, mat_mod) +fission_chamber = mcdc.Universe(cells=[fc, mod]) # Fuel rods -uo2 = mcdc.cell(-cy & -zf, mat_uo2) -mox4 = mcdc.cell(-cy & -zf, mat_mox43) -mox7 = mcdc.cell(-cy & -zf, mat_mox7) -mox8 = mcdc.cell(-cy & -zf, mat_mox87) -moda = mcdc.cell(-cy & +zf, mat_mod) # Water above pin -fuel_uo2 = mcdc.universe([uo2, mod, moda]) -fuel_mox43 = mcdc.universe([mox4, mod, moda]) -fuel_mox7 = mcdc.universe([mox7, mod, moda]) -fuel_mox87 = mcdc.universe([mox8, mod, moda]) +uo2 = mcdc.Cell(-cy & -zf, mat_uo2) +mox4 = mcdc.Cell(-cy & -zf, mat_mox43) +mox7 = mcdc.Cell(-cy & -zf, mat_mox7) +mox8 = mcdc.Cell(-cy & -zf, mat_mox87) +moda = mcdc.Cell(-cy & +zf, mat_mod) # Water above pin +fuel_uo2 = mcdc.Universe(cells=[uo2, mod, moda]) +fuel_mox43 = mcdc.Universe(cells=[mox4, mod, moda]) +fuel_mox7 = mcdc.Universe(cells=[mox7, mod, moda]) +fuel_mox87 = mcdc.Universe(cells=[mox8, mod, moda]) # Control rods and guide tubes -cr1 = mcdc.cell(-cy & +z1, mat_cr) -cr2 = mcdc.cell(-cy & +z2, mat_cr) -cr3 = mcdc.cell(-cy & +z3, mat_cr) -cr4 = mcdc.cell(-cy & +z4, mat_cr) -gt1 = mcdc.cell(-cy & -z1, mat_gt) -gt2 = mcdc.cell(-cy & -z2, mat_gt) -gt3 = mcdc.cell(-cy & -z3, mat_gt) -gt4 = mcdc.cell(-cy & -z4, mat_gt) -control_rod1 = mcdc.universe([cr1, gt1, mod]) -control_rod2 = mcdc.universe([cr2, gt2, mod]) -control_rod3 = mcdc.universe([cr3, gt3, mod]) -control_rod4 = mcdc.universe([cr4, gt4, mod]) +cr1 = mcdc.Cell(-cy & +z1, mat_cr) +cr2 = mcdc.Cell(-cy & +z2, mat_cr) +cr3 = mcdc.Cell(-cy & +z3, mat_cr) +cr4 = mcdc.Cell(-cy & +z4, mat_cr) +gt1 = mcdc.Cell(-cy & -z1, mat_gt) +gt2 = mcdc.Cell(-cy & -z2, mat_gt) +gt3 = mcdc.Cell(-cy & -z3, mat_gt) +gt4 = mcdc.Cell(-cy & -z4, mat_gt) +control_rod1 = mcdc.Universe(cells=[cr1, gt1, mod]) +control_rod2 = mcdc.Universe(cells=[cr2, gt2, mod]) +control_rod3 = mcdc.Universe(cells=[cr3, gt3, mod]) +control_rod4 = mcdc.Universe(cells=[cr4, gt4, mod]) # ============================================================================= # Fuel lattices @@ -134,7 +104,7 @@ def set_mat(mat): u = fuel_uo2 c = control_rod1 f = fission_chamber -lattice_1 = mcdc.lattice( +lattice_1 = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -164,7 +134,7 @@ def set_mat(mat): n = fuel_mox87 c = control_rod2 f = fission_chamber -lattice_2 = mcdc.lattice( +lattice_2 = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -194,7 +164,7 @@ def set_mat(mat): n = fuel_mox87 c = control_rod3 f = fission_chamber -lattice_3 = mcdc.lattice( +lattice_3 = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -222,7 +192,7 @@ def set_mat(mat): u = fuel_uo2 c = control_rod4 f = fission_chamber -lattice_4 = mcdc.lattice( +lattice_4 = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -251,43 +221,43 @@ def set_mat(mat): # ============================================================================= # Surfaces -x0 = mcdc.surface("plane-x", x=0.0, bc="reflective") -x1 = mcdc.surface("plane-x", x=pitch * 17) -x2 = mcdc.surface("plane-x", x=pitch * 17 * 2) -x3 = mcdc.surface("plane-x", x=pitch * 17 * 3, bc="vacuum") +x0 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +x1 = mcdc.Surface.PlaneX(x=pitch * 17) +x2 = mcdc.Surface.PlaneX(x=pitch * 17 * 2) +x3 = mcdc.Surface.PlaneX(x=pitch * 17 * 3, boundary_condition="vacuum") -y0 = mcdc.surface("plane-y", y=-pitch * 17 * 3, bc="vacuum") -y1 = mcdc.surface("plane-y", y=-pitch * 17 * 2) -y2 = mcdc.surface("plane-y", y=-pitch * 17) -y3 = mcdc.surface("plane-y", y=0.0, bc="reflective") +y0 = mcdc.Surface.PlaneY(y=-pitch * 17 * 3, boundary_condition="vacuum") +y1 = mcdc.Surface.PlaneY(y=-pitch * 17 * 2) +y2 = mcdc.Surface.PlaneY(y=-pitch * 17) +y3 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") -z0 = mcdc.surface("plane-z", z=-(core_height / 2 + refl_thick), bc="vacuum") -z1 = mcdc.surface("plane-z", z=-(core_height / 2)) -z2 = mcdc.surface("plane-z", z=(core_height / 2 + refl_thick), bc="vacuum") +z0 = mcdc.Surface.PlaneZ(z=-(core_height / 2 + refl_thick), boundary_condition="vacuum") +z1 = mcdc.Surface.PlaneZ(z=-(core_height / 2)) +z2 = mcdc.Surface.PlaneZ(z=(core_height / 2 + refl_thick), boundary_condition="vacuum") # Assembly cells center = np.array([pitch * 17 / 2, -pitch * 17 / 2, 0.0]) -assembly_1 = mcdc.cell(+x0 & -x1 & +y2 & -y3 & +z1 & -z2, lattice_1, translation=center) +assembly_1 = mcdc.Cell(+x0 & -x1 & +y2 & -y3 & +z1 & -z2, lattice_1, translation=center) center += np.array([pitch * 17, 0.0, 0.0]) -assembly_2 = mcdc.cell(+x1 & -x2 & +y2 & -y3 & +z1 & -z2, lattice_2, translation=center) +assembly_2 = mcdc.Cell(+x1 & -x2 & +y2 & -y3 & +z1 & -z2, lattice_2, translation=center) center += np.array([-pitch * 17, -pitch * 17, 0.0]) -assembly_3 = mcdc.cell(+x0 & -x1 & +y1 & -y2 & +z1 & -z2, lattice_3, translation=center) +assembly_3 = mcdc.Cell(+x0 & -x1 & +y1 & -y2 & +z1 & -z2, lattice_3, translation=center) center += np.array([pitch * 17, 0.0, 0.0]) -assembly_4 = mcdc.cell(+x1 & -x2 & +y1 & -y2 & +z1 & -z2, lattice_4, translation=center) +assembly_4 = mcdc.Cell(+x1 & -x2 & +y1 & -y2 & +z1 & -z2, lattice_4, translation=center) # Bottom reflector cell -reflector_bottom = mcdc.cell(+x0 & -x3 & +y0 & -y3 & +z0 & -z1, mat_mod) +reflector_bottom = mcdc.Cell(+x0 & -x3 & +y0 & -y3 & +z0 & -z1, mat_mod) # Side reflectors -reflector_south = mcdc.cell(+x0 & -x3 & +y0 & -y1 & +z1 & -z2, mat_mod) -reflector_east = mcdc.cell(+x2 & -x3 & +y1 & -y3 & +z1 & -z2, mat_mod) +reflector_south = mcdc.Cell(+x0 & -x3 & +y0 & -y1 & +z1 & -z2, mat_mod) +reflector_east = mcdc.Cell(+x2 & -x3 & +y1 & -y3 & +z1 & -z2, mat_mod) # Root universe -mcdc.universe( - [ +mcdc.simulation.set_root_universe( + cells=[ assembly_1, assembly_2, assembly_3, @@ -296,35 +266,41 @@ def set_mat(mat): reflector_south, reflector_east, ], - root=True, ) # ============================================================================= # Set source # ============================================================================= -# At highest energy - -energy = np.zeros(7) -energy[0] = 1.0 -source = mcdc.source( - point=[pitch * 17 / 2, -pitch * 17 / 2, 0.0], time=[0.0, 15.0], energy=energy +mcdc.Source( + x=[0.0, pitch * 17 * 2], + y=[-pitch * 17 * 2, 0.0], + z=[-core_height / 2, core_height / 2], + isotropic=True, + energy_group=0, # Highest energy ) # ============================================================================= -# Set tally and parameter, and then run mcdc +# Set tallies, settings, techniques and run MC/DC # ============================================================================= # Tally -t_grid = np.linspace(0.0, 20.0, 201) -mcdc.tally.mesh_tally(scores=["fission"], t=t_grid) - -# Setting -mcdc.setting(N_particle=1e2, active_bank_buff=1000) -# small particle count, a more realistic number is 1e7 or higher which -# will require some acceleration to run at those high particle counts -# This is a very hard problem to solve and may also require multiple -# nodes depending on your systems +x_grid = np.linspace(0.0, pitch * 17 * 3, 17 * 3 + 1) +y_grid = np.linspace(-pitch * 17 * 3, 0.0, 17 * 3 + 1) +z_grid = np.linspace( + -(core_height / 2 + refl_thick), (core_height / 2 + refl_thick), 102 + 17 * 2 + 1 +) +g_grid = np.array([-0.5, 3.5, 6.5]) # Collapsing to fast (1-4) and slow (5-7) +mesh = mcdc.MeshStructured(x=x_grid, y=y_grid, z=z_grid) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], energy=g_grid) + +# Settings +mcdc.settings.N_particle = 50 +mcdc.settings.census_bank_buffer_ratio = 4.0 +mcdc.settings.set_eigenmode(N_inactive=5, N_active=10, gyration_radius="all") + +# Techniques +mcdc.simulation.population_control() # Run mcdc.run() diff --git a/examples/eigenvalue/smr/process.py b/examples/c5g7/k-eigenvalue/process-output.py similarity index 100% rename from examples/eigenvalue/smr/process.py rename to examples/c5g7/k-eigenvalue/process-output.py diff --git a/examples/c5g7/transient/input.py b/examples/c5g7/transient/input.py new file mode 100644 index 000000000..40cbe4301 --- /dev/null +++ b/examples/c5g7/transient/input.py @@ -0,0 +1,367 @@ +import h5py +import numpy as np + +import mcdc + +# ============================================================================= +# Materials +# ============================================================================= + +# Load material data +lib = h5py.File("../MGXS-C5G7-TD.h5", "r") + + +# Setter +def set_mat(mat): + return mcdc.MaterialMG( + capture=mat["capture"][:], + scatter=mat["scatter"][:], + fission=mat["fission"][:], + nu_p=mat["nu_p"][:], + nu_d=mat["nu_d"][:], + chi_p=mat["chi_p"][:], + chi_d=mat["chi_d"][:], + speed=mat["speed"][:], + decay_rate=mat["decay"][:], + ) + + +# Materials +mat_uo2 = set_mat(lib["uo2"]) # Fuel: UO2 +mat_mox43 = set_mat(lib["mox43"]) # Fuel: MOX 4.3% +mat_mox7 = set_mat(lib["mox7"]) # Fuel: MOX 7.0% +mat_mox87 = set_mat(lib["mox87"]) # Fuel: MOX 8.7% +mat_gt = set_mat(lib["gt"]) # Guide tube +mat_fc = set_mat(lib["fc"]) # Fission chamber +mat_cr = set_mat(lib["cr"]) # Control rod +mat_mod = set_mat(lib["mod"]) # Moderator + +# ============================================================================= +# Pin cells +# ============================================================================= + +pitch = 1.26 +radius = 0.54 +core_height = 128.52 +reflector_thickness = 21.42 + +# Control rod banks fractions +# All out: 0.0 +# All in : 1.0 +cr1 = np.array([1.0, 1.0, 0.89, 1.0]) +cr1_t = np.array([0.0, 10.0, 15.0, 15.0 + 1.0 - cr1[-2]]) + +cr2 = np.array([1.0, 1.0, 0.0, 0.0, 0.8]) +cr2_t = np.array([0.0, 5.0, 10.0, 15.0, 15.8]) + +cr3 = np.array([0.75, 0.75, 1.0]) +cr3_t = np.array([0.0, 15.0, 15.25]) + +cr4 = np.array([1.0, 1.0, 0.5, 0.5, 1.0]) +cr4_t = np.array( + [0.0, 5.0, 5.0 + (cr4[1] - cr4[2]) / 2 * 10, 15.0, 15.0 + 1.0 - cr4[-2]] +) + +# Tips of the control rod banks +cr1_bottom = core_height * (0.5 - cr1) +cr2_bottom = core_height * (0.5 - cr2) +cr3_bottom = core_height * (0.5 - cr3) +cr4_bottom = core_height * (0.5 - cr4) +cr1_top = cr1_bottom + core_height +cr2_top = cr2_bottom + core_height +cr3_top = cr3_bottom + core_height +cr4_top = cr4_bottom + core_height + +# Durations of the moving tips +cr1_durations = cr1_t[1:] - cr1_t[:-1] +cr2_durations = cr2_t[1:] - cr2_t[:-1] +cr3_durations = cr3_t[1:] - cr3_t[:-1] +cr4_durations = cr4_t[1:] - cr4_t[:-1] + +# Velocities of the moving tips +cr1_velocities = np.zeros((len(cr1) - 1, 3)) +cr2_velocities = np.zeros((len(cr2) - 1, 3)) +cr3_velocities = np.zeros((len(cr3) - 1, 3)) +cr4_velocities = np.zeros((len(cr4) - 1, 3)) +cr1_velocities[:, 2] = (cr1_top[1:] - cr1_top[:-1]) / cr1_durations +cr2_velocities[:, 2] = (cr2_top[1:] - cr2_top[:-1]) / cr2_durations +cr3_velocities[:, 2] = (cr3_top[1:] - cr3_top[:-1]) / cr3_durations +cr4_velocities[:, 2] = (cr4_top[1:] - cr4_top[:-1]) / cr4_durations + +# Surfaces +cy = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=radius) +# Control rod top and bottom tips +z1_top = mcdc.Surface.PlaneZ(z=cr1_top[0]) +z1_bottom = mcdc.Surface.PlaneZ(z=cr1_bottom[0]) +z2_top = mcdc.Surface.PlaneZ(z=cr2_top[0]) +z2_bottom = mcdc.Surface.PlaneZ(z=cr2_bottom[0]) +z3_top = mcdc.Surface.PlaneZ(z=cr3_top[0]) +z3_bottom = mcdc.Surface.PlaneZ(z=cr3_bottom[0]) +z4_top = mcdc.Surface.PlaneZ(z=cr4_top[0]) +z4_bottom = mcdc.Surface.PlaneZ(z=cr4_bottom[0]) +# Fuel top +# (Bottom is bounded by the universe cell) +zf = mcdc.Surface.PlaneZ(z=0.5 * core_height) + +# Move the control tips +z1_top.move(cr1_velocities, cr1_durations) +z1_bottom.move(cr1_velocities, cr1_durations) +z2_top.move(cr2_velocities, cr2_durations) +z2_bottom.move(cr2_velocities, cr2_durations) +z3_top.move(cr3_velocities, cr3_durations) +z3_bottom.move(cr3_velocities, cr3_durations) +z4_top.move(cr4_velocities, cr4_durations) +z4_bottom.move(cr4_velocities, cr4_durations) + +# Fission chamber pin +fc = mcdc.Cell(-cy, mat_fc) +mod = mcdc.Cell(+cy, mat_mod) +fission_chamber = mcdc.Universe(cells=[fc, mod]) + +# Fuel rods +uo2 = mcdc.Cell(-cy & -zf, mat_uo2) +mox4 = mcdc.Cell(-cy & -zf, mat_mox43) +mox7 = mcdc.Cell(-cy & -zf, mat_mox7) +mox8 = mcdc.Cell(-cy & -zf, mat_mox87) +moda = mcdc.Cell(-cy & +zf, mat_mod) # Water above pin +fuel_uo2 = mcdc.Universe(cells=[uo2, mod, moda]) +fuel_mox43 = mcdc.Universe(cells=[mox4, mod, moda]) +fuel_mox7 = mcdc.Universe(cells=[mox7, mod, moda]) +fuel_mox87 = mcdc.Universe(cells=[mox8, mod, moda]) + +# Control rods and guide tubes +cr1 = mcdc.Cell(-cy & +z1_bottom & -z1_top, mat_cr) +gt1_lower = mcdc.Cell(-cy & -z1_bottom, mat_gt) +gt1_upper = mcdc.Cell(-cy & +z1_top, mat_gt) +# +cr2 = mcdc.Cell(-cy & +z2_bottom & -z2_top, mat_cr) +gt2_lower = mcdc.Cell(-cy & -z2_bottom, mat_gt) +gt2_upper = mcdc.Cell(-cy & +z2_top, mat_gt) +# +cr3 = mcdc.Cell(-cy & +z3_bottom & -z3_top, mat_cr) +gt3_lower = mcdc.Cell(-cy & -z3_bottom, mat_gt) +gt3_upper = mcdc.Cell(-cy & +z3_top, mat_gt) +# +cr4 = mcdc.Cell(-cy & +z4_bottom & -z4_top, mat_cr) +gt4_lower = mcdc.Cell(-cy & -z4_bottom, mat_gt) +gt4_upper = mcdc.Cell(-cy & +z4_top, mat_gt) +# +control_rod1 = mcdc.Universe(cells=[cr1, gt1_lower, gt1_upper, mod]) +control_rod2 = mcdc.Universe(cells=[cr2, gt2_lower, gt2_upper, mod]) +control_rod3 = mcdc.Universe(cells=[cr3, gt3_lower, gt3_upper, mod]) +control_rod4 = mcdc.Universe(cells=[cr4, gt4_lower, gt4_upper, mod]) + +# ============================================================================= +# Fuel lattices +# ============================================================================= + +# UO2 lattice 1 +u = fuel_uo2 +c = control_rod1 +f = fission_chamber +lattice_1 = mcdc.Lattice( + x=[-pitch * 17 / 2, pitch, 17], + y=[-pitch * 17 / 2, pitch, 17], + universes=[ + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, c, u, u, c, u, u, c, u, u, u, u, u], + [u, u, u, c, u, u, u, u, u, u, u, u, u, c, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, c, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, f, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, c, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, c, u, u, u, u, u, u, u, u, u, c, u, u, u], + [u, u, u, u, u, c, u, u, c, u, u, c, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + ], +) + +# MOX lattice 2 +l = fuel_mox43 +m = fuel_mox7 +n = fuel_mox87 +c = control_rod2 +f = fission_chamber +lattice_2 = mcdc.Lattice( + x=[-pitch * 17 / 2, pitch, 17], + y=[-pitch * 17 / 2, pitch, 17], + universes=[ + [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], + [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], + [l, m, m, m, m, c, m, m, c, m, m, c, m, m, m, m, l], + [l, m, m, c, m, n, n, n, n, n, n, n, m, c, m, m, l], + [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], + [l, m, c, n, n, c, n, n, c, n, n, c, n, n, c, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, c, n, n, c, n, n, f, n, n, c, n, n, c, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, c, n, n, c, n, n, c, n, n, c, n, n, c, m, l], + [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], + [l, m, m, c, m, n, n, n, n, n, n, n, m, c, m, m, l], + [l, m, m, m, m, c, m, m, c, m, m, c, m, m, m, m, l], + [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], + [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], + ], +) + +# MOX lattice 3 +l = fuel_mox43 +m = fuel_mox7 +n = fuel_mox87 +c = control_rod3 +f = fission_chamber +lattice_3 = mcdc.Lattice( + x=[-pitch * 17 / 2, pitch, 17], + y=[-pitch * 17 / 2, pitch, 17], + universes=[ + [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], + [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], + [l, m, m, m, m, c, m, m, c, m, m, c, m, m, m, m, l], + [l, m, m, c, m, n, n, n, n, n, n, n, m, c, m, m, l], + [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], + [l, m, c, n, n, c, n, n, c, n, n, c, n, n, c, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, c, n, n, c, n, n, f, n, n, c, n, n, c, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, m, n, n, n, n, n, n, n, n, n, n, n, m, m, l], + [l, m, c, n, n, c, n, n, c, n, n, c, n, n, c, m, l], + [l, m, m, m, n, n, n, n, n, n, n, n, n, m, m, m, l], + [l, m, m, c, m, n, n, n, n, n, n, n, m, c, m, m, l], + [l, m, m, m, m, c, m, m, c, m, m, c, m, m, m, m, l], + [l, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, l], + [l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l], + ], +) + +# UO2 lattice 4 +u = fuel_uo2 +c = control_rod4 +f = fission_chamber +lattice_4 = mcdc.Lattice( + x=[-pitch * 17 / 2, pitch, 17], + y=[-pitch * 17 / 2, pitch, 17], + universes=[ + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, c, u, u, c, u, u, c, u, u, u, u, u], + [u, u, u, c, u, u, u, u, u, u, u, u, u, c, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, c, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, f, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, c, u, u, c, u, u, c, u, u, c, u, u, c, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, c, u, u, u, u, u, u, u, u, u, c, u, u, u], + [u, u, u, u, u, c, u, u, c, u, u, c, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u], + ], +) + +# ============================================================================= +# Assemblies and core +# ============================================================================= + +# Surfaces +x0 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +x1 = mcdc.Surface.PlaneX(x=pitch * 17) +x2 = mcdc.Surface.PlaneX(x=pitch * 17 * 2) +x3 = mcdc.Surface.PlaneX(x=pitch * 17 * 3, boundary_condition="vacuum") + +y0 = mcdc.Surface.PlaneY(y=-pitch * 17 * 3, boundary_condition="vacuum") +y1 = mcdc.Surface.PlaneY(y=-pitch * 17 * 2) +y2 = mcdc.Surface.PlaneY(y=-pitch * 17) +y3 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") + +z0 = mcdc.Surface.PlaneZ( + z=-(core_height / 2 + reflector_thickness), boundary_condition="vacuum" +) +z1 = mcdc.Surface.PlaneZ(z=-(core_height / 2)) +z2 = mcdc.Surface.PlaneZ( + z=(core_height / 2 + reflector_thickness), boundary_condition="vacuum" +) + +# Assembly cells +center = np.array([pitch * 17 / 2, -pitch * 17 / 2, 0.0]) +assembly_1 = mcdc.Cell(+x0 & -x1 & +y2 & -y3 & +z1 & -z2, lattice_1, translation=center) + +center += np.array([pitch * 17, 0.0, 0.0]) +assembly_2 = mcdc.Cell(+x1 & -x2 & +y2 & -y3 & +z1 & -z2, lattice_2, translation=center) + +center += np.array([-pitch * 17, -pitch * 17, 0.0]) +assembly_3 = mcdc.Cell(+x0 & -x1 & +y1 & -y2 & +z1 & -z2, lattice_3, translation=center) + +center += np.array([pitch * 17, 0.0, 0.0]) +assembly_4 = mcdc.Cell(+x1 & -x2 & +y1 & -y2 & +z1 & -z2, lattice_4, translation=center) + +# Bottom reflector cell +reflector_bottom = mcdc.Cell(+x0 & -x3 & +y0 & -y3 & +z0 & -z1, mat_mod) + +# Side reflectors +reflector_south = mcdc.Cell(+x0 & -x3 & +y0 & -y1 & +z1 & -z2, mat_mod) +reflector_east = mcdc.Cell(+x2 & -x3 & +y1 & -y3 & +z1 & -z2, mat_mod) + +# Root universe +mcdc.simulation.set_root_universe( + cells=[ + assembly_1, + assembly_2, + assembly_3, + assembly_4, + reflector_bottom, + reflector_south, + reflector_east, + ], +) + +# ============================================================================= +# Set source +# ============================================================================= +# Throughout the active center pin of Assembly four, at highest energy, +# for the first 15 seconds + +source = mcdc.Source( + x=np.array([pitch * 17 * 3 / 2] * 2) + np.array([-pitch / 2, +pitch / 2]), + y=np.array([-pitch * 17 * 3 / 2] * 2) + np.array([-pitch / 2, +pitch / 2]), + z=[-core_height / 2, core_height / 2], + isotropic=True, + energy_group=0, # Highest energy + time=[0.0, 15.0], +) + +# ============================================================================= +# Set tallies, settings, techniques and run MC/DC +# ============================================================================= + +# Tallies +Nt = 100 +Nx = 17 * 2 +Ny = 17 * 2 +Nz = 17 * 6 +t = np.linspace(0.0, 20.0, Nt + 1) +x = np.linspace(0.0, pitch * 17 * 2, Nx + 1) +y = np.linspace(-pitch * 17 * 2, 0.0, Ny + 1) +z = np.linspace(-core_height / 2, core_height / 2, Nz + 1) +mesh = mcdc.MeshStructured(x=x, y=y, z=z) +mcdc.TallyMesh(mesh=mesh, scores=["fission"], time=t) + +# Settings +mcdc.settings.N_particle = 10000 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 + +# Run +mcdc.run() diff --git a/examples/c5g7/transient/plot-fission-sdev.py b/examples/c5g7/transient/plot-fission-sdev.py new file mode 100644 index 000000000..90c58957a --- /dev/null +++ b/examples/c5g7/transient/plot-fission-sdev.py @@ -0,0 +1,97 @@ +import h5py +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import numpy as np +import os +import shutil + +# Get fission rates +with h5py.File("output.h5", "r") as f: + fissions = f["tallies/mesh_tally_0/fission/mean"][()] + fissions_sd = f["tallies/mesh_tally_0/fission/sdev"][()] + + x = f["tallies/mesh_tally_0/grid/x"][()] + y = f["tallies/mesh_tally_0/grid/y"][()] + z = f["tallies/mesh_tally_0/grid/z"][()] + t = f["tallies/mesh_tally_0/grid/time"][()] + +# The grids +t_mid = 0.5 * (t[:-1] + t[1:]) +XY_X, XY_Y = np.meshgrid(x, y, indexing="ij") +XZ_X, XZ_Z = np.meshgrid(x, z, indexing="ij") +YZ_Y, YZ_Z = np.meshgrid(y, z, indexing="ij") + +# Relative stdevs +fissions_sd[fissions == 0.0] = 0.0 +non_zeros = fissions != 0.0 +fissions_sd[non_zeros] /= fissions[non_zeros] + +# Average relative stdev (in %) +fission_sd_avg = np.average(fissions_sd, axis=(1, 2, 3)) * 100.0 + +# Create clean folder for output figures +# Check if the folder exists +if os.path.exists("fission-sdev"): + shutil.rmtree("fission-sdev") # Remove the existing folder +os.makedirs("fission-sdev") # Create a new folder + +# Iterate over time step and create figures +N = len(fissions) +for i in range(N): + fission_sd = fissions_sd[i] + + # Calculate fission averages + fission_x_sd = np.average(fission_sd, axis=0) + fission_y_sd = np.average(fission_sd, axis=1) + fission_z_sd = np.average(fission_sd, axis=2) + + # Plot + fig = plt.figure(figsize=(8, 5)) + gs = gridspec.GridSpec( + 2, 3, width_ratios=[0.7, 1, 1], height_ratios=[1, 1], hspace=0.5 + ) + + ax1 = fig.add_subplot(gs[0, 0]) # Top-left + ax2 = fig.add_subplot(gs[1, 0]) # Bottom-left + ax3 = fig.add_subplot(gs[:, 1]) # Entire second column + ax4 = fig.add_subplot(gs[:, 2]) # Entire third column + + # Total fission curve + ax1.plot(t_mid, fission_sd_avg, "b") + ax1.set_yscale("log") + ax1.set_ylabel("Average relative sdev (%)") + ax1.set_xlabel("Time") + ax1.set_title("Average relative sdev") + # Total fission point + ax1.plot(t_mid[i], fission_sd_avg[i], "ro", fillstyle="none") + + # XY fission + ax2.pcolormesh(XY_X, XY_Y, fission_z_sd) + ax2.set_aspect("equal") + ax2.set_xlabel(r"$x$") + ax2.set_ylabel(r"$y$") + ax2.set_title("Fission-XY") + + # XZ fission + ax3.pcolormesh(XZ_X, XZ_Z, fission_y_sd) + ax3.set_aspect("equal") + ax3.set_xlabel(r"$x$") + ax3.set_ylabel(r"$z$") + ax3.set_title("Fission-XZ") + pos = ax3.get_position() + ax3.set_position( + [pos.x0 + 0.02, pos.y0, pos.width, pos.height] + ) # shift right by 0.02 + + # YZ fission + ax4.pcolormesh(YZ_Y, YZ_Z, fission_x_sd) + ax4.set_aspect("equal") + ax4.set_xlabel(r"$y$") + ax4.set_ylabel(r"$z$") + ax4.set_title("Fission-YZ") + + plt.suptitle("MC/DC result - Fission Rate Relative Sdev.") + plt.savefig( + f"fission-sdev/figure_{i:03}.png", dpi=300, bbox_inches="tight", pad_inches=0 + ) + plt.close() diff --git a/examples/c5g7/transient/plot-fission.py b/examples/c5g7/transient/plot-fission.py new file mode 100644 index 000000000..93aa77851 --- /dev/null +++ b/examples/c5g7/transient/plot-fission.py @@ -0,0 +1,89 @@ +import h5py +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import numpy as np +import os +import shutil + +# Get results +with h5py.File("output.h5", "r") as f: + fissions = f["tallies/mesh_tally_0/fission/mean"][()] + x = f["tallies/mesh_tally_0/grid/x"][()] + y = f["tallies/mesh_tally_0/grid/y"][()] + z = f["tallies/mesh_tally_0/grid/z"][()] + t = f["tallies/mesh_tally_0/grid/time"][()] + +# Total fission +fission_total = np.average(fissions, axis=(1, 2, 3)) +fission_total /= fission_total[0] + +# The grids +t_mid = 0.5 * (t[:-1] + t[1:]) +XY_X, XY_Y = np.meshgrid(x, y, indexing="ij") +XZ_X, XZ_Z = np.meshgrid(x, z, indexing="ij") +YZ_Y, YZ_Z = np.meshgrid(y, z, indexing="ij") + +# Create clean folder for output figures +# Check if the folder exists +if os.path.exists("fission"): + shutil.rmtree("fission") # Remove the existing folder +os.makedirs("fission") # Create a new folder + +# Iterate over time step and create figures +N = len(fissions) +for i in range(N): + fission = fissions[i] + + # Calculate fission averages + fission_x = np.average(fission, axis=0) + fission_y = np.average(fission, axis=1) + fission_z = np.average(fission, axis=2) + + # Plot + fig = plt.figure(figsize=(8, 5)) + gs = gridspec.GridSpec( + 2, 3, width_ratios=[0.7, 1, 1], height_ratios=[1, 1], hspace=0.5 + ) + + ax1 = fig.add_subplot(gs[0, 0]) # Top-left + ax2 = fig.add_subplot(gs[1, 0]) # Bottom-left + ax3 = fig.add_subplot(gs[:, 1]) # Entire second column + ax4 = fig.add_subplot(gs[:, 2]) # Entire third column + + # Total fission curve + ax1.plot(t_mid, fission_total, "b") + ax1.set_yscale("log") + ax1.set_ylabel("Total fission rate") + ax1.set_xlabel("Time") + ax1.set_title("Total fission rate") + # Total fission point + ax1.plot(t_mid[i], fission_total[i], "ro", fillstyle="none") + + # XY fission + ax2.pcolormesh(XY_X, XY_Y, fission_z) + ax2.set_aspect("equal") + ax2.set_xlabel(r"$x$") + ax2.set_ylabel(r"$y$") + ax2.set_title("Fission-XY") + + # XZ fission + ax3.pcolormesh(XZ_X, XZ_Z, fission_y) + ax3.set_aspect("equal") + ax3.set_xlabel(r"$x$") + ax3.set_ylabel(r"$z$") + ax3.set_title("Fission-XZ") + pos = ax3.get_position() + ax3.set_position( + [pos.x0 + 0.02, pos.y0, pos.width, pos.height] + ) # shift right by 0.02 + + # YZ fission + ax4.pcolormesh(YZ_Y, YZ_Z, fission_x) + ax4.set_aspect("equal") + ax4.set_xlabel(r"$y$") + ax4.set_ylabel(r"$z$") + ax4.set_title("Fission-YZ") + + plt.suptitle("MC/DC result - Fission Rate") + plt.savefig(f"fission/figure_{i:03}.png", bbox_inches="tight", pad_inches=0) + plt.close() diff --git a/examples/eigenvalue/slab_2gu_iqmc/input.py b/examples/eigenvalue/slab_2gu_iqmc/input.py deleted file mode 100644 index 49de1240a..000000000 --- a/examples/eigenvalue/slab_2gu_iqmc/input.py +++ /dev/null @@ -1,46 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Based on Sood, PNE, Volume 42, Issue 1, 2003, Pages 55-106 2003, -# "Analytical Benchmark Test Set For Criticality Code Verification" - -# Set materials -# 2G-U Slab data -m1 = mcdc.material( - capture=np.array([0.01344, 0.00384]), - scatter=np.array([[0.26304, 0.0720], [0.00000, 0.078240]]), - fission=np.array([0.06912, 0.06192]), - nu_p=np.array([2.5, 2.7]), - chi_p=np.array([[0.425, 0.425], [0.575, 0.575]]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=6.01275, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -Nx = 10 -N = 1000 -x = np.linspace(0.0, 6.01275, num=Nx + 1) -phi0 = np.ones((2, Nx)) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.iQMC(x=x, g=np.ones(2), phi0=phi0, mode="batched") -# Setting -mcdc.setting(N_particle=N) -mcdc.eigenmode(N_inactive=10, N_active=5) - -# Run -mcdc.run() diff --git a/examples/eigenvalue/slab_kornreich_iqmc/input.py b/examples/eigenvalue/slab_kornreich_iqmc/input.py deleted file mode 100644 index 13a8142ae..000000000 --- a/examples/eigenvalue/slab_kornreich_iqmc/input.py +++ /dev/null @@ -1,53 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Based on Kornreich, ANE 2004, 31, 1477-1494, -# DOI: 10.1016/j.anucene.2004.03.012 - -# Set materials -m1 = mcdc.material( - capture=np.array([0.0]), - scatter=np.array([[0.9]]), - fission=np.array([0.1]), - nu_p=np.array([6.0]), -) -m2 = mcdc.material( - capture=np.array([0.68]), - scatter=np.array([[0.2]]), - fission=np.array([0.12]), - nu_p=np.array([2.5]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=1.5) -s3 = mcdc.surface("plane-x", x=2.6, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) - - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 500 -x = np.linspace(0.0, 2.6, 52) -Nx = len(x) - 1 -phi0 = np.ones((Nx)) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.iQMC(x=x, phi0=phi0, scores=["source-x"], mode="batched", sample_method="halton") -# Setting -mcdc.setting(N_particle=N) -mcdc.eigenmode(N_inactive=20, N_active=5) - -# Run -mcdc.run() diff --git a/examples/eigenvalue/slab_kornreich_iqmc/process.py b/examples/eigenvalue/slab_kornreich_iqmc/process.py deleted file mode 100644 index 1ed0017a8..000000000 --- a/examples/eigenvalue/slab_kornreich_iqmc/process.py +++ /dev/null @@ -1,96 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py - -# ============================================================================= -# Import data -# ============================================================================= - -with h5py.File("output.h5", "r") as f: - # Note the spatial (dx) and source strength (100+1) normalization - keff = f["k_eff"][()] - phi_avg = f["iqmc/tally/flux/mean"][:] - sweeps = f["iqmc/sweep_count"][()] - x = f["iqmc/grid/x"][:] - dx = x[1] - x[0] - x_mid = 0.5 * (x[:-1] + x[1:]) - f.close() - -tmp = 0.5 * (phi_avg[1:] + phi_avg[:-1]) -norm = np.sum(tmp * dx) -phi_avg /= norm -print("Keff = ", keff) -print("Number of QMC Transport Sweeps = ", sweeps) - -# ============================================================================= -# Reference solution -# ============================================================================= - -x_exact = np.array( - [ - 0.0, - 0.15, - 0.3, - 0.45, - 0.6, - 0.75, - 0.9, - 1.05, - 1.2, - 1.35, - 1.5, - 1.6, - 1.7, - 1.8, - 1.9, - 2, - 2.1, - 2.2, - 2.3, - 2.4, - 2.5, - ] -) -dx = x_exact[1:] - x_exact[:-1] -k_exact = 1.28657 -phi_exact = np.array( - [ - 1, - 1.417721, - 1.698988, - 1.903163, - 2.03435, - 2.092069, - 2.075541, - 1.984535, - 1.818753, - 1.574144, - 1.199995, - 0.9532296, - 0.7980474, - 0.6788441, - 0.5823852, - 0.5020479, - 0.4337639, - 0.3747058, - 0.3226636, - 0.2755115, - 0.228371, - ] -) -tmp = 0.5 * (phi_exact[1:] + phi_exact[:-1]) -norm = np.sum(tmp * dx) -phi_exact /= norm - -# ============================================================================= -# Begin Plot -# ============================================================================= -plt.figure() -plt.plot(x_exact, phi_exact, label="analytic") -plt.plot(x_mid, phi_avg, label="iQMC") -plt.title("Kornreich et al. Slab") -plt.ylabel(r"$\phi(x)$") -plt.xlabel(r"$x$") -plt.grid() -plt.legend() -plt.show() diff --git a/examples/eigenvalue/smr/input.py b/examples/eigenvalue/smr/input.py deleted file mode 100644 index dd1ea47b7..000000000 --- a/examples/eigenvalue/smr/input.py +++ /dev/null @@ -1,14675 +0,0 @@ -import mcdc -import numpy as np - -# ====================================================================================== -# Materials -# ====================================================================================== - -# Material name: Helium -# ID: 1 -# Volume: 1.0 -m1 = mcdc.material( - nuclides=[ - ["He3", 4.808864272483583e-10], - ["He4", 0.00024044273273775193], - ] -) -# Material name: Inconel -# ID: 3 -# Volume: 1.0 -m3 = mcdc.material( - nuclides=[ - ["Si28", 0.0005675748458998167], - ["Si29", 2.881983126575598e-05], - ["Si30", 1.8998161560800606e-05], - ["Cr50", 0.0007823874015570459], - ["Cr52", 0.015087561698097418], - ["Cr53", 0.0017108083743585282], - ["Cr54", 0.00042585641630822467], - ["Mn55", 0.0007820073144981398], - ["Fe54", 0.0014797392701973641], - ["Fe56", 0.02322874201694273], - ["Fe57", 0.0005364529531388864], - ["Fe58", 7.139204007422978e-05], - ["Ni58", 0.02931978281911652], - ["Ni60", 0.011293927856516], - ["Ni61", 0.0004909392240540197], - ["Ni62", 0.0015653290762693152], - ["Ni64", 0.00039864316797716485], - ] -) -# Material name: SS302 -# ID: 4 -# Volume: 1.0 -m4 = mcdc.material( - nuclides=[ - ["Si28", 0.0015544035849381745], - ["Si29", 7.892817900656517e-05], - ["Si30", 5.202980831633897e-05], - ["Cr50", 0.000711974950938374], - ["Cr52", 0.013729727726193934], - ["Cr53", 0.0015568409025692384], - ["Cr54", 0.00038753065361793535], - ["Mn55", 0.0017231784390118814], - ["Fe54", 0.003467932096055604], - ["Fe56", 0.054439117494534534], - ["Fe57", 0.0012572366305896735], - ["Fe58", 0.00016731511568472964], - ["Ni58", 0.004941136170422727], - ["Ni60", 0.0019033168077081128], - ["Ni61", 8.273586378242074e-05], - ["Ni62", 0.0002637981381064599], - ["Ni64", 6.718160869525927e-05], - ] -) -# Material name: SS304 -# ID: 5 -# Volume: 1.0 -m5 = mcdc.material( - nuclides=[ - ["Si28", 0.000952813800538438], - ["Si29", 4.838116621547466e-05], - ["Si30", 3.189308097558792e-05], - ["Cr50", 0.0007677835613844196], - ["Cr52", 0.014805941187343848], - ["Cr53", 0.0016788748692747287], - ["Cr54", 0.000417907490970373], - ["Mn55", 0.0017604482016877105], - ["Fe54", 0.0034619568150176883], - ["Fe56", 0.05434531836079257], - ["Fe57", 0.0012550703995358764], - ["Fe58", 0.0001670268300982717], - ["Ni58", 0.005608895030886979], - ["Ni60", 0.002160536325402338], - ["Ni61", 9.391701811886321e-05], - ["Ni62", 0.0002994485508898603], - ["Ni64", 7.626071781494654e-05], - ] -) -# Material name: Carbon Steel -# ID: 6 -# Volume: 1.0 -m6 = mcdc.material( - nuclides=[ - ["C12", 0.0010442103094126405], - ["C13", 1.1697344995776637e-05], - ["Mn55", 0.0006412591519223605], - ["P31", 3.7913297334043665e-05], - ["S32", 3.480801497243693e-05], - ["S33", 2.742025443981405e-07], - ["S34", 1.536752373542364e-06], - ["S36", 5.339824353827618e-09], - ["Si28", 0.000617015163486909], - ["Si29", 3.1330269529323576e-05], - ["Si30", 2.0653053682821572e-05], - ["Ni58", 0.0004086181311418285], - ["Ni60", 0.00015739897264761742], - ["Ni61", 6.842024358597134e-06], - ["Ni62", 2.1815367655114368e-05], - ["Ni64", 5.555730998971823e-06], - ["Cr50", 1.373827831539271e-05], - ["Cr52", 0.00026492901252833927], - ["Cr53", 3.004082318358793e-05], - ["Cr54", 7.477796751321481e-06], - ["Mo92", 4.4822291310606895e-05], - ["Mo94", 2.810993160790809e-05], - ["Mo95", 4.856742618745322e-05], - ["Mo96", 5.1015226914058824e-05], - ["Mo97", 2.9318533259312206e-05], - ["Mo98", 7.432746922042984e-05], - ["Mo100", 2.9814212142465947e-05], - ["V50", 1.1526145240679119e-07], - ["V51", 4.5989319455791894e-05], - ["Nb93", 5.055917738603357e-06], - ["Cu63", 0.00010223019587827225], - ["Cu65", 4.56081209267397e-05], - ["Ca40", 1.704268333890243e-05], - ["Ca42", 1.1374564024217834e-07], - ["Ca43", 2.3733634358428184e-08], - ["Ca44", 3.6672860192375593e-07], - ["Ca46", 7.032187772753565e-10], - ["Ca48", 3.287547867637643e-08], - ["B10", 2.5832795133853293e-06], - ["B11", 1.0450421269107751e-05], - ["Ti46", 1.214386179605987e-06], - ["Ti47", 1.0951555387252844e-06], - ["Ti48", 1.0851460531518844e-05], - ["Ti49", 7.963429398385609e-07], - ["Ti50", 7.624873257424189e-07], - ["Al27", 4.352299802675485e-05], - ["Fe54", 0.004743658379473851], - ["Fe56", 0.07446529191498036], - ["Fe57", 0.0017197283316076073], - ["Fe58", 0.0002288642708527182], - ] -) -# Material name: Zircaloy-4 -# ID: 7 -# Volume: 1.0 -m7 = mcdc.material( - nuclides=[ - ["O16", 0.00030744435226246966], - ["O17", 1.1679932181228452e-07], - ["O18", 6.164785312704674e-07], - ["Cr50", 3.296180328418399e-06], - ["Cr52", 6.356355428793489e-05], - ["Cr53", 7.207596771153883e-06], - ["Cr54", 1.7941233963793304e-06], - ["Fe54", 8.669830240139012e-06], - ["Fe56", 0.00013609779373633635], - ["Fe57", 3.143091576474185e-06], - ["Fe58", 4.1828778921182414e-07], - ["Zr90", 0.02182757976935886], - ["Zr91", 0.004760066934270842], - ["Zr92", 0.007275859888090276], - ["Zr94", 0.00737343710204759], - ["Zr96", 0.0011878955606900586], - ["Sn112", 4.673521272730707e-06], - ["Sn114", 3.1799215898767953e-06], - ["Sn115", 1.6381414619925706e-06], - ["Sn116", 7.005463783334945e-05], - ["Sn117", 3.7002724807551606e-05], - ["Sn118", 0.00011669348891480064], - ["Sn119", 4.138716226578583e-05], - ["Sn120", 0.00015697249778294243], - ["Sn122", 2.230763257260888e-05], - ["Sn124", 2.789658616579101e-05], - ] -) -# Material name: M5 -# ID: 8 -# Volume: 1.0 -m8 = mcdc.material( - nuclides=[ - ["Zr90", 0.021826659699624183], - ["Zr91", 0.004759866313504049], - ["Zr92", 0.007275553233208061], - ["Zr94", 0.007373126250329802], - ["Zr96", 0.0011878454258298875], - ["Nb93", 0.00042910080334290177], - ["O16", 5.7790773120342736e-05], - ["O17", 2.195494260303957e-08], - ["O18", 1.15880388345964e-07], - ] -) -# Material name: Borated Water -# ID: 10 -# Volume: 1.0 -# S(a,b): c_H_in_H2O -m10 = mcdc.material( - nuclides=[ - ["B10", 1.0323440206972448e-05], - ["B11", 4.1762534601163005e-05], - ["H1", 0.050347844752850625], - ["H2", 7.842394716362082e-06], - ["O16", 0.025117935412784034], - ["O17", 9.542402714463945e-06], - ["O18", 5.03657582849965e-05], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 18 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m18 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 19 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m19 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 20 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m20 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 21 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m21 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 22 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m22 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 23 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m23 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 24 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m24 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 25 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m25 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 26 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m26 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 3.1% Enr. UO2 Fuel -# ID: 27 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m27 = mcdc.material( - nuclides=[ - ["O16", 0.04585265389377734], - ["O17", 1.7419604031574338e-05], - ["O18", 9.19424166352541e-05], - # ['U234',6.451090625866024e-06], - ["U235", 0.0007217486041189947], - ["U238", 0.02224950230720295], - # ['U236',3.3059552742695457e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 28 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m28 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 29 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m29 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 30 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m30 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 31 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m31 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 32 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m32 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 33 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m33 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 34 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m34 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 35 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m35 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 36 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m36 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 2.4% Enr. UO2 Fuel -# ID: 37 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m37 = mcdc.material( - nuclides=[ - ["O16", 0.04583036614158277], - ["O17", 1.741113682662514e-05], - ["O18", 9.189772587857765e-05], - # ['U234',4.9887180727590005e-06], - ["U235", 0.0005581382302893396], - ["U238", 0.022404154012604437], - # ['U236',2.5565411774489522e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 38 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m38 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 39 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m39 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 40 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m40 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 41 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m41 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 42 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m42 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 43 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m43 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 44 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m44 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 45 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m45 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 46 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m46 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) -# Material name: 1.6% Enr. UO2 Fuel -# ID: 47 -# Volume: 0.05278032927907148 -# Depletable: {depletable} -m47 = mcdc.material( - nuclides=[ - ["O16", 0.04589711643122753], - ["O17", 1.743649552488715e-05], - ["O18", 9.203157163056531e-05], - # ['U234',3.3520389074005344e-06], - ["U235", 0.0003750264168772414], - ["U238", 0.02262319599228636], - # ['U236',1.7178011204872611e-06], - ] -) - - -# ====================================================================================== -# Geometry -# ====================================================================================== - -# -------------------------------------------------------------------------------------- -# Surfaces -# -------------------------------------------------------------------------------------- - -s1 = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=0.405765) # Name: Pellet OR -s2 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.06459 -) # Name: FR Plenum Spring OR -s3 = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=0.41402) # Name: Clad IR -s4 = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=0.47498) # Name: Clad OR -s5 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.5715 -) # Name: GT IR (above dashpot) -s6 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.61214 -) # Name: GT OR (above dashpot) -s7 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.50419 -) # Name: GT IR (at dashpot) -s8 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.61214 -) # Name: GT OR (at dashpot) -s20 = mcdc.surface("plane-x", x=-0.62208) # Name: minimum x -s21 = mcdc.surface("plane-x", x=0.62208) # Name: maximum x -s22 = mcdc.surface("plane-y", y=-0.62208) # Name: minimum y -s23 = mcdc.surface("plane-y", y=0.62208) # Name: maximum y -s24 = mcdc.surface("plane-x", x=-10.70864) # Name: minimum x -s25 = mcdc.surface("plane-x", x=10.70864) # Name: maximum x -s26 = mcdc.surface("plane-y", y=-10.70864) # Name: minimum y -s27 = mcdc.surface("plane-y", y=10.70864) # Name: maximum y -s28 = mcdc.surface("plane-x", x=-10.73635) # Name: minimum x -s29 = mcdc.surface("plane-x", x=10.73635) # Name: maximum x -s30 = mcdc.surface("plane-y", y=-10.73635) # Name: minimum y -s31 = mcdc.surface("plane-y", y=10.73635) # Name: maximum y -s32 = mcdc.surface("plane-z", z=-16.6205) # Name: bot support plate -s33 = mcdc.surface("plane-z", z=-11.6205) # Name: top support plate -s34 = mcdc.surface("plane-z", z=-1.4604999999999997) # Name: bottom FR -s35 = mcdc.surface("plane-z", z=2.220446049250313e-16) # Name: bot active core -s36 = mcdc.surface("plane-z", z=199.9996) # Name: top active core -s38 = mcdc.surface("plane-z", z=4.5395) # Name: bottom grid 1 -s39 = mcdc.surface("plane-z", z=8.9845) # Name: top of grid 1 -s40 = mcdc.surface("plane-z", z=55.40325) # Name: bottom grid 2 -s41 = mcdc.surface("plane-z", z=59.84825) # Name: top of grid 2 -s42 = mcdc.surface("plane-z", z=106.26700000000001) # Name: bottom grid 3 -s43 = mcdc.surface("plane-z", z=110.71200000000002) # Name: top of grid 3 -s44 = mcdc.surface("plane-z", z=157.13075) # Name: bottom grid 4 -s45 = mcdc.surface("plane-z", z=161.57575) # Name: top of grid 4 -s46 = mcdc.surface("plane-z", z=207.99450000000002) # Name: bottom grid 5 -s47 = mcdc.surface("plane-z", z=212.4395) # Name: top of grid 5 -s48 = mcdc.surface("plane-z", z=46.079) # Name: top dashpot -s49 = mcdc.surface("plane-z", z=213.48953999999998) # Name: top pin plenum -s50 = mcdc.surface("plane-z", z=214.4395) # Name: top FR -s51 = mcdc.surface("plane-z", z=217.78449999999998) # Name: bottom upper nozzle -s52 = mcdc.surface("plane-z", z=226.61149999999998) # Name: top upper nozzle -s71 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=93.98 -) # Name: core barrel IR -s72 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=99.06 -) # Name: core barrel OR -s78 = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=122.555) # Name: RPV IR -s79 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=133.35, bc="vacuum" -) # Name: RPV OR -s80 = mcdc.surface( - "plane-z", z=246.61149999999998, bc="vacuum" -) # Name: upper problem boundary -s81 = mcdc.surface("plane-z", z=-36.6205, bc="vacuum") # Name: lower problem boundary -s82 = mcdc.surface("plane-z", z=1.0204061224489798) -s83 = mcdc.surface("plane-z", z=2.0408122448979595) -s84 = mcdc.surface("plane-z", z=3.061218367346939) -s85 = mcdc.surface("plane-z", z=4.081624489795918) -s86 = mcdc.surface("plane-z", z=5.1020306122448975) -s87 = mcdc.surface("plane-z", z=6.122436734693878) -s88 = mcdc.surface("plane-z", z=7.142842857142857) -s89 = mcdc.surface("plane-z", z=8.163248979591836) -s90 = mcdc.surface("plane-z", z=9.183655102040817) -s91 = mcdc.surface("plane-z", z=10.204061224489795) -s92 = mcdc.surface("plane-z", z=11.224467346938775) -s93 = mcdc.surface("plane-z", z=12.244873469387755) -s94 = mcdc.surface("plane-z", z=13.265279591836734) -s95 = mcdc.surface("plane-z", z=14.285685714285714) -s96 = mcdc.surface("plane-z", z=15.306091836734693) -s97 = mcdc.surface("plane-z", z=16.326497959183673) -s98 = mcdc.surface("plane-z", z=17.34690408163265) -s99 = mcdc.surface("plane-z", z=18.367310204081633) -s100 = mcdc.surface("plane-z", z=19.38771632653061) -s101 = mcdc.surface("plane-z", z=20.40812244897959) -s102 = mcdc.surface("plane-z", z=21.428528571428572) -s103 = mcdc.surface("plane-z", z=22.44893469387755) -s104 = mcdc.surface("plane-z", z=23.46934081632653) -s105 = mcdc.surface("plane-z", z=24.48974693877551) -s106 = mcdc.surface("plane-z", z=25.51015306122449) -s107 = mcdc.surface("plane-z", z=26.530559183673468) -s108 = mcdc.surface("plane-z", z=27.550965306122446) -s109 = mcdc.surface("plane-z", z=28.571371428571428) -s110 = mcdc.surface("plane-z", z=29.591777551020407) -s111 = mcdc.surface("plane-z", z=30.612183673469385) -s112 = mcdc.surface("plane-z", z=31.632589795918367) -s113 = mcdc.surface("plane-z", z=32.652995918367345) -s114 = mcdc.surface("plane-z", z=33.67340204081633) -s115 = mcdc.surface("plane-z", z=34.6938081632653) -s116 = mcdc.surface("plane-z", z=35.714214285714284) -s117 = mcdc.surface("plane-z", z=36.734620408163266) -s118 = mcdc.surface("plane-z", z=37.75502653061224) -s119 = mcdc.surface("plane-z", z=38.77543265306122) -s120 = mcdc.surface("plane-z", z=39.795838775510205) -s121 = mcdc.surface("plane-z", z=40.81624489795918) -s122 = mcdc.surface("plane-z", z=41.83665102040816) -s123 = mcdc.surface("plane-z", z=42.857057142857144) -s124 = mcdc.surface("plane-z", z=43.87746326530612) -s125 = mcdc.surface("plane-z", z=44.8978693877551) -s126 = mcdc.surface("plane-z", z=45.91827551020408) -s127 = mcdc.surface("plane-z", z=46.93868163265306) -s128 = mcdc.surface("plane-z", z=47.95908775510204) -s129 = mcdc.surface("plane-z", z=48.97949387755102) -s130 = mcdc.surface("plane-z", z=49.9999) -s131 = mcdc.surface("plane-z", z=51.02030612244898) -s132 = mcdc.surface("plane-z", z=52.040712244897954) -s133 = mcdc.surface("plane-z", z=53.061118367346936) -s134 = mcdc.surface("plane-z", z=54.08152448979592) -s135 = mcdc.surface("plane-z", z=55.10193061224489) -s136 = mcdc.surface("plane-z", z=56.122336734693874) -s137 = mcdc.surface("plane-z", z=57.142742857142856) -s138 = mcdc.surface("plane-z", z=58.16314897959183) -s139 = mcdc.surface("plane-z", z=59.18355510204081) -s140 = mcdc.surface("plane-z", z=60.203961224489795) -s141 = mcdc.surface("plane-z", z=61.22436734693877) -s142 = mcdc.surface("plane-z", z=62.24477346938775) -s143 = mcdc.surface("plane-z", z=63.265179591836734) -s144 = mcdc.surface("plane-z", z=64.28558571428572) -s145 = mcdc.surface("plane-z", z=65.30599183673469) -s146 = mcdc.surface("plane-z", z=66.32639795918367) -s147 = mcdc.surface("plane-z", z=67.34680408163265) -s148 = mcdc.surface("plane-z", z=68.36721020408163) -s149 = mcdc.surface("plane-z", z=69.3876163265306) -s150 = mcdc.surface("plane-z", z=70.4080224489796) -s151 = mcdc.surface("plane-z", z=71.42842857142857) -s152 = mcdc.surface("plane-z", z=72.44883469387754) -s153 = mcdc.surface("plane-z", z=73.46924081632653) -s154 = mcdc.surface("plane-z", z=74.48964693877551) -s155 = mcdc.surface("plane-z", z=75.51005306122448) -s156 = mcdc.surface("plane-z", z=76.53045918367347) -s157 = mcdc.surface("plane-z", z=77.55086530612245) -s158 = mcdc.surface("plane-z", z=78.57127142857142) -s159 = mcdc.surface("plane-z", z=79.59167755102041) -s160 = mcdc.surface("plane-z", z=80.61208367346939) -s161 = mcdc.surface("plane-z", z=81.63248979591836) -s162 = mcdc.surface("plane-z", z=82.65289591836735) -s163 = mcdc.surface("plane-z", z=83.67330204081632) -s164 = mcdc.surface("plane-z", z=84.6937081632653) -s165 = mcdc.surface("plane-z", z=85.71411428571429) -s166 = mcdc.surface("plane-z", z=86.73452040816326) -s167 = mcdc.surface("plane-z", z=87.75492653061224) -s168 = mcdc.surface("plane-z", z=88.77533265306123) -s169 = mcdc.surface("plane-z", z=89.7957387755102) -s170 = mcdc.surface("plane-z", z=90.81614489795918) -s171 = mcdc.surface("plane-z", z=91.83655102040817) -s172 = mcdc.surface("plane-z", z=92.85695714285714) -s173 = mcdc.surface("plane-z", z=93.87736326530612) -s174 = mcdc.surface("plane-z", z=94.8977693877551) -s175 = mcdc.surface("plane-z", z=95.91817551020408) -s176 = mcdc.surface("plane-z", z=96.93858163265305) -s177 = mcdc.surface("plane-z", z=97.95898775510204) -s178 = mcdc.surface("plane-z", z=98.97939387755102) -s179 = mcdc.surface("plane-z", z=99.9998) -s180 = mcdc.surface("plane-z", z=101.02020612244897) -s181 = mcdc.surface("plane-z", z=102.04061224489796) -s182 = mcdc.surface("plane-z", z=103.06101836734693) -s183 = mcdc.surface("plane-z", z=104.08142448979591) -s184 = mcdc.surface("plane-z", z=105.1018306122449) -s185 = mcdc.surface("plane-z", z=106.12223673469387) -s186 = mcdc.surface("plane-z", z=107.14264285714285) -s187 = mcdc.surface("plane-z", z=108.16304897959184) -s188 = mcdc.surface("plane-z", z=109.18345510204081) -s189 = mcdc.surface("plane-z", z=110.20386122448978) -s190 = mcdc.surface("plane-z", z=111.22426734693877) -s191 = mcdc.surface("plane-z", z=112.24467346938775) -s192 = mcdc.surface("plane-z", z=113.26507959183672) -s193 = mcdc.surface("plane-z", z=114.28548571428571) -s194 = mcdc.surface("plane-z", z=115.30589183673469) -s195 = mcdc.surface("plane-z", z=116.32629795918366) -s196 = mcdc.surface("plane-z", z=117.34670408163265) -s197 = mcdc.surface("plane-z", z=118.36711020408163) -s198 = mcdc.surface("plane-z", z=119.3875163265306) -s199 = mcdc.surface("plane-z", z=120.40792244897959) -s200 = mcdc.surface("plane-z", z=121.42832857142857) -s201 = mcdc.surface("plane-z", z=122.44873469387754) -s202 = mcdc.surface("plane-z", z=123.46914081632653) -s203 = mcdc.surface("plane-z", z=124.4895469387755) -s204 = mcdc.surface("plane-z", z=125.50995306122448) -s205 = mcdc.surface("plane-z", z=126.53035918367347) -s206 = mcdc.surface("plane-z", z=127.55076530612244) -s207 = mcdc.surface("plane-z", z=128.57117142857143) -s208 = mcdc.surface("plane-z", z=129.5915775510204) -s209 = mcdc.surface("plane-z", z=130.61198367346938) -s210 = mcdc.surface("plane-z", z=131.63238979591836) -s211 = mcdc.surface("plane-z", z=132.65279591836733) -s212 = mcdc.surface("plane-z", z=133.6732020408163) -s213 = mcdc.surface("plane-z", z=134.6936081632653) -s214 = mcdc.surface("plane-z", z=135.71401428571428) -s215 = mcdc.surface("plane-z", z=136.73442040816326) -s216 = mcdc.surface("plane-z", z=137.75482653061223) -s217 = mcdc.surface("plane-z", z=138.7752326530612) -s218 = mcdc.surface("plane-z", z=139.79563877551018) -s219 = mcdc.surface("plane-z", z=140.8160448979592) -s220 = mcdc.surface("plane-z", z=141.83645102040816) -s221 = mcdc.surface("plane-z", z=142.85685714285714) -s222 = mcdc.surface("plane-z", z=143.8772632653061) -s223 = mcdc.surface("plane-z", z=144.8976693877551) -s224 = mcdc.surface("plane-z", z=145.91807551020406) -s225 = mcdc.surface("plane-z", z=146.93848163265307) -s226 = mcdc.surface("plane-z", z=147.95888775510204) -s227 = mcdc.surface("plane-z", z=148.97929387755102) -s228 = mcdc.surface("plane-z", z=149.9997) -s229 = mcdc.surface("plane-z", z=151.02010612244896) -s230 = mcdc.surface("plane-z", z=152.04051224489794) -s231 = mcdc.surface("plane-z", z=153.06091836734694) -s232 = mcdc.surface("plane-z", z=154.08132448979592) -s233 = mcdc.surface("plane-z", z=155.1017306122449) -s234 = mcdc.surface("plane-z", z=156.12213673469387) -s235 = mcdc.surface("plane-z", z=157.14254285714284) -s236 = mcdc.surface("plane-z", z=158.16294897959182) -s237 = mcdc.surface("plane-z", z=159.18335510204082) -s238 = mcdc.surface("plane-z", z=160.2037612244898) -s239 = mcdc.surface("plane-z", z=161.22416734693877) -s240 = mcdc.surface("plane-z", z=162.24457346938775) -s241 = mcdc.surface("plane-z", z=163.26497959183672) -s242 = mcdc.surface("plane-z", z=164.2853857142857) -s243 = mcdc.surface("plane-z", z=165.3057918367347) -s244 = mcdc.surface("plane-z", z=166.32619795918367) -s245 = mcdc.surface("plane-z", z=167.34660408163265) -s246 = mcdc.surface("plane-z", z=168.36701020408162) -s247 = mcdc.surface("plane-z", z=169.3874163265306) -s248 = mcdc.surface("plane-z", z=170.40782244897957) -s249 = mcdc.surface("plane-z", z=171.42822857142858) -s250 = mcdc.surface("plane-z", z=172.44863469387755) -s251 = mcdc.surface("plane-z", z=173.46904081632653) -s252 = mcdc.surface("plane-z", z=174.4894469387755) -s253 = mcdc.surface("plane-z", z=175.50985306122448) -s254 = mcdc.surface("plane-z", z=176.53025918367345) -s255 = mcdc.surface("plane-z", z=177.55066530612245) -s256 = mcdc.surface("plane-z", z=178.57107142857143) -s257 = mcdc.surface("plane-z", z=179.5914775510204) -s258 = mcdc.surface("plane-z", z=180.61188367346938) -s259 = mcdc.surface("plane-z", z=181.63228979591835) -s260 = mcdc.surface("plane-z", z=182.65269591836733) -s261 = mcdc.surface("plane-z", z=183.67310204081633) -s262 = mcdc.surface("plane-z", z=184.6935081632653) -s263 = mcdc.surface("plane-z", z=185.71391428571428) -s264 = mcdc.surface("plane-z", z=186.73432040816326) -s265 = mcdc.surface("plane-z", z=187.75472653061223) -s266 = mcdc.surface("plane-z", z=188.7751326530612) -s267 = mcdc.surface("plane-z", z=189.7955387755102) -s268 = mcdc.surface("plane-z", z=190.81594489795918) -s269 = mcdc.surface("plane-z", z=191.83635102040816) -s270 = mcdc.surface("plane-z", z=192.85675714285713) -s271 = mcdc.surface("plane-z", z=193.8771632653061) -s272 = mcdc.surface("plane-z", z=194.89756938775508) -s273 = mcdc.surface("plane-z", z=195.9179755102041) -s274 = mcdc.surface("plane-z", z=196.93838163265306) -s275 = mcdc.surface("plane-z", z=197.95878775510204) -s276 = mcdc.surface("plane-z", z=198.979193877551) -s277 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.12831415947782224 -) # Name: fuel ring 0 -s278 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.18146362457804044 -) # Name: fuel ring 1 -s279 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.22224664354608373 -) # Name: fuel ring 2 -s280 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.2566283189556445 -) # Name: fuel ring 3 -s281 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.28691918306815944 -) # Name: fuel ring 4 -s282 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.3143042174947705 -) # Name: fuel ring 5 -s283 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.33948735566659916 -) # Name: fuel ring 6 -s284 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.3629272491560809 -) # Name: fuel ring 7 -s285 = mcdc.surface( - "cylinder-z", center=[0.0, 0.0], radius=0.38494247843346674 -) # Name: fuel ring 8 -s286 = mcdc.surface( - "cylinder-z", - center=[-9.816879130434781, -6.155027391304348], - radius=0.506426304347826, -) -s287 = mcdc.surface( - "cylinder-z", - center=[-4.518880869565217, -6.155027391304348], - radius=0.506426304347826, -) -s288 = mcdc.surface( - "cylinder-z", - center=[0.9349408695652173, -6.155027391304348], - radius=0.506426304347826, -) -s289 = mcdc.surface( - "cylinder-z", - center=[6.155027391304348, -6.155027391304348], - radius=1.1686760869565216, -) -s290 = mcdc.surface( - "cylinder-z", - center=[6.155027391304348, -0.9349408695652173], - radius=0.506426304347826, -) -s291 = mcdc.surface( - "cylinder-z", - center=[6.155027391304348, 4.518880869565216], - radius=0.506426304347826, -) -s292 = mcdc.surface( - "cylinder-z", - center=[6.155027391304348, 9.816879130434781], - radius=0.506426304347826, -) -s293 = mcdc.surface( - "cylinder-z", - center=[2.5710873913043475, -2.5710873913043475], - radius=0.506426304347826, -) -s294 = mcdc.surface( - "cylinder-z", - center=[-2.0257052173913053, -1.246587826086957], - radius=0.506426304347826, -) -s295 = mcdc.surface( - "cylinder-z", - center=[1.2465878260869552, 2.0257052173913035], - radius=0.506426304347826, -) -s296 = mcdc.surface( - "cylinder-z", center=[-6.544586086956521, 0.0], radius=0.506426304347826 -) -s297 = mcdc.surface( - "cylinder-z", center=[0.0, 6.544586086956521], radius=0.506426304347826 -) -s298 = mcdc.surface( - "cylinder-z", - center=[-9.816879130434781, 8.49237956521739], - radius=0.506426304347826, -) -s299 = mcdc.surface( - "cylinder-z", - center=[6.155027391304348, -6.155027391304348], - radius=0.506426304347826, -) -s300 = mcdc.surface( - "cylinder-z", - center=[2.726910869565218, 1.402411304347826], - radius=0.506426304347826, -) -s301 = mcdc.surface( - "cylinder-z", - center=[-1.5582347826086949, -2.726910869565218], - radius=0.506426304347826, -) -s302 = mcdc.surface( - "cylinder-z", center=[6.232939130434779, 0.0], radius=0.506426304347826 -) -s303 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 5.2200865217391295], - radius=0.506426304347826, -) -s304 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 10.440173043478259], - radius=0.506426304347826, -) -s305 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -5.2200865217391295], - radius=0.506426304347826, -) -s306 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -10.440173043478259], - radius=0.506426304347826, -) -s307 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, 2.6100432608695647], - radius=0.506426304347826, -) -s308 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, 7.830129782608694], - radius=0.506426304347826, -) -s309 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, -2.6100432608695647], - radius=0.506426304347826, -) -s310 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, -7.830129782608694], - radius=0.506426304347826, -) -s311 = mcdc.surface( - "cylinder-z", - center=[-2.726910869565218, 5.921292173913042], - radius=0.506426304347826, -) -s312 = mcdc.surface( - "cylinder-z", - center=[-2.726910869565218, -5.921292173913042], - radius=0.506426304347826, -) -s313 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -11.063466956521738], - radius=0.506426304347826, -) -s314 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -5.84338043478261], - radius=0.506426304347826, -) -s315 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -0.6232939130434794], - radius=0.506426304347826, -) -s316 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 4.596792608695651], - radius=0.506426304347826, -) -s317 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 9.816879130434778], - radius=0.506426304347826, -) -s318 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, -8.453423695652173], - radius=0.506426304347826, -) -s319 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, -3.2333371739130428], - radius=0.506426304347826, -) -s320 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, 7.206835869565214], - radius=0.506426304347826, -) -s321 = mcdc.surface( - "cylinder-z", - center=[-0.15582347826087073, 1.6361465217391302], - radius=0.506426304347826, -) -s322 = mcdc.surface( - "cylinder-z", - center=[-3.5060282608695648, -7.089968260869565], - radius=0.506426304347826, -) -s323 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 11.063466956521738], - radius=0.506426304347826, -) -s324 = mcdc.surface( - "cylinder-z", center=[6.232939130434779, 5.84338043478261], radius=0.506426304347826 -) -s325 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, 0.6232939130434794], - radius=0.506426304347826, -) -s326 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -4.596792608695651], - radius=0.506426304347826, -) -s327 = mcdc.surface( - "cylinder-z", - center=[6.232939130434779, -9.816879130434778], - radius=0.506426304347826, -) -s328 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, 8.453423695652173], - radius=0.506426304347826, -) -s329 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, 3.2333371739130428], - radius=0.506426304347826, -) -s330 = mcdc.surface( - "cylinder-z", - center=[1.5582347826086949, -7.206835869565214], - radius=0.506426304347826, -) -s331 = mcdc.surface( - "cylinder-z", - center=[-0.15582347826087073, -1.6361465217391302], - radius=0.506426304347826, -) -s332 = mcdc.surface( - "cylinder-z", - center=[-3.5060282608695648, 7.089968260869565], - radius=0.506426304347826, -) -s333 = mcdc.surface( - "cylinder-z", - center=[4.674704347826085, -3.1164695652173915], - radius=0.506426304347826, -) - -# -------------------------------------------------------------------------------------- -# Cells - Level 0 -# -------------------------------------------------------------------------------------- - -c1 = mcdc.cell(fill=m10) # Name: water pin -c2 = mcdc.cell(-s5, fill=m10) # Name: GT empty (0) -c3 = mcdc.cell(+s5 & -s6, fill=m7) # Name: GT empty (1) -c4 = mcdc.cell(+s6, fill=m10) # Name: GT empty (last) -c5 = mcdc.cell(-s5, fill=m10) # Name: GT empty grid (bottom) (0) -c6 = mcdc.cell(+s5 & -s6, fill=m7) # Name: GT empty grid (bottom) (1) -c7 = mcdc.cell( - +s6 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: GT empty grid (bottom) (last) -c8 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m3 -) # Name: GT empty grid (bottom) (grid) -c9 = mcdc.cell(-s5, fill=m10) # Name: GT empty grid (intermediate) (0) -c10 = mcdc.cell(+s5 & -s6, fill=m7) # Name: GT empty grid (intermediate) (1) -c11 = mcdc.cell( - +s6 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: GT empty grid (intermediate) (last) -c12 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m7 -) # Name: GT empty grid (intermediate) (grid) -c16 = mcdc.cell(-s7, fill=m10) # Name: GT empty at dashpot (0) -c17 = mcdc.cell(+s7 & -s8, fill=m7) # Name: GT empty at dashpot (1) -c18 = mcdc.cell(+s8, fill=m10) # Name: GT empty at dashpot (last) -c19 = mcdc.cell(-s7, fill=m10) # Name: GT empty at dashpot grid (bottom) (0) -c20 = mcdc.cell(+s7 & -s8, fill=m7) # Name: GT empty at dashpot grid (bottom) (1) -c21 = mcdc.cell( - +s8 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: GT empty at dashpot grid (bottom) (last) -c22 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m3 -) # Name: GT empty at dashpot grid (bottom) (grid) -c585 = mcdc.cell(-s4, fill=m5) # Name: SS pin (0) -c586 = mcdc.cell(+s4, fill=m10) # Name: SS pin (last) -c587 = mcdc.cell(-s4, fill=m8) # Name: end plug (0) -c588 = mcdc.cell(+s4, fill=m10) # Name: end plug (last) -c589 = mcdc.cell(-s2, fill=m4) # Name: pin plenum (0) -c590 = mcdc.cell(+s2 & -s3, fill=m1) # Name: pin plenum (1) -c591 = mcdc.cell(+s3 & -s4, fill=m8) # Name: pin plenum (2) -c592 = mcdc.cell(+s4, fill=m10) # Name: pin plenum (last) -c593 = mcdc.cell(-s2, fill=m3) # Name: pin plenum grid (intermediate) (0) -c594 = mcdc.cell(+s2 & -s3, fill=m1) # Name: pin plenum grid (intermediate) (1) -c595 = mcdc.cell(+s3 & -s4, fill=m7) # Name: pin plenum grid (intermediate) (2) -c596 = mcdc.cell( - +s4 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: pin plenum grid (intermediate) (last) -c597 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m7 -) # Name: pin plenum grid (intermediate) (grid) -c598 = mcdc.cell(-s82 & -s277, fill=m38) -c599 = mcdc.cell(-s82 & +s277 & -s278, fill=m39) -c600 = mcdc.cell(-s82 & +s278 & -s279, fill=m40) -c601 = mcdc.cell(-s82 & +s279 & -s280, fill=m41) -c602 = mcdc.cell(-s82 & +s280 & -s281, fill=m42) -c603 = mcdc.cell(-s82 & +s281 & -s282, fill=m43) -c604 = mcdc.cell(-s82 & +s282 & -s283, fill=m44) -c605 = mcdc.cell(-s82 & +s283 & -s284, fill=m45) -c606 = mcdc.cell(-s82 & +s284 & -s285, fill=m46) -c607 = mcdc.cell(-s82 & +s285, fill=m47) -c608 = mcdc.cell(+s82 & -s83 & -s277, fill=m38) -c609 = mcdc.cell(+s82 & -s83 & +s277 & -s278, fill=m39) -c610 = mcdc.cell(+s82 & -s83 & +s278 & -s279, fill=m40) -c611 = mcdc.cell(+s82 & -s83 & +s279 & -s280, fill=m41) -c612 = mcdc.cell(+s82 & -s83 & +s280 & -s281, fill=m42) -c613 = mcdc.cell(+s82 & -s83 & +s281 & -s282, fill=m43) -c614 = mcdc.cell(+s82 & -s83 & +s282 & -s283, fill=m44) -c615 = mcdc.cell(+s82 & -s83 & +s283 & -s284, fill=m45) -c616 = mcdc.cell(+s82 & -s83 & +s284 & -s285, fill=m46) -c617 = mcdc.cell(+s82 & -s83 & +s285, fill=m47) -c618 = mcdc.cell(+s83 & -s84 & -s277, fill=m38) -c619 = mcdc.cell(+s83 & -s84 & +s277 & -s278, fill=m39) -c620 = mcdc.cell(+s83 & -s84 & +s278 & -s279, fill=m40) -c621 = mcdc.cell(+s83 & -s84 & +s279 & -s280, fill=m41) -c622 = mcdc.cell(+s83 & -s84 & +s280 & -s281, fill=m42) -c623 = mcdc.cell(+s83 & -s84 & +s281 & -s282, fill=m43) -c624 = mcdc.cell(+s83 & -s84 & +s282 & -s283, fill=m44) -c625 = mcdc.cell(+s83 & -s84 & +s283 & -s284, fill=m45) -c626 = mcdc.cell(+s83 & -s84 & +s284 & -s285, fill=m46) -c627 = mcdc.cell(+s83 & -s84 & +s285, fill=m47) -c628 = mcdc.cell(+s84 & -s85 & -s277, fill=m38) -c629 = mcdc.cell(+s84 & -s85 & +s277 & -s278, fill=m39) -c630 = mcdc.cell(+s84 & -s85 & +s278 & -s279, fill=m40) -c631 = mcdc.cell(+s84 & -s85 & +s279 & -s280, fill=m41) -c632 = mcdc.cell(+s84 & -s85 & +s280 & -s281, fill=m42) -c633 = mcdc.cell(+s84 & -s85 & +s281 & -s282, fill=m43) -c634 = mcdc.cell(+s84 & -s85 & +s282 & -s283, fill=m44) -c635 = mcdc.cell(+s84 & -s85 & +s283 & -s284, fill=m45) -c636 = mcdc.cell(+s84 & -s85 & +s284 & -s285, fill=m46) -c637 = mcdc.cell(+s84 & -s85 & +s285, fill=m47) -c638 = mcdc.cell(+s85 & -s86 & -s277, fill=m38) -c639 = mcdc.cell(+s85 & -s86 & +s277 & -s278, fill=m39) -c640 = mcdc.cell(+s85 & -s86 & +s278 & -s279, fill=m40) -c641 = mcdc.cell(+s85 & -s86 & +s279 & -s280, fill=m41) -c642 = mcdc.cell(+s85 & -s86 & +s280 & -s281, fill=m42) -c643 = mcdc.cell(+s85 & -s86 & +s281 & -s282, fill=m43) -c644 = mcdc.cell(+s85 & -s86 & +s282 & -s283, fill=m44) -c645 = mcdc.cell(+s85 & -s86 & +s283 & -s284, fill=m45) -c646 = mcdc.cell(+s85 & -s86 & +s284 & -s285, fill=m46) -c647 = mcdc.cell(+s85 & -s86 & +s285, fill=m47) -c648 = mcdc.cell(+s86 & -s87 & -s277, fill=m38) -c649 = mcdc.cell(+s86 & -s87 & +s277 & -s278, fill=m39) -c650 = mcdc.cell(+s86 & -s87 & +s278 & -s279, fill=m40) -c651 = mcdc.cell(+s86 & -s87 & +s279 & -s280, fill=m41) -c652 = mcdc.cell(+s86 & -s87 & +s280 & -s281, fill=m42) -c653 = mcdc.cell(+s86 & -s87 & +s281 & -s282, fill=m43) -c654 = mcdc.cell(+s86 & -s87 & +s282 & -s283, fill=m44) -c655 = mcdc.cell(+s86 & -s87 & +s283 & -s284, fill=m45) -c656 = mcdc.cell(+s86 & -s87 & +s284 & -s285, fill=m46) -c657 = mcdc.cell(+s86 & -s87 & +s285, fill=m47) -c658 = mcdc.cell(+s87 & -s88 & -s277, fill=m38) -c659 = mcdc.cell(+s87 & -s88 & +s277 & -s278, fill=m39) -c660 = mcdc.cell(+s87 & -s88 & +s278 & -s279, fill=m40) -c661 = mcdc.cell(+s87 & -s88 & +s279 & -s280, fill=m41) -c662 = mcdc.cell(+s87 & -s88 & +s280 & -s281, fill=m42) -c663 = mcdc.cell(+s87 & -s88 & +s281 & -s282, fill=m43) -c664 = mcdc.cell(+s87 & -s88 & +s282 & -s283, fill=m44) -c665 = mcdc.cell(+s87 & -s88 & +s283 & -s284, fill=m45) -c666 = mcdc.cell(+s87 & -s88 & +s284 & -s285, fill=m46) -c667 = mcdc.cell(+s87 & -s88 & +s285, fill=m47) -c668 = mcdc.cell(+s88 & -s89 & -s277, fill=m38) -c669 = mcdc.cell(+s88 & -s89 & +s277 & -s278, fill=m39) -c670 = mcdc.cell(+s88 & -s89 & +s278 & -s279, fill=m40) -c671 = mcdc.cell(+s88 & -s89 & +s279 & -s280, fill=m41) -c672 = mcdc.cell(+s88 & -s89 & +s280 & -s281, fill=m42) -c673 = mcdc.cell(+s88 & -s89 & +s281 & -s282, fill=m43) -c674 = mcdc.cell(+s88 & -s89 & +s282 & -s283, fill=m44) -c675 = mcdc.cell(+s88 & -s89 & +s283 & -s284, fill=m45) -c676 = mcdc.cell(+s88 & -s89 & +s284 & -s285, fill=m46) -c677 = mcdc.cell(+s88 & -s89 & +s285, fill=m47) -c678 = mcdc.cell(+s89 & -s90 & -s277, fill=m38) -c679 = mcdc.cell(+s89 & -s90 & +s277 & -s278, fill=m39) -c680 = mcdc.cell(+s89 & -s90 & +s278 & -s279, fill=m40) -c681 = mcdc.cell(+s89 & -s90 & +s279 & -s280, fill=m41) -c682 = mcdc.cell(+s89 & -s90 & +s280 & -s281, fill=m42) -c683 = mcdc.cell(+s89 & -s90 & +s281 & -s282, fill=m43) -c684 = mcdc.cell(+s89 & -s90 & +s282 & -s283, fill=m44) -c685 = mcdc.cell(+s89 & -s90 & +s283 & -s284, fill=m45) -c686 = mcdc.cell(+s89 & -s90 & +s284 & -s285, fill=m46) -c687 = mcdc.cell(+s89 & -s90 & +s285, fill=m47) -c688 = mcdc.cell(+s90 & -s91 & -s277, fill=m38) -c689 = mcdc.cell(+s90 & -s91 & +s277 & -s278, fill=m39) -c690 = mcdc.cell(+s90 & -s91 & +s278 & -s279, fill=m40) -c691 = mcdc.cell(+s90 & -s91 & +s279 & -s280, fill=m41) -c692 = mcdc.cell(+s90 & -s91 & +s280 & -s281, fill=m42) -c693 = mcdc.cell(+s90 & -s91 & +s281 & -s282, fill=m43) -c694 = mcdc.cell(+s90 & -s91 & +s282 & -s283, fill=m44) -c695 = mcdc.cell(+s90 & -s91 & +s283 & -s284, fill=m45) -c696 = mcdc.cell(+s90 & -s91 & +s284 & -s285, fill=m46) -c697 = mcdc.cell(+s90 & -s91 & +s285, fill=m47) -c698 = mcdc.cell(+s91 & -s92 & -s277, fill=m38) -c699 = mcdc.cell(+s91 & -s92 & +s277 & -s278, fill=m39) -c700 = mcdc.cell(+s91 & -s92 & +s278 & -s279, fill=m40) -c701 = mcdc.cell(+s91 & -s92 & +s279 & -s280, fill=m41) -c702 = mcdc.cell(+s91 & -s92 & +s280 & -s281, fill=m42) -c703 = mcdc.cell(+s91 & -s92 & +s281 & -s282, fill=m43) -c704 = mcdc.cell(+s91 & -s92 & +s282 & -s283, fill=m44) -c705 = mcdc.cell(+s91 & -s92 & +s283 & -s284, fill=m45) -c706 = mcdc.cell(+s91 & -s92 & +s284 & -s285, fill=m46) -c707 = mcdc.cell(+s91 & -s92 & +s285, fill=m47) -c708 = mcdc.cell(+s92 & -s93 & -s277, fill=m38) -c709 = mcdc.cell(+s92 & -s93 & +s277 & -s278, fill=m39) -c710 = mcdc.cell(+s92 & -s93 & +s278 & -s279, fill=m40) -c711 = mcdc.cell(+s92 & -s93 & +s279 & -s280, fill=m41) -c712 = mcdc.cell(+s92 & -s93 & +s280 & -s281, fill=m42) -c713 = mcdc.cell(+s92 & -s93 & +s281 & -s282, fill=m43) -c714 = mcdc.cell(+s92 & -s93 & +s282 & -s283, fill=m44) -c715 = mcdc.cell(+s92 & -s93 & +s283 & -s284, fill=m45) -c716 = mcdc.cell(+s92 & -s93 & +s284 & -s285, fill=m46) -c717 = mcdc.cell(+s92 & -s93 & +s285, fill=m47) -c718 = mcdc.cell(+s93 & -s94 & -s277, fill=m38) -c719 = mcdc.cell(+s93 & -s94 & +s277 & -s278, fill=m39) -c720 = mcdc.cell(+s93 & -s94 & +s278 & -s279, fill=m40) -c721 = mcdc.cell(+s93 & -s94 & +s279 & -s280, fill=m41) -c722 = mcdc.cell(+s93 & -s94 & +s280 & -s281, fill=m42) -c723 = mcdc.cell(+s93 & -s94 & +s281 & -s282, fill=m43) -c724 = mcdc.cell(+s93 & -s94 & +s282 & -s283, fill=m44) -c725 = mcdc.cell(+s93 & -s94 & +s283 & -s284, fill=m45) -c726 = mcdc.cell(+s93 & -s94 & +s284 & -s285, fill=m46) -c727 = mcdc.cell(+s93 & -s94 & +s285, fill=m47) -c728 = mcdc.cell(+s94 & -s95 & -s277, fill=m38) -c729 = mcdc.cell(+s94 & -s95 & +s277 & -s278, fill=m39) -c730 = mcdc.cell(+s94 & -s95 & +s278 & -s279, fill=m40) -c731 = mcdc.cell(+s94 & -s95 & +s279 & -s280, fill=m41) -c732 = mcdc.cell(+s94 & -s95 & +s280 & -s281, fill=m42) -c733 = mcdc.cell(+s94 & -s95 & +s281 & -s282, fill=m43) -c734 = mcdc.cell(+s94 & -s95 & +s282 & -s283, fill=m44) -c735 = mcdc.cell(+s94 & -s95 & +s283 & -s284, fill=m45) -c736 = mcdc.cell(+s94 & -s95 & +s284 & -s285, fill=m46) -c737 = mcdc.cell(+s94 & -s95 & +s285, fill=m47) -c738 = mcdc.cell(+s95 & -s96 & -s277, fill=m38) -c739 = mcdc.cell(+s95 & -s96 & +s277 & -s278, fill=m39) -c740 = mcdc.cell(+s95 & -s96 & +s278 & -s279, fill=m40) -c741 = mcdc.cell(+s95 & -s96 & +s279 & -s280, fill=m41) -c742 = mcdc.cell(+s95 & -s96 & +s280 & -s281, fill=m42) -c743 = mcdc.cell(+s95 & -s96 & +s281 & -s282, fill=m43) -c744 = mcdc.cell(+s95 & -s96 & +s282 & -s283, fill=m44) -c745 = mcdc.cell(+s95 & -s96 & +s283 & -s284, fill=m45) -c746 = mcdc.cell(+s95 & -s96 & +s284 & -s285, fill=m46) -c747 = mcdc.cell(+s95 & -s96 & +s285, fill=m47) -c748 = mcdc.cell(+s96 & -s97 & -s277, fill=m38) -c749 = mcdc.cell(+s96 & -s97 & +s277 & -s278, fill=m39) -c750 = mcdc.cell(+s96 & -s97 & +s278 & -s279, fill=m40) -c751 = mcdc.cell(+s96 & -s97 & +s279 & -s280, fill=m41) -c752 = mcdc.cell(+s96 & -s97 & +s280 & -s281, fill=m42) -c753 = mcdc.cell(+s96 & -s97 & +s281 & -s282, fill=m43) -c754 = mcdc.cell(+s96 & -s97 & +s282 & -s283, fill=m44) -c755 = mcdc.cell(+s96 & -s97 & +s283 & -s284, fill=m45) -c756 = mcdc.cell(+s96 & -s97 & +s284 & -s285, fill=m46) -c757 = mcdc.cell(+s96 & -s97 & +s285, fill=m47) -c758 = mcdc.cell(+s97 & -s98 & -s277, fill=m38) -c759 = mcdc.cell(+s97 & -s98 & +s277 & -s278, fill=m39) -c760 = mcdc.cell(+s97 & -s98 & +s278 & -s279, fill=m40) -c761 = mcdc.cell(+s97 & -s98 & +s279 & -s280, fill=m41) -c762 = mcdc.cell(+s97 & -s98 & +s280 & -s281, fill=m42) -c763 = mcdc.cell(+s97 & -s98 & +s281 & -s282, fill=m43) -c764 = mcdc.cell(+s97 & -s98 & +s282 & -s283, fill=m44) -c765 = mcdc.cell(+s97 & -s98 & +s283 & -s284, fill=m45) -c766 = mcdc.cell(+s97 & -s98 & +s284 & -s285, fill=m46) -c767 = mcdc.cell(+s97 & -s98 & +s285, fill=m47) -c768 = mcdc.cell(+s98 & -s99 & -s277, fill=m38) -c769 = mcdc.cell(+s98 & -s99 & +s277 & -s278, fill=m39) -c770 = mcdc.cell(+s98 & -s99 & +s278 & -s279, fill=m40) -c771 = mcdc.cell(+s98 & -s99 & +s279 & -s280, fill=m41) -c772 = mcdc.cell(+s98 & -s99 & +s280 & -s281, fill=m42) -c773 = mcdc.cell(+s98 & -s99 & +s281 & -s282, fill=m43) -c774 = mcdc.cell(+s98 & -s99 & +s282 & -s283, fill=m44) -c775 = mcdc.cell(+s98 & -s99 & +s283 & -s284, fill=m45) -c776 = mcdc.cell(+s98 & -s99 & +s284 & -s285, fill=m46) -c777 = mcdc.cell(+s98 & -s99 & +s285, fill=m47) -c778 = mcdc.cell(+s99 & -s100 & -s277, fill=m38) -c779 = mcdc.cell(+s99 & -s100 & +s277 & -s278, fill=m39) -c780 = mcdc.cell(+s99 & -s100 & +s278 & -s279, fill=m40) -c781 = mcdc.cell(+s99 & -s100 & +s279 & -s280, fill=m41) -c782 = mcdc.cell(+s99 & -s100 & +s280 & -s281, fill=m42) -c783 = mcdc.cell(+s99 & -s100 & +s281 & -s282, fill=m43) -c784 = mcdc.cell(+s99 & -s100 & +s282 & -s283, fill=m44) -c785 = mcdc.cell(+s99 & -s100 & +s283 & -s284, fill=m45) -c786 = mcdc.cell(+s99 & -s100 & +s284 & -s285, fill=m46) -c787 = mcdc.cell(+s99 & -s100 & +s285, fill=m47) -c788 = mcdc.cell(+s100 & -s101 & -s277, fill=m38) -c789 = mcdc.cell(+s100 & -s101 & +s277 & -s278, fill=m39) -c790 = mcdc.cell(+s100 & -s101 & +s278 & -s279, fill=m40) -c791 = mcdc.cell(+s100 & -s101 & +s279 & -s280, fill=m41) -c792 = mcdc.cell(+s100 & -s101 & +s280 & -s281, fill=m42) -c793 = mcdc.cell(+s100 & -s101 & +s281 & -s282, fill=m43) -c794 = mcdc.cell(+s100 & -s101 & +s282 & -s283, fill=m44) -c795 = mcdc.cell(+s100 & -s101 & +s283 & -s284, fill=m45) -c796 = mcdc.cell(+s100 & -s101 & +s284 & -s285, fill=m46) -c797 = mcdc.cell(+s100 & -s101 & +s285, fill=m47) -c798 = mcdc.cell(+s101 & -s102 & -s277, fill=m38) -c799 = mcdc.cell(+s101 & -s102 & +s277 & -s278, fill=m39) -c800 = mcdc.cell(+s101 & -s102 & +s278 & -s279, fill=m40) -c801 = mcdc.cell(+s101 & -s102 & +s279 & -s280, fill=m41) -c802 = mcdc.cell(+s101 & -s102 & +s280 & -s281, fill=m42) -c803 = mcdc.cell(+s101 & -s102 & +s281 & -s282, fill=m43) -c804 = mcdc.cell(+s101 & -s102 & +s282 & -s283, fill=m44) -c805 = mcdc.cell(+s101 & -s102 & +s283 & -s284, fill=m45) -c806 = mcdc.cell(+s101 & -s102 & +s284 & -s285, fill=m46) -c807 = mcdc.cell(+s101 & -s102 & +s285, fill=m47) -c808 = mcdc.cell(+s102 & -s103 & -s277, fill=m38) -c809 = mcdc.cell(+s102 & -s103 & +s277 & -s278, fill=m39) -c810 = mcdc.cell(+s102 & -s103 & +s278 & -s279, fill=m40) -c811 = mcdc.cell(+s102 & -s103 & +s279 & -s280, fill=m41) -c812 = mcdc.cell(+s102 & -s103 & +s280 & -s281, fill=m42) -c813 = mcdc.cell(+s102 & -s103 & +s281 & -s282, fill=m43) -c814 = mcdc.cell(+s102 & -s103 & +s282 & -s283, fill=m44) -c815 = mcdc.cell(+s102 & -s103 & +s283 & -s284, fill=m45) -c816 = mcdc.cell(+s102 & -s103 & +s284 & -s285, fill=m46) -c817 = mcdc.cell(+s102 & -s103 & +s285, fill=m47) -c818 = mcdc.cell(+s103 & -s104 & -s277, fill=m38) -c819 = mcdc.cell(+s103 & -s104 & +s277 & -s278, fill=m39) -c820 = mcdc.cell(+s103 & -s104 & +s278 & -s279, fill=m40) -c821 = mcdc.cell(+s103 & -s104 & +s279 & -s280, fill=m41) -c822 = mcdc.cell(+s103 & -s104 & +s280 & -s281, fill=m42) -c823 = mcdc.cell(+s103 & -s104 & +s281 & -s282, fill=m43) -c824 = mcdc.cell(+s103 & -s104 & +s282 & -s283, fill=m44) -c825 = mcdc.cell(+s103 & -s104 & +s283 & -s284, fill=m45) -c826 = mcdc.cell(+s103 & -s104 & +s284 & -s285, fill=m46) -c827 = mcdc.cell(+s103 & -s104 & +s285, fill=m47) -c828 = mcdc.cell(+s104 & -s105 & -s277, fill=m38) -c829 = mcdc.cell(+s104 & -s105 & +s277 & -s278, fill=m39) -c830 = mcdc.cell(+s104 & -s105 & +s278 & -s279, fill=m40) -c831 = mcdc.cell(+s104 & -s105 & +s279 & -s280, fill=m41) -c832 = mcdc.cell(+s104 & -s105 & +s280 & -s281, fill=m42) -c833 = mcdc.cell(+s104 & -s105 & +s281 & -s282, fill=m43) -c834 = mcdc.cell(+s104 & -s105 & +s282 & -s283, fill=m44) -c835 = mcdc.cell(+s104 & -s105 & +s283 & -s284, fill=m45) -c836 = mcdc.cell(+s104 & -s105 & +s284 & -s285, fill=m46) -c837 = mcdc.cell(+s104 & -s105 & +s285, fill=m47) -c838 = mcdc.cell(+s105 & -s106 & -s277, fill=m38) -c839 = mcdc.cell(+s105 & -s106 & +s277 & -s278, fill=m39) -c840 = mcdc.cell(+s105 & -s106 & +s278 & -s279, fill=m40) -c841 = mcdc.cell(+s105 & -s106 & +s279 & -s280, fill=m41) -c842 = mcdc.cell(+s105 & -s106 & +s280 & -s281, fill=m42) -c843 = mcdc.cell(+s105 & -s106 & +s281 & -s282, fill=m43) -c844 = mcdc.cell(+s105 & -s106 & +s282 & -s283, fill=m44) -c845 = mcdc.cell(+s105 & -s106 & +s283 & -s284, fill=m45) -c846 = mcdc.cell(+s105 & -s106 & +s284 & -s285, fill=m46) -c847 = mcdc.cell(+s105 & -s106 & +s285, fill=m47) -c848 = mcdc.cell(+s106 & -s107 & -s277, fill=m38) -c849 = mcdc.cell(+s106 & -s107 & +s277 & -s278, fill=m39) -c850 = mcdc.cell(+s106 & -s107 & +s278 & -s279, fill=m40) -c851 = mcdc.cell(+s106 & -s107 & +s279 & -s280, fill=m41) -c852 = mcdc.cell(+s106 & -s107 & +s280 & -s281, fill=m42) -c853 = mcdc.cell(+s106 & -s107 & +s281 & -s282, fill=m43) -c854 = mcdc.cell(+s106 & -s107 & +s282 & -s283, fill=m44) -c855 = mcdc.cell(+s106 & -s107 & +s283 & -s284, fill=m45) -c856 = mcdc.cell(+s106 & -s107 & +s284 & -s285, fill=m46) -c857 = mcdc.cell(+s106 & -s107 & +s285, fill=m47) -c858 = mcdc.cell(+s107 & -s108 & -s277, fill=m38) -c859 = mcdc.cell(+s107 & -s108 & +s277 & -s278, fill=m39) -c860 = mcdc.cell(+s107 & -s108 & +s278 & -s279, fill=m40) -c861 = mcdc.cell(+s107 & -s108 & +s279 & -s280, fill=m41) -c862 = mcdc.cell(+s107 & -s108 & +s280 & -s281, fill=m42) -c863 = mcdc.cell(+s107 & -s108 & +s281 & -s282, fill=m43) -c864 = mcdc.cell(+s107 & -s108 & +s282 & -s283, fill=m44) -c865 = mcdc.cell(+s107 & -s108 & +s283 & -s284, fill=m45) -c866 = mcdc.cell(+s107 & -s108 & +s284 & -s285, fill=m46) -c867 = mcdc.cell(+s107 & -s108 & +s285, fill=m47) -c868 = mcdc.cell(+s108 & -s109 & -s277, fill=m38) -c869 = mcdc.cell(+s108 & -s109 & +s277 & -s278, fill=m39) -c870 = mcdc.cell(+s108 & -s109 & +s278 & -s279, fill=m40) -c871 = mcdc.cell(+s108 & -s109 & +s279 & -s280, fill=m41) -c872 = mcdc.cell(+s108 & -s109 & +s280 & -s281, fill=m42) -c873 = mcdc.cell(+s108 & -s109 & +s281 & -s282, fill=m43) -c874 = mcdc.cell(+s108 & -s109 & +s282 & -s283, fill=m44) -c875 = mcdc.cell(+s108 & -s109 & +s283 & -s284, fill=m45) -c876 = mcdc.cell(+s108 & -s109 & +s284 & -s285, fill=m46) -c877 = mcdc.cell(+s108 & -s109 & +s285, fill=m47) -c878 = mcdc.cell(+s109 & -s110 & -s277, fill=m38) -c879 = mcdc.cell(+s109 & -s110 & +s277 & -s278, fill=m39) -c880 = mcdc.cell(+s109 & -s110 & +s278 & -s279, fill=m40) -c881 = mcdc.cell(+s109 & -s110 & +s279 & -s280, fill=m41) -c882 = mcdc.cell(+s109 & -s110 & +s280 & -s281, fill=m42) -c883 = mcdc.cell(+s109 & -s110 & +s281 & -s282, fill=m43) -c884 = mcdc.cell(+s109 & -s110 & +s282 & -s283, fill=m44) -c885 = mcdc.cell(+s109 & -s110 & +s283 & -s284, fill=m45) -c886 = mcdc.cell(+s109 & -s110 & +s284 & -s285, fill=m46) -c887 = mcdc.cell(+s109 & -s110 & +s285, fill=m47) -c888 = mcdc.cell(+s110 & -s111 & -s277, fill=m38) -c889 = mcdc.cell(+s110 & -s111 & +s277 & -s278, fill=m39) -c890 = mcdc.cell(+s110 & -s111 & +s278 & -s279, fill=m40) -c891 = mcdc.cell(+s110 & -s111 & +s279 & -s280, fill=m41) -c892 = mcdc.cell(+s110 & -s111 & +s280 & -s281, fill=m42) -c893 = mcdc.cell(+s110 & -s111 & +s281 & -s282, fill=m43) -c894 = mcdc.cell(+s110 & -s111 & +s282 & -s283, fill=m44) -c895 = mcdc.cell(+s110 & -s111 & +s283 & -s284, fill=m45) -c896 = mcdc.cell(+s110 & -s111 & +s284 & -s285, fill=m46) -c897 = mcdc.cell(+s110 & -s111 & +s285, fill=m47) -c898 = mcdc.cell(+s111 & -s112 & -s277, fill=m38) -c899 = mcdc.cell(+s111 & -s112 & +s277 & -s278, fill=m39) -c900 = mcdc.cell(+s111 & -s112 & +s278 & -s279, fill=m40) -c901 = mcdc.cell(+s111 & -s112 & +s279 & -s280, fill=m41) -c902 = mcdc.cell(+s111 & -s112 & +s280 & -s281, fill=m42) -c903 = mcdc.cell(+s111 & -s112 & +s281 & -s282, fill=m43) -c904 = mcdc.cell(+s111 & -s112 & +s282 & -s283, fill=m44) -c905 = mcdc.cell(+s111 & -s112 & +s283 & -s284, fill=m45) -c906 = mcdc.cell(+s111 & -s112 & +s284 & -s285, fill=m46) -c907 = mcdc.cell(+s111 & -s112 & +s285, fill=m47) -c908 = mcdc.cell(+s112 & -s113 & -s277, fill=m38) -c909 = mcdc.cell(+s112 & -s113 & +s277 & -s278, fill=m39) -c910 = mcdc.cell(+s112 & -s113 & +s278 & -s279, fill=m40) -c911 = mcdc.cell(+s112 & -s113 & +s279 & -s280, fill=m41) -c912 = mcdc.cell(+s112 & -s113 & +s280 & -s281, fill=m42) -c913 = mcdc.cell(+s112 & -s113 & +s281 & -s282, fill=m43) -c914 = mcdc.cell(+s112 & -s113 & +s282 & -s283, fill=m44) -c915 = mcdc.cell(+s112 & -s113 & +s283 & -s284, fill=m45) -c916 = mcdc.cell(+s112 & -s113 & +s284 & -s285, fill=m46) -c917 = mcdc.cell(+s112 & -s113 & +s285, fill=m47) -c918 = mcdc.cell(+s113 & -s114 & -s277, fill=m38) -c919 = mcdc.cell(+s113 & -s114 & +s277 & -s278, fill=m39) -c920 = mcdc.cell(+s113 & -s114 & +s278 & -s279, fill=m40) -c921 = mcdc.cell(+s113 & -s114 & +s279 & -s280, fill=m41) -c922 = mcdc.cell(+s113 & -s114 & +s280 & -s281, fill=m42) -c923 = mcdc.cell(+s113 & -s114 & +s281 & -s282, fill=m43) -c924 = mcdc.cell(+s113 & -s114 & +s282 & -s283, fill=m44) -c925 = mcdc.cell(+s113 & -s114 & +s283 & -s284, fill=m45) -c926 = mcdc.cell(+s113 & -s114 & +s284 & -s285, fill=m46) -c927 = mcdc.cell(+s113 & -s114 & +s285, fill=m47) -c928 = mcdc.cell(+s114 & -s115 & -s277, fill=m38) -c929 = mcdc.cell(+s114 & -s115 & +s277 & -s278, fill=m39) -c930 = mcdc.cell(+s114 & -s115 & +s278 & -s279, fill=m40) -c931 = mcdc.cell(+s114 & -s115 & +s279 & -s280, fill=m41) -c932 = mcdc.cell(+s114 & -s115 & +s280 & -s281, fill=m42) -c933 = mcdc.cell(+s114 & -s115 & +s281 & -s282, fill=m43) -c934 = mcdc.cell(+s114 & -s115 & +s282 & -s283, fill=m44) -c935 = mcdc.cell(+s114 & -s115 & +s283 & -s284, fill=m45) -c936 = mcdc.cell(+s114 & -s115 & +s284 & -s285, fill=m46) -c937 = mcdc.cell(+s114 & -s115 & +s285, fill=m47) -c938 = mcdc.cell(+s115 & -s116 & -s277, fill=m38) -c939 = mcdc.cell(+s115 & -s116 & +s277 & -s278, fill=m39) -c940 = mcdc.cell(+s115 & -s116 & +s278 & -s279, fill=m40) -c941 = mcdc.cell(+s115 & -s116 & +s279 & -s280, fill=m41) -c942 = mcdc.cell(+s115 & -s116 & +s280 & -s281, fill=m42) -c943 = mcdc.cell(+s115 & -s116 & +s281 & -s282, fill=m43) -c944 = mcdc.cell(+s115 & -s116 & +s282 & -s283, fill=m44) -c945 = mcdc.cell(+s115 & -s116 & +s283 & -s284, fill=m45) -c946 = mcdc.cell(+s115 & -s116 & +s284 & -s285, fill=m46) -c947 = mcdc.cell(+s115 & -s116 & +s285, fill=m47) -c948 = mcdc.cell(+s116 & -s117 & -s277, fill=m38) -c949 = mcdc.cell(+s116 & -s117 & +s277 & -s278, fill=m39) -c950 = mcdc.cell(+s116 & -s117 & +s278 & -s279, fill=m40) -c951 = mcdc.cell(+s116 & -s117 & +s279 & -s280, fill=m41) -c952 = mcdc.cell(+s116 & -s117 & +s280 & -s281, fill=m42) -c953 = mcdc.cell(+s116 & -s117 & +s281 & -s282, fill=m43) -c954 = mcdc.cell(+s116 & -s117 & +s282 & -s283, fill=m44) -c955 = mcdc.cell(+s116 & -s117 & +s283 & -s284, fill=m45) -c956 = mcdc.cell(+s116 & -s117 & +s284 & -s285, fill=m46) -c957 = mcdc.cell(+s116 & -s117 & +s285, fill=m47) -c958 = mcdc.cell(+s117 & -s118 & -s277, fill=m38) -c959 = mcdc.cell(+s117 & -s118 & +s277 & -s278, fill=m39) -c960 = mcdc.cell(+s117 & -s118 & +s278 & -s279, fill=m40) -c961 = mcdc.cell(+s117 & -s118 & +s279 & -s280, fill=m41) -c962 = mcdc.cell(+s117 & -s118 & +s280 & -s281, fill=m42) -c963 = mcdc.cell(+s117 & -s118 & +s281 & -s282, fill=m43) -c964 = mcdc.cell(+s117 & -s118 & +s282 & -s283, fill=m44) -c965 = mcdc.cell(+s117 & -s118 & +s283 & -s284, fill=m45) -c966 = mcdc.cell(+s117 & -s118 & +s284 & -s285, fill=m46) -c967 = mcdc.cell(+s117 & -s118 & +s285, fill=m47) -c968 = mcdc.cell(+s118 & -s119 & -s277, fill=m38) -c969 = mcdc.cell(+s118 & -s119 & +s277 & -s278, fill=m39) -c970 = mcdc.cell(+s118 & -s119 & +s278 & -s279, fill=m40) -c971 = mcdc.cell(+s118 & -s119 & +s279 & -s280, fill=m41) -c972 = mcdc.cell(+s118 & -s119 & +s280 & -s281, fill=m42) -c973 = mcdc.cell(+s118 & -s119 & +s281 & -s282, fill=m43) -c974 = mcdc.cell(+s118 & -s119 & +s282 & -s283, fill=m44) -c975 = mcdc.cell(+s118 & -s119 & +s283 & -s284, fill=m45) -c976 = mcdc.cell(+s118 & -s119 & +s284 & -s285, fill=m46) -c977 = mcdc.cell(+s118 & -s119 & +s285, fill=m47) -c978 = mcdc.cell(+s119 & -s120 & -s277, fill=m38) -c979 = mcdc.cell(+s119 & -s120 & +s277 & -s278, fill=m39) -c980 = mcdc.cell(+s119 & -s120 & +s278 & -s279, fill=m40) -c981 = mcdc.cell(+s119 & -s120 & +s279 & -s280, fill=m41) -c982 = mcdc.cell(+s119 & -s120 & +s280 & -s281, fill=m42) -c983 = mcdc.cell(+s119 & -s120 & +s281 & -s282, fill=m43) -c984 = mcdc.cell(+s119 & -s120 & +s282 & -s283, fill=m44) -c985 = mcdc.cell(+s119 & -s120 & +s283 & -s284, fill=m45) -c986 = mcdc.cell(+s119 & -s120 & +s284 & -s285, fill=m46) -c987 = mcdc.cell(+s119 & -s120 & +s285, fill=m47) -c988 = mcdc.cell(+s120 & -s121 & -s277, fill=m38) -c989 = mcdc.cell(+s120 & -s121 & +s277 & -s278, fill=m39) -c990 = mcdc.cell(+s120 & -s121 & +s278 & -s279, fill=m40) -c991 = mcdc.cell(+s120 & -s121 & +s279 & -s280, fill=m41) -c992 = mcdc.cell(+s120 & -s121 & +s280 & -s281, fill=m42) -c993 = mcdc.cell(+s120 & -s121 & +s281 & -s282, fill=m43) -c994 = mcdc.cell(+s120 & -s121 & +s282 & -s283, fill=m44) -c995 = mcdc.cell(+s120 & -s121 & +s283 & -s284, fill=m45) -c996 = mcdc.cell(+s120 & -s121 & +s284 & -s285, fill=m46) -c997 = mcdc.cell(+s120 & -s121 & +s285, fill=m47) -c998 = mcdc.cell(+s121 & -s122 & -s277, fill=m38) -c999 = mcdc.cell(+s121 & -s122 & +s277 & -s278, fill=m39) -c1000 = mcdc.cell(+s121 & -s122 & +s278 & -s279, fill=m40) -c1001 = mcdc.cell(+s121 & -s122 & +s279 & -s280, fill=m41) -c1002 = mcdc.cell(+s121 & -s122 & +s280 & -s281, fill=m42) -c1003 = mcdc.cell(+s121 & -s122 & +s281 & -s282, fill=m43) -c1004 = mcdc.cell(+s121 & -s122 & +s282 & -s283, fill=m44) -c1005 = mcdc.cell(+s121 & -s122 & +s283 & -s284, fill=m45) -c1006 = mcdc.cell(+s121 & -s122 & +s284 & -s285, fill=m46) -c1007 = mcdc.cell(+s121 & -s122 & +s285, fill=m47) -c1008 = mcdc.cell(+s122 & -s123 & -s277, fill=m38) -c1009 = mcdc.cell(+s122 & -s123 & +s277 & -s278, fill=m39) -c1010 = mcdc.cell(+s122 & -s123 & +s278 & -s279, fill=m40) -c1011 = mcdc.cell(+s122 & -s123 & +s279 & -s280, fill=m41) -c1012 = mcdc.cell(+s122 & -s123 & +s280 & -s281, fill=m42) -c1013 = mcdc.cell(+s122 & -s123 & +s281 & -s282, fill=m43) -c1014 = mcdc.cell(+s122 & -s123 & +s282 & -s283, fill=m44) -c1015 = mcdc.cell(+s122 & -s123 & +s283 & -s284, fill=m45) -c1016 = mcdc.cell(+s122 & -s123 & +s284 & -s285, fill=m46) -c1017 = mcdc.cell(+s122 & -s123 & +s285, fill=m47) -c1018 = mcdc.cell(+s123 & -s124 & -s277, fill=m38) -c1019 = mcdc.cell(+s123 & -s124 & +s277 & -s278, fill=m39) -c1020 = mcdc.cell(+s123 & -s124 & +s278 & -s279, fill=m40) -c1021 = mcdc.cell(+s123 & -s124 & +s279 & -s280, fill=m41) -c1022 = mcdc.cell(+s123 & -s124 & +s280 & -s281, fill=m42) -c1023 = mcdc.cell(+s123 & -s124 & +s281 & -s282, fill=m43) -c1024 = mcdc.cell(+s123 & -s124 & +s282 & -s283, fill=m44) -c1025 = mcdc.cell(+s123 & -s124 & +s283 & -s284, fill=m45) -c1026 = mcdc.cell(+s123 & -s124 & +s284 & -s285, fill=m46) -c1027 = mcdc.cell(+s123 & -s124 & +s285, fill=m47) -c1028 = mcdc.cell(+s124 & -s125 & -s277, fill=m38) -c1029 = mcdc.cell(+s124 & -s125 & +s277 & -s278, fill=m39) -c1030 = mcdc.cell(+s124 & -s125 & +s278 & -s279, fill=m40) -c1031 = mcdc.cell(+s124 & -s125 & +s279 & -s280, fill=m41) -c1032 = mcdc.cell(+s124 & -s125 & +s280 & -s281, fill=m42) -c1033 = mcdc.cell(+s124 & -s125 & +s281 & -s282, fill=m43) -c1034 = mcdc.cell(+s124 & -s125 & +s282 & -s283, fill=m44) -c1035 = mcdc.cell(+s124 & -s125 & +s283 & -s284, fill=m45) -c1036 = mcdc.cell(+s124 & -s125 & +s284 & -s285, fill=m46) -c1037 = mcdc.cell(+s124 & -s125 & +s285, fill=m47) -c1038 = mcdc.cell(+s125 & -s126 & -s277, fill=m38) -c1039 = mcdc.cell(+s125 & -s126 & +s277 & -s278, fill=m39) -c1040 = mcdc.cell(+s125 & -s126 & +s278 & -s279, fill=m40) -c1041 = mcdc.cell(+s125 & -s126 & +s279 & -s280, fill=m41) -c1042 = mcdc.cell(+s125 & -s126 & +s280 & -s281, fill=m42) -c1043 = mcdc.cell(+s125 & -s126 & +s281 & -s282, fill=m43) -c1044 = mcdc.cell(+s125 & -s126 & +s282 & -s283, fill=m44) -c1045 = mcdc.cell(+s125 & -s126 & +s283 & -s284, fill=m45) -c1046 = mcdc.cell(+s125 & -s126 & +s284 & -s285, fill=m46) -c1047 = mcdc.cell(+s125 & -s126 & +s285, fill=m47) -c1048 = mcdc.cell(+s126 & -s127 & -s277, fill=m38) -c1049 = mcdc.cell(+s126 & -s127 & +s277 & -s278, fill=m39) -c1050 = mcdc.cell(+s126 & -s127 & +s278 & -s279, fill=m40) -c1051 = mcdc.cell(+s126 & -s127 & +s279 & -s280, fill=m41) -c1052 = mcdc.cell(+s126 & -s127 & +s280 & -s281, fill=m42) -c1053 = mcdc.cell(+s126 & -s127 & +s281 & -s282, fill=m43) -c1054 = mcdc.cell(+s126 & -s127 & +s282 & -s283, fill=m44) -c1055 = mcdc.cell(+s126 & -s127 & +s283 & -s284, fill=m45) -c1056 = mcdc.cell(+s126 & -s127 & +s284 & -s285, fill=m46) -c1057 = mcdc.cell(+s126 & -s127 & +s285, fill=m47) -c1058 = mcdc.cell(+s127 & -s128 & -s277, fill=m38) -c1059 = mcdc.cell(+s127 & -s128 & +s277 & -s278, fill=m39) -c1060 = mcdc.cell(+s127 & -s128 & +s278 & -s279, fill=m40) -c1061 = mcdc.cell(+s127 & -s128 & +s279 & -s280, fill=m41) -c1062 = mcdc.cell(+s127 & -s128 & +s280 & -s281, fill=m42) -c1063 = mcdc.cell(+s127 & -s128 & +s281 & -s282, fill=m43) -c1064 = mcdc.cell(+s127 & -s128 & +s282 & -s283, fill=m44) -c1065 = mcdc.cell(+s127 & -s128 & +s283 & -s284, fill=m45) -c1066 = mcdc.cell(+s127 & -s128 & +s284 & -s285, fill=m46) -c1067 = mcdc.cell(+s127 & -s128 & +s285, fill=m47) -c1068 = mcdc.cell(+s128 & -s129 & -s277, fill=m38) -c1069 = mcdc.cell(+s128 & -s129 & +s277 & -s278, fill=m39) -c1070 = mcdc.cell(+s128 & -s129 & +s278 & -s279, fill=m40) -c1071 = mcdc.cell(+s128 & -s129 & +s279 & -s280, fill=m41) -c1072 = mcdc.cell(+s128 & -s129 & +s280 & -s281, fill=m42) -c1073 = mcdc.cell(+s128 & -s129 & +s281 & -s282, fill=m43) -c1074 = mcdc.cell(+s128 & -s129 & +s282 & -s283, fill=m44) -c1075 = mcdc.cell(+s128 & -s129 & +s283 & -s284, fill=m45) -c1076 = mcdc.cell(+s128 & -s129 & +s284 & -s285, fill=m46) -c1077 = mcdc.cell(+s128 & -s129 & +s285, fill=m47) -c1078 = mcdc.cell(+s129 & -s130 & -s277, fill=m38) -c1079 = mcdc.cell(+s129 & -s130 & +s277 & -s278, fill=m39) -c1080 = mcdc.cell(+s129 & -s130 & +s278 & -s279, fill=m40) -c1081 = mcdc.cell(+s129 & -s130 & +s279 & -s280, fill=m41) -c1082 = mcdc.cell(+s129 & -s130 & +s280 & -s281, fill=m42) -c1083 = mcdc.cell(+s129 & -s130 & +s281 & -s282, fill=m43) -c1084 = mcdc.cell(+s129 & -s130 & +s282 & -s283, fill=m44) -c1085 = mcdc.cell(+s129 & -s130 & +s283 & -s284, fill=m45) -c1086 = mcdc.cell(+s129 & -s130 & +s284 & -s285, fill=m46) -c1087 = mcdc.cell(+s129 & -s130 & +s285, fill=m47) -c1088 = mcdc.cell(+s130 & -s131 & -s277, fill=m38) -c1089 = mcdc.cell(+s130 & -s131 & +s277 & -s278, fill=m39) -c1090 = mcdc.cell(+s130 & -s131 & +s278 & -s279, fill=m40) -c1091 = mcdc.cell(+s130 & -s131 & +s279 & -s280, fill=m41) -c1092 = mcdc.cell(+s130 & -s131 & +s280 & -s281, fill=m42) -c1093 = mcdc.cell(+s130 & -s131 & +s281 & -s282, fill=m43) -c1094 = mcdc.cell(+s130 & -s131 & +s282 & -s283, fill=m44) -c1095 = mcdc.cell(+s130 & -s131 & +s283 & -s284, fill=m45) -c1096 = mcdc.cell(+s130 & -s131 & +s284 & -s285, fill=m46) -c1097 = mcdc.cell(+s130 & -s131 & +s285, fill=m47) -c1098 = mcdc.cell(+s131 & -s132 & -s277, fill=m38) -c1099 = mcdc.cell(+s131 & -s132 & +s277 & -s278, fill=m39) -c1100 = mcdc.cell(+s131 & -s132 & +s278 & -s279, fill=m40) -c1101 = mcdc.cell(+s131 & -s132 & +s279 & -s280, fill=m41) -c1102 = mcdc.cell(+s131 & -s132 & +s280 & -s281, fill=m42) -c1103 = mcdc.cell(+s131 & -s132 & +s281 & -s282, fill=m43) -c1104 = mcdc.cell(+s131 & -s132 & +s282 & -s283, fill=m44) -c1105 = mcdc.cell(+s131 & -s132 & +s283 & -s284, fill=m45) -c1106 = mcdc.cell(+s131 & -s132 & +s284 & -s285, fill=m46) -c1107 = mcdc.cell(+s131 & -s132 & +s285, fill=m47) -c1108 = mcdc.cell(+s132 & -s133 & -s277, fill=m38) -c1109 = mcdc.cell(+s132 & -s133 & +s277 & -s278, fill=m39) -c1110 = mcdc.cell(+s132 & -s133 & +s278 & -s279, fill=m40) -c1111 = mcdc.cell(+s132 & -s133 & +s279 & -s280, fill=m41) -c1112 = mcdc.cell(+s132 & -s133 & +s280 & -s281, fill=m42) -c1113 = mcdc.cell(+s132 & -s133 & +s281 & -s282, fill=m43) -c1114 = mcdc.cell(+s132 & -s133 & +s282 & -s283, fill=m44) -c1115 = mcdc.cell(+s132 & -s133 & +s283 & -s284, fill=m45) -c1116 = mcdc.cell(+s132 & -s133 & +s284 & -s285, fill=m46) -c1117 = mcdc.cell(+s132 & -s133 & +s285, fill=m47) -c1118 = mcdc.cell(+s133 & -s134 & -s277, fill=m38) -c1119 = mcdc.cell(+s133 & -s134 & +s277 & -s278, fill=m39) -c1120 = mcdc.cell(+s133 & -s134 & +s278 & -s279, fill=m40) -c1121 = mcdc.cell(+s133 & -s134 & +s279 & -s280, fill=m41) -c1122 = mcdc.cell(+s133 & -s134 & +s280 & -s281, fill=m42) -c1123 = mcdc.cell(+s133 & -s134 & +s281 & -s282, fill=m43) -c1124 = mcdc.cell(+s133 & -s134 & +s282 & -s283, fill=m44) -c1125 = mcdc.cell(+s133 & -s134 & +s283 & -s284, fill=m45) -c1126 = mcdc.cell(+s133 & -s134 & +s284 & -s285, fill=m46) -c1127 = mcdc.cell(+s133 & -s134 & +s285, fill=m47) -c1128 = mcdc.cell(+s134 & -s135 & -s277, fill=m38) -c1129 = mcdc.cell(+s134 & -s135 & +s277 & -s278, fill=m39) -c1130 = mcdc.cell(+s134 & -s135 & +s278 & -s279, fill=m40) -c1131 = mcdc.cell(+s134 & -s135 & +s279 & -s280, fill=m41) -c1132 = mcdc.cell(+s134 & -s135 & +s280 & -s281, fill=m42) -c1133 = mcdc.cell(+s134 & -s135 & +s281 & -s282, fill=m43) -c1134 = mcdc.cell(+s134 & -s135 & +s282 & -s283, fill=m44) -c1135 = mcdc.cell(+s134 & -s135 & +s283 & -s284, fill=m45) -c1136 = mcdc.cell(+s134 & -s135 & +s284 & -s285, fill=m46) -c1137 = mcdc.cell(+s134 & -s135 & +s285, fill=m47) -c1138 = mcdc.cell(+s135 & -s136 & -s277, fill=m38) -c1139 = mcdc.cell(+s135 & -s136 & +s277 & -s278, fill=m39) -c1140 = mcdc.cell(+s135 & -s136 & +s278 & -s279, fill=m40) -c1141 = mcdc.cell(+s135 & -s136 & +s279 & -s280, fill=m41) -c1142 = mcdc.cell(+s135 & -s136 & +s280 & -s281, fill=m42) -c1143 = mcdc.cell(+s135 & -s136 & +s281 & -s282, fill=m43) -c1144 = mcdc.cell(+s135 & -s136 & +s282 & -s283, fill=m44) -c1145 = mcdc.cell(+s135 & -s136 & +s283 & -s284, fill=m45) -c1146 = mcdc.cell(+s135 & -s136 & +s284 & -s285, fill=m46) -c1147 = mcdc.cell(+s135 & -s136 & +s285, fill=m47) -c1148 = mcdc.cell(+s136 & -s137 & -s277, fill=m38) -c1149 = mcdc.cell(+s136 & -s137 & +s277 & -s278, fill=m39) -c1150 = mcdc.cell(+s136 & -s137 & +s278 & -s279, fill=m40) -c1151 = mcdc.cell(+s136 & -s137 & +s279 & -s280, fill=m41) -c1152 = mcdc.cell(+s136 & -s137 & +s280 & -s281, fill=m42) -c1153 = mcdc.cell(+s136 & -s137 & +s281 & -s282, fill=m43) -c1154 = mcdc.cell(+s136 & -s137 & +s282 & -s283, fill=m44) -c1155 = mcdc.cell(+s136 & -s137 & +s283 & -s284, fill=m45) -c1156 = mcdc.cell(+s136 & -s137 & +s284 & -s285, fill=m46) -c1157 = mcdc.cell(+s136 & -s137 & +s285, fill=m47) -c1158 = mcdc.cell(+s137 & -s138 & -s277, fill=m38) -c1159 = mcdc.cell(+s137 & -s138 & +s277 & -s278, fill=m39) -c1160 = mcdc.cell(+s137 & -s138 & +s278 & -s279, fill=m40) -c1161 = mcdc.cell(+s137 & -s138 & +s279 & -s280, fill=m41) -c1162 = mcdc.cell(+s137 & -s138 & +s280 & -s281, fill=m42) -c1163 = mcdc.cell(+s137 & -s138 & +s281 & -s282, fill=m43) -c1164 = mcdc.cell(+s137 & -s138 & +s282 & -s283, fill=m44) -c1165 = mcdc.cell(+s137 & -s138 & +s283 & -s284, fill=m45) -c1166 = mcdc.cell(+s137 & -s138 & +s284 & -s285, fill=m46) -c1167 = mcdc.cell(+s137 & -s138 & +s285, fill=m47) -c1168 = mcdc.cell(+s138 & -s139 & -s277, fill=m38) -c1169 = mcdc.cell(+s138 & -s139 & +s277 & -s278, fill=m39) -c1170 = mcdc.cell(+s138 & -s139 & +s278 & -s279, fill=m40) -c1171 = mcdc.cell(+s138 & -s139 & +s279 & -s280, fill=m41) -c1172 = mcdc.cell(+s138 & -s139 & +s280 & -s281, fill=m42) -c1173 = mcdc.cell(+s138 & -s139 & +s281 & -s282, fill=m43) -c1174 = mcdc.cell(+s138 & -s139 & +s282 & -s283, fill=m44) -c1175 = mcdc.cell(+s138 & -s139 & +s283 & -s284, fill=m45) -c1176 = mcdc.cell(+s138 & -s139 & +s284 & -s285, fill=m46) -c1177 = mcdc.cell(+s138 & -s139 & +s285, fill=m47) -c1178 = mcdc.cell(+s139 & -s140 & -s277, fill=m38) -c1179 = mcdc.cell(+s139 & -s140 & +s277 & -s278, fill=m39) -c1180 = mcdc.cell(+s139 & -s140 & +s278 & -s279, fill=m40) -c1181 = mcdc.cell(+s139 & -s140 & +s279 & -s280, fill=m41) -c1182 = mcdc.cell(+s139 & -s140 & +s280 & -s281, fill=m42) -c1183 = mcdc.cell(+s139 & -s140 & +s281 & -s282, fill=m43) -c1184 = mcdc.cell(+s139 & -s140 & +s282 & -s283, fill=m44) -c1185 = mcdc.cell(+s139 & -s140 & +s283 & -s284, fill=m45) -c1186 = mcdc.cell(+s139 & -s140 & +s284 & -s285, fill=m46) -c1187 = mcdc.cell(+s139 & -s140 & +s285, fill=m47) -c1188 = mcdc.cell(+s140 & -s141 & -s277, fill=m38) -c1189 = mcdc.cell(+s140 & -s141 & +s277 & -s278, fill=m39) -c1190 = mcdc.cell(+s140 & -s141 & +s278 & -s279, fill=m40) -c1191 = mcdc.cell(+s140 & -s141 & +s279 & -s280, fill=m41) -c1192 = mcdc.cell(+s140 & -s141 & +s280 & -s281, fill=m42) -c1193 = mcdc.cell(+s140 & -s141 & +s281 & -s282, fill=m43) -c1194 = mcdc.cell(+s140 & -s141 & +s282 & -s283, fill=m44) -c1195 = mcdc.cell(+s140 & -s141 & +s283 & -s284, fill=m45) -c1196 = mcdc.cell(+s140 & -s141 & +s284 & -s285, fill=m46) -c1197 = mcdc.cell(+s140 & -s141 & +s285, fill=m47) -c1198 = mcdc.cell(+s141 & -s142 & -s277, fill=m38) -c1199 = mcdc.cell(+s141 & -s142 & +s277 & -s278, fill=m39) -c1200 = mcdc.cell(+s141 & -s142 & +s278 & -s279, fill=m40) -c1201 = mcdc.cell(+s141 & -s142 & +s279 & -s280, fill=m41) -c1202 = mcdc.cell(+s141 & -s142 & +s280 & -s281, fill=m42) -c1203 = mcdc.cell(+s141 & -s142 & +s281 & -s282, fill=m43) -c1204 = mcdc.cell(+s141 & -s142 & +s282 & -s283, fill=m44) -c1205 = mcdc.cell(+s141 & -s142 & +s283 & -s284, fill=m45) -c1206 = mcdc.cell(+s141 & -s142 & +s284 & -s285, fill=m46) -c1207 = mcdc.cell(+s141 & -s142 & +s285, fill=m47) -c1208 = mcdc.cell(+s142 & -s143 & -s277, fill=m38) -c1209 = mcdc.cell(+s142 & -s143 & +s277 & -s278, fill=m39) -c1210 = mcdc.cell(+s142 & -s143 & +s278 & -s279, fill=m40) -c1211 = mcdc.cell(+s142 & -s143 & +s279 & -s280, fill=m41) -c1212 = mcdc.cell(+s142 & -s143 & +s280 & -s281, fill=m42) -c1213 = mcdc.cell(+s142 & -s143 & +s281 & -s282, fill=m43) -c1214 = mcdc.cell(+s142 & -s143 & +s282 & -s283, fill=m44) -c1215 = mcdc.cell(+s142 & -s143 & +s283 & -s284, fill=m45) -c1216 = mcdc.cell(+s142 & -s143 & +s284 & -s285, fill=m46) -c1217 = mcdc.cell(+s142 & -s143 & +s285, fill=m47) -c1218 = mcdc.cell(+s143 & -s144 & -s277, fill=m38) -c1219 = mcdc.cell(+s143 & -s144 & +s277 & -s278, fill=m39) -c1220 = mcdc.cell(+s143 & -s144 & +s278 & -s279, fill=m40) -c1221 = mcdc.cell(+s143 & -s144 & +s279 & -s280, fill=m41) -c1222 = mcdc.cell(+s143 & -s144 & +s280 & -s281, fill=m42) -c1223 = mcdc.cell(+s143 & -s144 & +s281 & -s282, fill=m43) -c1224 = mcdc.cell(+s143 & -s144 & +s282 & -s283, fill=m44) -c1225 = mcdc.cell(+s143 & -s144 & +s283 & -s284, fill=m45) -c1226 = mcdc.cell(+s143 & -s144 & +s284 & -s285, fill=m46) -c1227 = mcdc.cell(+s143 & -s144 & +s285, fill=m47) -c1228 = mcdc.cell(+s144 & -s145 & -s277, fill=m38) -c1229 = mcdc.cell(+s144 & -s145 & +s277 & -s278, fill=m39) -c1230 = mcdc.cell(+s144 & -s145 & +s278 & -s279, fill=m40) -c1231 = mcdc.cell(+s144 & -s145 & +s279 & -s280, fill=m41) -c1232 = mcdc.cell(+s144 & -s145 & +s280 & -s281, fill=m42) -c1233 = mcdc.cell(+s144 & -s145 & +s281 & -s282, fill=m43) -c1234 = mcdc.cell(+s144 & -s145 & +s282 & -s283, fill=m44) -c1235 = mcdc.cell(+s144 & -s145 & +s283 & -s284, fill=m45) -c1236 = mcdc.cell(+s144 & -s145 & +s284 & -s285, fill=m46) -c1237 = mcdc.cell(+s144 & -s145 & +s285, fill=m47) -c1238 = mcdc.cell(+s145 & -s146 & -s277, fill=m38) -c1239 = mcdc.cell(+s145 & -s146 & +s277 & -s278, fill=m39) -c1240 = mcdc.cell(+s145 & -s146 & +s278 & -s279, fill=m40) -c1241 = mcdc.cell(+s145 & -s146 & +s279 & -s280, fill=m41) -c1242 = mcdc.cell(+s145 & -s146 & +s280 & -s281, fill=m42) -c1243 = mcdc.cell(+s145 & -s146 & +s281 & -s282, fill=m43) -c1244 = mcdc.cell(+s145 & -s146 & +s282 & -s283, fill=m44) -c1245 = mcdc.cell(+s145 & -s146 & +s283 & -s284, fill=m45) -c1246 = mcdc.cell(+s145 & -s146 & +s284 & -s285, fill=m46) -c1247 = mcdc.cell(+s145 & -s146 & +s285, fill=m47) -c1248 = mcdc.cell(+s146 & -s147 & -s277, fill=m38) -c1249 = mcdc.cell(+s146 & -s147 & +s277 & -s278, fill=m39) -c1250 = mcdc.cell(+s146 & -s147 & +s278 & -s279, fill=m40) -c1251 = mcdc.cell(+s146 & -s147 & +s279 & -s280, fill=m41) -c1252 = mcdc.cell(+s146 & -s147 & +s280 & -s281, fill=m42) -c1253 = mcdc.cell(+s146 & -s147 & +s281 & -s282, fill=m43) -c1254 = mcdc.cell(+s146 & -s147 & +s282 & -s283, fill=m44) -c1255 = mcdc.cell(+s146 & -s147 & +s283 & -s284, fill=m45) -c1256 = mcdc.cell(+s146 & -s147 & +s284 & -s285, fill=m46) -c1257 = mcdc.cell(+s146 & -s147 & +s285, fill=m47) -c1258 = mcdc.cell(+s147 & -s148 & -s277, fill=m38) -c1259 = mcdc.cell(+s147 & -s148 & +s277 & -s278, fill=m39) -c1260 = mcdc.cell(+s147 & -s148 & +s278 & -s279, fill=m40) -c1261 = mcdc.cell(+s147 & -s148 & +s279 & -s280, fill=m41) -c1262 = mcdc.cell(+s147 & -s148 & +s280 & -s281, fill=m42) -c1263 = mcdc.cell(+s147 & -s148 & +s281 & -s282, fill=m43) -c1264 = mcdc.cell(+s147 & -s148 & +s282 & -s283, fill=m44) -c1265 = mcdc.cell(+s147 & -s148 & +s283 & -s284, fill=m45) -c1266 = mcdc.cell(+s147 & -s148 & +s284 & -s285, fill=m46) -c1267 = mcdc.cell(+s147 & -s148 & +s285, fill=m47) -c1268 = mcdc.cell(+s148 & -s149 & -s277, fill=m38) -c1269 = mcdc.cell(+s148 & -s149 & +s277 & -s278, fill=m39) -c1270 = mcdc.cell(+s148 & -s149 & +s278 & -s279, fill=m40) -c1271 = mcdc.cell(+s148 & -s149 & +s279 & -s280, fill=m41) -c1272 = mcdc.cell(+s148 & -s149 & +s280 & -s281, fill=m42) -c1273 = mcdc.cell(+s148 & -s149 & +s281 & -s282, fill=m43) -c1274 = mcdc.cell(+s148 & -s149 & +s282 & -s283, fill=m44) -c1275 = mcdc.cell(+s148 & -s149 & +s283 & -s284, fill=m45) -c1276 = mcdc.cell(+s148 & -s149 & +s284 & -s285, fill=m46) -c1277 = mcdc.cell(+s148 & -s149 & +s285, fill=m47) -c1278 = mcdc.cell(+s149 & -s150 & -s277, fill=m38) -c1279 = mcdc.cell(+s149 & -s150 & +s277 & -s278, fill=m39) -c1280 = mcdc.cell(+s149 & -s150 & +s278 & -s279, fill=m40) -c1281 = mcdc.cell(+s149 & -s150 & +s279 & -s280, fill=m41) -c1282 = mcdc.cell(+s149 & -s150 & +s280 & -s281, fill=m42) -c1283 = mcdc.cell(+s149 & -s150 & +s281 & -s282, fill=m43) -c1284 = mcdc.cell(+s149 & -s150 & +s282 & -s283, fill=m44) -c1285 = mcdc.cell(+s149 & -s150 & +s283 & -s284, fill=m45) -c1286 = mcdc.cell(+s149 & -s150 & +s284 & -s285, fill=m46) -c1287 = mcdc.cell(+s149 & -s150 & +s285, fill=m47) -c1288 = mcdc.cell(+s150 & -s151 & -s277, fill=m38) -c1289 = mcdc.cell(+s150 & -s151 & +s277 & -s278, fill=m39) -c1290 = mcdc.cell(+s150 & -s151 & +s278 & -s279, fill=m40) -c1291 = mcdc.cell(+s150 & -s151 & +s279 & -s280, fill=m41) -c1292 = mcdc.cell(+s150 & -s151 & +s280 & -s281, fill=m42) -c1293 = mcdc.cell(+s150 & -s151 & +s281 & -s282, fill=m43) -c1294 = mcdc.cell(+s150 & -s151 & +s282 & -s283, fill=m44) -c1295 = mcdc.cell(+s150 & -s151 & +s283 & -s284, fill=m45) -c1296 = mcdc.cell(+s150 & -s151 & +s284 & -s285, fill=m46) -c1297 = mcdc.cell(+s150 & -s151 & +s285, fill=m47) -c1298 = mcdc.cell(+s151 & -s152 & -s277, fill=m38) -c1299 = mcdc.cell(+s151 & -s152 & +s277 & -s278, fill=m39) -c1300 = mcdc.cell(+s151 & -s152 & +s278 & -s279, fill=m40) -c1301 = mcdc.cell(+s151 & -s152 & +s279 & -s280, fill=m41) -c1302 = mcdc.cell(+s151 & -s152 & +s280 & -s281, fill=m42) -c1303 = mcdc.cell(+s151 & -s152 & +s281 & -s282, fill=m43) -c1304 = mcdc.cell(+s151 & -s152 & +s282 & -s283, fill=m44) -c1305 = mcdc.cell(+s151 & -s152 & +s283 & -s284, fill=m45) -c1306 = mcdc.cell(+s151 & -s152 & +s284 & -s285, fill=m46) -c1307 = mcdc.cell(+s151 & -s152 & +s285, fill=m47) -c1308 = mcdc.cell(+s152 & -s153 & -s277, fill=m38) -c1309 = mcdc.cell(+s152 & -s153 & +s277 & -s278, fill=m39) -c1310 = mcdc.cell(+s152 & -s153 & +s278 & -s279, fill=m40) -c1311 = mcdc.cell(+s152 & -s153 & +s279 & -s280, fill=m41) -c1312 = mcdc.cell(+s152 & -s153 & +s280 & -s281, fill=m42) -c1313 = mcdc.cell(+s152 & -s153 & +s281 & -s282, fill=m43) -c1314 = mcdc.cell(+s152 & -s153 & +s282 & -s283, fill=m44) -c1315 = mcdc.cell(+s152 & -s153 & +s283 & -s284, fill=m45) -c1316 = mcdc.cell(+s152 & -s153 & +s284 & -s285, fill=m46) -c1317 = mcdc.cell(+s152 & -s153 & +s285, fill=m47) -c1318 = mcdc.cell(+s153 & -s154 & -s277, fill=m38) -c1319 = mcdc.cell(+s153 & -s154 & +s277 & -s278, fill=m39) -c1320 = mcdc.cell(+s153 & -s154 & +s278 & -s279, fill=m40) -c1321 = mcdc.cell(+s153 & -s154 & +s279 & -s280, fill=m41) -c1322 = mcdc.cell(+s153 & -s154 & +s280 & -s281, fill=m42) -c1323 = mcdc.cell(+s153 & -s154 & +s281 & -s282, fill=m43) -c1324 = mcdc.cell(+s153 & -s154 & +s282 & -s283, fill=m44) -c1325 = mcdc.cell(+s153 & -s154 & +s283 & -s284, fill=m45) -c1326 = mcdc.cell(+s153 & -s154 & +s284 & -s285, fill=m46) -c1327 = mcdc.cell(+s153 & -s154 & +s285, fill=m47) -c1328 = mcdc.cell(+s154 & -s155 & -s277, fill=m38) -c1329 = mcdc.cell(+s154 & -s155 & +s277 & -s278, fill=m39) -c1330 = mcdc.cell(+s154 & -s155 & +s278 & -s279, fill=m40) -c1331 = mcdc.cell(+s154 & -s155 & +s279 & -s280, fill=m41) -c1332 = mcdc.cell(+s154 & -s155 & +s280 & -s281, fill=m42) -c1333 = mcdc.cell(+s154 & -s155 & +s281 & -s282, fill=m43) -c1334 = mcdc.cell(+s154 & -s155 & +s282 & -s283, fill=m44) -c1335 = mcdc.cell(+s154 & -s155 & +s283 & -s284, fill=m45) -c1336 = mcdc.cell(+s154 & -s155 & +s284 & -s285, fill=m46) -c1337 = mcdc.cell(+s154 & -s155 & +s285, fill=m47) -c1338 = mcdc.cell(+s155 & -s156 & -s277, fill=m38) -c1339 = mcdc.cell(+s155 & -s156 & +s277 & -s278, fill=m39) -c1340 = mcdc.cell(+s155 & -s156 & +s278 & -s279, fill=m40) -c1341 = mcdc.cell(+s155 & -s156 & +s279 & -s280, fill=m41) -c1342 = mcdc.cell(+s155 & -s156 & +s280 & -s281, fill=m42) -c1343 = mcdc.cell(+s155 & -s156 & +s281 & -s282, fill=m43) -c1344 = mcdc.cell(+s155 & -s156 & +s282 & -s283, fill=m44) -c1345 = mcdc.cell(+s155 & -s156 & +s283 & -s284, fill=m45) -c1346 = mcdc.cell(+s155 & -s156 & +s284 & -s285, fill=m46) -c1347 = mcdc.cell(+s155 & -s156 & +s285, fill=m47) -c1348 = mcdc.cell(+s156 & -s157 & -s277, fill=m38) -c1349 = mcdc.cell(+s156 & -s157 & +s277 & -s278, fill=m39) -c1350 = mcdc.cell(+s156 & -s157 & +s278 & -s279, fill=m40) -c1351 = mcdc.cell(+s156 & -s157 & +s279 & -s280, fill=m41) -c1352 = mcdc.cell(+s156 & -s157 & +s280 & -s281, fill=m42) -c1353 = mcdc.cell(+s156 & -s157 & +s281 & -s282, fill=m43) -c1354 = mcdc.cell(+s156 & -s157 & +s282 & -s283, fill=m44) -c1355 = mcdc.cell(+s156 & -s157 & +s283 & -s284, fill=m45) -c1356 = mcdc.cell(+s156 & -s157 & +s284 & -s285, fill=m46) -c1357 = mcdc.cell(+s156 & -s157 & +s285, fill=m47) -c1358 = mcdc.cell(+s157 & -s158 & -s277, fill=m38) -c1359 = mcdc.cell(+s157 & -s158 & +s277 & -s278, fill=m39) -c1360 = mcdc.cell(+s157 & -s158 & +s278 & -s279, fill=m40) -c1361 = mcdc.cell(+s157 & -s158 & +s279 & -s280, fill=m41) -c1362 = mcdc.cell(+s157 & -s158 & +s280 & -s281, fill=m42) -c1363 = mcdc.cell(+s157 & -s158 & +s281 & -s282, fill=m43) -c1364 = mcdc.cell(+s157 & -s158 & +s282 & -s283, fill=m44) -c1365 = mcdc.cell(+s157 & -s158 & +s283 & -s284, fill=m45) -c1366 = mcdc.cell(+s157 & -s158 & +s284 & -s285, fill=m46) -c1367 = mcdc.cell(+s157 & -s158 & +s285, fill=m47) -c1368 = mcdc.cell(+s158 & -s159 & -s277, fill=m38) -c1369 = mcdc.cell(+s158 & -s159 & +s277 & -s278, fill=m39) -c1370 = mcdc.cell(+s158 & -s159 & +s278 & -s279, fill=m40) -c1371 = mcdc.cell(+s158 & -s159 & +s279 & -s280, fill=m41) -c1372 = mcdc.cell(+s158 & -s159 & +s280 & -s281, fill=m42) -c1373 = mcdc.cell(+s158 & -s159 & +s281 & -s282, fill=m43) -c1374 = mcdc.cell(+s158 & -s159 & +s282 & -s283, fill=m44) -c1375 = mcdc.cell(+s158 & -s159 & +s283 & -s284, fill=m45) -c1376 = mcdc.cell(+s158 & -s159 & +s284 & -s285, fill=m46) -c1377 = mcdc.cell(+s158 & -s159 & +s285, fill=m47) -c1378 = mcdc.cell(+s159 & -s160 & -s277, fill=m38) -c1379 = mcdc.cell(+s159 & -s160 & +s277 & -s278, fill=m39) -c1380 = mcdc.cell(+s159 & -s160 & +s278 & -s279, fill=m40) -c1381 = mcdc.cell(+s159 & -s160 & +s279 & -s280, fill=m41) -c1382 = mcdc.cell(+s159 & -s160 & +s280 & -s281, fill=m42) -c1383 = mcdc.cell(+s159 & -s160 & +s281 & -s282, fill=m43) -c1384 = mcdc.cell(+s159 & -s160 & +s282 & -s283, fill=m44) -c1385 = mcdc.cell(+s159 & -s160 & +s283 & -s284, fill=m45) -c1386 = mcdc.cell(+s159 & -s160 & +s284 & -s285, fill=m46) -c1387 = mcdc.cell(+s159 & -s160 & +s285, fill=m47) -c1388 = mcdc.cell(+s160 & -s161 & -s277, fill=m38) -c1389 = mcdc.cell(+s160 & -s161 & +s277 & -s278, fill=m39) -c1390 = mcdc.cell(+s160 & -s161 & +s278 & -s279, fill=m40) -c1391 = mcdc.cell(+s160 & -s161 & +s279 & -s280, fill=m41) -c1392 = mcdc.cell(+s160 & -s161 & +s280 & -s281, fill=m42) -c1393 = mcdc.cell(+s160 & -s161 & +s281 & -s282, fill=m43) -c1394 = mcdc.cell(+s160 & -s161 & +s282 & -s283, fill=m44) -c1395 = mcdc.cell(+s160 & -s161 & +s283 & -s284, fill=m45) -c1396 = mcdc.cell(+s160 & -s161 & +s284 & -s285, fill=m46) -c1397 = mcdc.cell(+s160 & -s161 & +s285, fill=m47) -c1398 = mcdc.cell(+s161 & -s162 & -s277, fill=m38) -c1399 = mcdc.cell(+s161 & -s162 & +s277 & -s278, fill=m39) -c1400 = mcdc.cell(+s161 & -s162 & +s278 & -s279, fill=m40) -c1401 = mcdc.cell(+s161 & -s162 & +s279 & -s280, fill=m41) -c1402 = mcdc.cell(+s161 & -s162 & +s280 & -s281, fill=m42) -c1403 = mcdc.cell(+s161 & -s162 & +s281 & -s282, fill=m43) -c1404 = mcdc.cell(+s161 & -s162 & +s282 & -s283, fill=m44) -c1405 = mcdc.cell(+s161 & -s162 & +s283 & -s284, fill=m45) -c1406 = mcdc.cell(+s161 & -s162 & +s284 & -s285, fill=m46) -c1407 = mcdc.cell(+s161 & -s162 & +s285, fill=m47) -c1408 = mcdc.cell(+s162 & -s163 & -s277, fill=m38) -c1409 = mcdc.cell(+s162 & -s163 & +s277 & -s278, fill=m39) -c1410 = mcdc.cell(+s162 & -s163 & +s278 & -s279, fill=m40) -c1411 = mcdc.cell(+s162 & -s163 & +s279 & -s280, fill=m41) -c1412 = mcdc.cell(+s162 & -s163 & +s280 & -s281, fill=m42) -c1413 = mcdc.cell(+s162 & -s163 & +s281 & -s282, fill=m43) -c1414 = mcdc.cell(+s162 & -s163 & +s282 & -s283, fill=m44) -c1415 = mcdc.cell(+s162 & -s163 & +s283 & -s284, fill=m45) -c1416 = mcdc.cell(+s162 & -s163 & +s284 & -s285, fill=m46) -c1417 = mcdc.cell(+s162 & -s163 & +s285, fill=m47) -c1418 = mcdc.cell(+s163 & -s164 & -s277, fill=m38) -c1419 = mcdc.cell(+s163 & -s164 & +s277 & -s278, fill=m39) -c1420 = mcdc.cell(+s163 & -s164 & +s278 & -s279, fill=m40) -c1421 = mcdc.cell(+s163 & -s164 & +s279 & -s280, fill=m41) -c1422 = mcdc.cell(+s163 & -s164 & +s280 & -s281, fill=m42) -c1423 = mcdc.cell(+s163 & -s164 & +s281 & -s282, fill=m43) -c1424 = mcdc.cell(+s163 & -s164 & +s282 & -s283, fill=m44) -c1425 = mcdc.cell(+s163 & -s164 & +s283 & -s284, fill=m45) -c1426 = mcdc.cell(+s163 & -s164 & +s284 & -s285, fill=m46) -c1427 = mcdc.cell(+s163 & -s164 & +s285, fill=m47) -c1428 = mcdc.cell(+s164 & -s165 & -s277, fill=m38) -c1429 = mcdc.cell(+s164 & -s165 & +s277 & -s278, fill=m39) -c1430 = mcdc.cell(+s164 & -s165 & +s278 & -s279, fill=m40) -c1431 = mcdc.cell(+s164 & -s165 & +s279 & -s280, fill=m41) -c1432 = mcdc.cell(+s164 & -s165 & +s280 & -s281, fill=m42) -c1433 = mcdc.cell(+s164 & -s165 & +s281 & -s282, fill=m43) -c1434 = mcdc.cell(+s164 & -s165 & +s282 & -s283, fill=m44) -c1435 = mcdc.cell(+s164 & -s165 & +s283 & -s284, fill=m45) -c1436 = mcdc.cell(+s164 & -s165 & +s284 & -s285, fill=m46) -c1437 = mcdc.cell(+s164 & -s165 & +s285, fill=m47) -c1438 = mcdc.cell(+s165 & -s166 & -s277, fill=m38) -c1439 = mcdc.cell(+s165 & -s166 & +s277 & -s278, fill=m39) -c1440 = mcdc.cell(+s165 & -s166 & +s278 & -s279, fill=m40) -c1441 = mcdc.cell(+s165 & -s166 & +s279 & -s280, fill=m41) -c1442 = mcdc.cell(+s165 & -s166 & +s280 & -s281, fill=m42) -c1443 = mcdc.cell(+s165 & -s166 & +s281 & -s282, fill=m43) -c1444 = mcdc.cell(+s165 & -s166 & +s282 & -s283, fill=m44) -c1445 = mcdc.cell(+s165 & -s166 & +s283 & -s284, fill=m45) -c1446 = mcdc.cell(+s165 & -s166 & +s284 & -s285, fill=m46) -c1447 = mcdc.cell(+s165 & -s166 & +s285, fill=m47) -c1448 = mcdc.cell(+s166 & -s167 & -s277, fill=m38) -c1449 = mcdc.cell(+s166 & -s167 & +s277 & -s278, fill=m39) -c1450 = mcdc.cell(+s166 & -s167 & +s278 & -s279, fill=m40) -c1451 = mcdc.cell(+s166 & -s167 & +s279 & -s280, fill=m41) -c1452 = mcdc.cell(+s166 & -s167 & +s280 & -s281, fill=m42) -c1453 = mcdc.cell(+s166 & -s167 & +s281 & -s282, fill=m43) -c1454 = mcdc.cell(+s166 & -s167 & +s282 & -s283, fill=m44) -c1455 = mcdc.cell(+s166 & -s167 & +s283 & -s284, fill=m45) -c1456 = mcdc.cell(+s166 & -s167 & +s284 & -s285, fill=m46) -c1457 = mcdc.cell(+s166 & -s167 & +s285, fill=m47) -c1458 = mcdc.cell(+s167 & -s168 & -s277, fill=m38) -c1459 = mcdc.cell(+s167 & -s168 & +s277 & -s278, fill=m39) -c1460 = mcdc.cell(+s167 & -s168 & +s278 & -s279, fill=m40) -c1461 = mcdc.cell(+s167 & -s168 & +s279 & -s280, fill=m41) -c1462 = mcdc.cell(+s167 & -s168 & +s280 & -s281, fill=m42) -c1463 = mcdc.cell(+s167 & -s168 & +s281 & -s282, fill=m43) -c1464 = mcdc.cell(+s167 & -s168 & +s282 & -s283, fill=m44) -c1465 = mcdc.cell(+s167 & -s168 & +s283 & -s284, fill=m45) -c1466 = mcdc.cell(+s167 & -s168 & +s284 & -s285, fill=m46) -c1467 = mcdc.cell(+s167 & -s168 & +s285, fill=m47) -c1468 = mcdc.cell(+s168 & -s169 & -s277, fill=m38) -c1469 = mcdc.cell(+s168 & -s169 & +s277 & -s278, fill=m39) -c1470 = mcdc.cell(+s168 & -s169 & +s278 & -s279, fill=m40) -c1471 = mcdc.cell(+s168 & -s169 & +s279 & -s280, fill=m41) -c1472 = mcdc.cell(+s168 & -s169 & +s280 & -s281, fill=m42) -c1473 = mcdc.cell(+s168 & -s169 & +s281 & -s282, fill=m43) -c1474 = mcdc.cell(+s168 & -s169 & +s282 & -s283, fill=m44) -c1475 = mcdc.cell(+s168 & -s169 & +s283 & -s284, fill=m45) -c1476 = mcdc.cell(+s168 & -s169 & +s284 & -s285, fill=m46) -c1477 = mcdc.cell(+s168 & -s169 & +s285, fill=m47) -c1478 = mcdc.cell(+s169 & -s170 & -s277, fill=m38) -c1479 = mcdc.cell(+s169 & -s170 & +s277 & -s278, fill=m39) -c1480 = mcdc.cell(+s169 & -s170 & +s278 & -s279, fill=m40) -c1481 = mcdc.cell(+s169 & -s170 & +s279 & -s280, fill=m41) -c1482 = mcdc.cell(+s169 & -s170 & +s280 & -s281, fill=m42) -c1483 = mcdc.cell(+s169 & -s170 & +s281 & -s282, fill=m43) -c1484 = mcdc.cell(+s169 & -s170 & +s282 & -s283, fill=m44) -c1485 = mcdc.cell(+s169 & -s170 & +s283 & -s284, fill=m45) -c1486 = mcdc.cell(+s169 & -s170 & +s284 & -s285, fill=m46) -c1487 = mcdc.cell(+s169 & -s170 & +s285, fill=m47) -c1488 = mcdc.cell(+s170 & -s171 & -s277, fill=m38) -c1489 = mcdc.cell(+s170 & -s171 & +s277 & -s278, fill=m39) -c1490 = mcdc.cell(+s170 & -s171 & +s278 & -s279, fill=m40) -c1491 = mcdc.cell(+s170 & -s171 & +s279 & -s280, fill=m41) -c1492 = mcdc.cell(+s170 & -s171 & +s280 & -s281, fill=m42) -c1493 = mcdc.cell(+s170 & -s171 & +s281 & -s282, fill=m43) -c1494 = mcdc.cell(+s170 & -s171 & +s282 & -s283, fill=m44) -c1495 = mcdc.cell(+s170 & -s171 & +s283 & -s284, fill=m45) -c1496 = mcdc.cell(+s170 & -s171 & +s284 & -s285, fill=m46) -c1497 = mcdc.cell(+s170 & -s171 & +s285, fill=m47) -c1498 = mcdc.cell(+s171 & -s172 & -s277, fill=m38) -c1499 = mcdc.cell(+s171 & -s172 & +s277 & -s278, fill=m39) -c1500 = mcdc.cell(+s171 & -s172 & +s278 & -s279, fill=m40) -c1501 = mcdc.cell(+s171 & -s172 & +s279 & -s280, fill=m41) -c1502 = mcdc.cell(+s171 & -s172 & +s280 & -s281, fill=m42) -c1503 = mcdc.cell(+s171 & -s172 & +s281 & -s282, fill=m43) -c1504 = mcdc.cell(+s171 & -s172 & +s282 & -s283, fill=m44) -c1505 = mcdc.cell(+s171 & -s172 & +s283 & -s284, fill=m45) -c1506 = mcdc.cell(+s171 & -s172 & +s284 & -s285, fill=m46) -c1507 = mcdc.cell(+s171 & -s172 & +s285, fill=m47) -c1508 = mcdc.cell(+s172 & -s173 & -s277, fill=m38) -c1509 = mcdc.cell(+s172 & -s173 & +s277 & -s278, fill=m39) -c1510 = mcdc.cell(+s172 & -s173 & +s278 & -s279, fill=m40) -c1511 = mcdc.cell(+s172 & -s173 & +s279 & -s280, fill=m41) -c1512 = mcdc.cell(+s172 & -s173 & +s280 & -s281, fill=m42) -c1513 = mcdc.cell(+s172 & -s173 & +s281 & -s282, fill=m43) -c1514 = mcdc.cell(+s172 & -s173 & +s282 & -s283, fill=m44) -c1515 = mcdc.cell(+s172 & -s173 & +s283 & -s284, fill=m45) -c1516 = mcdc.cell(+s172 & -s173 & +s284 & -s285, fill=m46) -c1517 = mcdc.cell(+s172 & -s173 & +s285, fill=m47) -c1518 = mcdc.cell(+s173 & -s174 & -s277, fill=m38) -c1519 = mcdc.cell(+s173 & -s174 & +s277 & -s278, fill=m39) -c1520 = mcdc.cell(+s173 & -s174 & +s278 & -s279, fill=m40) -c1521 = mcdc.cell(+s173 & -s174 & +s279 & -s280, fill=m41) -c1522 = mcdc.cell(+s173 & -s174 & +s280 & -s281, fill=m42) -c1523 = mcdc.cell(+s173 & -s174 & +s281 & -s282, fill=m43) -c1524 = mcdc.cell(+s173 & -s174 & +s282 & -s283, fill=m44) -c1525 = mcdc.cell(+s173 & -s174 & +s283 & -s284, fill=m45) -c1526 = mcdc.cell(+s173 & -s174 & +s284 & -s285, fill=m46) -c1527 = mcdc.cell(+s173 & -s174 & +s285, fill=m47) -c1528 = mcdc.cell(+s174 & -s175 & -s277, fill=m38) -c1529 = mcdc.cell(+s174 & -s175 & +s277 & -s278, fill=m39) -c1530 = mcdc.cell(+s174 & -s175 & +s278 & -s279, fill=m40) -c1531 = mcdc.cell(+s174 & -s175 & +s279 & -s280, fill=m41) -c1532 = mcdc.cell(+s174 & -s175 & +s280 & -s281, fill=m42) -c1533 = mcdc.cell(+s174 & -s175 & +s281 & -s282, fill=m43) -c1534 = mcdc.cell(+s174 & -s175 & +s282 & -s283, fill=m44) -c1535 = mcdc.cell(+s174 & -s175 & +s283 & -s284, fill=m45) -c1536 = mcdc.cell(+s174 & -s175 & +s284 & -s285, fill=m46) -c1537 = mcdc.cell(+s174 & -s175 & +s285, fill=m47) -c1538 = mcdc.cell(+s175 & -s176 & -s277, fill=m38) -c1539 = mcdc.cell(+s175 & -s176 & +s277 & -s278, fill=m39) -c1540 = mcdc.cell(+s175 & -s176 & +s278 & -s279, fill=m40) -c1541 = mcdc.cell(+s175 & -s176 & +s279 & -s280, fill=m41) -c1542 = mcdc.cell(+s175 & -s176 & +s280 & -s281, fill=m42) -c1543 = mcdc.cell(+s175 & -s176 & +s281 & -s282, fill=m43) -c1544 = mcdc.cell(+s175 & -s176 & +s282 & -s283, fill=m44) -c1545 = mcdc.cell(+s175 & -s176 & +s283 & -s284, fill=m45) -c1546 = mcdc.cell(+s175 & -s176 & +s284 & -s285, fill=m46) -c1547 = mcdc.cell(+s175 & -s176 & +s285, fill=m47) -c1548 = mcdc.cell(+s176 & -s177 & -s277, fill=m38) -c1549 = mcdc.cell(+s176 & -s177 & +s277 & -s278, fill=m39) -c1550 = mcdc.cell(+s176 & -s177 & +s278 & -s279, fill=m40) -c1551 = mcdc.cell(+s176 & -s177 & +s279 & -s280, fill=m41) -c1552 = mcdc.cell(+s176 & -s177 & +s280 & -s281, fill=m42) -c1553 = mcdc.cell(+s176 & -s177 & +s281 & -s282, fill=m43) -c1554 = mcdc.cell(+s176 & -s177 & +s282 & -s283, fill=m44) -c1555 = mcdc.cell(+s176 & -s177 & +s283 & -s284, fill=m45) -c1556 = mcdc.cell(+s176 & -s177 & +s284 & -s285, fill=m46) -c1557 = mcdc.cell(+s176 & -s177 & +s285, fill=m47) -c1558 = mcdc.cell(+s177 & -s178 & -s277, fill=m38) -c1559 = mcdc.cell(+s177 & -s178 & +s277 & -s278, fill=m39) -c1560 = mcdc.cell(+s177 & -s178 & +s278 & -s279, fill=m40) -c1561 = mcdc.cell(+s177 & -s178 & +s279 & -s280, fill=m41) -c1562 = mcdc.cell(+s177 & -s178 & +s280 & -s281, fill=m42) -c1563 = mcdc.cell(+s177 & -s178 & +s281 & -s282, fill=m43) -c1564 = mcdc.cell(+s177 & -s178 & +s282 & -s283, fill=m44) -c1565 = mcdc.cell(+s177 & -s178 & +s283 & -s284, fill=m45) -c1566 = mcdc.cell(+s177 & -s178 & +s284 & -s285, fill=m46) -c1567 = mcdc.cell(+s177 & -s178 & +s285, fill=m47) -c1568 = mcdc.cell(+s178 & -s179 & -s277, fill=m38) -c1569 = mcdc.cell(+s178 & -s179 & +s277 & -s278, fill=m39) -c1570 = mcdc.cell(+s178 & -s179 & +s278 & -s279, fill=m40) -c1571 = mcdc.cell(+s178 & -s179 & +s279 & -s280, fill=m41) -c1572 = mcdc.cell(+s178 & -s179 & +s280 & -s281, fill=m42) -c1573 = mcdc.cell(+s178 & -s179 & +s281 & -s282, fill=m43) -c1574 = mcdc.cell(+s178 & -s179 & +s282 & -s283, fill=m44) -c1575 = mcdc.cell(+s178 & -s179 & +s283 & -s284, fill=m45) -c1576 = mcdc.cell(+s178 & -s179 & +s284 & -s285, fill=m46) -c1577 = mcdc.cell(+s178 & -s179 & +s285, fill=m47) -c1578 = mcdc.cell(+s179 & -s180 & -s277, fill=m38) -c1579 = mcdc.cell(+s179 & -s180 & +s277 & -s278, fill=m39) -c1580 = mcdc.cell(+s179 & -s180 & +s278 & -s279, fill=m40) -c1581 = mcdc.cell(+s179 & -s180 & +s279 & -s280, fill=m41) -c1582 = mcdc.cell(+s179 & -s180 & +s280 & -s281, fill=m42) -c1583 = mcdc.cell(+s179 & -s180 & +s281 & -s282, fill=m43) -c1584 = mcdc.cell(+s179 & -s180 & +s282 & -s283, fill=m44) -c1585 = mcdc.cell(+s179 & -s180 & +s283 & -s284, fill=m45) -c1586 = mcdc.cell(+s179 & -s180 & +s284 & -s285, fill=m46) -c1587 = mcdc.cell(+s179 & -s180 & +s285, fill=m47) -c1588 = mcdc.cell(+s180 & -s181 & -s277, fill=m38) -c1589 = mcdc.cell(+s180 & -s181 & +s277 & -s278, fill=m39) -c1590 = mcdc.cell(+s180 & -s181 & +s278 & -s279, fill=m40) -c1591 = mcdc.cell(+s180 & -s181 & +s279 & -s280, fill=m41) -c1592 = mcdc.cell(+s180 & -s181 & +s280 & -s281, fill=m42) -c1593 = mcdc.cell(+s180 & -s181 & +s281 & -s282, fill=m43) -c1594 = mcdc.cell(+s180 & -s181 & +s282 & -s283, fill=m44) -c1595 = mcdc.cell(+s180 & -s181 & +s283 & -s284, fill=m45) -c1596 = mcdc.cell(+s180 & -s181 & +s284 & -s285, fill=m46) -c1597 = mcdc.cell(+s180 & -s181 & +s285, fill=m47) -c1598 = mcdc.cell(+s181 & -s182 & -s277, fill=m38) -c1599 = mcdc.cell(+s181 & -s182 & +s277 & -s278, fill=m39) -c1600 = mcdc.cell(+s181 & -s182 & +s278 & -s279, fill=m40) -c1601 = mcdc.cell(+s181 & -s182 & +s279 & -s280, fill=m41) -c1602 = mcdc.cell(+s181 & -s182 & +s280 & -s281, fill=m42) -c1603 = mcdc.cell(+s181 & -s182 & +s281 & -s282, fill=m43) -c1604 = mcdc.cell(+s181 & -s182 & +s282 & -s283, fill=m44) -c1605 = mcdc.cell(+s181 & -s182 & +s283 & -s284, fill=m45) -c1606 = mcdc.cell(+s181 & -s182 & +s284 & -s285, fill=m46) -c1607 = mcdc.cell(+s181 & -s182 & +s285, fill=m47) -c1608 = mcdc.cell(+s182 & -s183 & -s277, fill=m38) -c1609 = mcdc.cell(+s182 & -s183 & +s277 & -s278, fill=m39) -c1610 = mcdc.cell(+s182 & -s183 & +s278 & -s279, fill=m40) -c1611 = mcdc.cell(+s182 & -s183 & +s279 & -s280, fill=m41) -c1612 = mcdc.cell(+s182 & -s183 & +s280 & -s281, fill=m42) -c1613 = mcdc.cell(+s182 & -s183 & +s281 & -s282, fill=m43) -c1614 = mcdc.cell(+s182 & -s183 & +s282 & -s283, fill=m44) -c1615 = mcdc.cell(+s182 & -s183 & +s283 & -s284, fill=m45) -c1616 = mcdc.cell(+s182 & -s183 & +s284 & -s285, fill=m46) -c1617 = mcdc.cell(+s182 & -s183 & +s285, fill=m47) -c1618 = mcdc.cell(+s183 & -s184 & -s277, fill=m38) -c1619 = mcdc.cell(+s183 & -s184 & +s277 & -s278, fill=m39) -c1620 = mcdc.cell(+s183 & -s184 & +s278 & -s279, fill=m40) -c1621 = mcdc.cell(+s183 & -s184 & +s279 & -s280, fill=m41) -c1622 = mcdc.cell(+s183 & -s184 & +s280 & -s281, fill=m42) -c1623 = mcdc.cell(+s183 & -s184 & +s281 & -s282, fill=m43) -c1624 = mcdc.cell(+s183 & -s184 & +s282 & -s283, fill=m44) -c1625 = mcdc.cell(+s183 & -s184 & +s283 & -s284, fill=m45) -c1626 = mcdc.cell(+s183 & -s184 & +s284 & -s285, fill=m46) -c1627 = mcdc.cell(+s183 & -s184 & +s285, fill=m47) -c1628 = mcdc.cell(+s184 & -s185 & -s277, fill=m38) -c1629 = mcdc.cell(+s184 & -s185 & +s277 & -s278, fill=m39) -c1630 = mcdc.cell(+s184 & -s185 & +s278 & -s279, fill=m40) -c1631 = mcdc.cell(+s184 & -s185 & +s279 & -s280, fill=m41) -c1632 = mcdc.cell(+s184 & -s185 & +s280 & -s281, fill=m42) -c1633 = mcdc.cell(+s184 & -s185 & +s281 & -s282, fill=m43) -c1634 = mcdc.cell(+s184 & -s185 & +s282 & -s283, fill=m44) -c1635 = mcdc.cell(+s184 & -s185 & +s283 & -s284, fill=m45) -c1636 = mcdc.cell(+s184 & -s185 & +s284 & -s285, fill=m46) -c1637 = mcdc.cell(+s184 & -s185 & +s285, fill=m47) -c1638 = mcdc.cell(+s185 & -s186 & -s277, fill=m38) -c1639 = mcdc.cell(+s185 & -s186 & +s277 & -s278, fill=m39) -c1640 = mcdc.cell(+s185 & -s186 & +s278 & -s279, fill=m40) -c1641 = mcdc.cell(+s185 & -s186 & +s279 & -s280, fill=m41) -c1642 = mcdc.cell(+s185 & -s186 & +s280 & -s281, fill=m42) -c1643 = mcdc.cell(+s185 & -s186 & +s281 & -s282, fill=m43) -c1644 = mcdc.cell(+s185 & -s186 & +s282 & -s283, fill=m44) -c1645 = mcdc.cell(+s185 & -s186 & +s283 & -s284, fill=m45) -c1646 = mcdc.cell(+s185 & -s186 & +s284 & -s285, fill=m46) -c1647 = mcdc.cell(+s185 & -s186 & +s285, fill=m47) -c1648 = mcdc.cell(+s186 & -s187 & -s277, fill=m38) -c1649 = mcdc.cell(+s186 & -s187 & +s277 & -s278, fill=m39) -c1650 = mcdc.cell(+s186 & -s187 & +s278 & -s279, fill=m40) -c1651 = mcdc.cell(+s186 & -s187 & +s279 & -s280, fill=m41) -c1652 = mcdc.cell(+s186 & -s187 & +s280 & -s281, fill=m42) -c1653 = mcdc.cell(+s186 & -s187 & +s281 & -s282, fill=m43) -c1654 = mcdc.cell(+s186 & -s187 & +s282 & -s283, fill=m44) -c1655 = mcdc.cell(+s186 & -s187 & +s283 & -s284, fill=m45) -c1656 = mcdc.cell(+s186 & -s187 & +s284 & -s285, fill=m46) -c1657 = mcdc.cell(+s186 & -s187 & +s285, fill=m47) -c1658 = mcdc.cell(+s187 & -s188 & -s277, fill=m38) -c1659 = mcdc.cell(+s187 & -s188 & +s277 & -s278, fill=m39) -c1660 = mcdc.cell(+s187 & -s188 & +s278 & -s279, fill=m40) -c1661 = mcdc.cell(+s187 & -s188 & +s279 & -s280, fill=m41) -c1662 = mcdc.cell(+s187 & -s188 & +s280 & -s281, fill=m42) -c1663 = mcdc.cell(+s187 & -s188 & +s281 & -s282, fill=m43) -c1664 = mcdc.cell(+s187 & -s188 & +s282 & -s283, fill=m44) -c1665 = mcdc.cell(+s187 & -s188 & +s283 & -s284, fill=m45) -c1666 = mcdc.cell(+s187 & -s188 & +s284 & -s285, fill=m46) -c1667 = mcdc.cell(+s187 & -s188 & +s285, fill=m47) -c1668 = mcdc.cell(+s188 & -s189 & -s277, fill=m38) -c1669 = mcdc.cell(+s188 & -s189 & +s277 & -s278, fill=m39) -c1670 = mcdc.cell(+s188 & -s189 & +s278 & -s279, fill=m40) -c1671 = mcdc.cell(+s188 & -s189 & +s279 & -s280, fill=m41) -c1672 = mcdc.cell(+s188 & -s189 & +s280 & -s281, fill=m42) -c1673 = mcdc.cell(+s188 & -s189 & +s281 & -s282, fill=m43) -c1674 = mcdc.cell(+s188 & -s189 & +s282 & -s283, fill=m44) -c1675 = mcdc.cell(+s188 & -s189 & +s283 & -s284, fill=m45) -c1676 = mcdc.cell(+s188 & -s189 & +s284 & -s285, fill=m46) -c1677 = mcdc.cell(+s188 & -s189 & +s285, fill=m47) -c1678 = mcdc.cell(+s189 & -s190 & -s277, fill=m38) -c1679 = mcdc.cell(+s189 & -s190 & +s277 & -s278, fill=m39) -c1680 = mcdc.cell(+s189 & -s190 & +s278 & -s279, fill=m40) -c1681 = mcdc.cell(+s189 & -s190 & +s279 & -s280, fill=m41) -c1682 = mcdc.cell(+s189 & -s190 & +s280 & -s281, fill=m42) -c1683 = mcdc.cell(+s189 & -s190 & +s281 & -s282, fill=m43) -c1684 = mcdc.cell(+s189 & -s190 & +s282 & -s283, fill=m44) -c1685 = mcdc.cell(+s189 & -s190 & +s283 & -s284, fill=m45) -c1686 = mcdc.cell(+s189 & -s190 & +s284 & -s285, fill=m46) -c1687 = mcdc.cell(+s189 & -s190 & +s285, fill=m47) -c1688 = mcdc.cell(+s190 & -s191 & -s277, fill=m38) -c1689 = mcdc.cell(+s190 & -s191 & +s277 & -s278, fill=m39) -c1690 = mcdc.cell(+s190 & -s191 & +s278 & -s279, fill=m40) -c1691 = mcdc.cell(+s190 & -s191 & +s279 & -s280, fill=m41) -c1692 = mcdc.cell(+s190 & -s191 & +s280 & -s281, fill=m42) -c1693 = mcdc.cell(+s190 & -s191 & +s281 & -s282, fill=m43) -c1694 = mcdc.cell(+s190 & -s191 & +s282 & -s283, fill=m44) -c1695 = mcdc.cell(+s190 & -s191 & +s283 & -s284, fill=m45) -c1696 = mcdc.cell(+s190 & -s191 & +s284 & -s285, fill=m46) -c1697 = mcdc.cell(+s190 & -s191 & +s285, fill=m47) -c1698 = mcdc.cell(+s191 & -s192 & -s277, fill=m38) -c1699 = mcdc.cell(+s191 & -s192 & +s277 & -s278, fill=m39) -c1700 = mcdc.cell(+s191 & -s192 & +s278 & -s279, fill=m40) -c1701 = mcdc.cell(+s191 & -s192 & +s279 & -s280, fill=m41) -c1702 = mcdc.cell(+s191 & -s192 & +s280 & -s281, fill=m42) -c1703 = mcdc.cell(+s191 & -s192 & +s281 & -s282, fill=m43) -c1704 = mcdc.cell(+s191 & -s192 & +s282 & -s283, fill=m44) -c1705 = mcdc.cell(+s191 & -s192 & +s283 & -s284, fill=m45) -c1706 = mcdc.cell(+s191 & -s192 & +s284 & -s285, fill=m46) -c1707 = mcdc.cell(+s191 & -s192 & +s285, fill=m47) -c1708 = mcdc.cell(+s192 & -s193 & -s277, fill=m38) -c1709 = mcdc.cell(+s192 & -s193 & +s277 & -s278, fill=m39) -c1710 = mcdc.cell(+s192 & -s193 & +s278 & -s279, fill=m40) -c1711 = mcdc.cell(+s192 & -s193 & +s279 & -s280, fill=m41) -c1712 = mcdc.cell(+s192 & -s193 & +s280 & -s281, fill=m42) -c1713 = mcdc.cell(+s192 & -s193 & +s281 & -s282, fill=m43) -c1714 = mcdc.cell(+s192 & -s193 & +s282 & -s283, fill=m44) -c1715 = mcdc.cell(+s192 & -s193 & +s283 & -s284, fill=m45) -c1716 = mcdc.cell(+s192 & -s193 & +s284 & -s285, fill=m46) -c1717 = mcdc.cell(+s192 & -s193 & +s285, fill=m47) -c1718 = mcdc.cell(+s193 & -s194 & -s277, fill=m38) -c1719 = mcdc.cell(+s193 & -s194 & +s277 & -s278, fill=m39) -c1720 = mcdc.cell(+s193 & -s194 & +s278 & -s279, fill=m40) -c1721 = mcdc.cell(+s193 & -s194 & +s279 & -s280, fill=m41) -c1722 = mcdc.cell(+s193 & -s194 & +s280 & -s281, fill=m42) -c1723 = mcdc.cell(+s193 & -s194 & +s281 & -s282, fill=m43) -c1724 = mcdc.cell(+s193 & -s194 & +s282 & -s283, fill=m44) -c1725 = mcdc.cell(+s193 & -s194 & +s283 & -s284, fill=m45) -c1726 = mcdc.cell(+s193 & -s194 & +s284 & -s285, fill=m46) -c1727 = mcdc.cell(+s193 & -s194 & +s285, fill=m47) -c1728 = mcdc.cell(+s194 & -s195 & -s277, fill=m38) -c1729 = mcdc.cell(+s194 & -s195 & +s277 & -s278, fill=m39) -c1730 = mcdc.cell(+s194 & -s195 & +s278 & -s279, fill=m40) -c1731 = mcdc.cell(+s194 & -s195 & +s279 & -s280, fill=m41) -c1732 = mcdc.cell(+s194 & -s195 & +s280 & -s281, fill=m42) -c1733 = mcdc.cell(+s194 & -s195 & +s281 & -s282, fill=m43) -c1734 = mcdc.cell(+s194 & -s195 & +s282 & -s283, fill=m44) -c1735 = mcdc.cell(+s194 & -s195 & +s283 & -s284, fill=m45) -c1736 = mcdc.cell(+s194 & -s195 & +s284 & -s285, fill=m46) -c1737 = mcdc.cell(+s194 & -s195 & +s285, fill=m47) -c1738 = mcdc.cell(+s195 & -s196 & -s277, fill=m38) -c1739 = mcdc.cell(+s195 & -s196 & +s277 & -s278, fill=m39) -c1740 = mcdc.cell(+s195 & -s196 & +s278 & -s279, fill=m40) -c1741 = mcdc.cell(+s195 & -s196 & +s279 & -s280, fill=m41) -c1742 = mcdc.cell(+s195 & -s196 & +s280 & -s281, fill=m42) -c1743 = mcdc.cell(+s195 & -s196 & +s281 & -s282, fill=m43) -c1744 = mcdc.cell(+s195 & -s196 & +s282 & -s283, fill=m44) -c1745 = mcdc.cell(+s195 & -s196 & +s283 & -s284, fill=m45) -c1746 = mcdc.cell(+s195 & -s196 & +s284 & -s285, fill=m46) -c1747 = mcdc.cell(+s195 & -s196 & +s285, fill=m47) -c1748 = mcdc.cell(+s196 & -s197 & -s277, fill=m38) -c1749 = mcdc.cell(+s196 & -s197 & +s277 & -s278, fill=m39) -c1750 = mcdc.cell(+s196 & -s197 & +s278 & -s279, fill=m40) -c1751 = mcdc.cell(+s196 & -s197 & +s279 & -s280, fill=m41) -c1752 = mcdc.cell(+s196 & -s197 & +s280 & -s281, fill=m42) -c1753 = mcdc.cell(+s196 & -s197 & +s281 & -s282, fill=m43) -c1754 = mcdc.cell(+s196 & -s197 & +s282 & -s283, fill=m44) -c1755 = mcdc.cell(+s196 & -s197 & +s283 & -s284, fill=m45) -c1756 = mcdc.cell(+s196 & -s197 & +s284 & -s285, fill=m46) -c1757 = mcdc.cell(+s196 & -s197 & +s285, fill=m47) -c1758 = mcdc.cell(+s197 & -s198 & -s277, fill=m38) -c1759 = mcdc.cell(+s197 & -s198 & +s277 & -s278, fill=m39) -c1760 = mcdc.cell(+s197 & -s198 & +s278 & -s279, fill=m40) -c1761 = mcdc.cell(+s197 & -s198 & +s279 & -s280, fill=m41) -c1762 = mcdc.cell(+s197 & -s198 & +s280 & -s281, fill=m42) -c1763 = mcdc.cell(+s197 & -s198 & +s281 & -s282, fill=m43) -c1764 = mcdc.cell(+s197 & -s198 & +s282 & -s283, fill=m44) -c1765 = mcdc.cell(+s197 & -s198 & +s283 & -s284, fill=m45) -c1766 = mcdc.cell(+s197 & -s198 & +s284 & -s285, fill=m46) -c1767 = mcdc.cell(+s197 & -s198 & +s285, fill=m47) -c1768 = mcdc.cell(+s198 & -s199 & -s277, fill=m38) -c1769 = mcdc.cell(+s198 & -s199 & +s277 & -s278, fill=m39) -c1770 = mcdc.cell(+s198 & -s199 & +s278 & -s279, fill=m40) -c1771 = mcdc.cell(+s198 & -s199 & +s279 & -s280, fill=m41) -c1772 = mcdc.cell(+s198 & -s199 & +s280 & -s281, fill=m42) -c1773 = mcdc.cell(+s198 & -s199 & +s281 & -s282, fill=m43) -c1774 = mcdc.cell(+s198 & -s199 & +s282 & -s283, fill=m44) -c1775 = mcdc.cell(+s198 & -s199 & +s283 & -s284, fill=m45) -c1776 = mcdc.cell(+s198 & -s199 & +s284 & -s285, fill=m46) -c1777 = mcdc.cell(+s198 & -s199 & +s285, fill=m47) -c1778 = mcdc.cell(+s199 & -s200 & -s277, fill=m38) -c1779 = mcdc.cell(+s199 & -s200 & +s277 & -s278, fill=m39) -c1780 = mcdc.cell(+s199 & -s200 & +s278 & -s279, fill=m40) -c1781 = mcdc.cell(+s199 & -s200 & +s279 & -s280, fill=m41) -c1782 = mcdc.cell(+s199 & -s200 & +s280 & -s281, fill=m42) -c1783 = mcdc.cell(+s199 & -s200 & +s281 & -s282, fill=m43) -c1784 = mcdc.cell(+s199 & -s200 & +s282 & -s283, fill=m44) -c1785 = mcdc.cell(+s199 & -s200 & +s283 & -s284, fill=m45) -c1786 = mcdc.cell(+s199 & -s200 & +s284 & -s285, fill=m46) -c1787 = mcdc.cell(+s199 & -s200 & +s285, fill=m47) -c1788 = mcdc.cell(+s200 & -s201 & -s277, fill=m38) -c1789 = mcdc.cell(+s200 & -s201 & +s277 & -s278, fill=m39) -c1790 = mcdc.cell(+s200 & -s201 & +s278 & -s279, fill=m40) -c1791 = mcdc.cell(+s200 & -s201 & +s279 & -s280, fill=m41) -c1792 = mcdc.cell(+s200 & -s201 & +s280 & -s281, fill=m42) -c1793 = mcdc.cell(+s200 & -s201 & +s281 & -s282, fill=m43) -c1794 = mcdc.cell(+s200 & -s201 & +s282 & -s283, fill=m44) -c1795 = mcdc.cell(+s200 & -s201 & +s283 & -s284, fill=m45) -c1796 = mcdc.cell(+s200 & -s201 & +s284 & -s285, fill=m46) -c1797 = mcdc.cell(+s200 & -s201 & +s285, fill=m47) -c1798 = mcdc.cell(+s201 & -s202 & -s277, fill=m38) -c1799 = mcdc.cell(+s201 & -s202 & +s277 & -s278, fill=m39) -c1800 = mcdc.cell(+s201 & -s202 & +s278 & -s279, fill=m40) -c1801 = mcdc.cell(+s201 & -s202 & +s279 & -s280, fill=m41) -c1802 = mcdc.cell(+s201 & -s202 & +s280 & -s281, fill=m42) -c1803 = mcdc.cell(+s201 & -s202 & +s281 & -s282, fill=m43) -c1804 = mcdc.cell(+s201 & -s202 & +s282 & -s283, fill=m44) -c1805 = mcdc.cell(+s201 & -s202 & +s283 & -s284, fill=m45) -c1806 = mcdc.cell(+s201 & -s202 & +s284 & -s285, fill=m46) -c1807 = mcdc.cell(+s201 & -s202 & +s285, fill=m47) -c1808 = mcdc.cell(+s202 & -s203 & -s277, fill=m38) -c1809 = mcdc.cell(+s202 & -s203 & +s277 & -s278, fill=m39) -c1810 = mcdc.cell(+s202 & -s203 & +s278 & -s279, fill=m40) -c1811 = mcdc.cell(+s202 & -s203 & +s279 & -s280, fill=m41) -c1812 = mcdc.cell(+s202 & -s203 & +s280 & -s281, fill=m42) -c1813 = mcdc.cell(+s202 & -s203 & +s281 & -s282, fill=m43) -c1814 = mcdc.cell(+s202 & -s203 & +s282 & -s283, fill=m44) -c1815 = mcdc.cell(+s202 & -s203 & +s283 & -s284, fill=m45) -c1816 = mcdc.cell(+s202 & -s203 & +s284 & -s285, fill=m46) -c1817 = mcdc.cell(+s202 & -s203 & +s285, fill=m47) -c1818 = mcdc.cell(+s203 & -s204 & -s277, fill=m38) -c1819 = mcdc.cell(+s203 & -s204 & +s277 & -s278, fill=m39) -c1820 = mcdc.cell(+s203 & -s204 & +s278 & -s279, fill=m40) -c1821 = mcdc.cell(+s203 & -s204 & +s279 & -s280, fill=m41) -c1822 = mcdc.cell(+s203 & -s204 & +s280 & -s281, fill=m42) -c1823 = mcdc.cell(+s203 & -s204 & +s281 & -s282, fill=m43) -c1824 = mcdc.cell(+s203 & -s204 & +s282 & -s283, fill=m44) -c1825 = mcdc.cell(+s203 & -s204 & +s283 & -s284, fill=m45) -c1826 = mcdc.cell(+s203 & -s204 & +s284 & -s285, fill=m46) -c1827 = mcdc.cell(+s203 & -s204 & +s285, fill=m47) -c1828 = mcdc.cell(+s204 & -s205 & -s277, fill=m38) -c1829 = mcdc.cell(+s204 & -s205 & +s277 & -s278, fill=m39) -c1830 = mcdc.cell(+s204 & -s205 & +s278 & -s279, fill=m40) -c1831 = mcdc.cell(+s204 & -s205 & +s279 & -s280, fill=m41) -c1832 = mcdc.cell(+s204 & -s205 & +s280 & -s281, fill=m42) -c1833 = mcdc.cell(+s204 & -s205 & +s281 & -s282, fill=m43) -c1834 = mcdc.cell(+s204 & -s205 & +s282 & -s283, fill=m44) -c1835 = mcdc.cell(+s204 & -s205 & +s283 & -s284, fill=m45) -c1836 = mcdc.cell(+s204 & -s205 & +s284 & -s285, fill=m46) -c1837 = mcdc.cell(+s204 & -s205 & +s285, fill=m47) -c1838 = mcdc.cell(+s205 & -s206 & -s277, fill=m38) -c1839 = mcdc.cell(+s205 & -s206 & +s277 & -s278, fill=m39) -c1840 = mcdc.cell(+s205 & -s206 & +s278 & -s279, fill=m40) -c1841 = mcdc.cell(+s205 & -s206 & +s279 & -s280, fill=m41) -c1842 = mcdc.cell(+s205 & -s206 & +s280 & -s281, fill=m42) -c1843 = mcdc.cell(+s205 & -s206 & +s281 & -s282, fill=m43) -c1844 = mcdc.cell(+s205 & -s206 & +s282 & -s283, fill=m44) -c1845 = mcdc.cell(+s205 & -s206 & +s283 & -s284, fill=m45) -c1846 = mcdc.cell(+s205 & -s206 & +s284 & -s285, fill=m46) -c1847 = mcdc.cell(+s205 & -s206 & +s285, fill=m47) -c1848 = mcdc.cell(+s206 & -s207 & -s277, fill=m38) -c1849 = mcdc.cell(+s206 & -s207 & +s277 & -s278, fill=m39) -c1850 = mcdc.cell(+s206 & -s207 & +s278 & -s279, fill=m40) -c1851 = mcdc.cell(+s206 & -s207 & +s279 & -s280, fill=m41) -c1852 = mcdc.cell(+s206 & -s207 & +s280 & -s281, fill=m42) -c1853 = mcdc.cell(+s206 & -s207 & +s281 & -s282, fill=m43) -c1854 = mcdc.cell(+s206 & -s207 & +s282 & -s283, fill=m44) -c1855 = mcdc.cell(+s206 & -s207 & +s283 & -s284, fill=m45) -c1856 = mcdc.cell(+s206 & -s207 & +s284 & -s285, fill=m46) -c1857 = mcdc.cell(+s206 & -s207 & +s285, fill=m47) -c1858 = mcdc.cell(+s207 & -s208 & -s277, fill=m38) -c1859 = mcdc.cell(+s207 & -s208 & +s277 & -s278, fill=m39) -c1860 = mcdc.cell(+s207 & -s208 & +s278 & -s279, fill=m40) -c1861 = mcdc.cell(+s207 & -s208 & +s279 & -s280, fill=m41) -c1862 = mcdc.cell(+s207 & -s208 & +s280 & -s281, fill=m42) -c1863 = mcdc.cell(+s207 & -s208 & +s281 & -s282, fill=m43) -c1864 = mcdc.cell(+s207 & -s208 & +s282 & -s283, fill=m44) -c1865 = mcdc.cell(+s207 & -s208 & +s283 & -s284, fill=m45) -c1866 = mcdc.cell(+s207 & -s208 & +s284 & -s285, fill=m46) -c1867 = mcdc.cell(+s207 & -s208 & +s285, fill=m47) -c1868 = mcdc.cell(+s208 & -s209 & -s277, fill=m38) -c1869 = mcdc.cell(+s208 & -s209 & +s277 & -s278, fill=m39) -c1870 = mcdc.cell(+s208 & -s209 & +s278 & -s279, fill=m40) -c1871 = mcdc.cell(+s208 & -s209 & +s279 & -s280, fill=m41) -c1872 = mcdc.cell(+s208 & -s209 & +s280 & -s281, fill=m42) -c1873 = mcdc.cell(+s208 & -s209 & +s281 & -s282, fill=m43) -c1874 = mcdc.cell(+s208 & -s209 & +s282 & -s283, fill=m44) -c1875 = mcdc.cell(+s208 & -s209 & +s283 & -s284, fill=m45) -c1876 = mcdc.cell(+s208 & -s209 & +s284 & -s285, fill=m46) -c1877 = mcdc.cell(+s208 & -s209 & +s285, fill=m47) -c1878 = mcdc.cell(+s209 & -s210 & -s277, fill=m38) -c1879 = mcdc.cell(+s209 & -s210 & +s277 & -s278, fill=m39) -c1880 = mcdc.cell(+s209 & -s210 & +s278 & -s279, fill=m40) -c1881 = mcdc.cell(+s209 & -s210 & +s279 & -s280, fill=m41) -c1882 = mcdc.cell(+s209 & -s210 & +s280 & -s281, fill=m42) -c1883 = mcdc.cell(+s209 & -s210 & +s281 & -s282, fill=m43) -c1884 = mcdc.cell(+s209 & -s210 & +s282 & -s283, fill=m44) -c1885 = mcdc.cell(+s209 & -s210 & +s283 & -s284, fill=m45) -c1886 = mcdc.cell(+s209 & -s210 & +s284 & -s285, fill=m46) -c1887 = mcdc.cell(+s209 & -s210 & +s285, fill=m47) -c1888 = mcdc.cell(+s210 & -s211 & -s277, fill=m38) -c1889 = mcdc.cell(+s210 & -s211 & +s277 & -s278, fill=m39) -c1890 = mcdc.cell(+s210 & -s211 & +s278 & -s279, fill=m40) -c1891 = mcdc.cell(+s210 & -s211 & +s279 & -s280, fill=m41) -c1892 = mcdc.cell(+s210 & -s211 & +s280 & -s281, fill=m42) -c1893 = mcdc.cell(+s210 & -s211 & +s281 & -s282, fill=m43) -c1894 = mcdc.cell(+s210 & -s211 & +s282 & -s283, fill=m44) -c1895 = mcdc.cell(+s210 & -s211 & +s283 & -s284, fill=m45) -c1896 = mcdc.cell(+s210 & -s211 & +s284 & -s285, fill=m46) -c1897 = mcdc.cell(+s210 & -s211 & +s285, fill=m47) -c1898 = mcdc.cell(+s211 & -s212 & -s277, fill=m38) -c1899 = mcdc.cell(+s211 & -s212 & +s277 & -s278, fill=m39) -c1900 = mcdc.cell(+s211 & -s212 & +s278 & -s279, fill=m40) -c1901 = mcdc.cell(+s211 & -s212 & +s279 & -s280, fill=m41) -c1902 = mcdc.cell(+s211 & -s212 & +s280 & -s281, fill=m42) -c1903 = mcdc.cell(+s211 & -s212 & +s281 & -s282, fill=m43) -c1904 = mcdc.cell(+s211 & -s212 & +s282 & -s283, fill=m44) -c1905 = mcdc.cell(+s211 & -s212 & +s283 & -s284, fill=m45) -c1906 = mcdc.cell(+s211 & -s212 & +s284 & -s285, fill=m46) -c1907 = mcdc.cell(+s211 & -s212 & +s285, fill=m47) -c1908 = mcdc.cell(+s212 & -s213 & -s277, fill=m38) -c1909 = mcdc.cell(+s212 & -s213 & +s277 & -s278, fill=m39) -c1910 = mcdc.cell(+s212 & -s213 & +s278 & -s279, fill=m40) -c1911 = mcdc.cell(+s212 & -s213 & +s279 & -s280, fill=m41) -c1912 = mcdc.cell(+s212 & -s213 & +s280 & -s281, fill=m42) -c1913 = mcdc.cell(+s212 & -s213 & +s281 & -s282, fill=m43) -c1914 = mcdc.cell(+s212 & -s213 & +s282 & -s283, fill=m44) -c1915 = mcdc.cell(+s212 & -s213 & +s283 & -s284, fill=m45) -c1916 = mcdc.cell(+s212 & -s213 & +s284 & -s285, fill=m46) -c1917 = mcdc.cell(+s212 & -s213 & +s285, fill=m47) -c1918 = mcdc.cell(+s213 & -s214 & -s277, fill=m38) -c1919 = mcdc.cell(+s213 & -s214 & +s277 & -s278, fill=m39) -c1920 = mcdc.cell(+s213 & -s214 & +s278 & -s279, fill=m40) -c1921 = mcdc.cell(+s213 & -s214 & +s279 & -s280, fill=m41) -c1922 = mcdc.cell(+s213 & -s214 & +s280 & -s281, fill=m42) -c1923 = mcdc.cell(+s213 & -s214 & +s281 & -s282, fill=m43) -c1924 = mcdc.cell(+s213 & -s214 & +s282 & -s283, fill=m44) -c1925 = mcdc.cell(+s213 & -s214 & +s283 & -s284, fill=m45) -c1926 = mcdc.cell(+s213 & -s214 & +s284 & -s285, fill=m46) -c1927 = mcdc.cell(+s213 & -s214 & +s285, fill=m47) -c1928 = mcdc.cell(+s214 & -s215 & -s277, fill=m38) -c1929 = mcdc.cell(+s214 & -s215 & +s277 & -s278, fill=m39) -c1930 = mcdc.cell(+s214 & -s215 & +s278 & -s279, fill=m40) -c1931 = mcdc.cell(+s214 & -s215 & +s279 & -s280, fill=m41) -c1932 = mcdc.cell(+s214 & -s215 & +s280 & -s281, fill=m42) -c1933 = mcdc.cell(+s214 & -s215 & +s281 & -s282, fill=m43) -c1934 = mcdc.cell(+s214 & -s215 & +s282 & -s283, fill=m44) -c1935 = mcdc.cell(+s214 & -s215 & +s283 & -s284, fill=m45) -c1936 = mcdc.cell(+s214 & -s215 & +s284 & -s285, fill=m46) -c1937 = mcdc.cell(+s214 & -s215 & +s285, fill=m47) -c1938 = mcdc.cell(+s215 & -s216 & -s277, fill=m38) -c1939 = mcdc.cell(+s215 & -s216 & +s277 & -s278, fill=m39) -c1940 = mcdc.cell(+s215 & -s216 & +s278 & -s279, fill=m40) -c1941 = mcdc.cell(+s215 & -s216 & +s279 & -s280, fill=m41) -c1942 = mcdc.cell(+s215 & -s216 & +s280 & -s281, fill=m42) -c1943 = mcdc.cell(+s215 & -s216 & +s281 & -s282, fill=m43) -c1944 = mcdc.cell(+s215 & -s216 & +s282 & -s283, fill=m44) -c1945 = mcdc.cell(+s215 & -s216 & +s283 & -s284, fill=m45) -c1946 = mcdc.cell(+s215 & -s216 & +s284 & -s285, fill=m46) -c1947 = mcdc.cell(+s215 & -s216 & +s285, fill=m47) -c1948 = mcdc.cell(+s216 & -s217 & -s277, fill=m38) -c1949 = mcdc.cell(+s216 & -s217 & +s277 & -s278, fill=m39) -c1950 = mcdc.cell(+s216 & -s217 & +s278 & -s279, fill=m40) -c1951 = mcdc.cell(+s216 & -s217 & +s279 & -s280, fill=m41) -c1952 = mcdc.cell(+s216 & -s217 & +s280 & -s281, fill=m42) -c1953 = mcdc.cell(+s216 & -s217 & +s281 & -s282, fill=m43) -c1954 = mcdc.cell(+s216 & -s217 & +s282 & -s283, fill=m44) -c1955 = mcdc.cell(+s216 & -s217 & +s283 & -s284, fill=m45) -c1956 = mcdc.cell(+s216 & -s217 & +s284 & -s285, fill=m46) -c1957 = mcdc.cell(+s216 & -s217 & +s285, fill=m47) -c1958 = mcdc.cell(+s217 & -s218 & -s277, fill=m38) -c1959 = mcdc.cell(+s217 & -s218 & +s277 & -s278, fill=m39) -c1960 = mcdc.cell(+s217 & -s218 & +s278 & -s279, fill=m40) -c1961 = mcdc.cell(+s217 & -s218 & +s279 & -s280, fill=m41) -c1962 = mcdc.cell(+s217 & -s218 & +s280 & -s281, fill=m42) -c1963 = mcdc.cell(+s217 & -s218 & +s281 & -s282, fill=m43) -c1964 = mcdc.cell(+s217 & -s218 & +s282 & -s283, fill=m44) -c1965 = mcdc.cell(+s217 & -s218 & +s283 & -s284, fill=m45) -c1966 = mcdc.cell(+s217 & -s218 & +s284 & -s285, fill=m46) -c1967 = mcdc.cell(+s217 & -s218 & +s285, fill=m47) -c1968 = mcdc.cell(+s218 & -s219 & -s277, fill=m38) -c1969 = mcdc.cell(+s218 & -s219 & +s277 & -s278, fill=m39) -c1970 = mcdc.cell(+s218 & -s219 & +s278 & -s279, fill=m40) -c1971 = mcdc.cell(+s218 & -s219 & +s279 & -s280, fill=m41) -c1972 = mcdc.cell(+s218 & -s219 & +s280 & -s281, fill=m42) -c1973 = mcdc.cell(+s218 & -s219 & +s281 & -s282, fill=m43) -c1974 = mcdc.cell(+s218 & -s219 & +s282 & -s283, fill=m44) -c1975 = mcdc.cell(+s218 & -s219 & +s283 & -s284, fill=m45) -c1976 = mcdc.cell(+s218 & -s219 & +s284 & -s285, fill=m46) -c1977 = mcdc.cell(+s218 & -s219 & +s285, fill=m47) -c1978 = mcdc.cell(+s219 & -s220 & -s277, fill=m38) -c1979 = mcdc.cell(+s219 & -s220 & +s277 & -s278, fill=m39) -c1980 = mcdc.cell(+s219 & -s220 & +s278 & -s279, fill=m40) -c1981 = mcdc.cell(+s219 & -s220 & +s279 & -s280, fill=m41) -c1982 = mcdc.cell(+s219 & -s220 & +s280 & -s281, fill=m42) -c1983 = mcdc.cell(+s219 & -s220 & +s281 & -s282, fill=m43) -c1984 = mcdc.cell(+s219 & -s220 & +s282 & -s283, fill=m44) -c1985 = mcdc.cell(+s219 & -s220 & +s283 & -s284, fill=m45) -c1986 = mcdc.cell(+s219 & -s220 & +s284 & -s285, fill=m46) -c1987 = mcdc.cell(+s219 & -s220 & +s285, fill=m47) -c1988 = mcdc.cell(+s220 & -s221 & -s277, fill=m38) -c1989 = mcdc.cell(+s220 & -s221 & +s277 & -s278, fill=m39) -c1990 = mcdc.cell(+s220 & -s221 & +s278 & -s279, fill=m40) -c1991 = mcdc.cell(+s220 & -s221 & +s279 & -s280, fill=m41) -c1992 = mcdc.cell(+s220 & -s221 & +s280 & -s281, fill=m42) -c1993 = mcdc.cell(+s220 & -s221 & +s281 & -s282, fill=m43) -c1994 = mcdc.cell(+s220 & -s221 & +s282 & -s283, fill=m44) -c1995 = mcdc.cell(+s220 & -s221 & +s283 & -s284, fill=m45) -c1996 = mcdc.cell(+s220 & -s221 & +s284 & -s285, fill=m46) -c1997 = mcdc.cell(+s220 & -s221 & +s285, fill=m47) -c1998 = mcdc.cell(+s221 & -s222 & -s277, fill=m38) -c1999 = mcdc.cell(+s221 & -s222 & +s277 & -s278, fill=m39) -c2000 = mcdc.cell(+s221 & -s222 & +s278 & -s279, fill=m40) -c2001 = mcdc.cell(+s221 & -s222 & +s279 & -s280, fill=m41) -c2002 = mcdc.cell(+s221 & -s222 & +s280 & -s281, fill=m42) -c2003 = mcdc.cell(+s221 & -s222 & +s281 & -s282, fill=m43) -c2004 = mcdc.cell(+s221 & -s222 & +s282 & -s283, fill=m44) -c2005 = mcdc.cell(+s221 & -s222 & +s283 & -s284, fill=m45) -c2006 = mcdc.cell(+s221 & -s222 & +s284 & -s285, fill=m46) -c2007 = mcdc.cell(+s221 & -s222 & +s285, fill=m47) -c2008 = mcdc.cell(+s222 & -s223 & -s277, fill=m38) -c2009 = mcdc.cell(+s222 & -s223 & +s277 & -s278, fill=m39) -c2010 = mcdc.cell(+s222 & -s223 & +s278 & -s279, fill=m40) -c2011 = mcdc.cell(+s222 & -s223 & +s279 & -s280, fill=m41) -c2012 = mcdc.cell(+s222 & -s223 & +s280 & -s281, fill=m42) -c2013 = mcdc.cell(+s222 & -s223 & +s281 & -s282, fill=m43) -c2014 = mcdc.cell(+s222 & -s223 & +s282 & -s283, fill=m44) -c2015 = mcdc.cell(+s222 & -s223 & +s283 & -s284, fill=m45) -c2016 = mcdc.cell(+s222 & -s223 & +s284 & -s285, fill=m46) -c2017 = mcdc.cell(+s222 & -s223 & +s285, fill=m47) -c2018 = mcdc.cell(+s223 & -s224 & -s277, fill=m38) -c2019 = mcdc.cell(+s223 & -s224 & +s277 & -s278, fill=m39) -c2020 = mcdc.cell(+s223 & -s224 & +s278 & -s279, fill=m40) -c2021 = mcdc.cell(+s223 & -s224 & +s279 & -s280, fill=m41) -c2022 = mcdc.cell(+s223 & -s224 & +s280 & -s281, fill=m42) -c2023 = mcdc.cell(+s223 & -s224 & +s281 & -s282, fill=m43) -c2024 = mcdc.cell(+s223 & -s224 & +s282 & -s283, fill=m44) -c2025 = mcdc.cell(+s223 & -s224 & +s283 & -s284, fill=m45) -c2026 = mcdc.cell(+s223 & -s224 & +s284 & -s285, fill=m46) -c2027 = mcdc.cell(+s223 & -s224 & +s285, fill=m47) -c2028 = mcdc.cell(+s224 & -s225 & -s277, fill=m38) -c2029 = mcdc.cell(+s224 & -s225 & +s277 & -s278, fill=m39) -c2030 = mcdc.cell(+s224 & -s225 & +s278 & -s279, fill=m40) -c2031 = mcdc.cell(+s224 & -s225 & +s279 & -s280, fill=m41) -c2032 = mcdc.cell(+s224 & -s225 & +s280 & -s281, fill=m42) -c2033 = mcdc.cell(+s224 & -s225 & +s281 & -s282, fill=m43) -c2034 = mcdc.cell(+s224 & -s225 & +s282 & -s283, fill=m44) -c2035 = mcdc.cell(+s224 & -s225 & +s283 & -s284, fill=m45) -c2036 = mcdc.cell(+s224 & -s225 & +s284 & -s285, fill=m46) -c2037 = mcdc.cell(+s224 & -s225 & +s285, fill=m47) -c2038 = mcdc.cell(+s225 & -s226 & -s277, fill=m38) -c2039 = mcdc.cell(+s225 & -s226 & +s277 & -s278, fill=m39) -c2040 = mcdc.cell(+s225 & -s226 & +s278 & -s279, fill=m40) -c2041 = mcdc.cell(+s225 & -s226 & +s279 & -s280, fill=m41) -c2042 = mcdc.cell(+s225 & -s226 & +s280 & -s281, fill=m42) -c2043 = mcdc.cell(+s225 & -s226 & +s281 & -s282, fill=m43) -c2044 = mcdc.cell(+s225 & -s226 & +s282 & -s283, fill=m44) -c2045 = mcdc.cell(+s225 & -s226 & +s283 & -s284, fill=m45) -c2046 = mcdc.cell(+s225 & -s226 & +s284 & -s285, fill=m46) -c2047 = mcdc.cell(+s225 & -s226 & +s285, fill=m47) -c2048 = mcdc.cell(+s226 & -s227 & -s277, fill=m38) -c2049 = mcdc.cell(+s226 & -s227 & +s277 & -s278, fill=m39) -c2050 = mcdc.cell(+s226 & -s227 & +s278 & -s279, fill=m40) -c2051 = mcdc.cell(+s226 & -s227 & +s279 & -s280, fill=m41) -c2052 = mcdc.cell(+s226 & -s227 & +s280 & -s281, fill=m42) -c2053 = mcdc.cell(+s226 & -s227 & +s281 & -s282, fill=m43) -c2054 = mcdc.cell(+s226 & -s227 & +s282 & -s283, fill=m44) -c2055 = mcdc.cell(+s226 & -s227 & +s283 & -s284, fill=m45) -c2056 = mcdc.cell(+s226 & -s227 & +s284 & -s285, fill=m46) -c2057 = mcdc.cell(+s226 & -s227 & +s285, fill=m47) -c2058 = mcdc.cell(+s227 & -s228 & -s277, fill=m38) -c2059 = mcdc.cell(+s227 & -s228 & +s277 & -s278, fill=m39) -c2060 = mcdc.cell(+s227 & -s228 & +s278 & -s279, fill=m40) -c2061 = mcdc.cell(+s227 & -s228 & +s279 & -s280, fill=m41) -c2062 = mcdc.cell(+s227 & -s228 & +s280 & -s281, fill=m42) -c2063 = mcdc.cell(+s227 & -s228 & +s281 & -s282, fill=m43) -c2064 = mcdc.cell(+s227 & -s228 & +s282 & -s283, fill=m44) -c2065 = mcdc.cell(+s227 & -s228 & +s283 & -s284, fill=m45) -c2066 = mcdc.cell(+s227 & -s228 & +s284 & -s285, fill=m46) -c2067 = mcdc.cell(+s227 & -s228 & +s285, fill=m47) -c2068 = mcdc.cell(+s228 & -s229 & -s277, fill=m38) -c2069 = mcdc.cell(+s228 & -s229 & +s277 & -s278, fill=m39) -c2070 = mcdc.cell(+s228 & -s229 & +s278 & -s279, fill=m40) -c2071 = mcdc.cell(+s228 & -s229 & +s279 & -s280, fill=m41) -c2072 = mcdc.cell(+s228 & -s229 & +s280 & -s281, fill=m42) -c2073 = mcdc.cell(+s228 & -s229 & +s281 & -s282, fill=m43) -c2074 = mcdc.cell(+s228 & -s229 & +s282 & -s283, fill=m44) -c2075 = mcdc.cell(+s228 & -s229 & +s283 & -s284, fill=m45) -c2076 = mcdc.cell(+s228 & -s229 & +s284 & -s285, fill=m46) -c2077 = mcdc.cell(+s228 & -s229 & +s285, fill=m47) -c2078 = mcdc.cell(+s229 & -s230 & -s277, fill=m38) -c2079 = mcdc.cell(+s229 & -s230 & +s277 & -s278, fill=m39) -c2080 = mcdc.cell(+s229 & -s230 & +s278 & -s279, fill=m40) -c2081 = mcdc.cell(+s229 & -s230 & +s279 & -s280, fill=m41) -c2082 = mcdc.cell(+s229 & -s230 & +s280 & -s281, fill=m42) -c2083 = mcdc.cell(+s229 & -s230 & +s281 & -s282, fill=m43) -c2084 = mcdc.cell(+s229 & -s230 & +s282 & -s283, fill=m44) -c2085 = mcdc.cell(+s229 & -s230 & +s283 & -s284, fill=m45) -c2086 = mcdc.cell(+s229 & -s230 & +s284 & -s285, fill=m46) -c2087 = mcdc.cell(+s229 & -s230 & +s285, fill=m47) -c2088 = mcdc.cell(+s230 & -s231 & -s277, fill=m38) -c2089 = mcdc.cell(+s230 & -s231 & +s277 & -s278, fill=m39) -c2090 = mcdc.cell(+s230 & -s231 & +s278 & -s279, fill=m40) -c2091 = mcdc.cell(+s230 & -s231 & +s279 & -s280, fill=m41) -c2092 = mcdc.cell(+s230 & -s231 & +s280 & -s281, fill=m42) -c2093 = mcdc.cell(+s230 & -s231 & +s281 & -s282, fill=m43) -c2094 = mcdc.cell(+s230 & -s231 & +s282 & -s283, fill=m44) -c2095 = mcdc.cell(+s230 & -s231 & +s283 & -s284, fill=m45) -c2096 = mcdc.cell(+s230 & -s231 & +s284 & -s285, fill=m46) -c2097 = mcdc.cell(+s230 & -s231 & +s285, fill=m47) -c2098 = mcdc.cell(+s231 & -s232 & -s277, fill=m38) -c2099 = mcdc.cell(+s231 & -s232 & +s277 & -s278, fill=m39) -c2100 = mcdc.cell(+s231 & -s232 & +s278 & -s279, fill=m40) -c2101 = mcdc.cell(+s231 & -s232 & +s279 & -s280, fill=m41) -c2102 = mcdc.cell(+s231 & -s232 & +s280 & -s281, fill=m42) -c2103 = mcdc.cell(+s231 & -s232 & +s281 & -s282, fill=m43) -c2104 = mcdc.cell(+s231 & -s232 & +s282 & -s283, fill=m44) -c2105 = mcdc.cell(+s231 & -s232 & +s283 & -s284, fill=m45) -c2106 = mcdc.cell(+s231 & -s232 & +s284 & -s285, fill=m46) -c2107 = mcdc.cell(+s231 & -s232 & +s285, fill=m47) -c2108 = mcdc.cell(+s232 & -s233 & -s277, fill=m38) -c2109 = mcdc.cell(+s232 & -s233 & +s277 & -s278, fill=m39) -c2110 = mcdc.cell(+s232 & -s233 & +s278 & -s279, fill=m40) -c2111 = mcdc.cell(+s232 & -s233 & +s279 & -s280, fill=m41) -c2112 = mcdc.cell(+s232 & -s233 & +s280 & -s281, fill=m42) -c2113 = mcdc.cell(+s232 & -s233 & +s281 & -s282, fill=m43) -c2114 = mcdc.cell(+s232 & -s233 & +s282 & -s283, fill=m44) -c2115 = mcdc.cell(+s232 & -s233 & +s283 & -s284, fill=m45) -c2116 = mcdc.cell(+s232 & -s233 & +s284 & -s285, fill=m46) -c2117 = mcdc.cell(+s232 & -s233 & +s285, fill=m47) -c2118 = mcdc.cell(+s233 & -s234 & -s277, fill=m38) -c2119 = mcdc.cell(+s233 & -s234 & +s277 & -s278, fill=m39) -c2120 = mcdc.cell(+s233 & -s234 & +s278 & -s279, fill=m40) -c2121 = mcdc.cell(+s233 & -s234 & +s279 & -s280, fill=m41) -c2122 = mcdc.cell(+s233 & -s234 & +s280 & -s281, fill=m42) -c2123 = mcdc.cell(+s233 & -s234 & +s281 & -s282, fill=m43) -c2124 = mcdc.cell(+s233 & -s234 & +s282 & -s283, fill=m44) -c2125 = mcdc.cell(+s233 & -s234 & +s283 & -s284, fill=m45) -c2126 = mcdc.cell(+s233 & -s234 & +s284 & -s285, fill=m46) -c2127 = mcdc.cell(+s233 & -s234 & +s285, fill=m47) -c2128 = mcdc.cell(+s234 & -s235 & -s277, fill=m38) -c2129 = mcdc.cell(+s234 & -s235 & +s277 & -s278, fill=m39) -c2130 = mcdc.cell(+s234 & -s235 & +s278 & -s279, fill=m40) -c2131 = mcdc.cell(+s234 & -s235 & +s279 & -s280, fill=m41) -c2132 = mcdc.cell(+s234 & -s235 & +s280 & -s281, fill=m42) -c2133 = mcdc.cell(+s234 & -s235 & +s281 & -s282, fill=m43) -c2134 = mcdc.cell(+s234 & -s235 & +s282 & -s283, fill=m44) -c2135 = mcdc.cell(+s234 & -s235 & +s283 & -s284, fill=m45) -c2136 = mcdc.cell(+s234 & -s235 & +s284 & -s285, fill=m46) -c2137 = mcdc.cell(+s234 & -s235 & +s285, fill=m47) -c2138 = mcdc.cell(+s235 & -s236 & -s277, fill=m38) -c2139 = mcdc.cell(+s235 & -s236 & +s277 & -s278, fill=m39) -c2140 = mcdc.cell(+s235 & -s236 & +s278 & -s279, fill=m40) -c2141 = mcdc.cell(+s235 & -s236 & +s279 & -s280, fill=m41) -c2142 = mcdc.cell(+s235 & -s236 & +s280 & -s281, fill=m42) -c2143 = mcdc.cell(+s235 & -s236 & +s281 & -s282, fill=m43) -c2144 = mcdc.cell(+s235 & -s236 & +s282 & -s283, fill=m44) -c2145 = mcdc.cell(+s235 & -s236 & +s283 & -s284, fill=m45) -c2146 = mcdc.cell(+s235 & -s236 & +s284 & -s285, fill=m46) -c2147 = mcdc.cell(+s235 & -s236 & +s285, fill=m47) -c2148 = mcdc.cell(+s236 & -s237 & -s277, fill=m38) -c2149 = mcdc.cell(+s236 & -s237 & +s277 & -s278, fill=m39) -c2150 = mcdc.cell(+s236 & -s237 & +s278 & -s279, fill=m40) -c2151 = mcdc.cell(+s236 & -s237 & +s279 & -s280, fill=m41) -c2152 = mcdc.cell(+s236 & -s237 & +s280 & -s281, fill=m42) -c2153 = mcdc.cell(+s236 & -s237 & +s281 & -s282, fill=m43) -c2154 = mcdc.cell(+s236 & -s237 & +s282 & -s283, fill=m44) -c2155 = mcdc.cell(+s236 & -s237 & +s283 & -s284, fill=m45) -c2156 = mcdc.cell(+s236 & -s237 & +s284 & -s285, fill=m46) -c2157 = mcdc.cell(+s236 & -s237 & +s285, fill=m47) -c2158 = mcdc.cell(+s237 & -s238 & -s277, fill=m38) -c2159 = mcdc.cell(+s237 & -s238 & +s277 & -s278, fill=m39) -c2160 = mcdc.cell(+s237 & -s238 & +s278 & -s279, fill=m40) -c2161 = mcdc.cell(+s237 & -s238 & +s279 & -s280, fill=m41) -c2162 = mcdc.cell(+s237 & -s238 & +s280 & -s281, fill=m42) -c2163 = mcdc.cell(+s237 & -s238 & +s281 & -s282, fill=m43) -c2164 = mcdc.cell(+s237 & -s238 & +s282 & -s283, fill=m44) -c2165 = mcdc.cell(+s237 & -s238 & +s283 & -s284, fill=m45) -c2166 = mcdc.cell(+s237 & -s238 & +s284 & -s285, fill=m46) -c2167 = mcdc.cell(+s237 & -s238 & +s285, fill=m47) -c2168 = mcdc.cell(+s238 & -s239 & -s277, fill=m38) -c2169 = mcdc.cell(+s238 & -s239 & +s277 & -s278, fill=m39) -c2170 = mcdc.cell(+s238 & -s239 & +s278 & -s279, fill=m40) -c2171 = mcdc.cell(+s238 & -s239 & +s279 & -s280, fill=m41) -c2172 = mcdc.cell(+s238 & -s239 & +s280 & -s281, fill=m42) -c2173 = mcdc.cell(+s238 & -s239 & +s281 & -s282, fill=m43) -c2174 = mcdc.cell(+s238 & -s239 & +s282 & -s283, fill=m44) -c2175 = mcdc.cell(+s238 & -s239 & +s283 & -s284, fill=m45) -c2176 = mcdc.cell(+s238 & -s239 & +s284 & -s285, fill=m46) -c2177 = mcdc.cell(+s238 & -s239 & +s285, fill=m47) -c2178 = mcdc.cell(+s239 & -s240 & -s277, fill=m38) -c2179 = mcdc.cell(+s239 & -s240 & +s277 & -s278, fill=m39) -c2180 = mcdc.cell(+s239 & -s240 & +s278 & -s279, fill=m40) -c2181 = mcdc.cell(+s239 & -s240 & +s279 & -s280, fill=m41) -c2182 = mcdc.cell(+s239 & -s240 & +s280 & -s281, fill=m42) -c2183 = mcdc.cell(+s239 & -s240 & +s281 & -s282, fill=m43) -c2184 = mcdc.cell(+s239 & -s240 & +s282 & -s283, fill=m44) -c2185 = mcdc.cell(+s239 & -s240 & +s283 & -s284, fill=m45) -c2186 = mcdc.cell(+s239 & -s240 & +s284 & -s285, fill=m46) -c2187 = mcdc.cell(+s239 & -s240 & +s285, fill=m47) -c2188 = mcdc.cell(+s240 & -s241 & -s277, fill=m38) -c2189 = mcdc.cell(+s240 & -s241 & +s277 & -s278, fill=m39) -c2190 = mcdc.cell(+s240 & -s241 & +s278 & -s279, fill=m40) -c2191 = mcdc.cell(+s240 & -s241 & +s279 & -s280, fill=m41) -c2192 = mcdc.cell(+s240 & -s241 & +s280 & -s281, fill=m42) -c2193 = mcdc.cell(+s240 & -s241 & +s281 & -s282, fill=m43) -c2194 = mcdc.cell(+s240 & -s241 & +s282 & -s283, fill=m44) -c2195 = mcdc.cell(+s240 & -s241 & +s283 & -s284, fill=m45) -c2196 = mcdc.cell(+s240 & -s241 & +s284 & -s285, fill=m46) -c2197 = mcdc.cell(+s240 & -s241 & +s285, fill=m47) -c2198 = mcdc.cell(+s241 & -s242 & -s277, fill=m38) -c2199 = mcdc.cell(+s241 & -s242 & +s277 & -s278, fill=m39) -c2200 = mcdc.cell(+s241 & -s242 & +s278 & -s279, fill=m40) -c2201 = mcdc.cell(+s241 & -s242 & +s279 & -s280, fill=m41) -c2202 = mcdc.cell(+s241 & -s242 & +s280 & -s281, fill=m42) -c2203 = mcdc.cell(+s241 & -s242 & +s281 & -s282, fill=m43) -c2204 = mcdc.cell(+s241 & -s242 & +s282 & -s283, fill=m44) -c2205 = mcdc.cell(+s241 & -s242 & +s283 & -s284, fill=m45) -c2206 = mcdc.cell(+s241 & -s242 & +s284 & -s285, fill=m46) -c2207 = mcdc.cell(+s241 & -s242 & +s285, fill=m47) -c2208 = mcdc.cell(+s242 & -s243 & -s277, fill=m38) -c2209 = mcdc.cell(+s242 & -s243 & +s277 & -s278, fill=m39) -c2210 = mcdc.cell(+s242 & -s243 & +s278 & -s279, fill=m40) -c2211 = mcdc.cell(+s242 & -s243 & +s279 & -s280, fill=m41) -c2212 = mcdc.cell(+s242 & -s243 & +s280 & -s281, fill=m42) -c2213 = mcdc.cell(+s242 & -s243 & +s281 & -s282, fill=m43) -c2214 = mcdc.cell(+s242 & -s243 & +s282 & -s283, fill=m44) -c2215 = mcdc.cell(+s242 & -s243 & +s283 & -s284, fill=m45) -c2216 = mcdc.cell(+s242 & -s243 & +s284 & -s285, fill=m46) -c2217 = mcdc.cell(+s242 & -s243 & +s285, fill=m47) -c2218 = mcdc.cell(+s243 & -s244 & -s277, fill=m38) -c2219 = mcdc.cell(+s243 & -s244 & +s277 & -s278, fill=m39) -c2220 = mcdc.cell(+s243 & -s244 & +s278 & -s279, fill=m40) -c2221 = mcdc.cell(+s243 & -s244 & +s279 & -s280, fill=m41) -c2222 = mcdc.cell(+s243 & -s244 & +s280 & -s281, fill=m42) -c2223 = mcdc.cell(+s243 & -s244 & +s281 & -s282, fill=m43) -c2224 = mcdc.cell(+s243 & -s244 & +s282 & -s283, fill=m44) -c2225 = mcdc.cell(+s243 & -s244 & +s283 & -s284, fill=m45) -c2226 = mcdc.cell(+s243 & -s244 & +s284 & -s285, fill=m46) -c2227 = mcdc.cell(+s243 & -s244 & +s285, fill=m47) -c2228 = mcdc.cell(+s244 & -s245 & -s277, fill=m38) -c2229 = mcdc.cell(+s244 & -s245 & +s277 & -s278, fill=m39) -c2230 = mcdc.cell(+s244 & -s245 & +s278 & -s279, fill=m40) -c2231 = mcdc.cell(+s244 & -s245 & +s279 & -s280, fill=m41) -c2232 = mcdc.cell(+s244 & -s245 & +s280 & -s281, fill=m42) -c2233 = mcdc.cell(+s244 & -s245 & +s281 & -s282, fill=m43) -c2234 = mcdc.cell(+s244 & -s245 & +s282 & -s283, fill=m44) -c2235 = mcdc.cell(+s244 & -s245 & +s283 & -s284, fill=m45) -c2236 = mcdc.cell(+s244 & -s245 & +s284 & -s285, fill=m46) -c2237 = mcdc.cell(+s244 & -s245 & +s285, fill=m47) -c2238 = mcdc.cell(+s245 & -s246 & -s277, fill=m38) -c2239 = mcdc.cell(+s245 & -s246 & +s277 & -s278, fill=m39) -c2240 = mcdc.cell(+s245 & -s246 & +s278 & -s279, fill=m40) -c2241 = mcdc.cell(+s245 & -s246 & +s279 & -s280, fill=m41) -c2242 = mcdc.cell(+s245 & -s246 & +s280 & -s281, fill=m42) -c2243 = mcdc.cell(+s245 & -s246 & +s281 & -s282, fill=m43) -c2244 = mcdc.cell(+s245 & -s246 & +s282 & -s283, fill=m44) -c2245 = mcdc.cell(+s245 & -s246 & +s283 & -s284, fill=m45) -c2246 = mcdc.cell(+s245 & -s246 & +s284 & -s285, fill=m46) -c2247 = mcdc.cell(+s245 & -s246 & +s285, fill=m47) -c2248 = mcdc.cell(+s246 & -s247 & -s277, fill=m38) -c2249 = mcdc.cell(+s246 & -s247 & +s277 & -s278, fill=m39) -c2250 = mcdc.cell(+s246 & -s247 & +s278 & -s279, fill=m40) -c2251 = mcdc.cell(+s246 & -s247 & +s279 & -s280, fill=m41) -c2252 = mcdc.cell(+s246 & -s247 & +s280 & -s281, fill=m42) -c2253 = mcdc.cell(+s246 & -s247 & +s281 & -s282, fill=m43) -c2254 = mcdc.cell(+s246 & -s247 & +s282 & -s283, fill=m44) -c2255 = mcdc.cell(+s246 & -s247 & +s283 & -s284, fill=m45) -c2256 = mcdc.cell(+s246 & -s247 & +s284 & -s285, fill=m46) -c2257 = mcdc.cell(+s246 & -s247 & +s285, fill=m47) -c2258 = mcdc.cell(+s247 & -s248 & -s277, fill=m38) -c2259 = mcdc.cell(+s247 & -s248 & +s277 & -s278, fill=m39) -c2260 = mcdc.cell(+s247 & -s248 & +s278 & -s279, fill=m40) -c2261 = mcdc.cell(+s247 & -s248 & +s279 & -s280, fill=m41) -c2262 = mcdc.cell(+s247 & -s248 & +s280 & -s281, fill=m42) -c2263 = mcdc.cell(+s247 & -s248 & +s281 & -s282, fill=m43) -c2264 = mcdc.cell(+s247 & -s248 & +s282 & -s283, fill=m44) -c2265 = mcdc.cell(+s247 & -s248 & +s283 & -s284, fill=m45) -c2266 = mcdc.cell(+s247 & -s248 & +s284 & -s285, fill=m46) -c2267 = mcdc.cell(+s247 & -s248 & +s285, fill=m47) -c2268 = mcdc.cell(+s248 & -s249 & -s277, fill=m38) -c2269 = mcdc.cell(+s248 & -s249 & +s277 & -s278, fill=m39) -c2270 = mcdc.cell(+s248 & -s249 & +s278 & -s279, fill=m40) -c2271 = mcdc.cell(+s248 & -s249 & +s279 & -s280, fill=m41) -c2272 = mcdc.cell(+s248 & -s249 & +s280 & -s281, fill=m42) -c2273 = mcdc.cell(+s248 & -s249 & +s281 & -s282, fill=m43) -c2274 = mcdc.cell(+s248 & -s249 & +s282 & -s283, fill=m44) -c2275 = mcdc.cell(+s248 & -s249 & +s283 & -s284, fill=m45) -c2276 = mcdc.cell(+s248 & -s249 & +s284 & -s285, fill=m46) -c2277 = mcdc.cell(+s248 & -s249 & +s285, fill=m47) -c2278 = mcdc.cell(+s249 & -s250 & -s277, fill=m38) -c2279 = mcdc.cell(+s249 & -s250 & +s277 & -s278, fill=m39) -c2280 = mcdc.cell(+s249 & -s250 & +s278 & -s279, fill=m40) -c2281 = mcdc.cell(+s249 & -s250 & +s279 & -s280, fill=m41) -c2282 = mcdc.cell(+s249 & -s250 & +s280 & -s281, fill=m42) -c2283 = mcdc.cell(+s249 & -s250 & +s281 & -s282, fill=m43) -c2284 = mcdc.cell(+s249 & -s250 & +s282 & -s283, fill=m44) -c2285 = mcdc.cell(+s249 & -s250 & +s283 & -s284, fill=m45) -c2286 = mcdc.cell(+s249 & -s250 & +s284 & -s285, fill=m46) -c2287 = mcdc.cell(+s249 & -s250 & +s285, fill=m47) -c2288 = mcdc.cell(+s250 & -s251 & -s277, fill=m38) -c2289 = mcdc.cell(+s250 & -s251 & +s277 & -s278, fill=m39) -c2290 = mcdc.cell(+s250 & -s251 & +s278 & -s279, fill=m40) -c2291 = mcdc.cell(+s250 & -s251 & +s279 & -s280, fill=m41) -c2292 = mcdc.cell(+s250 & -s251 & +s280 & -s281, fill=m42) -c2293 = mcdc.cell(+s250 & -s251 & +s281 & -s282, fill=m43) -c2294 = mcdc.cell(+s250 & -s251 & +s282 & -s283, fill=m44) -c2295 = mcdc.cell(+s250 & -s251 & +s283 & -s284, fill=m45) -c2296 = mcdc.cell(+s250 & -s251 & +s284 & -s285, fill=m46) -c2297 = mcdc.cell(+s250 & -s251 & +s285, fill=m47) -c2298 = mcdc.cell(+s251 & -s252 & -s277, fill=m38) -c2299 = mcdc.cell(+s251 & -s252 & +s277 & -s278, fill=m39) -c2300 = mcdc.cell(+s251 & -s252 & +s278 & -s279, fill=m40) -c2301 = mcdc.cell(+s251 & -s252 & +s279 & -s280, fill=m41) -c2302 = mcdc.cell(+s251 & -s252 & +s280 & -s281, fill=m42) -c2303 = mcdc.cell(+s251 & -s252 & +s281 & -s282, fill=m43) -c2304 = mcdc.cell(+s251 & -s252 & +s282 & -s283, fill=m44) -c2305 = mcdc.cell(+s251 & -s252 & +s283 & -s284, fill=m45) -c2306 = mcdc.cell(+s251 & -s252 & +s284 & -s285, fill=m46) -c2307 = mcdc.cell(+s251 & -s252 & +s285, fill=m47) -c2308 = mcdc.cell(+s252 & -s253 & -s277, fill=m38) -c2309 = mcdc.cell(+s252 & -s253 & +s277 & -s278, fill=m39) -c2310 = mcdc.cell(+s252 & -s253 & +s278 & -s279, fill=m40) -c2311 = mcdc.cell(+s252 & -s253 & +s279 & -s280, fill=m41) -c2312 = mcdc.cell(+s252 & -s253 & +s280 & -s281, fill=m42) -c2313 = mcdc.cell(+s252 & -s253 & +s281 & -s282, fill=m43) -c2314 = mcdc.cell(+s252 & -s253 & +s282 & -s283, fill=m44) -c2315 = mcdc.cell(+s252 & -s253 & +s283 & -s284, fill=m45) -c2316 = mcdc.cell(+s252 & -s253 & +s284 & -s285, fill=m46) -c2317 = mcdc.cell(+s252 & -s253 & +s285, fill=m47) -c2318 = mcdc.cell(+s253 & -s254 & -s277, fill=m38) -c2319 = mcdc.cell(+s253 & -s254 & +s277 & -s278, fill=m39) -c2320 = mcdc.cell(+s253 & -s254 & +s278 & -s279, fill=m40) -c2321 = mcdc.cell(+s253 & -s254 & +s279 & -s280, fill=m41) -c2322 = mcdc.cell(+s253 & -s254 & +s280 & -s281, fill=m42) -c2323 = mcdc.cell(+s253 & -s254 & +s281 & -s282, fill=m43) -c2324 = mcdc.cell(+s253 & -s254 & +s282 & -s283, fill=m44) -c2325 = mcdc.cell(+s253 & -s254 & +s283 & -s284, fill=m45) -c2326 = mcdc.cell(+s253 & -s254 & +s284 & -s285, fill=m46) -c2327 = mcdc.cell(+s253 & -s254 & +s285, fill=m47) -c2328 = mcdc.cell(+s254 & -s255 & -s277, fill=m38) -c2329 = mcdc.cell(+s254 & -s255 & +s277 & -s278, fill=m39) -c2330 = mcdc.cell(+s254 & -s255 & +s278 & -s279, fill=m40) -c2331 = mcdc.cell(+s254 & -s255 & +s279 & -s280, fill=m41) -c2332 = mcdc.cell(+s254 & -s255 & +s280 & -s281, fill=m42) -c2333 = mcdc.cell(+s254 & -s255 & +s281 & -s282, fill=m43) -c2334 = mcdc.cell(+s254 & -s255 & +s282 & -s283, fill=m44) -c2335 = mcdc.cell(+s254 & -s255 & +s283 & -s284, fill=m45) -c2336 = mcdc.cell(+s254 & -s255 & +s284 & -s285, fill=m46) -c2337 = mcdc.cell(+s254 & -s255 & +s285, fill=m47) -c2338 = mcdc.cell(+s255 & -s256 & -s277, fill=m38) -c2339 = mcdc.cell(+s255 & -s256 & +s277 & -s278, fill=m39) -c2340 = mcdc.cell(+s255 & -s256 & +s278 & -s279, fill=m40) -c2341 = mcdc.cell(+s255 & -s256 & +s279 & -s280, fill=m41) -c2342 = mcdc.cell(+s255 & -s256 & +s280 & -s281, fill=m42) -c2343 = mcdc.cell(+s255 & -s256 & +s281 & -s282, fill=m43) -c2344 = mcdc.cell(+s255 & -s256 & +s282 & -s283, fill=m44) -c2345 = mcdc.cell(+s255 & -s256 & +s283 & -s284, fill=m45) -c2346 = mcdc.cell(+s255 & -s256 & +s284 & -s285, fill=m46) -c2347 = mcdc.cell(+s255 & -s256 & +s285, fill=m47) -c2348 = mcdc.cell(+s256 & -s257 & -s277, fill=m38) -c2349 = mcdc.cell(+s256 & -s257 & +s277 & -s278, fill=m39) -c2350 = mcdc.cell(+s256 & -s257 & +s278 & -s279, fill=m40) -c2351 = mcdc.cell(+s256 & -s257 & +s279 & -s280, fill=m41) -c2352 = mcdc.cell(+s256 & -s257 & +s280 & -s281, fill=m42) -c2353 = mcdc.cell(+s256 & -s257 & +s281 & -s282, fill=m43) -c2354 = mcdc.cell(+s256 & -s257 & +s282 & -s283, fill=m44) -c2355 = mcdc.cell(+s256 & -s257 & +s283 & -s284, fill=m45) -c2356 = mcdc.cell(+s256 & -s257 & +s284 & -s285, fill=m46) -c2357 = mcdc.cell(+s256 & -s257 & +s285, fill=m47) -c2358 = mcdc.cell(+s257 & -s258 & -s277, fill=m38) -c2359 = mcdc.cell(+s257 & -s258 & +s277 & -s278, fill=m39) -c2360 = mcdc.cell(+s257 & -s258 & +s278 & -s279, fill=m40) -c2361 = mcdc.cell(+s257 & -s258 & +s279 & -s280, fill=m41) -c2362 = mcdc.cell(+s257 & -s258 & +s280 & -s281, fill=m42) -c2363 = mcdc.cell(+s257 & -s258 & +s281 & -s282, fill=m43) -c2364 = mcdc.cell(+s257 & -s258 & +s282 & -s283, fill=m44) -c2365 = mcdc.cell(+s257 & -s258 & +s283 & -s284, fill=m45) -c2366 = mcdc.cell(+s257 & -s258 & +s284 & -s285, fill=m46) -c2367 = mcdc.cell(+s257 & -s258 & +s285, fill=m47) -c2368 = mcdc.cell(+s258 & -s259 & -s277, fill=m38) -c2369 = mcdc.cell(+s258 & -s259 & +s277 & -s278, fill=m39) -c2370 = mcdc.cell(+s258 & -s259 & +s278 & -s279, fill=m40) -c2371 = mcdc.cell(+s258 & -s259 & +s279 & -s280, fill=m41) -c2372 = mcdc.cell(+s258 & -s259 & +s280 & -s281, fill=m42) -c2373 = mcdc.cell(+s258 & -s259 & +s281 & -s282, fill=m43) -c2374 = mcdc.cell(+s258 & -s259 & +s282 & -s283, fill=m44) -c2375 = mcdc.cell(+s258 & -s259 & +s283 & -s284, fill=m45) -c2376 = mcdc.cell(+s258 & -s259 & +s284 & -s285, fill=m46) -c2377 = mcdc.cell(+s258 & -s259 & +s285, fill=m47) -c2378 = mcdc.cell(+s259 & -s260 & -s277, fill=m38) -c2379 = mcdc.cell(+s259 & -s260 & +s277 & -s278, fill=m39) -c2380 = mcdc.cell(+s259 & -s260 & +s278 & -s279, fill=m40) -c2381 = mcdc.cell(+s259 & -s260 & +s279 & -s280, fill=m41) -c2382 = mcdc.cell(+s259 & -s260 & +s280 & -s281, fill=m42) -c2383 = mcdc.cell(+s259 & -s260 & +s281 & -s282, fill=m43) -c2384 = mcdc.cell(+s259 & -s260 & +s282 & -s283, fill=m44) -c2385 = mcdc.cell(+s259 & -s260 & +s283 & -s284, fill=m45) -c2386 = mcdc.cell(+s259 & -s260 & +s284 & -s285, fill=m46) -c2387 = mcdc.cell(+s259 & -s260 & +s285, fill=m47) -c2388 = mcdc.cell(+s260 & -s261 & -s277, fill=m38) -c2389 = mcdc.cell(+s260 & -s261 & +s277 & -s278, fill=m39) -c2390 = mcdc.cell(+s260 & -s261 & +s278 & -s279, fill=m40) -c2391 = mcdc.cell(+s260 & -s261 & +s279 & -s280, fill=m41) -c2392 = mcdc.cell(+s260 & -s261 & +s280 & -s281, fill=m42) -c2393 = mcdc.cell(+s260 & -s261 & +s281 & -s282, fill=m43) -c2394 = mcdc.cell(+s260 & -s261 & +s282 & -s283, fill=m44) -c2395 = mcdc.cell(+s260 & -s261 & +s283 & -s284, fill=m45) -c2396 = mcdc.cell(+s260 & -s261 & +s284 & -s285, fill=m46) -c2397 = mcdc.cell(+s260 & -s261 & +s285, fill=m47) -c2398 = mcdc.cell(+s261 & -s262 & -s277, fill=m38) -c2399 = mcdc.cell(+s261 & -s262 & +s277 & -s278, fill=m39) -c2400 = mcdc.cell(+s261 & -s262 & +s278 & -s279, fill=m40) -c2401 = mcdc.cell(+s261 & -s262 & +s279 & -s280, fill=m41) -c2402 = mcdc.cell(+s261 & -s262 & +s280 & -s281, fill=m42) -c2403 = mcdc.cell(+s261 & -s262 & +s281 & -s282, fill=m43) -c2404 = mcdc.cell(+s261 & -s262 & +s282 & -s283, fill=m44) -c2405 = mcdc.cell(+s261 & -s262 & +s283 & -s284, fill=m45) -c2406 = mcdc.cell(+s261 & -s262 & +s284 & -s285, fill=m46) -c2407 = mcdc.cell(+s261 & -s262 & +s285, fill=m47) -c2408 = mcdc.cell(+s262 & -s263 & -s277, fill=m38) -c2409 = mcdc.cell(+s262 & -s263 & +s277 & -s278, fill=m39) -c2410 = mcdc.cell(+s262 & -s263 & +s278 & -s279, fill=m40) -c2411 = mcdc.cell(+s262 & -s263 & +s279 & -s280, fill=m41) -c2412 = mcdc.cell(+s262 & -s263 & +s280 & -s281, fill=m42) -c2413 = mcdc.cell(+s262 & -s263 & +s281 & -s282, fill=m43) -c2414 = mcdc.cell(+s262 & -s263 & +s282 & -s283, fill=m44) -c2415 = mcdc.cell(+s262 & -s263 & +s283 & -s284, fill=m45) -c2416 = mcdc.cell(+s262 & -s263 & +s284 & -s285, fill=m46) -c2417 = mcdc.cell(+s262 & -s263 & +s285, fill=m47) -c2418 = mcdc.cell(+s263 & -s264 & -s277, fill=m38) -c2419 = mcdc.cell(+s263 & -s264 & +s277 & -s278, fill=m39) -c2420 = mcdc.cell(+s263 & -s264 & +s278 & -s279, fill=m40) -c2421 = mcdc.cell(+s263 & -s264 & +s279 & -s280, fill=m41) -c2422 = mcdc.cell(+s263 & -s264 & +s280 & -s281, fill=m42) -c2423 = mcdc.cell(+s263 & -s264 & +s281 & -s282, fill=m43) -c2424 = mcdc.cell(+s263 & -s264 & +s282 & -s283, fill=m44) -c2425 = mcdc.cell(+s263 & -s264 & +s283 & -s284, fill=m45) -c2426 = mcdc.cell(+s263 & -s264 & +s284 & -s285, fill=m46) -c2427 = mcdc.cell(+s263 & -s264 & +s285, fill=m47) -c2428 = mcdc.cell(+s264 & -s265 & -s277, fill=m38) -c2429 = mcdc.cell(+s264 & -s265 & +s277 & -s278, fill=m39) -c2430 = mcdc.cell(+s264 & -s265 & +s278 & -s279, fill=m40) -c2431 = mcdc.cell(+s264 & -s265 & +s279 & -s280, fill=m41) -c2432 = mcdc.cell(+s264 & -s265 & +s280 & -s281, fill=m42) -c2433 = mcdc.cell(+s264 & -s265 & +s281 & -s282, fill=m43) -c2434 = mcdc.cell(+s264 & -s265 & +s282 & -s283, fill=m44) -c2435 = mcdc.cell(+s264 & -s265 & +s283 & -s284, fill=m45) -c2436 = mcdc.cell(+s264 & -s265 & +s284 & -s285, fill=m46) -c2437 = mcdc.cell(+s264 & -s265 & +s285, fill=m47) -c2438 = mcdc.cell(+s265 & -s266 & -s277, fill=m38) -c2439 = mcdc.cell(+s265 & -s266 & +s277 & -s278, fill=m39) -c2440 = mcdc.cell(+s265 & -s266 & +s278 & -s279, fill=m40) -c2441 = mcdc.cell(+s265 & -s266 & +s279 & -s280, fill=m41) -c2442 = mcdc.cell(+s265 & -s266 & +s280 & -s281, fill=m42) -c2443 = mcdc.cell(+s265 & -s266 & +s281 & -s282, fill=m43) -c2444 = mcdc.cell(+s265 & -s266 & +s282 & -s283, fill=m44) -c2445 = mcdc.cell(+s265 & -s266 & +s283 & -s284, fill=m45) -c2446 = mcdc.cell(+s265 & -s266 & +s284 & -s285, fill=m46) -c2447 = mcdc.cell(+s265 & -s266 & +s285, fill=m47) -c2448 = mcdc.cell(+s266 & -s267 & -s277, fill=m38) -c2449 = mcdc.cell(+s266 & -s267 & +s277 & -s278, fill=m39) -c2450 = mcdc.cell(+s266 & -s267 & +s278 & -s279, fill=m40) -c2451 = mcdc.cell(+s266 & -s267 & +s279 & -s280, fill=m41) -c2452 = mcdc.cell(+s266 & -s267 & +s280 & -s281, fill=m42) -c2453 = mcdc.cell(+s266 & -s267 & +s281 & -s282, fill=m43) -c2454 = mcdc.cell(+s266 & -s267 & +s282 & -s283, fill=m44) -c2455 = mcdc.cell(+s266 & -s267 & +s283 & -s284, fill=m45) -c2456 = mcdc.cell(+s266 & -s267 & +s284 & -s285, fill=m46) -c2457 = mcdc.cell(+s266 & -s267 & +s285, fill=m47) -c2458 = mcdc.cell(+s267 & -s268 & -s277, fill=m38) -c2459 = mcdc.cell(+s267 & -s268 & +s277 & -s278, fill=m39) -c2460 = mcdc.cell(+s267 & -s268 & +s278 & -s279, fill=m40) -c2461 = mcdc.cell(+s267 & -s268 & +s279 & -s280, fill=m41) -c2462 = mcdc.cell(+s267 & -s268 & +s280 & -s281, fill=m42) -c2463 = mcdc.cell(+s267 & -s268 & +s281 & -s282, fill=m43) -c2464 = mcdc.cell(+s267 & -s268 & +s282 & -s283, fill=m44) -c2465 = mcdc.cell(+s267 & -s268 & +s283 & -s284, fill=m45) -c2466 = mcdc.cell(+s267 & -s268 & +s284 & -s285, fill=m46) -c2467 = mcdc.cell(+s267 & -s268 & +s285, fill=m47) -c2468 = mcdc.cell(+s268 & -s269 & -s277, fill=m38) -c2469 = mcdc.cell(+s268 & -s269 & +s277 & -s278, fill=m39) -c2470 = mcdc.cell(+s268 & -s269 & +s278 & -s279, fill=m40) -c2471 = mcdc.cell(+s268 & -s269 & +s279 & -s280, fill=m41) -c2472 = mcdc.cell(+s268 & -s269 & +s280 & -s281, fill=m42) -c2473 = mcdc.cell(+s268 & -s269 & +s281 & -s282, fill=m43) -c2474 = mcdc.cell(+s268 & -s269 & +s282 & -s283, fill=m44) -c2475 = mcdc.cell(+s268 & -s269 & +s283 & -s284, fill=m45) -c2476 = mcdc.cell(+s268 & -s269 & +s284 & -s285, fill=m46) -c2477 = mcdc.cell(+s268 & -s269 & +s285, fill=m47) -c2478 = mcdc.cell(+s269 & -s270 & -s277, fill=m38) -c2479 = mcdc.cell(+s269 & -s270 & +s277 & -s278, fill=m39) -c2480 = mcdc.cell(+s269 & -s270 & +s278 & -s279, fill=m40) -c2481 = mcdc.cell(+s269 & -s270 & +s279 & -s280, fill=m41) -c2482 = mcdc.cell(+s269 & -s270 & +s280 & -s281, fill=m42) -c2483 = mcdc.cell(+s269 & -s270 & +s281 & -s282, fill=m43) -c2484 = mcdc.cell(+s269 & -s270 & +s282 & -s283, fill=m44) -c2485 = mcdc.cell(+s269 & -s270 & +s283 & -s284, fill=m45) -c2486 = mcdc.cell(+s269 & -s270 & +s284 & -s285, fill=m46) -c2487 = mcdc.cell(+s269 & -s270 & +s285, fill=m47) -c2488 = mcdc.cell(+s270 & -s271 & -s277, fill=m38) -c2489 = mcdc.cell(+s270 & -s271 & +s277 & -s278, fill=m39) -c2490 = mcdc.cell(+s270 & -s271 & +s278 & -s279, fill=m40) -c2491 = mcdc.cell(+s270 & -s271 & +s279 & -s280, fill=m41) -c2492 = mcdc.cell(+s270 & -s271 & +s280 & -s281, fill=m42) -c2493 = mcdc.cell(+s270 & -s271 & +s281 & -s282, fill=m43) -c2494 = mcdc.cell(+s270 & -s271 & +s282 & -s283, fill=m44) -c2495 = mcdc.cell(+s270 & -s271 & +s283 & -s284, fill=m45) -c2496 = mcdc.cell(+s270 & -s271 & +s284 & -s285, fill=m46) -c2497 = mcdc.cell(+s270 & -s271 & +s285, fill=m47) -c2498 = mcdc.cell(+s271 & -s272 & -s277, fill=m38) -c2499 = mcdc.cell(+s271 & -s272 & +s277 & -s278, fill=m39) -c2500 = mcdc.cell(+s271 & -s272 & +s278 & -s279, fill=m40) -c2501 = mcdc.cell(+s271 & -s272 & +s279 & -s280, fill=m41) -c2502 = mcdc.cell(+s271 & -s272 & +s280 & -s281, fill=m42) -c2503 = mcdc.cell(+s271 & -s272 & +s281 & -s282, fill=m43) -c2504 = mcdc.cell(+s271 & -s272 & +s282 & -s283, fill=m44) -c2505 = mcdc.cell(+s271 & -s272 & +s283 & -s284, fill=m45) -c2506 = mcdc.cell(+s271 & -s272 & +s284 & -s285, fill=m46) -c2507 = mcdc.cell(+s271 & -s272 & +s285, fill=m47) -c2508 = mcdc.cell(+s272 & -s273 & -s277, fill=m38) -c2509 = mcdc.cell(+s272 & -s273 & +s277 & -s278, fill=m39) -c2510 = mcdc.cell(+s272 & -s273 & +s278 & -s279, fill=m40) -c2511 = mcdc.cell(+s272 & -s273 & +s279 & -s280, fill=m41) -c2512 = mcdc.cell(+s272 & -s273 & +s280 & -s281, fill=m42) -c2513 = mcdc.cell(+s272 & -s273 & +s281 & -s282, fill=m43) -c2514 = mcdc.cell(+s272 & -s273 & +s282 & -s283, fill=m44) -c2515 = mcdc.cell(+s272 & -s273 & +s283 & -s284, fill=m45) -c2516 = mcdc.cell(+s272 & -s273 & +s284 & -s285, fill=m46) -c2517 = mcdc.cell(+s272 & -s273 & +s285, fill=m47) -c2518 = mcdc.cell(+s273 & -s274 & -s277, fill=m38) -c2519 = mcdc.cell(+s273 & -s274 & +s277 & -s278, fill=m39) -c2520 = mcdc.cell(+s273 & -s274 & +s278 & -s279, fill=m40) -c2521 = mcdc.cell(+s273 & -s274 & +s279 & -s280, fill=m41) -c2522 = mcdc.cell(+s273 & -s274 & +s280 & -s281, fill=m42) -c2523 = mcdc.cell(+s273 & -s274 & +s281 & -s282, fill=m43) -c2524 = mcdc.cell(+s273 & -s274 & +s282 & -s283, fill=m44) -c2525 = mcdc.cell(+s273 & -s274 & +s283 & -s284, fill=m45) -c2526 = mcdc.cell(+s273 & -s274 & +s284 & -s285, fill=m46) -c2527 = mcdc.cell(+s273 & -s274 & +s285, fill=m47) -c2528 = mcdc.cell(+s274 & -s275 & -s277, fill=m38) -c2529 = mcdc.cell(+s274 & -s275 & +s277 & -s278, fill=m39) -c2530 = mcdc.cell(+s274 & -s275 & +s278 & -s279, fill=m40) -c2531 = mcdc.cell(+s274 & -s275 & +s279 & -s280, fill=m41) -c2532 = mcdc.cell(+s274 & -s275 & +s280 & -s281, fill=m42) -c2533 = mcdc.cell(+s274 & -s275 & +s281 & -s282, fill=m43) -c2534 = mcdc.cell(+s274 & -s275 & +s282 & -s283, fill=m44) -c2535 = mcdc.cell(+s274 & -s275 & +s283 & -s284, fill=m45) -c2536 = mcdc.cell(+s274 & -s275 & +s284 & -s285, fill=m46) -c2537 = mcdc.cell(+s274 & -s275 & +s285, fill=m47) -c2538 = mcdc.cell(+s275 & -s276 & -s277, fill=m38) -c2539 = mcdc.cell(+s275 & -s276 & +s277 & -s278, fill=m39) -c2540 = mcdc.cell(+s275 & -s276 & +s278 & -s279, fill=m40) -c2541 = mcdc.cell(+s275 & -s276 & +s279 & -s280, fill=m41) -c2542 = mcdc.cell(+s275 & -s276 & +s280 & -s281, fill=m42) -c2543 = mcdc.cell(+s275 & -s276 & +s281 & -s282, fill=m43) -c2544 = mcdc.cell(+s275 & -s276 & +s282 & -s283, fill=m44) -c2545 = mcdc.cell(+s275 & -s276 & +s283 & -s284, fill=m45) -c2546 = mcdc.cell(+s275 & -s276 & +s284 & -s285, fill=m46) -c2547 = mcdc.cell(+s275 & -s276 & +s285, fill=m47) -c2548 = mcdc.cell(+s276 & -s277, fill=m38) -c2549 = mcdc.cell(+s276 & +s277 & -s278, fill=m39) -c2550 = mcdc.cell(+s276 & +s278 & -s279, fill=m40) -c2551 = mcdc.cell(+s276 & +s279 & -s280, fill=m41) -c2552 = mcdc.cell(+s276 & +s280 & -s281, fill=m42) -c2553 = mcdc.cell(+s276 & +s281 & -s282, fill=m43) -c2554 = mcdc.cell(+s276 & +s282 & -s283, fill=m44) -c2555 = mcdc.cell(+s276 & +s283 & -s284, fill=m45) -c2556 = mcdc.cell(+s276 & +s284 & -s285, fill=m46) -c2557 = mcdc.cell(+s276 & +s285, fill=m47) -c2558 = mcdc.cell(-s3, fill=m1) # Name: Outside pin (0) -c2559 = mcdc.cell(+s3 & -s4, fill=m8) # Name: Outside pin (1) -c2560 = mcdc.cell(+s4, fill=m10) # Name: Outside pin (last) -c2561 = mcdc.cell(-s3, fill=m1) # Name: Outside pin grid (bottom) (0) -c2562 = mcdc.cell(+s3 & -s4, fill=m8) # Name: Outside pin grid (bottom) (1) -c2563 = mcdc.cell( - +s4 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: Outside pin grid (bottom) (last) -c2564 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m3 -) # Name: Outside pin grid (bottom) (grid) -c2565 = mcdc.cell(-s3, fill=m1) # Name: Outside pin grid (intermediate) (0) -c2566 = mcdc.cell(+s3 & -s4, fill=m8) # Name: Outside pin grid (intermediate) (1) -c2567 = mcdc.cell( - +s4 & +s20 & -s21 & +s22 & -s23, fill=m10 -) # Name: Outside pin grid (intermediate) (last) -c2568 = mcdc.cell( - ~(+s20 & -s21 & +s22 & -s23), fill=m7 -) # Name: Outside pin grid (intermediate) (grid) -c2596 = mcdc.cell(-s82 & -s277, fill=m28) -c2597 = mcdc.cell(-s82 & +s277 & -s278, fill=m29) -c2598 = mcdc.cell(-s82 & +s278 & -s279, fill=m30) -c2599 = mcdc.cell(-s82 & +s279 & -s280, fill=m31) -c2600 = mcdc.cell(-s82 & +s280 & -s281, fill=m32) -c2601 = mcdc.cell(-s82 & +s281 & -s282, fill=m33) -c2602 = mcdc.cell(-s82 & +s282 & -s283, fill=m34) -c2603 = mcdc.cell(-s82 & +s283 & -s284, fill=m35) -c2604 = mcdc.cell(-s82 & +s284 & -s285, fill=m36) -c2605 = mcdc.cell(-s82 & +s285, fill=m37) -c2606 = mcdc.cell(+s82 & -s83 & -s277, fill=m28) -c2607 = mcdc.cell(+s82 & -s83 & +s277 & -s278, fill=m29) -c2608 = mcdc.cell(+s82 & -s83 & +s278 & -s279, fill=m30) -c2609 = mcdc.cell(+s82 & -s83 & +s279 & -s280, fill=m31) -c2610 = mcdc.cell(+s82 & -s83 & +s280 & -s281, fill=m32) -c2611 = mcdc.cell(+s82 & -s83 & +s281 & -s282, fill=m33) -c2612 = mcdc.cell(+s82 & -s83 & +s282 & -s283, fill=m34) -c2613 = mcdc.cell(+s82 & -s83 & +s283 & -s284, fill=m35) -c2614 = mcdc.cell(+s82 & -s83 & +s284 & -s285, fill=m36) -c2615 = mcdc.cell(+s82 & -s83 & +s285, fill=m37) -c2616 = mcdc.cell(+s83 & -s84 & -s277, fill=m28) -c2617 = mcdc.cell(+s83 & -s84 & +s277 & -s278, fill=m29) -c2618 = mcdc.cell(+s83 & -s84 & +s278 & -s279, fill=m30) -c2619 = mcdc.cell(+s83 & -s84 & +s279 & -s280, fill=m31) -c2620 = mcdc.cell(+s83 & -s84 & +s280 & -s281, fill=m32) -c2621 = mcdc.cell(+s83 & -s84 & +s281 & -s282, fill=m33) -c2622 = mcdc.cell(+s83 & -s84 & +s282 & -s283, fill=m34) -c2623 = mcdc.cell(+s83 & -s84 & +s283 & -s284, fill=m35) -c2624 = mcdc.cell(+s83 & -s84 & +s284 & -s285, fill=m36) -c2625 = mcdc.cell(+s83 & -s84 & +s285, fill=m37) -c2626 = mcdc.cell(+s84 & -s85 & -s277, fill=m28) -c2627 = mcdc.cell(+s84 & -s85 & +s277 & -s278, fill=m29) -c2628 = mcdc.cell(+s84 & -s85 & +s278 & -s279, fill=m30) -c2629 = mcdc.cell(+s84 & -s85 & +s279 & -s280, fill=m31) -c2630 = mcdc.cell(+s84 & -s85 & +s280 & -s281, fill=m32) -c2631 = mcdc.cell(+s84 & -s85 & +s281 & -s282, fill=m33) -c2632 = mcdc.cell(+s84 & -s85 & +s282 & -s283, fill=m34) -c2633 = mcdc.cell(+s84 & -s85 & +s283 & -s284, fill=m35) -c2634 = mcdc.cell(+s84 & -s85 & +s284 & -s285, fill=m36) -c2635 = mcdc.cell(+s84 & -s85 & +s285, fill=m37) -c2636 = mcdc.cell(+s85 & -s86 & -s277, fill=m28) -c2637 = mcdc.cell(+s85 & -s86 & +s277 & -s278, fill=m29) -c2638 = mcdc.cell(+s85 & -s86 & +s278 & -s279, fill=m30) -c2639 = mcdc.cell(+s85 & -s86 & +s279 & -s280, fill=m31) -c2640 = mcdc.cell(+s85 & -s86 & +s280 & -s281, fill=m32) -c2641 = mcdc.cell(+s85 & -s86 & +s281 & -s282, fill=m33) -c2642 = mcdc.cell(+s85 & -s86 & +s282 & -s283, fill=m34) -c2643 = mcdc.cell(+s85 & -s86 & +s283 & -s284, fill=m35) -c2644 = mcdc.cell(+s85 & -s86 & +s284 & -s285, fill=m36) -c2645 = mcdc.cell(+s85 & -s86 & +s285, fill=m37) -c2646 = mcdc.cell(+s86 & -s87 & -s277, fill=m28) -c2647 = mcdc.cell(+s86 & -s87 & +s277 & -s278, fill=m29) -c2648 = mcdc.cell(+s86 & -s87 & +s278 & -s279, fill=m30) -c2649 = mcdc.cell(+s86 & -s87 & +s279 & -s280, fill=m31) -c2650 = mcdc.cell(+s86 & -s87 & +s280 & -s281, fill=m32) -c2651 = mcdc.cell(+s86 & -s87 & +s281 & -s282, fill=m33) -c2652 = mcdc.cell(+s86 & -s87 & +s282 & -s283, fill=m34) -c2653 = mcdc.cell(+s86 & -s87 & +s283 & -s284, fill=m35) -c2654 = mcdc.cell(+s86 & -s87 & +s284 & -s285, fill=m36) -c2655 = mcdc.cell(+s86 & -s87 & +s285, fill=m37) -c2656 = mcdc.cell(+s87 & -s88 & -s277, fill=m28) -c2657 = mcdc.cell(+s87 & -s88 & +s277 & -s278, fill=m29) -c2658 = mcdc.cell(+s87 & -s88 & +s278 & -s279, fill=m30) -c2659 = mcdc.cell(+s87 & -s88 & +s279 & -s280, fill=m31) -c2660 = mcdc.cell(+s87 & -s88 & +s280 & -s281, fill=m32) -c2661 = mcdc.cell(+s87 & -s88 & +s281 & -s282, fill=m33) -c2662 = mcdc.cell(+s87 & -s88 & +s282 & -s283, fill=m34) -c2663 = mcdc.cell(+s87 & -s88 & +s283 & -s284, fill=m35) -c2664 = mcdc.cell(+s87 & -s88 & +s284 & -s285, fill=m36) -c2665 = mcdc.cell(+s87 & -s88 & +s285, fill=m37) -c2666 = mcdc.cell(+s88 & -s89 & -s277, fill=m28) -c2667 = mcdc.cell(+s88 & -s89 & +s277 & -s278, fill=m29) -c2668 = mcdc.cell(+s88 & -s89 & +s278 & -s279, fill=m30) -c2669 = mcdc.cell(+s88 & -s89 & +s279 & -s280, fill=m31) -c2670 = mcdc.cell(+s88 & -s89 & +s280 & -s281, fill=m32) -c2671 = mcdc.cell(+s88 & -s89 & +s281 & -s282, fill=m33) -c2672 = mcdc.cell(+s88 & -s89 & +s282 & -s283, fill=m34) -c2673 = mcdc.cell(+s88 & -s89 & +s283 & -s284, fill=m35) -c2674 = mcdc.cell(+s88 & -s89 & +s284 & -s285, fill=m36) -c2675 = mcdc.cell(+s88 & -s89 & +s285, fill=m37) -c2676 = mcdc.cell(+s89 & -s90 & -s277, fill=m28) -c2677 = mcdc.cell(+s89 & -s90 & +s277 & -s278, fill=m29) -c2678 = mcdc.cell(+s89 & -s90 & +s278 & -s279, fill=m30) -c2679 = mcdc.cell(+s89 & -s90 & +s279 & -s280, fill=m31) -c2680 = mcdc.cell(+s89 & -s90 & +s280 & -s281, fill=m32) -c2681 = mcdc.cell(+s89 & -s90 & +s281 & -s282, fill=m33) -c2682 = mcdc.cell(+s89 & -s90 & +s282 & -s283, fill=m34) -c2683 = mcdc.cell(+s89 & -s90 & +s283 & -s284, fill=m35) -c2684 = mcdc.cell(+s89 & -s90 & +s284 & -s285, fill=m36) -c2685 = mcdc.cell(+s89 & -s90 & +s285, fill=m37) -c2686 = mcdc.cell(+s90 & -s91 & -s277, fill=m28) -c2687 = mcdc.cell(+s90 & -s91 & +s277 & -s278, fill=m29) -c2688 = mcdc.cell(+s90 & -s91 & +s278 & -s279, fill=m30) -c2689 = mcdc.cell(+s90 & -s91 & +s279 & -s280, fill=m31) -c2690 = mcdc.cell(+s90 & -s91 & +s280 & -s281, fill=m32) -c2691 = mcdc.cell(+s90 & -s91 & +s281 & -s282, fill=m33) -c2692 = mcdc.cell(+s90 & -s91 & +s282 & -s283, fill=m34) -c2693 = mcdc.cell(+s90 & -s91 & +s283 & -s284, fill=m35) -c2694 = mcdc.cell(+s90 & -s91 & +s284 & -s285, fill=m36) -c2695 = mcdc.cell(+s90 & -s91 & +s285, fill=m37) -c2696 = mcdc.cell(+s91 & -s92 & -s277, fill=m28) -c2697 = mcdc.cell(+s91 & -s92 & +s277 & -s278, fill=m29) -c2698 = mcdc.cell(+s91 & -s92 & +s278 & -s279, fill=m30) -c2699 = mcdc.cell(+s91 & -s92 & +s279 & -s280, fill=m31) -c2700 = mcdc.cell(+s91 & -s92 & +s280 & -s281, fill=m32) -c2701 = mcdc.cell(+s91 & -s92 & +s281 & -s282, fill=m33) -c2702 = mcdc.cell(+s91 & -s92 & +s282 & -s283, fill=m34) -c2703 = mcdc.cell(+s91 & -s92 & +s283 & -s284, fill=m35) -c2704 = mcdc.cell(+s91 & -s92 & +s284 & -s285, fill=m36) -c2705 = mcdc.cell(+s91 & -s92 & +s285, fill=m37) -c2706 = mcdc.cell(+s92 & -s93 & -s277, fill=m28) -c2707 = mcdc.cell(+s92 & -s93 & +s277 & -s278, fill=m29) -c2708 = mcdc.cell(+s92 & -s93 & +s278 & -s279, fill=m30) -c2709 = mcdc.cell(+s92 & -s93 & +s279 & -s280, fill=m31) -c2710 = mcdc.cell(+s92 & -s93 & +s280 & -s281, fill=m32) -c2711 = mcdc.cell(+s92 & -s93 & +s281 & -s282, fill=m33) -c2712 = mcdc.cell(+s92 & -s93 & +s282 & -s283, fill=m34) -c2713 = mcdc.cell(+s92 & -s93 & +s283 & -s284, fill=m35) -c2714 = mcdc.cell(+s92 & -s93 & +s284 & -s285, fill=m36) -c2715 = mcdc.cell(+s92 & -s93 & +s285, fill=m37) -c2716 = mcdc.cell(+s93 & -s94 & -s277, fill=m28) -c2717 = mcdc.cell(+s93 & -s94 & +s277 & -s278, fill=m29) -c2718 = mcdc.cell(+s93 & -s94 & +s278 & -s279, fill=m30) -c2719 = mcdc.cell(+s93 & -s94 & +s279 & -s280, fill=m31) -c2720 = mcdc.cell(+s93 & -s94 & +s280 & -s281, fill=m32) -c2721 = mcdc.cell(+s93 & -s94 & +s281 & -s282, fill=m33) -c2722 = mcdc.cell(+s93 & -s94 & +s282 & -s283, fill=m34) -c2723 = mcdc.cell(+s93 & -s94 & +s283 & -s284, fill=m35) -c2724 = mcdc.cell(+s93 & -s94 & +s284 & -s285, fill=m36) -c2725 = mcdc.cell(+s93 & -s94 & +s285, fill=m37) -c2726 = mcdc.cell(+s94 & -s95 & -s277, fill=m28) -c2727 = mcdc.cell(+s94 & -s95 & +s277 & -s278, fill=m29) -c2728 = mcdc.cell(+s94 & -s95 & +s278 & -s279, fill=m30) -c2729 = mcdc.cell(+s94 & -s95 & +s279 & -s280, fill=m31) -c2730 = mcdc.cell(+s94 & -s95 & +s280 & -s281, fill=m32) -c2731 = mcdc.cell(+s94 & -s95 & +s281 & -s282, fill=m33) -c2732 = mcdc.cell(+s94 & -s95 & +s282 & -s283, fill=m34) -c2733 = mcdc.cell(+s94 & -s95 & +s283 & -s284, fill=m35) -c2734 = mcdc.cell(+s94 & -s95 & +s284 & -s285, fill=m36) -c2735 = mcdc.cell(+s94 & -s95 & +s285, fill=m37) -c2736 = mcdc.cell(+s95 & -s96 & -s277, fill=m28) -c2737 = mcdc.cell(+s95 & -s96 & +s277 & -s278, fill=m29) -c2738 = mcdc.cell(+s95 & -s96 & +s278 & -s279, fill=m30) -c2739 = mcdc.cell(+s95 & -s96 & +s279 & -s280, fill=m31) -c2740 = mcdc.cell(+s95 & -s96 & +s280 & -s281, fill=m32) -c2741 = mcdc.cell(+s95 & -s96 & +s281 & -s282, fill=m33) -c2742 = mcdc.cell(+s95 & -s96 & +s282 & -s283, fill=m34) -c2743 = mcdc.cell(+s95 & -s96 & +s283 & -s284, fill=m35) -c2744 = mcdc.cell(+s95 & -s96 & +s284 & -s285, fill=m36) -c2745 = mcdc.cell(+s95 & -s96 & +s285, fill=m37) -c2746 = mcdc.cell(+s96 & -s97 & -s277, fill=m28) -c2747 = mcdc.cell(+s96 & -s97 & +s277 & -s278, fill=m29) -c2748 = mcdc.cell(+s96 & -s97 & +s278 & -s279, fill=m30) -c2749 = mcdc.cell(+s96 & -s97 & +s279 & -s280, fill=m31) -c2750 = mcdc.cell(+s96 & -s97 & +s280 & -s281, fill=m32) -c2751 = mcdc.cell(+s96 & -s97 & +s281 & -s282, fill=m33) -c2752 = mcdc.cell(+s96 & -s97 & +s282 & -s283, fill=m34) -c2753 = mcdc.cell(+s96 & -s97 & +s283 & -s284, fill=m35) -c2754 = mcdc.cell(+s96 & -s97 & +s284 & -s285, fill=m36) -c2755 = mcdc.cell(+s96 & -s97 & +s285, fill=m37) -c2756 = mcdc.cell(+s97 & -s98 & -s277, fill=m28) -c2757 = mcdc.cell(+s97 & -s98 & +s277 & -s278, fill=m29) -c2758 = mcdc.cell(+s97 & -s98 & +s278 & -s279, fill=m30) -c2759 = mcdc.cell(+s97 & -s98 & +s279 & -s280, fill=m31) -c2760 = mcdc.cell(+s97 & -s98 & +s280 & -s281, fill=m32) -c2761 = mcdc.cell(+s97 & -s98 & +s281 & -s282, fill=m33) -c2762 = mcdc.cell(+s97 & -s98 & +s282 & -s283, fill=m34) -c2763 = mcdc.cell(+s97 & -s98 & +s283 & -s284, fill=m35) -c2764 = mcdc.cell(+s97 & -s98 & +s284 & -s285, fill=m36) -c2765 = mcdc.cell(+s97 & -s98 & +s285, fill=m37) -c2766 = mcdc.cell(+s98 & -s99 & -s277, fill=m28) -c2767 = mcdc.cell(+s98 & -s99 & +s277 & -s278, fill=m29) -c2768 = mcdc.cell(+s98 & -s99 & +s278 & -s279, fill=m30) -c2769 = mcdc.cell(+s98 & -s99 & +s279 & -s280, fill=m31) -c2770 = mcdc.cell(+s98 & -s99 & +s280 & -s281, fill=m32) -c2771 = mcdc.cell(+s98 & -s99 & +s281 & -s282, fill=m33) -c2772 = mcdc.cell(+s98 & -s99 & +s282 & -s283, fill=m34) -c2773 = mcdc.cell(+s98 & -s99 & +s283 & -s284, fill=m35) -c2774 = mcdc.cell(+s98 & -s99 & +s284 & -s285, fill=m36) -c2775 = mcdc.cell(+s98 & -s99 & +s285, fill=m37) -c2776 = mcdc.cell(+s99 & -s100 & -s277, fill=m28) -c2777 = mcdc.cell(+s99 & -s100 & +s277 & -s278, fill=m29) -c2778 = mcdc.cell(+s99 & -s100 & +s278 & -s279, fill=m30) -c2779 = mcdc.cell(+s99 & -s100 & +s279 & -s280, fill=m31) -c2780 = mcdc.cell(+s99 & -s100 & +s280 & -s281, fill=m32) -c2781 = mcdc.cell(+s99 & -s100 & +s281 & -s282, fill=m33) -c2782 = mcdc.cell(+s99 & -s100 & +s282 & -s283, fill=m34) -c2783 = mcdc.cell(+s99 & -s100 & +s283 & -s284, fill=m35) -c2784 = mcdc.cell(+s99 & -s100 & +s284 & -s285, fill=m36) -c2785 = mcdc.cell(+s99 & -s100 & +s285, fill=m37) -c2786 = mcdc.cell(+s100 & -s101 & -s277, fill=m28) -c2787 = mcdc.cell(+s100 & -s101 & +s277 & -s278, fill=m29) -c2788 = mcdc.cell(+s100 & -s101 & +s278 & -s279, fill=m30) -c2789 = mcdc.cell(+s100 & -s101 & +s279 & -s280, fill=m31) -c2790 = mcdc.cell(+s100 & -s101 & +s280 & -s281, fill=m32) -c2791 = mcdc.cell(+s100 & -s101 & +s281 & -s282, fill=m33) -c2792 = mcdc.cell(+s100 & -s101 & +s282 & -s283, fill=m34) -c2793 = mcdc.cell(+s100 & -s101 & +s283 & -s284, fill=m35) -c2794 = mcdc.cell(+s100 & -s101 & +s284 & -s285, fill=m36) -c2795 = mcdc.cell(+s100 & -s101 & +s285, fill=m37) -c2796 = mcdc.cell(+s101 & -s102 & -s277, fill=m28) -c2797 = mcdc.cell(+s101 & -s102 & +s277 & -s278, fill=m29) -c2798 = mcdc.cell(+s101 & -s102 & +s278 & -s279, fill=m30) -c2799 = mcdc.cell(+s101 & -s102 & +s279 & -s280, fill=m31) -c2800 = mcdc.cell(+s101 & -s102 & +s280 & -s281, fill=m32) -c2801 = mcdc.cell(+s101 & -s102 & +s281 & -s282, fill=m33) -c2802 = mcdc.cell(+s101 & -s102 & +s282 & -s283, fill=m34) -c2803 = mcdc.cell(+s101 & -s102 & +s283 & -s284, fill=m35) -c2804 = mcdc.cell(+s101 & -s102 & +s284 & -s285, fill=m36) -c2805 = mcdc.cell(+s101 & -s102 & +s285, fill=m37) -c2806 = mcdc.cell(+s102 & -s103 & -s277, fill=m28) -c2807 = mcdc.cell(+s102 & -s103 & +s277 & -s278, fill=m29) -c2808 = mcdc.cell(+s102 & -s103 & +s278 & -s279, fill=m30) -c2809 = mcdc.cell(+s102 & -s103 & +s279 & -s280, fill=m31) -c2810 = mcdc.cell(+s102 & -s103 & +s280 & -s281, fill=m32) -c2811 = mcdc.cell(+s102 & -s103 & +s281 & -s282, fill=m33) -c2812 = mcdc.cell(+s102 & -s103 & +s282 & -s283, fill=m34) -c2813 = mcdc.cell(+s102 & -s103 & +s283 & -s284, fill=m35) -c2814 = mcdc.cell(+s102 & -s103 & +s284 & -s285, fill=m36) -c2815 = mcdc.cell(+s102 & -s103 & +s285, fill=m37) -c2816 = mcdc.cell(+s103 & -s104 & -s277, fill=m28) -c2817 = mcdc.cell(+s103 & -s104 & +s277 & -s278, fill=m29) -c2818 = mcdc.cell(+s103 & -s104 & +s278 & -s279, fill=m30) -c2819 = mcdc.cell(+s103 & -s104 & +s279 & -s280, fill=m31) -c2820 = mcdc.cell(+s103 & -s104 & +s280 & -s281, fill=m32) -c2821 = mcdc.cell(+s103 & -s104 & +s281 & -s282, fill=m33) -c2822 = mcdc.cell(+s103 & -s104 & +s282 & -s283, fill=m34) -c2823 = mcdc.cell(+s103 & -s104 & +s283 & -s284, fill=m35) -c2824 = mcdc.cell(+s103 & -s104 & +s284 & -s285, fill=m36) -c2825 = mcdc.cell(+s103 & -s104 & +s285, fill=m37) -c2826 = mcdc.cell(+s104 & -s105 & -s277, fill=m28) -c2827 = mcdc.cell(+s104 & -s105 & +s277 & -s278, fill=m29) -c2828 = mcdc.cell(+s104 & -s105 & +s278 & -s279, fill=m30) -c2829 = mcdc.cell(+s104 & -s105 & +s279 & -s280, fill=m31) -c2830 = mcdc.cell(+s104 & -s105 & +s280 & -s281, fill=m32) -c2831 = mcdc.cell(+s104 & -s105 & +s281 & -s282, fill=m33) -c2832 = mcdc.cell(+s104 & -s105 & +s282 & -s283, fill=m34) -c2833 = mcdc.cell(+s104 & -s105 & +s283 & -s284, fill=m35) -c2834 = mcdc.cell(+s104 & -s105 & +s284 & -s285, fill=m36) -c2835 = mcdc.cell(+s104 & -s105 & +s285, fill=m37) -c2836 = mcdc.cell(+s105 & -s106 & -s277, fill=m28) -c2837 = mcdc.cell(+s105 & -s106 & +s277 & -s278, fill=m29) -c2838 = mcdc.cell(+s105 & -s106 & +s278 & -s279, fill=m30) -c2839 = mcdc.cell(+s105 & -s106 & +s279 & -s280, fill=m31) -c2840 = mcdc.cell(+s105 & -s106 & +s280 & -s281, fill=m32) -c2841 = mcdc.cell(+s105 & -s106 & +s281 & -s282, fill=m33) -c2842 = mcdc.cell(+s105 & -s106 & +s282 & -s283, fill=m34) -c2843 = mcdc.cell(+s105 & -s106 & +s283 & -s284, fill=m35) -c2844 = mcdc.cell(+s105 & -s106 & +s284 & -s285, fill=m36) -c2845 = mcdc.cell(+s105 & -s106 & +s285, fill=m37) -c2846 = mcdc.cell(+s106 & -s107 & -s277, fill=m28) -c2847 = mcdc.cell(+s106 & -s107 & +s277 & -s278, fill=m29) -c2848 = mcdc.cell(+s106 & -s107 & +s278 & -s279, fill=m30) -c2849 = mcdc.cell(+s106 & -s107 & +s279 & -s280, fill=m31) -c2850 = mcdc.cell(+s106 & -s107 & +s280 & -s281, fill=m32) -c2851 = mcdc.cell(+s106 & -s107 & +s281 & -s282, fill=m33) -c2852 = mcdc.cell(+s106 & -s107 & +s282 & -s283, fill=m34) -c2853 = mcdc.cell(+s106 & -s107 & +s283 & -s284, fill=m35) -c2854 = mcdc.cell(+s106 & -s107 & +s284 & -s285, fill=m36) -c2855 = mcdc.cell(+s106 & -s107 & +s285, fill=m37) -c2856 = mcdc.cell(+s107 & -s108 & -s277, fill=m28) -c2857 = mcdc.cell(+s107 & -s108 & +s277 & -s278, fill=m29) -c2858 = mcdc.cell(+s107 & -s108 & +s278 & -s279, fill=m30) -c2859 = mcdc.cell(+s107 & -s108 & +s279 & -s280, fill=m31) -c2860 = mcdc.cell(+s107 & -s108 & +s280 & -s281, fill=m32) -c2861 = mcdc.cell(+s107 & -s108 & +s281 & -s282, fill=m33) -c2862 = mcdc.cell(+s107 & -s108 & +s282 & -s283, fill=m34) -c2863 = mcdc.cell(+s107 & -s108 & +s283 & -s284, fill=m35) -c2864 = mcdc.cell(+s107 & -s108 & +s284 & -s285, fill=m36) -c2865 = mcdc.cell(+s107 & -s108 & +s285, fill=m37) -c2866 = mcdc.cell(+s108 & -s109 & -s277, fill=m28) -c2867 = mcdc.cell(+s108 & -s109 & +s277 & -s278, fill=m29) -c2868 = mcdc.cell(+s108 & -s109 & +s278 & -s279, fill=m30) -c2869 = mcdc.cell(+s108 & -s109 & +s279 & -s280, fill=m31) -c2870 = mcdc.cell(+s108 & -s109 & +s280 & -s281, fill=m32) -c2871 = mcdc.cell(+s108 & -s109 & +s281 & -s282, fill=m33) -c2872 = mcdc.cell(+s108 & -s109 & +s282 & -s283, fill=m34) -c2873 = mcdc.cell(+s108 & -s109 & +s283 & -s284, fill=m35) -c2874 = mcdc.cell(+s108 & -s109 & +s284 & -s285, fill=m36) -c2875 = mcdc.cell(+s108 & -s109 & +s285, fill=m37) -c2876 = mcdc.cell(+s109 & -s110 & -s277, fill=m28) -c2877 = mcdc.cell(+s109 & -s110 & +s277 & -s278, fill=m29) -c2878 = mcdc.cell(+s109 & -s110 & +s278 & -s279, fill=m30) -c2879 = mcdc.cell(+s109 & -s110 & +s279 & -s280, fill=m31) -c2880 = mcdc.cell(+s109 & -s110 & +s280 & -s281, fill=m32) -c2881 = mcdc.cell(+s109 & -s110 & +s281 & -s282, fill=m33) -c2882 = mcdc.cell(+s109 & -s110 & +s282 & -s283, fill=m34) -c2883 = mcdc.cell(+s109 & -s110 & +s283 & -s284, fill=m35) -c2884 = mcdc.cell(+s109 & -s110 & +s284 & -s285, fill=m36) -c2885 = mcdc.cell(+s109 & -s110 & +s285, fill=m37) -c2886 = mcdc.cell(+s110 & -s111 & -s277, fill=m28) -c2887 = mcdc.cell(+s110 & -s111 & +s277 & -s278, fill=m29) -c2888 = mcdc.cell(+s110 & -s111 & +s278 & -s279, fill=m30) -c2889 = mcdc.cell(+s110 & -s111 & +s279 & -s280, fill=m31) -c2890 = mcdc.cell(+s110 & -s111 & +s280 & -s281, fill=m32) -c2891 = mcdc.cell(+s110 & -s111 & +s281 & -s282, fill=m33) -c2892 = mcdc.cell(+s110 & -s111 & +s282 & -s283, fill=m34) -c2893 = mcdc.cell(+s110 & -s111 & +s283 & -s284, fill=m35) -c2894 = mcdc.cell(+s110 & -s111 & +s284 & -s285, fill=m36) -c2895 = mcdc.cell(+s110 & -s111 & +s285, fill=m37) -c2896 = mcdc.cell(+s111 & -s112 & -s277, fill=m28) -c2897 = mcdc.cell(+s111 & -s112 & +s277 & -s278, fill=m29) -c2898 = mcdc.cell(+s111 & -s112 & +s278 & -s279, fill=m30) -c2899 = mcdc.cell(+s111 & -s112 & +s279 & -s280, fill=m31) -c2900 = mcdc.cell(+s111 & -s112 & +s280 & -s281, fill=m32) -c2901 = mcdc.cell(+s111 & -s112 & +s281 & -s282, fill=m33) -c2902 = mcdc.cell(+s111 & -s112 & +s282 & -s283, fill=m34) -c2903 = mcdc.cell(+s111 & -s112 & +s283 & -s284, fill=m35) -c2904 = mcdc.cell(+s111 & -s112 & +s284 & -s285, fill=m36) -c2905 = mcdc.cell(+s111 & -s112 & +s285, fill=m37) -c2906 = mcdc.cell(+s112 & -s113 & -s277, fill=m28) -c2907 = mcdc.cell(+s112 & -s113 & +s277 & -s278, fill=m29) -c2908 = mcdc.cell(+s112 & -s113 & +s278 & -s279, fill=m30) -c2909 = mcdc.cell(+s112 & -s113 & +s279 & -s280, fill=m31) -c2910 = mcdc.cell(+s112 & -s113 & +s280 & -s281, fill=m32) -c2911 = mcdc.cell(+s112 & -s113 & +s281 & -s282, fill=m33) -c2912 = mcdc.cell(+s112 & -s113 & +s282 & -s283, fill=m34) -c2913 = mcdc.cell(+s112 & -s113 & +s283 & -s284, fill=m35) -c2914 = mcdc.cell(+s112 & -s113 & +s284 & -s285, fill=m36) -c2915 = mcdc.cell(+s112 & -s113 & +s285, fill=m37) -c2916 = mcdc.cell(+s113 & -s114 & -s277, fill=m28) -c2917 = mcdc.cell(+s113 & -s114 & +s277 & -s278, fill=m29) -c2918 = mcdc.cell(+s113 & -s114 & +s278 & -s279, fill=m30) -c2919 = mcdc.cell(+s113 & -s114 & +s279 & -s280, fill=m31) -c2920 = mcdc.cell(+s113 & -s114 & +s280 & -s281, fill=m32) -c2921 = mcdc.cell(+s113 & -s114 & +s281 & -s282, fill=m33) -c2922 = mcdc.cell(+s113 & -s114 & +s282 & -s283, fill=m34) -c2923 = mcdc.cell(+s113 & -s114 & +s283 & -s284, fill=m35) -c2924 = mcdc.cell(+s113 & -s114 & +s284 & -s285, fill=m36) -c2925 = mcdc.cell(+s113 & -s114 & +s285, fill=m37) -c2926 = mcdc.cell(+s114 & -s115 & -s277, fill=m28) -c2927 = mcdc.cell(+s114 & -s115 & +s277 & -s278, fill=m29) -c2928 = mcdc.cell(+s114 & -s115 & +s278 & -s279, fill=m30) -c2929 = mcdc.cell(+s114 & -s115 & +s279 & -s280, fill=m31) -c2930 = mcdc.cell(+s114 & -s115 & +s280 & -s281, fill=m32) -c2931 = mcdc.cell(+s114 & -s115 & +s281 & -s282, fill=m33) -c2932 = mcdc.cell(+s114 & -s115 & +s282 & -s283, fill=m34) -c2933 = mcdc.cell(+s114 & -s115 & +s283 & -s284, fill=m35) -c2934 = mcdc.cell(+s114 & -s115 & +s284 & -s285, fill=m36) -c2935 = mcdc.cell(+s114 & -s115 & +s285, fill=m37) -c2936 = mcdc.cell(+s115 & -s116 & -s277, fill=m28) -c2937 = mcdc.cell(+s115 & -s116 & +s277 & -s278, fill=m29) -c2938 = mcdc.cell(+s115 & -s116 & +s278 & -s279, fill=m30) -c2939 = mcdc.cell(+s115 & -s116 & +s279 & -s280, fill=m31) -c2940 = mcdc.cell(+s115 & -s116 & +s280 & -s281, fill=m32) -c2941 = mcdc.cell(+s115 & -s116 & +s281 & -s282, fill=m33) -c2942 = mcdc.cell(+s115 & -s116 & +s282 & -s283, fill=m34) -c2943 = mcdc.cell(+s115 & -s116 & +s283 & -s284, fill=m35) -c2944 = mcdc.cell(+s115 & -s116 & +s284 & -s285, fill=m36) -c2945 = mcdc.cell(+s115 & -s116 & +s285, fill=m37) -c2946 = mcdc.cell(+s116 & -s117 & -s277, fill=m28) -c2947 = mcdc.cell(+s116 & -s117 & +s277 & -s278, fill=m29) -c2948 = mcdc.cell(+s116 & -s117 & +s278 & -s279, fill=m30) -c2949 = mcdc.cell(+s116 & -s117 & +s279 & -s280, fill=m31) -c2950 = mcdc.cell(+s116 & -s117 & +s280 & -s281, fill=m32) -c2951 = mcdc.cell(+s116 & -s117 & +s281 & -s282, fill=m33) -c2952 = mcdc.cell(+s116 & -s117 & +s282 & -s283, fill=m34) -c2953 = mcdc.cell(+s116 & -s117 & +s283 & -s284, fill=m35) -c2954 = mcdc.cell(+s116 & -s117 & +s284 & -s285, fill=m36) -c2955 = mcdc.cell(+s116 & -s117 & +s285, fill=m37) -c2956 = mcdc.cell(+s117 & -s118 & -s277, fill=m28) -c2957 = mcdc.cell(+s117 & -s118 & +s277 & -s278, fill=m29) -c2958 = mcdc.cell(+s117 & -s118 & +s278 & -s279, fill=m30) -c2959 = mcdc.cell(+s117 & -s118 & +s279 & -s280, fill=m31) -c2960 = mcdc.cell(+s117 & -s118 & +s280 & -s281, fill=m32) -c2961 = mcdc.cell(+s117 & -s118 & +s281 & -s282, fill=m33) -c2962 = mcdc.cell(+s117 & -s118 & +s282 & -s283, fill=m34) -c2963 = mcdc.cell(+s117 & -s118 & +s283 & -s284, fill=m35) -c2964 = mcdc.cell(+s117 & -s118 & +s284 & -s285, fill=m36) -c2965 = mcdc.cell(+s117 & -s118 & +s285, fill=m37) -c2966 = mcdc.cell(+s118 & -s119 & -s277, fill=m28) -c2967 = mcdc.cell(+s118 & -s119 & +s277 & -s278, fill=m29) -c2968 = mcdc.cell(+s118 & -s119 & +s278 & -s279, fill=m30) -c2969 = mcdc.cell(+s118 & -s119 & +s279 & -s280, fill=m31) -c2970 = mcdc.cell(+s118 & -s119 & +s280 & -s281, fill=m32) -c2971 = mcdc.cell(+s118 & -s119 & +s281 & -s282, fill=m33) -c2972 = mcdc.cell(+s118 & -s119 & +s282 & -s283, fill=m34) -c2973 = mcdc.cell(+s118 & -s119 & +s283 & -s284, fill=m35) -c2974 = mcdc.cell(+s118 & -s119 & +s284 & -s285, fill=m36) -c2975 = mcdc.cell(+s118 & -s119 & +s285, fill=m37) -c2976 = mcdc.cell(+s119 & -s120 & -s277, fill=m28) -c2977 = mcdc.cell(+s119 & -s120 & +s277 & -s278, fill=m29) -c2978 = mcdc.cell(+s119 & -s120 & +s278 & -s279, fill=m30) -c2979 = mcdc.cell(+s119 & -s120 & +s279 & -s280, fill=m31) -c2980 = mcdc.cell(+s119 & -s120 & +s280 & -s281, fill=m32) -c2981 = mcdc.cell(+s119 & -s120 & +s281 & -s282, fill=m33) -c2982 = mcdc.cell(+s119 & -s120 & +s282 & -s283, fill=m34) -c2983 = mcdc.cell(+s119 & -s120 & +s283 & -s284, fill=m35) -c2984 = mcdc.cell(+s119 & -s120 & +s284 & -s285, fill=m36) -c2985 = mcdc.cell(+s119 & -s120 & +s285, fill=m37) -c2986 = mcdc.cell(+s120 & -s121 & -s277, fill=m28) -c2987 = mcdc.cell(+s120 & -s121 & +s277 & -s278, fill=m29) -c2988 = mcdc.cell(+s120 & -s121 & +s278 & -s279, fill=m30) -c2989 = mcdc.cell(+s120 & -s121 & +s279 & -s280, fill=m31) -c2990 = mcdc.cell(+s120 & -s121 & +s280 & -s281, fill=m32) -c2991 = mcdc.cell(+s120 & -s121 & +s281 & -s282, fill=m33) -c2992 = mcdc.cell(+s120 & -s121 & +s282 & -s283, fill=m34) -c2993 = mcdc.cell(+s120 & -s121 & +s283 & -s284, fill=m35) -c2994 = mcdc.cell(+s120 & -s121 & +s284 & -s285, fill=m36) -c2995 = mcdc.cell(+s120 & -s121 & +s285, fill=m37) -c2996 = mcdc.cell(+s121 & -s122 & -s277, fill=m28) -c2997 = mcdc.cell(+s121 & -s122 & +s277 & -s278, fill=m29) -c2998 = mcdc.cell(+s121 & -s122 & +s278 & -s279, fill=m30) -c2999 = mcdc.cell(+s121 & -s122 & +s279 & -s280, fill=m31) -c3000 = mcdc.cell(+s121 & -s122 & +s280 & -s281, fill=m32) -c3001 = mcdc.cell(+s121 & -s122 & +s281 & -s282, fill=m33) -c3002 = mcdc.cell(+s121 & -s122 & +s282 & -s283, fill=m34) -c3003 = mcdc.cell(+s121 & -s122 & +s283 & -s284, fill=m35) -c3004 = mcdc.cell(+s121 & -s122 & +s284 & -s285, fill=m36) -c3005 = mcdc.cell(+s121 & -s122 & +s285, fill=m37) -c3006 = mcdc.cell(+s122 & -s123 & -s277, fill=m28) -c3007 = mcdc.cell(+s122 & -s123 & +s277 & -s278, fill=m29) -c3008 = mcdc.cell(+s122 & -s123 & +s278 & -s279, fill=m30) -c3009 = mcdc.cell(+s122 & -s123 & +s279 & -s280, fill=m31) -c3010 = mcdc.cell(+s122 & -s123 & +s280 & -s281, fill=m32) -c3011 = mcdc.cell(+s122 & -s123 & +s281 & -s282, fill=m33) -c3012 = mcdc.cell(+s122 & -s123 & +s282 & -s283, fill=m34) -c3013 = mcdc.cell(+s122 & -s123 & +s283 & -s284, fill=m35) -c3014 = mcdc.cell(+s122 & -s123 & +s284 & -s285, fill=m36) -c3015 = mcdc.cell(+s122 & -s123 & +s285, fill=m37) -c3016 = mcdc.cell(+s123 & -s124 & -s277, fill=m28) -c3017 = mcdc.cell(+s123 & -s124 & +s277 & -s278, fill=m29) -c3018 = mcdc.cell(+s123 & -s124 & +s278 & -s279, fill=m30) -c3019 = mcdc.cell(+s123 & -s124 & +s279 & -s280, fill=m31) -c3020 = mcdc.cell(+s123 & -s124 & +s280 & -s281, fill=m32) -c3021 = mcdc.cell(+s123 & -s124 & +s281 & -s282, fill=m33) -c3022 = mcdc.cell(+s123 & -s124 & +s282 & -s283, fill=m34) -c3023 = mcdc.cell(+s123 & -s124 & +s283 & -s284, fill=m35) -c3024 = mcdc.cell(+s123 & -s124 & +s284 & -s285, fill=m36) -c3025 = mcdc.cell(+s123 & -s124 & +s285, fill=m37) -c3026 = mcdc.cell(+s124 & -s125 & -s277, fill=m28) -c3027 = mcdc.cell(+s124 & -s125 & +s277 & -s278, fill=m29) -c3028 = mcdc.cell(+s124 & -s125 & +s278 & -s279, fill=m30) -c3029 = mcdc.cell(+s124 & -s125 & +s279 & -s280, fill=m31) -c3030 = mcdc.cell(+s124 & -s125 & +s280 & -s281, fill=m32) -c3031 = mcdc.cell(+s124 & -s125 & +s281 & -s282, fill=m33) -c3032 = mcdc.cell(+s124 & -s125 & +s282 & -s283, fill=m34) -c3033 = mcdc.cell(+s124 & -s125 & +s283 & -s284, fill=m35) -c3034 = mcdc.cell(+s124 & -s125 & +s284 & -s285, fill=m36) -c3035 = mcdc.cell(+s124 & -s125 & +s285, fill=m37) -c3036 = mcdc.cell(+s125 & -s126 & -s277, fill=m28) -c3037 = mcdc.cell(+s125 & -s126 & +s277 & -s278, fill=m29) -c3038 = mcdc.cell(+s125 & -s126 & +s278 & -s279, fill=m30) -c3039 = mcdc.cell(+s125 & -s126 & +s279 & -s280, fill=m31) -c3040 = mcdc.cell(+s125 & -s126 & +s280 & -s281, fill=m32) -c3041 = mcdc.cell(+s125 & -s126 & +s281 & -s282, fill=m33) -c3042 = mcdc.cell(+s125 & -s126 & +s282 & -s283, fill=m34) -c3043 = mcdc.cell(+s125 & -s126 & +s283 & -s284, fill=m35) -c3044 = mcdc.cell(+s125 & -s126 & +s284 & -s285, fill=m36) -c3045 = mcdc.cell(+s125 & -s126 & +s285, fill=m37) -c3046 = mcdc.cell(+s126 & -s127 & -s277, fill=m28) -c3047 = mcdc.cell(+s126 & -s127 & +s277 & -s278, fill=m29) -c3048 = mcdc.cell(+s126 & -s127 & +s278 & -s279, fill=m30) -c3049 = mcdc.cell(+s126 & -s127 & +s279 & -s280, fill=m31) -c3050 = mcdc.cell(+s126 & -s127 & +s280 & -s281, fill=m32) -c3051 = mcdc.cell(+s126 & -s127 & +s281 & -s282, fill=m33) -c3052 = mcdc.cell(+s126 & -s127 & +s282 & -s283, fill=m34) -c3053 = mcdc.cell(+s126 & -s127 & +s283 & -s284, fill=m35) -c3054 = mcdc.cell(+s126 & -s127 & +s284 & -s285, fill=m36) -c3055 = mcdc.cell(+s126 & -s127 & +s285, fill=m37) -c3056 = mcdc.cell(+s127 & -s128 & -s277, fill=m28) -c3057 = mcdc.cell(+s127 & -s128 & +s277 & -s278, fill=m29) -c3058 = mcdc.cell(+s127 & -s128 & +s278 & -s279, fill=m30) -c3059 = mcdc.cell(+s127 & -s128 & +s279 & -s280, fill=m31) -c3060 = mcdc.cell(+s127 & -s128 & +s280 & -s281, fill=m32) -c3061 = mcdc.cell(+s127 & -s128 & +s281 & -s282, fill=m33) -c3062 = mcdc.cell(+s127 & -s128 & +s282 & -s283, fill=m34) -c3063 = mcdc.cell(+s127 & -s128 & +s283 & -s284, fill=m35) -c3064 = mcdc.cell(+s127 & -s128 & +s284 & -s285, fill=m36) -c3065 = mcdc.cell(+s127 & -s128 & +s285, fill=m37) -c3066 = mcdc.cell(+s128 & -s129 & -s277, fill=m28) -c3067 = mcdc.cell(+s128 & -s129 & +s277 & -s278, fill=m29) -c3068 = mcdc.cell(+s128 & -s129 & +s278 & -s279, fill=m30) -c3069 = mcdc.cell(+s128 & -s129 & +s279 & -s280, fill=m31) -c3070 = mcdc.cell(+s128 & -s129 & +s280 & -s281, fill=m32) -c3071 = mcdc.cell(+s128 & -s129 & +s281 & -s282, fill=m33) -c3072 = mcdc.cell(+s128 & -s129 & +s282 & -s283, fill=m34) -c3073 = mcdc.cell(+s128 & -s129 & +s283 & -s284, fill=m35) -c3074 = mcdc.cell(+s128 & -s129 & +s284 & -s285, fill=m36) -c3075 = mcdc.cell(+s128 & -s129 & +s285, fill=m37) -c3076 = mcdc.cell(+s129 & -s130 & -s277, fill=m28) -c3077 = mcdc.cell(+s129 & -s130 & +s277 & -s278, fill=m29) -c3078 = mcdc.cell(+s129 & -s130 & +s278 & -s279, fill=m30) -c3079 = mcdc.cell(+s129 & -s130 & +s279 & -s280, fill=m31) -c3080 = mcdc.cell(+s129 & -s130 & +s280 & -s281, fill=m32) -c3081 = mcdc.cell(+s129 & -s130 & +s281 & -s282, fill=m33) -c3082 = mcdc.cell(+s129 & -s130 & +s282 & -s283, fill=m34) -c3083 = mcdc.cell(+s129 & -s130 & +s283 & -s284, fill=m35) -c3084 = mcdc.cell(+s129 & -s130 & +s284 & -s285, fill=m36) -c3085 = mcdc.cell(+s129 & -s130 & +s285, fill=m37) -c3086 = mcdc.cell(+s130 & -s131 & -s277, fill=m28) -c3087 = mcdc.cell(+s130 & -s131 & +s277 & -s278, fill=m29) -c3088 = mcdc.cell(+s130 & -s131 & +s278 & -s279, fill=m30) -c3089 = mcdc.cell(+s130 & -s131 & +s279 & -s280, fill=m31) -c3090 = mcdc.cell(+s130 & -s131 & +s280 & -s281, fill=m32) -c3091 = mcdc.cell(+s130 & -s131 & +s281 & -s282, fill=m33) -c3092 = mcdc.cell(+s130 & -s131 & +s282 & -s283, fill=m34) -c3093 = mcdc.cell(+s130 & -s131 & +s283 & -s284, fill=m35) -c3094 = mcdc.cell(+s130 & -s131 & +s284 & -s285, fill=m36) -c3095 = mcdc.cell(+s130 & -s131 & +s285, fill=m37) -c3096 = mcdc.cell(+s131 & -s132 & -s277, fill=m28) -c3097 = mcdc.cell(+s131 & -s132 & +s277 & -s278, fill=m29) -c3098 = mcdc.cell(+s131 & -s132 & +s278 & -s279, fill=m30) -c3099 = mcdc.cell(+s131 & -s132 & +s279 & -s280, fill=m31) -c3100 = mcdc.cell(+s131 & -s132 & +s280 & -s281, fill=m32) -c3101 = mcdc.cell(+s131 & -s132 & +s281 & -s282, fill=m33) -c3102 = mcdc.cell(+s131 & -s132 & +s282 & -s283, fill=m34) -c3103 = mcdc.cell(+s131 & -s132 & +s283 & -s284, fill=m35) -c3104 = mcdc.cell(+s131 & -s132 & +s284 & -s285, fill=m36) -c3105 = mcdc.cell(+s131 & -s132 & +s285, fill=m37) -c3106 = mcdc.cell(+s132 & -s133 & -s277, fill=m28) -c3107 = mcdc.cell(+s132 & -s133 & +s277 & -s278, fill=m29) -c3108 = mcdc.cell(+s132 & -s133 & +s278 & -s279, fill=m30) -c3109 = mcdc.cell(+s132 & -s133 & +s279 & -s280, fill=m31) -c3110 = mcdc.cell(+s132 & -s133 & +s280 & -s281, fill=m32) -c3111 = mcdc.cell(+s132 & -s133 & +s281 & -s282, fill=m33) -c3112 = mcdc.cell(+s132 & -s133 & +s282 & -s283, fill=m34) -c3113 = mcdc.cell(+s132 & -s133 & +s283 & -s284, fill=m35) -c3114 = mcdc.cell(+s132 & -s133 & +s284 & -s285, fill=m36) -c3115 = mcdc.cell(+s132 & -s133 & +s285, fill=m37) -c3116 = mcdc.cell(+s133 & -s134 & -s277, fill=m28) -c3117 = mcdc.cell(+s133 & -s134 & +s277 & -s278, fill=m29) -c3118 = mcdc.cell(+s133 & -s134 & +s278 & -s279, fill=m30) -c3119 = mcdc.cell(+s133 & -s134 & +s279 & -s280, fill=m31) -c3120 = mcdc.cell(+s133 & -s134 & +s280 & -s281, fill=m32) -c3121 = mcdc.cell(+s133 & -s134 & +s281 & -s282, fill=m33) -c3122 = mcdc.cell(+s133 & -s134 & +s282 & -s283, fill=m34) -c3123 = mcdc.cell(+s133 & -s134 & +s283 & -s284, fill=m35) -c3124 = mcdc.cell(+s133 & -s134 & +s284 & -s285, fill=m36) -c3125 = mcdc.cell(+s133 & -s134 & +s285, fill=m37) -c3126 = mcdc.cell(+s134 & -s135 & -s277, fill=m28) -c3127 = mcdc.cell(+s134 & -s135 & +s277 & -s278, fill=m29) -c3128 = mcdc.cell(+s134 & -s135 & +s278 & -s279, fill=m30) -c3129 = mcdc.cell(+s134 & -s135 & +s279 & -s280, fill=m31) -c3130 = mcdc.cell(+s134 & -s135 & +s280 & -s281, fill=m32) -c3131 = mcdc.cell(+s134 & -s135 & +s281 & -s282, fill=m33) -c3132 = mcdc.cell(+s134 & -s135 & +s282 & -s283, fill=m34) -c3133 = mcdc.cell(+s134 & -s135 & +s283 & -s284, fill=m35) -c3134 = mcdc.cell(+s134 & -s135 & +s284 & -s285, fill=m36) -c3135 = mcdc.cell(+s134 & -s135 & +s285, fill=m37) -c3136 = mcdc.cell(+s135 & -s136 & -s277, fill=m28) -c3137 = mcdc.cell(+s135 & -s136 & +s277 & -s278, fill=m29) -c3138 = mcdc.cell(+s135 & -s136 & +s278 & -s279, fill=m30) -c3139 = mcdc.cell(+s135 & -s136 & +s279 & -s280, fill=m31) -c3140 = mcdc.cell(+s135 & -s136 & +s280 & -s281, fill=m32) -c3141 = mcdc.cell(+s135 & -s136 & +s281 & -s282, fill=m33) -c3142 = mcdc.cell(+s135 & -s136 & +s282 & -s283, fill=m34) -c3143 = mcdc.cell(+s135 & -s136 & +s283 & -s284, fill=m35) -c3144 = mcdc.cell(+s135 & -s136 & +s284 & -s285, fill=m36) -c3145 = mcdc.cell(+s135 & -s136 & +s285, fill=m37) -c3146 = mcdc.cell(+s136 & -s137 & -s277, fill=m28) -c3147 = mcdc.cell(+s136 & -s137 & +s277 & -s278, fill=m29) -c3148 = mcdc.cell(+s136 & -s137 & +s278 & -s279, fill=m30) -c3149 = mcdc.cell(+s136 & -s137 & +s279 & -s280, fill=m31) -c3150 = mcdc.cell(+s136 & -s137 & +s280 & -s281, fill=m32) -c3151 = mcdc.cell(+s136 & -s137 & +s281 & -s282, fill=m33) -c3152 = mcdc.cell(+s136 & -s137 & +s282 & -s283, fill=m34) -c3153 = mcdc.cell(+s136 & -s137 & +s283 & -s284, fill=m35) -c3154 = mcdc.cell(+s136 & -s137 & +s284 & -s285, fill=m36) -c3155 = mcdc.cell(+s136 & -s137 & +s285, fill=m37) -c3156 = mcdc.cell(+s137 & -s138 & -s277, fill=m28) -c3157 = mcdc.cell(+s137 & -s138 & +s277 & -s278, fill=m29) -c3158 = mcdc.cell(+s137 & -s138 & +s278 & -s279, fill=m30) -c3159 = mcdc.cell(+s137 & -s138 & +s279 & -s280, fill=m31) -c3160 = mcdc.cell(+s137 & -s138 & +s280 & -s281, fill=m32) -c3161 = mcdc.cell(+s137 & -s138 & +s281 & -s282, fill=m33) -c3162 = mcdc.cell(+s137 & -s138 & +s282 & -s283, fill=m34) -c3163 = mcdc.cell(+s137 & -s138 & +s283 & -s284, fill=m35) -c3164 = mcdc.cell(+s137 & -s138 & +s284 & -s285, fill=m36) -c3165 = mcdc.cell(+s137 & -s138 & +s285, fill=m37) -c3166 = mcdc.cell(+s138 & -s139 & -s277, fill=m28) -c3167 = mcdc.cell(+s138 & -s139 & +s277 & -s278, fill=m29) -c3168 = mcdc.cell(+s138 & -s139 & +s278 & -s279, fill=m30) -c3169 = mcdc.cell(+s138 & -s139 & +s279 & -s280, fill=m31) -c3170 = mcdc.cell(+s138 & -s139 & +s280 & -s281, fill=m32) -c3171 = mcdc.cell(+s138 & -s139 & +s281 & -s282, fill=m33) -c3172 = mcdc.cell(+s138 & -s139 & +s282 & -s283, fill=m34) -c3173 = mcdc.cell(+s138 & -s139 & +s283 & -s284, fill=m35) -c3174 = mcdc.cell(+s138 & -s139 & +s284 & -s285, fill=m36) -c3175 = mcdc.cell(+s138 & -s139 & +s285, fill=m37) -c3176 = mcdc.cell(+s139 & -s140 & -s277, fill=m28) -c3177 = mcdc.cell(+s139 & -s140 & +s277 & -s278, fill=m29) -c3178 = mcdc.cell(+s139 & -s140 & +s278 & -s279, fill=m30) -c3179 = mcdc.cell(+s139 & -s140 & +s279 & -s280, fill=m31) -c3180 = mcdc.cell(+s139 & -s140 & +s280 & -s281, fill=m32) -c3181 = mcdc.cell(+s139 & -s140 & +s281 & -s282, fill=m33) -c3182 = mcdc.cell(+s139 & -s140 & +s282 & -s283, fill=m34) -c3183 = mcdc.cell(+s139 & -s140 & +s283 & -s284, fill=m35) -c3184 = mcdc.cell(+s139 & -s140 & +s284 & -s285, fill=m36) -c3185 = mcdc.cell(+s139 & -s140 & +s285, fill=m37) -c3186 = mcdc.cell(+s140 & -s141 & -s277, fill=m28) -c3187 = mcdc.cell(+s140 & -s141 & +s277 & -s278, fill=m29) -c3188 = mcdc.cell(+s140 & -s141 & +s278 & -s279, fill=m30) -c3189 = mcdc.cell(+s140 & -s141 & +s279 & -s280, fill=m31) -c3190 = mcdc.cell(+s140 & -s141 & +s280 & -s281, fill=m32) -c3191 = mcdc.cell(+s140 & -s141 & +s281 & -s282, fill=m33) -c3192 = mcdc.cell(+s140 & -s141 & +s282 & -s283, fill=m34) -c3193 = mcdc.cell(+s140 & -s141 & +s283 & -s284, fill=m35) -c3194 = mcdc.cell(+s140 & -s141 & +s284 & -s285, fill=m36) -c3195 = mcdc.cell(+s140 & -s141 & +s285, fill=m37) -c3196 = mcdc.cell(+s141 & -s142 & -s277, fill=m28) -c3197 = mcdc.cell(+s141 & -s142 & +s277 & -s278, fill=m29) -c3198 = mcdc.cell(+s141 & -s142 & +s278 & -s279, fill=m30) -c3199 = mcdc.cell(+s141 & -s142 & +s279 & -s280, fill=m31) -c3200 = mcdc.cell(+s141 & -s142 & +s280 & -s281, fill=m32) -c3201 = mcdc.cell(+s141 & -s142 & +s281 & -s282, fill=m33) -c3202 = mcdc.cell(+s141 & -s142 & +s282 & -s283, fill=m34) -c3203 = mcdc.cell(+s141 & -s142 & +s283 & -s284, fill=m35) -c3204 = mcdc.cell(+s141 & -s142 & +s284 & -s285, fill=m36) -c3205 = mcdc.cell(+s141 & -s142 & +s285, fill=m37) -c3206 = mcdc.cell(+s142 & -s143 & -s277, fill=m28) -c3207 = mcdc.cell(+s142 & -s143 & +s277 & -s278, fill=m29) -c3208 = mcdc.cell(+s142 & -s143 & +s278 & -s279, fill=m30) -c3209 = mcdc.cell(+s142 & -s143 & +s279 & -s280, fill=m31) -c3210 = mcdc.cell(+s142 & -s143 & +s280 & -s281, fill=m32) -c3211 = mcdc.cell(+s142 & -s143 & +s281 & -s282, fill=m33) -c3212 = mcdc.cell(+s142 & -s143 & +s282 & -s283, fill=m34) -c3213 = mcdc.cell(+s142 & -s143 & +s283 & -s284, fill=m35) -c3214 = mcdc.cell(+s142 & -s143 & +s284 & -s285, fill=m36) -c3215 = mcdc.cell(+s142 & -s143 & +s285, fill=m37) -c3216 = mcdc.cell(+s143 & -s144 & -s277, fill=m28) -c3217 = mcdc.cell(+s143 & -s144 & +s277 & -s278, fill=m29) -c3218 = mcdc.cell(+s143 & -s144 & +s278 & -s279, fill=m30) -c3219 = mcdc.cell(+s143 & -s144 & +s279 & -s280, fill=m31) -c3220 = mcdc.cell(+s143 & -s144 & +s280 & -s281, fill=m32) -c3221 = mcdc.cell(+s143 & -s144 & +s281 & -s282, fill=m33) -c3222 = mcdc.cell(+s143 & -s144 & +s282 & -s283, fill=m34) -c3223 = mcdc.cell(+s143 & -s144 & +s283 & -s284, fill=m35) -c3224 = mcdc.cell(+s143 & -s144 & +s284 & -s285, fill=m36) -c3225 = mcdc.cell(+s143 & -s144 & +s285, fill=m37) -c3226 = mcdc.cell(+s144 & -s145 & -s277, fill=m28) -c3227 = mcdc.cell(+s144 & -s145 & +s277 & -s278, fill=m29) -c3228 = mcdc.cell(+s144 & -s145 & +s278 & -s279, fill=m30) -c3229 = mcdc.cell(+s144 & -s145 & +s279 & -s280, fill=m31) -c3230 = mcdc.cell(+s144 & -s145 & +s280 & -s281, fill=m32) -c3231 = mcdc.cell(+s144 & -s145 & +s281 & -s282, fill=m33) -c3232 = mcdc.cell(+s144 & -s145 & +s282 & -s283, fill=m34) -c3233 = mcdc.cell(+s144 & -s145 & +s283 & -s284, fill=m35) -c3234 = mcdc.cell(+s144 & -s145 & +s284 & -s285, fill=m36) -c3235 = mcdc.cell(+s144 & -s145 & +s285, fill=m37) -c3236 = mcdc.cell(+s145 & -s146 & -s277, fill=m28) -c3237 = mcdc.cell(+s145 & -s146 & +s277 & -s278, fill=m29) -c3238 = mcdc.cell(+s145 & -s146 & +s278 & -s279, fill=m30) -c3239 = mcdc.cell(+s145 & -s146 & +s279 & -s280, fill=m31) -c3240 = mcdc.cell(+s145 & -s146 & +s280 & -s281, fill=m32) -c3241 = mcdc.cell(+s145 & -s146 & +s281 & -s282, fill=m33) -c3242 = mcdc.cell(+s145 & -s146 & +s282 & -s283, fill=m34) -c3243 = mcdc.cell(+s145 & -s146 & +s283 & -s284, fill=m35) -c3244 = mcdc.cell(+s145 & -s146 & +s284 & -s285, fill=m36) -c3245 = mcdc.cell(+s145 & -s146 & +s285, fill=m37) -c3246 = mcdc.cell(+s146 & -s147 & -s277, fill=m28) -c3247 = mcdc.cell(+s146 & -s147 & +s277 & -s278, fill=m29) -c3248 = mcdc.cell(+s146 & -s147 & +s278 & -s279, fill=m30) -c3249 = mcdc.cell(+s146 & -s147 & +s279 & -s280, fill=m31) -c3250 = mcdc.cell(+s146 & -s147 & +s280 & -s281, fill=m32) -c3251 = mcdc.cell(+s146 & -s147 & +s281 & -s282, fill=m33) -c3252 = mcdc.cell(+s146 & -s147 & +s282 & -s283, fill=m34) -c3253 = mcdc.cell(+s146 & -s147 & +s283 & -s284, fill=m35) -c3254 = mcdc.cell(+s146 & -s147 & +s284 & -s285, fill=m36) -c3255 = mcdc.cell(+s146 & -s147 & +s285, fill=m37) -c3256 = mcdc.cell(+s147 & -s148 & -s277, fill=m28) -c3257 = mcdc.cell(+s147 & -s148 & +s277 & -s278, fill=m29) -c3258 = mcdc.cell(+s147 & -s148 & +s278 & -s279, fill=m30) -c3259 = mcdc.cell(+s147 & -s148 & +s279 & -s280, fill=m31) -c3260 = mcdc.cell(+s147 & -s148 & +s280 & -s281, fill=m32) -c3261 = mcdc.cell(+s147 & -s148 & +s281 & -s282, fill=m33) -c3262 = mcdc.cell(+s147 & -s148 & +s282 & -s283, fill=m34) -c3263 = mcdc.cell(+s147 & -s148 & +s283 & -s284, fill=m35) -c3264 = mcdc.cell(+s147 & -s148 & +s284 & -s285, fill=m36) -c3265 = mcdc.cell(+s147 & -s148 & +s285, fill=m37) -c3266 = mcdc.cell(+s148 & -s149 & -s277, fill=m28) -c3267 = mcdc.cell(+s148 & -s149 & +s277 & -s278, fill=m29) -c3268 = mcdc.cell(+s148 & -s149 & +s278 & -s279, fill=m30) -c3269 = mcdc.cell(+s148 & -s149 & +s279 & -s280, fill=m31) -c3270 = mcdc.cell(+s148 & -s149 & +s280 & -s281, fill=m32) -c3271 = mcdc.cell(+s148 & -s149 & +s281 & -s282, fill=m33) -c3272 = mcdc.cell(+s148 & -s149 & +s282 & -s283, fill=m34) -c3273 = mcdc.cell(+s148 & -s149 & +s283 & -s284, fill=m35) -c3274 = mcdc.cell(+s148 & -s149 & +s284 & -s285, fill=m36) -c3275 = mcdc.cell(+s148 & -s149 & +s285, fill=m37) -c3276 = mcdc.cell(+s149 & -s150 & -s277, fill=m28) -c3277 = mcdc.cell(+s149 & -s150 & +s277 & -s278, fill=m29) -c3278 = mcdc.cell(+s149 & -s150 & +s278 & -s279, fill=m30) -c3279 = mcdc.cell(+s149 & -s150 & +s279 & -s280, fill=m31) -c3280 = mcdc.cell(+s149 & -s150 & +s280 & -s281, fill=m32) -c3281 = mcdc.cell(+s149 & -s150 & +s281 & -s282, fill=m33) -c3282 = mcdc.cell(+s149 & -s150 & +s282 & -s283, fill=m34) -c3283 = mcdc.cell(+s149 & -s150 & +s283 & -s284, fill=m35) -c3284 = mcdc.cell(+s149 & -s150 & +s284 & -s285, fill=m36) -c3285 = mcdc.cell(+s149 & -s150 & +s285, fill=m37) -c3286 = mcdc.cell(+s150 & -s151 & -s277, fill=m28) -c3287 = mcdc.cell(+s150 & -s151 & +s277 & -s278, fill=m29) -c3288 = mcdc.cell(+s150 & -s151 & +s278 & -s279, fill=m30) -c3289 = mcdc.cell(+s150 & -s151 & +s279 & -s280, fill=m31) -c3290 = mcdc.cell(+s150 & -s151 & +s280 & -s281, fill=m32) -c3291 = mcdc.cell(+s150 & -s151 & +s281 & -s282, fill=m33) -c3292 = mcdc.cell(+s150 & -s151 & +s282 & -s283, fill=m34) -c3293 = mcdc.cell(+s150 & -s151 & +s283 & -s284, fill=m35) -c3294 = mcdc.cell(+s150 & -s151 & +s284 & -s285, fill=m36) -c3295 = mcdc.cell(+s150 & -s151 & +s285, fill=m37) -c3296 = mcdc.cell(+s151 & -s152 & -s277, fill=m28) -c3297 = mcdc.cell(+s151 & -s152 & +s277 & -s278, fill=m29) -c3298 = mcdc.cell(+s151 & -s152 & +s278 & -s279, fill=m30) -c3299 = mcdc.cell(+s151 & -s152 & +s279 & -s280, fill=m31) -c3300 = mcdc.cell(+s151 & -s152 & +s280 & -s281, fill=m32) -c3301 = mcdc.cell(+s151 & -s152 & +s281 & -s282, fill=m33) -c3302 = mcdc.cell(+s151 & -s152 & +s282 & -s283, fill=m34) -c3303 = mcdc.cell(+s151 & -s152 & +s283 & -s284, fill=m35) -c3304 = mcdc.cell(+s151 & -s152 & +s284 & -s285, fill=m36) -c3305 = mcdc.cell(+s151 & -s152 & +s285, fill=m37) -c3306 = mcdc.cell(+s152 & -s153 & -s277, fill=m28) -c3307 = mcdc.cell(+s152 & -s153 & +s277 & -s278, fill=m29) -c3308 = mcdc.cell(+s152 & -s153 & +s278 & -s279, fill=m30) -c3309 = mcdc.cell(+s152 & -s153 & +s279 & -s280, fill=m31) -c3310 = mcdc.cell(+s152 & -s153 & +s280 & -s281, fill=m32) -c3311 = mcdc.cell(+s152 & -s153 & +s281 & -s282, fill=m33) -c3312 = mcdc.cell(+s152 & -s153 & +s282 & -s283, fill=m34) -c3313 = mcdc.cell(+s152 & -s153 & +s283 & -s284, fill=m35) -c3314 = mcdc.cell(+s152 & -s153 & +s284 & -s285, fill=m36) -c3315 = mcdc.cell(+s152 & -s153 & +s285, fill=m37) -c3316 = mcdc.cell(+s153 & -s154 & -s277, fill=m28) -c3317 = mcdc.cell(+s153 & -s154 & +s277 & -s278, fill=m29) -c3318 = mcdc.cell(+s153 & -s154 & +s278 & -s279, fill=m30) -c3319 = mcdc.cell(+s153 & -s154 & +s279 & -s280, fill=m31) -c3320 = mcdc.cell(+s153 & -s154 & +s280 & -s281, fill=m32) -c3321 = mcdc.cell(+s153 & -s154 & +s281 & -s282, fill=m33) -c3322 = mcdc.cell(+s153 & -s154 & +s282 & -s283, fill=m34) -c3323 = mcdc.cell(+s153 & -s154 & +s283 & -s284, fill=m35) -c3324 = mcdc.cell(+s153 & -s154 & +s284 & -s285, fill=m36) -c3325 = mcdc.cell(+s153 & -s154 & +s285, fill=m37) -c3326 = mcdc.cell(+s154 & -s155 & -s277, fill=m28) -c3327 = mcdc.cell(+s154 & -s155 & +s277 & -s278, fill=m29) -c3328 = mcdc.cell(+s154 & -s155 & +s278 & -s279, fill=m30) -c3329 = mcdc.cell(+s154 & -s155 & +s279 & -s280, fill=m31) -c3330 = mcdc.cell(+s154 & -s155 & +s280 & -s281, fill=m32) -c3331 = mcdc.cell(+s154 & -s155 & +s281 & -s282, fill=m33) -c3332 = mcdc.cell(+s154 & -s155 & +s282 & -s283, fill=m34) -c3333 = mcdc.cell(+s154 & -s155 & +s283 & -s284, fill=m35) -c3334 = mcdc.cell(+s154 & -s155 & +s284 & -s285, fill=m36) -c3335 = mcdc.cell(+s154 & -s155 & +s285, fill=m37) -c3336 = mcdc.cell(+s155 & -s156 & -s277, fill=m28) -c3337 = mcdc.cell(+s155 & -s156 & +s277 & -s278, fill=m29) -c3338 = mcdc.cell(+s155 & -s156 & +s278 & -s279, fill=m30) -c3339 = mcdc.cell(+s155 & -s156 & +s279 & -s280, fill=m31) -c3340 = mcdc.cell(+s155 & -s156 & +s280 & -s281, fill=m32) -c3341 = mcdc.cell(+s155 & -s156 & +s281 & -s282, fill=m33) -c3342 = mcdc.cell(+s155 & -s156 & +s282 & -s283, fill=m34) -c3343 = mcdc.cell(+s155 & -s156 & +s283 & -s284, fill=m35) -c3344 = mcdc.cell(+s155 & -s156 & +s284 & -s285, fill=m36) -c3345 = mcdc.cell(+s155 & -s156 & +s285, fill=m37) -c3346 = mcdc.cell(+s156 & -s157 & -s277, fill=m28) -c3347 = mcdc.cell(+s156 & -s157 & +s277 & -s278, fill=m29) -c3348 = mcdc.cell(+s156 & -s157 & +s278 & -s279, fill=m30) -c3349 = mcdc.cell(+s156 & -s157 & +s279 & -s280, fill=m31) -c3350 = mcdc.cell(+s156 & -s157 & +s280 & -s281, fill=m32) -c3351 = mcdc.cell(+s156 & -s157 & +s281 & -s282, fill=m33) -c3352 = mcdc.cell(+s156 & -s157 & +s282 & -s283, fill=m34) -c3353 = mcdc.cell(+s156 & -s157 & +s283 & -s284, fill=m35) -c3354 = mcdc.cell(+s156 & -s157 & +s284 & -s285, fill=m36) -c3355 = mcdc.cell(+s156 & -s157 & +s285, fill=m37) -c3356 = mcdc.cell(+s157 & -s158 & -s277, fill=m28) -c3357 = mcdc.cell(+s157 & -s158 & +s277 & -s278, fill=m29) -c3358 = mcdc.cell(+s157 & -s158 & +s278 & -s279, fill=m30) -c3359 = mcdc.cell(+s157 & -s158 & +s279 & -s280, fill=m31) -c3360 = mcdc.cell(+s157 & -s158 & +s280 & -s281, fill=m32) -c3361 = mcdc.cell(+s157 & -s158 & +s281 & -s282, fill=m33) -c3362 = mcdc.cell(+s157 & -s158 & +s282 & -s283, fill=m34) -c3363 = mcdc.cell(+s157 & -s158 & +s283 & -s284, fill=m35) -c3364 = mcdc.cell(+s157 & -s158 & +s284 & -s285, fill=m36) -c3365 = mcdc.cell(+s157 & -s158 & +s285, fill=m37) -c3366 = mcdc.cell(+s158 & -s159 & -s277, fill=m28) -c3367 = mcdc.cell(+s158 & -s159 & +s277 & -s278, fill=m29) -c3368 = mcdc.cell(+s158 & -s159 & +s278 & -s279, fill=m30) -c3369 = mcdc.cell(+s158 & -s159 & +s279 & -s280, fill=m31) -c3370 = mcdc.cell(+s158 & -s159 & +s280 & -s281, fill=m32) -c3371 = mcdc.cell(+s158 & -s159 & +s281 & -s282, fill=m33) -c3372 = mcdc.cell(+s158 & -s159 & +s282 & -s283, fill=m34) -c3373 = mcdc.cell(+s158 & -s159 & +s283 & -s284, fill=m35) -c3374 = mcdc.cell(+s158 & -s159 & +s284 & -s285, fill=m36) -c3375 = mcdc.cell(+s158 & -s159 & +s285, fill=m37) -c3376 = mcdc.cell(+s159 & -s160 & -s277, fill=m28) -c3377 = mcdc.cell(+s159 & -s160 & +s277 & -s278, fill=m29) -c3378 = mcdc.cell(+s159 & -s160 & +s278 & -s279, fill=m30) -c3379 = mcdc.cell(+s159 & -s160 & +s279 & -s280, fill=m31) -c3380 = mcdc.cell(+s159 & -s160 & +s280 & -s281, fill=m32) -c3381 = mcdc.cell(+s159 & -s160 & +s281 & -s282, fill=m33) -c3382 = mcdc.cell(+s159 & -s160 & +s282 & -s283, fill=m34) -c3383 = mcdc.cell(+s159 & -s160 & +s283 & -s284, fill=m35) -c3384 = mcdc.cell(+s159 & -s160 & +s284 & -s285, fill=m36) -c3385 = mcdc.cell(+s159 & -s160 & +s285, fill=m37) -c3386 = mcdc.cell(+s160 & -s161 & -s277, fill=m28) -c3387 = mcdc.cell(+s160 & -s161 & +s277 & -s278, fill=m29) -c3388 = mcdc.cell(+s160 & -s161 & +s278 & -s279, fill=m30) -c3389 = mcdc.cell(+s160 & -s161 & +s279 & -s280, fill=m31) -c3390 = mcdc.cell(+s160 & -s161 & +s280 & -s281, fill=m32) -c3391 = mcdc.cell(+s160 & -s161 & +s281 & -s282, fill=m33) -c3392 = mcdc.cell(+s160 & -s161 & +s282 & -s283, fill=m34) -c3393 = mcdc.cell(+s160 & -s161 & +s283 & -s284, fill=m35) -c3394 = mcdc.cell(+s160 & -s161 & +s284 & -s285, fill=m36) -c3395 = mcdc.cell(+s160 & -s161 & +s285, fill=m37) -c3396 = mcdc.cell(+s161 & -s162 & -s277, fill=m28) -c3397 = mcdc.cell(+s161 & -s162 & +s277 & -s278, fill=m29) -c3398 = mcdc.cell(+s161 & -s162 & +s278 & -s279, fill=m30) -c3399 = mcdc.cell(+s161 & -s162 & +s279 & -s280, fill=m31) -c3400 = mcdc.cell(+s161 & -s162 & +s280 & -s281, fill=m32) -c3401 = mcdc.cell(+s161 & -s162 & +s281 & -s282, fill=m33) -c3402 = mcdc.cell(+s161 & -s162 & +s282 & -s283, fill=m34) -c3403 = mcdc.cell(+s161 & -s162 & +s283 & -s284, fill=m35) -c3404 = mcdc.cell(+s161 & -s162 & +s284 & -s285, fill=m36) -c3405 = mcdc.cell(+s161 & -s162 & +s285, fill=m37) -c3406 = mcdc.cell(+s162 & -s163 & -s277, fill=m28) -c3407 = mcdc.cell(+s162 & -s163 & +s277 & -s278, fill=m29) -c3408 = mcdc.cell(+s162 & -s163 & +s278 & -s279, fill=m30) -c3409 = mcdc.cell(+s162 & -s163 & +s279 & -s280, fill=m31) -c3410 = mcdc.cell(+s162 & -s163 & +s280 & -s281, fill=m32) -c3411 = mcdc.cell(+s162 & -s163 & +s281 & -s282, fill=m33) -c3412 = mcdc.cell(+s162 & -s163 & +s282 & -s283, fill=m34) -c3413 = mcdc.cell(+s162 & -s163 & +s283 & -s284, fill=m35) -c3414 = mcdc.cell(+s162 & -s163 & +s284 & -s285, fill=m36) -c3415 = mcdc.cell(+s162 & -s163 & +s285, fill=m37) -c3416 = mcdc.cell(+s163 & -s164 & -s277, fill=m28) -c3417 = mcdc.cell(+s163 & -s164 & +s277 & -s278, fill=m29) -c3418 = mcdc.cell(+s163 & -s164 & +s278 & -s279, fill=m30) -c3419 = mcdc.cell(+s163 & -s164 & +s279 & -s280, fill=m31) -c3420 = mcdc.cell(+s163 & -s164 & +s280 & -s281, fill=m32) -c3421 = mcdc.cell(+s163 & -s164 & +s281 & -s282, fill=m33) -c3422 = mcdc.cell(+s163 & -s164 & +s282 & -s283, fill=m34) -c3423 = mcdc.cell(+s163 & -s164 & +s283 & -s284, fill=m35) -c3424 = mcdc.cell(+s163 & -s164 & +s284 & -s285, fill=m36) -c3425 = mcdc.cell(+s163 & -s164 & +s285, fill=m37) -c3426 = mcdc.cell(+s164 & -s165 & -s277, fill=m28) -c3427 = mcdc.cell(+s164 & -s165 & +s277 & -s278, fill=m29) -c3428 = mcdc.cell(+s164 & -s165 & +s278 & -s279, fill=m30) -c3429 = mcdc.cell(+s164 & -s165 & +s279 & -s280, fill=m31) -c3430 = mcdc.cell(+s164 & -s165 & +s280 & -s281, fill=m32) -c3431 = mcdc.cell(+s164 & -s165 & +s281 & -s282, fill=m33) -c3432 = mcdc.cell(+s164 & -s165 & +s282 & -s283, fill=m34) -c3433 = mcdc.cell(+s164 & -s165 & +s283 & -s284, fill=m35) -c3434 = mcdc.cell(+s164 & -s165 & +s284 & -s285, fill=m36) -c3435 = mcdc.cell(+s164 & -s165 & +s285, fill=m37) -c3436 = mcdc.cell(+s165 & -s166 & -s277, fill=m28) -c3437 = mcdc.cell(+s165 & -s166 & +s277 & -s278, fill=m29) -c3438 = mcdc.cell(+s165 & -s166 & +s278 & -s279, fill=m30) -c3439 = mcdc.cell(+s165 & -s166 & +s279 & -s280, fill=m31) -c3440 = mcdc.cell(+s165 & -s166 & +s280 & -s281, fill=m32) -c3441 = mcdc.cell(+s165 & -s166 & +s281 & -s282, fill=m33) -c3442 = mcdc.cell(+s165 & -s166 & +s282 & -s283, fill=m34) -c3443 = mcdc.cell(+s165 & -s166 & +s283 & -s284, fill=m35) -c3444 = mcdc.cell(+s165 & -s166 & +s284 & -s285, fill=m36) -c3445 = mcdc.cell(+s165 & -s166 & +s285, fill=m37) -c3446 = mcdc.cell(+s166 & -s167 & -s277, fill=m28) -c3447 = mcdc.cell(+s166 & -s167 & +s277 & -s278, fill=m29) -c3448 = mcdc.cell(+s166 & -s167 & +s278 & -s279, fill=m30) -c3449 = mcdc.cell(+s166 & -s167 & +s279 & -s280, fill=m31) -c3450 = mcdc.cell(+s166 & -s167 & +s280 & -s281, fill=m32) -c3451 = mcdc.cell(+s166 & -s167 & +s281 & -s282, fill=m33) -c3452 = mcdc.cell(+s166 & -s167 & +s282 & -s283, fill=m34) -c3453 = mcdc.cell(+s166 & -s167 & +s283 & -s284, fill=m35) -c3454 = mcdc.cell(+s166 & -s167 & +s284 & -s285, fill=m36) -c3455 = mcdc.cell(+s166 & -s167 & +s285, fill=m37) -c3456 = mcdc.cell(+s167 & -s168 & -s277, fill=m28) -c3457 = mcdc.cell(+s167 & -s168 & +s277 & -s278, fill=m29) -c3458 = mcdc.cell(+s167 & -s168 & +s278 & -s279, fill=m30) -c3459 = mcdc.cell(+s167 & -s168 & +s279 & -s280, fill=m31) -c3460 = mcdc.cell(+s167 & -s168 & +s280 & -s281, fill=m32) -c3461 = mcdc.cell(+s167 & -s168 & +s281 & -s282, fill=m33) -c3462 = mcdc.cell(+s167 & -s168 & +s282 & -s283, fill=m34) -c3463 = mcdc.cell(+s167 & -s168 & +s283 & -s284, fill=m35) -c3464 = mcdc.cell(+s167 & -s168 & +s284 & -s285, fill=m36) -c3465 = mcdc.cell(+s167 & -s168 & +s285, fill=m37) -c3466 = mcdc.cell(+s168 & -s169 & -s277, fill=m28) -c3467 = mcdc.cell(+s168 & -s169 & +s277 & -s278, fill=m29) -c3468 = mcdc.cell(+s168 & -s169 & +s278 & -s279, fill=m30) -c3469 = mcdc.cell(+s168 & -s169 & +s279 & -s280, fill=m31) -c3470 = mcdc.cell(+s168 & -s169 & +s280 & -s281, fill=m32) -c3471 = mcdc.cell(+s168 & -s169 & +s281 & -s282, fill=m33) -c3472 = mcdc.cell(+s168 & -s169 & +s282 & -s283, fill=m34) -c3473 = mcdc.cell(+s168 & -s169 & +s283 & -s284, fill=m35) -c3474 = mcdc.cell(+s168 & -s169 & +s284 & -s285, fill=m36) -c3475 = mcdc.cell(+s168 & -s169 & +s285, fill=m37) -c3476 = mcdc.cell(+s169 & -s170 & -s277, fill=m28) -c3477 = mcdc.cell(+s169 & -s170 & +s277 & -s278, fill=m29) -c3478 = mcdc.cell(+s169 & -s170 & +s278 & -s279, fill=m30) -c3479 = mcdc.cell(+s169 & -s170 & +s279 & -s280, fill=m31) -c3480 = mcdc.cell(+s169 & -s170 & +s280 & -s281, fill=m32) -c3481 = mcdc.cell(+s169 & -s170 & +s281 & -s282, fill=m33) -c3482 = mcdc.cell(+s169 & -s170 & +s282 & -s283, fill=m34) -c3483 = mcdc.cell(+s169 & -s170 & +s283 & -s284, fill=m35) -c3484 = mcdc.cell(+s169 & -s170 & +s284 & -s285, fill=m36) -c3485 = mcdc.cell(+s169 & -s170 & +s285, fill=m37) -c3486 = mcdc.cell(+s170 & -s171 & -s277, fill=m28) -c3487 = mcdc.cell(+s170 & -s171 & +s277 & -s278, fill=m29) -c3488 = mcdc.cell(+s170 & -s171 & +s278 & -s279, fill=m30) -c3489 = mcdc.cell(+s170 & -s171 & +s279 & -s280, fill=m31) -c3490 = mcdc.cell(+s170 & -s171 & +s280 & -s281, fill=m32) -c3491 = mcdc.cell(+s170 & -s171 & +s281 & -s282, fill=m33) -c3492 = mcdc.cell(+s170 & -s171 & +s282 & -s283, fill=m34) -c3493 = mcdc.cell(+s170 & -s171 & +s283 & -s284, fill=m35) -c3494 = mcdc.cell(+s170 & -s171 & +s284 & -s285, fill=m36) -c3495 = mcdc.cell(+s170 & -s171 & +s285, fill=m37) -c3496 = mcdc.cell(+s171 & -s172 & -s277, fill=m28) -c3497 = mcdc.cell(+s171 & -s172 & +s277 & -s278, fill=m29) -c3498 = mcdc.cell(+s171 & -s172 & +s278 & -s279, fill=m30) -c3499 = mcdc.cell(+s171 & -s172 & +s279 & -s280, fill=m31) -c3500 = mcdc.cell(+s171 & -s172 & +s280 & -s281, fill=m32) -c3501 = mcdc.cell(+s171 & -s172 & +s281 & -s282, fill=m33) -c3502 = mcdc.cell(+s171 & -s172 & +s282 & -s283, fill=m34) -c3503 = mcdc.cell(+s171 & -s172 & +s283 & -s284, fill=m35) -c3504 = mcdc.cell(+s171 & -s172 & +s284 & -s285, fill=m36) -c3505 = mcdc.cell(+s171 & -s172 & +s285, fill=m37) -c3506 = mcdc.cell(+s172 & -s173 & -s277, fill=m28) -c3507 = mcdc.cell(+s172 & -s173 & +s277 & -s278, fill=m29) -c3508 = mcdc.cell(+s172 & -s173 & +s278 & -s279, fill=m30) -c3509 = mcdc.cell(+s172 & -s173 & +s279 & -s280, fill=m31) -c3510 = mcdc.cell(+s172 & -s173 & +s280 & -s281, fill=m32) -c3511 = mcdc.cell(+s172 & -s173 & +s281 & -s282, fill=m33) -c3512 = mcdc.cell(+s172 & -s173 & +s282 & -s283, fill=m34) -c3513 = mcdc.cell(+s172 & -s173 & +s283 & -s284, fill=m35) -c3514 = mcdc.cell(+s172 & -s173 & +s284 & -s285, fill=m36) -c3515 = mcdc.cell(+s172 & -s173 & +s285, fill=m37) -c3516 = mcdc.cell(+s173 & -s174 & -s277, fill=m28) -c3517 = mcdc.cell(+s173 & -s174 & +s277 & -s278, fill=m29) -c3518 = mcdc.cell(+s173 & -s174 & +s278 & -s279, fill=m30) -c3519 = mcdc.cell(+s173 & -s174 & +s279 & -s280, fill=m31) -c3520 = mcdc.cell(+s173 & -s174 & +s280 & -s281, fill=m32) -c3521 = mcdc.cell(+s173 & -s174 & +s281 & -s282, fill=m33) -c3522 = mcdc.cell(+s173 & -s174 & +s282 & -s283, fill=m34) -c3523 = mcdc.cell(+s173 & -s174 & +s283 & -s284, fill=m35) -c3524 = mcdc.cell(+s173 & -s174 & +s284 & -s285, fill=m36) -c3525 = mcdc.cell(+s173 & -s174 & +s285, fill=m37) -c3526 = mcdc.cell(+s174 & -s175 & -s277, fill=m28) -c3527 = mcdc.cell(+s174 & -s175 & +s277 & -s278, fill=m29) -c3528 = mcdc.cell(+s174 & -s175 & +s278 & -s279, fill=m30) -c3529 = mcdc.cell(+s174 & -s175 & +s279 & -s280, fill=m31) -c3530 = mcdc.cell(+s174 & -s175 & +s280 & -s281, fill=m32) -c3531 = mcdc.cell(+s174 & -s175 & +s281 & -s282, fill=m33) -c3532 = mcdc.cell(+s174 & -s175 & +s282 & -s283, fill=m34) -c3533 = mcdc.cell(+s174 & -s175 & +s283 & -s284, fill=m35) -c3534 = mcdc.cell(+s174 & -s175 & +s284 & -s285, fill=m36) -c3535 = mcdc.cell(+s174 & -s175 & +s285, fill=m37) -c3536 = mcdc.cell(+s175 & -s176 & -s277, fill=m28) -c3537 = mcdc.cell(+s175 & -s176 & +s277 & -s278, fill=m29) -c3538 = mcdc.cell(+s175 & -s176 & +s278 & -s279, fill=m30) -c3539 = mcdc.cell(+s175 & -s176 & +s279 & -s280, fill=m31) -c3540 = mcdc.cell(+s175 & -s176 & +s280 & -s281, fill=m32) -c3541 = mcdc.cell(+s175 & -s176 & +s281 & -s282, fill=m33) -c3542 = mcdc.cell(+s175 & -s176 & +s282 & -s283, fill=m34) -c3543 = mcdc.cell(+s175 & -s176 & +s283 & -s284, fill=m35) -c3544 = mcdc.cell(+s175 & -s176 & +s284 & -s285, fill=m36) -c3545 = mcdc.cell(+s175 & -s176 & +s285, fill=m37) -c3546 = mcdc.cell(+s176 & -s177 & -s277, fill=m28) -c3547 = mcdc.cell(+s176 & -s177 & +s277 & -s278, fill=m29) -c3548 = mcdc.cell(+s176 & -s177 & +s278 & -s279, fill=m30) -c3549 = mcdc.cell(+s176 & -s177 & +s279 & -s280, fill=m31) -c3550 = mcdc.cell(+s176 & -s177 & +s280 & -s281, fill=m32) -c3551 = mcdc.cell(+s176 & -s177 & +s281 & -s282, fill=m33) -c3552 = mcdc.cell(+s176 & -s177 & +s282 & -s283, fill=m34) -c3553 = mcdc.cell(+s176 & -s177 & +s283 & -s284, fill=m35) -c3554 = mcdc.cell(+s176 & -s177 & +s284 & -s285, fill=m36) -c3555 = mcdc.cell(+s176 & -s177 & +s285, fill=m37) -c3556 = mcdc.cell(+s177 & -s178 & -s277, fill=m28) -c3557 = mcdc.cell(+s177 & -s178 & +s277 & -s278, fill=m29) -c3558 = mcdc.cell(+s177 & -s178 & +s278 & -s279, fill=m30) -c3559 = mcdc.cell(+s177 & -s178 & +s279 & -s280, fill=m31) -c3560 = mcdc.cell(+s177 & -s178 & +s280 & -s281, fill=m32) -c3561 = mcdc.cell(+s177 & -s178 & +s281 & -s282, fill=m33) -c3562 = mcdc.cell(+s177 & -s178 & +s282 & -s283, fill=m34) -c3563 = mcdc.cell(+s177 & -s178 & +s283 & -s284, fill=m35) -c3564 = mcdc.cell(+s177 & -s178 & +s284 & -s285, fill=m36) -c3565 = mcdc.cell(+s177 & -s178 & +s285, fill=m37) -c3566 = mcdc.cell(+s178 & -s179 & -s277, fill=m28) -c3567 = mcdc.cell(+s178 & -s179 & +s277 & -s278, fill=m29) -c3568 = mcdc.cell(+s178 & -s179 & +s278 & -s279, fill=m30) -c3569 = mcdc.cell(+s178 & -s179 & +s279 & -s280, fill=m31) -c3570 = mcdc.cell(+s178 & -s179 & +s280 & -s281, fill=m32) -c3571 = mcdc.cell(+s178 & -s179 & +s281 & -s282, fill=m33) -c3572 = mcdc.cell(+s178 & -s179 & +s282 & -s283, fill=m34) -c3573 = mcdc.cell(+s178 & -s179 & +s283 & -s284, fill=m35) -c3574 = mcdc.cell(+s178 & -s179 & +s284 & -s285, fill=m36) -c3575 = mcdc.cell(+s178 & -s179 & +s285, fill=m37) -c3576 = mcdc.cell(+s179 & -s180 & -s277, fill=m28) -c3577 = mcdc.cell(+s179 & -s180 & +s277 & -s278, fill=m29) -c3578 = mcdc.cell(+s179 & -s180 & +s278 & -s279, fill=m30) -c3579 = mcdc.cell(+s179 & -s180 & +s279 & -s280, fill=m31) -c3580 = mcdc.cell(+s179 & -s180 & +s280 & -s281, fill=m32) -c3581 = mcdc.cell(+s179 & -s180 & +s281 & -s282, fill=m33) -c3582 = mcdc.cell(+s179 & -s180 & +s282 & -s283, fill=m34) -c3583 = mcdc.cell(+s179 & -s180 & +s283 & -s284, fill=m35) -c3584 = mcdc.cell(+s179 & -s180 & +s284 & -s285, fill=m36) -c3585 = mcdc.cell(+s179 & -s180 & +s285, fill=m37) -c3586 = mcdc.cell(+s180 & -s181 & -s277, fill=m28) -c3587 = mcdc.cell(+s180 & -s181 & +s277 & -s278, fill=m29) -c3588 = mcdc.cell(+s180 & -s181 & +s278 & -s279, fill=m30) -c3589 = mcdc.cell(+s180 & -s181 & +s279 & -s280, fill=m31) -c3590 = mcdc.cell(+s180 & -s181 & +s280 & -s281, fill=m32) -c3591 = mcdc.cell(+s180 & -s181 & +s281 & -s282, fill=m33) -c3592 = mcdc.cell(+s180 & -s181 & +s282 & -s283, fill=m34) -c3593 = mcdc.cell(+s180 & -s181 & +s283 & -s284, fill=m35) -c3594 = mcdc.cell(+s180 & -s181 & +s284 & -s285, fill=m36) -c3595 = mcdc.cell(+s180 & -s181 & +s285, fill=m37) -c3596 = mcdc.cell(+s181 & -s182 & -s277, fill=m28) -c3597 = mcdc.cell(+s181 & -s182 & +s277 & -s278, fill=m29) -c3598 = mcdc.cell(+s181 & -s182 & +s278 & -s279, fill=m30) -c3599 = mcdc.cell(+s181 & -s182 & +s279 & -s280, fill=m31) -c3600 = mcdc.cell(+s181 & -s182 & +s280 & -s281, fill=m32) -c3601 = mcdc.cell(+s181 & -s182 & +s281 & -s282, fill=m33) -c3602 = mcdc.cell(+s181 & -s182 & +s282 & -s283, fill=m34) -c3603 = mcdc.cell(+s181 & -s182 & +s283 & -s284, fill=m35) -c3604 = mcdc.cell(+s181 & -s182 & +s284 & -s285, fill=m36) -c3605 = mcdc.cell(+s181 & -s182 & +s285, fill=m37) -c3606 = mcdc.cell(+s182 & -s183 & -s277, fill=m28) -c3607 = mcdc.cell(+s182 & -s183 & +s277 & -s278, fill=m29) -c3608 = mcdc.cell(+s182 & -s183 & +s278 & -s279, fill=m30) -c3609 = mcdc.cell(+s182 & -s183 & +s279 & -s280, fill=m31) -c3610 = mcdc.cell(+s182 & -s183 & +s280 & -s281, fill=m32) -c3611 = mcdc.cell(+s182 & -s183 & +s281 & -s282, fill=m33) -c3612 = mcdc.cell(+s182 & -s183 & +s282 & -s283, fill=m34) -c3613 = mcdc.cell(+s182 & -s183 & +s283 & -s284, fill=m35) -c3614 = mcdc.cell(+s182 & -s183 & +s284 & -s285, fill=m36) -c3615 = mcdc.cell(+s182 & -s183 & +s285, fill=m37) -c3616 = mcdc.cell(+s183 & -s184 & -s277, fill=m28) -c3617 = mcdc.cell(+s183 & -s184 & +s277 & -s278, fill=m29) -c3618 = mcdc.cell(+s183 & -s184 & +s278 & -s279, fill=m30) -c3619 = mcdc.cell(+s183 & -s184 & +s279 & -s280, fill=m31) -c3620 = mcdc.cell(+s183 & -s184 & +s280 & -s281, fill=m32) -c3621 = mcdc.cell(+s183 & -s184 & +s281 & -s282, fill=m33) -c3622 = mcdc.cell(+s183 & -s184 & +s282 & -s283, fill=m34) -c3623 = mcdc.cell(+s183 & -s184 & +s283 & -s284, fill=m35) -c3624 = mcdc.cell(+s183 & -s184 & +s284 & -s285, fill=m36) -c3625 = mcdc.cell(+s183 & -s184 & +s285, fill=m37) -c3626 = mcdc.cell(+s184 & -s185 & -s277, fill=m28) -c3627 = mcdc.cell(+s184 & -s185 & +s277 & -s278, fill=m29) -c3628 = mcdc.cell(+s184 & -s185 & +s278 & -s279, fill=m30) -c3629 = mcdc.cell(+s184 & -s185 & +s279 & -s280, fill=m31) -c3630 = mcdc.cell(+s184 & -s185 & +s280 & -s281, fill=m32) -c3631 = mcdc.cell(+s184 & -s185 & +s281 & -s282, fill=m33) -c3632 = mcdc.cell(+s184 & -s185 & +s282 & -s283, fill=m34) -c3633 = mcdc.cell(+s184 & -s185 & +s283 & -s284, fill=m35) -c3634 = mcdc.cell(+s184 & -s185 & +s284 & -s285, fill=m36) -c3635 = mcdc.cell(+s184 & -s185 & +s285, fill=m37) -c3636 = mcdc.cell(+s185 & -s186 & -s277, fill=m28) -c3637 = mcdc.cell(+s185 & -s186 & +s277 & -s278, fill=m29) -c3638 = mcdc.cell(+s185 & -s186 & +s278 & -s279, fill=m30) -c3639 = mcdc.cell(+s185 & -s186 & +s279 & -s280, fill=m31) -c3640 = mcdc.cell(+s185 & -s186 & +s280 & -s281, fill=m32) -c3641 = mcdc.cell(+s185 & -s186 & +s281 & -s282, fill=m33) -c3642 = mcdc.cell(+s185 & -s186 & +s282 & -s283, fill=m34) -c3643 = mcdc.cell(+s185 & -s186 & +s283 & -s284, fill=m35) -c3644 = mcdc.cell(+s185 & -s186 & +s284 & -s285, fill=m36) -c3645 = mcdc.cell(+s185 & -s186 & +s285, fill=m37) -c3646 = mcdc.cell(+s186 & -s187 & -s277, fill=m28) -c3647 = mcdc.cell(+s186 & -s187 & +s277 & -s278, fill=m29) -c3648 = mcdc.cell(+s186 & -s187 & +s278 & -s279, fill=m30) -c3649 = mcdc.cell(+s186 & -s187 & +s279 & -s280, fill=m31) -c3650 = mcdc.cell(+s186 & -s187 & +s280 & -s281, fill=m32) -c3651 = mcdc.cell(+s186 & -s187 & +s281 & -s282, fill=m33) -c3652 = mcdc.cell(+s186 & -s187 & +s282 & -s283, fill=m34) -c3653 = mcdc.cell(+s186 & -s187 & +s283 & -s284, fill=m35) -c3654 = mcdc.cell(+s186 & -s187 & +s284 & -s285, fill=m36) -c3655 = mcdc.cell(+s186 & -s187 & +s285, fill=m37) -c3656 = mcdc.cell(+s187 & -s188 & -s277, fill=m28) -c3657 = mcdc.cell(+s187 & -s188 & +s277 & -s278, fill=m29) -c3658 = mcdc.cell(+s187 & -s188 & +s278 & -s279, fill=m30) -c3659 = mcdc.cell(+s187 & -s188 & +s279 & -s280, fill=m31) -c3660 = mcdc.cell(+s187 & -s188 & +s280 & -s281, fill=m32) -c3661 = mcdc.cell(+s187 & -s188 & +s281 & -s282, fill=m33) -c3662 = mcdc.cell(+s187 & -s188 & +s282 & -s283, fill=m34) -c3663 = mcdc.cell(+s187 & -s188 & +s283 & -s284, fill=m35) -c3664 = mcdc.cell(+s187 & -s188 & +s284 & -s285, fill=m36) -c3665 = mcdc.cell(+s187 & -s188 & +s285, fill=m37) -c3666 = mcdc.cell(+s188 & -s189 & -s277, fill=m28) -c3667 = mcdc.cell(+s188 & -s189 & +s277 & -s278, fill=m29) -c3668 = mcdc.cell(+s188 & -s189 & +s278 & -s279, fill=m30) -c3669 = mcdc.cell(+s188 & -s189 & +s279 & -s280, fill=m31) -c3670 = mcdc.cell(+s188 & -s189 & +s280 & -s281, fill=m32) -c3671 = mcdc.cell(+s188 & -s189 & +s281 & -s282, fill=m33) -c3672 = mcdc.cell(+s188 & -s189 & +s282 & -s283, fill=m34) -c3673 = mcdc.cell(+s188 & -s189 & +s283 & -s284, fill=m35) -c3674 = mcdc.cell(+s188 & -s189 & +s284 & -s285, fill=m36) -c3675 = mcdc.cell(+s188 & -s189 & +s285, fill=m37) -c3676 = mcdc.cell(+s189 & -s190 & -s277, fill=m28) -c3677 = mcdc.cell(+s189 & -s190 & +s277 & -s278, fill=m29) -c3678 = mcdc.cell(+s189 & -s190 & +s278 & -s279, fill=m30) -c3679 = mcdc.cell(+s189 & -s190 & +s279 & -s280, fill=m31) -c3680 = mcdc.cell(+s189 & -s190 & +s280 & -s281, fill=m32) -c3681 = mcdc.cell(+s189 & -s190 & +s281 & -s282, fill=m33) -c3682 = mcdc.cell(+s189 & -s190 & +s282 & -s283, fill=m34) -c3683 = mcdc.cell(+s189 & -s190 & +s283 & -s284, fill=m35) -c3684 = mcdc.cell(+s189 & -s190 & +s284 & -s285, fill=m36) -c3685 = mcdc.cell(+s189 & -s190 & +s285, fill=m37) -c3686 = mcdc.cell(+s190 & -s191 & -s277, fill=m28) -c3687 = mcdc.cell(+s190 & -s191 & +s277 & -s278, fill=m29) -c3688 = mcdc.cell(+s190 & -s191 & +s278 & -s279, fill=m30) -c3689 = mcdc.cell(+s190 & -s191 & +s279 & -s280, fill=m31) -c3690 = mcdc.cell(+s190 & -s191 & +s280 & -s281, fill=m32) -c3691 = mcdc.cell(+s190 & -s191 & +s281 & -s282, fill=m33) -c3692 = mcdc.cell(+s190 & -s191 & +s282 & -s283, fill=m34) -c3693 = mcdc.cell(+s190 & -s191 & +s283 & -s284, fill=m35) -c3694 = mcdc.cell(+s190 & -s191 & +s284 & -s285, fill=m36) -c3695 = mcdc.cell(+s190 & -s191 & +s285, fill=m37) -c3696 = mcdc.cell(+s191 & -s192 & -s277, fill=m28) -c3697 = mcdc.cell(+s191 & -s192 & +s277 & -s278, fill=m29) -c3698 = mcdc.cell(+s191 & -s192 & +s278 & -s279, fill=m30) -c3699 = mcdc.cell(+s191 & -s192 & +s279 & -s280, fill=m31) -c3700 = mcdc.cell(+s191 & -s192 & +s280 & -s281, fill=m32) -c3701 = mcdc.cell(+s191 & -s192 & +s281 & -s282, fill=m33) -c3702 = mcdc.cell(+s191 & -s192 & +s282 & -s283, fill=m34) -c3703 = mcdc.cell(+s191 & -s192 & +s283 & -s284, fill=m35) -c3704 = mcdc.cell(+s191 & -s192 & +s284 & -s285, fill=m36) -c3705 = mcdc.cell(+s191 & -s192 & +s285, fill=m37) -c3706 = mcdc.cell(+s192 & -s193 & -s277, fill=m28) -c3707 = mcdc.cell(+s192 & -s193 & +s277 & -s278, fill=m29) -c3708 = mcdc.cell(+s192 & -s193 & +s278 & -s279, fill=m30) -c3709 = mcdc.cell(+s192 & -s193 & +s279 & -s280, fill=m31) -c3710 = mcdc.cell(+s192 & -s193 & +s280 & -s281, fill=m32) -c3711 = mcdc.cell(+s192 & -s193 & +s281 & -s282, fill=m33) -c3712 = mcdc.cell(+s192 & -s193 & +s282 & -s283, fill=m34) -c3713 = mcdc.cell(+s192 & -s193 & +s283 & -s284, fill=m35) -c3714 = mcdc.cell(+s192 & -s193 & +s284 & -s285, fill=m36) -c3715 = mcdc.cell(+s192 & -s193 & +s285, fill=m37) -c3716 = mcdc.cell(+s193 & -s194 & -s277, fill=m28) -c3717 = mcdc.cell(+s193 & -s194 & +s277 & -s278, fill=m29) -c3718 = mcdc.cell(+s193 & -s194 & +s278 & -s279, fill=m30) -c3719 = mcdc.cell(+s193 & -s194 & +s279 & -s280, fill=m31) -c3720 = mcdc.cell(+s193 & -s194 & +s280 & -s281, fill=m32) -c3721 = mcdc.cell(+s193 & -s194 & +s281 & -s282, fill=m33) -c3722 = mcdc.cell(+s193 & -s194 & +s282 & -s283, fill=m34) -c3723 = mcdc.cell(+s193 & -s194 & +s283 & -s284, fill=m35) -c3724 = mcdc.cell(+s193 & -s194 & +s284 & -s285, fill=m36) -c3725 = mcdc.cell(+s193 & -s194 & +s285, fill=m37) -c3726 = mcdc.cell(+s194 & -s195 & -s277, fill=m28) -c3727 = mcdc.cell(+s194 & -s195 & +s277 & -s278, fill=m29) -c3728 = mcdc.cell(+s194 & -s195 & +s278 & -s279, fill=m30) -c3729 = mcdc.cell(+s194 & -s195 & +s279 & -s280, fill=m31) -c3730 = mcdc.cell(+s194 & -s195 & +s280 & -s281, fill=m32) -c3731 = mcdc.cell(+s194 & -s195 & +s281 & -s282, fill=m33) -c3732 = mcdc.cell(+s194 & -s195 & +s282 & -s283, fill=m34) -c3733 = mcdc.cell(+s194 & -s195 & +s283 & -s284, fill=m35) -c3734 = mcdc.cell(+s194 & -s195 & +s284 & -s285, fill=m36) -c3735 = mcdc.cell(+s194 & -s195 & +s285, fill=m37) -c3736 = mcdc.cell(+s195 & -s196 & -s277, fill=m28) -c3737 = mcdc.cell(+s195 & -s196 & +s277 & -s278, fill=m29) -c3738 = mcdc.cell(+s195 & -s196 & +s278 & -s279, fill=m30) -c3739 = mcdc.cell(+s195 & -s196 & +s279 & -s280, fill=m31) -c3740 = mcdc.cell(+s195 & -s196 & +s280 & -s281, fill=m32) -c3741 = mcdc.cell(+s195 & -s196 & +s281 & -s282, fill=m33) -c3742 = mcdc.cell(+s195 & -s196 & +s282 & -s283, fill=m34) -c3743 = mcdc.cell(+s195 & -s196 & +s283 & -s284, fill=m35) -c3744 = mcdc.cell(+s195 & -s196 & +s284 & -s285, fill=m36) -c3745 = mcdc.cell(+s195 & -s196 & +s285, fill=m37) -c3746 = mcdc.cell(+s196 & -s197 & -s277, fill=m28) -c3747 = mcdc.cell(+s196 & -s197 & +s277 & -s278, fill=m29) -c3748 = mcdc.cell(+s196 & -s197 & +s278 & -s279, fill=m30) -c3749 = mcdc.cell(+s196 & -s197 & +s279 & -s280, fill=m31) -c3750 = mcdc.cell(+s196 & -s197 & +s280 & -s281, fill=m32) -c3751 = mcdc.cell(+s196 & -s197 & +s281 & -s282, fill=m33) -c3752 = mcdc.cell(+s196 & -s197 & +s282 & -s283, fill=m34) -c3753 = mcdc.cell(+s196 & -s197 & +s283 & -s284, fill=m35) -c3754 = mcdc.cell(+s196 & -s197 & +s284 & -s285, fill=m36) -c3755 = mcdc.cell(+s196 & -s197 & +s285, fill=m37) -c3756 = mcdc.cell(+s197 & -s198 & -s277, fill=m28) -c3757 = mcdc.cell(+s197 & -s198 & +s277 & -s278, fill=m29) -c3758 = mcdc.cell(+s197 & -s198 & +s278 & -s279, fill=m30) -c3759 = mcdc.cell(+s197 & -s198 & +s279 & -s280, fill=m31) -c3760 = mcdc.cell(+s197 & -s198 & +s280 & -s281, fill=m32) -c3761 = mcdc.cell(+s197 & -s198 & +s281 & -s282, fill=m33) -c3762 = mcdc.cell(+s197 & -s198 & +s282 & -s283, fill=m34) -c3763 = mcdc.cell(+s197 & -s198 & +s283 & -s284, fill=m35) -c3764 = mcdc.cell(+s197 & -s198 & +s284 & -s285, fill=m36) -c3765 = mcdc.cell(+s197 & -s198 & +s285, fill=m37) -c3766 = mcdc.cell(+s198 & -s199 & -s277, fill=m28) -c3767 = mcdc.cell(+s198 & -s199 & +s277 & -s278, fill=m29) -c3768 = mcdc.cell(+s198 & -s199 & +s278 & -s279, fill=m30) -c3769 = mcdc.cell(+s198 & -s199 & +s279 & -s280, fill=m31) -c3770 = mcdc.cell(+s198 & -s199 & +s280 & -s281, fill=m32) -c3771 = mcdc.cell(+s198 & -s199 & +s281 & -s282, fill=m33) -c3772 = mcdc.cell(+s198 & -s199 & +s282 & -s283, fill=m34) -c3773 = mcdc.cell(+s198 & -s199 & +s283 & -s284, fill=m35) -c3774 = mcdc.cell(+s198 & -s199 & +s284 & -s285, fill=m36) -c3775 = mcdc.cell(+s198 & -s199 & +s285, fill=m37) -c3776 = mcdc.cell(+s199 & -s200 & -s277, fill=m28) -c3777 = mcdc.cell(+s199 & -s200 & +s277 & -s278, fill=m29) -c3778 = mcdc.cell(+s199 & -s200 & +s278 & -s279, fill=m30) -c3779 = mcdc.cell(+s199 & -s200 & +s279 & -s280, fill=m31) -c3780 = mcdc.cell(+s199 & -s200 & +s280 & -s281, fill=m32) -c3781 = mcdc.cell(+s199 & -s200 & +s281 & -s282, fill=m33) -c3782 = mcdc.cell(+s199 & -s200 & +s282 & -s283, fill=m34) -c3783 = mcdc.cell(+s199 & -s200 & +s283 & -s284, fill=m35) -c3784 = mcdc.cell(+s199 & -s200 & +s284 & -s285, fill=m36) -c3785 = mcdc.cell(+s199 & -s200 & +s285, fill=m37) -c3786 = mcdc.cell(+s200 & -s201 & -s277, fill=m28) -c3787 = mcdc.cell(+s200 & -s201 & +s277 & -s278, fill=m29) -c3788 = mcdc.cell(+s200 & -s201 & +s278 & -s279, fill=m30) -c3789 = mcdc.cell(+s200 & -s201 & +s279 & -s280, fill=m31) -c3790 = mcdc.cell(+s200 & -s201 & +s280 & -s281, fill=m32) -c3791 = mcdc.cell(+s200 & -s201 & +s281 & -s282, fill=m33) -c3792 = mcdc.cell(+s200 & -s201 & +s282 & -s283, fill=m34) -c3793 = mcdc.cell(+s200 & -s201 & +s283 & -s284, fill=m35) -c3794 = mcdc.cell(+s200 & -s201 & +s284 & -s285, fill=m36) -c3795 = mcdc.cell(+s200 & -s201 & +s285, fill=m37) -c3796 = mcdc.cell(+s201 & -s202 & -s277, fill=m28) -c3797 = mcdc.cell(+s201 & -s202 & +s277 & -s278, fill=m29) -c3798 = mcdc.cell(+s201 & -s202 & +s278 & -s279, fill=m30) -c3799 = mcdc.cell(+s201 & -s202 & +s279 & -s280, fill=m31) -c3800 = mcdc.cell(+s201 & -s202 & +s280 & -s281, fill=m32) -c3801 = mcdc.cell(+s201 & -s202 & +s281 & -s282, fill=m33) -c3802 = mcdc.cell(+s201 & -s202 & +s282 & -s283, fill=m34) -c3803 = mcdc.cell(+s201 & -s202 & +s283 & -s284, fill=m35) -c3804 = mcdc.cell(+s201 & -s202 & +s284 & -s285, fill=m36) -c3805 = mcdc.cell(+s201 & -s202 & +s285, fill=m37) -c3806 = mcdc.cell(+s202 & -s203 & -s277, fill=m28) -c3807 = mcdc.cell(+s202 & -s203 & +s277 & -s278, fill=m29) -c3808 = mcdc.cell(+s202 & -s203 & +s278 & -s279, fill=m30) -c3809 = mcdc.cell(+s202 & -s203 & +s279 & -s280, fill=m31) -c3810 = mcdc.cell(+s202 & -s203 & +s280 & -s281, fill=m32) -c3811 = mcdc.cell(+s202 & -s203 & +s281 & -s282, fill=m33) -c3812 = mcdc.cell(+s202 & -s203 & +s282 & -s283, fill=m34) -c3813 = mcdc.cell(+s202 & -s203 & +s283 & -s284, fill=m35) -c3814 = mcdc.cell(+s202 & -s203 & +s284 & -s285, fill=m36) -c3815 = mcdc.cell(+s202 & -s203 & +s285, fill=m37) -c3816 = mcdc.cell(+s203 & -s204 & -s277, fill=m28) -c3817 = mcdc.cell(+s203 & -s204 & +s277 & -s278, fill=m29) -c3818 = mcdc.cell(+s203 & -s204 & +s278 & -s279, fill=m30) -c3819 = mcdc.cell(+s203 & -s204 & +s279 & -s280, fill=m31) -c3820 = mcdc.cell(+s203 & -s204 & +s280 & -s281, fill=m32) -c3821 = mcdc.cell(+s203 & -s204 & +s281 & -s282, fill=m33) -c3822 = mcdc.cell(+s203 & -s204 & +s282 & -s283, fill=m34) -c3823 = mcdc.cell(+s203 & -s204 & +s283 & -s284, fill=m35) -c3824 = mcdc.cell(+s203 & -s204 & +s284 & -s285, fill=m36) -c3825 = mcdc.cell(+s203 & -s204 & +s285, fill=m37) -c3826 = mcdc.cell(+s204 & -s205 & -s277, fill=m28) -c3827 = mcdc.cell(+s204 & -s205 & +s277 & -s278, fill=m29) -c3828 = mcdc.cell(+s204 & -s205 & +s278 & -s279, fill=m30) -c3829 = mcdc.cell(+s204 & -s205 & +s279 & -s280, fill=m31) -c3830 = mcdc.cell(+s204 & -s205 & +s280 & -s281, fill=m32) -c3831 = mcdc.cell(+s204 & -s205 & +s281 & -s282, fill=m33) -c3832 = mcdc.cell(+s204 & -s205 & +s282 & -s283, fill=m34) -c3833 = mcdc.cell(+s204 & -s205 & +s283 & -s284, fill=m35) -c3834 = mcdc.cell(+s204 & -s205 & +s284 & -s285, fill=m36) -c3835 = mcdc.cell(+s204 & -s205 & +s285, fill=m37) -c3836 = mcdc.cell(+s205 & -s206 & -s277, fill=m28) -c3837 = mcdc.cell(+s205 & -s206 & +s277 & -s278, fill=m29) -c3838 = mcdc.cell(+s205 & -s206 & +s278 & -s279, fill=m30) -c3839 = mcdc.cell(+s205 & -s206 & +s279 & -s280, fill=m31) -c3840 = mcdc.cell(+s205 & -s206 & +s280 & -s281, fill=m32) -c3841 = mcdc.cell(+s205 & -s206 & +s281 & -s282, fill=m33) -c3842 = mcdc.cell(+s205 & -s206 & +s282 & -s283, fill=m34) -c3843 = mcdc.cell(+s205 & -s206 & +s283 & -s284, fill=m35) -c3844 = mcdc.cell(+s205 & -s206 & +s284 & -s285, fill=m36) -c3845 = mcdc.cell(+s205 & -s206 & +s285, fill=m37) -c3846 = mcdc.cell(+s206 & -s207 & -s277, fill=m28) -c3847 = mcdc.cell(+s206 & -s207 & +s277 & -s278, fill=m29) -c3848 = mcdc.cell(+s206 & -s207 & +s278 & -s279, fill=m30) -c3849 = mcdc.cell(+s206 & -s207 & +s279 & -s280, fill=m31) -c3850 = mcdc.cell(+s206 & -s207 & +s280 & -s281, fill=m32) -c3851 = mcdc.cell(+s206 & -s207 & +s281 & -s282, fill=m33) -c3852 = mcdc.cell(+s206 & -s207 & +s282 & -s283, fill=m34) -c3853 = mcdc.cell(+s206 & -s207 & +s283 & -s284, fill=m35) -c3854 = mcdc.cell(+s206 & -s207 & +s284 & -s285, fill=m36) -c3855 = mcdc.cell(+s206 & -s207 & +s285, fill=m37) -c3856 = mcdc.cell(+s207 & -s208 & -s277, fill=m28) -c3857 = mcdc.cell(+s207 & -s208 & +s277 & -s278, fill=m29) -c3858 = mcdc.cell(+s207 & -s208 & +s278 & -s279, fill=m30) -c3859 = mcdc.cell(+s207 & -s208 & +s279 & -s280, fill=m31) -c3860 = mcdc.cell(+s207 & -s208 & +s280 & -s281, fill=m32) -c3861 = mcdc.cell(+s207 & -s208 & +s281 & -s282, fill=m33) -c3862 = mcdc.cell(+s207 & -s208 & +s282 & -s283, fill=m34) -c3863 = mcdc.cell(+s207 & -s208 & +s283 & -s284, fill=m35) -c3864 = mcdc.cell(+s207 & -s208 & +s284 & -s285, fill=m36) -c3865 = mcdc.cell(+s207 & -s208 & +s285, fill=m37) -c3866 = mcdc.cell(+s208 & -s209 & -s277, fill=m28) -c3867 = mcdc.cell(+s208 & -s209 & +s277 & -s278, fill=m29) -c3868 = mcdc.cell(+s208 & -s209 & +s278 & -s279, fill=m30) -c3869 = mcdc.cell(+s208 & -s209 & +s279 & -s280, fill=m31) -c3870 = mcdc.cell(+s208 & -s209 & +s280 & -s281, fill=m32) -c3871 = mcdc.cell(+s208 & -s209 & +s281 & -s282, fill=m33) -c3872 = mcdc.cell(+s208 & -s209 & +s282 & -s283, fill=m34) -c3873 = mcdc.cell(+s208 & -s209 & +s283 & -s284, fill=m35) -c3874 = mcdc.cell(+s208 & -s209 & +s284 & -s285, fill=m36) -c3875 = mcdc.cell(+s208 & -s209 & +s285, fill=m37) -c3876 = mcdc.cell(+s209 & -s210 & -s277, fill=m28) -c3877 = mcdc.cell(+s209 & -s210 & +s277 & -s278, fill=m29) -c3878 = mcdc.cell(+s209 & -s210 & +s278 & -s279, fill=m30) -c3879 = mcdc.cell(+s209 & -s210 & +s279 & -s280, fill=m31) -c3880 = mcdc.cell(+s209 & -s210 & +s280 & -s281, fill=m32) -c3881 = mcdc.cell(+s209 & -s210 & +s281 & -s282, fill=m33) -c3882 = mcdc.cell(+s209 & -s210 & +s282 & -s283, fill=m34) -c3883 = mcdc.cell(+s209 & -s210 & +s283 & -s284, fill=m35) -c3884 = mcdc.cell(+s209 & -s210 & +s284 & -s285, fill=m36) -c3885 = mcdc.cell(+s209 & -s210 & +s285, fill=m37) -c3886 = mcdc.cell(+s210 & -s211 & -s277, fill=m28) -c3887 = mcdc.cell(+s210 & -s211 & +s277 & -s278, fill=m29) -c3888 = mcdc.cell(+s210 & -s211 & +s278 & -s279, fill=m30) -c3889 = mcdc.cell(+s210 & -s211 & +s279 & -s280, fill=m31) -c3890 = mcdc.cell(+s210 & -s211 & +s280 & -s281, fill=m32) -c3891 = mcdc.cell(+s210 & -s211 & +s281 & -s282, fill=m33) -c3892 = mcdc.cell(+s210 & -s211 & +s282 & -s283, fill=m34) -c3893 = mcdc.cell(+s210 & -s211 & +s283 & -s284, fill=m35) -c3894 = mcdc.cell(+s210 & -s211 & +s284 & -s285, fill=m36) -c3895 = mcdc.cell(+s210 & -s211 & +s285, fill=m37) -c3896 = mcdc.cell(+s211 & -s212 & -s277, fill=m28) -c3897 = mcdc.cell(+s211 & -s212 & +s277 & -s278, fill=m29) -c3898 = mcdc.cell(+s211 & -s212 & +s278 & -s279, fill=m30) -c3899 = mcdc.cell(+s211 & -s212 & +s279 & -s280, fill=m31) -c3900 = mcdc.cell(+s211 & -s212 & +s280 & -s281, fill=m32) -c3901 = mcdc.cell(+s211 & -s212 & +s281 & -s282, fill=m33) -c3902 = mcdc.cell(+s211 & -s212 & +s282 & -s283, fill=m34) -c3903 = mcdc.cell(+s211 & -s212 & +s283 & -s284, fill=m35) -c3904 = mcdc.cell(+s211 & -s212 & +s284 & -s285, fill=m36) -c3905 = mcdc.cell(+s211 & -s212 & +s285, fill=m37) -c3906 = mcdc.cell(+s212 & -s213 & -s277, fill=m28) -c3907 = mcdc.cell(+s212 & -s213 & +s277 & -s278, fill=m29) -c3908 = mcdc.cell(+s212 & -s213 & +s278 & -s279, fill=m30) -c3909 = mcdc.cell(+s212 & -s213 & +s279 & -s280, fill=m31) -c3910 = mcdc.cell(+s212 & -s213 & +s280 & -s281, fill=m32) -c3911 = mcdc.cell(+s212 & -s213 & +s281 & -s282, fill=m33) -c3912 = mcdc.cell(+s212 & -s213 & +s282 & -s283, fill=m34) -c3913 = mcdc.cell(+s212 & -s213 & +s283 & -s284, fill=m35) -c3914 = mcdc.cell(+s212 & -s213 & +s284 & -s285, fill=m36) -c3915 = mcdc.cell(+s212 & -s213 & +s285, fill=m37) -c3916 = mcdc.cell(+s213 & -s214 & -s277, fill=m28) -c3917 = mcdc.cell(+s213 & -s214 & +s277 & -s278, fill=m29) -c3918 = mcdc.cell(+s213 & -s214 & +s278 & -s279, fill=m30) -c3919 = mcdc.cell(+s213 & -s214 & +s279 & -s280, fill=m31) -c3920 = mcdc.cell(+s213 & -s214 & +s280 & -s281, fill=m32) -c3921 = mcdc.cell(+s213 & -s214 & +s281 & -s282, fill=m33) -c3922 = mcdc.cell(+s213 & -s214 & +s282 & -s283, fill=m34) -c3923 = mcdc.cell(+s213 & -s214 & +s283 & -s284, fill=m35) -c3924 = mcdc.cell(+s213 & -s214 & +s284 & -s285, fill=m36) -c3925 = mcdc.cell(+s213 & -s214 & +s285, fill=m37) -c3926 = mcdc.cell(+s214 & -s215 & -s277, fill=m28) -c3927 = mcdc.cell(+s214 & -s215 & +s277 & -s278, fill=m29) -c3928 = mcdc.cell(+s214 & -s215 & +s278 & -s279, fill=m30) -c3929 = mcdc.cell(+s214 & -s215 & +s279 & -s280, fill=m31) -c3930 = mcdc.cell(+s214 & -s215 & +s280 & -s281, fill=m32) -c3931 = mcdc.cell(+s214 & -s215 & +s281 & -s282, fill=m33) -c3932 = mcdc.cell(+s214 & -s215 & +s282 & -s283, fill=m34) -c3933 = mcdc.cell(+s214 & -s215 & +s283 & -s284, fill=m35) -c3934 = mcdc.cell(+s214 & -s215 & +s284 & -s285, fill=m36) -c3935 = mcdc.cell(+s214 & -s215 & +s285, fill=m37) -c3936 = mcdc.cell(+s215 & -s216 & -s277, fill=m28) -c3937 = mcdc.cell(+s215 & -s216 & +s277 & -s278, fill=m29) -c3938 = mcdc.cell(+s215 & -s216 & +s278 & -s279, fill=m30) -c3939 = mcdc.cell(+s215 & -s216 & +s279 & -s280, fill=m31) -c3940 = mcdc.cell(+s215 & -s216 & +s280 & -s281, fill=m32) -c3941 = mcdc.cell(+s215 & -s216 & +s281 & -s282, fill=m33) -c3942 = mcdc.cell(+s215 & -s216 & +s282 & -s283, fill=m34) -c3943 = mcdc.cell(+s215 & -s216 & +s283 & -s284, fill=m35) -c3944 = mcdc.cell(+s215 & -s216 & +s284 & -s285, fill=m36) -c3945 = mcdc.cell(+s215 & -s216 & +s285, fill=m37) -c3946 = mcdc.cell(+s216 & -s217 & -s277, fill=m28) -c3947 = mcdc.cell(+s216 & -s217 & +s277 & -s278, fill=m29) -c3948 = mcdc.cell(+s216 & -s217 & +s278 & -s279, fill=m30) -c3949 = mcdc.cell(+s216 & -s217 & +s279 & -s280, fill=m31) -c3950 = mcdc.cell(+s216 & -s217 & +s280 & -s281, fill=m32) -c3951 = mcdc.cell(+s216 & -s217 & +s281 & -s282, fill=m33) -c3952 = mcdc.cell(+s216 & -s217 & +s282 & -s283, fill=m34) -c3953 = mcdc.cell(+s216 & -s217 & +s283 & -s284, fill=m35) -c3954 = mcdc.cell(+s216 & -s217 & +s284 & -s285, fill=m36) -c3955 = mcdc.cell(+s216 & -s217 & +s285, fill=m37) -c3956 = mcdc.cell(+s217 & -s218 & -s277, fill=m28) -c3957 = mcdc.cell(+s217 & -s218 & +s277 & -s278, fill=m29) -c3958 = mcdc.cell(+s217 & -s218 & +s278 & -s279, fill=m30) -c3959 = mcdc.cell(+s217 & -s218 & +s279 & -s280, fill=m31) -c3960 = mcdc.cell(+s217 & -s218 & +s280 & -s281, fill=m32) -c3961 = mcdc.cell(+s217 & -s218 & +s281 & -s282, fill=m33) -c3962 = mcdc.cell(+s217 & -s218 & +s282 & -s283, fill=m34) -c3963 = mcdc.cell(+s217 & -s218 & +s283 & -s284, fill=m35) -c3964 = mcdc.cell(+s217 & -s218 & +s284 & -s285, fill=m36) -c3965 = mcdc.cell(+s217 & -s218 & +s285, fill=m37) -c3966 = mcdc.cell(+s218 & -s219 & -s277, fill=m28) -c3967 = mcdc.cell(+s218 & -s219 & +s277 & -s278, fill=m29) -c3968 = mcdc.cell(+s218 & -s219 & +s278 & -s279, fill=m30) -c3969 = mcdc.cell(+s218 & -s219 & +s279 & -s280, fill=m31) -c3970 = mcdc.cell(+s218 & -s219 & +s280 & -s281, fill=m32) -c3971 = mcdc.cell(+s218 & -s219 & +s281 & -s282, fill=m33) -c3972 = mcdc.cell(+s218 & -s219 & +s282 & -s283, fill=m34) -c3973 = mcdc.cell(+s218 & -s219 & +s283 & -s284, fill=m35) -c3974 = mcdc.cell(+s218 & -s219 & +s284 & -s285, fill=m36) -c3975 = mcdc.cell(+s218 & -s219 & +s285, fill=m37) -c3976 = mcdc.cell(+s219 & -s220 & -s277, fill=m28) -c3977 = mcdc.cell(+s219 & -s220 & +s277 & -s278, fill=m29) -c3978 = mcdc.cell(+s219 & -s220 & +s278 & -s279, fill=m30) -c3979 = mcdc.cell(+s219 & -s220 & +s279 & -s280, fill=m31) -c3980 = mcdc.cell(+s219 & -s220 & +s280 & -s281, fill=m32) -c3981 = mcdc.cell(+s219 & -s220 & +s281 & -s282, fill=m33) -c3982 = mcdc.cell(+s219 & -s220 & +s282 & -s283, fill=m34) -c3983 = mcdc.cell(+s219 & -s220 & +s283 & -s284, fill=m35) -c3984 = mcdc.cell(+s219 & -s220 & +s284 & -s285, fill=m36) -c3985 = mcdc.cell(+s219 & -s220 & +s285, fill=m37) -c3986 = mcdc.cell(+s220 & -s221 & -s277, fill=m28) -c3987 = mcdc.cell(+s220 & -s221 & +s277 & -s278, fill=m29) -c3988 = mcdc.cell(+s220 & -s221 & +s278 & -s279, fill=m30) -c3989 = mcdc.cell(+s220 & -s221 & +s279 & -s280, fill=m31) -c3990 = mcdc.cell(+s220 & -s221 & +s280 & -s281, fill=m32) -c3991 = mcdc.cell(+s220 & -s221 & +s281 & -s282, fill=m33) -c3992 = mcdc.cell(+s220 & -s221 & +s282 & -s283, fill=m34) -c3993 = mcdc.cell(+s220 & -s221 & +s283 & -s284, fill=m35) -c3994 = mcdc.cell(+s220 & -s221 & +s284 & -s285, fill=m36) -c3995 = mcdc.cell(+s220 & -s221 & +s285, fill=m37) -c3996 = mcdc.cell(+s221 & -s222 & -s277, fill=m28) -c3997 = mcdc.cell(+s221 & -s222 & +s277 & -s278, fill=m29) -c3998 = mcdc.cell(+s221 & -s222 & +s278 & -s279, fill=m30) -c3999 = mcdc.cell(+s221 & -s222 & +s279 & -s280, fill=m31) -c4000 = mcdc.cell(+s221 & -s222 & +s280 & -s281, fill=m32) -c4001 = mcdc.cell(+s221 & -s222 & +s281 & -s282, fill=m33) -c4002 = mcdc.cell(+s221 & -s222 & +s282 & -s283, fill=m34) -c4003 = mcdc.cell(+s221 & -s222 & +s283 & -s284, fill=m35) -c4004 = mcdc.cell(+s221 & -s222 & +s284 & -s285, fill=m36) -c4005 = mcdc.cell(+s221 & -s222 & +s285, fill=m37) -c4006 = mcdc.cell(+s222 & -s223 & -s277, fill=m28) -c4007 = mcdc.cell(+s222 & -s223 & +s277 & -s278, fill=m29) -c4008 = mcdc.cell(+s222 & -s223 & +s278 & -s279, fill=m30) -c4009 = mcdc.cell(+s222 & -s223 & +s279 & -s280, fill=m31) -c4010 = mcdc.cell(+s222 & -s223 & +s280 & -s281, fill=m32) -c4011 = mcdc.cell(+s222 & -s223 & +s281 & -s282, fill=m33) -c4012 = mcdc.cell(+s222 & -s223 & +s282 & -s283, fill=m34) -c4013 = mcdc.cell(+s222 & -s223 & +s283 & -s284, fill=m35) -c4014 = mcdc.cell(+s222 & -s223 & +s284 & -s285, fill=m36) -c4015 = mcdc.cell(+s222 & -s223 & +s285, fill=m37) -c4016 = mcdc.cell(+s223 & -s224 & -s277, fill=m28) -c4017 = mcdc.cell(+s223 & -s224 & +s277 & -s278, fill=m29) -c4018 = mcdc.cell(+s223 & -s224 & +s278 & -s279, fill=m30) -c4019 = mcdc.cell(+s223 & -s224 & +s279 & -s280, fill=m31) -c4020 = mcdc.cell(+s223 & -s224 & +s280 & -s281, fill=m32) -c4021 = mcdc.cell(+s223 & -s224 & +s281 & -s282, fill=m33) -c4022 = mcdc.cell(+s223 & -s224 & +s282 & -s283, fill=m34) -c4023 = mcdc.cell(+s223 & -s224 & +s283 & -s284, fill=m35) -c4024 = mcdc.cell(+s223 & -s224 & +s284 & -s285, fill=m36) -c4025 = mcdc.cell(+s223 & -s224 & +s285, fill=m37) -c4026 = mcdc.cell(+s224 & -s225 & -s277, fill=m28) -c4027 = mcdc.cell(+s224 & -s225 & +s277 & -s278, fill=m29) -c4028 = mcdc.cell(+s224 & -s225 & +s278 & -s279, fill=m30) -c4029 = mcdc.cell(+s224 & -s225 & +s279 & -s280, fill=m31) -c4030 = mcdc.cell(+s224 & -s225 & +s280 & -s281, fill=m32) -c4031 = mcdc.cell(+s224 & -s225 & +s281 & -s282, fill=m33) -c4032 = mcdc.cell(+s224 & -s225 & +s282 & -s283, fill=m34) -c4033 = mcdc.cell(+s224 & -s225 & +s283 & -s284, fill=m35) -c4034 = mcdc.cell(+s224 & -s225 & +s284 & -s285, fill=m36) -c4035 = mcdc.cell(+s224 & -s225 & +s285, fill=m37) -c4036 = mcdc.cell(+s225 & -s226 & -s277, fill=m28) -c4037 = mcdc.cell(+s225 & -s226 & +s277 & -s278, fill=m29) -c4038 = mcdc.cell(+s225 & -s226 & +s278 & -s279, fill=m30) -c4039 = mcdc.cell(+s225 & -s226 & +s279 & -s280, fill=m31) -c4040 = mcdc.cell(+s225 & -s226 & +s280 & -s281, fill=m32) -c4041 = mcdc.cell(+s225 & -s226 & +s281 & -s282, fill=m33) -c4042 = mcdc.cell(+s225 & -s226 & +s282 & -s283, fill=m34) -c4043 = mcdc.cell(+s225 & -s226 & +s283 & -s284, fill=m35) -c4044 = mcdc.cell(+s225 & -s226 & +s284 & -s285, fill=m36) -c4045 = mcdc.cell(+s225 & -s226 & +s285, fill=m37) -c4046 = mcdc.cell(+s226 & -s227 & -s277, fill=m28) -c4047 = mcdc.cell(+s226 & -s227 & +s277 & -s278, fill=m29) -c4048 = mcdc.cell(+s226 & -s227 & +s278 & -s279, fill=m30) -c4049 = mcdc.cell(+s226 & -s227 & +s279 & -s280, fill=m31) -c4050 = mcdc.cell(+s226 & -s227 & +s280 & -s281, fill=m32) -c4051 = mcdc.cell(+s226 & -s227 & +s281 & -s282, fill=m33) -c4052 = mcdc.cell(+s226 & -s227 & +s282 & -s283, fill=m34) -c4053 = mcdc.cell(+s226 & -s227 & +s283 & -s284, fill=m35) -c4054 = mcdc.cell(+s226 & -s227 & +s284 & -s285, fill=m36) -c4055 = mcdc.cell(+s226 & -s227 & +s285, fill=m37) -c4056 = mcdc.cell(+s227 & -s228 & -s277, fill=m28) -c4057 = mcdc.cell(+s227 & -s228 & +s277 & -s278, fill=m29) -c4058 = mcdc.cell(+s227 & -s228 & +s278 & -s279, fill=m30) -c4059 = mcdc.cell(+s227 & -s228 & +s279 & -s280, fill=m31) -c4060 = mcdc.cell(+s227 & -s228 & +s280 & -s281, fill=m32) -c4061 = mcdc.cell(+s227 & -s228 & +s281 & -s282, fill=m33) -c4062 = mcdc.cell(+s227 & -s228 & +s282 & -s283, fill=m34) -c4063 = mcdc.cell(+s227 & -s228 & +s283 & -s284, fill=m35) -c4064 = mcdc.cell(+s227 & -s228 & +s284 & -s285, fill=m36) -c4065 = mcdc.cell(+s227 & -s228 & +s285, fill=m37) -c4066 = mcdc.cell(+s228 & -s229 & -s277, fill=m28) -c4067 = mcdc.cell(+s228 & -s229 & +s277 & -s278, fill=m29) -c4068 = mcdc.cell(+s228 & -s229 & +s278 & -s279, fill=m30) -c4069 = mcdc.cell(+s228 & -s229 & +s279 & -s280, fill=m31) -c4070 = mcdc.cell(+s228 & -s229 & +s280 & -s281, fill=m32) -c4071 = mcdc.cell(+s228 & -s229 & +s281 & -s282, fill=m33) -c4072 = mcdc.cell(+s228 & -s229 & +s282 & -s283, fill=m34) -c4073 = mcdc.cell(+s228 & -s229 & +s283 & -s284, fill=m35) -c4074 = mcdc.cell(+s228 & -s229 & +s284 & -s285, fill=m36) -c4075 = mcdc.cell(+s228 & -s229 & +s285, fill=m37) -c4076 = mcdc.cell(+s229 & -s230 & -s277, fill=m28) -c4077 = mcdc.cell(+s229 & -s230 & +s277 & -s278, fill=m29) -c4078 = mcdc.cell(+s229 & -s230 & +s278 & -s279, fill=m30) -c4079 = mcdc.cell(+s229 & -s230 & +s279 & -s280, fill=m31) -c4080 = mcdc.cell(+s229 & -s230 & +s280 & -s281, fill=m32) -c4081 = mcdc.cell(+s229 & -s230 & +s281 & -s282, fill=m33) -c4082 = mcdc.cell(+s229 & -s230 & +s282 & -s283, fill=m34) -c4083 = mcdc.cell(+s229 & -s230 & +s283 & -s284, fill=m35) -c4084 = mcdc.cell(+s229 & -s230 & +s284 & -s285, fill=m36) -c4085 = mcdc.cell(+s229 & -s230 & +s285, fill=m37) -c4086 = mcdc.cell(+s230 & -s231 & -s277, fill=m28) -c4087 = mcdc.cell(+s230 & -s231 & +s277 & -s278, fill=m29) -c4088 = mcdc.cell(+s230 & -s231 & +s278 & -s279, fill=m30) -c4089 = mcdc.cell(+s230 & -s231 & +s279 & -s280, fill=m31) -c4090 = mcdc.cell(+s230 & -s231 & +s280 & -s281, fill=m32) -c4091 = mcdc.cell(+s230 & -s231 & +s281 & -s282, fill=m33) -c4092 = mcdc.cell(+s230 & -s231 & +s282 & -s283, fill=m34) -c4093 = mcdc.cell(+s230 & -s231 & +s283 & -s284, fill=m35) -c4094 = mcdc.cell(+s230 & -s231 & +s284 & -s285, fill=m36) -c4095 = mcdc.cell(+s230 & -s231 & +s285, fill=m37) -c4096 = mcdc.cell(+s231 & -s232 & -s277, fill=m28) -c4097 = mcdc.cell(+s231 & -s232 & +s277 & -s278, fill=m29) -c4098 = mcdc.cell(+s231 & -s232 & +s278 & -s279, fill=m30) -c4099 = mcdc.cell(+s231 & -s232 & +s279 & -s280, fill=m31) -c4100 = mcdc.cell(+s231 & -s232 & +s280 & -s281, fill=m32) -c4101 = mcdc.cell(+s231 & -s232 & +s281 & -s282, fill=m33) -c4102 = mcdc.cell(+s231 & -s232 & +s282 & -s283, fill=m34) -c4103 = mcdc.cell(+s231 & -s232 & +s283 & -s284, fill=m35) -c4104 = mcdc.cell(+s231 & -s232 & +s284 & -s285, fill=m36) -c4105 = mcdc.cell(+s231 & -s232 & +s285, fill=m37) -c4106 = mcdc.cell(+s232 & -s233 & -s277, fill=m28) -c4107 = mcdc.cell(+s232 & -s233 & +s277 & -s278, fill=m29) -c4108 = mcdc.cell(+s232 & -s233 & +s278 & -s279, fill=m30) -c4109 = mcdc.cell(+s232 & -s233 & +s279 & -s280, fill=m31) -c4110 = mcdc.cell(+s232 & -s233 & +s280 & -s281, fill=m32) -c4111 = mcdc.cell(+s232 & -s233 & +s281 & -s282, fill=m33) -c4112 = mcdc.cell(+s232 & -s233 & +s282 & -s283, fill=m34) -c4113 = mcdc.cell(+s232 & -s233 & +s283 & -s284, fill=m35) -c4114 = mcdc.cell(+s232 & -s233 & +s284 & -s285, fill=m36) -c4115 = mcdc.cell(+s232 & -s233 & +s285, fill=m37) -c4116 = mcdc.cell(+s233 & -s234 & -s277, fill=m28) -c4117 = mcdc.cell(+s233 & -s234 & +s277 & -s278, fill=m29) -c4118 = mcdc.cell(+s233 & -s234 & +s278 & -s279, fill=m30) -c4119 = mcdc.cell(+s233 & -s234 & +s279 & -s280, fill=m31) -c4120 = mcdc.cell(+s233 & -s234 & +s280 & -s281, fill=m32) -c4121 = mcdc.cell(+s233 & -s234 & +s281 & -s282, fill=m33) -c4122 = mcdc.cell(+s233 & -s234 & +s282 & -s283, fill=m34) -c4123 = mcdc.cell(+s233 & -s234 & +s283 & -s284, fill=m35) -c4124 = mcdc.cell(+s233 & -s234 & +s284 & -s285, fill=m36) -c4125 = mcdc.cell(+s233 & -s234 & +s285, fill=m37) -c4126 = mcdc.cell(+s234 & -s235 & -s277, fill=m28) -c4127 = mcdc.cell(+s234 & -s235 & +s277 & -s278, fill=m29) -c4128 = mcdc.cell(+s234 & -s235 & +s278 & -s279, fill=m30) -c4129 = mcdc.cell(+s234 & -s235 & +s279 & -s280, fill=m31) -c4130 = mcdc.cell(+s234 & -s235 & +s280 & -s281, fill=m32) -c4131 = mcdc.cell(+s234 & -s235 & +s281 & -s282, fill=m33) -c4132 = mcdc.cell(+s234 & -s235 & +s282 & -s283, fill=m34) -c4133 = mcdc.cell(+s234 & -s235 & +s283 & -s284, fill=m35) -c4134 = mcdc.cell(+s234 & -s235 & +s284 & -s285, fill=m36) -c4135 = mcdc.cell(+s234 & -s235 & +s285, fill=m37) -c4136 = mcdc.cell(+s235 & -s236 & -s277, fill=m28) -c4137 = mcdc.cell(+s235 & -s236 & +s277 & -s278, fill=m29) -c4138 = mcdc.cell(+s235 & -s236 & +s278 & -s279, fill=m30) -c4139 = mcdc.cell(+s235 & -s236 & +s279 & -s280, fill=m31) -c4140 = mcdc.cell(+s235 & -s236 & +s280 & -s281, fill=m32) -c4141 = mcdc.cell(+s235 & -s236 & +s281 & -s282, fill=m33) -c4142 = mcdc.cell(+s235 & -s236 & +s282 & -s283, fill=m34) -c4143 = mcdc.cell(+s235 & -s236 & +s283 & -s284, fill=m35) -c4144 = mcdc.cell(+s235 & -s236 & +s284 & -s285, fill=m36) -c4145 = mcdc.cell(+s235 & -s236 & +s285, fill=m37) -c4146 = mcdc.cell(+s236 & -s237 & -s277, fill=m28) -c4147 = mcdc.cell(+s236 & -s237 & +s277 & -s278, fill=m29) -c4148 = mcdc.cell(+s236 & -s237 & +s278 & -s279, fill=m30) -c4149 = mcdc.cell(+s236 & -s237 & +s279 & -s280, fill=m31) -c4150 = mcdc.cell(+s236 & -s237 & +s280 & -s281, fill=m32) -c4151 = mcdc.cell(+s236 & -s237 & +s281 & -s282, fill=m33) -c4152 = mcdc.cell(+s236 & -s237 & +s282 & -s283, fill=m34) -c4153 = mcdc.cell(+s236 & -s237 & +s283 & -s284, fill=m35) -c4154 = mcdc.cell(+s236 & -s237 & +s284 & -s285, fill=m36) -c4155 = mcdc.cell(+s236 & -s237 & +s285, fill=m37) -c4156 = mcdc.cell(+s237 & -s238 & -s277, fill=m28) -c4157 = mcdc.cell(+s237 & -s238 & +s277 & -s278, fill=m29) -c4158 = mcdc.cell(+s237 & -s238 & +s278 & -s279, fill=m30) -c4159 = mcdc.cell(+s237 & -s238 & +s279 & -s280, fill=m31) -c4160 = mcdc.cell(+s237 & -s238 & +s280 & -s281, fill=m32) -c4161 = mcdc.cell(+s237 & -s238 & +s281 & -s282, fill=m33) -c4162 = mcdc.cell(+s237 & -s238 & +s282 & -s283, fill=m34) -c4163 = mcdc.cell(+s237 & -s238 & +s283 & -s284, fill=m35) -c4164 = mcdc.cell(+s237 & -s238 & +s284 & -s285, fill=m36) -c4165 = mcdc.cell(+s237 & -s238 & +s285, fill=m37) -c4166 = mcdc.cell(+s238 & -s239 & -s277, fill=m28) -c4167 = mcdc.cell(+s238 & -s239 & +s277 & -s278, fill=m29) -c4168 = mcdc.cell(+s238 & -s239 & +s278 & -s279, fill=m30) -c4169 = mcdc.cell(+s238 & -s239 & +s279 & -s280, fill=m31) -c4170 = mcdc.cell(+s238 & -s239 & +s280 & -s281, fill=m32) -c4171 = mcdc.cell(+s238 & -s239 & +s281 & -s282, fill=m33) -c4172 = mcdc.cell(+s238 & -s239 & +s282 & -s283, fill=m34) -c4173 = mcdc.cell(+s238 & -s239 & +s283 & -s284, fill=m35) -c4174 = mcdc.cell(+s238 & -s239 & +s284 & -s285, fill=m36) -c4175 = mcdc.cell(+s238 & -s239 & +s285, fill=m37) -c4176 = mcdc.cell(+s239 & -s240 & -s277, fill=m28) -c4177 = mcdc.cell(+s239 & -s240 & +s277 & -s278, fill=m29) -c4178 = mcdc.cell(+s239 & -s240 & +s278 & -s279, fill=m30) -c4179 = mcdc.cell(+s239 & -s240 & +s279 & -s280, fill=m31) -c4180 = mcdc.cell(+s239 & -s240 & +s280 & -s281, fill=m32) -c4181 = mcdc.cell(+s239 & -s240 & +s281 & -s282, fill=m33) -c4182 = mcdc.cell(+s239 & -s240 & +s282 & -s283, fill=m34) -c4183 = mcdc.cell(+s239 & -s240 & +s283 & -s284, fill=m35) -c4184 = mcdc.cell(+s239 & -s240 & +s284 & -s285, fill=m36) -c4185 = mcdc.cell(+s239 & -s240 & +s285, fill=m37) -c4186 = mcdc.cell(+s240 & -s241 & -s277, fill=m28) -c4187 = mcdc.cell(+s240 & -s241 & +s277 & -s278, fill=m29) -c4188 = mcdc.cell(+s240 & -s241 & +s278 & -s279, fill=m30) -c4189 = mcdc.cell(+s240 & -s241 & +s279 & -s280, fill=m31) -c4190 = mcdc.cell(+s240 & -s241 & +s280 & -s281, fill=m32) -c4191 = mcdc.cell(+s240 & -s241 & +s281 & -s282, fill=m33) -c4192 = mcdc.cell(+s240 & -s241 & +s282 & -s283, fill=m34) -c4193 = mcdc.cell(+s240 & -s241 & +s283 & -s284, fill=m35) -c4194 = mcdc.cell(+s240 & -s241 & +s284 & -s285, fill=m36) -c4195 = mcdc.cell(+s240 & -s241 & +s285, fill=m37) -c4196 = mcdc.cell(+s241 & -s242 & -s277, fill=m28) -c4197 = mcdc.cell(+s241 & -s242 & +s277 & -s278, fill=m29) -c4198 = mcdc.cell(+s241 & -s242 & +s278 & -s279, fill=m30) -c4199 = mcdc.cell(+s241 & -s242 & +s279 & -s280, fill=m31) -c4200 = mcdc.cell(+s241 & -s242 & +s280 & -s281, fill=m32) -c4201 = mcdc.cell(+s241 & -s242 & +s281 & -s282, fill=m33) -c4202 = mcdc.cell(+s241 & -s242 & +s282 & -s283, fill=m34) -c4203 = mcdc.cell(+s241 & -s242 & +s283 & -s284, fill=m35) -c4204 = mcdc.cell(+s241 & -s242 & +s284 & -s285, fill=m36) -c4205 = mcdc.cell(+s241 & -s242 & +s285, fill=m37) -c4206 = mcdc.cell(+s242 & -s243 & -s277, fill=m28) -c4207 = mcdc.cell(+s242 & -s243 & +s277 & -s278, fill=m29) -c4208 = mcdc.cell(+s242 & -s243 & +s278 & -s279, fill=m30) -c4209 = mcdc.cell(+s242 & -s243 & +s279 & -s280, fill=m31) -c4210 = mcdc.cell(+s242 & -s243 & +s280 & -s281, fill=m32) -c4211 = mcdc.cell(+s242 & -s243 & +s281 & -s282, fill=m33) -c4212 = mcdc.cell(+s242 & -s243 & +s282 & -s283, fill=m34) -c4213 = mcdc.cell(+s242 & -s243 & +s283 & -s284, fill=m35) -c4214 = mcdc.cell(+s242 & -s243 & +s284 & -s285, fill=m36) -c4215 = mcdc.cell(+s242 & -s243 & +s285, fill=m37) -c4216 = mcdc.cell(+s243 & -s244 & -s277, fill=m28) -c4217 = mcdc.cell(+s243 & -s244 & +s277 & -s278, fill=m29) -c4218 = mcdc.cell(+s243 & -s244 & +s278 & -s279, fill=m30) -c4219 = mcdc.cell(+s243 & -s244 & +s279 & -s280, fill=m31) -c4220 = mcdc.cell(+s243 & -s244 & +s280 & -s281, fill=m32) -c4221 = mcdc.cell(+s243 & -s244 & +s281 & -s282, fill=m33) -c4222 = mcdc.cell(+s243 & -s244 & +s282 & -s283, fill=m34) -c4223 = mcdc.cell(+s243 & -s244 & +s283 & -s284, fill=m35) -c4224 = mcdc.cell(+s243 & -s244 & +s284 & -s285, fill=m36) -c4225 = mcdc.cell(+s243 & -s244 & +s285, fill=m37) -c4226 = mcdc.cell(+s244 & -s245 & -s277, fill=m28) -c4227 = mcdc.cell(+s244 & -s245 & +s277 & -s278, fill=m29) -c4228 = mcdc.cell(+s244 & -s245 & +s278 & -s279, fill=m30) -c4229 = mcdc.cell(+s244 & -s245 & +s279 & -s280, fill=m31) -c4230 = mcdc.cell(+s244 & -s245 & +s280 & -s281, fill=m32) -c4231 = mcdc.cell(+s244 & -s245 & +s281 & -s282, fill=m33) -c4232 = mcdc.cell(+s244 & -s245 & +s282 & -s283, fill=m34) -c4233 = mcdc.cell(+s244 & -s245 & +s283 & -s284, fill=m35) -c4234 = mcdc.cell(+s244 & -s245 & +s284 & -s285, fill=m36) -c4235 = mcdc.cell(+s244 & -s245 & +s285, fill=m37) -c4236 = mcdc.cell(+s245 & -s246 & -s277, fill=m28) -c4237 = mcdc.cell(+s245 & -s246 & +s277 & -s278, fill=m29) -c4238 = mcdc.cell(+s245 & -s246 & +s278 & -s279, fill=m30) -c4239 = mcdc.cell(+s245 & -s246 & +s279 & -s280, fill=m31) -c4240 = mcdc.cell(+s245 & -s246 & +s280 & -s281, fill=m32) -c4241 = mcdc.cell(+s245 & -s246 & +s281 & -s282, fill=m33) -c4242 = mcdc.cell(+s245 & -s246 & +s282 & -s283, fill=m34) -c4243 = mcdc.cell(+s245 & -s246 & +s283 & -s284, fill=m35) -c4244 = mcdc.cell(+s245 & -s246 & +s284 & -s285, fill=m36) -c4245 = mcdc.cell(+s245 & -s246 & +s285, fill=m37) -c4246 = mcdc.cell(+s246 & -s247 & -s277, fill=m28) -c4247 = mcdc.cell(+s246 & -s247 & +s277 & -s278, fill=m29) -c4248 = mcdc.cell(+s246 & -s247 & +s278 & -s279, fill=m30) -c4249 = mcdc.cell(+s246 & -s247 & +s279 & -s280, fill=m31) -c4250 = mcdc.cell(+s246 & -s247 & +s280 & -s281, fill=m32) -c4251 = mcdc.cell(+s246 & -s247 & +s281 & -s282, fill=m33) -c4252 = mcdc.cell(+s246 & -s247 & +s282 & -s283, fill=m34) -c4253 = mcdc.cell(+s246 & -s247 & +s283 & -s284, fill=m35) -c4254 = mcdc.cell(+s246 & -s247 & +s284 & -s285, fill=m36) -c4255 = mcdc.cell(+s246 & -s247 & +s285, fill=m37) -c4256 = mcdc.cell(+s247 & -s248 & -s277, fill=m28) -c4257 = mcdc.cell(+s247 & -s248 & +s277 & -s278, fill=m29) -c4258 = mcdc.cell(+s247 & -s248 & +s278 & -s279, fill=m30) -c4259 = mcdc.cell(+s247 & -s248 & +s279 & -s280, fill=m31) -c4260 = mcdc.cell(+s247 & -s248 & +s280 & -s281, fill=m32) -c4261 = mcdc.cell(+s247 & -s248 & +s281 & -s282, fill=m33) -c4262 = mcdc.cell(+s247 & -s248 & +s282 & -s283, fill=m34) -c4263 = mcdc.cell(+s247 & -s248 & +s283 & -s284, fill=m35) -c4264 = mcdc.cell(+s247 & -s248 & +s284 & -s285, fill=m36) -c4265 = mcdc.cell(+s247 & -s248 & +s285, fill=m37) -c4266 = mcdc.cell(+s248 & -s249 & -s277, fill=m28) -c4267 = mcdc.cell(+s248 & -s249 & +s277 & -s278, fill=m29) -c4268 = mcdc.cell(+s248 & -s249 & +s278 & -s279, fill=m30) -c4269 = mcdc.cell(+s248 & -s249 & +s279 & -s280, fill=m31) -c4270 = mcdc.cell(+s248 & -s249 & +s280 & -s281, fill=m32) -c4271 = mcdc.cell(+s248 & -s249 & +s281 & -s282, fill=m33) -c4272 = mcdc.cell(+s248 & -s249 & +s282 & -s283, fill=m34) -c4273 = mcdc.cell(+s248 & -s249 & +s283 & -s284, fill=m35) -c4274 = mcdc.cell(+s248 & -s249 & +s284 & -s285, fill=m36) -c4275 = mcdc.cell(+s248 & -s249 & +s285, fill=m37) -c4276 = mcdc.cell(+s249 & -s250 & -s277, fill=m28) -c4277 = mcdc.cell(+s249 & -s250 & +s277 & -s278, fill=m29) -c4278 = mcdc.cell(+s249 & -s250 & +s278 & -s279, fill=m30) -c4279 = mcdc.cell(+s249 & -s250 & +s279 & -s280, fill=m31) -c4280 = mcdc.cell(+s249 & -s250 & +s280 & -s281, fill=m32) -c4281 = mcdc.cell(+s249 & -s250 & +s281 & -s282, fill=m33) -c4282 = mcdc.cell(+s249 & -s250 & +s282 & -s283, fill=m34) -c4283 = mcdc.cell(+s249 & -s250 & +s283 & -s284, fill=m35) -c4284 = mcdc.cell(+s249 & -s250 & +s284 & -s285, fill=m36) -c4285 = mcdc.cell(+s249 & -s250 & +s285, fill=m37) -c4286 = mcdc.cell(+s250 & -s251 & -s277, fill=m28) -c4287 = mcdc.cell(+s250 & -s251 & +s277 & -s278, fill=m29) -c4288 = mcdc.cell(+s250 & -s251 & +s278 & -s279, fill=m30) -c4289 = mcdc.cell(+s250 & -s251 & +s279 & -s280, fill=m31) -c4290 = mcdc.cell(+s250 & -s251 & +s280 & -s281, fill=m32) -c4291 = mcdc.cell(+s250 & -s251 & +s281 & -s282, fill=m33) -c4292 = mcdc.cell(+s250 & -s251 & +s282 & -s283, fill=m34) -c4293 = mcdc.cell(+s250 & -s251 & +s283 & -s284, fill=m35) -c4294 = mcdc.cell(+s250 & -s251 & +s284 & -s285, fill=m36) -c4295 = mcdc.cell(+s250 & -s251 & +s285, fill=m37) -c4296 = mcdc.cell(+s251 & -s252 & -s277, fill=m28) -c4297 = mcdc.cell(+s251 & -s252 & +s277 & -s278, fill=m29) -c4298 = mcdc.cell(+s251 & -s252 & +s278 & -s279, fill=m30) -c4299 = mcdc.cell(+s251 & -s252 & +s279 & -s280, fill=m31) -c4300 = mcdc.cell(+s251 & -s252 & +s280 & -s281, fill=m32) -c4301 = mcdc.cell(+s251 & -s252 & +s281 & -s282, fill=m33) -c4302 = mcdc.cell(+s251 & -s252 & +s282 & -s283, fill=m34) -c4303 = mcdc.cell(+s251 & -s252 & +s283 & -s284, fill=m35) -c4304 = mcdc.cell(+s251 & -s252 & +s284 & -s285, fill=m36) -c4305 = mcdc.cell(+s251 & -s252 & +s285, fill=m37) -c4306 = mcdc.cell(+s252 & -s253 & -s277, fill=m28) -c4307 = mcdc.cell(+s252 & -s253 & +s277 & -s278, fill=m29) -c4308 = mcdc.cell(+s252 & -s253 & +s278 & -s279, fill=m30) -c4309 = mcdc.cell(+s252 & -s253 & +s279 & -s280, fill=m31) -c4310 = mcdc.cell(+s252 & -s253 & +s280 & -s281, fill=m32) -c4311 = mcdc.cell(+s252 & -s253 & +s281 & -s282, fill=m33) -c4312 = mcdc.cell(+s252 & -s253 & +s282 & -s283, fill=m34) -c4313 = mcdc.cell(+s252 & -s253 & +s283 & -s284, fill=m35) -c4314 = mcdc.cell(+s252 & -s253 & +s284 & -s285, fill=m36) -c4315 = mcdc.cell(+s252 & -s253 & +s285, fill=m37) -c4316 = mcdc.cell(+s253 & -s254 & -s277, fill=m28) -c4317 = mcdc.cell(+s253 & -s254 & +s277 & -s278, fill=m29) -c4318 = mcdc.cell(+s253 & -s254 & +s278 & -s279, fill=m30) -c4319 = mcdc.cell(+s253 & -s254 & +s279 & -s280, fill=m31) -c4320 = mcdc.cell(+s253 & -s254 & +s280 & -s281, fill=m32) -c4321 = mcdc.cell(+s253 & -s254 & +s281 & -s282, fill=m33) -c4322 = mcdc.cell(+s253 & -s254 & +s282 & -s283, fill=m34) -c4323 = mcdc.cell(+s253 & -s254 & +s283 & -s284, fill=m35) -c4324 = mcdc.cell(+s253 & -s254 & +s284 & -s285, fill=m36) -c4325 = mcdc.cell(+s253 & -s254 & +s285, fill=m37) -c4326 = mcdc.cell(+s254 & -s255 & -s277, fill=m28) -c4327 = mcdc.cell(+s254 & -s255 & +s277 & -s278, fill=m29) -c4328 = mcdc.cell(+s254 & -s255 & +s278 & -s279, fill=m30) -c4329 = mcdc.cell(+s254 & -s255 & +s279 & -s280, fill=m31) -c4330 = mcdc.cell(+s254 & -s255 & +s280 & -s281, fill=m32) -c4331 = mcdc.cell(+s254 & -s255 & +s281 & -s282, fill=m33) -c4332 = mcdc.cell(+s254 & -s255 & +s282 & -s283, fill=m34) -c4333 = mcdc.cell(+s254 & -s255 & +s283 & -s284, fill=m35) -c4334 = mcdc.cell(+s254 & -s255 & +s284 & -s285, fill=m36) -c4335 = mcdc.cell(+s254 & -s255 & +s285, fill=m37) -c4336 = mcdc.cell(+s255 & -s256 & -s277, fill=m28) -c4337 = mcdc.cell(+s255 & -s256 & +s277 & -s278, fill=m29) -c4338 = mcdc.cell(+s255 & -s256 & +s278 & -s279, fill=m30) -c4339 = mcdc.cell(+s255 & -s256 & +s279 & -s280, fill=m31) -c4340 = mcdc.cell(+s255 & -s256 & +s280 & -s281, fill=m32) -c4341 = mcdc.cell(+s255 & -s256 & +s281 & -s282, fill=m33) -c4342 = mcdc.cell(+s255 & -s256 & +s282 & -s283, fill=m34) -c4343 = mcdc.cell(+s255 & -s256 & +s283 & -s284, fill=m35) -c4344 = mcdc.cell(+s255 & -s256 & +s284 & -s285, fill=m36) -c4345 = mcdc.cell(+s255 & -s256 & +s285, fill=m37) -c4346 = mcdc.cell(+s256 & -s257 & -s277, fill=m28) -c4347 = mcdc.cell(+s256 & -s257 & +s277 & -s278, fill=m29) -c4348 = mcdc.cell(+s256 & -s257 & +s278 & -s279, fill=m30) -c4349 = mcdc.cell(+s256 & -s257 & +s279 & -s280, fill=m31) -c4350 = mcdc.cell(+s256 & -s257 & +s280 & -s281, fill=m32) -c4351 = mcdc.cell(+s256 & -s257 & +s281 & -s282, fill=m33) -c4352 = mcdc.cell(+s256 & -s257 & +s282 & -s283, fill=m34) -c4353 = mcdc.cell(+s256 & -s257 & +s283 & -s284, fill=m35) -c4354 = mcdc.cell(+s256 & -s257 & +s284 & -s285, fill=m36) -c4355 = mcdc.cell(+s256 & -s257 & +s285, fill=m37) -c4356 = mcdc.cell(+s257 & -s258 & -s277, fill=m28) -c4357 = mcdc.cell(+s257 & -s258 & +s277 & -s278, fill=m29) -c4358 = mcdc.cell(+s257 & -s258 & +s278 & -s279, fill=m30) -c4359 = mcdc.cell(+s257 & -s258 & +s279 & -s280, fill=m31) -c4360 = mcdc.cell(+s257 & -s258 & +s280 & -s281, fill=m32) -c4361 = mcdc.cell(+s257 & -s258 & +s281 & -s282, fill=m33) -c4362 = mcdc.cell(+s257 & -s258 & +s282 & -s283, fill=m34) -c4363 = mcdc.cell(+s257 & -s258 & +s283 & -s284, fill=m35) -c4364 = mcdc.cell(+s257 & -s258 & +s284 & -s285, fill=m36) -c4365 = mcdc.cell(+s257 & -s258 & +s285, fill=m37) -c4366 = mcdc.cell(+s258 & -s259 & -s277, fill=m28) -c4367 = mcdc.cell(+s258 & -s259 & +s277 & -s278, fill=m29) -c4368 = mcdc.cell(+s258 & -s259 & +s278 & -s279, fill=m30) -c4369 = mcdc.cell(+s258 & -s259 & +s279 & -s280, fill=m31) -c4370 = mcdc.cell(+s258 & -s259 & +s280 & -s281, fill=m32) -c4371 = mcdc.cell(+s258 & -s259 & +s281 & -s282, fill=m33) -c4372 = mcdc.cell(+s258 & -s259 & +s282 & -s283, fill=m34) -c4373 = mcdc.cell(+s258 & -s259 & +s283 & -s284, fill=m35) -c4374 = mcdc.cell(+s258 & -s259 & +s284 & -s285, fill=m36) -c4375 = mcdc.cell(+s258 & -s259 & +s285, fill=m37) -c4376 = mcdc.cell(+s259 & -s260 & -s277, fill=m28) -c4377 = mcdc.cell(+s259 & -s260 & +s277 & -s278, fill=m29) -c4378 = mcdc.cell(+s259 & -s260 & +s278 & -s279, fill=m30) -c4379 = mcdc.cell(+s259 & -s260 & +s279 & -s280, fill=m31) -c4380 = mcdc.cell(+s259 & -s260 & +s280 & -s281, fill=m32) -c4381 = mcdc.cell(+s259 & -s260 & +s281 & -s282, fill=m33) -c4382 = mcdc.cell(+s259 & -s260 & +s282 & -s283, fill=m34) -c4383 = mcdc.cell(+s259 & -s260 & +s283 & -s284, fill=m35) -c4384 = mcdc.cell(+s259 & -s260 & +s284 & -s285, fill=m36) -c4385 = mcdc.cell(+s259 & -s260 & +s285, fill=m37) -c4386 = mcdc.cell(+s260 & -s261 & -s277, fill=m28) -c4387 = mcdc.cell(+s260 & -s261 & +s277 & -s278, fill=m29) -c4388 = mcdc.cell(+s260 & -s261 & +s278 & -s279, fill=m30) -c4389 = mcdc.cell(+s260 & -s261 & +s279 & -s280, fill=m31) -c4390 = mcdc.cell(+s260 & -s261 & +s280 & -s281, fill=m32) -c4391 = mcdc.cell(+s260 & -s261 & +s281 & -s282, fill=m33) -c4392 = mcdc.cell(+s260 & -s261 & +s282 & -s283, fill=m34) -c4393 = mcdc.cell(+s260 & -s261 & +s283 & -s284, fill=m35) -c4394 = mcdc.cell(+s260 & -s261 & +s284 & -s285, fill=m36) -c4395 = mcdc.cell(+s260 & -s261 & +s285, fill=m37) -c4396 = mcdc.cell(+s261 & -s262 & -s277, fill=m28) -c4397 = mcdc.cell(+s261 & -s262 & +s277 & -s278, fill=m29) -c4398 = mcdc.cell(+s261 & -s262 & +s278 & -s279, fill=m30) -c4399 = mcdc.cell(+s261 & -s262 & +s279 & -s280, fill=m31) -c4400 = mcdc.cell(+s261 & -s262 & +s280 & -s281, fill=m32) -c4401 = mcdc.cell(+s261 & -s262 & +s281 & -s282, fill=m33) -c4402 = mcdc.cell(+s261 & -s262 & +s282 & -s283, fill=m34) -c4403 = mcdc.cell(+s261 & -s262 & +s283 & -s284, fill=m35) -c4404 = mcdc.cell(+s261 & -s262 & +s284 & -s285, fill=m36) -c4405 = mcdc.cell(+s261 & -s262 & +s285, fill=m37) -c4406 = mcdc.cell(+s262 & -s263 & -s277, fill=m28) -c4407 = mcdc.cell(+s262 & -s263 & +s277 & -s278, fill=m29) -c4408 = mcdc.cell(+s262 & -s263 & +s278 & -s279, fill=m30) -c4409 = mcdc.cell(+s262 & -s263 & +s279 & -s280, fill=m31) -c4410 = mcdc.cell(+s262 & -s263 & +s280 & -s281, fill=m32) -c4411 = mcdc.cell(+s262 & -s263 & +s281 & -s282, fill=m33) -c4412 = mcdc.cell(+s262 & -s263 & +s282 & -s283, fill=m34) -c4413 = mcdc.cell(+s262 & -s263 & +s283 & -s284, fill=m35) -c4414 = mcdc.cell(+s262 & -s263 & +s284 & -s285, fill=m36) -c4415 = mcdc.cell(+s262 & -s263 & +s285, fill=m37) -c4416 = mcdc.cell(+s263 & -s264 & -s277, fill=m28) -c4417 = mcdc.cell(+s263 & -s264 & +s277 & -s278, fill=m29) -c4418 = mcdc.cell(+s263 & -s264 & +s278 & -s279, fill=m30) -c4419 = mcdc.cell(+s263 & -s264 & +s279 & -s280, fill=m31) -c4420 = mcdc.cell(+s263 & -s264 & +s280 & -s281, fill=m32) -c4421 = mcdc.cell(+s263 & -s264 & +s281 & -s282, fill=m33) -c4422 = mcdc.cell(+s263 & -s264 & +s282 & -s283, fill=m34) -c4423 = mcdc.cell(+s263 & -s264 & +s283 & -s284, fill=m35) -c4424 = mcdc.cell(+s263 & -s264 & +s284 & -s285, fill=m36) -c4425 = mcdc.cell(+s263 & -s264 & +s285, fill=m37) -c4426 = mcdc.cell(+s264 & -s265 & -s277, fill=m28) -c4427 = mcdc.cell(+s264 & -s265 & +s277 & -s278, fill=m29) -c4428 = mcdc.cell(+s264 & -s265 & +s278 & -s279, fill=m30) -c4429 = mcdc.cell(+s264 & -s265 & +s279 & -s280, fill=m31) -c4430 = mcdc.cell(+s264 & -s265 & +s280 & -s281, fill=m32) -c4431 = mcdc.cell(+s264 & -s265 & +s281 & -s282, fill=m33) -c4432 = mcdc.cell(+s264 & -s265 & +s282 & -s283, fill=m34) -c4433 = mcdc.cell(+s264 & -s265 & +s283 & -s284, fill=m35) -c4434 = mcdc.cell(+s264 & -s265 & +s284 & -s285, fill=m36) -c4435 = mcdc.cell(+s264 & -s265 & +s285, fill=m37) -c4436 = mcdc.cell(+s265 & -s266 & -s277, fill=m28) -c4437 = mcdc.cell(+s265 & -s266 & +s277 & -s278, fill=m29) -c4438 = mcdc.cell(+s265 & -s266 & +s278 & -s279, fill=m30) -c4439 = mcdc.cell(+s265 & -s266 & +s279 & -s280, fill=m31) -c4440 = mcdc.cell(+s265 & -s266 & +s280 & -s281, fill=m32) -c4441 = mcdc.cell(+s265 & -s266 & +s281 & -s282, fill=m33) -c4442 = mcdc.cell(+s265 & -s266 & +s282 & -s283, fill=m34) -c4443 = mcdc.cell(+s265 & -s266 & +s283 & -s284, fill=m35) -c4444 = mcdc.cell(+s265 & -s266 & +s284 & -s285, fill=m36) -c4445 = mcdc.cell(+s265 & -s266 & +s285, fill=m37) -c4446 = mcdc.cell(+s266 & -s267 & -s277, fill=m28) -c4447 = mcdc.cell(+s266 & -s267 & +s277 & -s278, fill=m29) -c4448 = mcdc.cell(+s266 & -s267 & +s278 & -s279, fill=m30) -c4449 = mcdc.cell(+s266 & -s267 & +s279 & -s280, fill=m31) -c4450 = mcdc.cell(+s266 & -s267 & +s280 & -s281, fill=m32) -c4451 = mcdc.cell(+s266 & -s267 & +s281 & -s282, fill=m33) -c4452 = mcdc.cell(+s266 & -s267 & +s282 & -s283, fill=m34) -c4453 = mcdc.cell(+s266 & -s267 & +s283 & -s284, fill=m35) -c4454 = mcdc.cell(+s266 & -s267 & +s284 & -s285, fill=m36) -c4455 = mcdc.cell(+s266 & -s267 & +s285, fill=m37) -c4456 = mcdc.cell(+s267 & -s268 & -s277, fill=m28) -c4457 = mcdc.cell(+s267 & -s268 & +s277 & -s278, fill=m29) -c4458 = mcdc.cell(+s267 & -s268 & +s278 & -s279, fill=m30) -c4459 = mcdc.cell(+s267 & -s268 & +s279 & -s280, fill=m31) -c4460 = mcdc.cell(+s267 & -s268 & +s280 & -s281, fill=m32) -c4461 = mcdc.cell(+s267 & -s268 & +s281 & -s282, fill=m33) -c4462 = mcdc.cell(+s267 & -s268 & +s282 & -s283, fill=m34) -c4463 = mcdc.cell(+s267 & -s268 & +s283 & -s284, fill=m35) -c4464 = mcdc.cell(+s267 & -s268 & +s284 & -s285, fill=m36) -c4465 = mcdc.cell(+s267 & -s268 & +s285, fill=m37) -c4466 = mcdc.cell(+s268 & -s269 & -s277, fill=m28) -c4467 = mcdc.cell(+s268 & -s269 & +s277 & -s278, fill=m29) -c4468 = mcdc.cell(+s268 & -s269 & +s278 & -s279, fill=m30) -c4469 = mcdc.cell(+s268 & -s269 & +s279 & -s280, fill=m31) -c4470 = mcdc.cell(+s268 & -s269 & +s280 & -s281, fill=m32) -c4471 = mcdc.cell(+s268 & -s269 & +s281 & -s282, fill=m33) -c4472 = mcdc.cell(+s268 & -s269 & +s282 & -s283, fill=m34) -c4473 = mcdc.cell(+s268 & -s269 & +s283 & -s284, fill=m35) -c4474 = mcdc.cell(+s268 & -s269 & +s284 & -s285, fill=m36) -c4475 = mcdc.cell(+s268 & -s269 & +s285, fill=m37) -c4476 = mcdc.cell(+s269 & -s270 & -s277, fill=m28) -c4477 = mcdc.cell(+s269 & -s270 & +s277 & -s278, fill=m29) -c4478 = mcdc.cell(+s269 & -s270 & +s278 & -s279, fill=m30) -c4479 = mcdc.cell(+s269 & -s270 & +s279 & -s280, fill=m31) -c4480 = mcdc.cell(+s269 & -s270 & +s280 & -s281, fill=m32) -c4481 = mcdc.cell(+s269 & -s270 & +s281 & -s282, fill=m33) -c4482 = mcdc.cell(+s269 & -s270 & +s282 & -s283, fill=m34) -c4483 = mcdc.cell(+s269 & -s270 & +s283 & -s284, fill=m35) -c4484 = mcdc.cell(+s269 & -s270 & +s284 & -s285, fill=m36) -c4485 = mcdc.cell(+s269 & -s270 & +s285, fill=m37) -c4486 = mcdc.cell(+s270 & -s271 & -s277, fill=m28) -c4487 = mcdc.cell(+s270 & -s271 & +s277 & -s278, fill=m29) -c4488 = mcdc.cell(+s270 & -s271 & +s278 & -s279, fill=m30) -c4489 = mcdc.cell(+s270 & -s271 & +s279 & -s280, fill=m31) -c4490 = mcdc.cell(+s270 & -s271 & +s280 & -s281, fill=m32) -c4491 = mcdc.cell(+s270 & -s271 & +s281 & -s282, fill=m33) -c4492 = mcdc.cell(+s270 & -s271 & +s282 & -s283, fill=m34) -c4493 = mcdc.cell(+s270 & -s271 & +s283 & -s284, fill=m35) -c4494 = mcdc.cell(+s270 & -s271 & +s284 & -s285, fill=m36) -c4495 = mcdc.cell(+s270 & -s271 & +s285, fill=m37) -c4496 = mcdc.cell(+s271 & -s272 & -s277, fill=m28) -c4497 = mcdc.cell(+s271 & -s272 & +s277 & -s278, fill=m29) -c4498 = mcdc.cell(+s271 & -s272 & +s278 & -s279, fill=m30) -c4499 = mcdc.cell(+s271 & -s272 & +s279 & -s280, fill=m31) -c4500 = mcdc.cell(+s271 & -s272 & +s280 & -s281, fill=m32) -c4501 = mcdc.cell(+s271 & -s272 & +s281 & -s282, fill=m33) -c4502 = mcdc.cell(+s271 & -s272 & +s282 & -s283, fill=m34) -c4503 = mcdc.cell(+s271 & -s272 & +s283 & -s284, fill=m35) -c4504 = mcdc.cell(+s271 & -s272 & +s284 & -s285, fill=m36) -c4505 = mcdc.cell(+s271 & -s272 & +s285, fill=m37) -c4506 = mcdc.cell(+s272 & -s273 & -s277, fill=m28) -c4507 = mcdc.cell(+s272 & -s273 & +s277 & -s278, fill=m29) -c4508 = mcdc.cell(+s272 & -s273 & +s278 & -s279, fill=m30) -c4509 = mcdc.cell(+s272 & -s273 & +s279 & -s280, fill=m31) -c4510 = mcdc.cell(+s272 & -s273 & +s280 & -s281, fill=m32) -c4511 = mcdc.cell(+s272 & -s273 & +s281 & -s282, fill=m33) -c4512 = mcdc.cell(+s272 & -s273 & +s282 & -s283, fill=m34) -c4513 = mcdc.cell(+s272 & -s273 & +s283 & -s284, fill=m35) -c4514 = mcdc.cell(+s272 & -s273 & +s284 & -s285, fill=m36) -c4515 = mcdc.cell(+s272 & -s273 & +s285, fill=m37) -c4516 = mcdc.cell(+s273 & -s274 & -s277, fill=m28) -c4517 = mcdc.cell(+s273 & -s274 & +s277 & -s278, fill=m29) -c4518 = mcdc.cell(+s273 & -s274 & +s278 & -s279, fill=m30) -c4519 = mcdc.cell(+s273 & -s274 & +s279 & -s280, fill=m31) -c4520 = mcdc.cell(+s273 & -s274 & +s280 & -s281, fill=m32) -c4521 = mcdc.cell(+s273 & -s274 & +s281 & -s282, fill=m33) -c4522 = mcdc.cell(+s273 & -s274 & +s282 & -s283, fill=m34) -c4523 = mcdc.cell(+s273 & -s274 & +s283 & -s284, fill=m35) -c4524 = mcdc.cell(+s273 & -s274 & +s284 & -s285, fill=m36) -c4525 = mcdc.cell(+s273 & -s274 & +s285, fill=m37) -c4526 = mcdc.cell(+s274 & -s275 & -s277, fill=m28) -c4527 = mcdc.cell(+s274 & -s275 & +s277 & -s278, fill=m29) -c4528 = mcdc.cell(+s274 & -s275 & +s278 & -s279, fill=m30) -c4529 = mcdc.cell(+s274 & -s275 & +s279 & -s280, fill=m31) -c4530 = mcdc.cell(+s274 & -s275 & +s280 & -s281, fill=m32) -c4531 = mcdc.cell(+s274 & -s275 & +s281 & -s282, fill=m33) -c4532 = mcdc.cell(+s274 & -s275 & +s282 & -s283, fill=m34) -c4533 = mcdc.cell(+s274 & -s275 & +s283 & -s284, fill=m35) -c4534 = mcdc.cell(+s274 & -s275 & +s284 & -s285, fill=m36) -c4535 = mcdc.cell(+s274 & -s275 & +s285, fill=m37) -c4536 = mcdc.cell(+s275 & -s276 & -s277, fill=m28) -c4537 = mcdc.cell(+s275 & -s276 & +s277 & -s278, fill=m29) -c4538 = mcdc.cell(+s275 & -s276 & +s278 & -s279, fill=m30) -c4539 = mcdc.cell(+s275 & -s276 & +s279 & -s280, fill=m31) -c4540 = mcdc.cell(+s275 & -s276 & +s280 & -s281, fill=m32) -c4541 = mcdc.cell(+s275 & -s276 & +s281 & -s282, fill=m33) -c4542 = mcdc.cell(+s275 & -s276 & +s282 & -s283, fill=m34) -c4543 = mcdc.cell(+s275 & -s276 & +s283 & -s284, fill=m35) -c4544 = mcdc.cell(+s275 & -s276 & +s284 & -s285, fill=m36) -c4545 = mcdc.cell(+s275 & -s276 & +s285, fill=m37) -c4546 = mcdc.cell(+s276 & -s277, fill=m28) -c4547 = mcdc.cell(+s276 & +s277 & -s278, fill=m29) -c4548 = mcdc.cell(+s276 & +s278 & -s279, fill=m30) -c4549 = mcdc.cell(+s276 & +s279 & -s280, fill=m31) -c4550 = mcdc.cell(+s276 & +s280 & -s281, fill=m32) -c4551 = mcdc.cell(+s276 & +s281 & -s282, fill=m33) -c4552 = mcdc.cell(+s276 & +s282 & -s283, fill=m34) -c4553 = mcdc.cell(+s276 & +s283 & -s284, fill=m35) -c4554 = mcdc.cell(+s276 & +s284 & -s285, fill=m36) -c4555 = mcdc.cell(+s276 & +s285, fill=m37) -c4583 = mcdc.cell(-s82 & -s277, fill=m18) -c4584 = mcdc.cell(-s82 & +s277 & -s278, fill=m19) -c4585 = mcdc.cell(-s82 & +s278 & -s279, fill=m20) -c4586 = mcdc.cell(-s82 & +s279 & -s280, fill=m21) -c4587 = mcdc.cell(-s82 & +s280 & -s281, fill=m22) -c4588 = mcdc.cell(-s82 & +s281 & -s282, fill=m23) -c4589 = mcdc.cell(-s82 & +s282 & -s283, fill=m24) -c4590 = mcdc.cell(-s82 & +s283 & -s284, fill=m25) -c4591 = mcdc.cell(-s82 & +s284 & -s285, fill=m26) -c4592 = mcdc.cell(-s82 & +s285, fill=m27) -c4593 = mcdc.cell(+s82 & -s83 & -s277, fill=m18) -c4594 = mcdc.cell(+s82 & -s83 & +s277 & -s278, fill=m19) -c4595 = mcdc.cell(+s82 & -s83 & +s278 & -s279, fill=m20) -c4596 = mcdc.cell(+s82 & -s83 & +s279 & -s280, fill=m21) -c4597 = mcdc.cell(+s82 & -s83 & +s280 & -s281, fill=m22) -c4598 = mcdc.cell(+s82 & -s83 & +s281 & -s282, fill=m23) -c4599 = mcdc.cell(+s82 & -s83 & +s282 & -s283, fill=m24) -c4600 = mcdc.cell(+s82 & -s83 & +s283 & -s284, fill=m25) -c4601 = mcdc.cell(+s82 & -s83 & +s284 & -s285, fill=m26) -c4602 = mcdc.cell(+s82 & -s83 & +s285, fill=m27) -c4603 = mcdc.cell(+s83 & -s84 & -s277, fill=m18) -c4604 = mcdc.cell(+s83 & -s84 & +s277 & -s278, fill=m19) -c4605 = mcdc.cell(+s83 & -s84 & +s278 & -s279, fill=m20) -c4606 = mcdc.cell(+s83 & -s84 & +s279 & -s280, fill=m21) -c4607 = mcdc.cell(+s83 & -s84 & +s280 & -s281, fill=m22) -c4608 = mcdc.cell(+s83 & -s84 & +s281 & -s282, fill=m23) -c4609 = mcdc.cell(+s83 & -s84 & +s282 & -s283, fill=m24) -c4610 = mcdc.cell(+s83 & -s84 & +s283 & -s284, fill=m25) -c4611 = mcdc.cell(+s83 & -s84 & +s284 & -s285, fill=m26) -c4612 = mcdc.cell(+s83 & -s84 & +s285, fill=m27) -c4613 = mcdc.cell(+s84 & -s85 & -s277, fill=m18) -c4614 = mcdc.cell(+s84 & -s85 & +s277 & -s278, fill=m19) -c4615 = mcdc.cell(+s84 & -s85 & +s278 & -s279, fill=m20) -c4616 = mcdc.cell(+s84 & -s85 & +s279 & -s280, fill=m21) -c4617 = mcdc.cell(+s84 & -s85 & +s280 & -s281, fill=m22) -c4618 = mcdc.cell(+s84 & -s85 & +s281 & -s282, fill=m23) -c4619 = mcdc.cell(+s84 & -s85 & +s282 & -s283, fill=m24) -c4620 = mcdc.cell(+s84 & -s85 & +s283 & -s284, fill=m25) -c4621 = mcdc.cell(+s84 & -s85 & +s284 & -s285, fill=m26) -c4622 = mcdc.cell(+s84 & -s85 & +s285, fill=m27) -c4623 = mcdc.cell(+s85 & -s86 & -s277, fill=m18) -c4624 = mcdc.cell(+s85 & -s86 & +s277 & -s278, fill=m19) -c4625 = mcdc.cell(+s85 & -s86 & +s278 & -s279, fill=m20) -c4626 = mcdc.cell(+s85 & -s86 & +s279 & -s280, fill=m21) -c4627 = mcdc.cell(+s85 & -s86 & +s280 & -s281, fill=m22) -c4628 = mcdc.cell(+s85 & -s86 & +s281 & -s282, fill=m23) -c4629 = mcdc.cell(+s85 & -s86 & +s282 & -s283, fill=m24) -c4630 = mcdc.cell(+s85 & -s86 & +s283 & -s284, fill=m25) -c4631 = mcdc.cell(+s85 & -s86 & +s284 & -s285, fill=m26) -c4632 = mcdc.cell(+s85 & -s86 & +s285, fill=m27) -c4633 = mcdc.cell(+s86 & -s87 & -s277, fill=m18) -c4634 = mcdc.cell(+s86 & -s87 & +s277 & -s278, fill=m19) -c4635 = mcdc.cell(+s86 & -s87 & +s278 & -s279, fill=m20) -c4636 = mcdc.cell(+s86 & -s87 & +s279 & -s280, fill=m21) -c4637 = mcdc.cell(+s86 & -s87 & +s280 & -s281, fill=m22) -c4638 = mcdc.cell(+s86 & -s87 & +s281 & -s282, fill=m23) -c4639 = mcdc.cell(+s86 & -s87 & +s282 & -s283, fill=m24) -c4640 = mcdc.cell(+s86 & -s87 & +s283 & -s284, fill=m25) -c4641 = mcdc.cell(+s86 & -s87 & +s284 & -s285, fill=m26) -c4642 = mcdc.cell(+s86 & -s87 & +s285, fill=m27) -c4643 = mcdc.cell(+s87 & -s88 & -s277, fill=m18) -c4644 = mcdc.cell(+s87 & -s88 & +s277 & -s278, fill=m19) -c4645 = mcdc.cell(+s87 & -s88 & +s278 & -s279, fill=m20) -c4646 = mcdc.cell(+s87 & -s88 & +s279 & -s280, fill=m21) -c4647 = mcdc.cell(+s87 & -s88 & +s280 & -s281, fill=m22) -c4648 = mcdc.cell(+s87 & -s88 & +s281 & -s282, fill=m23) -c4649 = mcdc.cell(+s87 & -s88 & +s282 & -s283, fill=m24) -c4650 = mcdc.cell(+s87 & -s88 & +s283 & -s284, fill=m25) -c4651 = mcdc.cell(+s87 & -s88 & +s284 & -s285, fill=m26) -c4652 = mcdc.cell(+s87 & -s88 & +s285, fill=m27) -c4653 = mcdc.cell(+s88 & -s89 & -s277, fill=m18) -c4654 = mcdc.cell(+s88 & -s89 & +s277 & -s278, fill=m19) -c4655 = mcdc.cell(+s88 & -s89 & +s278 & -s279, fill=m20) -c4656 = mcdc.cell(+s88 & -s89 & +s279 & -s280, fill=m21) -c4657 = mcdc.cell(+s88 & -s89 & +s280 & -s281, fill=m22) -c4658 = mcdc.cell(+s88 & -s89 & +s281 & -s282, fill=m23) -c4659 = mcdc.cell(+s88 & -s89 & +s282 & -s283, fill=m24) -c4660 = mcdc.cell(+s88 & -s89 & +s283 & -s284, fill=m25) -c4661 = mcdc.cell(+s88 & -s89 & +s284 & -s285, fill=m26) -c4662 = mcdc.cell(+s88 & -s89 & +s285, fill=m27) -c4663 = mcdc.cell(+s89 & -s90 & -s277, fill=m18) -c4664 = mcdc.cell(+s89 & -s90 & +s277 & -s278, fill=m19) -c4665 = mcdc.cell(+s89 & -s90 & +s278 & -s279, fill=m20) -c4666 = mcdc.cell(+s89 & -s90 & +s279 & -s280, fill=m21) -c4667 = mcdc.cell(+s89 & -s90 & +s280 & -s281, fill=m22) -c4668 = mcdc.cell(+s89 & -s90 & +s281 & -s282, fill=m23) -c4669 = mcdc.cell(+s89 & -s90 & +s282 & -s283, fill=m24) -c4670 = mcdc.cell(+s89 & -s90 & +s283 & -s284, fill=m25) -c4671 = mcdc.cell(+s89 & -s90 & +s284 & -s285, fill=m26) -c4672 = mcdc.cell(+s89 & -s90 & +s285, fill=m27) -c4673 = mcdc.cell(+s90 & -s91 & -s277, fill=m18) -c4674 = mcdc.cell(+s90 & -s91 & +s277 & -s278, fill=m19) -c4675 = mcdc.cell(+s90 & -s91 & +s278 & -s279, fill=m20) -c4676 = mcdc.cell(+s90 & -s91 & +s279 & -s280, fill=m21) -c4677 = mcdc.cell(+s90 & -s91 & +s280 & -s281, fill=m22) -c4678 = mcdc.cell(+s90 & -s91 & +s281 & -s282, fill=m23) -c4679 = mcdc.cell(+s90 & -s91 & +s282 & -s283, fill=m24) -c4680 = mcdc.cell(+s90 & -s91 & +s283 & -s284, fill=m25) -c4681 = mcdc.cell(+s90 & -s91 & +s284 & -s285, fill=m26) -c4682 = mcdc.cell(+s90 & -s91 & +s285, fill=m27) -c4683 = mcdc.cell(+s91 & -s92 & -s277, fill=m18) -c4684 = mcdc.cell(+s91 & -s92 & +s277 & -s278, fill=m19) -c4685 = mcdc.cell(+s91 & -s92 & +s278 & -s279, fill=m20) -c4686 = mcdc.cell(+s91 & -s92 & +s279 & -s280, fill=m21) -c4687 = mcdc.cell(+s91 & -s92 & +s280 & -s281, fill=m22) -c4688 = mcdc.cell(+s91 & -s92 & +s281 & -s282, fill=m23) -c4689 = mcdc.cell(+s91 & -s92 & +s282 & -s283, fill=m24) -c4690 = mcdc.cell(+s91 & -s92 & +s283 & -s284, fill=m25) -c4691 = mcdc.cell(+s91 & -s92 & +s284 & -s285, fill=m26) -c4692 = mcdc.cell(+s91 & -s92 & +s285, fill=m27) -c4693 = mcdc.cell(+s92 & -s93 & -s277, fill=m18) -c4694 = mcdc.cell(+s92 & -s93 & +s277 & -s278, fill=m19) -c4695 = mcdc.cell(+s92 & -s93 & +s278 & -s279, fill=m20) -c4696 = mcdc.cell(+s92 & -s93 & +s279 & -s280, fill=m21) -c4697 = mcdc.cell(+s92 & -s93 & +s280 & -s281, fill=m22) -c4698 = mcdc.cell(+s92 & -s93 & +s281 & -s282, fill=m23) -c4699 = mcdc.cell(+s92 & -s93 & +s282 & -s283, fill=m24) -c4700 = mcdc.cell(+s92 & -s93 & +s283 & -s284, fill=m25) -c4701 = mcdc.cell(+s92 & -s93 & +s284 & -s285, fill=m26) -c4702 = mcdc.cell(+s92 & -s93 & +s285, fill=m27) -c4703 = mcdc.cell(+s93 & -s94 & -s277, fill=m18) -c4704 = mcdc.cell(+s93 & -s94 & +s277 & -s278, fill=m19) -c4705 = mcdc.cell(+s93 & -s94 & +s278 & -s279, fill=m20) -c4706 = mcdc.cell(+s93 & -s94 & +s279 & -s280, fill=m21) -c4707 = mcdc.cell(+s93 & -s94 & +s280 & -s281, fill=m22) -c4708 = mcdc.cell(+s93 & -s94 & +s281 & -s282, fill=m23) -c4709 = mcdc.cell(+s93 & -s94 & +s282 & -s283, fill=m24) -c4710 = mcdc.cell(+s93 & -s94 & +s283 & -s284, fill=m25) -c4711 = mcdc.cell(+s93 & -s94 & +s284 & -s285, fill=m26) -c4712 = mcdc.cell(+s93 & -s94 & +s285, fill=m27) -c4713 = mcdc.cell(+s94 & -s95 & -s277, fill=m18) -c4714 = mcdc.cell(+s94 & -s95 & +s277 & -s278, fill=m19) -c4715 = mcdc.cell(+s94 & -s95 & +s278 & -s279, fill=m20) -c4716 = mcdc.cell(+s94 & -s95 & +s279 & -s280, fill=m21) -c4717 = mcdc.cell(+s94 & -s95 & +s280 & -s281, fill=m22) -c4718 = mcdc.cell(+s94 & -s95 & +s281 & -s282, fill=m23) -c4719 = mcdc.cell(+s94 & -s95 & +s282 & -s283, fill=m24) -c4720 = mcdc.cell(+s94 & -s95 & +s283 & -s284, fill=m25) -c4721 = mcdc.cell(+s94 & -s95 & +s284 & -s285, fill=m26) -c4722 = mcdc.cell(+s94 & -s95 & +s285, fill=m27) -c4723 = mcdc.cell(+s95 & -s96 & -s277, fill=m18) -c4724 = mcdc.cell(+s95 & -s96 & +s277 & -s278, fill=m19) -c4725 = mcdc.cell(+s95 & -s96 & +s278 & -s279, fill=m20) -c4726 = mcdc.cell(+s95 & -s96 & +s279 & -s280, fill=m21) -c4727 = mcdc.cell(+s95 & -s96 & +s280 & -s281, fill=m22) -c4728 = mcdc.cell(+s95 & -s96 & +s281 & -s282, fill=m23) -c4729 = mcdc.cell(+s95 & -s96 & +s282 & -s283, fill=m24) -c4730 = mcdc.cell(+s95 & -s96 & +s283 & -s284, fill=m25) -c4731 = mcdc.cell(+s95 & -s96 & +s284 & -s285, fill=m26) -c4732 = mcdc.cell(+s95 & -s96 & +s285, fill=m27) -c4733 = mcdc.cell(+s96 & -s97 & -s277, fill=m18) -c4734 = mcdc.cell(+s96 & -s97 & +s277 & -s278, fill=m19) -c4735 = mcdc.cell(+s96 & -s97 & +s278 & -s279, fill=m20) -c4736 = mcdc.cell(+s96 & -s97 & +s279 & -s280, fill=m21) -c4737 = mcdc.cell(+s96 & -s97 & +s280 & -s281, fill=m22) -c4738 = mcdc.cell(+s96 & -s97 & +s281 & -s282, fill=m23) -c4739 = mcdc.cell(+s96 & -s97 & +s282 & -s283, fill=m24) -c4740 = mcdc.cell(+s96 & -s97 & +s283 & -s284, fill=m25) -c4741 = mcdc.cell(+s96 & -s97 & +s284 & -s285, fill=m26) -c4742 = mcdc.cell(+s96 & -s97 & +s285, fill=m27) -c4743 = mcdc.cell(+s97 & -s98 & -s277, fill=m18) -c4744 = mcdc.cell(+s97 & -s98 & +s277 & -s278, fill=m19) -c4745 = mcdc.cell(+s97 & -s98 & +s278 & -s279, fill=m20) -c4746 = mcdc.cell(+s97 & -s98 & +s279 & -s280, fill=m21) -c4747 = mcdc.cell(+s97 & -s98 & +s280 & -s281, fill=m22) -c4748 = mcdc.cell(+s97 & -s98 & +s281 & -s282, fill=m23) -c4749 = mcdc.cell(+s97 & -s98 & +s282 & -s283, fill=m24) -c4750 = mcdc.cell(+s97 & -s98 & +s283 & -s284, fill=m25) -c4751 = mcdc.cell(+s97 & -s98 & +s284 & -s285, fill=m26) -c4752 = mcdc.cell(+s97 & -s98 & +s285, fill=m27) -c4753 = mcdc.cell(+s98 & -s99 & -s277, fill=m18) -c4754 = mcdc.cell(+s98 & -s99 & +s277 & -s278, fill=m19) -c4755 = mcdc.cell(+s98 & -s99 & +s278 & -s279, fill=m20) -c4756 = mcdc.cell(+s98 & -s99 & +s279 & -s280, fill=m21) -c4757 = mcdc.cell(+s98 & -s99 & +s280 & -s281, fill=m22) -c4758 = mcdc.cell(+s98 & -s99 & +s281 & -s282, fill=m23) -c4759 = mcdc.cell(+s98 & -s99 & +s282 & -s283, fill=m24) -c4760 = mcdc.cell(+s98 & -s99 & +s283 & -s284, fill=m25) -c4761 = mcdc.cell(+s98 & -s99 & +s284 & -s285, fill=m26) -c4762 = mcdc.cell(+s98 & -s99 & +s285, fill=m27) -c4763 = mcdc.cell(+s99 & -s100 & -s277, fill=m18) -c4764 = mcdc.cell(+s99 & -s100 & +s277 & -s278, fill=m19) -c4765 = mcdc.cell(+s99 & -s100 & +s278 & -s279, fill=m20) -c4766 = mcdc.cell(+s99 & -s100 & +s279 & -s280, fill=m21) -c4767 = mcdc.cell(+s99 & -s100 & +s280 & -s281, fill=m22) -c4768 = mcdc.cell(+s99 & -s100 & +s281 & -s282, fill=m23) -c4769 = mcdc.cell(+s99 & -s100 & +s282 & -s283, fill=m24) -c4770 = mcdc.cell(+s99 & -s100 & +s283 & -s284, fill=m25) -c4771 = mcdc.cell(+s99 & -s100 & +s284 & -s285, fill=m26) -c4772 = mcdc.cell(+s99 & -s100 & +s285, fill=m27) -c4773 = mcdc.cell(+s100 & -s101 & -s277, fill=m18) -c4774 = mcdc.cell(+s100 & -s101 & +s277 & -s278, fill=m19) -c4775 = mcdc.cell(+s100 & -s101 & +s278 & -s279, fill=m20) -c4776 = mcdc.cell(+s100 & -s101 & +s279 & -s280, fill=m21) -c4777 = mcdc.cell(+s100 & -s101 & +s280 & -s281, fill=m22) -c4778 = mcdc.cell(+s100 & -s101 & +s281 & -s282, fill=m23) -c4779 = mcdc.cell(+s100 & -s101 & +s282 & -s283, fill=m24) -c4780 = mcdc.cell(+s100 & -s101 & +s283 & -s284, fill=m25) -c4781 = mcdc.cell(+s100 & -s101 & +s284 & -s285, fill=m26) -c4782 = mcdc.cell(+s100 & -s101 & +s285, fill=m27) -c4783 = mcdc.cell(+s101 & -s102 & -s277, fill=m18) -c4784 = mcdc.cell(+s101 & -s102 & +s277 & -s278, fill=m19) -c4785 = mcdc.cell(+s101 & -s102 & +s278 & -s279, fill=m20) -c4786 = mcdc.cell(+s101 & -s102 & +s279 & -s280, fill=m21) -c4787 = mcdc.cell(+s101 & -s102 & +s280 & -s281, fill=m22) -c4788 = mcdc.cell(+s101 & -s102 & +s281 & -s282, fill=m23) -c4789 = mcdc.cell(+s101 & -s102 & +s282 & -s283, fill=m24) -c4790 = mcdc.cell(+s101 & -s102 & +s283 & -s284, fill=m25) -c4791 = mcdc.cell(+s101 & -s102 & +s284 & -s285, fill=m26) -c4792 = mcdc.cell(+s101 & -s102 & +s285, fill=m27) -c4793 = mcdc.cell(+s102 & -s103 & -s277, fill=m18) -c4794 = mcdc.cell(+s102 & -s103 & +s277 & -s278, fill=m19) -c4795 = mcdc.cell(+s102 & -s103 & +s278 & -s279, fill=m20) -c4796 = mcdc.cell(+s102 & -s103 & +s279 & -s280, fill=m21) -c4797 = mcdc.cell(+s102 & -s103 & +s280 & -s281, fill=m22) -c4798 = mcdc.cell(+s102 & -s103 & +s281 & -s282, fill=m23) -c4799 = mcdc.cell(+s102 & -s103 & +s282 & -s283, fill=m24) -c4800 = mcdc.cell(+s102 & -s103 & +s283 & -s284, fill=m25) -c4801 = mcdc.cell(+s102 & -s103 & +s284 & -s285, fill=m26) -c4802 = mcdc.cell(+s102 & -s103 & +s285, fill=m27) -c4803 = mcdc.cell(+s103 & -s104 & -s277, fill=m18) -c4804 = mcdc.cell(+s103 & -s104 & +s277 & -s278, fill=m19) -c4805 = mcdc.cell(+s103 & -s104 & +s278 & -s279, fill=m20) -c4806 = mcdc.cell(+s103 & -s104 & +s279 & -s280, fill=m21) -c4807 = mcdc.cell(+s103 & -s104 & +s280 & -s281, fill=m22) -c4808 = mcdc.cell(+s103 & -s104 & +s281 & -s282, fill=m23) -c4809 = mcdc.cell(+s103 & -s104 & +s282 & -s283, fill=m24) -c4810 = mcdc.cell(+s103 & -s104 & +s283 & -s284, fill=m25) -c4811 = mcdc.cell(+s103 & -s104 & +s284 & -s285, fill=m26) -c4812 = mcdc.cell(+s103 & -s104 & +s285, fill=m27) -c4813 = mcdc.cell(+s104 & -s105 & -s277, fill=m18) -c4814 = mcdc.cell(+s104 & -s105 & +s277 & -s278, fill=m19) -c4815 = mcdc.cell(+s104 & -s105 & +s278 & -s279, fill=m20) -c4816 = mcdc.cell(+s104 & -s105 & +s279 & -s280, fill=m21) -c4817 = mcdc.cell(+s104 & -s105 & +s280 & -s281, fill=m22) -c4818 = mcdc.cell(+s104 & -s105 & +s281 & -s282, fill=m23) -c4819 = mcdc.cell(+s104 & -s105 & +s282 & -s283, fill=m24) -c4820 = mcdc.cell(+s104 & -s105 & +s283 & -s284, fill=m25) -c4821 = mcdc.cell(+s104 & -s105 & +s284 & -s285, fill=m26) -c4822 = mcdc.cell(+s104 & -s105 & +s285, fill=m27) -c4823 = mcdc.cell(+s105 & -s106 & -s277, fill=m18) -c4824 = mcdc.cell(+s105 & -s106 & +s277 & -s278, fill=m19) -c4825 = mcdc.cell(+s105 & -s106 & +s278 & -s279, fill=m20) -c4826 = mcdc.cell(+s105 & -s106 & +s279 & -s280, fill=m21) -c4827 = mcdc.cell(+s105 & -s106 & +s280 & -s281, fill=m22) -c4828 = mcdc.cell(+s105 & -s106 & +s281 & -s282, fill=m23) -c4829 = mcdc.cell(+s105 & -s106 & +s282 & -s283, fill=m24) -c4830 = mcdc.cell(+s105 & -s106 & +s283 & -s284, fill=m25) -c4831 = mcdc.cell(+s105 & -s106 & +s284 & -s285, fill=m26) -c4832 = mcdc.cell(+s105 & -s106 & +s285, fill=m27) -c4833 = mcdc.cell(+s106 & -s107 & -s277, fill=m18) -c4834 = mcdc.cell(+s106 & -s107 & +s277 & -s278, fill=m19) -c4835 = mcdc.cell(+s106 & -s107 & +s278 & -s279, fill=m20) -c4836 = mcdc.cell(+s106 & -s107 & +s279 & -s280, fill=m21) -c4837 = mcdc.cell(+s106 & -s107 & +s280 & -s281, fill=m22) -c4838 = mcdc.cell(+s106 & -s107 & +s281 & -s282, fill=m23) -c4839 = mcdc.cell(+s106 & -s107 & +s282 & -s283, fill=m24) -c4840 = mcdc.cell(+s106 & -s107 & +s283 & -s284, fill=m25) -c4841 = mcdc.cell(+s106 & -s107 & +s284 & -s285, fill=m26) -c4842 = mcdc.cell(+s106 & -s107 & +s285, fill=m27) -c4843 = mcdc.cell(+s107 & -s108 & -s277, fill=m18) -c4844 = mcdc.cell(+s107 & -s108 & +s277 & -s278, fill=m19) -c4845 = mcdc.cell(+s107 & -s108 & +s278 & -s279, fill=m20) -c4846 = mcdc.cell(+s107 & -s108 & +s279 & -s280, fill=m21) -c4847 = mcdc.cell(+s107 & -s108 & +s280 & -s281, fill=m22) -c4848 = mcdc.cell(+s107 & -s108 & +s281 & -s282, fill=m23) -c4849 = mcdc.cell(+s107 & -s108 & +s282 & -s283, fill=m24) -c4850 = mcdc.cell(+s107 & -s108 & +s283 & -s284, fill=m25) -c4851 = mcdc.cell(+s107 & -s108 & +s284 & -s285, fill=m26) -c4852 = mcdc.cell(+s107 & -s108 & +s285, fill=m27) -c4853 = mcdc.cell(+s108 & -s109 & -s277, fill=m18) -c4854 = mcdc.cell(+s108 & -s109 & +s277 & -s278, fill=m19) -c4855 = mcdc.cell(+s108 & -s109 & +s278 & -s279, fill=m20) -c4856 = mcdc.cell(+s108 & -s109 & +s279 & -s280, fill=m21) -c4857 = mcdc.cell(+s108 & -s109 & +s280 & -s281, fill=m22) -c4858 = mcdc.cell(+s108 & -s109 & +s281 & -s282, fill=m23) -c4859 = mcdc.cell(+s108 & -s109 & +s282 & -s283, fill=m24) -c4860 = mcdc.cell(+s108 & -s109 & +s283 & -s284, fill=m25) -c4861 = mcdc.cell(+s108 & -s109 & +s284 & -s285, fill=m26) -c4862 = mcdc.cell(+s108 & -s109 & +s285, fill=m27) -c4863 = mcdc.cell(+s109 & -s110 & -s277, fill=m18) -c4864 = mcdc.cell(+s109 & -s110 & +s277 & -s278, fill=m19) -c4865 = mcdc.cell(+s109 & -s110 & +s278 & -s279, fill=m20) -c4866 = mcdc.cell(+s109 & -s110 & +s279 & -s280, fill=m21) -c4867 = mcdc.cell(+s109 & -s110 & +s280 & -s281, fill=m22) -c4868 = mcdc.cell(+s109 & -s110 & +s281 & -s282, fill=m23) -c4869 = mcdc.cell(+s109 & -s110 & +s282 & -s283, fill=m24) -c4870 = mcdc.cell(+s109 & -s110 & +s283 & -s284, fill=m25) -c4871 = mcdc.cell(+s109 & -s110 & +s284 & -s285, fill=m26) -c4872 = mcdc.cell(+s109 & -s110 & +s285, fill=m27) -c4873 = mcdc.cell(+s110 & -s111 & -s277, fill=m18) -c4874 = mcdc.cell(+s110 & -s111 & +s277 & -s278, fill=m19) -c4875 = mcdc.cell(+s110 & -s111 & +s278 & -s279, fill=m20) -c4876 = mcdc.cell(+s110 & -s111 & +s279 & -s280, fill=m21) -c4877 = mcdc.cell(+s110 & -s111 & +s280 & -s281, fill=m22) -c4878 = mcdc.cell(+s110 & -s111 & +s281 & -s282, fill=m23) -c4879 = mcdc.cell(+s110 & -s111 & +s282 & -s283, fill=m24) -c4880 = mcdc.cell(+s110 & -s111 & +s283 & -s284, fill=m25) -c4881 = mcdc.cell(+s110 & -s111 & +s284 & -s285, fill=m26) -c4882 = mcdc.cell(+s110 & -s111 & +s285, fill=m27) -c4883 = mcdc.cell(+s111 & -s112 & -s277, fill=m18) -c4884 = mcdc.cell(+s111 & -s112 & +s277 & -s278, fill=m19) -c4885 = mcdc.cell(+s111 & -s112 & +s278 & -s279, fill=m20) -c4886 = mcdc.cell(+s111 & -s112 & +s279 & -s280, fill=m21) -c4887 = mcdc.cell(+s111 & -s112 & +s280 & -s281, fill=m22) -c4888 = mcdc.cell(+s111 & -s112 & +s281 & -s282, fill=m23) -c4889 = mcdc.cell(+s111 & -s112 & +s282 & -s283, fill=m24) -c4890 = mcdc.cell(+s111 & -s112 & +s283 & -s284, fill=m25) -c4891 = mcdc.cell(+s111 & -s112 & +s284 & -s285, fill=m26) -c4892 = mcdc.cell(+s111 & -s112 & +s285, fill=m27) -c4893 = mcdc.cell(+s112 & -s113 & -s277, fill=m18) -c4894 = mcdc.cell(+s112 & -s113 & +s277 & -s278, fill=m19) -c4895 = mcdc.cell(+s112 & -s113 & +s278 & -s279, fill=m20) -c4896 = mcdc.cell(+s112 & -s113 & +s279 & -s280, fill=m21) -c4897 = mcdc.cell(+s112 & -s113 & +s280 & -s281, fill=m22) -c4898 = mcdc.cell(+s112 & -s113 & +s281 & -s282, fill=m23) -c4899 = mcdc.cell(+s112 & -s113 & +s282 & -s283, fill=m24) -c4900 = mcdc.cell(+s112 & -s113 & +s283 & -s284, fill=m25) -c4901 = mcdc.cell(+s112 & -s113 & +s284 & -s285, fill=m26) -c4902 = mcdc.cell(+s112 & -s113 & +s285, fill=m27) -c4903 = mcdc.cell(+s113 & -s114 & -s277, fill=m18) -c4904 = mcdc.cell(+s113 & -s114 & +s277 & -s278, fill=m19) -c4905 = mcdc.cell(+s113 & -s114 & +s278 & -s279, fill=m20) -c4906 = mcdc.cell(+s113 & -s114 & +s279 & -s280, fill=m21) -c4907 = mcdc.cell(+s113 & -s114 & +s280 & -s281, fill=m22) -c4908 = mcdc.cell(+s113 & -s114 & +s281 & -s282, fill=m23) -c4909 = mcdc.cell(+s113 & -s114 & +s282 & -s283, fill=m24) -c4910 = mcdc.cell(+s113 & -s114 & +s283 & -s284, fill=m25) -c4911 = mcdc.cell(+s113 & -s114 & +s284 & -s285, fill=m26) -c4912 = mcdc.cell(+s113 & -s114 & +s285, fill=m27) -c4913 = mcdc.cell(+s114 & -s115 & -s277, fill=m18) -c4914 = mcdc.cell(+s114 & -s115 & +s277 & -s278, fill=m19) -c4915 = mcdc.cell(+s114 & -s115 & +s278 & -s279, fill=m20) -c4916 = mcdc.cell(+s114 & -s115 & +s279 & -s280, fill=m21) -c4917 = mcdc.cell(+s114 & -s115 & +s280 & -s281, fill=m22) -c4918 = mcdc.cell(+s114 & -s115 & +s281 & -s282, fill=m23) -c4919 = mcdc.cell(+s114 & -s115 & +s282 & -s283, fill=m24) -c4920 = mcdc.cell(+s114 & -s115 & +s283 & -s284, fill=m25) -c4921 = mcdc.cell(+s114 & -s115 & +s284 & -s285, fill=m26) -c4922 = mcdc.cell(+s114 & -s115 & +s285, fill=m27) -c4923 = mcdc.cell(+s115 & -s116 & -s277, fill=m18) -c4924 = mcdc.cell(+s115 & -s116 & +s277 & -s278, fill=m19) -c4925 = mcdc.cell(+s115 & -s116 & +s278 & -s279, fill=m20) -c4926 = mcdc.cell(+s115 & -s116 & +s279 & -s280, fill=m21) -c4927 = mcdc.cell(+s115 & -s116 & +s280 & -s281, fill=m22) -c4928 = mcdc.cell(+s115 & -s116 & +s281 & -s282, fill=m23) -c4929 = mcdc.cell(+s115 & -s116 & +s282 & -s283, fill=m24) -c4930 = mcdc.cell(+s115 & -s116 & +s283 & -s284, fill=m25) -c4931 = mcdc.cell(+s115 & -s116 & +s284 & -s285, fill=m26) -c4932 = mcdc.cell(+s115 & -s116 & +s285, fill=m27) -c4933 = mcdc.cell(+s116 & -s117 & -s277, fill=m18) -c4934 = mcdc.cell(+s116 & -s117 & +s277 & -s278, fill=m19) -c4935 = mcdc.cell(+s116 & -s117 & +s278 & -s279, fill=m20) -c4936 = mcdc.cell(+s116 & -s117 & +s279 & -s280, fill=m21) -c4937 = mcdc.cell(+s116 & -s117 & +s280 & -s281, fill=m22) -c4938 = mcdc.cell(+s116 & -s117 & +s281 & -s282, fill=m23) -c4939 = mcdc.cell(+s116 & -s117 & +s282 & -s283, fill=m24) -c4940 = mcdc.cell(+s116 & -s117 & +s283 & -s284, fill=m25) -c4941 = mcdc.cell(+s116 & -s117 & +s284 & -s285, fill=m26) -c4942 = mcdc.cell(+s116 & -s117 & +s285, fill=m27) -c4943 = mcdc.cell(+s117 & -s118 & -s277, fill=m18) -c4944 = mcdc.cell(+s117 & -s118 & +s277 & -s278, fill=m19) -c4945 = mcdc.cell(+s117 & -s118 & +s278 & -s279, fill=m20) -c4946 = mcdc.cell(+s117 & -s118 & +s279 & -s280, fill=m21) -c4947 = mcdc.cell(+s117 & -s118 & +s280 & -s281, fill=m22) -c4948 = mcdc.cell(+s117 & -s118 & +s281 & -s282, fill=m23) -c4949 = mcdc.cell(+s117 & -s118 & +s282 & -s283, fill=m24) -c4950 = mcdc.cell(+s117 & -s118 & +s283 & -s284, fill=m25) -c4951 = mcdc.cell(+s117 & -s118 & +s284 & -s285, fill=m26) -c4952 = mcdc.cell(+s117 & -s118 & +s285, fill=m27) -c4953 = mcdc.cell(+s118 & -s119 & -s277, fill=m18) -c4954 = mcdc.cell(+s118 & -s119 & +s277 & -s278, fill=m19) -c4955 = mcdc.cell(+s118 & -s119 & +s278 & -s279, fill=m20) -c4956 = mcdc.cell(+s118 & -s119 & +s279 & -s280, fill=m21) -c4957 = mcdc.cell(+s118 & -s119 & +s280 & -s281, fill=m22) -c4958 = mcdc.cell(+s118 & -s119 & +s281 & -s282, fill=m23) -c4959 = mcdc.cell(+s118 & -s119 & +s282 & -s283, fill=m24) -c4960 = mcdc.cell(+s118 & -s119 & +s283 & -s284, fill=m25) -c4961 = mcdc.cell(+s118 & -s119 & +s284 & -s285, fill=m26) -c4962 = mcdc.cell(+s118 & -s119 & +s285, fill=m27) -c4963 = mcdc.cell(+s119 & -s120 & -s277, fill=m18) -c4964 = mcdc.cell(+s119 & -s120 & +s277 & -s278, fill=m19) -c4965 = mcdc.cell(+s119 & -s120 & +s278 & -s279, fill=m20) -c4966 = mcdc.cell(+s119 & -s120 & +s279 & -s280, fill=m21) -c4967 = mcdc.cell(+s119 & -s120 & +s280 & -s281, fill=m22) -c4968 = mcdc.cell(+s119 & -s120 & +s281 & -s282, fill=m23) -c4969 = mcdc.cell(+s119 & -s120 & +s282 & -s283, fill=m24) -c4970 = mcdc.cell(+s119 & -s120 & +s283 & -s284, fill=m25) -c4971 = mcdc.cell(+s119 & -s120 & +s284 & -s285, fill=m26) -c4972 = mcdc.cell(+s119 & -s120 & +s285, fill=m27) -c4973 = mcdc.cell(+s120 & -s121 & -s277, fill=m18) -c4974 = mcdc.cell(+s120 & -s121 & +s277 & -s278, fill=m19) -c4975 = mcdc.cell(+s120 & -s121 & +s278 & -s279, fill=m20) -c4976 = mcdc.cell(+s120 & -s121 & +s279 & -s280, fill=m21) -c4977 = mcdc.cell(+s120 & -s121 & +s280 & -s281, fill=m22) -c4978 = mcdc.cell(+s120 & -s121 & +s281 & -s282, fill=m23) -c4979 = mcdc.cell(+s120 & -s121 & +s282 & -s283, fill=m24) -c4980 = mcdc.cell(+s120 & -s121 & +s283 & -s284, fill=m25) -c4981 = mcdc.cell(+s120 & -s121 & +s284 & -s285, fill=m26) -c4982 = mcdc.cell(+s120 & -s121 & +s285, fill=m27) -c4983 = mcdc.cell(+s121 & -s122 & -s277, fill=m18) -c4984 = mcdc.cell(+s121 & -s122 & +s277 & -s278, fill=m19) -c4985 = mcdc.cell(+s121 & -s122 & +s278 & -s279, fill=m20) -c4986 = mcdc.cell(+s121 & -s122 & +s279 & -s280, fill=m21) -c4987 = mcdc.cell(+s121 & -s122 & +s280 & -s281, fill=m22) -c4988 = mcdc.cell(+s121 & -s122 & +s281 & -s282, fill=m23) -c4989 = mcdc.cell(+s121 & -s122 & +s282 & -s283, fill=m24) -c4990 = mcdc.cell(+s121 & -s122 & +s283 & -s284, fill=m25) -c4991 = mcdc.cell(+s121 & -s122 & +s284 & -s285, fill=m26) -c4992 = mcdc.cell(+s121 & -s122 & +s285, fill=m27) -c4993 = mcdc.cell(+s122 & -s123 & -s277, fill=m18) -c4994 = mcdc.cell(+s122 & -s123 & +s277 & -s278, fill=m19) -c4995 = mcdc.cell(+s122 & -s123 & +s278 & -s279, fill=m20) -c4996 = mcdc.cell(+s122 & -s123 & +s279 & -s280, fill=m21) -c4997 = mcdc.cell(+s122 & -s123 & +s280 & -s281, fill=m22) -c4998 = mcdc.cell(+s122 & -s123 & +s281 & -s282, fill=m23) -c4999 = mcdc.cell(+s122 & -s123 & +s282 & -s283, fill=m24) -c5000 = mcdc.cell(+s122 & -s123 & +s283 & -s284, fill=m25) -c5001 = mcdc.cell(+s122 & -s123 & +s284 & -s285, fill=m26) -c5002 = mcdc.cell(+s122 & -s123 & +s285, fill=m27) -c5003 = mcdc.cell(+s123 & -s124 & -s277, fill=m18) -c5004 = mcdc.cell(+s123 & -s124 & +s277 & -s278, fill=m19) -c5005 = mcdc.cell(+s123 & -s124 & +s278 & -s279, fill=m20) -c5006 = mcdc.cell(+s123 & -s124 & +s279 & -s280, fill=m21) -c5007 = mcdc.cell(+s123 & -s124 & +s280 & -s281, fill=m22) -c5008 = mcdc.cell(+s123 & -s124 & +s281 & -s282, fill=m23) -c5009 = mcdc.cell(+s123 & -s124 & +s282 & -s283, fill=m24) -c5010 = mcdc.cell(+s123 & -s124 & +s283 & -s284, fill=m25) -c5011 = mcdc.cell(+s123 & -s124 & +s284 & -s285, fill=m26) -c5012 = mcdc.cell(+s123 & -s124 & +s285, fill=m27) -c5013 = mcdc.cell(+s124 & -s125 & -s277, fill=m18) -c5014 = mcdc.cell(+s124 & -s125 & +s277 & -s278, fill=m19) -c5015 = mcdc.cell(+s124 & -s125 & +s278 & -s279, fill=m20) -c5016 = mcdc.cell(+s124 & -s125 & +s279 & -s280, fill=m21) -c5017 = mcdc.cell(+s124 & -s125 & +s280 & -s281, fill=m22) -c5018 = mcdc.cell(+s124 & -s125 & +s281 & -s282, fill=m23) -c5019 = mcdc.cell(+s124 & -s125 & +s282 & -s283, fill=m24) -c5020 = mcdc.cell(+s124 & -s125 & +s283 & -s284, fill=m25) -c5021 = mcdc.cell(+s124 & -s125 & +s284 & -s285, fill=m26) -c5022 = mcdc.cell(+s124 & -s125 & +s285, fill=m27) -c5023 = mcdc.cell(+s125 & -s126 & -s277, fill=m18) -c5024 = mcdc.cell(+s125 & -s126 & +s277 & -s278, fill=m19) -c5025 = mcdc.cell(+s125 & -s126 & +s278 & -s279, fill=m20) -c5026 = mcdc.cell(+s125 & -s126 & +s279 & -s280, fill=m21) -c5027 = mcdc.cell(+s125 & -s126 & +s280 & -s281, fill=m22) -c5028 = mcdc.cell(+s125 & -s126 & +s281 & -s282, fill=m23) -c5029 = mcdc.cell(+s125 & -s126 & +s282 & -s283, fill=m24) -c5030 = mcdc.cell(+s125 & -s126 & +s283 & -s284, fill=m25) -c5031 = mcdc.cell(+s125 & -s126 & +s284 & -s285, fill=m26) -c5032 = mcdc.cell(+s125 & -s126 & +s285, fill=m27) -c5033 = mcdc.cell(+s126 & -s127 & -s277, fill=m18) -c5034 = mcdc.cell(+s126 & -s127 & +s277 & -s278, fill=m19) -c5035 = mcdc.cell(+s126 & -s127 & +s278 & -s279, fill=m20) -c5036 = mcdc.cell(+s126 & -s127 & +s279 & -s280, fill=m21) -c5037 = mcdc.cell(+s126 & -s127 & +s280 & -s281, fill=m22) -c5038 = mcdc.cell(+s126 & -s127 & +s281 & -s282, fill=m23) -c5039 = mcdc.cell(+s126 & -s127 & +s282 & -s283, fill=m24) -c5040 = mcdc.cell(+s126 & -s127 & +s283 & -s284, fill=m25) -c5041 = mcdc.cell(+s126 & -s127 & +s284 & -s285, fill=m26) -c5042 = mcdc.cell(+s126 & -s127 & +s285, fill=m27) -c5043 = mcdc.cell(+s127 & -s128 & -s277, fill=m18) -c5044 = mcdc.cell(+s127 & -s128 & +s277 & -s278, fill=m19) -c5045 = mcdc.cell(+s127 & -s128 & +s278 & -s279, fill=m20) -c5046 = mcdc.cell(+s127 & -s128 & +s279 & -s280, fill=m21) -c5047 = mcdc.cell(+s127 & -s128 & +s280 & -s281, fill=m22) -c5048 = mcdc.cell(+s127 & -s128 & +s281 & -s282, fill=m23) -c5049 = mcdc.cell(+s127 & -s128 & +s282 & -s283, fill=m24) -c5050 = mcdc.cell(+s127 & -s128 & +s283 & -s284, fill=m25) -c5051 = mcdc.cell(+s127 & -s128 & +s284 & -s285, fill=m26) -c5052 = mcdc.cell(+s127 & -s128 & +s285, fill=m27) -c5053 = mcdc.cell(+s128 & -s129 & -s277, fill=m18) -c5054 = mcdc.cell(+s128 & -s129 & +s277 & -s278, fill=m19) -c5055 = mcdc.cell(+s128 & -s129 & +s278 & -s279, fill=m20) -c5056 = mcdc.cell(+s128 & -s129 & +s279 & -s280, fill=m21) -c5057 = mcdc.cell(+s128 & -s129 & +s280 & -s281, fill=m22) -c5058 = mcdc.cell(+s128 & -s129 & +s281 & -s282, fill=m23) -c5059 = mcdc.cell(+s128 & -s129 & +s282 & -s283, fill=m24) -c5060 = mcdc.cell(+s128 & -s129 & +s283 & -s284, fill=m25) -c5061 = mcdc.cell(+s128 & -s129 & +s284 & -s285, fill=m26) -c5062 = mcdc.cell(+s128 & -s129 & +s285, fill=m27) -c5063 = mcdc.cell(+s129 & -s130 & -s277, fill=m18) -c5064 = mcdc.cell(+s129 & -s130 & +s277 & -s278, fill=m19) -c5065 = mcdc.cell(+s129 & -s130 & +s278 & -s279, fill=m20) -c5066 = mcdc.cell(+s129 & -s130 & +s279 & -s280, fill=m21) -c5067 = mcdc.cell(+s129 & -s130 & +s280 & -s281, fill=m22) -c5068 = mcdc.cell(+s129 & -s130 & +s281 & -s282, fill=m23) -c5069 = mcdc.cell(+s129 & -s130 & +s282 & -s283, fill=m24) -c5070 = mcdc.cell(+s129 & -s130 & +s283 & -s284, fill=m25) -c5071 = mcdc.cell(+s129 & -s130 & +s284 & -s285, fill=m26) -c5072 = mcdc.cell(+s129 & -s130 & +s285, fill=m27) -c5073 = mcdc.cell(+s130 & -s131 & -s277, fill=m18) -c5074 = mcdc.cell(+s130 & -s131 & +s277 & -s278, fill=m19) -c5075 = mcdc.cell(+s130 & -s131 & +s278 & -s279, fill=m20) -c5076 = mcdc.cell(+s130 & -s131 & +s279 & -s280, fill=m21) -c5077 = mcdc.cell(+s130 & -s131 & +s280 & -s281, fill=m22) -c5078 = mcdc.cell(+s130 & -s131 & +s281 & -s282, fill=m23) -c5079 = mcdc.cell(+s130 & -s131 & +s282 & -s283, fill=m24) -c5080 = mcdc.cell(+s130 & -s131 & +s283 & -s284, fill=m25) -c5081 = mcdc.cell(+s130 & -s131 & +s284 & -s285, fill=m26) -c5082 = mcdc.cell(+s130 & -s131 & +s285, fill=m27) -c5083 = mcdc.cell(+s131 & -s132 & -s277, fill=m18) -c5084 = mcdc.cell(+s131 & -s132 & +s277 & -s278, fill=m19) -c5085 = mcdc.cell(+s131 & -s132 & +s278 & -s279, fill=m20) -c5086 = mcdc.cell(+s131 & -s132 & +s279 & -s280, fill=m21) -c5087 = mcdc.cell(+s131 & -s132 & +s280 & -s281, fill=m22) -c5088 = mcdc.cell(+s131 & -s132 & +s281 & -s282, fill=m23) -c5089 = mcdc.cell(+s131 & -s132 & +s282 & -s283, fill=m24) -c5090 = mcdc.cell(+s131 & -s132 & +s283 & -s284, fill=m25) -c5091 = mcdc.cell(+s131 & -s132 & +s284 & -s285, fill=m26) -c5092 = mcdc.cell(+s131 & -s132 & +s285, fill=m27) -c5093 = mcdc.cell(+s132 & -s133 & -s277, fill=m18) -c5094 = mcdc.cell(+s132 & -s133 & +s277 & -s278, fill=m19) -c5095 = mcdc.cell(+s132 & -s133 & +s278 & -s279, fill=m20) -c5096 = mcdc.cell(+s132 & -s133 & +s279 & -s280, fill=m21) -c5097 = mcdc.cell(+s132 & -s133 & +s280 & -s281, fill=m22) -c5098 = mcdc.cell(+s132 & -s133 & +s281 & -s282, fill=m23) -c5099 = mcdc.cell(+s132 & -s133 & +s282 & -s283, fill=m24) -c5100 = mcdc.cell(+s132 & -s133 & +s283 & -s284, fill=m25) -c5101 = mcdc.cell(+s132 & -s133 & +s284 & -s285, fill=m26) -c5102 = mcdc.cell(+s132 & -s133 & +s285, fill=m27) -c5103 = mcdc.cell(+s133 & -s134 & -s277, fill=m18) -c5104 = mcdc.cell(+s133 & -s134 & +s277 & -s278, fill=m19) -c5105 = mcdc.cell(+s133 & -s134 & +s278 & -s279, fill=m20) -c5106 = mcdc.cell(+s133 & -s134 & +s279 & -s280, fill=m21) -c5107 = mcdc.cell(+s133 & -s134 & +s280 & -s281, fill=m22) -c5108 = mcdc.cell(+s133 & -s134 & +s281 & -s282, fill=m23) -c5109 = mcdc.cell(+s133 & -s134 & +s282 & -s283, fill=m24) -c5110 = mcdc.cell(+s133 & -s134 & +s283 & -s284, fill=m25) -c5111 = mcdc.cell(+s133 & -s134 & +s284 & -s285, fill=m26) -c5112 = mcdc.cell(+s133 & -s134 & +s285, fill=m27) -c5113 = mcdc.cell(+s134 & -s135 & -s277, fill=m18) -c5114 = mcdc.cell(+s134 & -s135 & +s277 & -s278, fill=m19) -c5115 = mcdc.cell(+s134 & -s135 & +s278 & -s279, fill=m20) -c5116 = mcdc.cell(+s134 & -s135 & +s279 & -s280, fill=m21) -c5117 = mcdc.cell(+s134 & -s135 & +s280 & -s281, fill=m22) -c5118 = mcdc.cell(+s134 & -s135 & +s281 & -s282, fill=m23) -c5119 = mcdc.cell(+s134 & -s135 & +s282 & -s283, fill=m24) -c5120 = mcdc.cell(+s134 & -s135 & +s283 & -s284, fill=m25) -c5121 = mcdc.cell(+s134 & -s135 & +s284 & -s285, fill=m26) -c5122 = mcdc.cell(+s134 & -s135 & +s285, fill=m27) -c5123 = mcdc.cell(+s135 & -s136 & -s277, fill=m18) -c5124 = mcdc.cell(+s135 & -s136 & +s277 & -s278, fill=m19) -c5125 = mcdc.cell(+s135 & -s136 & +s278 & -s279, fill=m20) -c5126 = mcdc.cell(+s135 & -s136 & +s279 & -s280, fill=m21) -c5127 = mcdc.cell(+s135 & -s136 & +s280 & -s281, fill=m22) -c5128 = mcdc.cell(+s135 & -s136 & +s281 & -s282, fill=m23) -c5129 = mcdc.cell(+s135 & -s136 & +s282 & -s283, fill=m24) -c5130 = mcdc.cell(+s135 & -s136 & +s283 & -s284, fill=m25) -c5131 = mcdc.cell(+s135 & -s136 & +s284 & -s285, fill=m26) -c5132 = mcdc.cell(+s135 & -s136 & +s285, fill=m27) -c5133 = mcdc.cell(+s136 & -s137 & -s277, fill=m18) -c5134 = mcdc.cell(+s136 & -s137 & +s277 & -s278, fill=m19) -c5135 = mcdc.cell(+s136 & -s137 & +s278 & -s279, fill=m20) -c5136 = mcdc.cell(+s136 & -s137 & +s279 & -s280, fill=m21) -c5137 = mcdc.cell(+s136 & -s137 & +s280 & -s281, fill=m22) -c5138 = mcdc.cell(+s136 & -s137 & +s281 & -s282, fill=m23) -c5139 = mcdc.cell(+s136 & -s137 & +s282 & -s283, fill=m24) -c5140 = mcdc.cell(+s136 & -s137 & +s283 & -s284, fill=m25) -c5141 = mcdc.cell(+s136 & -s137 & +s284 & -s285, fill=m26) -c5142 = mcdc.cell(+s136 & -s137 & +s285, fill=m27) -c5143 = mcdc.cell(+s137 & -s138 & -s277, fill=m18) -c5144 = mcdc.cell(+s137 & -s138 & +s277 & -s278, fill=m19) -c5145 = mcdc.cell(+s137 & -s138 & +s278 & -s279, fill=m20) -c5146 = mcdc.cell(+s137 & -s138 & +s279 & -s280, fill=m21) -c5147 = mcdc.cell(+s137 & -s138 & +s280 & -s281, fill=m22) -c5148 = mcdc.cell(+s137 & -s138 & +s281 & -s282, fill=m23) -c5149 = mcdc.cell(+s137 & -s138 & +s282 & -s283, fill=m24) -c5150 = mcdc.cell(+s137 & -s138 & +s283 & -s284, fill=m25) -c5151 = mcdc.cell(+s137 & -s138 & +s284 & -s285, fill=m26) -c5152 = mcdc.cell(+s137 & -s138 & +s285, fill=m27) -c5153 = mcdc.cell(+s138 & -s139 & -s277, fill=m18) -c5154 = mcdc.cell(+s138 & -s139 & +s277 & -s278, fill=m19) -c5155 = mcdc.cell(+s138 & -s139 & +s278 & -s279, fill=m20) -c5156 = mcdc.cell(+s138 & -s139 & +s279 & -s280, fill=m21) -c5157 = mcdc.cell(+s138 & -s139 & +s280 & -s281, fill=m22) -c5158 = mcdc.cell(+s138 & -s139 & +s281 & -s282, fill=m23) -c5159 = mcdc.cell(+s138 & -s139 & +s282 & -s283, fill=m24) -c5160 = mcdc.cell(+s138 & -s139 & +s283 & -s284, fill=m25) -c5161 = mcdc.cell(+s138 & -s139 & +s284 & -s285, fill=m26) -c5162 = mcdc.cell(+s138 & -s139 & +s285, fill=m27) -c5163 = mcdc.cell(+s139 & -s140 & -s277, fill=m18) -c5164 = mcdc.cell(+s139 & -s140 & +s277 & -s278, fill=m19) -c5165 = mcdc.cell(+s139 & -s140 & +s278 & -s279, fill=m20) -c5166 = mcdc.cell(+s139 & -s140 & +s279 & -s280, fill=m21) -c5167 = mcdc.cell(+s139 & -s140 & +s280 & -s281, fill=m22) -c5168 = mcdc.cell(+s139 & -s140 & +s281 & -s282, fill=m23) -c5169 = mcdc.cell(+s139 & -s140 & +s282 & -s283, fill=m24) -c5170 = mcdc.cell(+s139 & -s140 & +s283 & -s284, fill=m25) -c5171 = mcdc.cell(+s139 & -s140 & +s284 & -s285, fill=m26) -c5172 = mcdc.cell(+s139 & -s140 & +s285, fill=m27) -c5173 = mcdc.cell(+s140 & -s141 & -s277, fill=m18) -c5174 = mcdc.cell(+s140 & -s141 & +s277 & -s278, fill=m19) -c5175 = mcdc.cell(+s140 & -s141 & +s278 & -s279, fill=m20) -c5176 = mcdc.cell(+s140 & -s141 & +s279 & -s280, fill=m21) -c5177 = mcdc.cell(+s140 & -s141 & +s280 & -s281, fill=m22) -c5178 = mcdc.cell(+s140 & -s141 & +s281 & -s282, fill=m23) -c5179 = mcdc.cell(+s140 & -s141 & +s282 & -s283, fill=m24) -c5180 = mcdc.cell(+s140 & -s141 & +s283 & -s284, fill=m25) -c5181 = mcdc.cell(+s140 & -s141 & +s284 & -s285, fill=m26) -c5182 = mcdc.cell(+s140 & -s141 & +s285, fill=m27) -c5183 = mcdc.cell(+s141 & -s142 & -s277, fill=m18) -c5184 = mcdc.cell(+s141 & -s142 & +s277 & -s278, fill=m19) -c5185 = mcdc.cell(+s141 & -s142 & +s278 & -s279, fill=m20) -c5186 = mcdc.cell(+s141 & -s142 & +s279 & -s280, fill=m21) -c5187 = mcdc.cell(+s141 & -s142 & +s280 & -s281, fill=m22) -c5188 = mcdc.cell(+s141 & -s142 & +s281 & -s282, fill=m23) -c5189 = mcdc.cell(+s141 & -s142 & +s282 & -s283, fill=m24) -c5190 = mcdc.cell(+s141 & -s142 & +s283 & -s284, fill=m25) -c5191 = mcdc.cell(+s141 & -s142 & +s284 & -s285, fill=m26) -c5192 = mcdc.cell(+s141 & -s142 & +s285, fill=m27) -c5193 = mcdc.cell(+s142 & -s143 & -s277, fill=m18) -c5194 = mcdc.cell(+s142 & -s143 & +s277 & -s278, fill=m19) -c5195 = mcdc.cell(+s142 & -s143 & +s278 & -s279, fill=m20) -c5196 = mcdc.cell(+s142 & -s143 & +s279 & -s280, fill=m21) -c5197 = mcdc.cell(+s142 & -s143 & +s280 & -s281, fill=m22) -c5198 = mcdc.cell(+s142 & -s143 & +s281 & -s282, fill=m23) -c5199 = mcdc.cell(+s142 & -s143 & +s282 & -s283, fill=m24) -c5200 = mcdc.cell(+s142 & -s143 & +s283 & -s284, fill=m25) -c5201 = mcdc.cell(+s142 & -s143 & +s284 & -s285, fill=m26) -c5202 = mcdc.cell(+s142 & -s143 & +s285, fill=m27) -c5203 = mcdc.cell(+s143 & -s144 & -s277, fill=m18) -c5204 = mcdc.cell(+s143 & -s144 & +s277 & -s278, fill=m19) -c5205 = mcdc.cell(+s143 & -s144 & +s278 & -s279, fill=m20) -c5206 = mcdc.cell(+s143 & -s144 & +s279 & -s280, fill=m21) -c5207 = mcdc.cell(+s143 & -s144 & +s280 & -s281, fill=m22) -c5208 = mcdc.cell(+s143 & -s144 & +s281 & -s282, fill=m23) -c5209 = mcdc.cell(+s143 & -s144 & +s282 & -s283, fill=m24) -c5210 = mcdc.cell(+s143 & -s144 & +s283 & -s284, fill=m25) -c5211 = mcdc.cell(+s143 & -s144 & +s284 & -s285, fill=m26) -c5212 = mcdc.cell(+s143 & -s144 & +s285, fill=m27) -c5213 = mcdc.cell(+s144 & -s145 & -s277, fill=m18) -c5214 = mcdc.cell(+s144 & -s145 & +s277 & -s278, fill=m19) -c5215 = mcdc.cell(+s144 & -s145 & +s278 & -s279, fill=m20) -c5216 = mcdc.cell(+s144 & -s145 & +s279 & -s280, fill=m21) -c5217 = mcdc.cell(+s144 & -s145 & +s280 & -s281, fill=m22) -c5218 = mcdc.cell(+s144 & -s145 & +s281 & -s282, fill=m23) -c5219 = mcdc.cell(+s144 & -s145 & +s282 & -s283, fill=m24) -c5220 = mcdc.cell(+s144 & -s145 & +s283 & -s284, fill=m25) -c5221 = mcdc.cell(+s144 & -s145 & +s284 & -s285, fill=m26) -c5222 = mcdc.cell(+s144 & -s145 & +s285, fill=m27) -c5223 = mcdc.cell(+s145 & -s146 & -s277, fill=m18) -c5224 = mcdc.cell(+s145 & -s146 & +s277 & -s278, fill=m19) -c5225 = mcdc.cell(+s145 & -s146 & +s278 & -s279, fill=m20) -c5226 = mcdc.cell(+s145 & -s146 & +s279 & -s280, fill=m21) -c5227 = mcdc.cell(+s145 & -s146 & +s280 & -s281, fill=m22) -c5228 = mcdc.cell(+s145 & -s146 & +s281 & -s282, fill=m23) -c5229 = mcdc.cell(+s145 & -s146 & +s282 & -s283, fill=m24) -c5230 = mcdc.cell(+s145 & -s146 & +s283 & -s284, fill=m25) -c5231 = mcdc.cell(+s145 & -s146 & +s284 & -s285, fill=m26) -c5232 = mcdc.cell(+s145 & -s146 & +s285, fill=m27) -c5233 = mcdc.cell(+s146 & -s147 & -s277, fill=m18) -c5234 = mcdc.cell(+s146 & -s147 & +s277 & -s278, fill=m19) -c5235 = mcdc.cell(+s146 & -s147 & +s278 & -s279, fill=m20) -c5236 = mcdc.cell(+s146 & -s147 & +s279 & -s280, fill=m21) -c5237 = mcdc.cell(+s146 & -s147 & +s280 & -s281, fill=m22) -c5238 = mcdc.cell(+s146 & -s147 & +s281 & -s282, fill=m23) -c5239 = mcdc.cell(+s146 & -s147 & +s282 & -s283, fill=m24) -c5240 = mcdc.cell(+s146 & -s147 & +s283 & -s284, fill=m25) -c5241 = mcdc.cell(+s146 & -s147 & +s284 & -s285, fill=m26) -c5242 = mcdc.cell(+s146 & -s147 & +s285, fill=m27) -c5243 = mcdc.cell(+s147 & -s148 & -s277, fill=m18) -c5244 = mcdc.cell(+s147 & -s148 & +s277 & -s278, fill=m19) -c5245 = mcdc.cell(+s147 & -s148 & +s278 & -s279, fill=m20) -c5246 = mcdc.cell(+s147 & -s148 & +s279 & -s280, fill=m21) -c5247 = mcdc.cell(+s147 & -s148 & +s280 & -s281, fill=m22) -c5248 = mcdc.cell(+s147 & -s148 & +s281 & -s282, fill=m23) -c5249 = mcdc.cell(+s147 & -s148 & +s282 & -s283, fill=m24) -c5250 = mcdc.cell(+s147 & -s148 & +s283 & -s284, fill=m25) -c5251 = mcdc.cell(+s147 & -s148 & +s284 & -s285, fill=m26) -c5252 = mcdc.cell(+s147 & -s148 & +s285, fill=m27) -c5253 = mcdc.cell(+s148 & -s149 & -s277, fill=m18) -c5254 = mcdc.cell(+s148 & -s149 & +s277 & -s278, fill=m19) -c5255 = mcdc.cell(+s148 & -s149 & +s278 & -s279, fill=m20) -c5256 = mcdc.cell(+s148 & -s149 & +s279 & -s280, fill=m21) -c5257 = mcdc.cell(+s148 & -s149 & +s280 & -s281, fill=m22) -c5258 = mcdc.cell(+s148 & -s149 & +s281 & -s282, fill=m23) -c5259 = mcdc.cell(+s148 & -s149 & +s282 & -s283, fill=m24) -c5260 = mcdc.cell(+s148 & -s149 & +s283 & -s284, fill=m25) -c5261 = mcdc.cell(+s148 & -s149 & +s284 & -s285, fill=m26) -c5262 = mcdc.cell(+s148 & -s149 & +s285, fill=m27) -c5263 = mcdc.cell(+s149 & -s150 & -s277, fill=m18) -c5264 = mcdc.cell(+s149 & -s150 & +s277 & -s278, fill=m19) -c5265 = mcdc.cell(+s149 & -s150 & +s278 & -s279, fill=m20) -c5266 = mcdc.cell(+s149 & -s150 & +s279 & -s280, fill=m21) -c5267 = mcdc.cell(+s149 & -s150 & +s280 & -s281, fill=m22) -c5268 = mcdc.cell(+s149 & -s150 & +s281 & -s282, fill=m23) -c5269 = mcdc.cell(+s149 & -s150 & +s282 & -s283, fill=m24) -c5270 = mcdc.cell(+s149 & -s150 & +s283 & -s284, fill=m25) -c5271 = mcdc.cell(+s149 & -s150 & +s284 & -s285, fill=m26) -c5272 = mcdc.cell(+s149 & -s150 & +s285, fill=m27) -c5273 = mcdc.cell(+s150 & -s151 & -s277, fill=m18) -c5274 = mcdc.cell(+s150 & -s151 & +s277 & -s278, fill=m19) -c5275 = mcdc.cell(+s150 & -s151 & +s278 & -s279, fill=m20) -c5276 = mcdc.cell(+s150 & -s151 & +s279 & -s280, fill=m21) -c5277 = mcdc.cell(+s150 & -s151 & +s280 & -s281, fill=m22) -c5278 = mcdc.cell(+s150 & -s151 & +s281 & -s282, fill=m23) -c5279 = mcdc.cell(+s150 & -s151 & +s282 & -s283, fill=m24) -c5280 = mcdc.cell(+s150 & -s151 & +s283 & -s284, fill=m25) -c5281 = mcdc.cell(+s150 & -s151 & +s284 & -s285, fill=m26) -c5282 = mcdc.cell(+s150 & -s151 & +s285, fill=m27) -c5283 = mcdc.cell(+s151 & -s152 & -s277, fill=m18) -c5284 = mcdc.cell(+s151 & -s152 & +s277 & -s278, fill=m19) -c5285 = mcdc.cell(+s151 & -s152 & +s278 & -s279, fill=m20) -c5286 = mcdc.cell(+s151 & -s152 & +s279 & -s280, fill=m21) -c5287 = mcdc.cell(+s151 & -s152 & +s280 & -s281, fill=m22) -c5288 = mcdc.cell(+s151 & -s152 & +s281 & -s282, fill=m23) -c5289 = mcdc.cell(+s151 & -s152 & +s282 & -s283, fill=m24) -c5290 = mcdc.cell(+s151 & -s152 & +s283 & -s284, fill=m25) -c5291 = mcdc.cell(+s151 & -s152 & +s284 & -s285, fill=m26) -c5292 = mcdc.cell(+s151 & -s152 & +s285, fill=m27) -c5293 = mcdc.cell(+s152 & -s153 & -s277, fill=m18) -c5294 = mcdc.cell(+s152 & -s153 & +s277 & -s278, fill=m19) -c5295 = mcdc.cell(+s152 & -s153 & +s278 & -s279, fill=m20) -c5296 = mcdc.cell(+s152 & -s153 & +s279 & -s280, fill=m21) -c5297 = mcdc.cell(+s152 & -s153 & +s280 & -s281, fill=m22) -c5298 = mcdc.cell(+s152 & -s153 & +s281 & -s282, fill=m23) -c5299 = mcdc.cell(+s152 & -s153 & +s282 & -s283, fill=m24) -c5300 = mcdc.cell(+s152 & -s153 & +s283 & -s284, fill=m25) -c5301 = mcdc.cell(+s152 & -s153 & +s284 & -s285, fill=m26) -c5302 = mcdc.cell(+s152 & -s153 & +s285, fill=m27) -c5303 = mcdc.cell(+s153 & -s154 & -s277, fill=m18) -c5304 = mcdc.cell(+s153 & -s154 & +s277 & -s278, fill=m19) -c5305 = mcdc.cell(+s153 & -s154 & +s278 & -s279, fill=m20) -c5306 = mcdc.cell(+s153 & -s154 & +s279 & -s280, fill=m21) -c5307 = mcdc.cell(+s153 & -s154 & +s280 & -s281, fill=m22) -c5308 = mcdc.cell(+s153 & -s154 & +s281 & -s282, fill=m23) -c5309 = mcdc.cell(+s153 & -s154 & +s282 & -s283, fill=m24) -c5310 = mcdc.cell(+s153 & -s154 & +s283 & -s284, fill=m25) -c5311 = mcdc.cell(+s153 & -s154 & +s284 & -s285, fill=m26) -c5312 = mcdc.cell(+s153 & -s154 & +s285, fill=m27) -c5313 = mcdc.cell(+s154 & -s155 & -s277, fill=m18) -c5314 = mcdc.cell(+s154 & -s155 & +s277 & -s278, fill=m19) -c5315 = mcdc.cell(+s154 & -s155 & +s278 & -s279, fill=m20) -c5316 = mcdc.cell(+s154 & -s155 & +s279 & -s280, fill=m21) -c5317 = mcdc.cell(+s154 & -s155 & +s280 & -s281, fill=m22) -c5318 = mcdc.cell(+s154 & -s155 & +s281 & -s282, fill=m23) -c5319 = mcdc.cell(+s154 & -s155 & +s282 & -s283, fill=m24) -c5320 = mcdc.cell(+s154 & -s155 & +s283 & -s284, fill=m25) -c5321 = mcdc.cell(+s154 & -s155 & +s284 & -s285, fill=m26) -c5322 = mcdc.cell(+s154 & -s155 & +s285, fill=m27) -c5323 = mcdc.cell(+s155 & -s156 & -s277, fill=m18) -c5324 = mcdc.cell(+s155 & -s156 & +s277 & -s278, fill=m19) -c5325 = mcdc.cell(+s155 & -s156 & +s278 & -s279, fill=m20) -c5326 = mcdc.cell(+s155 & -s156 & +s279 & -s280, fill=m21) -c5327 = mcdc.cell(+s155 & -s156 & +s280 & -s281, fill=m22) -c5328 = mcdc.cell(+s155 & -s156 & +s281 & -s282, fill=m23) -c5329 = mcdc.cell(+s155 & -s156 & +s282 & -s283, fill=m24) -c5330 = mcdc.cell(+s155 & -s156 & +s283 & -s284, fill=m25) -c5331 = mcdc.cell(+s155 & -s156 & +s284 & -s285, fill=m26) -c5332 = mcdc.cell(+s155 & -s156 & +s285, fill=m27) -c5333 = mcdc.cell(+s156 & -s157 & -s277, fill=m18) -c5334 = mcdc.cell(+s156 & -s157 & +s277 & -s278, fill=m19) -c5335 = mcdc.cell(+s156 & -s157 & +s278 & -s279, fill=m20) -c5336 = mcdc.cell(+s156 & -s157 & +s279 & -s280, fill=m21) -c5337 = mcdc.cell(+s156 & -s157 & +s280 & -s281, fill=m22) -c5338 = mcdc.cell(+s156 & -s157 & +s281 & -s282, fill=m23) -c5339 = mcdc.cell(+s156 & -s157 & +s282 & -s283, fill=m24) -c5340 = mcdc.cell(+s156 & -s157 & +s283 & -s284, fill=m25) -c5341 = mcdc.cell(+s156 & -s157 & +s284 & -s285, fill=m26) -c5342 = mcdc.cell(+s156 & -s157 & +s285, fill=m27) -c5343 = mcdc.cell(+s157 & -s158 & -s277, fill=m18) -c5344 = mcdc.cell(+s157 & -s158 & +s277 & -s278, fill=m19) -c5345 = mcdc.cell(+s157 & -s158 & +s278 & -s279, fill=m20) -c5346 = mcdc.cell(+s157 & -s158 & +s279 & -s280, fill=m21) -c5347 = mcdc.cell(+s157 & -s158 & +s280 & -s281, fill=m22) -c5348 = mcdc.cell(+s157 & -s158 & +s281 & -s282, fill=m23) -c5349 = mcdc.cell(+s157 & -s158 & +s282 & -s283, fill=m24) -c5350 = mcdc.cell(+s157 & -s158 & +s283 & -s284, fill=m25) -c5351 = mcdc.cell(+s157 & -s158 & +s284 & -s285, fill=m26) -c5352 = mcdc.cell(+s157 & -s158 & +s285, fill=m27) -c5353 = mcdc.cell(+s158 & -s159 & -s277, fill=m18) -c5354 = mcdc.cell(+s158 & -s159 & +s277 & -s278, fill=m19) -c5355 = mcdc.cell(+s158 & -s159 & +s278 & -s279, fill=m20) -c5356 = mcdc.cell(+s158 & -s159 & +s279 & -s280, fill=m21) -c5357 = mcdc.cell(+s158 & -s159 & +s280 & -s281, fill=m22) -c5358 = mcdc.cell(+s158 & -s159 & +s281 & -s282, fill=m23) -c5359 = mcdc.cell(+s158 & -s159 & +s282 & -s283, fill=m24) -c5360 = mcdc.cell(+s158 & -s159 & +s283 & -s284, fill=m25) -c5361 = mcdc.cell(+s158 & -s159 & +s284 & -s285, fill=m26) -c5362 = mcdc.cell(+s158 & -s159 & +s285, fill=m27) -c5363 = mcdc.cell(+s159 & -s160 & -s277, fill=m18) -c5364 = mcdc.cell(+s159 & -s160 & +s277 & -s278, fill=m19) -c5365 = mcdc.cell(+s159 & -s160 & +s278 & -s279, fill=m20) -c5366 = mcdc.cell(+s159 & -s160 & +s279 & -s280, fill=m21) -c5367 = mcdc.cell(+s159 & -s160 & +s280 & -s281, fill=m22) -c5368 = mcdc.cell(+s159 & -s160 & +s281 & -s282, fill=m23) -c5369 = mcdc.cell(+s159 & -s160 & +s282 & -s283, fill=m24) -c5370 = mcdc.cell(+s159 & -s160 & +s283 & -s284, fill=m25) -c5371 = mcdc.cell(+s159 & -s160 & +s284 & -s285, fill=m26) -c5372 = mcdc.cell(+s159 & -s160 & +s285, fill=m27) -c5373 = mcdc.cell(+s160 & -s161 & -s277, fill=m18) -c5374 = mcdc.cell(+s160 & -s161 & +s277 & -s278, fill=m19) -c5375 = mcdc.cell(+s160 & -s161 & +s278 & -s279, fill=m20) -c5376 = mcdc.cell(+s160 & -s161 & +s279 & -s280, fill=m21) -c5377 = mcdc.cell(+s160 & -s161 & +s280 & -s281, fill=m22) -c5378 = mcdc.cell(+s160 & -s161 & +s281 & -s282, fill=m23) -c5379 = mcdc.cell(+s160 & -s161 & +s282 & -s283, fill=m24) -c5380 = mcdc.cell(+s160 & -s161 & +s283 & -s284, fill=m25) -c5381 = mcdc.cell(+s160 & -s161 & +s284 & -s285, fill=m26) -c5382 = mcdc.cell(+s160 & -s161 & +s285, fill=m27) -c5383 = mcdc.cell(+s161 & -s162 & -s277, fill=m18) -c5384 = mcdc.cell(+s161 & -s162 & +s277 & -s278, fill=m19) -c5385 = mcdc.cell(+s161 & -s162 & +s278 & -s279, fill=m20) -c5386 = mcdc.cell(+s161 & -s162 & +s279 & -s280, fill=m21) -c5387 = mcdc.cell(+s161 & -s162 & +s280 & -s281, fill=m22) -c5388 = mcdc.cell(+s161 & -s162 & +s281 & -s282, fill=m23) -c5389 = mcdc.cell(+s161 & -s162 & +s282 & -s283, fill=m24) -c5390 = mcdc.cell(+s161 & -s162 & +s283 & -s284, fill=m25) -c5391 = mcdc.cell(+s161 & -s162 & +s284 & -s285, fill=m26) -c5392 = mcdc.cell(+s161 & -s162 & +s285, fill=m27) -c5393 = mcdc.cell(+s162 & -s163 & -s277, fill=m18) -c5394 = mcdc.cell(+s162 & -s163 & +s277 & -s278, fill=m19) -c5395 = mcdc.cell(+s162 & -s163 & +s278 & -s279, fill=m20) -c5396 = mcdc.cell(+s162 & -s163 & +s279 & -s280, fill=m21) -c5397 = mcdc.cell(+s162 & -s163 & +s280 & -s281, fill=m22) -c5398 = mcdc.cell(+s162 & -s163 & +s281 & -s282, fill=m23) -c5399 = mcdc.cell(+s162 & -s163 & +s282 & -s283, fill=m24) -c5400 = mcdc.cell(+s162 & -s163 & +s283 & -s284, fill=m25) -c5401 = mcdc.cell(+s162 & -s163 & +s284 & -s285, fill=m26) -c5402 = mcdc.cell(+s162 & -s163 & +s285, fill=m27) -c5403 = mcdc.cell(+s163 & -s164 & -s277, fill=m18) -c5404 = mcdc.cell(+s163 & -s164 & +s277 & -s278, fill=m19) -c5405 = mcdc.cell(+s163 & -s164 & +s278 & -s279, fill=m20) -c5406 = mcdc.cell(+s163 & -s164 & +s279 & -s280, fill=m21) -c5407 = mcdc.cell(+s163 & -s164 & +s280 & -s281, fill=m22) -c5408 = mcdc.cell(+s163 & -s164 & +s281 & -s282, fill=m23) -c5409 = mcdc.cell(+s163 & -s164 & +s282 & -s283, fill=m24) -c5410 = mcdc.cell(+s163 & -s164 & +s283 & -s284, fill=m25) -c5411 = mcdc.cell(+s163 & -s164 & +s284 & -s285, fill=m26) -c5412 = mcdc.cell(+s163 & -s164 & +s285, fill=m27) -c5413 = mcdc.cell(+s164 & -s165 & -s277, fill=m18) -c5414 = mcdc.cell(+s164 & -s165 & +s277 & -s278, fill=m19) -c5415 = mcdc.cell(+s164 & -s165 & +s278 & -s279, fill=m20) -c5416 = mcdc.cell(+s164 & -s165 & +s279 & -s280, fill=m21) -c5417 = mcdc.cell(+s164 & -s165 & +s280 & -s281, fill=m22) -c5418 = mcdc.cell(+s164 & -s165 & +s281 & -s282, fill=m23) -c5419 = mcdc.cell(+s164 & -s165 & +s282 & -s283, fill=m24) -c5420 = mcdc.cell(+s164 & -s165 & +s283 & -s284, fill=m25) -c5421 = mcdc.cell(+s164 & -s165 & +s284 & -s285, fill=m26) -c5422 = mcdc.cell(+s164 & -s165 & +s285, fill=m27) -c5423 = mcdc.cell(+s165 & -s166 & -s277, fill=m18) -c5424 = mcdc.cell(+s165 & -s166 & +s277 & -s278, fill=m19) -c5425 = mcdc.cell(+s165 & -s166 & +s278 & -s279, fill=m20) -c5426 = mcdc.cell(+s165 & -s166 & +s279 & -s280, fill=m21) -c5427 = mcdc.cell(+s165 & -s166 & +s280 & -s281, fill=m22) -c5428 = mcdc.cell(+s165 & -s166 & +s281 & -s282, fill=m23) -c5429 = mcdc.cell(+s165 & -s166 & +s282 & -s283, fill=m24) -c5430 = mcdc.cell(+s165 & -s166 & +s283 & -s284, fill=m25) -c5431 = mcdc.cell(+s165 & -s166 & +s284 & -s285, fill=m26) -c5432 = mcdc.cell(+s165 & -s166 & +s285, fill=m27) -c5433 = mcdc.cell(+s166 & -s167 & -s277, fill=m18) -c5434 = mcdc.cell(+s166 & -s167 & +s277 & -s278, fill=m19) -c5435 = mcdc.cell(+s166 & -s167 & +s278 & -s279, fill=m20) -c5436 = mcdc.cell(+s166 & -s167 & +s279 & -s280, fill=m21) -c5437 = mcdc.cell(+s166 & -s167 & +s280 & -s281, fill=m22) -c5438 = mcdc.cell(+s166 & -s167 & +s281 & -s282, fill=m23) -c5439 = mcdc.cell(+s166 & -s167 & +s282 & -s283, fill=m24) -c5440 = mcdc.cell(+s166 & -s167 & +s283 & -s284, fill=m25) -c5441 = mcdc.cell(+s166 & -s167 & +s284 & -s285, fill=m26) -c5442 = mcdc.cell(+s166 & -s167 & +s285, fill=m27) -c5443 = mcdc.cell(+s167 & -s168 & -s277, fill=m18) -c5444 = mcdc.cell(+s167 & -s168 & +s277 & -s278, fill=m19) -c5445 = mcdc.cell(+s167 & -s168 & +s278 & -s279, fill=m20) -c5446 = mcdc.cell(+s167 & -s168 & +s279 & -s280, fill=m21) -c5447 = mcdc.cell(+s167 & -s168 & +s280 & -s281, fill=m22) -c5448 = mcdc.cell(+s167 & -s168 & +s281 & -s282, fill=m23) -c5449 = mcdc.cell(+s167 & -s168 & +s282 & -s283, fill=m24) -c5450 = mcdc.cell(+s167 & -s168 & +s283 & -s284, fill=m25) -c5451 = mcdc.cell(+s167 & -s168 & +s284 & -s285, fill=m26) -c5452 = mcdc.cell(+s167 & -s168 & +s285, fill=m27) -c5453 = mcdc.cell(+s168 & -s169 & -s277, fill=m18) -c5454 = mcdc.cell(+s168 & -s169 & +s277 & -s278, fill=m19) -c5455 = mcdc.cell(+s168 & -s169 & +s278 & -s279, fill=m20) -c5456 = mcdc.cell(+s168 & -s169 & +s279 & -s280, fill=m21) -c5457 = mcdc.cell(+s168 & -s169 & +s280 & -s281, fill=m22) -c5458 = mcdc.cell(+s168 & -s169 & +s281 & -s282, fill=m23) -c5459 = mcdc.cell(+s168 & -s169 & +s282 & -s283, fill=m24) -c5460 = mcdc.cell(+s168 & -s169 & +s283 & -s284, fill=m25) -c5461 = mcdc.cell(+s168 & -s169 & +s284 & -s285, fill=m26) -c5462 = mcdc.cell(+s168 & -s169 & +s285, fill=m27) -c5463 = mcdc.cell(+s169 & -s170 & -s277, fill=m18) -c5464 = mcdc.cell(+s169 & -s170 & +s277 & -s278, fill=m19) -c5465 = mcdc.cell(+s169 & -s170 & +s278 & -s279, fill=m20) -c5466 = mcdc.cell(+s169 & -s170 & +s279 & -s280, fill=m21) -c5467 = mcdc.cell(+s169 & -s170 & +s280 & -s281, fill=m22) -c5468 = mcdc.cell(+s169 & -s170 & +s281 & -s282, fill=m23) -c5469 = mcdc.cell(+s169 & -s170 & +s282 & -s283, fill=m24) -c5470 = mcdc.cell(+s169 & -s170 & +s283 & -s284, fill=m25) -c5471 = mcdc.cell(+s169 & -s170 & +s284 & -s285, fill=m26) -c5472 = mcdc.cell(+s169 & -s170 & +s285, fill=m27) -c5473 = mcdc.cell(+s170 & -s171 & -s277, fill=m18) -c5474 = mcdc.cell(+s170 & -s171 & +s277 & -s278, fill=m19) -c5475 = mcdc.cell(+s170 & -s171 & +s278 & -s279, fill=m20) -c5476 = mcdc.cell(+s170 & -s171 & +s279 & -s280, fill=m21) -c5477 = mcdc.cell(+s170 & -s171 & +s280 & -s281, fill=m22) -c5478 = mcdc.cell(+s170 & -s171 & +s281 & -s282, fill=m23) -c5479 = mcdc.cell(+s170 & -s171 & +s282 & -s283, fill=m24) -c5480 = mcdc.cell(+s170 & -s171 & +s283 & -s284, fill=m25) -c5481 = mcdc.cell(+s170 & -s171 & +s284 & -s285, fill=m26) -c5482 = mcdc.cell(+s170 & -s171 & +s285, fill=m27) -c5483 = mcdc.cell(+s171 & -s172 & -s277, fill=m18) -c5484 = mcdc.cell(+s171 & -s172 & +s277 & -s278, fill=m19) -c5485 = mcdc.cell(+s171 & -s172 & +s278 & -s279, fill=m20) -c5486 = mcdc.cell(+s171 & -s172 & +s279 & -s280, fill=m21) -c5487 = mcdc.cell(+s171 & -s172 & +s280 & -s281, fill=m22) -c5488 = mcdc.cell(+s171 & -s172 & +s281 & -s282, fill=m23) -c5489 = mcdc.cell(+s171 & -s172 & +s282 & -s283, fill=m24) -c5490 = mcdc.cell(+s171 & -s172 & +s283 & -s284, fill=m25) -c5491 = mcdc.cell(+s171 & -s172 & +s284 & -s285, fill=m26) -c5492 = mcdc.cell(+s171 & -s172 & +s285, fill=m27) -c5493 = mcdc.cell(+s172 & -s173 & -s277, fill=m18) -c5494 = mcdc.cell(+s172 & -s173 & +s277 & -s278, fill=m19) -c5495 = mcdc.cell(+s172 & -s173 & +s278 & -s279, fill=m20) -c5496 = mcdc.cell(+s172 & -s173 & +s279 & -s280, fill=m21) -c5497 = mcdc.cell(+s172 & -s173 & +s280 & -s281, fill=m22) -c5498 = mcdc.cell(+s172 & -s173 & +s281 & -s282, fill=m23) -c5499 = mcdc.cell(+s172 & -s173 & +s282 & -s283, fill=m24) -c5500 = mcdc.cell(+s172 & -s173 & +s283 & -s284, fill=m25) -c5501 = mcdc.cell(+s172 & -s173 & +s284 & -s285, fill=m26) -c5502 = mcdc.cell(+s172 & -s173 & +s285, fill=m27) -c5503 = mcdc.cell(+s173 & -s174 & -s277, fill=m18) -c5504 = mcdc.cell(+s173 & -s174 & +s277 & -s278, fill=m19) -c5505 = mcdc.cell(+s173 & -s174 & +s278 & -s279, fill=m20) -c5506 = mcdc.cell(+s173 & -s174 & +s279 & -s280, fill=m21) -c5507 = mcdc.cell(+s173 & -s174 & +s280 & -s281, fill=m22) -c5508 = mcdc.cell(+s173 & -s174 & +s281 & -s282, fill=m23) -c5509 = mcdc.cell(+s173 & -s174 & +s282 & -s283, fill=m24) -c5510 = mcdc.cell(+s173 & -s174 & +s283 & -s284, fill=m25) -c5511 = mcdc.cell(+s173 & -s174 & +s284 & -s285, fill=m26) -c5512 = mcdc.cell(+s173 & -s174 & +s285, fill=m27) -c5513 = mcdc.cell(+s174 & -s175 & -s277, fill=m18) -c5514 = mcdc.cell(+s174 & -s175 & +s277 & -s278, fill=m19) -c5515 = mcdc.cell(+s174 & -s175 & +s278 & -s279, fill=m20) -c5516 = mcdc.cell(+s174 & -s175 & +s279 & -s280, fill=m21) -c5517 = mcdc.cell(+s174 & -s175 & +s280 & -s281, fill=m22) -c5518 = mcdc.cell(+s174 & -s175 & +s281 & -s282, fill=m23) -c5519 = mcdc.cell(+s174 & -s175 & +s282 & -s283, fill=m24) -c5520 = mcdc.cell(+s174 & -s175 & +s283 & -s284, fill=m25) -c5521 = mcdc.cell(+s174 & -s175 & +s284 & -s285, fill=m26) -c5522 = mcdc.cell(+s174 & -s175 & +s285, fill=m27) -c5523 = mcdc.cell(+s175 & -s176 & -s277, fill=m18) -c5524 = mcdc.cell(+s175 & -s176 & +s277 & -s278, fill=m19) -c5525 = mcdc.cell(+s175 & -s176 & +s278 & -s279, fill=m20) -c5526 = mcdc.cell(+s175 & -s176 & +s279 & -s280, fill=m21) -c5527 = mcdc.cell(+s175 & -s176 & +s280 & -s281, fill=m22) -c5528 = mcdc.cell(+s175 & -s176 & +s281 & -s282, fill=m23) -c5529 = mcdc.cell(+s175 & -s176 & +s282 & -s283, fill=m24) -c5530 = mcdc.cell(+s175 & -s176 & +s283 & -s284, fill=m25) -c5531 = mcdc.cell(+s175 & -s176 & +s284 & -s285, fill=m26) -c5532 = mcdc.cell(+s175 & -s176 & +s285, fill=m27) -c5533 = mcdc.cell(+s176 & -s177 & -s277, fill=m18) -c5534 = mcdc.cell(+s176 & -s177 & +s277 & -s278, fill=m19) -c5535 = mcdc.cell(+s176 & -s177 & +s278 & -s279, fill=m20) -c5536 = mcdc.cell(+s176 & -s177 & +s279 & -s280, fill=m21) -c5537 = mcdc.cell(+s176 & -s177 & +s280 & -s281, fill=m22) -c5538 = mcdc.cell(+s176 & -s177 & +s281 & -s282, fill=m23) -c5539 = mcdc.cell(+s176 & -s177 & +s282 & -s283, fill=m24) -c5540 = mcdc.cell(+s176 & -s177 & +s283 & -s284, fill=m25) -c5541 = mcdc.cell(+s176 & -s177 & +s284 & -s285, fill=m26) -c5542 = mcdc.cell(+s176 & -s177 & +s285, fill=m27) -c5543 = mcdc.cell(+s177 & -s178 & -s277, fill=m18) -c5544 = mcdc.cell(+s177 & -s178 & +s277 & -s278, fill=m19) -c5545 = mcdc.cell(+s177 & -s178 & +s278 & -s279, fill=m20) -c5546 = mcdc.cell(+s177 & -s178 & +s279 & -s280, fill=m21) -c5547 = mcdc.cell(+s177 & -s178 & +s280 & -s281, fill=m22) -c5548 = mcdc.cell(+s177 & -s178 & +s281 & -s282, fill=m23) -c5549 = mcdc.cell(+s177 & -s178 & +s282 & -s283, fill=m24) -c5550 = mcdc.cell(+s177 & -s178 & +s283 & -s284, fill=m25) -c5551 = mcdc.cell(+s177 & -s178 & +s284 & -s285, fill=m26) -c5552 = mcdc.cell(+s177 & -s178 & +s285, fill=m27) -c5553 = mcdc.cell(+s178 & -s179 & -s277, fill=m18) -c5554 = mcdc.cell(+s178 & -s179 & +s277 & -s278, fill=m19) -c5555 = mcdc.cell(+s178 & -s179 & +s278 & -s279, fill=m20) -c5556 = mcdc.cell(+s178 & -s179 & +s279 & -s280, fill=m21) -c5557 = mcdc.cell(+s178 & -s179 & +s280 & -s281, fill=m22) -c5558 = mcdc.cell(+s178 & -s179 & +s281 & -s282, fill=m23) -c5559 = mcdc.cell(+s178 & -s179 & +s282 & -s283, fill=m24) -c5560 = mcdc.cell(+s178 & -s179 & +s283 & -s284, fill=m25) -c5561 = mcdc.cell(+s178 & -s179 & +s284 & -s285, fill=m26) -c5562 = mcdc.cell(+s178 & -s179 & +s285, fill=m27) -c5563 = mcdc.cell(+s179 & -s180 & -s277, fill=m18) -c5564 = mcdc.cell(+s179 & -s180 & +s277 & -s278, fill=m19) -c5565 = mcdc.cell(+s179 & -s180 & +s278 & -s279, fill=m20) -c5566 = mcdc.cell(+s179 & -s180 & +s279 & -s280, fill=m21) -c5567 = mcdc.cell(+s179 & -s180 & +s280 & -s281, fill=m22) -c5568 = mcdc.cell(+s179 & -s180 & +s281 & -s282, fill=m23) -c5569 = mcdc.cell(+s179 & -s180 & +s282 & -s283, fill=m24) -c5570 = mcdc.cell(+s179 & -s180 & +s283 & -s284, fill=m25) -c5571 = mcdc.cell(+s179 & -s180 & +s284 & -s285, fill=m26) -c5572 = mcdc.cell(+s179 & -s180 & +s285, fill=m27) -c5573 = mcdc.cell(+s180 & -s181 & -s277, fill=m18) -c5574 = mcdc.cell(+s180 & -s181 & +s277 & -s278, fill=m19) -c5575 = mcdc.cell(+s180 & -s181 & +s278 & -s279, fill=m20) -c5576 = mcdc.cell(+s180 & -s181 & +s279 & -s280, fill=m21) -c5577 = mcdc.cell(+s180 & -s181 & +s280 & -s281, fill=m22) -c5578 = mcdc.cell(+s180 & -s181 & +s281 & -s282, fill=m23) -c5579 = mcdc.cell(+s180 & -s181 & +s282 & -s283, fill=m24) -c5580 = mcdc.cell(+s180 & -s181 & +s283 & -s284, fill=m25) -c5581 = mcdc.cell(+s180 & -s181 & +s284 & -s285, fill=m26) -c5582 = mcdc.cell(+s180 & -s181 & +s285, fill=m27) -c5583 = mcdc.cell(+s181 & -s182 & -s277, fill=m18) -c5584 = mcdc.cell(+s181 & -s182 & +s277 & -s278, fill=m19) -c5585 = mcdc.cell(+s181 & -s182 & +s278 & -s279, fill=m20) -c5586 = mcdc.cell(+s181 & -s182 & +s279 & -s280, fill=m21) -c5587 = mcdc.cell(+s181 & -s182 & +s280 & -s281, fill=m22) -c5588 = mcdc.cell(+s181 & -s182 & +s281 & -s282, fill=m23) -c5589 = mcdc.cell(+s181 & -s182 & +s282 & -s283, fill=m24) -c5590 = mcdc.cell(+s181 & -s182 & +s283 & -s284, fill=m25) -c5591 = mcdc.cell(+s181 & -s182 & +s284 & -s285, fill=m26) -c5592 = mcdc.cell(+s181 & -s182 & +s285, fill=m27) -c5593 = mcdc.cell(+s182 & -s183 & -s277, fill=m18) -c5594 = mcdc.cell(+s182 & -s183 & +s277 & -s278, fill=m19) -c5595 = mcdc.cell(+s182 & -s183 & +s278 & -s279, fill=m20) -c5596 = mcdc.cell(+s182 & -s183 & +s279 & -s280, fill=m21) -c5597 = mcdc.cell(+s182 & -s183 & +s280 & -s281, fill=m22) -c5598 = mcdc.cell(+s182 & -s183 & +s281 & -s282, fill=m23) -c5599 = mcdc.cell(+s182 & -s183 & +s282 & -s283, fill=m24) -c5600 = mcdc.cell(+s182 & -s183 & +s283 & -s284, fill=m25) -c5601 = mcdc.cell(+s182 & -s183 & +s284 & -s285, fill=m26) -c5602 = mcdc.cell(+s182 & -s183 & +s285, fill=m27) -c5603 = mcdc.cell(+s183 & -s184 & -s277, fill=m18) -c5604 = mcdc.cell(+s183 & -s184 & +s277 & -s278, fill=m19) -c5605 = mcdc.cell(+s183 & -s184 & +s278 & -s279, fill=m20) -c5606 = mcdc.cell(+s183 & -s184 & +s279 & -s280, fill=m21) -c5607 = mcdc.cell(+s183 & -s184 & +s280 & -s281, fill=m22) -c5608 = mcdc.cell(+s183 & -s184 & +s281 & -s282, fill=m23) -c5609 = mcdc.cell(+s183 & -s184 & +s282 & -s283, fill=m24) -c5610 = mcdc.cell(+s183 & -s184 & +s283 & -s284, fill=m25) -c5611 = mcdc.cell(+s183 & -s184 & +s284 & -s285, fill=m26) -c5612 = mcdc.cell(+s183 & -s184 & +s285, fill=m27) -c5613 = mcdc.cell(+s184 & -s185 & -s277, fill=m18) -c5614 = mcdc.cell(+s184 & -s185 & +s277 & -s278, fill=m19) -c5615 = mcdc.cell(+s184 & -s185 & +s278 & -s279, fill=m20) -c5616 = mcdc.cell(+s184 & -s185 & +s279 & -s280, fill=m21) -c5617 = mcdc.cell(+s184 & -s185 & +s280 & -s281, fill=m22) -c5618 = mcdc.cell(+s184 & -s185 & +s281 & -s282, fill=m23) -c5619 = mcdc.cell(+s184 & -s185 & +s282 & -s283, fill=m24) -c5620 = mcdc.cell(+s184 & -s185 & +s283 & -s284, fill=m25) -c5621 = mcdc.cell(+s184 & -s185 & +s284 & -s285, fill=m26) -c5622 = mcdc.cell(+s184 & -s185 & +s285, fill=m27) -c5623 = mcdc.cell(+s185 & -s186 & -s277, fill=m18) -c5624 = mcdc.cell(+s185 & -s186 & +s277 & -s278, fill=m19) -c5625 = mcdc.cell(+s185 & -s186 & +s278 & -s279, fill=m20) -c5626 = mcdc.cell(+s185 & -s186 & +s279 & -s280, fill=m21) -c5627 = mcdc.cell(+s185 & -s186 & +s280 & -s281, fill=m22) -c5628 = mcdc.cell(+s185 & -s186 & +s281 & -s282, fill=m23) -c5629 = mcdc.cell(+s185 & -s186 & +s282 & -s283, fill=m24) -c5630 = mcdc.cell(+s185 & -s186 & +s283 & -s284, fill=m25) -c5631 = mcdc.cell(+s185 & -s186 & +s284 & -s285, fill=m26) -c5632 = mcdc.cell(+s185 & -s186 & +s285, fill=m27) -c5633 = mcdc.cell(+s186 & -s187 & -s277, fill=m18) -c5634 = mcdc.cell(+s186 & -s187 & +s277 & -s278, fill=m19) -c5635 = mcdc.cell(+s186 & -s187 & +s278 & -s279, fill=m20) -c5636 = mcdc.cell(+s186 & -s187 & +s279 & -s280, fill=m21) -c5637 = mcdc.cell(+s186 & -s187 & +s280 & -s281, fill=m22) -c5638 = mcdc.cell(+s186 & -s187 & +s281 & -s282, fill=m23) -c5639 = mcdc.cell(+s186 & -s187 & +s282 & -s283, fill=m24) -c5640 = mcdc.cell(+s186 & -s187 & +s283 & -s284, fill=m25) -c5641 = mcdc.cell(+s186 & -s187 & +s284 & -s285, fill=m26) -c5642 = mcdc.cell(+s186 & -s187 & +s285, fill=m27) -c5643 = mcdc.cell(+s187 & -s188 & -s277, fill=m18) -c5644 = mcdc.cell(+s187 & -s188 & +s277 & -s278, fill=m19) -c5645 = mcdc.cell(+s187 & -s188 & +s278 & -s279, fill=m20) -c5646 = mcdc.cell(+s187 & -s188 & +s279 & -s280, fill=m21) -c5647 = mcdc.cell(+s187 & -s188 & +s280 & -s281, fill=m22) -c5648 = mcdc.cell(+s187 & -s188 & +s281 & -s282, fill=m23) -c5649 = mcdc.cell(+s187 & -s188 & +s282 & -s283, fill=m24) -c5650 = mcdc.cell(+s187 & -s188 & +s283 & -s284, fill=m25) -c5651 = mcdc.cell(+s187 & -s188 & +s284 & -s285, fill=m26) -c5652 = mcdc.cell(+s187 & -s188 & +s285, fill=m27) -c5653 = mcdc.cell(+s188 & -s189 & -s277, fill=m18) -c5654 = mcdc.cell(+s188 & -s189 & +s277 & -s278, fill=m19) -c5655 = mcdc.cell(+s188 & -s189 & +s278 & -s279, fill=m20) -c5656 = mcdc.cell(+s188 & -s189 & +s279 & -s280, fill=m21) -c5657 = mcdc.cell(+s188 & -s189 & +s280 & -s281, fill=m22) -c5658 = mcdc.cell(+s188 & -s189 & +s281 & -s282, fill=m23) -c5659 = mcdc.cell(+s188 & -s189 & +s282 & -s283, fill=m24) -c5660 = mcdc.cell(+s188 & -s189 & +s283 & -s284, fill=m25) -c5661 = mcdc.cell(+s188 & -s189 & +s284 & -s285, fill=m26) -c5662 = mcdc.cell(+s188 & -s189 & +s285, fill=m27) -c5663 = mcdc.cell(+s189 & -s190 & -s277, fill=m18) -c5664 = mcdc.cell(+s189 & -s190 & +s277 & -s278, fill=m19) -c5665 = mcdc.cell(+s189 & -s190 & +s278 & -s279, fill=m20) -c5666 = mcdc.cell(+s189 & -s190 & +s279 & -s280, fill=m21) -c5667 = mcdc.cell(+s189 & -s190 & +s280 & -s281, fill=m22) -c5668 = mcdc.cell(+s189 & -s190 & +s281 & -s282, fill=m23) -c5669 = mcdc.cell(+s189 & -s190 & +s282 & -s283, fill=m24) -c5670 = mcdc.cell(+s189 & -s190 & +s283 & -s284, fill=m25) -c5671 = mcdc.cell(+s189 & -s190 & +s284 & -s285, fill=m26) -c5672 = mcdc.cell(+s189 & -s190 & +s285, fill=m27) -c5673 = mcdc.cell(+s190 & -s191 & -s277, fill=m18) -c5674 = mcdc.cell(+s190 & -s191 & +s277 & -s278, fill=m19) -c5675 = mcdc.cell(+s190 & -s191 & +s278 & -s279, fill=m20) -c5676 = mcdc.cell(+s190 & -s191 & +s279 & -s280, fill=m21) -c5677 = mcdc.cell(+s190 & -s191 & +s280 & -s281, fill=m22) -c5678 = mcdc.cell(+s190 & -s191 & +s281 & -s282, fill=m23) -c5679 = mcdc.cell(+s190 & -s191 & +s282 & -s283, fill=m24) -c5680 = mcdc.cell(+s190 & -s191 & +s283 & -s284, fill=m25) -c5681 = mcdc.cell(+s190 & -s191 & +s284 & -s285, fill=m26) -c5682 = mcdc.cell(+s190 & -s191 & +s285, fill=m27) -c5683 = mcdc.cell(+s191 & -s192 & -s277, fill=m18) -c5684 = mcdc.cell(+s191 & -s192 & +s277 & -s278, fill=m19) -c5685 = mcdc.cell(+s191 & -s192 & +s278 & -s279, fill=m20) -c5686 = mcdc.cell(+s191 & -s192 & +s279 & -s280, fill=m21) -c5687 = mcdc.cell(+s191 & -s192 & +s280 & -s281, fill=m22) -c5688 = mcdc.cell(+s191 & -s192 & +s281 & -s282, fill=m23) -c5689 = mcdc.cell(+s191 & -s192 & +s282 & -s283, fill=m24) -c5690 = mcdc.cell(+s191 & -s192 & +s283 & -s284, fill=m25) -c5691 = mcdc.cell(+s191 & -s192 & +s284 & -s285, fill=m26) -c5692 = mcdc.cell(+s191 & -s192 & +s285, fill=m27) -c5693 = mcdc.cell(+s192 & -s193 & -s277, fill=m18) -c5694 = mcdc.cell(+s192 & -s193 & +s277 & -s278, fill=m19) -c5695 = mcdc.cell(+s192 & -s193 & +s278 & -s279, fill=m20) -c5696 = mcdc.cell(+s192 & -s193 & +s279 & -s280, fill=m21) -c5697 = mcdc.cell(+s192 & -s193 & +s280 & -s281, fill=m22) -c5698 = mcdc.cell(+s192 & -s193 & +s281 & -s282, fill=m23) -c5699 = mcdc.cell(+s192 & -s193 & +s282 & -s283, fill=m24) -c5700 = mcdc.cell(+s192 & -s193 & +s283 & -s284, fill=m25) -c5701 = mcdc.cell(+s192 & -s193 & +s284 & -s285, fill=m26) -c5702 = mcdc.cell(+s192 & -s193 & +s285, fill=m27) -c5703 = mcdc.cell(+s193 & -s194 & -s277, fill=m18) -c5704 = mcdc.cell(+s193 & -s194 & +s277 & -s278, fill=m19) -c5705 = mcdc.cell(+s193 & -s194 & +s278 & -s279, fill=m20) -c5706 = mcdc.cell(+s193 & -s194 & +s279 & -s280, fill=m21) -c5707 = mcdc.cell(+s193 & -s194 & +s280 & -s281, fill=m22) -c5708 = mcdc.cell(+s193 & -s194 & +s281 & -s282, fill=m23) -c5709 = mcdc.cell(+s193 & -s194 & +s282 & -s283, fill=m24) -c5710 = mcdc.cell(+s193 & -s194 & +s283 & -s284, fill=m25) -c5711 = mcdc.cell(+s193 & -s194 & +s284 & -s285, fill=m26) -c5712 = mcdc.cell(+s193 & -s194 & +s285, fill=m27) -c5713 = mcdc.cell(+s194 & -s195 & -s277, fill=m18) -c5714 = mcdc.cell(+s194 & -s195 & +s277 & -s278, fill=m19) -c5715 = mcdc.cell(+s194 & -s195 & +s278 & -s279, fill=m20) -c5716 = mcdc.cell(+s194 & -s195 & +s279 & -s280, fill=m21) -c5717 = mcdc.cell(+s194 & -s195 & +s280 & -s281, fill=m22) -c5718 = mcdc.cell(+s194 & -s195 & +s281 & -s282, fill=m23) -c5719 = mcdc.cell(+s194 & -s195 & +s282 & -s283, fill=m24) -c5720 = mcdc.cell(+s194 & -s195 & +s283 & -s284, fill=m25) -c5721 = mcdc.cell(+s194 & -s195 & +s284 & -s285, fill=m26) -c5722 = mcdc.cell(+s194 & -s195 & +s285, fill=m27) -c5723 = mcdc.cell(+s195 & -s196 & -s277, fill=m18) -c5724 = mcdc.cell(+s195 & -s196 & +s277 & -s278, fill=m19) -c5725 = mcdc.cell(+s195 & -s196 & +s278 & -s279, fill=m20) -c5726 = mcdc.cell(+s195 & -s196 & +s279 & -s280, fill=m21) -c5727 = mcdc.cell(+s195 & -s196 & +s280 & -s281, fill=m22) -c5728 = mcdc.cell(+s195 & -s196 & +s281 & -s282, fill=m23) -c5729 = mcdc.cell(+s195 & -s196 & +s282 & -s283, fill=m24) -c5730 = mcdc.cell(+s195 & -s196 & +s283 & -s284, fill=m25) -c5731 = mcdc.cell(+s195 & -s196 & +s284 & -s285, fill=m26) -c5732 = mcdc.cell(+s195 & -s196 & +s285, fill=m27) -c5733 = mcdc.cell(+s196 & -s197 & -s277, fill=m18) -c5734 = mcdc.cell(+s196 & -s197 & +s277 & -s278, fill=m19) -c5735 = mcdc.cell(+s196 & -s197 & +s278 & -s279, fill=m20) -c5736 = mcdc.cell(+s196 & -s197 & +s279 & -s280, fill=m21) -c5737 = mcdc.cell(+s196 & -s197 & +s280 & -s281, fill=m22) -c5738 = mcdc.cell(+s196 & -s197 & +s281 & -s282, fill=m23) -c5739 = mcdc.cell(+s196 & -s197 & +s282 & -s283, fill=m24) -c5740 = mcdc.cell(+s196 & -s197 & +s283 & -s284, fill=m25) -c5741 = mcdc.cell(+s196 & -s197 & +s284 & -s285, fill=m26) -c5742 = mcdc.cell(+s196 & -s197 & +s285, fill=m27) -c5743 = mcdc.cell(+s197 & -s198 & -s277, fill=m18) -c5744 = mcdc.cell(+s197 & -s198 & +s277 & -s278, fill=m19) -c5745 = mcdc.cell(+s197 & -s198 & +s278 & -s279, fill=m20) -c5746 = mcdc.cell(+s197 & -s198 & +s279 & -s280, fill=m21) -c5747 = mcdc.cell(+s197 & -s198 & +s280 & -s281, fill=m22) -c5748 = mcdc.cell(+s197 & -s198 & +s281 & -s282, fill=m23) -c5749 = mcdc.cell(+s197 & -s198 & +s282 & -s283, fill=m24) -c5750 = mcdc.cell(+s197 & -s198 & +s283 & -s284, fill=m25) -c5751 = mcdc.cell(+s197 & -s198 & +s284 & -s285, fill=m26) -c5752 = mcdc.cell(+s197 & -s198 & +s285, fill=m27) -c5753 = mcdc.cell(+s198 & -s199 & -s277, fill=m18) -c5754 = mcdc.cell(+s198 & -s199 & +s277 & -s278, fill=m19) -c5755 = mcdc.cell(+s198 & -s199 & +s278 & -s279, fill=m20) -c5756 = mcdc.cell(+s198 & -s199 & +s279 & -s280, fill=m21) -c5757 = mcdc.cell(+s198 & -s199 & +s280 & -s281, fill=m22) -c5758 = mcdc.cell(+s198 & -s199 & +s281 & -s282, fill=m23) -c5759 = mcdc.cell(+s198 & -s199 & +s282 & -s283, fill=m24) -c5760 = mcdc.cell(+s198 & -s199 & +s283 & -s284, fill=m25) -c5761 = mcdc.cell(+s198 & -s199 & +s284 & -s285, fill=m26) -c5762 = mcdc.cell(+s198 & -s199 & +s285, fill=m27) -c5763 = mcdc.cell(+s199 & -s200 & -s277, fill=m18) -c5764 = mcdc.cell(+s199 & -s200 & +s277 & -s278, fill=m19) -c5765 = mcdc.cell(+s199 & -s200 & +s278 & -s279, fill=m20) -c5766 = mcdc.cell(+s199 & -s200 & +s279 & -s280, fill=m21) -c5767 = mcdc.cell(+s199 & -s200 & +s280 & -s281, fill=m22) -c5768 = mcdc.cell(+s199 & -s200 & +s281 & -s282, fill=m23) -c5769 = mcdc.cell(+s199 & -s200 & +s282 & -s283, fill=m24) -c5770 = mcdc.cell(+s199 & -s200 & +s283 & -s284, fill=m25) -c5771 = mcdc.cell(+s199 & -s200 & +s284 & -s285, fill=m26) -c5772 = mcdc.cell(+s199 & -s200 & +s285, fill=m27) -c5773 = mcdc.cell(+s200 & -s201 & -s277, fill=m18) -c5774 = mcdc.cell(+s200 & -s201 & +s277 & -s278, fill=m19) -c5775 = mcdc.cell(+s200 & -s201 & +s278 & -s279, fill=m20) -c5776 = mcdc.cell(+s200 & -s201 & +s279 & -s280, fill=m21) -c5777 = mcdc.cell(+s200 & -s201 & +s280 & -s281, fill=m22) -c5778 = mcdc.cell(+s200 & -s201 & +s281 & -s282, fill=m23) -c5779 = mcdc.cell(+s200 & -s201 & +s282 & -s283, fill=m24) -c5780 = mcdc.cell(+s200 & -s201 & +s283 & -s284, fill=m25) -c5781 = mcdc.cell(+s200 & -s201 & +s284 & -s285, fill=m26) -c5782 = mcdc.cell(+s200 & -s201 & +s285, fill=m27) -c5783 = mcdc.cell(+s201 & -s202 & -s277, fill=m18) -c5784 = mcdc.cell(+s201 & -s202 & +s277 & -s278, fill=m19) -c5785 = mcdc.cell(+s201 & -s202 & +s278 & -s279, fill=m20) -c5786 = mcdc.cell(+s201 & -s202 & +s279 & -s280, fill=m21) -c5787 = mcdc.cell(+s201 & -s202 & +s280 & -s281, fill=m22) -c5788 = mcdc.cell(+s201 & -s202 & +s281 & -s282, fill=m23) -c5789 = mcdc.cell(+s201 & -s202 & +s282 & -s283, fill=m24) -c5790 = mcdc.cell(+s201 & -s202 & +s283 & -s284, fill=m25) -c5791 = mcdc.cell(+s201 & -s202 & +s284 & -s285, fill=m26) -c5792 = mcdc.cell(+s201 & -s202 & +s285, fill=m27) -c5793 = mcdc.cell(+s202 & -s203 & -s277, fill=m18) -c5794 = mcdc.cell(+s202 & -s203 & +s277 & -s278, fill=m19) -c5795 = mcdc.cell(+s202 & -s203 & +s278 & -s279, fill=m20) -c5796 = mcdc.cell(+s202 & -s203 & +s279 & -s280, fill=m21) -c5797 = mcdc.cell(+s202 & -s203 & +s280 & -s281, fill=m22) -c5798 = mcdc.cell(+s202 & -s203 & +s281 & -s282, fill=m23) -c5799 = mcdc.cell(+s202 & -s203 & +s282 & -s283, fill=m24) -c5800 = mcdc.cell(+s202 & -s203 & +s283 & -s284, fill=m25) -c5801 = mcdc.cell(+s202 & -s203 & +s284 & -s285, fill=m26) -c5802 = mcdc.cell(+s202 & -s203 & +s285, fill=m27) -c5803 = mcdc.cell(+s203 & -s204 & -s277, fill=m18) -c5804 = mcdc.cell(+s203 & -s204 & +s277 & -s278, fill=m19) -c5805 = mcdc.cell(+s203 & -s204 & +s278 & -s279, fill=m20) -c5806 = mcdc.cell(+s203 & -s204 & +s279 & -s280, fill=m21) -c5807 = mcdc.cell(+s203 & -s204 & +s280 & -s281, fill=m22) -c5808 = mcdc.cell(+s203 & -s204 & +s281 & -s282, fill=m23) -c5809 = mcdc.cell(+s203 & -s204 & +s282 & -s283, fill=m24) -c5810 = mcdc.cell(+s203 & -s204 & +s283 & -s284, fill=m25) -c5811 = mcdc.cell(+s203 & -s204 & +s284 & -s285, fill=m26) -c5812 = mcdc.cell(+s203 & -s204 & +s285, fill=m27) -c5813 = mcdc.cell(+s204 & -s205 & -s277, fill=m18) -c5814 = mcdc.cell(+s204 & -s205 & +s277 & -s278, fill=m19) -c5815 = mcdc.cell(+s204 & -s205 & +s278 & -s279, fill=m20) -c5816 = mcdc.cell(+s204 & -s205 & +s279 & -s280, fill=m21) -c5817 = mcdc.cell(+s204 & -s205 & +s280 & -s281, fill=m22) -c5818 = mcdc.cell(+s204 & -s205 & +s281 & -s282, fill=m23) -c5819 = mcdc.cell(+s204 & -s205 & +s282 & -s283, fill=m24) -c5820 = mcdc.cell(+s204 & -s205 & +s283 & -s284, fill=m25) -c5821 = mcdc.cell(+s204 & -s205 & +s284 & -s285, fill=m26) -c5822 = mcdc.cell(+s204 & -s205 & +s285, fill=m27) -c5823 = mcdc.cell(+s205 & -s206 & -s277, fill=m18) -c5824 = mcdc.cell(+s205 & -s206 & +s277 & -s278, fill=m19) -c5825 = mcdc.cell(+s205 & -s206 & +s278 & -s279, fill=m20) -c5826 = mcdc.cell(+s205 & -s206 & +s279 & -s280, fill=m21) -c5827 = mcdc.cell(+s205 & -s206 & +s280 & -s281, fill=m22) -c5828 = mcdc.cell(+s205 & -s206 & +s281 & -s282, fill=m23) -c5829 = mcdc.cell(+s205 & -s206 & +s282 & -s283, fill=m24) -c5830 = mcdc.cell(+s205 & -s206 & +s283 & -s284, fill=m25) -c5831 = mcdc.cell(+s205 & -s206 & +s284 & -s285, fill=m26) -c5832 = mcdc.cell(+s205 & -s206 & +s285, fill=m27) -c5833 = mcdc.cell(+s206 & -s207 & -s277, fill=m18) -c5834 = mcdc.cell(+s206 & -s207 & +s277 & -s278, fill=m19) -c5835 = mcdc.cell(+s206 & -s207 & +s278 & -s279, fill=m20) -c5836 = mcdc.cell(+s206 & -s207 & +s279 & -s280, fill=m21) -c5837 = mcdc.cell(+s206 & -s207 & +s280 & -s281, fill=m22) -c5838 = mcdc.cell(+s206 & -s207 & +s281 & -s282, fill=m23) -c5839 = mcdc.cell(+s206 & -s207 & +s282 & -s283, fill=m24) -c5840 = mcdc.cell(+s206 & -s207 & +s283 & -s284, fill=m25) -c5841 = mcdc.cell(+s206 & -s207 & +s284 & -s285, fill=m26) -c5842 = mcdc.cell(+s206 & -s207 & +s285, fill=m27) -c5843 = mcdc.cell(+s207 & -s208 & -s277, fill=m18) -c5844 = mcdc.cell(+s207 & -s208 & +s277 & -s278, fill=m19) -c5845 = mcdc.cell(+s207 & -s208 & +s278 & -s279, fill=m20) -c5846 = mcdc.cell(+s207 & -s208 & +s279 & -s280, fill=m21) -c5847 = mcdc.cell(+s207 & -s208 & +s280 & -s281, fill=m22) -c5848 = mcdc.cell(+s207 & -s208 & +s281 & -s282, fill=m23) -c5849 = mcdc.cell(+s207 & -s208 & +s282 & -s283, fill=m24) -c5850 = mcdc.cell(+s207 & -s208 & +s283 & -s284, fill=m25) -c5851 = mcdc.cell(+s207 & -s208 & +s284 & -s285, fill=m26) -c5852 = mcdc.cell(+s207 & -s208 & +s285, fill=m27) -c5853 = mcdc.cell(+s208 & -s209 & -s277, fill=m18) -c5854 = mcdc.cell(+s208 & -s209 & +s277 & -s278, fill=m19) -c5855 = mcdc.cell(+s208 & -s209 & +s278 & -s279, fill=m20) -c5856 = mcdc.cell(+s208 & -s209 & +s279 & -s280, fill=m21) -c5857 = mcdc.cell(+s208 & -s209 & +s280 & -s281, fill=m22) -c5858 = mcdc.cell(+s208 & -s209 & +s281 & -s282, fill=m23) -c5859 = mcdc.cell(+s208 & -s209 & +s282 & -s283, fill=m24) -c5860 = mcdc.cell(+s208 & -s209 & +s283 & -s284, fill=m25) -c5861 = mcdc.cell(+s208 & -s209 & +s284 & -s285, fill=m26) -c5862 = mcdc.cell(+s208 & -s209 & +s285, fill=m27) -c5863 = mcdc.cell(+s209 & -s210 & -s277, fill=m18) -c5864 = mcdc.cell(+s209 & -s210 & +s277 & -s278, fill=m19) -c5865 = mcdc.cell(+s209 & -s210 & +s278 & -s279, fill=m20) -c5866 = mcdc.cell(+s209 & -s210 & +s279 & -s280, fill=m21) -c5867 = mcdc.cell(+s209 & -s210 & +s280 & -s281, fill=m22) -c5868 = mcdc.cell(+s209 & -s210 & +s281 & -s282, fill=m23) -c5869 = mcdc.cell(+s209 & -s210 & +s282 & -s283, fill=m24) -c5870 = mcdc.cell(+s209 & -s210 & +s283 & -s284, fill=m25) -c5871 = mcdc.cell(+s209 & -s210 & +s284 & -s285, fill=m26) -c5872 = mcdc.cell(+s209 & -s210 & +s285, fill=m27) -c5873 = mcdc.cell(+s210 & -s211 & -s277, fill=m18) -c5874 = mcdc.cell(+s210 & -s211 & +s277 & -s278, fill=m19) -c5875 = mcdc.cell(+s210 & -s211 & +s278 & -s279, fill=m20) -c5876 = mcdc.cell(+s210 & -s211 & +s279 & -s280, fill=m21) -c5877 = mcdc.cell(+s210 & -s211 & +s280 & -s281, fill=m22) -c5878 = mcdc.cell(+s210 & -s211 & +s281 & -s282, fill=m23) -c5879 = mcdc.cell(+s210 & -s211 & +s282 & -s283, fill=m24) -c5880 = mcdc.cell(+s210 & -s211 & +s283 & -s284, fill=m25) -c5881 = mcdc.cell(+s210 & -s211 & +s284 & -s285, fill=m26) -c5882 = mcdc.cell(+s210 & -s211 & +s285, fill=m27) -c5883 = mcdc.cell(+s211 & -s212 & -s277, fill=m18) -c5884 = mcdc.cell(+s211 & -s212 & +s277 & -s278, fill=m19) -c5885 = mcdc.cell(+s211 & -s212 & +s278 & -s279, fill=m20) -c5886 = mcdc.cell(+s211 & -s212 & +s279 & -s280, fill=m21) -c5887 = mcdc.cell(+s211 & -s212 & +s280 & -s281, fill=m22) -c5888 = mcdc.cell(+s211 & -s212 & +s281 & -s282, fill=m23) -c5889 = mcdc.cell(+s211 & -s212 & +s282 & -s283, fill=m24) -c5890 = mcdc.cell(+s211 & -s212 & +s283 & -s284, fill=m25) -c5891 = mcdc.cell(+s211 & -s212 & +s284 & -s285, fill=m26) -c5892 = mcdc.cell(+s211 & -s212 & +s285, fill=m27) -c5893 = mcdc.cell(+s212 & -s213 & -s277, fill=m18) -c5894 = mcdc.cell(+s212 & -s213 & +s277 & -s278, fill=m19) -c5895 = mcdc.cell(+s212 & -s213 & +s278 & -s279, fill=m20) -c5896 = mcdc.cell(+s212 & -s213 & +s279 & -s280, fill=m21) -c5897 = mcdc.cell(+s212 & -s213 & +s280 & -s281, fill=m22) -c5898 = mcdc.cell(+s212 & -s213 & +s281 & -s282, fill=m23) -c5899 = mcdc.cell(+s212 & -s213 & +s282 & -s283, fill=m24) -c5900 = mcdc.cell(+s212 & -s213 & +s283 & -s284, fill=m25) -c5901 = mcdc.cell(+s212 & -s213 & +s284 & -s285, fill=m26) -c5902 = mcdc.cell(+s212 & -s213 & +s285, fill=m27) -c5903 = mcdc.cell(+s213 & -s214 & -s277, fill=m18) -c5904 = mcdc.cell(+s213 & -s214 & +s277 & -s278, fill=m19) -c5905 = mcdc.cell(+s213 & -s214 & +s278 & -s279, fill=m20) -c5906 = mcdc.cell(+s213 & -s214 & +s279 & -s280, fill=m21) -c5907 = mcdc.cell(+s213 & -s214 & +s280 & -s281, fill=m22) -c5908 = mcdc.cell(+s213 & -s214 & +s281 & -s282, fill=m23) -c5909 = mcdc.cell(+s213 & -s214 & +s282 & -s283, fill=m24) -c5910 = mcdc.cell(+s213 & -s214 & +s283 & -s284, fill=m25) -c5911 = mcdc.cell(+s213 & -s214 & +s284 & -s285, fill=m26) -c5912 = mcdc.cell(+s213 & -s214 & +s285, fill=m27) -c5913 = mcdc.cell(+s214 & -s215 & -s277, fill=m18) -c5914 = mcdc.cell(+s214 & -s215 & +s277 & -s278, fill=m19) -c5915 = mcdc.cell(+s214 & -s215 & +s278 & -s279, fill=m20) -c5916 = mcdc.cell(+s214 & -s215 & +s279 & -s280, fill=m21) -c5917 = mcdc.cell(+s214 & -s215 & +s280 & -s281, fill=m22) -c5918 = mcdc.cell(+s214 & -s215 & +s281 & -s282, fill=m23) -c5919 = mcdc.cell(+s214 & -s215 & +s282 & -s283, fill=m24) -c5920 = mcdc.cell(+s214 & -s215 & +s283 & -s284, fill=m25) -c5921 = mcdc.cell(+s214 & -s215 & +s284 & -s285, fill=m26) -c5922 = mcdc.cell(+s214 & -s215 & +s285, fill=m27) -c5923 = mcdc.cell(+s215 & -s216 & -s277, fill=m18) -c5924 = mcdc.cell(+s215 & -s216 & +s277 & -s278, fill=m19) -c5925 = mcdc.cell(+s215 & -s216 & +s278 & -s279, fill=m20) -c5926 = mcdc.cell(+s215 & -s216 & +s279 & -s280, fill=m21) -c5927 = mcdc.cell(+s215 & -s216 & +s280 & -s281, fill=m22) -c5928 = mcdc.cell(+s215 & -s216 & +s281 & -s282, fill=m23) -c5929 = mcdc.cell(+s215 & -s216 & +s282 & -s283, fill=m24) -c5930 = mcdc.cell(+s215 & -s216 & +s283 & -s284, fill=m25) -c5931 = mcdc.cell(+s215 & -s216 & +s284 & -s285, fill=m26) -c5932 = mcdc.cell(+s215 & -s216 & +s285, fill=m27) -c5933 = mcdc.cell(+s216 & -s217 & -s277, fill=m18) -c5934 = mcdc.cell(+s216 & -s217 & +s277 & -s278, fill=m19) -c5935 = mcdc.cell(+s216 & -s217 & +s278 & -s279, fill=m20) -c5936 = mcdc.cell(+s216 & -s217 & +s279 & -s280, fill=m21) -c5937 = mcdc.cell(+s216 & -s217 & +s280 & -s281, fill=m22) -c5938 = mcdc.cell(+s216 & -s217 & +s281 & -s282, fill=m23) -c5939 = mcdc.cell(+s216 & -s217 & +s282 & -s283, fill=m24) -c5940 = mcdc.cell(+s216 & -s217 & +s283 & -s284, fill=m25) -c5941 = mcdc.cell(+s216 & -s217 & +s284 & -s285, fill=m26) -c5942 = mcdc.cell(+s216 & -s217 & +s285, fill=m27) -c5943 = mcdc.cell(+s217 & -s218 & -s277, fill=m18) -c5944 = mcdc.cell(+s217 & -s218 & +s277 & -s278, fill=m19) -c5945 = mcdc.cell(+s217 & -s218 & +s278 & -s279, fill=m20) -c5946 = mcdc.cell(+s217 & -s218 & +s279 & -s280, fill=m21) -c5947 = mcdc.cell(+s217 & -s218 & +s280 & -s281, fill=m22) -c5948 = mcdc.cell(+s217 & -s218 & +s281 & -s282, fill=m23) -c5949 = mcdc.cell(+s217 & -s218 & +s282 & -s283, fill=m24) -c5950 = mcdc.cell(+s217 & -s218 & +s283 & -s284, fill=m25) -c5951 = mcdc.cell(+s217 & -s218 & +s284 & -s285, fill=m26) -c5952 = mcdc.cell(+s217 & -s218 & +s285, fill=m27) -c5953 = mcdc.cell(+s218 & -s219 & -s277, fill=m18) -c5954 = mcdc.cell(+s218 & -s219 & +s277 & -s278, fill=m19) -c5955 = mcdc.cell(+s218 & -s219 & +s278 & -s279, fill=m20) -c5956 = mcdc.cell(+s218 & -s219 & +s279 & -s280, fill=m21) -c5957 = mcdc.cell(+s218 & -s219 & +s280 & -s281, fill=m22) -c5958 = mcdc.cell(+s218 & -s219 & +s281 & -s282, fill=m23) -c5959 = mcdc.cell(+s218 & -s219 & +s282 & -s283, fill=m24) -c5960 = mcdc.cell(+s218 & -s219 & +s283 & -s284, fill=m25) -c5961 = mcdc.cell(+s218 & -s219 & +s284 & -s285, fill=m26) -c5962 = mcdc.cell(+s218 & -s219 & +s285, fill=m27) -c5963 = mcdc.cell(+s219 & -s220 & -s277, fill=m18) -c5964 = mcdc.cell(+s219 & -s220 & +s277 & -s278, fill=m19) -c5965 = mcdc.cell(+s219 & -s220 & +s278 & -s279, fill=m20) -c5966 = mcdc.cell(+s219 & -s220 & +s279 & -s280, fill=m21) -c5967 = mcdc.cell(+s219 & -s220 & +s280 & -s281, fill=m22) -c5968 = mcdc.cell(+s219 & -s220 & +s281 & -s282, fill=m23) -c5969 = mcdc.cell(+s219 & -s220 & +s282 & -s283, fill=m24) -c5970 = mcdc.cell(+s219 & -s220 & +s283 & -s284, fill=m25) -c5971 = mcdc.cell(+s219 & -s220 & +s284 & -s285, fill=m26) -c5972 = mcdc.cell(+s219 & -s220 & +s285, fill=m27) -c5973 = mcdc.cell(+s220 & -s221 & -s277, fill=m18) -c5974 = mcdc.cell(+s220 & -s221 & +s277 & -s278, fill=m19) -c5975 = mcdc.cell(+s220 & -s221 & +s278 & -s279, fill=m20) -c5976 = mcdc.cell(+s220 & -s221 & +s279 & -s280, fill=m21) -c5977 = mcdc.cell(+s220 & -s221 & +s280 & -s281, fill=m22) -c5978 = mcdc.cell(+s220 & -s221 & +s281 & -s282, fill=m23) -c5979 = mcdc.cell(+s220 & -s221 & +s282 & -s283, fill=m24) -c5980 = mcdc.cell(+s220 & -s221 & +s283 & -s284, fill=m25) -c5981 = mcdc.cell(+s220 & -s221 & +s284 & -s285, fill=m26) -c5982 = mcdc.cell(+s220 & -s221 & +s285, fill=m27) -c5983 = mcdc.cell(+s221 & -s222 & -s277, fill=m18) -c5984 = mcdc.cell(+s221 & -s222 & +s277 & -s278, fill=m19) -c5985 = mcdc.cell(+s221 & -s222 & +s278 & -s279, fill=m20) -c5986 = mcdc.cell(+s221 & -s222 & +s279 & -s280, fill=m21) -c5987 = mcdc.cell(+s221 & -s222 & +s280 & -s281, fill=m22) -c5988 = mcdc.cell(+s221 & -s222 & +s281 & -s282, fill=m23) -c5989 = mcdc.cell(+s221 & -s222 & +s282 & -s283, fill=m24) -c5990 = mcdc.cell(+s221 & -s222 & +s283 & -s284, fill=m25) -c5991 = mcdc.cell(+s221 & -s222 & +s284 & -s285, fill=m26) -c5992 = mcdc.cell(+s221 & -s222 & +s285, fill=m27) -c5993 = mcdc.cell(+s222 & -s223 & -s277, fill=m18) -c5994 = mcdc.cell(+s222 & -s223 & +s277 & -s278, fill=m19) -c5995 = mcdc.cell(+s222 & -s223 & +s278 & -s279, fill=m20) -c5996 = mcdc.cell(+s222 & -s223 & +s279 & -s280, fill=m21) -c5997 = mcdc.cell(+s222 & -s223 & +s280 & -s281, fill=m22) -c5998 = mcdc.cell(+s222 & -s223 & +s281 & -s282, fill=m23) -c5999 = mcdc.cell(+s222 & -s223 & +s282 & -s283, fill=m24) -c6000 = mcdc.cell(+s222 & -s223 & +s283 & -s284, fill=m25) -c6001 = mcdc.cell(+s222 & -s223 & +s284 & -s285, fill=m26) -c6002 = mcdc.cell(+s222 & -s223 & +s285, fill=m27) -c6003 = mcdc.cell(+s223 & -s224 & -s277, fill=m18) -c6004 = mcdc.cell(+s223 & -s224 & +s277 & -s278, fill=m19) -c6005 = mcdc.cell(+s223 & -s224 & +s278 & -s279, fill=m20) -c6006 = mcdc.cell(+s223 & -s224 & +s279 & -s280, fill=m21) -c6007 = mcdc.cell(+s223 & -s224 & +s280 & -s281, fill=m22) -c6008 = mcdc.cell(+s223 & -s224 & +s281 & -s282, fill=m23) -c6009 = mcdc.cell(+s223 & -s224 & +s282 & -s283, fill=m24) -c6010 = mcdc.cell(+s223 & -s224 & +s283 & -s284, fill=m25) -c6011 = mcdc.cell(+s223 & -s224 & +s284 & -s285, fill=m26) -c6012 = mcdc.cell(+s223 & -s224 & +s285, fill=m27) -c6013 = mcdc.cell(+s224 & -s225 & -s277, fill=m18) -c6014 = mcdc.cell(+s224 & -s225 & +s277 & -s278, fill=m19) -c6015 = mcdc.cell(+s224 & -s225 & +s278 & -s279, fill=m20) -c6016 = mcdc.cell(+s224 & -s225 & +s279 & -s280, fill=m21) -c6017 = mcdc.cell(+s224 & -s225 & +s280 & -s281, fill=m22) -c6018 = mcdc.cell(+s224 & -s225 & +s281 & -s282, fill=m23) -c6019 = mcdc.cell(+s224 & -s225 & +s282 & -s283, fill=m24) -c6020 = mcdc.cell(+s224 & -s225 & +s283 & -s284, fill=m25) -c6021 = mcdc.cell(+s224 & -s225 & +s284 & -s285, fill=m26) -c6022 = mcdc.cell(+s224 & -s225 & +s285, fill=m27) -c6023 = mcdc.cell(+s225 & -s226 & -s277, fill=m18) -c6024 = mcdc.cell(+s225 & -s226 & +s277 & -s278, fill=m19) -c6025 = mcdc.cell(+s225 & -s226 & +s278 & -s279, fill=m20) -c6026 = mcdc.cell(+s225 & -s226 & +s279 & -s280, fill=m21) -c6027 = mcdc.cell(+s225 & -s226 & +s280 & -s281, fill=m22) -c6028 = mcdc.cell(+s225 & -s226 & +s281 & -s282, fill=m23) -c6029 = mcdc.cell(+s225 & -s226 & +s282 & -s283, fill=m24) -c6030 = mcdc.cell(+s225 & -s226 & +s283 & -s284, fill=m25) -c6031 = mcdc.cell(+s225 & -s226 & +s284 & -s285, fill=m26) -c6032 = mcdc.cell(+s225 & -s226 & +s285, fill=m27) -c6033 = mcdc.cell(+s226 & -s227 & -s277, fill=m18) -c6034 = mcdc.cell(+s226 & -s227 & +s277 & -s278, fill=m19) -c6035 = mcdc.cell(+s226 & -s227 & +s278 & -s279, fill=m20) -c6036 = mcdc.cell(+s226 & -s227 & +s279 & -s280, fill=m21) -c6037 = mcdc.cell(+s226 & -s227 & +s280 & -s281, fill=m22) -c6038 = mcdc.cell(+s226 & -s227 & +s281 & -s282, fill=m23) -c6039 = mcdc.cell(+s226 & -s227 & +s282 & -s283, fill=m24) -c6040 = mcdc.cell(+s226 & -s227 & +s283 & -s284, fill=m25) -c6041 = mcdc.cell(+s226 & -s227 & +s284 & -s285, fill=m26) -c6042 = mcdc.cell(+s226 & -s227 & +s285, fill=m27) -c6043 = mcdc.cell(+s227 & -s228 & -s277, fill=m18) -c6044 = mcdc.cell(+s227 & -s228 & +s277 & -s278, fill=m19) -c6045 = mcdc.cell(+s227 & -s228 & +s278 & -s279, fill=m20) -c6046 = mcdc.cell(+s227 & -s228 & +s279 & -s280, fill=m21) -c6047 = mcdc.cell(+s227 & -s228 & +s280 & -s281, fill=m22) -c6048 = mcdc.cell(+s227 & -s228 & +s281 & -s282, fill=m23) -c6049 = mcdc.cell(+s227 & -s228 & +s282 & -s283, fill=m24) -c6050 = mcdc.cell(+s227 & -s228 & +s283 & -s284, fill=m25) -c6051 = mcdc.cell(+s227 & -s228 & +s284 & -s285, fill=m26) -c6052 = mcdc.cell(+s227 & -s228 & +s285, fill=m27) -c6053 = mcdc.cell(+s228 & -s229 & -s277, fill=m18) -c6054 = mcdc.cell(+s228 & -s229 & +s277 & -s278, fill=m19) -c6055 = mcdc.cell(+s228 & -s229 & +s278 & -s279, fill=m20) -c6056 = mcdc.cell(+s228 & -s229 & +s279 & -s280, fill=m21) -c6057 = mcdc.cell(+s228 & -s229 & +s280 & -s281, fill=m22) -c6058 = mcdc.cell(+s228 & -s229 & +s281 & -s282, fill=m23) -c6059 = mcdc.cell(+s228 & -s229 & +s282 & -s283, fill=m24) -c6060 = mcdc.cell(+s228 & -s229 & +s283 & -s284, fill=m25) -c6061 = mcdc.cell(+s228 & -s229 & +s284 & -s285, fill=m26) -c6062 = mcdc.cell(+s228 & -s229 & +s285, fill=m27) -c6063 = mcdc.cell(+s229 & -s230 & -s277, fill=m18) -c6064 = mcdc.cell(+s229 & -s230 & +s277 & -s278, fill=m19) -c6065 = mcdc.cell(+s229 & -s230 & +s278 & -s279, fill=m20) -c6066 = mcdc.cell(+s229 & -s230 & +s279 & -s280, fill=m21) -c6067 = mcdc.cell(+s229 & -s230 & +s280 & -s281, fill=m22) -c6068 = mcdc.cell(+s229 & -s230 & +s281 & -s282, fill=m23) -c6069 = mcdc.cell(+s229 & -s230 & +s282 & -s283, fill=m24) -c6070 = mcdc.cell(+s229 & -s230 & +s283 & -s284, fill=m25) -c6071 = mcdc.cell(+s229 & -s230 & +s284 & -s285, fill=m26) -c6072 = mcdc.cell(+s229 & -s230 & +s285, fill=m27) -c6073 = mcdc.cell(+s230 & -s231 & -s277, fill=m18) -c6074 = mcdc.cell(+s230 & -s231 & +s277 & -s278, fill=m19) -c6075 = mcdc.cell(+s230 & -s231 & +s278 & -s279, fill=m20) -c6076 = mcdc.cell(+s230 & -s231 & +s279 & -s280, fill=m21) -c6077 = mcdc.cell(+s230 & -s231 & +s280 & -s281, fill=m22) -c6078 = mcdc.cell(+s230 & -s231 & +s281 & -s282, fill=m23) -c6079 = mcdc.cell(+s230 & -s231 & +s282 & -s283, fill=m24) -c6080 = mcdc.cell(+s230 & -s231 & +s283 & -s284, fill=m25) -c6081 = mcdc.cell(+s230 & -s231 & +s284 & -s285, fill=m26) -c6082 = mcdc.cell(+s230 & -s231 & +s285, fill=m27) -c6083 = mcdc.cell(+s231 & -s232 & -s277, fill=m18) -c6084 = mcdc.cell(+s231 & -s232 & +s277 & -s278, fill=m19) -c6085 = mcdc.cell(+s231 & -s232 & +s278 & -s279, fill=m20) -c6086 = mcdc.cell(+s231 & -s232 & +s279 & -s280, fill=m21) -c6087 = mcdc.cell(+s231 & -s232 & +s280 & -s281, fill=m22) -c6088 = mcdc.cell(+s231 & -s232 & +s281 & -s282, fill=m23) -c6089 = mcdc.cell(+s231 & -s232 & +s282 & -s283, fill=m24) -c6090 = mcdc.cell(+s231 & -s232 & +s283 & -s284, fill=m25) -c6091 = mcdc.cell(+s231 & -s232 & +s284 & -s285, fill=m26) -c6092 = mcdc.cell(+s231 & -s232 & +s285, fill=m27) -c6093 = mcdc.cell(+s232 & -s233 & -s277, fill=m18) -c6094 = mcdc.cell(+s232 & -s233 & +s277 & -s278, fill=m19) -c6095 = mcdc.cell(+s232 & -s233 & +s278 & -s279, fill=m20) -c6096 = mcdc.cell(+s232 & -s233 & +s279 & -s280, fill=m21) -c6097 = mcdc.cell(+s232 & -s233 & +s280 & -s281, fill=m22) -c6098 = mcdc.cell(+s232 & -s233 & +s281 & -s282, fill=m23) -c6099 = mcdc.cell(+s232 & -s233 & +s282 & -s283, fill=m24) -c6100 = mcdc.cell(+s232 & -s233 & +s283 & -s284, fill=m25) -c6101 = mcdc.cell(+s232 & -s233 & +s284 & -s285, fill=m26) -c6102 = mcdc.cell(+s232 & -s233 & +s285, fill=m27) -c6103 = mcdc.cell(+s233 & -s234 & -s277, fill=m18) -c6104 = mcdc.cell(+s233 & -s234 & +s277 & -s278, fill=m19) -c6105 = mcdc.cell(+s233 & -s234 & +s278 & -s279, fill=m20) -c6106 = mcdc.cell(+s233 & -s234 & +s279 & -s280, fill=m21) -c6107 = mcdc.cell(+s233 & -s234 & +s280 & -s281, fill=m22) -c6108 = mcdc.cell(+s233 & -s234 & +s281 & -s282, fill=m23) -c6109 = mcdc.cell(+s233 & -s234 & +s282 & -s283, fill=m24) -c6110 = mcdc.cell(+s233 & -s234 & +s283 & -s284, fill=m25) -c6111 = mcdc.cell(+s233 & -s234 & +s284 & -s285, fill=m26) -c6112 = mcdc.cell(+s233 & -s234 & +s285, fill=m27) -c6113 = mcdc.cell(+s234 & -s235 & -s277, fill=m18) -c6114 = mcdc.cell(+s234 & -s235 & +s277 & -s278, fill=m19) -c6115 = mcdc.cell(+s234 & -s235 & +s278 & -s279, fill=m20) -c6116 = mcdc.cell(+s234 & -s235 & +s279 & -s280, fill=m21) -c6117 = mcdc.cell(+s234 & -s235 & +s280 & -s281, fill=m22) -c6118 = mcdc.cell(+s234 & -s235 & +s281 & -s282, fill=m23) -c6119 = mcdc.cell(+s234 & -s235 & +s282 & -s283, fill=m24) -c6120 = mcdc.cell(+s234 & -s235 & +s283 & -s284, fill=m25) -c6121 = mcdc.cell(+s234 & -s235 & +s284 & -s285, fill=m26) -c6122 = mcdc.cell(+s234 & -s235 & +s285, fill=m27) -c6123 = mcdc.cell(+s235 & -s236 & -s277, fill=m18) -c6124 = mcdc.cell(+s235 & -s236 & +s277 & -s278, fill=m19) -c6125 = mcdc.cell(+s235 & -s236 & +s278 & -s279, fill=m20) -c6126 = mcdc.cell(+s235 & -s236 & +s279 & -s280, fill=m21) -c6127 = mcdc.cell(+s235 & -s236 & +s280 & -s281, fill=m22) -c6128 = mcdc.cell(+s235 & -s236 & +s281 & -s282, fill=m23) -c6129 = mcdc.cell(+s235 & -s236 & +s282 & -s283, fill=m24) -c6130 = mcdc.cell(+s235 & -s236 & +s283 & -s284, fill=m25) -c6131 = mcdc.cell(+s235 & -s236 & +s284 & -s285, fill=m26) -c6132 = mcdc.cell(+s235 & -s236 & +s285, fill=m27) -c6133 = mcdc.cell(+s236 & -s237 & -s277, fill=m18) -c6134 = mcdc.cell(+s236 & -s237 & +s277 & -s278, fill=m19) -c6135 = mcdc.cell(+s236 & -s237 & +s278 & -s279, fill=m20) -c6136 = mcdc.cell(+s236 & -s237 & +s279 & -s280, fill=m21) -c6137 = mcdc.cell(+s236 & -s237 & +s280 & -s281, fill=m22) -c6138 = mcdc.cell(+s236 & -s237 & +s281 & -s282, fill=m23) -c6139 = mcdc.cell(+s236 & -s237 & +s282 & -s283, fill=m24) -c6140 = mcdc.cell(+s236 & -s237 & +s283 & -s284, fill=m25) -c6141 = mcdc.cell(+s236 & -s237 & +s284 & -s285, fill=m26) -c6142 = mcdc.cell(+s236 & -s237 & +s285, fill=m27) -c6143 = mcdc.cell(+s237 & -s238 & -s277, fill=m18) -c6144 = mcdc.cell(+s237 & -s238 & +s277 & -s278, fill=m19) -c6145 = mcdc.cell(+s237 & -s238 & +s278 & -s279, fill=m20) -c6146 = mcdc.cell(+s237 & -s238 & +s279 & -s280, fill=m21) -c6147 = mcdc.cell(+s237 & -s238 & +s280 & -s281, fill=m22) -c6148 = mcdc.cell(+s237 & -s238 & +s281 & -s282, fill=m23) -c6149 = mcdc.cell(+s237 & -s238 & +s282 & -s283, fill=m24) -c6150 = mcdc.cell(+s237 & -s238 & +s283 & -s284, fill=m25) -c6151 = mcdc.cell(+s237 & -s238 & +s284 & -s285, fill=m26) -c6152 = mcdc.cell(+s237 & -s238 & +s285, fill=m27) -c6153 = mcdc.cell(+s238 & -s239 & -s277, fill=m18) -c6154 = mcdc.cell(+s238 & -s239 & +s277 & -s278, fill=m19) -c6155 = mcdc.cell(+s238 & -s239 & +s278 & -s279, fill=m20) -c6156 = mcdc.cell(+s238 & -s239 & +s279 & -s280, fill=m21) -c6157 = mcdc.cell(+s238 & -s239 & +s280 & -s281, fill=m22) -c6158 = mcdc.cell(+s238 & -s239 & +s281 & -s282, fill=m23) -c6159 = mcdc.cell(+s238 & -s239 & +s282 & -s283, fill=m24) -c6160 = mcdc.cell(+s238 & -s239 & +s283 & -s284, fill=m25) -c6161 = mcdc.cell(+s238 & -s239 & +s284 & -s285, fill=m26) -c6162 = mcdc.cell(+s238 & -s239 & +s285, fill=m27) -c6163 = mcdc.cell(+s239 & -s240 & -s277, fill=m18) -c6164 = mcdc.cell(+s239 & -s240 & +s277 & -s278, fill=m19) -c6165 = mcdc.cell(+s239 & -s240 & +s278 & -s279, fill=m20) -c6166 = mcdc.cell(+s239 & -s240 & +s279 & -s280, fill=m21) -c6167 = mcdc.cell(+s239 & -s240 & +s280 & -s281, fill=m22) -c6168 = mcdc.cell(+s239 & -s240 & +s281 & -s282, fill=m23) -c6169 = mcdc.cell(+s239 & -s240 & +s282 & -s283, fill=m24) -c6170 = mcdc.cell(+s239 & -s240 & +s283 & -s284, fill=m25) -c6171 = mcdc.cell(+s239 & -s240 & +s284 & -s285, fill=m26) -c6172 = mcdc.cell(+s239 & -s240 & +s285, fill=m27) -c6173 = mcdc.cell(+s240 & -s241 & -s277, fill=m18) -c6174 = mcdc.cell(+s240 & -s241 & +s277 & -s278, fill=m19) -c6175 = mcdc.cell(+s240 & -s241 & +s278 & -s279, fill=m20) -c6176 = mcdc.cell(+s240 & -s241 & +s279 & -s280, fill=m21) -c6177 = mcdc.cell(+s240 & -s241 & +s280 & -s281, fill=m22) -c6178 = mcdc.cell(+s240 & -s241 & +s281 & -s282, fill=m23) -c6179 = mcdc.cell(+s240 & -s241 & +s282 & -s283, fill=m24) -c6180 = mcdc.cell(+s240 & -s241 & +s283 & -s284, fill=m25) -c6181 = mcdc.cell(+s240 & -s241 & +s284 & -s285, fill=m26) -c6182 = mcdc.cell(+s240 & -s241 & +s285, fill=m27) -c6183 = mcdc.cell(+s241 & -s242 & -s277, fill=m18) -c6184 = mcdc.cell(+s241 & -s242 & +s277 & -s278, fill=m19) -c6185 = mcdc.cell(+s241 & -s242 & +s278 & -s279, fill=m20) -c6186 = mcdc.cell(+s241 & -s242 & +s279 & -s280, fill=m21) -c6187 = mcdc.cell(+s241 & -s242 & +s280 & -s281, fill=m22) -c6188 = mcdc.cell(+s241 & -s242 & +s281 & -s282, fill=m23) -c6189 = mcdc.cell(+s241 & -s242 & +s282 & -s283, fill=m24) -c6190 = mcdc.cell(+s241 & -s242 & +s283 & -s284, fill=m25) -c6191 = mcdc.cell(+s241 & -s242 & +s284 & -s285, fill=m26) -c6192 = mcdc.cell(+s241 & -s242 & +s285, fill=m27) -c6193 = mcdc.cell(+s242 & -s243 & -s277, fill=m18) -c6194 = mcdc.cell(+s242 & -s243 & +s277 & -s278, fill=m19) -c6195 = mcdc.cell(+s242 & -s243 & +s278 & -s279, fill=m20) -c6196 = mcdc.cell(+s242 & -s243 & +s279 & -s280, fill=m21) -c6197 = mcdc.cell(+s242 & -s243 & +s280 & -s281, fill=m22) -c6198 = mcdc.cell(+s242 & -s243 & +s281 & -s282, fill=m23) -c6199 = mcdc.cell(+s242 & -s243 & +s282 & -s283, fill=m24) -c6200 = mcdc.cell(+s242 & -s243 & +s283 & -s284, fill=m25) -c6201 = mcdc.cell(+s242 & -s243 & +s284 & -s285, fill=m26) -c6202 = mcdc.cell(+s242 & -s243 & +s285, fill=m27) -c6203 = mcdc.cell(+s243 & -s244 & -s277, fill=m18) -c6204 = mcdc.cell(+s243 & -s244 & +s277 & -s278, fill=m19) -c6205 = mcdc.cell(+s243 & -s244 & +s278 & -s279, fill=m20) -c6206 = mcdc.cell(+s243 & -s244 & +s279 & -s280, fill=m21) -c6207 = mcdc.cell(+s243 & -s244 & +s280 & -s281, fill=m22) -c6208 = mcdc.cell(+s243 & -s244 & +s281 & -s282, fill=m23) -c6209 = mcdc.cell(+s243 & -s244 & +s282 & -s283, fill=m24) -c6210 = mcdc.cell(+s243 & -s244 & +s283 & -s284, fill=m25) -c6211 = mcdc.cell(+s243 & -s244 & +s284 & -s285, fill=m26) -c6212 = mcdc.cell(+s243 & -s244 & +s285, fill=m27) -c6213 = mcdc.cell(+s244 & -s245 & -s277, fill=m18) -c6214 = mcdc.cell(+s244 & -s245 & +s277 & -s278, fill=m19) -c6215 = mcdc.cell(+s244 & -s245 & +s278 & -s279, fill=m20) -c6216 = mcdc.cell(+s244 & -s245 & +s279 & -s280, fill=m21) -c6217 = mcdc.cell(+s244 & -s245 & +s280 & -s281, fill=m22) -c6218 = mcdc.cell(+s244 & -s245 & +s281 & -s282, fill=m23) -c6219 = mcdc.cell(+s244 & -s245 & +s282 & -s283, fill=m24) -c6220 = mcdc.cell(+s244 & -s245 & +s283 & -s284, fill=m25) -c6221 = mcdc.cell(+s244 & -s245 & +s284 & -s285, fill=m26) -c6222 = mcdc.cell(+s244 & -s245 & +s285, fill=m27) -c6223 = mcdc.cell(+s245 & -s246 & -s277, fill=m18) -c6224 = mcdc.cell(+s245 & -s246 & +s277 & -s278, fill=m19) -c6225 = mcdc.cell(+s245 & -s246 & +s278 & -s279, fill=m20) -c6226 = mcdc.cell(+s245 & -s246 & +s279 & -s280, fill=m21) -c6227 = mcdc.cell(+s245 & -s246 & +s280 & -s281, fill=m22) -c6228 = mcdc.cell(+s245 & -s246 & +s281 & -s282, fill=m23) -c6229 = mcdc.cell(+s245 & -s246 & +s282 & -s283, fill=m24) -c6230 = mcdc.cell(+s245 & -s246 & +s283 & -s284, fill=m25) -c6231 = mcdc.cell(+s245 & -s246 & +s284 & -s285, fill=m26) -c6232 = mcdc.cell(+s245 & -s246 & +s285, fill=m27) -c6233 = mcdc.cell(+s246 & -s247 & -s277, fill=m18) -c6234 = mcdc.cell(+s246 & -s247 & +s277 & -s278, fill=m19) -c6235 = mcdc.cell(+s246 & -s247 & +s278 & -s279, fill=m20) -c6236 = mcdc.cell(+s246 & -s247 & +s279 & -s280, fill=m21) -c6237 = mcdc.cell(+s246 & -s247 & +s280 & -s281, fill=m22) -c6238 = mcdc.cell(+s246 & -s247 & +s281 & -s282, fill=m23) -c6239 = mcdc.cell(+s246 & -s247 & +s282 & -s283, fill=m24) -c6240 = mcdc.cell(+s246 & -s247 & +s283 & -s284, fill=m25) -c6241 = mcdc.cell(+s246 & -s247 & +s284 & -s285, fill=m26) -c6242 = mcdc.cell(+s246 & -s247 & +s285, fill=m27) -c6243 = mcdc.cell(+s247 & -s248 & -s277, fill=m18) -c6244 = mcdc.cell(+s247 & -s248 & +s277 & -s278, fill=m19) -c6245 = mcdc.cell(+s247 & -s248 & +s278 & -s279, fill=m20) -c6246 = mcdc.cell(+s247 & -s248 & +s279 & -s280, fill=m21) -c6247 = mcdc.cell(+s247 & -s248 & +s280 & -s281, fill=m22) -c6248 = mcdc.cell(+s247 & -s248 & +s281 & -s282, fill=m23) -c6249 = mcdc.cell(+s247 & -s248 & +s282 & -s283, fill=m24) -c6250 = mcdc.cell(+s247 & -s248 & +s283 & -s284, fill=m25) -c6251 = mcdc.cell(+s247 & -s248 & +s284 & -s285, fill=m26) -c6252 = mcdc.cell(+s247 & -s248 & +s285, fill=m27) -c6253 = mcdc.cell(+s248 & -s249 & -s277, fill=m18) -c6254 = mcdc.cell(+s248 & -s249 & +s277 & -s278, fill=m19) -c6255 = mcdc.cell(+s248 & -s249 & +s278 & -s279, fill=m20) -c6256 = mcdc.cell(+s248 & -s249 & +s279 & -s280, fill=m21) -c6257 = mcdc.cell(+s248 & -s249 & +s280 & -s281, fill=m22) -c6258 = mcdc.cell(+s248 & -s249 & +s281 & -s282, fill=m23) -c6259 = mcdc.cell(+s248 & -s249 & +s282 & -s283, fill=m24) -c6260 = mcdc.cell(+s248 & -s249 & +s283 & -s284, fill=m25) -c6261 = mcdc.cell(+s248 & -s249 & +s284 & -s285, fill=m26) -c6262 = mcdc.cell(+s248 & -s249 & +s285, fill=m27) -c6263 = mcdc.cell(+s249 & -s250 & -s277, fill=m18) -c6264 = mcdc.cell(+s249 & -s250 & +s277 & -s278, fill=m19) -c6265 = mcdc.cell(+s249 & -s250 & +s278 & -s279, fill=m20) -c6266 = mcdc.cell(+s249 & -s250 & +s279 & -s280, fill=m21) -c6267 = mcdc.cell(+s249 & -s250 & +s280 & -s281, fill=m22) -c6268 = mcdc.cell(+s249 & -s250 & +s281 & -s282, fill=m23) -c6269 = mcdc.cell(+s249 & -s250 & +s282 & -s283, fill=m24) -c6270 = mcdc.cell(+s249 & -s250 & +s283 & -s284, fill=m25) -c6271 = mcdc.cell(+s249 & -s250 & +s284 & -s285, fill=m26) -c6272 = mcdc.cell(+s249 & -s250 & +s285, fill=m27) -c6273 = mcdc.cell(+s250 & -s251 & -s277, fill=m18) -c6274 = mcdc.cell(+s250 & -s251 & +s277 & -s278, fill=m19) -c6275 = mcdc.cell(+s250 & -s251 & +s278 & -s279, fill=m20) -c6276 = mcdc.cell(+s250 & -s251 & +s279 & -s280, fill=m21) -c6277 = mcdc.cell(+s250 & -s251 & +s280 & -s281, fill=m22) -c6278 = mcdc.cell(+s250 & -s251 & +s281 & -s282, fill=m23) -c6279 = mcdc.cell(+s250 & -s251 & +s282 & -s283, fill=m24) -c6280 = mcdc.cell(+s250 & -s251 & +s283 & -s284, fill=m25) -c6281 = mcdc.cell(+s250 & -s251 & +s284 & -s285, fill=m26) -c6282 = mcdc.cell(+s250 & -s251 & +s285, fill=m27) -c6283 = mcdc.cell(+s251 & -s252 & -s277, fill=m18) -c6284 = mcdc.cell(+s251 & -s252 & +s277 & -s278, fill=m19) -c6285 = mcdc.cell(+s251 & -s252 & +s278 & -s279, fill=m20) -c6286 = mcdc.cell(+s251 & -s252 & +s279 & -s280, fill=m21) -c6287 = mcdc.cell(+s251 & -s252 & +s280 & -s281, fill=m22) -c6288 = mcdc.cell(+s251 & -s252 & +s281 & -s282, fill=m23) -c6289 = mcdc.cell(+s251 & -s252 & +s282 & -s283, fill=m24) -c6290 = mcdc.cell(+s251 & -s252 & +s283 & -s284, fill=m25) -c6291 = mcdc.cell(+s251 & -s252 & +s284 & -s285, fill=m26) -c6292 = mcdc.cell(+s251 & -s252 & +s285, fill=m27) -c6293 = mcdc.cell(+s252 & -s253 & -s277, fill=m18) -c6294 = mcdc.cell(+s252 & -s253 & +s277 & -s278, fill=m19) -c6295 = mcdc.cell(+s252 & -s253 & +s278 & -s279, fill=m20) -c6296 = mcdc.cell(+s252 & -s253 & +s279 & -s280, fill=m21) -c6297 = mcdc.cell(+s252 & -s253 & +s280 & -s281, fill=m22) -c6298 = mcdc.cell(+s252 & -s253 & +s281 & -s282, fill=m23) -c6299 = mcdc.cell(+s252 & -s253 & +s282 & -s283, fill=m24) -c6300 = mcdc.cell(+s252 & -s253 & +s283 & -s284, fill=m25) -c6301 = mcdc.cell(+s252 & -s253 & +s284 & -s285, fill=m26) -c6302 = mcdc.cell(+s252 & -s253 & +s285, fill=m27) -c6303 = mcdc.cell(+s253 & -s254 & -s277, fill=m18) -c6304 = mcdc.cell(+s253 & -s254 & +s277 & -s278, fill=m19) -c6305 = mcdc.cell(+s253 & -s254 & +s278 & -s279, fill=m20) -c6306 = mcdc.cell(+s253 & -s254 & +s279 & -s280, fill=m21) -c6307 = mcdc.cell(+s253 & -s254 & +s280 & -s281, fill=m22) -c6308 = mcdc.cell(+s253 & -s254 & +s281 & -s282, fill=m23) -c6309 = mcdc.cell(+s253 & -s254 & +s282 & -s283, fill=m24) -c6310 = mcdc.cell(+s253 & -s254 & +s283 & -s284, fill=m25) -c6311 = mcdc.cell(+s253 & -s254 & +s284 & -s285, fill=m26) -c6312 = mcdc.cell(+s253 & -s254 & +s285, fill=m27) -c6313 = mcdc.cell(+s254 & -s255 & -s277, fill=m18) -c6314 = mcdc.cell(+s254 & -s255 & +s277 & -s278, fill=m19) -c6315 = mcdc.cell(+s254 & -s255 & +s278 & -s279, fill=m20) -c6316 = mcdc.cell(+s254 & -s255 & +s279 & -s280, fill=m21) -c6317 = mcdc.cell(+s254 & -s255 & +s280 & -s281, fill=m22) -c6318 = mcdc.cell(+s254 & -s255 & +s281 & -s282, fill=m23) -c6319 = mcdc.cell(+s254 & -s255 & +s282 & -s283, fill=m24) -c6320 = mcdc.cell(+s254 & -s255 & +s283 & -s284, fill=m25) -c6321 = mcdc.cell(+s254 & -s255 & +s284 & -s285, fill=m26) -c6322 = mcdc.cell(+s254 & -s255 & +s285, fill=m27) -c6323 = mcdc.cell(+s255 & -s256 & -s277, fill=m18) -c6324 = mcdc.cell(+s255 & -s256 & +s277 & -s278, fill=m19) -c6325 = mcdc.cell(+s255 & -s256 & +s278 & -s279, fill=m20) -c6326 = mcdc.cell(+s255 & -s256 & +s279 & -s280, fill=m21) -c6327 = mcdc.cell(+s255 & -s256 & +s280 & -s281, fill=m22) -c6328 = mcdc.cell(+s255 & -s256 & +s281 & -s282, fill=m23) -c6329 = mcdc.cell(+s255 & -s256 & +s282 & -s283, fill=m24) -c6330 = mcdc.cell(+s255 & -s256 & +s283 & -s284, fill=m25) -c6331 = mcdc.cell(+s255 & -s256 & +s284 & -s285, fill=m26) -c6332 = mcdc.cell(+s255 & -s256 & +s285, fill=m27) -c6333 = mcdc.cell(+s256 & -s257 & -s277, fill=m18) -c6334 = mcdc.cell(+s256 & -s257 & +s277 & -s278, fill=m19) -c6335 = mcdc.cell(+s256 & -s257 & +s278 & -s279, fill=m20) -c6336 = mcdc.cell(+s256 & -s257 & +s279 & -s280, fill=m21) -c6337 = mcdc.cell(+s256 & -s257 & +s280 & -s281, fill=m22) -c6338 = mcdc.cell(+s256 & -s257 & +s281 & -s282, fill=m23) -c6339 = mcdc.cell(+s256 & -s257 & +s282 & -s283, fill=m24) -c6340 = mcdc.cell(+s256 & -s257 & +s283 & -s284, fill=m25) -c6341 = mcdc.cell(+s256 & -s257 & +s284 & -s285, fill=m26) -c6342 = mcdc.cell(+s256 & -s257 & +s285, fill=m27) -c6343 = mcdc.cell(+s257 & -s258 & -s277, fill=m18) -c6344 = mcdc.cell(+s257 & -s258 & +s277 & -s278, fill=m19) -c6345 = mcdc.cell(+s257 & -s258 & +s278 & -s279, fill=m20) -c6346 = mcdc.cell(+s257 & -s258 & +s279 & -s280, fill=m21) -c6347 = mcdc.cell(+s257 & -s258 & +s280 & -s281, fill=m22) -c6348 = mcdc.cell(+s257 & -s258 & +s281 & -s282, fill=m23) -c6349 = mcdc.cell(+s257 & -s258 & +s282 & -s283, fill=m24) -c6350 = mcdc.cell(+s257 & -s258 & +s283 & -s284, fill=m25) -c6351 = mcdc.cell(+s257 & -s258 & +s284 & -s285, fill=m26) -c6352 = mcdc.cell(+s257 & -s258 & +s285, fill=m27) -c6353 = mcdc.cell(+s258 & -s259 & -s277, fill=m18) -c6354 = mcdc.cell(+s258 & -s259 & +s277 & -s278, fill=m19) -c6355 = mcdc.cell(+s258 & -s259 & +s278 & -s279, fill=m20) -c6356 = mcdc.cell(+s258 & -s259 & +s279 & -s280, fill=m21) -c6357 = mcdc.cell(+s258 & -s259 & +s280 & -s281, fill=m22) -c6358 = mcdc.cell(+s258 & -s259 & +s281 & -s282, fill=m23) -c6359 = mcdc.cell(+s258 & -s259 & +s282 & -s283, fill=m24) -c6360 = mcdc.cell(+s258 & -s259 & +s283 & -s284, fill=m25) -c6361 = mcdc.cell(+s258 & -s259 & +s284 & -s285, fill=m26) -c6362 = mcdc.cell(+s258 & -s259 & +s285, fill=m27) -c6363 = mcdc.cell(+s259 & -s260 & -s277, fill=m18) -c6364 = mcdc.cell(+s259 & -s260 & +s277 & -s278, fill=m19) -c6365 = mcdc.cell(+s259 & -s260 & +s278 & -s279, fill=m20) -c6366 = mcdc.cell(+s259 & -s260 & +s279 & -s280, fill=m21) -c6367 = mcdc.cell(+s259 & -s260 & +s280 & -s281, fill=m22) -c6368 = mcdc.cell(+s259 & -s260 & +s281 & -s282, fill=m23) -c6369 = mcdc.cell(+s259 & -s260 & +s282 & -s283, fill=m24) -c6370 = mcdc.cell(+s259 & -s260 & +s283 & -s284, fill=m25) -c6371 = mcdc.cell(+s259 & -s260 & +s284 & -s285, fill=m26) -c6372 = mcdc.cell(+s259 & -s260 & +s285, fill=m27) -c6373 = mcdc.cell(+s260 & -s261 & -s277, fill=m18) -c6374 = mcdc.cell(+s260 & -s261 & +s277 & -s278, fill=m19) -c6375 = mcdc.cell(+s260 & -s261 & +s278 & -s279, fill=m20) -c6376 = mcdc.cell(+s260 & -s261 & +s279 & -s280, fill=m21) -c6377 = mcdc.cell(+s260 & -s261 & +s280 & -s281, fill=m22) -c6378 = mcdc.cell(+s260 & -s261 & +s281 & -s282, fill=m23) -c6379 = mcdc.cell(+s260 & -s261 & +s282 & -s283, fill=m24) -c6380 = mcdc.cell(+s260 & -s261 & +s283 & -s284, fill=m25) -c6381 = mcdc.cell(+s260 & -s261 & +s284 & -s285, fill=m26) -c6382 = mcdc.cell(+s260 & -s261 & +s285, fill=m27) -c6383 = mcdc.cell(+s261 & -s262 & -s277, fill=m18) -c6384 = mcdc.cell(+s261 & -s262 & +s277 & -s278, fill=m19) -c6385 = mcdc.cell(+s261 & -s262 & +s278 & -s279, fill=m20) -c6386 = mcdc.cell(+s261 & -s262 & +s279 & -s280, fill=m21) -c6387 = mcdc.cell(+s261 & -s262 & +s280 & -s281, fill=m22) -c6388 = mcdc.cell(+s261 & -s262 & +s281 & -s282, fill=m23) -c6389 = mcdc.cell(+s261 & -s262 & +s282 & -s283, fill=m24) -c6390 = mcdc.cell(+s261 & -s262 & +s283 & -s284, fill=m25) -c6391 = mcdc.cell(+s261 & -s262 & +s284 & -s285, fill=m26) -c6392 = mcdc.cell(+s261 & -s262 & +s285, fill=m27) -c6393 = mcdc.cell(+s262 & -s263 & -s277, fill=m18) -c6394 = mcdc.cell(+s262 & -s263 & +s277 & -s278, fill=m19) -c6395 = mcdc.cell(+s262 & -s263 & +s278 & -s279, fill=m20) -c6396 = mcdc.cell(+s262 & -s263 & +s279 & -s280, fill=m21) -c6397 = mcdc.cell(+s262 & -s263 & +s280 & -s281, fill=m22) -c6398 = mcdc.cell(+s262 & -s263 & +s281 & -s282, fill=m23) -c6399 = mcdc.cell(+s262 & -s263 & +s282 & -s283, fill=m24) -c6400 = mcdc.cell(+s262 & -s263 & +s283 & -s284, fill=m25) -c6401 = mcdc.cell(+s262 & -s263 & +s284 & -s285, fill=m26) -c6402 = mcdc.cell(+s262 & -s263 & +s285, fill=m27) -c6403 = mcdc.cell(+s263 & -s264 & -s277, fill=m18) -c6404 = mcdc.cell(+s263 & -s264 & +s277 & -s278, fill=m19) -c6405 = mcdc.cell(+s263 & -s264 & +s278 & -s279, fill=m20) -c6406 = mcdc.cell(+s263 & -s264 & +s279 & -s280, fill=m21) -c6407 = mcdc.cell(+s263 & -s264 & +s280 & -s281, fill=m22) -c6408 = mcdc.cell(+s263 & -s264 & +s281 & -s282, fill=m23) -c6409 = mcdc.cell(+s263 & -s264 & +s282 & -s283, fill=m24) -c6410 = mcdc.cell(+s263 & -s264 & +s283 & -s284, fill=m25) -c6411 = mcdc.cell(+s263 & -s264 & +s284 & -s285, fill=m26) -c6412 = mcdc.cell(+s263 & -s264 & +s285, fill=m27) -c6413 = mcdc.cell(+s264 & -s265 & -s277, fill=m18) -c6414 = mcdc.cell(+s264 & -s265 & +s277 & -s278, fill=m19) -c6415 = mcdc.cell(+s264 & -s265 & +s278 & -s279, fill=m20) -c6416 = mcdc.cell(+s264 & -s265 & +s279 & -s280, fill=m21) -c6417 = mcdc.cell(+s264 & -s265 & +s280 & -s281, fill=m22) -c6418 = mcdc.cell(+s264 & -s265 & +s281 & -s282, fill=m23) -c6419 = mcdc.cell(+s264 & -s265 & +s282 & -s283, fill=m24) -c6420 = mcdc.cell(+s264 & -s265 & +s283 & -s284, fill=m25) -c6421 = mcdc.cell(+s264 & -s265 & +s284 & -s285, fill=m26) -c6422 = mcdc.cell(+s264 & -s265 & +s285, fill=m27) -c6423 = mcdc.cell(+s265 & -s266 & -s277, fill=m18) -c6424 = mcdc.cell(+s265 & -s266 & +s277 & -s278, fill=m19) -c6425 = mcdc.cell(+s265 & -s266 & +s278 & -s279, fill=m20) -c6426 = mcdc.cell(+s265 & -s266 & +s279 & -s280, fill=m21) -c6427 = mcdc.cell(+s265 & -s266 & +s280 & -s281, fill=m22) -c6428 = mcdc.cell(+s265 & -s266 & +s281 & -s282, fill=m23) -c6429 = mcdc.cell(+s265 & -s266 & +s282 & -s283, fill=m24) -c6430 = mcdc.cell(+s265 & -s266 & +s283 & -s284, fill=m25) -c6431 = mcdc.cell(+s265 & -s266 & +s284 & -s285, fill=m26) -c6432 = mcdc.cell(+s265 & -s266 & +s285, fill=m27) -c6433 = mcdc.cell(+s266 & -s267 & -s277, fill=m18) -c6434 = mcdc.cell(+s266 & -s267 & +s277 & -s278, fill=m19) -c6435 = mcdc.cell(+s266 & -s267 & +s278 & -s279, fill=m20) -c6436 = mcdc.cell(+s266 & -s267 & +s279 & -s280, fill=m21) -c6437 = mcdc.cell(+s266 & -s267 & +s280 & -s281, fill=m22) -c6438 = mcdc.cell(+s266 & -s267 & +s281 & -s282, fill=m23) -c6439 = mcdc.cell(+s266 & -s267 & +s282 & -s283, fill=m24) -c6440 = mcdc.cell(+s266 & -s267 & +s283 & -s284, fill=m25) -c6441 = mcdc.cell(+s266 & -s267 & +s284 & -s285, fill=m26) -c6442 = mcdc.cell(+s266 & -s267 & +s285, fill=m27) -c6443 = mcdc.cell(+s267 & -s268 & -s277, fill=m18) -c6444 = mcdc.cell(+s267 & -s268 & +s277 & -s278, fill=m19) -c6445 = mcdc.cell(+s267 & -s268 & +s278 & -s279, fill=m20) -c6446 = mcdc.cell(+s267 & -s268 & +s279 & -s280, fill=m21) -c6447 = mcdc.cell(+s267 & -s268 & +s280 & -s281, fill=m22) -c6448 = mcdc.cell(+s267 & -s268 & +s281 & -s282, fill=m23) -c6449 = mcdc.cell(+s267 & -s268 & +s282 & -s283, fill=m24) -c6450 = mcdc.cell(+s267 & -s268 & +s283 & -s284, fill=m25) -c6451 = mcdc.cell(+s267 & -s268 & +s284 & -s285, fill=m26) -c6452 = mcdc.cell(+s267 & -s268 & +s285, fill=m27) -c6453 = mcdc.cell(+s268 & -s269 & -s277, fill=m18) -c6454 = mcdc.cell(+s268 & -s269 & +s277 & -s278, fill=m19) -c6455 = mcdc.cell(+s268 & -s269 & +s278 & -s279, fill=m20) -c6456 = mcdc.cell(+s268 & -s269 & +s279 & -s280, fill=m21) -c6457 = mcdc.cell(+s268 & -s269 & +s280 & -s281, fill=m22) -c6458 = mcdc.cell(+s268 & -s269 & +s281 & -s282, fill=m23) -c6459 = mcdc.cell(+s268 & -s269 & +s282 & -s283, fill=m24) -c6460 = mcdc.cell(+s268 & -s269 & +s283 & -s284, fill=m25) -c6461 = mcdc.cell(+s268 & -s269 & +s284 & -s285, fill=m26) -c6462 = mcdc.cell(+s268 & -s269 & +s285, fill=m27) -c6463 = mcdc.cell(+s269 & -s270 & -s277, fill=m18) -c6464 = mcdc.cell(+s269 & -s270 & +s277 & -s278, fill=m19) -c6465 = mcdc.cell(+s269 & -s270 & +s278 & -s279, fill=m20) -c6466 = mcdc.cell(+s269 & -s270 & +s279 & -s280, fill=m21) -c6467 = mcdc.cell(+s269 & -s270 & +s280 & -s281, fill=m22) -c6468 = mcdc.cell(+s269 & -s270 & +s281 & -s282, fill=m23) -c6469 = mcdc.cell(+s269 & -s270 & +s282 & -s283, fill=m24) -c6470 = mcdc.cell(+s269 & -s270 & +s283 & -s284, fill=m25) -c6471 = mcdc.cell(+s269 & -s270 & +s284 & -s285, fill=m26) -c6472 = mcdc.cell(+s269 & -s270 & +s285, fill=m27) -c6473 = mcdc.cell(+s270 & -s271 & -s277, fill=m18) -c6474 = mcdc.cell(+s270 & -s271 & +s277 & -s278, fill=m19) -c6475 = mcdc.cell(+s270 & -s271 & +s278 & -s279, fill=m20) -c6476 = mcdc.cell(+s270 & -s271 & +s279 & -s280, fill=m21) -c6477 = mcdc.cell(+s270 & -s271 & +s280 & -s281, fill=m22) -c6478 = mcdc.cell(+s270 & -s271 & +s281 & -s282, fill=m23) -c6479 = mcdc.cell(+s270 & -s271 & +s282 & -s283, fill=m24) -c6480 = mcdc.cell(+s270 & -s271 & +s283 & -s284, fill=m25) -c6481 = mcdc.cell(+s270 & -s271 & +s284 & -s285, fill=m26) -c6482 = mcdc.cell(+s270 & -s271 & +s285, fill=m27) -c6483 = mcdc.cell(+s271 & -s272 & -s277, fill=m18) -c6484 = mcdc.cell(+s271 & -s272 & +s277 & -s278, fill=m19) -c6485 = mcdc.cell(+s271 & -s272 & +s278 & -s279, fill=m20) -c6486 = mcdc.cell(+s271 & -s272 & +s279 & -s280, fill=m21) -c6487 = mcdc.cell(+s271 & -s272 & +s280 & -s281, fill=m22) -c6488 = mcdc.cell(+s271 & -s272 & +s281 & -s282, fill=m23) -c6489 = mcdc.cell(+s271 & -s272 & +s282 & -s283, fill=m24) -c6490 = mcdc.cell(+s271 & -s272 & +s283 & -s284, fill=m25) -c6491 = mcdc.cell(+s271 & -s272 & +s284 & -s285, fill=m26) -c6492 = mcdc.cell(+s271 & -s272 & +s285, fill=m27) -c6493 = mcdc.cell(+s272 & -s273 & -s277, fill=m18) -c6494 = mcdc.cell(+s272 & -s273 & +s277 & -s278, fill=m19) -c6495 = mcdc.cell(+s272 & -s273 & +s278 & -s279, fill=m20) -c6496 = mcdc.cell(+s272 & -s273 & +s279 & -s280, fill=m21) -c6497 = mcdc.cell(+s272 & -s273 & +s280 & -s281, fill=m22) -c6498 = mcdc.cell(+s272 & -s273 & +s281 & -s282, fill=m23) -c6499 = mcdc.cell(+s272 & -s273 & +s282 & -s283, fill=m24) -c6500 = mcdc.cell(+s272 & -s273 & +s283 & -s284, fill=m25) -c6501 = mcdc.cell(+s272 & -s273 & +s284 & -s285, fill=m26) -c6502 = mcdc.cell(+s272 & -s273 & +s285, fill=m27) -c6503 = mcdc.cell(+s273 & -s274 & -s277, fill=m18) -c6504 = mcdc.cell(+s273 & -s274 & +s277 & -s278, fill=m19) -c6505 = mcdc.cell(+s273 & -s274 & +s278 & -s279, fill=m20) -c6506 = mcdc.cell(+s273 & -s274 & +s279 & -s280, fill=m21) -c6507 = mcdc.cell(+s273 & -s274 & +s280 & -s281, fill=m22) -c6508 = mcdc.cell(+s273 & -s274 & +s281 & -s282, fill=m23) -c6509 = mcdc.cell(+s273 & -s274 & +s282 & -s283, fill=m24) -c6510 = mcdc.cell(+s273 & -s274 & +s283 & -s284, fill=m25) -c6511 = mcdc.cell(+s273 & -s274 & +s284 & -s285, fill=m26) -c6512 = mcdc.cell(+s273 & -s274 & +s285, fill=m27) -c6513 = mcdc.cell(+s274 & -s275 & -s277, fill=m18) -c6514 = mcdc.cell(+s274 & -s275 & +s277 & -s278, fill=m19) -c6515 = mcdc.cell(+s274 & -s275 & +s278 & -s279, fill=m20) -c6516 = mcdc.cell(+s274 & -s275 & +s279 & -s280, fill=m21) -c6517 = mcdc.cell(+s274 & -s275 & +s280 & -s281, fill=m22) -c6518 = mcdc.cell(+s274 & -s275 & +s281 & -s282, fill=m23) -c6519 = mcdc.cell(+s274 & -s275 & +s282 & -s283, fill=m24) -c6520 = mcdc.cell(+s274 & -s275 & +s283 & -s284, fill=m25) -c6521 = mcdc.cell(+s274 & -s275 & +s284 & -s285, fill=m26) -c6522 = mcdc.cell(+s274 & -s275 & +s285, fill=m27) -c6523 = mcdc.cell(+s275 & -s276 & -s277, fill=m18) -c6524 = mcdc.cell(+s275 & -s276 & +s277 & -s278, fill=m19) -c6525 = mcdc.cell(+s275 & -s276 & +s278 & -s279, fill=m20) -c6526 = mcdc.cell(+s275 & -s276 & +s279 & -s280, fill=m21) -c6527 = mcdc.cell(+s275 & -s276 & +s280 & -s281, fill=m22) -c6528 = mcdc.cell(+s275 & -s276 & +s281 & -s282, fill=m23) -c6529 = mcdc.cell(+s275 & -s276 & +s282 & -s283, fill=m24) -c6530 = mcdc.cell(+s275 & -s276 & +s283 & -s284, fill=m25) -c6531 = mcdc.cell(+s275 & -s276 & +s284 & -s285, fill=m26) -c6532 = mcdc.cell(+s275 & -s276 & +s285, fill=m27) -c6533 = mcdc.cell(+s276 & -s277, fill=m18) -c6534 = mcdc.cell(+s276 & +s277 & -s278, fill=m19) -c6535 = mcdc.cell(+s276 & +s278 & -s279, fill=m20) -c6536 = mcdc.cell(+s276 & +s279 & -s280, fill=m21) -c6537 = mcdc.cell(+s276 & +s280 & -s281, fill=m22) -c6538 = mcdc.cell(+s276 & +s281 & -s282, fill=m23) -c6539 = mcdc.cell(+s276 & +s282 & -s283, fill=m24) -c6540 = mcdc.cell(+s276 & +s283 & -s284, fill=m25) -c6541 = mcdc.cell(+s276 & +s284 & -s285, fill=m26) -c6542 = mcdc.cell(+s276 & +s285, fill=m27) -c6767 = mcdc.cell( - ~(+s28 & -s29 & +s30 & -s31), fill=m10 -) # Name: Assembly (1.6%) no BAs lattice outer water -c6768 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & -s38, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (0) -c6769 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s38 & -s39, fill=m3 -) # Name: Assembly (1.6%) no BAs lattice axial (1) -c6770 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s39 & -s40, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (2) -c6771 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s40 & -s41, fill=m7 -) # Name: Assembly (1.6%) no BAs lattice axial (3) -c6772 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s41 & -s42, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (4) -c6773 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s42 & -s43, fill=m7 -) # Name: Assembly (1.6%) no BAs lattice axial (5) -c6774 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s43 & -s44, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (6) -c6775 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s44 & -s45, fill=m7 -) # Name: Assembly (1.6%) no BAs lattice axial (7) -c6776 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s45 & -s46, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (8) -c6777 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s46 & -s47, fill=m7 -) # Name: Assembly (1.6%) no BAs lattice axial (9) -c6778 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s47, fill=m10 -) # Name: Assembly (1.6%) no BAs lattice axial (last) -c7001 = mcdc.cell( - ~(+s28 & -s29 & +s30 & -s31), fill=m10 -) # Name: Assembly (2.4%) no BAs lattice outer water -c7002 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & -s38, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (0) -c7003 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s38 & -s39, fill=m3 -) # Name: Assembly (2.4%) no BAs lattice axial (1) -c7004 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s39 & -s40, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (2) -c7005 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s40 & -s41, fill=m7 -) # Name: Assembly (2.4%) no BAs lattice axial (3) -c7006 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s41 & -s42, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (4) -c7007 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s42 & -s43, fill=m7 -) # Name: Assembly (2.4%) no BAs lattice axial (5) -c7008 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s43 & -s44, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (6) -c7009 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s44 & -s45, fill=m7 -) # Name: Assembly (2.4%) no BAs lattice axial (7) -c7010 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s45 & -s46, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (8) -c7011 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s46 & -s47, fill=m7 -) # Name: Assembly (2.4%) no BAs lattice axial (9) -c7012 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s47, fill=m10 -) # Name: Assembly (2.4%) no BAs lattice axial (last) -c7053 = mcdc.cell( - ~(+s28 & -s29 & +s30 & -s31), fill=m10 -) # Name: Assembly (3.1%) no BAs lattice outer water -c7054 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & -s38, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (0) -c7055 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s38 & -s39, fill=m3 -) # Name: Assembly (3.1%) no BAs lattice axial (1) -c7056 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s39 & -s40, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (2) -c7057 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s40 & -s41, fill=m7 -) # Name: Assembly (3.1%) no BAs lattice axial (3) -c7058 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s41 & -s42, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (4) -c7059 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s42 & -s43, fill=m7 -) # Name: Assembly (3.1%) no BAs lattice axial (5) -c7060 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s43 & -s44, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (6) -c7061 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s44 & -s45, fill=m7 -) # Name: Assembly (3.1%) no BAs lattice axial (7) -c7062 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s45 & -s46, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (8) -c7063 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s46 & -s47, fill=m7 -) # Name: Assembly (3.1%) no BAs lattice axial (9) -c7064 = mcdc.cell( - +s28 & -s29 & +s30 & -s31 & ~(+s24 & -s25 & +s26 & -s27) & +s47, fill=m10 -) # Name: Assembly (3.1%) no BAs lattice axial (last) -c7104 = mcdc.cell(-s286, fill=m10) -c7105 = mcdc.cell(-s287, fill=m10) -c7106 = mcdc.cell(-s288, fill=m10) -c7107 = mcdc.cell(-s289, fill=m10) -c7108 = mcdc.cell(-s290, fill=m10) -c7109 = mcdc.cell(-s291, fill=m10) -c7110 = mcdc.cell(-s292, fill=m10) -c7111 = mcdc.cell(-s293, fill=m10) -c7112 = mcdc.cell(-s294, fill=m10) -c7113 = mcdc.cell(-s295, fill=m10) -c7114 = mcdc.cell(-s296, fill=m10) -c7115 = mcdc.cell(-s297, fill=m10) -c7116 = mcdc.cell(-s298, fill=m10) -c7117 = mcdc.cell( - +s286 - & +s287 - & +s288 - & +s289 - & +s290 - & +s291 - & +s292 - & +s293 - & +s294 - & +s295 - & +s296 - & +s297 - & +s298, - fill=m5, -) # Name: reflector NW SS -c7118 = mcdc.cell(-s299, fill=m10) -c7119 = mcdc.cell(-s300, fill=m10) -c7120 = mcdc.cell(-s301, fill=m10) -c7121 = mcdc.cell(+s299 & +s300 & +s301, fill=m5) # Name: reflector 1,1 SS -c7122 = mcdc.cell(-s302, fill=m10) -c7123 = mcdc.cell(-s303, fill=m10) -c7124 = mcdc.cell(-s304, fill=m10) -c7125 = mcdc.cell(-s305, fill=m10) -c7126 = mcdc.cell(-s306, fill=m10) -c7127 = mcdc.cell(-s307, fill=m10) -c7128 = mcdc.cell(-s308, fill=m10) -c7129 = mcdc.cell(-s309, fill=m10) -c7130 = mcdc.cell(-s310, fill=m10) -c7131 = mcdc.cell(-s311, fill=m10) -c7132 = mcdc.cell(-s312, fill=m10) -c7133 = mcdc.cell( - +s302 - & +s303 - & +s304 - & +s305 - & +s306 - & +s307 - & +s308 - & +s309 - & +s310 - & +s311 - & +s312, - fill=m5, -) # Name: reflector 4,0 SS -c7134 = mcdc.cell(-s313, fill=m10) -c7135 = mcdc.cell(-s314, fill=m10) -c7136 = mcdc.cell(-s315, fill=m10) -c7137 = mcdc.cell(-s316, fill=m10) -c7138 = mcdc.cell(-s317, fill=m10) -c7139 = mcdc.cell(-s318, fill=m10) -c7140 = mcdc.cell(-s319, fill=m10) -c7141 = mcdc.cell(-s320, fill=m10) -c7142 = mcdc.cell(-s321, fill=m10) -c7143 = mcdc.cell(-s322, fill=m10) -c7144 = mcdc.cell( - +s313 & +s314 & +s315 & +s316 & +s317 & +s318 & +s319 & +s320 & +s321 & +s322, - fill=m5, -) # Name: reflector 3,0 SS -c7145 = mcdc.cell(-s323, fill=m10) -c7146 = mcdc.cell(-s324, fill=m10) -c7147 = mcdc.cell(-s325, fill=m10) -c7148 = mcdc.cell(-s326, fill=m10) -c7149 = mcdc.cell(-s327, fill=m10) -c7150 = mcdc.cell(-s328, fill=m10) -c7151 = mcdc.cell(-s329, fill=m10) -c7152 = mcdc.cell(-s330, fill=m10) -c7153 = mcdc.cell(-s331, fill=m10) -c7154 = mcdc.cell(-s332, fill=m10) -c7155 = mcdc.cell( - +s323 & +s324 & +s325 & +s326 & +s327 & +s328 & +s329 & +s330 & +s331 & +s332, - fill=m5, -) # Name: reflector 5,0 SS -c7156 = mcdc.cell(-s333, fill=m10) -c7157 = mcdc.cell(+s333, fill=m5) # Name: reflector 2,0 SS -c7180 = mcdc.cell(fill=m5) # Name: heavy reflector -c7182 = mcdc.cell(+s71 & -s72 & +s81 & -s80, fill=m5) # Name: core barrel -c7183 = mcdc.cell(+s72 & -s78 & +s81 & -s80, fill=m10) # Name: downcomer -c7184 = mcdc.cell(+s78 & -s79 & +s81 & -s80, fill=m6) # Name: reactor pressure vessel - -# -------------------------------------------------------------------------------------- -# Universes - Level 1 -# -------------------------------------------------------------------------------------- - -u1 = mcdc.universe([c1]) -u154 = mcdc.universe( - [ - c7104, - c7105, - c7106, - c7107, - c7108, - c7109, - c7110, - c7111, - c7112, - c7113, - c7114, - c7115, - c7116, - c7117, - ] -) -u155 = mcdc.universe([c7118, c7119, c7120, c7121]) -u156 = mcdc.universe( - [c7122, c7123, c7124, c7125, c7126, c7127, c7128, c7129, c7130, c7131, c7132, c7133] -) -u157 = mcdc.universe( - [c7134, c7135, c7136, c7137, c7138, c7139, c7140, c7141, c7142, c7143, c7144] -) -u158 = mcdc.universe( - [c7145, c7146, c7147, c7148, c7149, c7150, c7151, c7152, c7153, c7154, c7155] -) -u159 = mcdc.universe([c7156, c7157]) -u182 = mcdc.universe([c7180]) -u2 = mcdc.universe([c2, c3, c4]) -u3 = mcdc.universe([c5, c6, c7, c8]) -u4 = mcdc.universe([c9, c10, c11, c12]) -u6 = mcdc.universe([c16, c17, c18]) -u7 = mcdc.universe([c19, c20, c21, c22]) -u82 = mcdc.universe([c585, c586]) -u83 = mcdc.universe([c587, c588]) -u84 = mcdc.universe([c589, c590, c591, c592]) -u85 = mcdc.universe([c593, c594, c595, c596, c597]) -u86 = mcdc.universe( - [ - c598, - c599, - c600, - c601, - c602, - c603, - c604, - c605, - c606, - c607, - c608, - c609, - c610, - c611, - c612, - c613, - c614, - c615, - c616, - c617, - c618, - c619, - c620, - c621, - c622, - c623, - c624, - c625, - c626, - c627, - c628, - c629, - c630, - c631, - c632, - c633, - c634, - c635, - c636, - c637, - c638, - c639, - c640, - c641, - c642, - c643, - c644, - c645, - c646, - c647, - c648, - c649, - c650, - c651, - c652, - c653, - c654, - c655, - c656, - c657, - c658, - c659, - c660, - c661, - c662, - c663, - c664, - c665, - c666, - c667, - c668, - c669, - c670, - c671, - c672, - c673, - c674, - c675, - c676, - c677, - c678, - c679, - c680, - c681, - c682, - c683, - c684, - c685, - c686, - c687, - c688, - c689, - c690, - c691, - c692, - c693, - c694, - c695, - c696, - c697, - c698, - c699, - c700, - c701, - c702, - c703, - c704, - c705, - c706, - c707, - c708, - c709, - c710, - c711, - c712, - c713, - c714, - c715, - c716, - c717, - c718, - c719, - c720, - c721, - c722, - c723, - c724, - c725, - c726, - c727, - c728, - c729, - c730, - c731, - c732, - c733, - c734, - c735, - c736, - c737, - c738, - c739, - c740, - c741, - c742, - c743, - c744, - c745, - c746, - c747, - c748, - c749, - c750, - c751, - c752, - c753, - c754, - c755, - c756, - c757, - c758, - c759, - c760, - c761, - c762, - c763, - c764, - c765, - c766, - c767, - c768, - c769, - c770, - c771, - c772, - c773, - c774, - c775, - c776, - c777, - c778, - c779, - c780, - c781, - c782, - c783, - c784, - c785, - c786, - c787, - c788, - c789, - c790, - c791, - c792, - c793, - c794, - c795, - c796, - c797, - c798, - c799, - c800, - c801, - c802, - c803, - c804, - c805, - c806, - c807, - c808, - c809, - c810, - c811, - c812, - c813, - c814, - c815, - c816, - c817, - c818, - c819, - c820, - c821, - c822, - c823, - c824, - c825, - c826, - c827, - c828, - c829, - c830, - c831, - c832, - c833, - c834, - c835, - c836, - c837, - c838, - c839, - c840, - c841, - c842, - c843, - c844, - c845, - c846, - c847, - c848, - c849, - c850, - c851, - c852, - c853, - c854, - c855, - c856, - c857, - c858, - c859, - c860, - c861, - c862, - c863, - c864, - c865, - c866, - c867, - c868, - c869, - c870, - c871, - c872, - c873, - c874, - c875, - c876, - c877, - c878, - c879, - c880, - c881, - c882, - c883, - c884, - c885, - c886, - c887, - c888, - c889, - c890, - c891, - c892, - c893, - c894, - c895, - c896, - c897, - c898, - c899, - c900, - c901, - c902, - c903, - c904, - c905, - c906, - c907, - c908, - c909, - c910, - c911, - c912, - c913, - c914, - c915, - c916, - c917, - c918, - c919, - c920, - c921, - c922, - c923, - c924, - c925, - c926, - c927, - c928, - c929, - c930, - c931, - c932, - c933, - c934, - c935, - c936, - c937, - c938, - c939, - c940, - c941, - c942, - c943, - c944, - c945, - c946, - c947, - c948, - c949, - c950, - c951, - c952, - c953, - c954, - c955, - c956, - c957, - c958, - c959, - c960, - c961, - c962, - c963, - c964, - c965, - c966, - c967, - c968, - c969, - c970, - c971, - c972, - c973, - c974, - c975, - c976, - c977, - c978, - c979, - c980, - c981, - c982, - c983, - c984, - c985, - c986, - c987, - c988, - c989, - c990, - c991, - c992, - c993, - c994, - c995, - c996, - c997, - c998, - c999, - c1000, - c1001, - c1002, - c1003, - c1004, - c1005, - c1006, - c1007, - c1008, - c1009, - c1010, - c1011, - c1012, - c1013, - c1014, - c1015, - c1016, - c1017, - c1018, - c1019, - c1020, - c1021, - c1022, - c1023, - c1024, - c1025, - c1026, - c1027, - c1028, - c1029, - c1030, - c1031, - c1032, - c1033, - c1034, - c1035, - c1036, - c1037, - c1038, - c1039, - c1040, - c1041, - c1042, - c1043, - c1044, - c1045, - c1046, - c1047, - c1048, - c1049, - c1050, - c1051, - c1052, - c1053, - c1054, - c1055, - c1056, - c1057, - c1058, - c1059, - c1060, - c1061, - c1062, - c1063, - c1064, - c1065, - c1066, - c1067, - c1068, - c1069, - c1070, - c1071, - c1072, - c1073, - c1074, - c1075, - c1076, - c1077, - c1078, - c1079, - c1080, - c1081, - c1082, - c1083, - c1084, - c1085, - c1086, - c1087, - c1088, - c1089, - c1090, - c1091, - c1092, - c1093, - c1094, - c1095, - c1096, - c1097, - c1098, - c1099, - c1100, - c1101, - c1102, - c1103, - c1104, - c1105, - c1106, - c1107, - c1108, - c1109, - c1110, - c1111, - c1112, - c1113, - c1114, - c1115, - c1116, - c1117, - c1118, - c1119, - c1120, - c1121, - c1122, - c1123, - c1124, - c1125, - c1126, - c1127, - c1128, - c1129, - c1130, - c1131, - c1132, - c1133, - c1134, - c1135, - c1136, - c1137, - c1138, - c1139, - c1140, - c1141, - c1142, - c1143, - c1144, - c1145, - c1146, - c1147, - c1148, - c1149, - c1150, - c1151, - c1152, - c1153, - c1154, - c1155, - c1156, - c1157, - c1158, - c1159, - c1160, - c1161, - c1162, - c1163, - c1164, - c1165, - c1166, - c1167, - c1168, - c1169, - c1170, - c1171, - c1172, - c1173, - c1174, - c1175, - c1176, - c1177, - c1178, - c1179, - c1180, - c1181, - c1182, - c1183, - c1184, - c1185, - c1186, - c1187, - c1188, - c1189, - c1190, - c1191, - c1192, - c1193, - c1194, - c1195, - c1196, - c1197, - c1198, - c1199, - c1200, - c1201, - c1202, - c1203, - c1204, - c1205, - c1206, - c1207, - c1208, - c1209, - c1210, - c1211, - c1212, - c1213, - c1214, - c1215, - c1216, - c1217, - c1218, - c1219, - c1220, - c1221, - c1222, - c1223, - c1224, - c1225, - c1226, - c1227, - c1228, - c1229, - c1230, - c1231, - c1232, - c1233, - c1234, - c1235, - c1236, - c1237, - c1238, - c1239, - c1240, - c1241, - c1242, - c1243, - c1244, - c1245, - c1246, - c1247, - c1248, - c1249, - c1250, - c1251, - c1252, - c1253, - c1254, - c1255, - c1256, - c1257, - c1258, - c1259, - c1260, - c1261, - c1262, - c1263, - c1264, - c1265, - c1266, - c1267, - c1268, - c1269, - c1270, - c1271, - c1272, - c1273, - c1274, - c1275, - c1276, - c1277, - c1278, - c1279, - c1280, - c1281, - c1282, - c1283, - c1284, - c1285, - c1286, - c1287, - c1288, - c1289, - c1290, - c1291, - c1292, - c1293, - c1294, - c1295, - c1296, - c1297, - c1298, - c1299, - c1300, - c1301, - c1302, - c1303, - c1304, - c1305, - c1306, - c1307, - c1308, - c1309, - c1310, - c1311, - c1312, - c1313, - c1314, - c1315, - c1316, - c1317, - c1318, - c1319, - c1320, - c1321, - c1322, - c1323, - c1324, - c1325, - c1326, - c1327, - c1328, - c1329, - c1330, - c1331, - c1332, - c1333, - c1334, - c1335, - c1336, - c1337, - c1338, - c1339, - c1340, - c1341, - c1342, - c1343, - c1344, - c1345, - c1346, - c1347, - c1348, - c1349, - c1350, - c1351, - c1352, - c1353, - c1354, - c1355, - c1356, - c1357, - c1358, - c1359, - c1360, - c1361, - c1362, - c1363, - c1364, - c1365, - c1366, - c1367, - c1368, - c1369, - c1370, - c1371, - c1372, - c1373, - c1374, - c1375, - c1376, - c1377, - c1378, - c1379, - c1380, - c1381, - c1382, - c1383, - c1384, - c1385, - c1386, - c1387, - c1388, - c1389, - c1390, - c1391, - c1392, - c1393, - c1394, - c1395, - c1396, - c1397, - c1398, - c1399, - c1400, - c1401, - c1402, - c1403, - c1404, - c1405, - c1406, - c1407, - c1408, - c1409, - c1410, - c1411, - c1412, - c1413, - c1414, - c1415, - c1416, - c1417, - c1418, - c1419, - c1420, - c1421, - c1422, - c1423, - c1424, - c1425, - c1426, - c1427, - c1428, - c1429, - c1430, - c1431, - c1432, - c1433, - c1434, - c1435, - c1436, - c1437, - c1438, - c1439, - c1440, - c1441, - c1442, - c1443, - c1444, - c1445, - c1446, - c1447, - c1448, - c1449, - c1450, - c1451, - c1452, - c1453, - c1454, - c1455, - c1456, - c1457, - c1458, - c1459, - c1460, - c1461, - c1462, - c1463, - c1464, - c1465, - c1466, - c1467, - c1468, - c1469, - c1470, - c1471, - c1472, - c1473, - c1474, - c1475, - c1476, - c1477, - c1478, - c1479, - c1480, - c1481, - c1482, - c1483, - c1484, - c1485, - c1486, - c1487, - c1488, - c1489, - c1490, - c1491, - c1492, - c1493, - c1494, - c1495, - c1496, - c1497, - c1498, - c1499, - c1500, - c1501, - c1502, - c1503, - c1504, - c1505, - c1506, - c1507, - c1508, - c1509, - c1510, - c1511, - c1512, - c1513, - c1514, - c1515, - c1516, - c1517, - c1518, - c1519, - c1520, - c1521, - c1522, - c1523, - c1524, - c1525, - c1526, - c1527, - c1528, - c1529, - c1530, - c1531, - c1532, - c1533, - c1534, - c1535, - c1536, - c1537, - c1538, - c1539, - c1540, - c1541, - c1542, - c1543, - c1544, - c1545, - c1546, - c1547, - c1548, - c1549, - c1550, - c1551, - c1552, - c1553, - c1554, - c1555, - c1556, - c1557, - c1558, - c1559, - c1560, - c1561, - c1562, - c1563, - c1564, - c1565, - c1566, - c1567, - c1568, - c1569, - c1570, - c1571, - c1572, - c1573, - c1574, - c1575, - c1576, - c1577, - c1578, - c1579, - c1580, - c1581, - c1582, - c1583, - c1584, - c1585, - c1586, - c1587, - c1588, - c1589, - c1590, - c1591, - c1592, - c1593, - c1594, - c1595, - c1596, - c1597, - c1598, - c1599, - c1600, - c1601, - c1602, - c1603, - c1604, - c1605, - c1606, - c1607, - c1608, - c1609, - c1610, - c1611, - c1612, - c1613, - c1614, - c1615, - c1616, - c1617, - c1618, - c1619, - c1620, - c1621, - c1622, - c1623, - c1624, - c1625, - c1626, - c1627, - c1628, - c1629, - c1630, - c1631, - c1632, - c1633, - c1634, - c1635, - c1636, - c1637, - c1638, - c1639, - c1640, - c1641, - c1642, - c1643, - c1644, - c1645, - c1646, - c1647, - c1648, - c1649, - c1650, - c1651, - c1652, - c1653, - c1654, - c1655, - c1656, - c1657, - c1658, - c1659, - c1660, - c1661, - c1662, - c1663, - c1664, - c1665, - c1666, - c1667, - c1668, - c1669, - c1670, - c1671, - c1672, - c1673, - c1674, - c1675, - c1676, - c1677, - c1678, - c1679, - c1680, - c1681, - c1682, - c1683, - c1684, - c1685, - c1686, - c1687, - c1688, - c1689, - c1690, - c1691, - c1692, - c1693, - c1694, - c1695, - c1696, - c1697, - c1698, - c1699, - c1700, - c1701, - c1702, - c1703, - c1704, - c1705, - c1706, - c1707, - c1708, - c1709, - c1710, - c1711, - c1712, - c1713, - c1714, - c1715, - c1716, - c1717, - c1718, - c1719, - c1720, - c1721, - c1722, - c1723, - c1724, - c1725, - c1726, - c1727, - c1728, - c1729, - c1730, - c1731, - c1732, - c1733, - c1734, - c1735, - c1736, - c1737, - c1738, - c1739, - c1740, - c1741, - c1742, - c1743, - c1744, - c1745, - c1746, - c1747, - c1748, - c1749, - c1750, - c1751, - c1752, - c1753, - c1754, - c1755, - c1756, - c1757, - c1758, - c1759, - c1760, - c1761, - c1762, - c1763, - c1764, - c1765, - c1766, - c1767, - c1768, - c1769, - c1770, - c1771, - c1772, - c1773, - c1774, - c1775, - c1776, - c1777, - c1778, - c1779, - c1780, - c1781, - c1782, - c1783, - c1784, - c1785, - c1786, - c1787, - c1788, - c1789, - c1790, - c1791, - c1792, - c1793, - c1794, - c1795, - c1796, - c1797, - c1798, - c1799, - c1800, - c1801, - c1802, - c1803, - c1804, - c1805, - c1806, - c1807, - c1808, - c1809, - c1810, - c1811, - c1812, - c1813, - c1814, - c1815, - c1816, - c1817, - c1818, - c1819, - c1820, - c1821, - c1822, - c1823, - c1824, - c1825, - c1826, - c1827, - c1828, - c1829, - c1830, - c1831, - c1832, - c1833, - c1834, - c1835, - c1836, - c1837, - c1838, - c1839, - c1840, - c1841, - c1842, - c1843, - c1844, - c1845, - c1846, - c1847, - c1848, - c1849, - c1850, - c1851, - c1852, - c1853, - c1854, - c1855, - c1856, - c1857, - c1858, - c1859, - c1860, - c1861, - c1862, - c1863, - c1864, - c1865, - c1866, - c1867, - c1868, - c1869, - c1870, - c1871, - c1872, - c1873, - c1874, - c1875, - c1876, - c1877, - c1878, - c1879, - c1880, - c1881, - c1882, - c1883, - c1884, - c1885, - c1886, - c1887, - c1888, - c1889, - c1890, - c1891, - c1892, - c1893, - c1894, - c1895, - c1896, - c1897, - c1898, - c1899, - c1900, - c1901, - c1902, - c1903, - c1904, - c1905, - c1906, - c1907, - c1908, - c1909, - c1910, - c1911, - c1912, - c1913, - c1914, - c1915, - c1916, - c1917, - c1918, - c1919, - c1920, - c1921, - c1922, - c1923, - c1924, - c1925, - c1926, - c1927, - c1928, - c1929, - c1930, - c1931, - c1932, - c1933, - c1934, - c1935, - c1936, - c1937, - c1938, - c1939, - c1940, - c1941, - c1942, - c1943, - c1944, - c1945, - c1946, - c1947, - c1948, - c1949, - c1950, - c1951, - c1952, - c1953, - c1954, - c1955, - c1956, - c1957, - c1958, - c1959, - c1960, - c1961, - c1962, - c1963, - c1964, - c1965, - c1966, - c1967, - c1968, - c1969, - c1970, - c1971, - c1972, - c1973, - c1974, - c1975, - c1976, - c1977, - c1978, - c1979, - c1980, - c1981, - c1982, - c1983, - c1984, - c1985, - c1986, - c1987, - c1988, - c1989, - c1990, - c1991, - c1992, - c1993, - c1994, - c1995, - c1996, - c1997, - c1998, - c1999, - c2000, - c2001, - c2002, - c2003, - c2004, - c2005, - c2006, - c2007, - c2008, - c2009, - c2010, - c2011, - c2012, - c2013, - c2014, - c2015, - c2016, - c2017, - c2018, - c2019, - c2020, - c2021, - c2022, - c2023, - c2024, - c2025, - c2026, - c2027, - c2028, - c2029, - c2030, - c2031, - c2032, - c2033, - c2034, - c2035, - c2036, - c2037, - c2038, - c2039, - c2040, - c2041, - c2042, - c2043, - c2044, - c2045, - c2046, - c2047, - c2048, - c2049, - c2050, - c2051, - c2052, - c2053, - c2054, - c2055, - c2056, - c2057, - c2058, - c2059, - c2060, - c2061, - c2062, - c2063, - c2064, - c2065, - c2066, - c2067, - c2068, - c2069, - c2070, - c2071, - c2072, - c2073, - c2074, - c2075, - c2076, - c2077, - c2078, - c2079, - c2080, - c2081, - c2082, - c2083, - c2084, - c2085, - c2086, - c2087, - c2088, - c2089, - c2090, - c2091, - c2092, - c2093, - c2094, - c2095, - c2096, - c2097, - c2098, - c2099, - c2100, - c2101, - c2102, - c2103, - c2104, - c2105, - c2106, - c2107, - c2108, - c2109, - c2110, - c2111, - c2112, - c2113, - c2114, - c2115, - c2116, - c2117, - c2118, - c2119, - c2120, - c2121, - c2122, - c2123, - c2124, - c2125, - c2126, - c2127, - c2128, - c2129, - c2130, - c2131, - c2132, - c2133, - c2134, - c2135, - c2136, - c2137, - c2138, - c2139, - c2140, - c2141, - c2142, - c2143, - c2144, - c2145, - c2146, - c2147, - c2148, - c2149, - c2150, - c2151, - c2152, - c2153, - c2154, - c2155, - c2156, - c2157, - c2158, - c2159, - c2160, - c2161, - c2162, - c2163, - c2164, - c2165, - c2166, - c2167, - c2168, - c2169, - c2170, - c2171, - c2172, - c2173, - c2174, - c2175, - c2176, - c2177, - c2178, - c2179, - c2180, - c2181, - c2182, - c2183, - c2184, - c2185, - c2186, - c2187, - c2188, - c2189, - c2190, - c2191, - c2192, - c2193, - c2194, - c2195, - c2196, - c2197, - c2198, - c2199, - c2200, - c2201, - c2202, - c2203, - c2204, - c2205, - c2206, - c2207, - c2208, - c2209, - c2210, - c2211, - c2212, - c2213, - c2214, - c2215, - c2216, - c2217, - c2218, - c2219, - c2220, - c2221, - c2222, - c2223, - c2224, - c2225, - c2226, - c2227, - c2228, - c2229, - c2230, - c2231, - c2232, - c2233, - c2234, - c2235, - c2236, - c2237, - c2238, - c2239, - c2240, - c2241, - c2242, - c2243, - c2244, - c2245, - c2246, - c2247, - c2248, - c2249, - c2250, - c2251, - c2252, - c2253, - c2254, - c2255, - c2256, - c2257, - c2258, - c2259, - c2260, - c2261, - c2262, - c2263, - c2264, - c2265, - c2266, - c2267, - c2268, - c2269, - c2270, - c2271, - c2272, - c2273, - c2274, - c2275, - c2276, - c2277, - c2278, - c2279, - c2280, - c2281, - c2282, - c2283, - c2284, - c2285, - c2286, - c2287, - c2288, - c2289, - c2290, - c2291, - c2292, - c2293, - c2294, - c2295, - c2296, - c2297, - c2298, - c2299, - c2300, - c2301, - c2302, - c2303, - c2304, - c2305, - c2306, - c2307, - c2308, - c2309, - c2310, - c2311, - c2312, - c2313, - c2314, - c2315, - c2316, - c2317, - c2318, - c2319, - c2320, - c2321, - c2322, - c2323, - c2324, - c2325, - c2326, - c2327, - c2328, - c2329, - c2330, - c2331, - c2332, - c2333, - c2334, - c2335, - c2336, - c2337, - c2338, - c2339, - c2340, - c2341, - c2342, - c2343, - c2344, - c2345, - c2346, - c2347, - c2348, - c2349, - c2350, - c2351, - c2352, - c2353, - c2354, - c2355, - c2356, - c2357, - c2358, - c2359, - c2360, - c2361, - c2362, - c2363, - c2364, - c2365, - c2366, - c2367, - c2368, - c2369, - c2370, - c2371, - c2372, - c2373, - c2374, - c2375, - c2376, - c2377, - c2378, - c2379, - c2380, - c2381, - c2382, - c2383, - c2384, - c2385, - c2386, - c2387, - c2388, - c2389, - c2390, - c2391, - c2392, - c2393, - c2394, - c2395, - c2396, - c2397, - c2398, - c2399, - c2400, - c2401, - c2402, - c2403, - c2404, - c2405, - c2406, - c2407, - c2408, - c2409, - c2410, - c2411, - c2412, - c2413, - c2414, - c2415, - c2416, - c2417, - c2418, - c2419, - c2420, - c2421, - c2422, - c2423, - c2424, - c2425, - c2426, - c2427, - c2428, - c2429, - c2430, - c2431, - c2432, - c2433, - c2434, - c2435, - c2436, - c2437, - c2438, - c2439, - c2440, - c2441, - c2442, - c2443, - c2444, - c2445, - c2446, - c2447, - c2448, - c2449, - c2450, - c2451, - c2452, - c2453, - c2454, - c2455, - c2456, - c2457, - c2458, - c2459, - c2460, - c2461, - c2462, - c2463, - c2464, - c2465, - c2466, - c2467, - c2468, - c2469, - c2470, - c2471, - c2472, - c2473, - c2474, - c2475, - c2476, - c2477, - c2478, - c2479, - c2480, - c2481, - c2482, - c2483, - c2484, - c2485, - c2486, - c2487, - c2488, - c2489, - c2490, - c2491, - c2492, - c2493, - c2494, - c2495, - c2496, - c2497, - c2498, - c2499, - c2500, - c2501, - c2502, - c2503, - c2504, - c2505, - c2506, - c2507, - c2508, - c2509, - c2510, - c2511, - c2512, - c2513, - c2514, - c2515, - c2516, - c2517, - c2518, - c2519, - c2520, - c2521, - c2522, - c2523, - c2524, - c2525, - c2526, - c2527, - c2528, - c2529, - c2530, - c2531, - c2532, - c2533, - c2534, - c2535, - c2536, - c2537, - c2538, - c2539, - c2540, - c2541, - c2542, - c2543, - c2544, - c2545, - c2546, - c2547, - c2548, - c2549, - c2550, - c2551, - c2552, - c2553, - c2554, - c2555, - c2556, - c2557, - ] -) -u87 = mcdc.universe([c2558, c2559, c2560]) -u88 = mcdc.universe([c2561, c2562, c2563, c2564]) -u89 = mcdc.universe([c2565, c2566, c2567, c2568]) -u93 = mcdc.universe( - [ - c2596, - c2597, - c2598, - c2599, - c2600, - c2601, - c2602, - c2603, - c2604, - c2605, - c2606, - c2607, - c2608, - c2609, - c2610, - c2611, - c2612, - c2613, - c2614, - c2615, - c2616, - c2617, - c2618, - c2619, - c2620, - c2621, - c2622, - c2623, - c2624, - c2625, - c2626, - c2627, - c2628, - c2629, - c2630, - c2631, - c2632, - c2633, - c2634, - c2635, - c2636, - c2637, - c2638, - c2639, - c2640, - c2641, - c2642, - c2643, - c2644, - c2645, - c2646, - c2647, - c2648, - c2649, - c2650, - c2651, - c2652, - c2653, - c2654, - c2655, - c2656, - c2657, - c2658, - c2659, - c2660, - c2661, - c2662, - c2663, - c2664, - c2665, - c2666, - c2667, - c2668, - c2669, - c2670, - c2671, - c2672, - c2673, - c2674, - c2675, - c2676, - c2677, - c2678, - c2679, - c2680, - c2681, - c2682, - c2683, - c2684, - c2685, - c2686, - c2687, - c2688, - c2689, - c2690, - c2691, - c2692, - c2693, - c2694, - c2695, - c2696, - c2697, - c2698, - c2699, - c2700, - c2701, - c2702, - c2703, - c2704, - c2705, - c2706, - c2707, - c2708, - c2709, - c2710, - c2711, - c2712, - c2713, - c2714, - c2715, - c2716, - c2717, - c2718, - c2719, - c2720, - c2721, - c2722, - c2723, - c2724, - c2725, - c2726, - c2727, - c2728, - c2729, - c2730, - c2731, - c2732, - c2733, - c2734, - c2735, - c2736, - c2737, - c2738, - c2739, - c2740, - c2741, - c2742, - c2743, - c2744, - c2745, - c2746, - c2747, - c2748, - c2749, - c2750, - c2751, - c2752, - c2753, - c2754, - c2755, - c2756, - c2757, - c2758, - c2759, - c2760, - c2761, - c2762, - c2763, - c2764, - c2765, - c2766, - c2767, - c2768, - c2769, - c2770, - c2771, - c2772, - c2773, - c2774, - c2775, - c2776, - c2777, - c2778, - c2779, - c2780, - c2781, - c2782, - c2783, - c2784, - c2785, - c2786, - c2787, - c2788, - c2789, - c2790, - c2791, - c2792, - c2793, - c2794, - c2795, - c2796, - c2797, - c2798, - c2799, - c2800, - c2801, - c2802, - c2803, - c2804, - c2805, - c2806, - c2807, - c2808, - c2809, - c2810, - c2811, - c2812, - c2813, - c2814, - c2815, - c2816, - c2817, - c2818, - c2819, - c2820, - c2821, - c2822, - c2823, - c2824, - c2825, - c2826, - c2827, - c2828, - c2829, - c2830, - c2831, - c2832, - c2833, - c2834, - c2835, - c2836, - c2837, - c2838, - c2839, - c2840, - c2841, - c2842, - c2843, - c2844, - c2845, - c2846, - c2847, - c2848, - c2849, - c2850, - c2851, - c2852, - c2853, - c2854, - c2855, - c2856, - c2857, - c2858, - c2859, - c2860, - c2861, - c2862, - c2863, - c2864, - c2865, - c2866, - c2867, - c2868, - c2869, - c2870, - c2871, - c2872, - c2873, - c2874, - c2875, - c2876, - c2877, - c2878, - c2879, - c2880, - c2881, - c2882, - c2883, - c2884, - c2885, - c2886, - c2887, - c2888, - c2889, - c2890, - c2891, - c2892, - c2893, - c2894, - c2895, - c2896, - c2897, - c2898, - c2899, - c2900, - c2901, - c2902, - c2903, - c2904, - c2905, - c2906, - c2907, - c2908, - c2909, - c2910, - c2911, - c2912, - c2913, - c2914, - c2915, - c2916, - c2917, - c2918, - c2919, - c2920, - c2921, - c2922, - c2923, - c2924, - c2925, - c2926, - c2927, - c2928, - c2929, - c2930, - c2931, - c2932, - c2933, - c2934, - c2935, - c2936, - c2937, - c2938, - c2939, - c2940, - c2941, - c2942, - c2943, - c2944, - c2945, - c2946, - c2947, - c2948, - c2949, - c2950, - c2951, - c2952, - c2953, - c2954, - c2955, - c2956, - c2957, - c2958, - c2959, - c2960, - c2961, - c2962, - c2963, - c2964, - c2965, - c2966, - c2967, - c2968, - c2969, - c2970, - c2971, - c2972, - c2973, - c2974, - c2975, - c2976, - c2977, - c2978, - c2979, - c2980, - c2981, - c2982, - c2983, - c2984, - c2985, - c2986, - c2987, - c2988, - c2989, - c2990, - c2991, - c2992, - c2993, - c2994, - c2995, - c2996, - c2997, - c2998, - c2999, - c3000, - c3001, - c3002, - c3003, - c3004, - c3005, - c3006, - c3007, - c3008, - c3009, - c3010, - c3011, - c3012, - c3013, - c3014, - c3015, - c3016, - c3017, - c3018, - c3019, - c3020, - c3021, - c3022, - c3023, - c3024, - c3025, - c3026, - c3027, - c3028, - c3029, - c3030, - c3031, - c3032, - c3033, - c3034, - c3035, - c3036, - c3037, - c3038, - c3039, - c3040, - c3041, - c3042, - c3043, - c3044, - c3045, - c3046, - c3047, - c3048, - c3049, - c3050, - c3051, - c3052, - c3053, - c3054, - c3055, - c3056, - c3057, - c3058, - c3059, - c3060, - c3061, - c3062, - c3063, - c3064, - c3065, - c3066, - c3067, - c3068, - c3069, - c3070, - c3071, - c3072, - c3073, - c3074, - c3075, - c3076, - c3077, - c3078, - c3079, - c3080, - c3081, - c3082, - c3083, - c3084, - c3085, - c3086, - c3087, - c3088, - c3089, - c3090, - c3091, - c3092, - c3093, - c3094, - c3095, - c3096, - c3097, - c3098, - c3099, - c3100, - c3101, - c3102, - c3103, - c3104, - c3105, - c3106, - c3107, - c3108, - c3109, - c3110, - c3111, - c3112, - c3113, - c3114, - c3115, - c3116, - c3117, - c3118, - c3119, - c3120, - c3121, - c3122, - c3123, - c3124, - c3125, - c3126, - c3127, - c3128, - c3129, - c3130, - c3131, - c3132, - c3133, - c3134, - c3135, - c3136, - c3137, - c3138, - c3139, - c3140, - c3141, - c3142, - c3143, - c3144, - c3145, - c3146, - c3147, - c3148, - c3149, - c3150, - c3151, - c3152, - c3153, - c3154, - c3155, - c3156, - c3157, - c3158, - c3159, - c3160, - c3161, - c3162, - c3163, - c3164, - c3165, - c3166, - c3167, - c3168, - c3169, - c3170, - c3171, - c3172, - c3173, - c3174, - c3175, - c3176, - c3177, - c3178, - c3179, - c3180, - c3181, - c3182, - c3183, - c3184, - c3185, - c3186, - c3187, - c3188, - c3189, - c3190, - c3191, - c3192, - c3193, - c3194, - c3195, - c3196, - c3197, - c3198, - c3199, - c3200, - c3201, - c3202, - c3203, - c3204, - c3205, - c3206, - c3207, - c3208, - c3209, - c3210, - c3211, - c3212, - c3213, - c3214, - c3215, - c3216, - c3217, - c3218, - c3219, - c3220, - c3221, - c3222, - c3223, - c3224, - c3225, - c3226, - c3227, - c3228, - c3229, - c3230, - c3231, - c3232, - c3233, - c3234, - c3235, - c3236, - c3237, - c3238, - c3239, - c3240, - c3241, - c3242, - c3243, - c3244, - c3245, - c3246, - c3247, - c3248, - c3249, - c3250, - c3251, - c3252, - c3253, - c3254, - c3255, - c3256, - c3257, - c3258, - c3259, - c3260, - c3261, - c3262, - c3263, - c3264, - c3265, - c3266, - c3267, - c3268, - c3269, - c3270, - c3271, - c3272, - c3273, - c3274, - c3275, - c3276, - c3277, - c3278, - c3279, - c3280, - c3281, - c3282, - c3283, - c3284, - c3285, - c3286, - c3287, - c3288, - c3289, - c3290, - c3291, - c3292, - c3293, - c3294, - c3295, - c3296, - c3297, - c3298, - c3299, - c3300, - c3301, - c3302, - c3303, - c3304, - c3305, - c3306, - c3307, - c3308, - c3309, - c3310, - c3311, - c3312, - c3313, - c3314, - c3315, - c3316, - c3317, - c3318, - c3319, - c3320, - c3321, - c3322, - c3323, - c3324, - c3325, - c3326, - c3327, - c3328, - c3329, - c3330, - c3331, - c3332, - c3333, - c3334, - c3335, - c3336, - c3337, - c3338, - c3339, - c3340, - c3341, - c3342, - c3343, - c3344, - c3345, - c3346, - c3347, - c3348, - c3349, - c3350, - c3351, - c3352, - c3353, - c3354, - c3355, - c3356, - c3357, - c3358, - c3359, - c3360, - c3361, - c3362, - c3363, - c3364, - c3365, - c3366, - c3367, - c3368, - c3369, - c3370, - c3371, - c3372, - c3373, - c3374, - c3375, - c3376, - c3377, - c3378, - c3379, - c3380, - c3381, - c3382, - c3383, - c3384, - c3385, - c3386, - c3387, - c3388, - c3389, - c3390, - c3391, - c3392, - c3393, - c3394, - c3395, - c3396, - c3397, - c3398, - c3399, - c3400, - c3401, - c3402, - c3403, - c3404, - c3405, - c3406, - c3407, - c3408, - c3409, - c3410, - c3411, - c3412, - c3413, - c3414, - c3415, - c3416, - c3417, - c3418, - c3419, - c3420, - c3421, - c3422, - c3423, - c3424, - c3425, - c3426, - c3427, - c3428, - c3429, - c3430, - c3431, - c3432, - c3433, - c3434, - c3435, - c3436, - c3437, - c3438, - c3439, - c3440, - c3441, - c3442, - c3443, - c3444, - c3445, - c3446, - c3447, - c3448, - c3449, - c3450, - c3451, - c3452, - c3453, - c3454, - c3455, - c3456, - c3457, - c3458, - c3459, - c3460, - c3461, - c3462, - c3463, - c3464, - c3465, - c3466, - c3467, - c3468, - c3469, - c3470, - c3471, - c3472, - c3473, - c3474, - c3475, - c3476, - c3477, - c3478, - c3479, - c3480, - c3481, - c3482, - c3483, - c3484, - c3485, - c3486, - c3487, - c3488, - c3489, - c3490, - c3491, - c3492, - c3493, - c3494, - c3495, - c3496, - c3497, - c3498, - c3499, - c3500, - c3501, - c3502, - c3503, - c3504, - c3505, - c3506, - c3507, - c3508, - c3509, - c3510, - c3511, - c3512, - c3513, - c3514, - c3515, - c3516, - c3517, - c3518, - c3519, - c3520, - c3521, - c3522, - c3523, - c3524, - c3525, - c3526, - c3527, - c3528, - c3529, - c3530, - c3531, - c3532, - c3533, - c3534, - c3535, - c3536, - c3537, - c3538, - c3539, - c3540, - c3541, - c3542, - c3543, - c3544, - c3545, - c3546, - c3547, - c3548, - c3549, - c3550, - c3551, - c3552, - c3553, - c3554, - c3555, - c3556, - c3557, - c3558, - c3559, - c3560, - c3561, - c3562, - c3563, - c3564, - c3565, - c3566, - c3567, - c3568, - c3569, - c3570, - c3571, - c3572, - c3573, - c3574, - c3575, - c3576, - c3577, - c3578, - c3579, - c3580, - c3581, - c3582, - c3583, - c3584, - c3585, - c3586, - c3587, - c3588, - c3589, - c3590, - c3591, - c3592, - c3593, - c3594, - c3595, - c3596, - c3597, - c3598, - c3599, - c3600, - c3601, - c3602, - c3603, - c3604, - c3605, - c3606, - c3607, - c3608, - c3609, - c3610, - c3611, - c3612, - c3613, - c3614, - c3615, - c3616, - c3617, - c3618, - c3619, - c3620, - c3621, - c3622, - c3623, - c3624, - c3625, - c3626, - c3627, - c3628, - c3629, - c3630, - c3631, - c3632, - c3633, - c3634, - c3635, - c3636, - c3637, - c3638, - c3639, - c3640, - c3641, - c3642, - c3643, - c3644, - c3645, - c3646, - c3647, - c3648, - c3649, - c3650, - c3651, - c3652, - c3653, - c3654, - c3655, - c3656, - c3657, - c3658, - c3659, - c3660, - c3661, - c3662, - c3663, - c3664, - c3665, - c3666, - c3667, - c3668, - c3669, - c3670, - c3671, - c3672, - c3673, - c3674, - c3675, - c3676, - c3677, - c3678, - c3679, - c3680, - c3681, - c3682, - c3683, - c3684, - c3685, - c3686, - c3687, - c3688, - c3689, - c3690, - c3691, - c3692, - c3693, - c3694, - c3695, - c3696, - c3697, - c3698, - c3699, - c3700, - c3701, - c3702, - c3703, - c3704, - c3705, - c3706, - c3707, - c3708, - c3709, - c3710, - c3711, - c3712, - c3713, - c3714, - c3715, - c3716, - c3717, - c3718, - c3719, - c3720, - c3721, - c3722, - c3723, - c3724, - c3725, - c3726, - c3727, - c3728, - c3729, - c3730, - c3731, - c3732, - c3733, - c3734, - c3735, - c3736, - c3737, - c3738, - c3739, - c3740, - c3741, - c3742, - c3743, - c3744, - c3745, - c3746, - c3747, - c3748, - c3749, - c3750, - c3751, - c3752, - c3753, - c3754, - c3755, - c3756, - c3757, - c3758, - c3759, - c3760, - c3761, - c3762, - c3763, - c3764, - c3765, - c3766, - c3767, - c3768, - c3769, - c3770, - c3771, - c3772, - c3773, - c3774, - c3775, - c3776, - c3777, - c3778, - c3779, - c3780, - c3781, - c3782, - c3783, - c3784, - c3785, - c3786, - c3787, - c3788, - c3789, - c3790, - c3791, - c3792, - c3793, - c3794, - c3795, - c3796, - c3797, - c3798, - c3799, - c3800, - c3801, - c3802, - c3803, - c3804, - c3805, - c3806, - c3807, - c3808, - c3809, - c3810, - c3811, - c3812, - c3813, - c3814, - c3815, - c3816, - c3817, - c3818, - c3819, - c3820, - c3821, - c3822, - c3823, - c3824, - c3825, - c3826, - c3827, - c3828, - c3829, - c3830, - c3831, - c3832, - c3833, - c3834, - c3835, - c3836, - c3837, - c3838, - c3839, - c3840, - c3841, - c3842, - c3843, - c3844, - c3845, - c3846, - c3847, - c3848, - c3849, - c3850, - c3851, - c3852, - c3853, - c3854, - c3855, - c3856, - c3857, - c3858, - c3859, - c3860, - c3861, - c3862, - c3863, - c3864, - c3865, - c3866, - c3867, - c3868, - c3869, - c3870, - c3871, - c3872, - c3873, - c3874, - c3875, - c3876, - c3877, - c3878, - c3879, - c3880, - c3881, - c3882, - c3883, - c3884, - c3885, - c3886, - c3887, - c3888, - c3889, - c3890, - c3891, - c3892, - c3893, - c3894, - c3895, - c3896, - c3897, - c3898, - c3899, - c3900, - c3901, - c3902, - c3903, - c3904, - c3905, - c3906, - c3907, - c3908, - c3909, - c3910, - c3911, - c3912, - c3913, - c3914, - c3915, - c3916, - c3917, - c3918, - c3919, - c3920, - c3921, - c3922, - c3923, - c3924, - c3925, - c3926, - c3927, - c3928, - c3929, - c3930, - c3931, - c3932, - c3933, - c3934, - c3935, - c3936, - c3937, - c3938, - c3939, - c3940, - c3941, - c3942, - c3943, - c3944, - c3945, - c3946, - c3947, - c3948, - c3949, - c3950, - c3951, - c3952, - c3953, - c3954, - c3955, - c3956, - c3957, - c3958, - c3959, - c3960, - c3961, - c3962, - c3963, - c3964, - c3965, - c3966, - c3967, - c3968, - c3969, - c3970, - c3971, - c3972, - c3973, - c3974, - c3975, - c3976, - c3977, - c3978, - c3979, - c3980, - c3981, - c3982, - c3983, - c3984, - c3985, - c3986, - c3987, - c3988, - c3989, - c3990, - c3991, - c3992, - c3993, - c3994, - c3995, - c3996, - c3997, - c3998, - c3999, - c4000, - c4001, - c4002, - c4003, - c4004, - c4005, - c4006, - c4007, - c4008, - c4009, - c4010, - c4011, - c4012, - c4013, - c4014, - c4015, - c4016, - c4017, - c4018, - c4019, - c4020, - c4021, - c4022, - c4023, - c4024, - c4025, - c4026, - c4027, - c4028, - c4029, - c4030, - c4031, - c4032, - c4033, - c4034, - c4035, - c4036, - c4037, - c4038, - c4039, - c4040, - c4041, - c4042, - c4043, - c4044, - c4045, - c4046, - c4047, - c4048, - c4049, - c4050, - c4051, - c4052, - c4053, - c4054, - c4055, - c4056, - c4057, - c4058, - c4059, - c4060, - c4061, - c4062, - c4063, - c4064, - c4065, - c4066, - c4067, - c4068, - c4069, - c4070, - c4071, - c4072, - c4073, - c4074, - c4075, - c4076, - c4077, - c4078, - c4079, - c4080, - c4081, - c4082, - c4083, - c4084, - c4085, - c4086, - c4087, - c4088, - c4089, - c4090, - c4091, - c4092, - c4093, - c4094, - c4095, - c4096, - c4097, - c4098, - c4099, - c4100, - c4101, - c4102, - c4103, - c4104, - c4105, - c4106, - c4107, - c4108, - c4109, - c4110, - c4111, - c4112, - c4113, - c4114, - c4115, - c4116, - c4117, - c4118, - c4119, - c4120, - c4121, - c4122, - c4123, - c4124, - c4125, - c4126, - c4127, - c4128, - c4129, - c4130, - c4131, - c4132, - c4133, - c4134, - c4135, - c4136, - c4137, - c4138, - c4139, - c4140, - c4141, - c4142, - c4143, - c4144, - c4145, - c4146, - c4147, - c4148, - c4149, - c4150, - c4151, - c4152, - c4153, - c4154, - c4155, - c4156, - c4157, - c4158, - c4159, - c4160, - c4161, - c4162, - c4163, - c4164, - c4165, - c4166, - c4167, - c4168, - c4169, - c4170, - c4171, - c4172, - c4173, - c4174, - c4175, - c4176, - c4177, - c4178, - c4179, - c4180, - c4181, - c4182, - c4183, - c4184, - c4185, - c4186, - c4187, - c4188, - c4189, - c4190, - c4191, - c4192, - c4193, - c4194, - c4195, - c4196, - c4197, - c4198, - c4199, - c4200, - c4201, - c4202, - c4203, - c4204, - c4205, - c4206, - c4207, - c4208, - c4209, - c4210, - c4211, - c4212, - c4213, - c4214, - c4215, - c4216, - c4217, - c4218, - c4219, - c4220, - c4221, - c4222, - c4223, - c4224, - c4225, - c4226, - c4227, - c4228, - c4229, - c4230, - c4231, - c4232, - c4233, - c4234, - c4235, - c4236, - c4237, - c4238, - c4239, - c4240, - c4241, - c4242, - c4243, - c4244, - c4245, - c4246, - c4247, - c4248, - c4249, - c4250, - c4251, - c4252, - c4253, - c4254, - c4255, - c4256, - c4257, - c4258, - c4259, - c4260, - c4261, - c4262, - c4263, - c4264, - c4265, - c4266, - c4267, - c4268, - c4269, - c4270, - c4271, - c4272, - c4273, - c4274, - c4275, - c4276, - c4277, - c4278, - c4279, - c4280, - c4281, - c4282, - c4283, - c4284, - c4285, - c4286, - c4287, - c4288, - c4289, - c4290, - c4291, - c4292, - c4293, - c4294, - c4295, - c4296, - c4297, - c4298, - c4299, - c4300, - c4301, - c4302, - c4303, - c4304, - c4305, - c4306, - c4307, - c4308, - c4309, - c4310, - c4311, - c4312, - c4313, - c4314, - c4315, - c4316, - c4317, - c4318, - c4319, - c4320, - c4321, - c4322, - c4323, - c4324, - c4325, - c4326, - c4327, - c4328, - c4329, - c4330, - c4331, - c4332, - c4333, - c4334, - c4335, - c4336, - c4337, - c4338, - c4339, - c4340, - c4341, - c4342, - c4343, - c4344, - c4345, - c4346, - c4347, - c4348, - c4349, - c4350, - c4351, - c4352, - c4353, - c4354, - c4355, - c4356, - c4357, - c4358, - c4359, - c4360, - c4361, - c4362, - c4363, - c4364, - c4365, - c4366, - c4367, - c4368, - c4369, - c4370, - c4371, - c4372, - c4373, - c4374, - c4375, - c4376, - c4377, - c4378, - c4379, - c4380, - c4381, - c4382, - c4383, - c4384, - c4385, - c4386, - c4387, - c4388, - c4389, - c4390, - c4391, - c4392, - c4393, - c4394, - c4395, - c4396, - c4397, - c4398, - c4399, - c4400, - c4401, - c4402, - c4403, - c4404, - c4405, - c4406, - c4407, - c4408, - c4409, - c4410, - c4411, - c4412, - c4413, - c4414, - c4415, - c4416, - c4417, - c4418, - c4419, - c4420, - c4421, - c4422, - c4423, - c4424, - c4425, - c4426, - c4427, - c4428, - c4429, - c4430, - c4431, - c4432, - c4433, - c4434, - c4435, - c4436, - c4437, - c4438, - c4439, - c4440, - c4441, - c4442, - c4443, - c4444, - c4445, - c4446, - c4447, - c4448, - c4449, - c4450, - c4451, - c4452, - c4453, - c4454, - c4455, - c4456, - c4457, - c4458, - c4459, - c4460, - c4461, - c4462, - c4463, - c4464, - c4465, - c4466, - c4467, - c4468, - c4469, - c4470, - c4471, - c4472, - c4473, - c4474, - c4475, - c4476, - c4477, - c4478, - c4479, - c4480, - c4481, - c4482, - c4483, - c4484, - c4485, - c4486, - c4487, - c4488, - c4489, - c4490, - c4491, - c4492, - c4493, - c4494, - c4495, - c4496, - c4497, - c4498, - c4499, - c4500, - c4501, - c4502, - c4503, - c4504, - c4505, - c4506, - c4507, - c4508, - c4509, - c4510, - c4511, - c4512, - c4513, - c4514, - c4515, - c4516, - c4517, - c4518, - c4519, - c4520, - c4521, - c4522, - c4523, - c4524, - c4525, - c4526, - c4527, - c4528, - c4529, - c4530, - c4531, - c4532, - c4533, - c4534, - c4535, - c4536, - c4537, - c4538, - c4539, - c4540, - c4541, - c4542, - c4543, - c4544, - c4545, - c4546, - c4547, - c4548, - c4549, - c4550, - c4551, - c4552, - c4553, - c4554, - c4555, - ] -) -u97 = mcdc.universe( - [ - c4583, - c4584, - c4585, - c4586, - c4587, - c4588, - c4589, - c4590, - c4591, - c4592, - c4593, - c4594, - c4595, - c4596, - c4597, - c4598, - c4599, - c4600, - c4601, - c4602, - c4603, - c4604, - c4605, - c4606, - c4607, - c4608, - c4609, - c4610, - c4611, - c4612, - c4613, - c4614, - c4615, - c4616, - c4617, - c4618, - c4619, - c4620, - c4621, - c4622, - c4623, - c4624, - c4625, - c4626, - c4627, - c4628, - c4629, - c4630, - c4631, - c4632, - c4633, - c4634, - c4635, - c4636, - c4637, - c4638, - c4639, - c4640, - c4641, - c4642, - c4643, - c4644, - c4645, - c4646, - c4647, - c4648, - c4649, - c4650, - c4651, - c4652, - c4653, - c4654, - c4655, - c4656, - c4657, - c4658, - c4659, - c4660, - c4661, - c4662, - c4663, - c4664, - c4665, - c4666, - c4667, - c4668, - c4669, - c4670, - c4671, - c4672, - c4673, - c4674, - c4675, - c4676, - c4677, - c4678, - c4679, - c4680, - c4681, - c4682, - c4683, - c4684, - c4685, - c4686, - c4687, - c4688, - c4689, - c4690, - c4691, - c4692, - c4693, - c4694, - c4695, - c4696, - c4697, - c4698, - c4699, - c4700, - c4701, - c4702, - c4703, - c4704, - c4705, - c4706, - c4707, - c4708, - c4709, - c4710, - c4711, - c4712, - c4713, - c4714, - c4715, - c4716, - c4717, - c4718, - c4719, - c4720, - c4721, - c4722, - c4723, - c4724, - c4725, - c4726, - c4727, - c4728, - c4729, - c4730, - c4731, - c4732, - c4733, - c4734, - c4735, - c4736, - c4737, - c4738, - c4739, - c4740, - c4741, - c4742, - c4743, - c4744, - c4745, - c4746, - c4747, - c4748, - c4749, - c4750, - c4751, - c4752, - c4753, - c4754, - c4755, - c4756, - c4757, - c4758, - c4759, - c4760, - c4761, - c4762, - c4763, - c4764, - c4765, - c4766, - c4767, - c4768, - c4769, - c4770, - c4771, - c4772, - c4773, - c4774, - c4775, - c4776, - c4777, - c4778, - c4779, - c4780, - c4781, - c4782, - c4783, - c4784, - c4785, - c4786, - c4787, - c4788, - c4789, - c4790, - c4791, - c4792, - c4793, - c4794, - c4795, - c4796, - c4797, - c4798, - c4799, - c4800, - c4801, - c4802, - c4803, - c4804, - c4805, - c4806, - c4807, - c4808, - c4809, - c4810, - c4811, - c4812, - c4813, - c4814, - c4815, - c4816, - c4817, - c4818, - c4819, - c4820, - c4821, - c4822, - c4823, - c4824, - c4825, - c4826, - c4827, - c4828, - c4829, - c4830, - c4831, - c4832, - c4833, - c4834, - c4835, - c4836, - c4837, - c4838, - c4839, - c4840, - c4841, - c4842, - c4843, - c4844, - c4845, - c4846, - c4847, - c4848, - c4849, - c4850, - c4851, - c4852, - c4853, - c4854, - c4855, - c4856, - c4857, - c4858, - c4859, - c4860, - c4861, - c4862, - c4863, - c4864, - c4865, - c4866, - c4867, - c4868, - c4869, - c4870, - c4871, - c4872, - c4873, - c4874, - c4875, - c4876, - c4877, - c4878, - c4879, - c4880, - c4881, - c4882, - c4883, - c4884, - c4885, - c4886, - c4887, - c4888, - c4889, - c4890, - c4891, - c4892, - c4893, - c4894, - c4895, - c4896, - c4897, - c4898, - c4899, - c4900, - c4901, - c4902, - c4903, - c4904, - c4905, - c4906, - c4907, - c4908, - c4909, - c4910, - c4911, - c4912, - c4913, - c4914, - c4915, - c4916, - c4917, - c4918, - c4919, - c4920, - c4921, - c4922, - c4923, - c4924, - c4925, - c4926, - c4927, - c4928, - c4929, - c4930, - c4931, - c4932, - c4933, - c4934, - c4935, - c4936, - c4937, - c4938, - c4939, - c4940, - c4941, - c4942, - c4943, - c4944, - c4945, - c4946, - c4947, - c4948, - c4949, - c4950, - c4951, - c4952, - c4953, - c4954, - c4955, - c4956, - c4957, - c4958, - c4959, - c4960, - c4961, - c4962, - c4963, - c4964, - c4965, - c4966, - c4967, - c4968, - c4969, - c4970, - c4971, - c4972, - c4973, - c4974, - c4975, - c4976, - c4977, - c4978, - c4979, - c4980, - c4981, - c4982, - c4983, - c4984, - c4985, - c4986, - c4987, - c4988, - c4989, - c4990, - c4991, - c4992, - c4993, - c4994, - c4995, - c4996, - c4997, - c4998, - c4999, - c5000, - c5001, - c5002, - c5003, - c5004, - c5005, - c5006, - c5007, - c5008, - c5009, - c5010, - c5011, - c5012, - c5013, - c5014, - c5015, - c5016, - c5017, - c5018, - c5019, - c5020, - c5021, - c5022, - c5023, - c5024, - c5025, - c5026, - c5027, - c5028, - c5029, - c5030, - c5031, - c5032, - c5033, - c5034, - c5035, - c5036, - c5037, - c5038, - c5039, - c5040, - c5041, - c5042, - c5043, - c5044, - c5045, - c5046, - c5047, - c5048, - c5049, - c5050, - c5051, - c5052, - c5053, - c5054, - c5055, - c5056, - c5057, - c5058, - c5059, - c5060, - c5061, - c5062, - c5063, - c5064, - c5065, - c5066, - c5067, - c5068, - c5069, - c5070, - c5071, - c5072, - c5073, - c5074, - c5075, - c5076, - c5077, - c5078, - c5079, - c5080, - c5081, - c5082, - c5083, - c5084, - c5085, - c5086, - c5087, - c5088, - c5089, - c5090, - c5091, - c5092, - c5093, - c5094, - c5095, - c5096, - c5097, - c5098, - c5099, - c5100, - c5101, - c5102, - c5103, - c5104, - c5105, - c5106, - c5107, - c5108, - c5109, - c5110, - c5111, - c5112, - c5113, - c5114, - c5115, - c5116, - c5117, - c5118, - c5119, - c5120, - c5121, - c5122, - c5123, - c5124, - c5125, - c5126, - c5127, - c5128, - c5129, - c5130, - c5131, - c5132, - c5133, - c5134, - c5135, - c5136, - c5137, - c5138, - c5139, - c5140, - c5141, - c5142, - c5143, - c5144, - c5145, - c5146, - c5147, - c5148, - c5149, - c5150, - c5151, - c5152, - c5153, - c5154, - c5155, - c5156, - c5157, - c5158, - c5159, - c5160, - c5161, - c5162, - c5163, - c5164, - c5165, - c5166, - c5167, - c5168, - c5169, - c5170, - c5171, - c5172, - c5173, - c5174, - c5175, - c5176, - c5177, - c5178, - c5179, - c5180, - c5181, - c5182, - c5183, - c5184, - c5185, - c5186, - c5187, - c5188, - c5189, - c5190, - c5191, - c5192, - c5193, - c5194, - c5195, - c5196, - c5197, - c5198, - c5199, - c5200, - c5201, - c5202, - c5203, - c5204, - c5205, - c5206, - c5207, - c5208, - c5209, - c5210, - c5211, - c5212, - c5213, - c5214, - c5215, - c5216, - c5217, - c5218, - c5219, - c5220, - c5221, - c5222, - c5223, - c5224, - c5225, - c5226, - c5227, - c5228, - c5229, - c5230, - c5231, - c5232, - c5233, - c5234, - c5235, - c5236, - c5237, - c5238, - c5239, - c5240, - c5241, - c5242, - c5243, - c5244, - c5245, - c5246, - c5247, - c5248, - c5249, - c5250, - c5251, - c5252, - c5253, - c5254, - c5255, - c5256, - c5257, - c5258, - c5259, - c5260, - c5261, - c5262, - c5263, - c5264, - c5265, - c5266, - c5267, - c5268, - c5269, - c5270, - c5271, - c5272, - c5273, - c5274, - c5275, - c5276, - c5277, - c5278, - c5279, - c5280, - c5281, - c5282, - c5283, - c5284, - c5285, - c5286, - c5287, - c5288, - c5289, - c5290, - c5291, - c5292, - c5293, - c5294, - c5295, - c5296, - c5297, - c5298, - c5299, - c5300, - c5301, - c5302, - c5303, - c5304, - c5305, - c5306, - c5307, - c5308, - c5309, - c5310, - c5311, - c5312, - c5313, - c5314, - c5315, - c5316, - c5317, - c5318, - c5319, - c5320, - c5321, - c5322, - c5323, - c5324, - c5325, - c5326, - c5327, - c5328, - c5329, - c5330, - c5331, - c5332, - c5333, - c5334, - c5335, - c5336, - c5337, - c5338, - c5339, - c5340, - c5341, - c5342, - c5343, - c5344, - c5345, - c5346, - c5347, - c5348, - c5349, - c5350, - c5351, - c5352, - c5353, - c5354, - c5355, - c5356, - c5357, - c5358, - c5359, - c5360, - c5361, - c5362, - c5363, - c5364, - c5365, - c5366, - c5367, - c5368, - c5369, - c5370, - c5371, - c5372, - c5373, - c5374, - c5375, - c5376, - c5377, - c5378, - c5379, - c5380, - c5381, - c5382, - c5383, - c5384, - c5385, - c5386, - c5387, - c5388, - c5389, - c5390, - c5391, - c5392, - c5393, - c5394, - c5395, - c5396, - c5397, - c5398, - c5399, - c5400, - c5401, - c5402, - c5403, - c5404, - c5405, - c5406, - c5407, - c5408, - c5409, - c5410, - c5411, - c5412, - c5413, - c5414, - c5415, - c5416, - c5417, - c5418, - c5419, - c5420, - c5421, - c5422, - c5423, - c5424, - c5425, - c5426, - c5427, - c5428, - c5429, - c5430, - c5431, - c5432, - c5433, - c5434, - c5435, - c5436, - c5437, - c5438, - c5439, - c5440, - c5441, - c5442, - c5443, - c5444, - c5445, - c5446, - c5447, - c5448, - c5449, - c5450, - c5451, - c5452, - c5453, - c5454, - c5455, - c5456, - c5457, - c5458, - c5459, - c5460, - c5461, - c5462, - c5463, - c5464, - c5465, - c5466, - c5467, - c5468, - c5469, - c5470, - c5471, - c5472, - c5473, - c5474, - c5475, - c5476, - c5477, - c5478, - c5479, - c5480, - c5481, - c5482, - c5483, - c5484, - c5485, - c5486, - c5487, - c5488, - c5489, - c5490, - c5491, - c5492, - c5493, - c5494, - c5495, - c5496, - c5497, - c5498, - c5499, - c5500, - c5501, - c5502, - c5503, - c5504, - c5505, - c5506, - c5507, - c5508, - c5509, - c5510, - c5511, - c5512, - c5513, - c5514, - c5515, - c5516, - c5517, - c5518, - c5519, - c5520, - c5521, - c5522, - c5523, - c5524, - c5525, - c5526, - c5527, - c5528, - c5529, - c5530, - c5531, - c5532, - c5533, - c5534, - c5535, - c5536, - c5537, - c5538, - c5539, - c5540, - c5541, - c5542, - c5543, - c5544, - c5545, - c5546, - c5547, - c5548, - c5549, - c5550, - c5551, - c5552, - c5553, - c5554, - c5555, - c5556, - c5557, - c5558, - c5559, - c5560, - c5561, - c5562, - c5563, - c5564, - c5565, - c5566, - c5567, - c5568, - c5569, - c5570, - c5571, - c5572, - c5573, - c5574, - c5575, - c5576, - c5577, - c5578, - c5579, - c5580, - c5581, - c5582, - c5583, - c5584, - c5585, - c5586, - c5587, - c5588, - c5589, - c5590, - c5591, - c5592, - c5593, - c5594, - c5595, - c5596, - c5597, - c5598, - c5599, - c5600, - c5601, - c5602, - c5603, - c5604, - c5605, - c5606, - c5607, - c5608, - c5609, - c5610, - c5611, - c5612, - c5613, - c5614, - c5615, - c5616, - c5617, - c5618, - c5619, - c5620, - c5621, - c5622, - c5623, - c5624, - c5625, - c5626, - c5627, - c5628, - c5629, - c5630, - c5631, - c5632, - c5633, - c5634, - c5635, - c5636, - c5637, - c5638, - c5639, - c5640, - c5641, - c5642, - c5643, - c5644, - c5645, - c5646, - c5647, - c5648, - c5649, - c5650, - c5651, - c5652, - c5653, - c5654, - c5655, - c5656, - c5657, - c5658, - c5659, - c5660, - c5661, - c5662, - c5663, - c5664, - c5665, - c5666, - c5667, - c5668, - c5669, - c5670, - c5671, - c5672, - c5673, - c5674, - c5675, - c5676, - c5677, - c5678, - c5679, - c5680, - c5681, - c5682, - c5683, - c5684, - c5685, - c5686, - c5687, - c5688, - c5689, - c5690, - c5691, - c5692, - c5693, - c5694, - c5695, - c5696, - c5697, - c5698, - c5699, - c5700, - c5701, - c5702, - c5703, - c5704, - c5705, - c5706, - c5707, - c5708, - c5709, - c5710, - c5711, - c5712, - c5713, - c5714, - c5715, - c5716, - c5717, - c5718, - c5719, - c5720, - c5721, - c5722, - c5723, - c5724, - c5725, - c5726, - c5727, - c5728, - c5729, - c5730, - c5731, - c5732, - c5733, - c5734, - c5735, - c5736, - c5737, - c5738, - c5739, - c5740, - c5741, - c5742, - c5743, - c5744, - c5745, - c5746, - c5747, - c5748, - c5749, - c5750, - c5751, - c5752, - c5753, - c5754, - c5755, - c5756, - c5757, - c5758, - c5759, - c5760, - c5761, - c5762, - c5763, - c5764, - c5765, - c5766, - c5767, - c5768, - c5769, - c5770, - c5771, - c5772, - c5773, - c5774, - c5775, - c5776, - c5777, - c5778, - c5779, - c5780, - c5781, - c5782, - c5783, - c5784, - c5785, - c5786, - c5787, - c5788, - c5789, - c5790, - c5791, - c5792, - c5793, - c5794, - c5795, - c5796, - c5797, - c5798, - c5799, - c5800, - c5801, - c5802, - c5803, - c5804, - c5805, - c5806, - c5807, - c5808, - c5809, - c5810, - c5811, - c5812, - c5813, - c5814, - c5815, - c5816, - c5817, - c5818, - c5819, - c5820, - c5821, - c5822, - c5823, - c5824, - c5825, - c5826, - c5827, - c5828, - c5829, - c5830, - c5831, - c5832, - c5833, - c5834, - c5835, - c5836, - c5837, - c5838, - c5839, - c5840, - c5841, - c5842, - c5843, - c5844, - c5845, - c5846, - c5847, - c5848, - c5849, - c5850, - c5851, - c5852, - c5853, - c5854, - c5855, - c5856, - c5857, - c5858, - c5859, - c5860, - c5861, - c5862, - c5863, - c5864, - c5865, - c5866, - c5867, - c5868, - c5869, - c5870, - c5871, - c5872, - c5873, - c5874, - c5875, - c5876, - c5877, - c5878, - c5879, - c5880, - c5881, - c5882, - c5883, - c5884, - c5885, - c5886, - c5887, - c5888, - c5889, - c5890, - c5891, - c5892, - c5893, - c5894, - c5895, - c5896, - c5897, - c5898, - c5899, - c5900, - c5901, - c5902, - c5903, - c5904, - c5905, - c5906, - c5907, - c5908, - c5909, - c5910, - c5911, - c5912, - c5913, - c5914, - c5915, - c5916, - c5917, - c5918, - c5919, - c5920, - c5921, - c5922, - c5923, - c5924, - c5925, - c5926, - c5927, - c5928, - c5929, - c5930, - c5931, - c5932, - c5933, - c5934, - c5935, - c5936, - c5937, - c5938, - c5939, - c5940, - c5941, - c5942, - c5943, - c5944, - c5945, - c5946, - c5947, - c5948, - c5949, - c5950, - c5951, - c5952, - c5953, - c5954, - c5955, - c5956, - c5957, - c5958, - c5959, - c5960, - c5961, - c5962, - c5963, - c5964, - c5965, - c5966, - c5967, - c5968, - c5969, - c5970, - c5971, - c5972, - c5973, - c5974, - c5975, - c5976, - c5977, - c5978, - c5979, - c5980, - c5981, - c5982, - c5983, - c5984, - c5985, - c5986, - c5987, - c5988, - c5989, - c5990, - c5991, - c5992, - c5993, - c5994, - c5995, - c5996, - c5997, - c5998, - c5999, - c6000, - c6001, - c6002, - c6003, - c6004, - c6005, - c6006, - c6007, - c6008, - c6009, - c6010, - c6011, - c6012, - c6013, - c6014, - c6015, - c6016, - c6017, - c6018, - c6019, - c6020, - c6021, - c6022, - c6023, - c6024, - c6025, - c6026, - c6027, - c6028, - c6029, - c6030, - c6031, - c6032, - c6033, - c6034, - c6035, - c6036, - c6037, - c6038, - c6039, - c6040, - c6041, - c6042, - c6043, - c6044, - c6045, - c6046, - c6047, - c6048, - c6049, - c6050, - c6051, - c6052, - c6053, - c6054, - c6055, - c6056, - c6057, - c6058, - c6059, - c6060, - c6061, - c6062, - c6063, - c6064, - c6065, - c6066, - c6067, - c6068, - c6069, - c6070, - c6071, - c6072, - c6073, - c6074, - c6075, - c6076, - c6077, - c6078, - c6079, - c6080, - c6081, - c6082, - c6083, - c6084, - c6085, - c6086, - c6087, - c6088, - c6089, - c6090, - c6091, - c6092, - c6093, - c6094, - c6095, - c6096, - c6097, - c6098, - c6099, - c6100, - c6101, - c6102, - c6103, - c6104, - c6105, - c6106, - c6107, - c6108, - c6109, - c6110, - c6111, - c6112, - c6113, - c6114, - c6115, - c6116, - c6117, - c6118, - c6119, - c6120, - c6121, - c6122, - c6123, - c6124, - c6125, - c6126, - c6127, - c6128, - c6129, - c6130, - c6131, - c6132, - c6133, - c6134, - c6135, - c6136, - c6137, - c6138, - c6139, - c6140, - c6141, - c6142, - c6143, - c6144, - c6145, - c6146, - c6147, - c6148, - c6149, - c6150, - c6151, - c6152, - c6153, - c6154, - c6155, - c6156, - c6157, - c6158, - c6159, - c6160, - c6161, - c6162, - c6163, - c6164, - c6165, - c6166, - c6167, - c6168, - c6169, - c6170, - c6171, - c6172, - c6173, - c6174, - c6175, - c6176, - c6177, - c6178, - c6179, - c6180, - c6181, - c6182, - c6183, - c6184, - c6185, - c6186, - c6187, - c6188, - c6189, - c6190, - c6191, - c6192, - c6193, - c6194, - c6195, - c6196, - c6197, - c6198, - c6199, - c6200, - c6201, - c6202, - c6203, - c6204, - c6205, - c6206, - c6207, - c6208, - c6209, - c6210, - c6211, - c6212, - c6213, - c6214, - c6215, - c6216, - c6217, - c6218, - c6219, - c6220, - c6221, - c6222, - c6223, - c6224, - c6225, - c6226, - c6227, - c6228, - c6229, - c6230, - c6231, - c6232, - c6233, - c6234, - c6235, - c6236, - c6237, - c6238, - c6239, - c6240, - c6241, - c6242, - c6243, - c6244, - c6245, - c6246, - c6247, - c6248, - c6249, - c6250, - c6251, - c6252, - c6253, - c6254, - c6255, - c6256, - c6257, - c6258, - c6259, - c6260, - c6261, - c6262, - c6263, - c6264, - c6265, - c6266, - c6267, - c6268, - c6269, - c6270, - c6271, - c6272, - c6273, - c6274, - c6275, - c6276, - c6277, - c6278, - c6279, - c6280, - c6281, - c6282, - c6283, - c6284, - c6285, - c6286, - c6287, - c6288, - c6289, - c6290, - c6291, - c6292, - c6293, - c6294, - c6295, - c6296, - c6297, - c6298, - c6299, - c6300, - c6301, - c6302, - c6303, - c6304, - c6305, - c6306, - c6307, - c6308, - c6309, - c6310, - c6311, - c6312, - c6313, - c6314, - c6315, - c6316, - c6317, - c6318, - c6319, - c6320, - c6321, - c6322, - c6323, - c6324, - c6325, - c6326, - c6327, - c6328, - c6329, - c6330, - c6331, - c6332, - c6333, - c6334, - c6335, - c6336, - c6337, - c6338, - c6339, - c6340, - c6341, - c6342, - c6343, - c6344, - c6345, - c6346, - c6347, - c6348, - c6349, - c6350, - c6351, - c6352, - c6353, - c6354, - c6355, - c6356, - c6357, - c6358, - c6359, - c6360, - c6361, - c6362, - c6363, - c6364, - c6365, - c6366, - c6367, - c6368, - c6369, - c6370, - c6371, - c6372, - c6373, - c6374, - c6375, - c6376, - c6377, - c6378, - c6379, - c6380, - c6381, - c6382, - c6383, - c6384, - c6385, - c6386, - c6387, - c6388, - c6389, - c6390, - c6391, - c6392, - c6393, - c6394, - c6395, - c6396, - c6397, - c6398, - c6399, - c6400, - c6401, - c6402, - c6403, - c6404, - c6405, - c6406, - c6407, - c6408, - c6409, - c6410, - c6411, - c6412, - c6413, - c6414, - c6415, - c6416, - c6417, - c6418, - c6419, - c6420, - c6421, - c6422, - c6423, - c6424, - c6425, - c6426, - c6427, - c6428, - c6429, - c6430, - c6431, - c6432, - c6433, - c6434, - c6435, - c6436, - c6437, - c6438, - c6439, - c6440, - c6441, - c6442, - c6443, - c6444, - c6445, - c6446, - c6447, - c6448, - c6449, - c6450, - c6451, - c6452, - c6453, - c6454, - c6455, - c6456, - c6457, - c6458, - c6459, - c6460, - c6461, - c6462, - c6463, - c6464, - c6465, - c6466, - c6467, - c6468, - c6469, - c6470, - c6471, - c6472, - c6473, - c6474, - c6475, - c6476, - c6477, - c6478, - c6479, - c6480, - c6481, - c6482, - c6483, - c6484, - c6485, - c6486, - c6487, - c6488, - c6489, - c6490, - c6491, - c6492, - c6493, - c6494, - c6495, - c6496, - c6497, - c6498, - c6499, - c6500, - c6501, - c6502, - c6503, - c6504, - c6505, - c6506, - c6507, - c6508, - c6509, - c6510, - c6511, - c6512, - c6513, - c6514, - c6515, - c6516, - c6517, - c6518, - c6519, - c6520, - c6521, - c6522, - c6523, - c6524, - c6525, - c6526, - c6527, - c6528, - c6529, - c6530, - c6531, - c6532, - c6533, - c6534, - c6535, - c6536, - c6537, - c6538, - c6539, - c6540, - c6541, - c6542, - ] -) - -# -------------------------------------------------------------------------------------- -# Cells - Level 1 -# -------------------------------------------------------------------------------------- - -c30 = mcdc.cell(-s32, fill=u1) # Name: GT empty stack (0) -c31 = mcdc.cell(+s32 & -s33, fill=u1) # Name: GT empty stack (1) -c32 = mcdc.cell(+s33 & -s34, fill=u1) # Name: GT empty stack (2) -c33 = mcdc.cell(+s34 & -s35, fill=u6) # Name: GT empty stack (3) -c34 = mcdc.cell(+s35 & -s38, fill=u6) # Name: GT empty stack (4) -c35 = mcdc.cell(+s38 & -s39, fill=u7) # Name: GT empty stack (5) -c36 = mcdc.cell(+s39 & -s48, fill=u6) # Name: GT empty stack (6) -c37 = mcdc.cell(+s48 & -s40, fill=u2) # Name: GT empty stack (7) -c38 = mcdc.cell(+s40 & -s41, fill=u4) # Name: GT empty stack (8) -c39 = mcdc.cell(+s41 & -s42, fill=u2) # Name: GT empty stack (9) -c40 = mcdc.cell(+s42 & -s43, fill=u4) # Name: GT empty stack (10) -c41 = mcdc.cell(+s43 & -s44, fill=u2) # Name: GT empty stack (11) -c42 = mcdc.cell(+s44 & -s45, fill=u4) # Name: GT empty stack (12) -c43 = mcdc.cell(+s45 & -s36, fill=u2) # Name: GT empty stack (13) -c44 = mcdc.cell(+s36 & -s46, fill=u2) # Name: GT empty stack (14) -c45 = mcdc.cell(+s46 & -s47, fill=u4) # Name: GT empty stack (15) -c46 = mcdc.cell(+s47 & -s49, fill=u2) # Name: GT empty stack (16) -c47 = mcdc.cell(+s49 & -s50, fill=u2) # Name: GT empty stack (17) -c48 = mcdc.cell(+s50 & -s51, fill=u2) # Name: GT empty stack (18) -c49 = mcdc.cell(+s51 & -s52, fill=u1) # Name: GT empty stack (19) -c50 = mcdc.cell(+s52, fill=u1) # Name: GT empty stack (20) -c51 = mcdc.cell(-s32, fill=u1) # Name: GT empty instr (0) -c52 = mcdc.cell(+s32 & -s33, fill=u1) # Name: GT empty instr (1) -c53 = mcdc.cell(+s33 & -s34, fill=u1) # Name: GT empty instr (2) -c54 = mcdc.cell(+s34 & -s35, fill=u2) # Name: GT empty instr (3) -c55 = mcdc.cell(+s35 & -s38, fill=u2) # Name: GT empty instr (4) -c56 = mcdc.cell(+s38 & -s39, fill=u3) # Name: GT empty instr (5) -c57 = mcdc.cell(+s39 & -s48, fill=u2) # Name: GT empty instr (6) -c58 = mcdc.cell(+s48 & -s40, fill=u2) # Name: GT empty instr (7) -c59 = mcdc.cell(+s40 & -s41, fill=u4) # Name: GT empty instr (8) -c60 = mcdc.cell(+s41 & -s42, fill=u2) # Name: GT empty instr (9) -c61 = mcdc.cell(+s42 & -s43, fill=u4) # Name: GT empty instr (10) -c62 = mcdc.cell(+s43 & -s44, fill=u2) # Name: GT empty instr (11) -c63 = mcdc.cell(+s44 & -s45, fill=u4) # Name: GT empty instr (12) -c64 = mcdc.cell(+s45 & -s36, fill=u2) # Name: GT empty instr (13) -c65 = mcdc.cell(+s36 & -s46, fill=u2) # Name: GT empty instr (14) -c66 = mcdc.cell(+s46 & -s47, fill=u4) # Name: GT empty instr (15) -c67 = mcdc.cell(+s47 & -s49, fill=u2) # Name: GT empty instr (16) -c68 = mcdc.cell(+s49 & -s50, fill=u2) # Name: GT empty instr (17) -c69 = mcdc.cell(+s50 & -s51, fill=u2) # Name: GT empty instr (18) -c70 = mcdc.cell(+s51 & -s52, fill=u1) # Name: GT empty instr (19) -c71 = mcdc.cell(+s52, fill=u1) # Name: GT empty instr (20) -c2573 = mcdc.cell(-s38 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o0) -c2574 = mcdc.cell(+s38 & -s39 & +s1, fill=u88) # Name: Fuel pin (1.6%) stack (o1) -c2575 = mcdc.cell(+s39 & -s48 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o2) -c2576 = mcdc.cell(+s48 & -s40 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o3) -c2577 = mcdc.cell(+s40 & -s41 & +s1, fill=u89) # Name: Fuel pin (1.6%) stack (o4) -c2578 = mcdc.cell(+s41 & -s42 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o5) -c2579 = mcdc.cell(+s42 & -s43 & +s1, fill=u89) # Name: Fuel pin (1.6%) stack (o6) -c2580 = mcdc.cell(+s43 & -s44 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o7) -c2581 = mcdc.cell(+s44 & -s45 & +s1, fill=u89) # Name: Fuel pin (1.6%) stack (o8) -c2582 = mcdc.cell(+s45 & +s1, fill=u87) # Name: Fuel pin (1.6%) stack (o9) -c2583 = mcdc.cell(-s1, fill=u86) # Name: Fuel pin (1.6%) stack (i) -c2584 = mcdc.cell(-s32, fill=u1) # Name: Fuel (1.6%) stack (0) -c2585 = mcdc.cell(+s32 & -s33, fill=u82) # Name: Fuel (1.6%) stack (1) -c2586 = mcdc.cell(+s33 & -s34, fill=u82) # Name: Fuel (1.6%) stack (2) -c2587 = mcdc.cell(+s34 & -s35, fill=u83) # Name: Fuel (1.6%) stack (3) -c2589 = mcdc.cell(+s36 & -s46, fill=u84) # Name: Fuel (1.6%) stack (5) -c2590 = mcdc.cell(+s46 & -s47, fill=u85) # Name: Fuel (1.6%) stack (6) -c2591 = mcdc.cell(+s47 & -s49, fill=u84) # Name: Fuel (1.6%) stack (7) -c2592 = mcdc.cell(+s49 & -s50, fill=u83) # Name: Fuel (1.6%) stack (8) -c2593 = mcdc.cell(+s50 & -s51, fill=u1) # Name: Fuel (1.6%) stack (9) -c2594 = mcdc.cell(+s51 & -s52, fill=u82) # Name: Fuel (1.6%) stack (10) -c2595 = mcdc.cell(+s52, fill=u1) # Name: Fuel (1.6%) stack (11) -c4560 = mcdc.cell(-s38 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o0) -c4561 = mcdc.cell(+s38 & -s39 & +s1, fill=u88) # Name: Fuel pin (2.4%) stack (o1) -c4562 = mcdc.cell(+s39 & -s48 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o2) -c4563 = mcdc.cell(+s48 & -s40 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o3) -c4564 = mcdc.cell(+s40 & -s41 & +s1, fill=u89) # Name: Fuel pin (2.4%) stack (o4) -c4565 = mcdc.cell(+s41 & -s42 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o5) -c4566 = mcdc.cell(+s42 & -s43 & +s1, fill=u89) # Name: Fuel pin (2.4%) stack (o6) -c4567 = mcdc.cell(+s43 & -s44 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o7) -c4568 = mcdc.cell(+s44 & -s45 & +s1, fill=u89) # Name: Fuel pin (2.4%) stack (o8) -c4569 = mcdc.cell(+s45 & +s1, fill=u87) # Name: Fuel pin (2.4%) stack (o9) -c4570 = mcdc.cell(-s1, fill=u93) # Name: Fuel pin (2.4%) stack (i) -c4571 = mcdc.cell(-s32, fill=u1) # Name: Fuel (2.4%) stack (0) -c4572 = mcdc.cell(+s32 & -s33, fill=u82) # Name: Fuel (2.4%) stack (1) -c4573 = mcdc.cell(+s33 & -s34, fill=u82) # Name: Fuel (2.4%) stack (2) -c4574 = mcdc.cell(+s34 & -s35, fill=u83) # Name: Fuel (2.4%) stack (3) -c4576 = mcdc.cell(+s36 & -s46, fill=u84) # Name: Fuel (2.4%) stack (5) -c4577 = mcdc.cell(+s46 & -s47, fill=u85) # Name: Fuel (2.4%) stack (6) -c4578 = mcdc.cell(+s47 & -s49, fill=u84) # Name: Fuel (2.4%) stack (7) -c4579 = mcdc.cell(+s49 & -s50, fill=u83) # Name: Fuel (2.4%) stack (8) -c4580 = mcdc.cell(+s50 & -s51, fill=u1) # Name: Fuel (2.4%) stack (9) -c4581 = mcdc.cell(+s51 & -s52, fill=u82) # Name: Fuel (2.4%) stack (10) -c4582 = mcdc.cell(+s52, fill=u1) # Name: Fuel (2.4%) stack (11) -c6743 = mcdc.cell(-s38 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o0) -c6744 = mcdc.cell(+s38 & -s39 & +s1, fill=u88) # Name: Fuel pin (3.1%) stack (o1) -c6745 = mcdc.cell(+s39 & -s48 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o2) -c6746 = mcdc.cell(+s48 & -s40 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o3) -c6747 = mcdc.cell(+s40 & -s41 & +s1, fill=u89) # Name: Fuel pin (3.1%) stack (o4) -c6748 = mcdc.cell(+s41 & -s42 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o5) -c6749 = mcdc.cell(+s42 & -s43 & +s1, fill=u89) # Name: Fuel pin (3.1%) stack (o6) -c6750 = mcdc.cell(+s43 & -s44 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o7) -c6751 = mcdc.cell(+s44 & -s45 & +s1, fill=u89) # Name: Fuel pin (3.1%) stack (o8) -c6752 = mcdc.cell(+s45 & +s1, fill=u87) # Name: Fuel pin (3.1%) stack (o9) -c6753 = mcdc.cell(-s1, fill=u97) # Name: Fuel pin (3.1%) stack (i) -c6754 = mcdc.cell(-s32, fill=u1) # Name: Fuel (3.1%) stack (0) -c6755 = mcdc.cell(+s32 & -s33, fill=u82) # Name: Fuel (3.1%) stack (1) -c6756 = mcdc.cell(+s33 & -s34, fill=u82) # Name: Fuel (3.1%) stack (2) -c6757 = mcdc.cell(+s34 & -s35, fill=u83) # Name: Fuel (3.1%) stack (3) -c6759 = mcdc.cell(+s36 & -s46, fill=u84) # Name: Fuel (3.1%) stack (5) -c6760 = mcdc.cell(+s46 & -s47, fill=u85) # Name: Fuel (3.1%) stack (6) -c6761 = mcdc.cell(+s47 & -s49, fill=u84) # Name: Fuel (3.1%) stack (7) -c6762 = mcdc.cell(+s49 & -s50, fill=u83) # Name: Fuel (3.1%) stack (8) -c6763 = mcdc.cell(+s50 & -s51, fill=u1) # Name: Fuel (3.1%) stack (9) -c6764 = mcdc.cell(+s51 & -s52, fill=u82) # Name: Fuel (3.1%) stack (10) -c6765 = mcdc.cell(+s52, fill=u1) # Name: Fuel (3.1%) stack (11) -c7158 = mcdc.cell(fill=u154, rotation=[-0.0, -0.0, 90.0]) # Name: reflector NE -c7159 = mcdc.cell(fill=u154, rotation=[-0.0, -0.0, -90.0]) # Name: reflector SW -c7160 = mcdc.cell(fill=u154, rotation=[-0.0, -0.0, -180.0]) # Name: reflector SE -c7161 = mcdc.cell(fill=u159, rotation=[-0.0, -180.0, 90.0]) # Name: reflector 0,2 -c7162 = mcdc.cell(fill=u158, rotation=[-0.0, -0.0, 90.0]) # Name: reflector 0,3 -c7163 = mcdc.cell(fill=u156, rotation=[-0.0, -0.0, 90.0]) # Name: reflector 0,4 -c7164 = mcdc.cell(fill=u157, rotation=[-0.0, -0.0, 90.0]) # Name: reflector 0,5 -c7165 = mcdc.cell(fill=u159, rotation=[-0.0, -0.0, 90.0]) # Name: reflector 0,6 -c7166 = mcdc.cell(fill=u155, rotation=[-0.0, -0.0, 90.0]) # Name: reflector 1,7 -c7167 = mcdc.cell(fill=u159, rotation=[-0.0, -180.0, -0.0]) # Name: reflector 2,8 -c7168 = mcdc.cell(fill=u157, rotation=[-0.0, -180.0, -0.0]) # Name: reflector 3,8 -c7169 = mcdc.cell(fill=u156, rotation=[-0.0, -180.0, -0.0]) # Name: reflector 4,8 -c7170 = mcdc.cell(fill=u157, rotation=[-0.0, -0.0, -180.0]) # Name: reflector 5,8 -c7171 = mcdc.cell(fill=u159, rotation=[-180.0, -0.0, -0.0]) # Name: reflector 6,0 -c7172 = mcdc.cell(fill=u159, rotation=[-0.0, -0.0, -180.0]) # Name: reflector 6,8 -c7173 = mcdc.cell(fill=u155, rotation=[-180.0, -0.0, -0.0]) # Name: reflector 7,1 -c7174 = mcdc.cell(fill=u155, rotation=[-0.0, -0.0, -180.0]) # Name: reflector 7,7 -c7175 = mcdc.cell(fill=u159, rotation=[-0.0, -0.0, -90.0]) # Name: reflector 8,2 -c7176 = mcdc.cell(fill=u157, rotation=[-0.0, -0.0, -90.0]) # Name: reflector 8,3 -c7177 = mcdc.cell(fill=u156, rotation=[-0.0, -0.0, -90.0]) # Name: reflector 8,4 -c7178 = mcdc.cell(fill=u158, rotation=[-0.0, -0.0, -90.0]) # Name: reflector 8,5 -c7179 = mcdc.cell(fill=u159, rotation=[-0.0, -0.0, -180.0]) # Name: reflector 8,6 - -# -------------------------------------------------------------------------------------- -# Universes - Level 2 -# -------------------------------------------------------------------------------------- - -u10 = mcdc.universe( - [ - c30, - c31, - c32, - c33, - c34, - c35, - c36, - c37, - c38, - c39, - c40, - c41, - c42, - c43, - c44, - c45, - c46, - c47, - c48, - c49, - c50, - ] -) -u100 = mcdc.universe( - [c6743, c6744, c6745, c6746, c6747, c6748, c6749, c6750, c6751, c6752, c6753] -) -u11 = mcdc.universe( - [ - c51, - c52, - c53, - c54, - c55, - c56, - c57, - c58, - c59, - c60, - c61, - c62, - c63, - c64, - c65, - c66, - c67, - c68, - c69, - c70, - c71, - ] -) -u160 = mcdc.universe([c7158]) -u161 = mcdc.universe([c7159]) -u162 = mcdc.universe([c7160]) -u163 = mcdc.universe([c7161]) -u164 = mcdc.universe([c7162]) -u165 = mcdc.universe([c7163]) -u166 = mcdc.universe([c7164]) -u167 = mcdc.universe([c7165]) -u168 = mcdc.universe([c7166]) -u169 = mcdc.universe([c7167]) -u170 = mcdc.universe([c7168]) -u171 = mcdc.universe([c7169]) -u172 = mcdc.universe([c7170]) -u173 = mcdc.universe([c7171]) -u174 = mcdc.universe([c7172]) -u175 = mcdc.universe([c7173]) -u176 = mcdc.universe([c7174]) -u177 = mcdc.universe([c7175]) -u178 = mcdc.universe([c7176]) -u179 = mcdc.universe([c7177]) -u180 = mcdc.universe([c7178]) -u181 = mcdc.universe([c7179]) -u91 = mcdc.universe( - [c2573, c2574, c2575, c2576, c2577, c2578, c2579, c2580, c2581, c2582, c2583] -) -u95 = mcdc.universe( - [c4560, c4561, c4562, c4563, c4564, c4565, c4566, c4567, c4568, c4569, c4570] -) - -# -------------------------------------------------------------------------------------- -# Cells - Level 2 -# -------------------------------------------------------------------------------------- - -c2588 = mcdc.cell(+s35 & -s36, fill=u91) # Name: Fuel (1.6%) stack (4) -c4575 = mcdc.cell(+s35 & -s36, fill=u95) # Name: Fuel (2.4%) stack (4) -c6758 = mcdc.cell(+s35 & -s36, fill=u100) # Name: Fuel (3.1%) stack (4) - -# -------------------------------------------------------------------------------------- -# Universes - Level 3 -# -------------------------------------------------------------------------------------- - -u101 = mcdc.universe( - [c6754, c6755, c6756, c6757, c6758, c6759, c6760, c6761, c6762, c6763, c6764, c6765] -) -u92 = mcdc.universe( - [c2584, c2585, c2586, c2587, c2588, c2589, c2590, c2591, c2592, c2593, c2594, c2595] -) -u96 = mcdc.universe( - [c4571, c4572, c4573, c4574, c4575, c4576, c4577, c4578, c4579, c4580, c4581, c4582] -) - -# -------------------------------------------------------------------------------------- -# Lattices - Level 3 -# -------------------------------------------------------------------------------------- - -# Lattice name: Assembly (1.6%) no BAs -l102 = mcdc.lattice( - x=[-10.70864, 1.25984, 17], - y=[-10.70864, 1.25984, 17], - universes=[ - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u10, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u10, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u11, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u10, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u10, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u10, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - [ - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - u92, - ], - ], -) - -# Lattice name: Assembly (2.4%) no BAs -l138 = mcdc.lattice( - x=[-10.70864, 1.25984, 17], - y=[-10.70864, 1.25984, 17], - universes=[ - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u10, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u10, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u11, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u10, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u10, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u10, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - [ - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - u96, - ], - ], -) - -# Lattice name: Assembly (3.1%) no BAs -l146 = mcdc.lattice( - x=[-10.70864, 1.25984, 17], - y=[-10.70864, 1.25984, 17], - universes=[ - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u10, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u10, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u11, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u10, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u10, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u10, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - [ - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - u101, - ], - ], -) - -# -------------------------------------------------------------------------------------- -# Cells - Level 3 -# -------------------------------------------------------------------------------------- - -c6766 = mcdc.cell( - +s24 & -s25 & +s26 & -s27, fill=l102 -) # Name: Assembly (1.6%) no BAs lattice -c7000 = mcdc.cell( - +s24 & -s25 & +s26 & -s27, fill=l138 -) # Name: Assembly (2.4%) no BAs lattice -c7052 = mcdc.cell( - +s24 & -s25 & +s26 & -s27, fill=l146 -) # Name: Assembly (3.1%) no BAs lattice - -# -------------------------------------------------------------------------------------- -# Universes - Level 4 -# -------------------------------------------------------------------------------------- - -u103 = mcdc.universe( - [ - c6766, - c6767, - c6768, - c6769, - c6770, - c6771, - c6772, - c6773, - c6774, - c6775, - c6776, - c6777, - c6778, - ] -) -u139 = mcdc.universe( - [ - c7000, - c7001, - c7002, - c7003, - c7004, - c7005, - c7006, - c7007, - c7008, - c7009, - c7010, - c7011, - c7012, - ] -) -u147 = mcdc.universe( - [ - c7052, - c7053, - c7054, - c7055, - c7056, - c7057, - c7058, - c7059, - c7060, - c7061, - c7062, - c7063, - c7064, - ] -) - -# -------------------------------------------------------------------------------------- -# Lattices - Level 4 -# -------------------------------------------------------------------------------------- - -# Lattice name: Main core -l183 = mcdc.lattice( - x=[-96.76637999999998, 21.503639999999997, 9], - y=[-96.76637999999998, 21.503639999999997, 9], - universes=[ - [u182, u182, u163, u164, u165, u166, u167, u182, u182], - [u182, u155, u154, u147, u147, u147, u160, u168, u182], - [u159, u154, u147, u139, u103, u139, u147, u160, u169], - [u157, u147, u139, u103, u103, u103, u139, u147, u170], - [u156, u147, u103, u103, u139, u103, u103, u147, u171], - [u158, u147, u139, u103, u103, u103, u139, u147, u172], - [u173, u161, u147, u139, u103, u139, u147, u162, u174], - [u182, u175, u161, u147, u147, u147, u162, u176, u182], - [u182, u182, u177, u178, u179, u180, u181, u182, u182], - ], -) - -# -------------------------------------------------------------------------------------- -# Cells - Level 4 -# -------------------------------------------------------------------------------------- - -c7181 = mcdc.cell(-s71 & +s81 & -s80, fill=l183) # Name: Main core - -# -------------------------------------------------------------------------------------- -# Universes - Level 5 -# -------------------------------------------------------------------------------------- - -u0 = mcdc.universe([c7181, c7182, c7183, c7184], root=True) - -# ============================================================================= -# Set source -# ============================================================================= - -mcdc.source( - energy=np.array([[1e6 - 1, 1e6 + 1], [1.0, 1.0]]), - isotropic=True, -) - -# ============================================================================= -# Set tally and parameter, and then run mcdc -# ============================================================================= - -# Tally -x_grid = np.linspace(-133.25, 133.25, 101) -y_grid = np.linspace(-133.25, 133.25, 101) -z_grid = np.linspace(-36.6205, 246.61149999999998, 101) - -mcdc.tally.mesh_tally( - scores=["flux"], - x=x_grid, - y=y_grid, - z=z_grid, - E=np.array([0.0, 0.625, 2e7]), -) - -# Setting -mcdc.setting(N_particle=1e2) - -mcdc.eigenmode(N_inactive=10, N_active=20, gyration_radius="all") -mcdc.population_control() - -# Run -mcdc.run() - -# Plot -""" -colors = { - m1: "azure", - m3: "gray", - m4: "sienna", - m5: "tan", - m6: "olive", - m7: "slategray", - m8: "black", - m18: "red", - m28: "orange", - m38: "gold", - m10: 'blue', -} -mcdc.visualize('xy', x=[-150, 150], y=[-150, 150], z=100.0, pixels=(200, 200), colors=colors) -""" diff --git a/examples/fixed_source/azurv1_pl_super/process.py b/examples/fixed_source/azurv1_pl_super/process.py deleted file mode 100644 index ed34724eb..000000000 --- a/examples/fixed_source/azurv1_pl_super/process.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.animation as animation -import h5py - - -# Reference solution -data = np.load("reference.npz") -phi_ref = data["phi"] - -# Get results -with h5py.File("output.h5", "r") as f: - tallies = f["tallies/mesh_tally_0"] - flux = tallies["flux"] - grid = tallies["grid"] - x = grid["x"][:] - dx = x[1:] - x[:-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - t = grid["t"][:] - dt = t[1:] - t[:-1] - K = len(t) - 1 - - phi = flux["mean"][:] - phi_sd = flux["sdev"][:] - - # Normalize - for k in range(K): - phi[k] /= dx * dt[k] - phi_sd[k] /= dx * dt[k] - -# Flux - average -fig = plt.figure() -ax = plt.axes( - xlim=(-21.889999999999997, 21.89), ylim=(-0.042992644459595206, 0.9028455336514992) -) -ax.grid() -ax.set_xlabel(r"$x$") -ax.set_ylabel(r"Flux") -ax.set_title(r"$\bar{\phi}_{k,j}$") -(line1,) = ax.plot([], [], "-b", label="MC") -(line2,) = ax.plot([], [], "--r", label="Ref.") -fb = ax.fill_between([], [], [], [], alpha=0.2, color="b") -text = ax.text(0.02, 0.9, "", transform=ax.transAxes) -ax.legend() - - -def animate(k): - global fb - fb.remove() - line1.set_data(x_mid, phi[k, :]) - fb = ax.fill_between( - x_mid, phi[k, :] - phi_sd[k, :], phi[k, :] + phi_sd[k, :], alpha=0.2, color="b" - ) - line2.set_data(x_mid, phi_ref[k, :]) - text.set_text(r"$t \in [%.1f,%.1f]$ s" % (t[k], t[k + 1])) - return line1, line2, text - - -simulation = animation.FuncAnimation(fig, animate, frames=K) -simulation.save( - "azurv1.gif", - fps=4, - writer="imagemagick", - savefig_kwargs={"bbox_inches": "tight", "pad_inches": 0}, -) -plt.show() diff --git a/examples/fixed_source/azurv1_pl_super/reference.npz b/examples/fixed_source/azurv1_pl_super/reference.npz deleted file mode 100644 index f4cccebe4..000000000 Binary files a/examples/fixed_source/azurv1_pl_super/reference.npz and /dev/null differ diff --git a/examples/fixed_source/azurv1_pl_super/reference.py b/examples/fixed_source/azurv1_pl_super/reference.py deleted file mode 100644 index a2ad8f67e..000000000 --- a/examples/fixed_source/azurv1_pl_super/reference.py +++ /dev/null @@ -1,72 +0,0 @@ -import numpy as np -from scipy.integrate import quad - - -# ============================================================================= -# Reference solution generator -# ============================================================================= - -# Scattering ratio -c = 1.1 -i = complex(0, 1) - -# Spatial grid -J = 201 -x = np.linspace(-20.5, 20.5, J + 1) - -# Time grid -K = 20 -t = np.linspace(0.0, 20.0, K + 1) - - -def integrand(u, eta, t): - q = (1 + eta) / (1 - eta) - xi = (np.log(q) + i * u) / (eta + i * np.tan(u / 2)) - return ( - 1.0 - / (np.cos(u / 2)) ** 2 - * (xi**2 * np.e ** (c * t / 2 * (1 - eta**2) * xi)).real - ) - - -def phi(x, t): - if t == 0.0 or abs(x) >= t: - return 0.0 - eta = x / t - integral = quad(integrand, 0.0, np.pi, args=(eta, t))[0] - return np.e**-t / 2 / t * (1 + c * t / 4 / np.pi * (1 - eta**2) * integral) - - -def phi_t(t, x): - if t == 0.0 or abs(x) >= t: - return 0.0 - eta = x / t - integral = quad(integrand, 0.0, np.pi, args=(eta, t))[0] - return np.e**-t / 2 / t * (1 + c * t / 4 / np.pi * (1 - eta**2) * integral) - - -def phiX(x, t0, t1): - return quad(phi_t, t0, t1, args=(x))[0] - - -phi_avg = np.zeros([K, J]) - -for k in range(K): - for j in range(J): - x0 = x[j] - x1 = x[j + 1] - dx = x1 - x0 - t0 = t[k] - t1 = t[k + 1] - dt = t1 - t0 - phi_avg[k, j] = quad(phiX, x0, x1, args=(t0, t1))[0] / dx / dt - -for j in range(J + 1): - for k in range(K): - t0 = t[k] - t1 = t[k + 1] - dt = t1 - t0 - -phi_avg = np.nan_to_num(phi_avg) - -np.savez("reference.npz", x=x, t=t, phi=phi_avg) diff --git a/examples/fixed_source/azurv1_pl_super_ww/input.py b/examples/fixed_source/azurv1_pl_super_ww/input.py deleted file mode 100644 index 1988f1ce0..000000000 --- a/examples/fixed_source/azurv1_pl_super_ww/input.py +++ /dev/null @@ -1,96 +0,0 @@ -import numpy as np - -import mcdc, mpi4py, h5py - -# ============================================================================= -# Set model -# ============================================================================= -# Infinite medium with isotropic plane surface at the center -# Based on Ganapol LA-UR-01-1854 (AZURV1 benchmark) -# Effective scattering ratio c = 1.1 -N_history = 1e2 -# Set materials -m = mcdc.material( - capture=np.array([1.0 / 3.0]), - scatter=np.array([[1.0 / 3.0]]), - fission=np.array([1.0 / 3.0]), - nu_p=np.array([2.3]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") - -# Set cells -mcdc.cell(+s1 & -s2, m) - -# ============================================================================= -# Set source -# ============================================================================= -# Isotropic pulse at x=t=0 - -mcdc.source(point=[0.0, 0.0, 0.0], isotropic=True, time=[1e-10, 1e-10]) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: cell-average, cell-edge, and time-edge scalar fluxes -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(-20.5, 20.5, 202), - t=np.linspace(0.0, 20.0, 21), -) - -# Setting -mcdc.setting( - N_particle=N_history, - active_bank_buff=1e4, - census_bank_buff=1e3, - source_bank_buff=1e3, -) -mcdc.time_census(np.linspace(0.0, 20.0, 21)[1:], tally_frequency=1) - -mcdc.weight_window( - x=np.linspace(-20.5, 20.5, 202), - method="previous", - modifications=[["min-center", 1e-3]], - width=2.5, - save_ww_data=True, -) - -# Run -mcdc.run() -# Combine the tally output into a single file -if mpi4py.MPI.COMM_WORLD.Get_rank() == 0: - phi = np.zeros((20, 201)) - phi_sd = np.zeros((20, 201)) - centers = np.zeros((20, 201)) - N_census = 20 - N_batch = 1 - N_tallies = 1 - for i_census in range(N_census): - for i_batch in range(N_batch): - with h5py.File( - "output-batch_%i-census_%i.h5" % (i_batch, i_census), "r" - ) as f: - phi_score = f["tallies/mesh_tally_0/flux/score"][:] - window_centers = f["weight_window_centers"][:] - phi[ - N_tallies * i_census : N_tallies * i_census + N_tallies, : - ] += phi_score - phi_sd[N_tallies * i_census : N_tallies * i_census + N_tallies, :] += ( - phi_score * phi_score - ) - centers[ - N_tallies * i_census : N_tallies * i_census + N_tallies, : - ] += np.squeeze(window_centers) - phi /= N_batch - phi_sd = np.sqrt( - (phi_sd / N_history - np.square(phi / N_history)) / (N_history - 1) - ) - # Write the results - with h5py.File("output.h5", "a") as f: - f.create_dataset("tallies/mesh_tally_0/flux/mean", data=phi) - f.create_dataset("tallies/mesh_tally_0/flux/sdev", data=phi_sd) - f.create_dataset("weight_window_centers", data=centers) diff --git a/examples/fixed_source/azurv1_pl_super_ww/process.py b/examples/fixed_source/azurv1_pl_super_ww/process.py deleted file mode 100644 index ed34724eb..000000000 --- a/examples/fixed_source/azurv1_pl_super_ww/process.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.animation as animation -import h5py - - -# Reference solution -data = np.load("reference.npz") -phi_ref = data["phi"] - -# Get results -with h5py.File("output.h5", "r") as f: - tallies = f["tallies/mesh_tally_0"] - flux = tallies["flux"] - grid = tallies["grid"] - x = grid["x"][:] - dx = x[1:] - x[:-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - t = grid["t"][:] - dt = t[1:] - t[:-1] - K = len(t) - 1 - - phi = flux["mean"][:] - phi_sd = flux["sdev"][:] - - # Normalize - for k in range(K): - phi[k] /= dx * dt[k] - phi_sd[k] /= dx * dt[k] - -# Flux - average -fig = plt.figure() -ax = plt.axes( - xlim=(-21.889999999999997, 21.89), ylim=(-0.042992644459595206, 0.9028455336514992) -) -ax.grid() -ax.set_xlabel(r"$x$") -ax.set_ylabel(r"Flux") -ax.set_title(r"$\bar{\phi}_{k,j}$") -(line1,) = ax.plot([], [], "-b", label="MC") -(line2,) = ax.plot([], [], "--r", label="Ref.") -fb = ax.fill_between([], [], [], [], alpha=0.2, color="b") -text = ax.text(0.02, 0.9, "", transform=ax.transAxes) -ax.legend() - - -def animate(k): - global fb - fb.remove() - line1.set_data(x_mid, phi[k, :]) - fb = ax.fill_between( - x_mid, phi[k, :] - phi_sd[k, :], phi[k, :] + phi_sd[k, :], alpha=0.2, color="b" - ) - line2.set_data(x_mid, phi_ref[k, :]) - text.set_text(r"$t \in [%.1f,%.1f]$ s" % (t[k], t[k + 1])) - return line1, line2, text - - -simulation = animation.FuncAnimation(fig, animate, frames=K) -simulation.save( - "azurv1.gif", - fps=4, - writer="imagemagick", - savefig_kwargs={"bbox_inches": "tight", "pad_inches": 0}, -) -plt.show() diff --git a/examples/fixed_source/azurv1_pl_super_ww/reference.npz b/examples/fixed_source/azurv1_pl_super_ww/reference.npz deleted file mode 100644 index f4cccebe4..000000000 Binary files a/examples/fixed_source/azurv1_pl_super_ww/reference.npz and /dev/null differ diff --git a/examples/fixed_source/azurv1_pl_super_ww/reference.py b/examples/fixed_source/azurv1_pl_super_ww/reference.py deleted file mode 100644 index a2ad8f67e..000000000 --- a/examples/fixed_source/azurv1_pl_super_ww/reference.py +++ /dev/null @@ -1,72 +0,0 @@ -import numpy as np -from scipy.integrate import quad - - -# ============================================================================= -# Reference solution generator -# ============================================================================= - -# Scattering ratio -c = 1.1 -i = complex(0, 1) - -# Spatial grid -J = 201 -x = np.linspace(-20.5, 20.5, J + 1) - -# Time grid -K = 20 -t = np.linspace(0.0, 20.0, K + 1) - - -def integrand(u, eta, t): - q = (1 + eta) / (1 - eta) - xi = (np.log(q) + i * u) / (eta + i * np.tan(u / 2)) - return ( - 1.0 - / (np.cos(u / 2)) ** 2 - * (xi**2 * np.e ** (c * t / 2 * (1 - eta**2) * xi)).real - ) - - -def phi(x, t): - if t == 0.0 or abs(x) >= t: - return 0.0 - eta = x / t - integral = quad(integrand, 0.0, np.pi, args=(eta, t))[0] - return np.e**-t / 2 / t * (1 + c * t / 4 / np.pi * (1 - eta**2) * integral) - - -def phi_t(t, x): - if t == 0.0 or abs(x) >= t: - return 0.0 - eta = x / t - integral = quad(integrand, 0.0, np.pi, args=(eta, t))[0] - return np.e**-t / 2 / t * (1 + c * t / 4 / np.pi * (1 - eta**2) * integral) - - -def phiX(x, t0, t1): - return quad(phi_t, t0, t1, args=(x))[0] - - -phi_avg = np.zeros([K, J]) - -for k in range(K): - for j in range(J): - x0 = x[j] - x1 = x[j + 1] - dx = x1 - x0 - t0 = t[k] - t1 = t[k + 1] - dt = t1 - t0 - phi_avg[k, j] = quad(phiX, x0, x1, args=(t0, t1))[0] / dx / dt - -for j in range(J + 1): - for k in range(K): - t0 = t[k] - t1 = t[k + 1] - dt = t1 - t0 - -phi_avg = np.nan_to_num(phi_avg) - -np.savez("reference.npz", x=x, t=t, phi=phi_avg) diff --git a/examples/fixed_source/cooper1/input.py b/examples/fixed_source/cooper1/input.py deleted file mode 100644 index 082b26700..000000000 --- a/examples/fixed_source/cooper1/input.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# A problem based on Problem 1 of [Coper NSE 2001] -# https://ans.tandfonline.com/action/showCitFormats?doi=10.13182/NSE00-34 - -# Set materials -SigmaT = 0.01 -c = 0.8 -m_duct = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=1.0) -sy3 = mcdc.surface("plane-y", y=2.6) -sy4 = mcdc.surface("plane-y", y=3) -sy5 = mcdc.surface("plane-y", y=4.0, bc="vacuum") - -# Set cells -# Room -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy5, m_room) -mcdc.cell(+sx1 & -sx4 & +sy4 & -sy5, m_room) -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy3, m_room) - -# Duct Channel -channel_1 = +sx2 & -sx3 & +sy2 & -sy3 -channel_2 = +sx2 & -sx4 & +sy3 & -sy4 -mcdc.cell(channel_1 | channel_2, m_duct) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source(x=[0.0, 1.0], y=[0.0, 1.0], isotropic=True) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 4.0, 40), - y=np.linspace(0.0, 4.0, 40), -) - -# Setting -mcdc.setting(N_particle=50) -mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/examples/fixed_source/cooper1/process.py b/examples/fixed_source/cooper1/process.py deleted file mode 100644 index 7bbfe3c9d..000000000 --- a/examples/fixed_source/cooper1/process.py +++ /dev/null @@ -1,38 +0,0 @@ -import matplotlib.pyplot as plt -import h5py -import numpy as np - -# Load result -with h5py.File("output.h5", "r") as f: - tally = f["tallies/mesh_tally_0"] - x = tally["grid/x"][:] - dx = [x[1:] - x[:-1]][-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - - phi = tally["flux/mean"][:] - phi_sd = tally["flux/sdev"][:] - - -# Plot result -X, Y = np.meshgrid(x_mid, x_mid) -Z = phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() - -Z = phi_sd / phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux rel. stdev.", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() diff --git a/examples/fixed_source/cooper2/input.py b/examples/fixed_source/cooper2/input.py deleted file mode 100644 index b2363580b..000000000 --- a/examples/fixed_source/cooper2/input.py +++ /dev/null @@ -1,55 +0,0 @@ -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# A shielding problem based on Problem 2 of [Coper NSE 2001] -# https://ans.tandfonline.com/action/showCitFormats?doi=10.13182/NSE00-34 - -# Set materials -SigmaT = 5.0 -c = 0.8 -m_barrier = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=2.0) -sy3 = mcdc.surface("plane-y", y=4.0, bc="vacuum") - -# Set cells -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2, m_room) -mcdc.cell(+sx1 & -sx4 & +sy2 & -sy3, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy2, m_room) -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_barrier) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source(x=[0.0, 1.0], y=[0.0, 1.0], isotropic=True) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 4.0, 40), - y=np.linspace(0.0, 4.0, 40), -) - -# Setting -mcdc.setting(N_particle=50) -mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/examples/fixed_source/cooper2/process.py b/examples/fixed_source/cooper2/process.py deleted file mode 100644 index bb77cc821..000000000 --- a/examples/fixed_source/cooper2/process.py +++ /dev/null @@ -1,38 +0,0 @@ -import matplotlib.pyplot as plt -import h5py -import numpy as np - - -# Load result -with h5py.File("output.h5", "r") as f: - x = f["tallies/mesh_tally_0/grid/x"][:] - dx = [x[1:] - x[:-1]][-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - - phi = f["tallies/mesh_tally_0/flux/mean"][:] - phi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] - - -# Plot result -X, Y = np.meshgrid(x_mid, x_mid) -Z = phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() - -Z = phi_sd / phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux rel. stdev.", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() diff --git a/examples/fixed_source/cooper2_iqmc/input.py b/examples/fixed_source/cooper2_iqmc/input.py deleted file mode 100644 index d5472b351..000000000 --- a/examples/fixed_source/cooper2_iqmc/input.py +++ /dev/null @@ -1,65 +0,0 @@ -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# A shielding problem based on Problem 2 of [Coper NSE 2001] -# https://ans.tandfonline.com/action/showCitFormats?doi=10.13182/NSE00-34 - -# Set materials -SigmaT = 5.0 -c = 0.8 -m_barrier = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=2.0) -sy3 = mcdc.surface("plane-y", y=4.0, bc="vacuum") - -# Set cells -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2, m_room) -mcdc.cell(+sx1 & -sx4 & +sy2 & -sy3, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy2, m_room) -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_barrier) - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 1e2 -Nx = Ny = 40 -tol = 1e1 -x = np.linspace(0, 4, num=Nx + 1) -y = np.linspace(0, 4, num=Ny + 1) -solver = "gmres" - -# fixed source in lower left corner -fixed_source = np.zeros((Nx, Ny)) -fixed_source[0 : int(0.25 * Nx), 0 : int(0.25 * Nx)] = 1 - -phi0 = np.ones((Nx, Ny)) - -mcdc.iQMC( - x=x, - y=y, - fixed_source=fixed_source, - phi0=phi0, - tol=tol, - fixed_source_solver=solver, - scores=["source-x", "source-y"], -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= -# Setting -mcdc.setting(N_particle=N) -# Run -mcdc.run() diff --git a/examples/fixed_source/cooper2_iqmc/process.py b/examples/fixed_source/cooper2_iqmc/process.py deleted file mode 100644 index fdcce0ed9..000000000 --- a/examples/fixed_source/cooper2_iqmc/process.py +++ /dev/null @@ -1,26 +0,0 @@ -import matplotlib.pyplot as plt -import h5py -import numpy as np - -# Load iqmc result -with h5py.File("output.h5", "r") as f: - meshx = f["iqmc/grid/x"][:] - meshy = f["iqmc/grid/y"][:] - dx = [meshx[1:] - meshx[:-1]][-1] - x_mid = 0.5 * (meshx[:-1] + meshx[1:]) - phi = f["iqmc/tally/flux/mean"][:] - - f.close() - -# ============================================================================= -# Flux Plot -# ============================================================================= -X, Y = np.meshgrid(x_mid, x_mid) -Z = np.log10(np.abs(phi / phi.min())) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="b", color="white", linewidth=0.5) -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.set_zlabel(r"log($\phi$)", rotation=180) - -plt.show() diff --git a/examples/fixed_source/cooper_combo/input.py b/examples/fixed_source/cooper_combo/input.py deleted file mode 100644 index c84c4f4e9..000000000 --- a/examples/fixed_source/cooper_combo/input.py +++ /dev/null @@ -1,68 +0,0 @@ -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# A problem based on a combination of Problems 1 & 2 of [Coper NSE 2001] -# https://ans.tandfonline.com/action/showCitFormats?doi=10.13182/NSE00-34 - -# Set materials -SigmaT = 5.0 -c = 0.8 -m_barrier = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 0.01 -m_duct = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) - - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=1.0) -sy3 = mcdc.surface("plane-y", y=2.6) -sy4 = mcdc.surface("plane-y", y=3) -sy5 = mcdc.surface("plane-y", y=4.0, bc="vacuum") - -# Set cells -# Room -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy5, m_room) -mcdc.cell(+sx1 & -sx4 & +sy4 & -sy5, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy3, m_room) - -# Barrier -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_barrier) - -# Duct Channel -channel_1 = +sx2 & -sx3 & +sy2 & -sy3 -channel_2 = +sx2 & -sx4 & +sy3 & -sy4 -mcdc.cell(channel_1 | channel_2, m_duct) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source(x=[0.0, 1.0], y=[0.0, 1.0], isotropic=True) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 4.0, 41), - y=np.linspace(0.0, 4.0, 41), -) - -# Setting -mcdc.setting(N_particle=1e2) -mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/examples/fixed_source/cooper_combo/process.py b/examples/fixed_source/cooper_combo/process.py deleted file mode 100644 index 8ab5fad07..000000000 --- a/examples/fixed_source/cooper_combo/process.py +++ /dev/null @@ -1,39 +0,0 @@ -import matplotlib.pyplot as plt -import h5py -import numpy as np - - -# Load result -with h5py.File("output.h5", "r") as f: - tally = f["tallies/mesh_tally_0"] - x = tally["grid/x"][:] - dx = [x[1:] - x[:-1]][-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - - phi = tally["flux/mean"][:] - phi_sd = tally["flux/sdev"][:] - - -# Plot result -X, Y = np.meshgrid(x_mid, x_mid) -Z = phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() - -Z = phi_sd / phi -Z = np.log10(np.abs(Z)) -fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) -ax.plot_surface(Y, X, Z, edgecolor="k", color="white") -ax.set_xlabel("x") -ax.set_ylabel("y") -ax.zaxis.set_rotate_label(False) -ax.set_zlabel("Log10 of scalar flux rel. stdev.", rotation=90) -ax.view_init(elev=18, azim=38) -plt.show() diff --git a/examples/fixed_source/inf_pin_ce/input.py b/examples/fixed_source/inf_pin_ce/input.py deleted file mode 100644 index 0e634a6c7..000000000 --- a/examples/fixed_source/inf_pin_ce/input.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= - -# Set materials - -fuel = mcdc.material( - [ - ["U235", 0.0005581658948833916], - ["U238", 0.022404594715383263], - ["O16", 0.045831301393656466], - ["O17", 1.7411492132576054e-05], - ["O18", 9.18996012190109e-05], - ] -) - -water = mcdc.material( - [ - ["B10", 0.0001357003217727274], - ["B11", 0.0005489632593207509], - ["H1", 0.0684556951587359], - ["H2", 1.0662950611949833e-5], - ["O16", 0.032785655643293984], - ["O17", 1.245539986725256e-5], - ["O18", 6.574084932573092e-5], - ] -) - -# Set surfaces -cy = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=0.45720) -pitch = 1.25984 -x1 = mcdc.surface("plane-x", x=-pitch / 2, bc="reflective") -x2 = mcdc.surface("plane-x", x=pitch / 2, bc="reflective") -y1 = mcdc.surface("plane-y", y=-pitch / 2, bc="reflective") -y2 = mcdc.surface("plane-y", y=pitch / 2, bc="reflective") - -# Set cells -mcdc.cell(-cy & +x1 & -x2 & +y1 & -y2, fuel) -mcdc.cell(+cy & +x1 & -x2 & +y1 & -y2, water) - -# ============================================================================= -# Set source -# ============================================================================= - -mcdc.source( - x=[-pitch / 2, pitch / 2], - y=[-pitch / 2, pitch / 2], - energy=np.array([[1e6 - 1, 1e6 + 1], [1.0, 1.0]]), - isotropic=True, -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux", "density"], - E=np.loadtxt("energy_grid.txt"), - t=np.insert(np.logspace(-8, 2, 50), 0, 0.0), -) -mcdc.setting(N_particle=1e2, active_bank_buff=1000) -mcdc.run() diff --git a/examples/fixed_source/kobayashi3-TD/input_template.py b/examples/fixed_source/kobayashi3-TD/input_template.py deleted file mode 100644 index 8c2ddba4e..000000000 --- a/examples/fixed_source/kobayashi3-TD/input_template.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# Based on Kobayashi dog-leg benchmark problem -# (PNE 2001, https://doi.org/10.1016/S0149-1970(01)00007-5) - - -x_sect = X_SECT - -# Set materials -m = mcdc.material( - capture=np.array([0.01 * x_sect]), scatter=np.array([[0.01 * x_sect]]) -) -m_void = mcdc.material( - capture=np.array([5e-5 * x_sect]), scatter=np.array([[5e-5 * x_sect]]) -) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=10.0) -sx3 = mcdc.surface("plane-x", x=30.0) -sx4 = mcdc.surface("plane-x", x=40.0) -sx5 = mcdc.surface("plane-x", x=60.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=10.0) -sy3 = mcdc.surface("plane-y", y=50.0) -sy4 = mcdc.surface("plane-y", y=60.0) -sy5 = mcdc.surface("plane-y", y=100.0, bc="vacuum") -sz1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -sz2 = mcdc.surface("plane-z", z=10.0) -sz3 = mcdc.surface("plane-z", z=30.0) -sz4 = mcdc.surface("plane-z", z=40.0) -sz5 = mcdc.surface("plane-z", z=60.0, bc="vacuum") - -# Set cells -# Soruce -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2, m) -# Voids -mcdc.cell(+sx1 & -sx2 & +sy2 & -sy3 & +sz1 & -sz2, m_void) -mcdc.cell(+sx1 & -sx3 & +sy3 & -sy4 & +sz1 & -sz2, m_void) -mcdc.cell(+sx3 & -sx4 & +sy3 & -sy4 & +sz1 & -sz3, m_void) -mcdc.cell(+sx3 & -sx4 & +sy3 & -sy5 & +sz3 & -sz4, m_void) -# Shield -mcdc.cell(+sx1 & -sx3 & +sy1 & -sy5 & +sz2 & -sz5, m) -mcdc.cell(+sx2 & -sx5 & +sy1 & -sy3 & +sz1 & -sz2, m) -mcdc.cell(+sx3 & -sx5 & +sy1 & -sy3 & +sz2 & -sz5, m) -mcdc.cell(+sx3 & -sx5 & +sy4 & -sy5 & +sz1 & -sz3, m) -mcdc.cell(+sx4 & -sx5 & +sy4 & -sy5 & +sz3 & -sz5, m) -mcdc.cell(+sx4 & -sx5 & +sy3 & -sy4 & +sz1 & -sz5, m) -mcdc.cell(+sx3 & -sx4 & +sy3 & -sy5 & +sz4 & -sz5, m) -mcdc.cell(+sx1 & -sx3 & +sy4 & -sy5 & +sz1 & -sz2, m) - -# ============================================================================= -# Set source -# ============================================================================= -# The source pulses in t=[0,5] - -mcdc.source( - x=[0.0, 10.0], y=[0.0, 10.0], z=[0.0, 10.0], time=[0.0, 50.0], isotropic=True -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: z-integrated flux (X-Y section view) -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 60.0, 61), - y=np.linspace(0.0, 100.0, 101), - z=np.linspace(0.0, 60.0, 61), - t=np.linspace(0.0, 200.0, TIME_SPLITS), -) - -# Setting -mcdc.setting(N_particle=PARTICLE_COUNT) -# mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/examples/fixed_source/kobayashi3-TD/process.py b/examples/fixed_source/kobayashi3-TD/process.py deleted file mode 100644 index 211b2d891..000000000 --- a/examples/fixed_source/kobayashi3-TD/process.py +++ /dev/null @@ -1,36 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.colors import LogNorm -import h5py -import matplotlib.animation as animation - - -# ============================================================================= -# Plot results -# ============================================================================= - -# Results -with h5py.File("output.h5", "r") as f: - cs_recon = f["tallies/cs_tally_0/flux/reconstruction"][:] - plt.imshow(cs_recon) - plt.show() - - tallies = f["tallies/mesh_tally_0"] - flux = tallies["flux"] - grid = tallies["grid"] - x = grid["x"][:] - x_mid = 0.5 * (x[:-1] + x[1:]) - y = grid["y"][:] - y_mid = 0.5 * (y[:-1] + y[1:]) - t = grid["t"][:] - t_mid = 0.5 * (t[:-1] + t[1:]) - X, Y = np.meshgrid(y, x) - - phi = flux["mean"][:] - phi_sd = flux["sdev"][:] - - for i in range(len(f["input_deck"]["cell_tallies"])): - flux_score = f[f"tallies/cell_tally_{i}/flux"] - print( - f'cell {i+1} mean = {flux_score["mean"][()]}, sdev = {flux_score["sdev"][()]}' - ) diff --git a/examples/fixed_source/kobayashi3-TD/scraper.py b/examples/fixed_source/kobayashi3-TD/scraper.py deleted file mode 100755 index ab73302c5..000000000 --- a/examples/fixed_source/kobayashi3-TD/scraper.py +++ /dev/null @@ -1,608 +0,0 @@ -#!/bin/bash -# -# This script is both a bash script and a python script. -# These first two lines are the bash part, which in turn -# launches python to interpret this file. In python, -# freestanding strings are comments, so these two lines are -# technically legal. The "exit" means that the bash shell -# will exit immediately, meaning the bash interpreter will -# never read any of the definitely-not-bash code that follows. -"python" "$0" "$@" -"exit" -# Yes, this is silly, but it's necessary to get shell-based -# batching commands to work on python scripts that could -# by executed with arbitrary python install paths. If we just -# shoved in '#!/bin/python', that would likely not be the python -# installation we want. Instead we delegate the path lookup to -# bash, which already knows where our python installation is. - -import subprocess -import shutil -import sys -import os -import re - -############################################################################### -# Here are the variables you will likely wish to modify the most -############################################################################### - -# Valid values -# - 'always' : Always used cached info no matter what -# - 'first' : Set up cached info with an initial run before -# launching real jobs (reccomended) -# - 'never' : Never used cached info -cache = "first" - -# Valid values: -# - 'python' : Python-mode CPU execution -# (SUPER slow. Probably shouldn't run this with -# any of the other modes for any reasonably -# sized problems.) -# - 'numba' : Numba-mode CPU execution -# (Semi-slow. Okay to run with smaller problems.) -# - 'event' : Event-based GPU execution -# - 'async' : Async GPU execution -strat_list = [ - # "python", - # "numba", - "event", - # "async", -] - - -# List of node counts to run jobs on. -node_count_list = [1] - -# Number of samples to take for each configuration -sample_count = 3 - -# List of particle counts to run jobs for. -# This list uses the smallest particle count first so -# that cache-generating runs go quickly. After this, the -# counts goes in descending order to front-load long running -# jobs and allow short jobs to fill in the gaps. -particle_count_list = [ - 100000, - # 464158880000, - # 166810050000, - # 59948420000, - # 21544340000, - # 7742630000, - # 2782550000, - # 1000000000, - # 359381366, - # 129154966, - 46415888, - 16681005, - 5994842, - 2154434, - 774263, - 278255, -] - - -# The space of parameters that will be iterated through by -# the script. The order of iteration nesting is from the bottom up, -# with later entries acting like inner for loops. -param_space = { - "TIME_SPLITS": [101], # [ 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025 ], - "X_SECT": [1.25, 2.5, 5, 10, 20], - "PARTICLE_COUNT": particle_count_list, -} -# Feel free to add additional parameters, but make sure there are -# corresponding strings in your `input_template.py` file, otherwise -# they won't do anything and you'll have a bunch of additional runs -# that didn't do anything unique (assuming they don't just crash) -# -# NOTE: It is strongly reccomended that you place cache-breaking -# parameters before parameters that don't break the cache. This -# allows for the most parallelism and hence the fastest completion -# of jobs. - -# A list of parameters which should force a cache reset whenever -# they change. ( The node count and strat both automatically -# force cache rests. ) Force-resets are disabled when cache="always". -reset_cache_on = ["TIME_SPLITS"] - - -# Set the email variable to your email if you want to be -# emailed when the program has completed. -email = None # "bcuneo@seattleu.edu" - - -############################################################################### -# Handling command-line input -############################################################################### - - -mode_set = { - "run": None, - "dry_run": None, - "collect": None, -} - -if len(sys.argv) < 3: - print( - "A mode and batch name is required to run this script.\n" - + "Example: 'scraper.py mode_here batch_name_here'" - ) - exit(1) - -mode = sys.argv[1] -batch_name = sys.argv[2] - -if not mode in mode_set: - mode_list = ", ".join([f"'{name}'" for name in mode_set]) - print(f"Mode '{mode}' not recognized.\nValid modes: {mode_list}") - exit(1) - -if (mode != "collect") and len(sys.argv) > 3: - extra_args = ", ".join([f"'{arg}'" for arg in sys.argv[3:]]) - print(f"Unrecognized argument(s): {extra_args}") - exit(1) - - -stat_types = ["avg", "min", "max", "each"] - -stats = {} - -if mode == "collect": - bad = [] - for extra_arg in sys.argv[3:]: - if not extra_arg in stat_types: - bad.append(extra_arg) - else: - stats[extra_arg] = None - - if len(bad) > 0: - bad_args = ", ".join([f"'{arg}'" for arg in bad]) - print(f"Unrecognized argument(s): {bad_args}") - exit(1) - -if len(stats) == 0: - stats["avg"] = None - -############################################################################### -# Function for making sure a directory exists -############################################################################### - - -def ensure_dir(dir_path): - - global mode - - if mode in ["run", "dry_run"]: - print(f"Ensuring directory exists at '{dir_path}'") - - if mode != "run": - return - - if not os.path.exists(dir_path): - os.mkdir(dir_path) - elif not os.path.isdir(dir_path): - print(f"ERROR: Creation of directory at '{dir_path}' blocked by file") - exit(1) - - -############################################################################### -# Convenience function for running commands without arguments containing -# any whitespace -############################################################################### - - -def go_run(cmd_text, cwd=None, always=False, quiet=False): - - global mode - - if mode in ["run", "dry_run"]: - print(cmd_text) - - if (not always) and (mode != "run"): - return - - try: - return subprocess.check_output( - cmd_text.split(), - stderr=subprocess.STDOUT, - cwd=cwd, - ).decode() - except subprocess.CalledProcessError as exc: - print( - "ERROR: Child process exited with non-zero status code ", - exc.returncode, - "\nOUTPUT:\n", - exc.output.decode(), - ) - raise exc - - -############################################################################### -# Figuring out general configuration based on host, user, and -# current working directory -############################################################################### - -machine = "mystery_machine" -base_path = os.getcwd() -base_job_path = base_path -username = go_run("id -u -n", always=True, quiet=True).strip() -hostname = go_run("hostname", always=True, quiet=True).strip() - - -if "tioga" in hostname: - machine = "tioga" - base_job_path = f"/p/lustre1/{username}/{batch_name}" - machine_arena_size_opt = "--gpu_arena_size=100000000" -elif "lassen" in hostname: - machine = "lassen" - base_job_path = f"/p/gpfs1/{username}/{batch_name}" - machine_arena_size_opt = "--gpu_arena_size=20000000" -else: - print( - "Zoinks, Scoob -- Looks like we're on a Mystery Machine!\n" - + "Edit the script if you want it to run on this host!" - ) - exit(1) - - -base_out_path = f"{base_path}/{batch_name}" -ensure_dir(base_out_path) -ensure_dir(base_job_path) - - -############################################################################### -# Function for replacing strings in a file -############################################################################### - - -def specialize_template(template_path, repl_list, output_path): - - template_file = open(template_path) - text = template_file.read() - template_file.close() - - for key, val in repl_list.items(): - key = str(key) - val = str(val) - text = re.sub(key, val, text) - - output_file = open(output_path, "w") - output_file.write(text) - output_file.close() - - -############################################################################### -# Function for iterating through parameter space -############################################################################### - - -def unroll_param_space(param_space): - result = [{}] - - for param in reversed(param_space.keys()): - sub_result = result - result = [] - for value in param_space[param]: - for sub_config in sub_result: - entry = {param: value} - for p, v in sub_config.items(): - entry[p] = v - result.append(entry) - - return result - - -############################################################################### -# Per-job logic -############################################################################### - - -# Fetch the latest Total time in the file called 'out' in the directory at -# the provided path. If no such time exists, return None -def get_result(out_path): - result = None - try: - file = open(f"{out_path}/out") - text = file.read() - file.close() - total_matches = re.findall(r"Total.*\(", text) - total_match = total_matches[-1] - total_text = re.search(r" [0-9]+\.[0-9]+ ", total_match) - total = float(total_text.group(0).strip()) - if "minutes" in total_match: - total *= 60 - result = str(total) - except Exception as e: - pass - return result - - -# Returns the text to put at the start of a command to launch it on the -# job system used by the current machine -def launch_preamble(out_path, immediate=True): - # Figure out the launch command that should receive our python command - if machine == "tioga": - rank_count = node_count * 8 - if immediate: - directive = "submit" - else: - directive = "run" - return f"flux {directive} -N {node_count} -n {rank_count} -g 1 --output={out_path}/out --error={out_path}/err --flags=waitable" - elif machine == "lassen": - rank_count = node_count * 4 - if immediate: - immediate_opt = "-i" - else: - immediate_opt = "" - return f"jsrun {immediate_opt} -n {rank_count} -r 4 -a 1 -g 1 -o {out_path}/out -k {out_path}/err" - else: - print("ERROR: Mystery machine") - return None - - -def handle_job(strat, node_count, sample_index, config): - - global cache_needs_refresh - global last_cache - - # Create a string identifier to signify the combination of - # parameters being used - param_sig = "" - for k, v in config.items(): - param_sig += f"_{k}-{v}" - dir_name = f"run_strat-{strat}_nodes-{node_count}{param_sig}-sample_{sample_index}" - - # Setup directories to execute the job and to store the output - out_path = f"{base_out_path}/{dir_name}" - ensure_dir(out_path) - job_path = f"{base_job_path}/{dir_name}" - ensure_dir(job_path) - - script_path = f"{job_path}/input.py" - cache_path = f"{job_path}/__harmonize_cache__" - - # Check to see if a result was already found during a previous scraper - # batch execution - result = get_result(out_path) - - # If in collection mode, just print the result - if mode == "collect": - if result == None: - return {dir_name: None} - else: - return {dir_name: float(result)} - # If NOT in collection mode, skip run if a result is already present - elif result != None: - return {dir_name: float(result)} - - # Script files don't need to be generated for dry runs - if mode == "run": - # Perform find/replace on `input_template.py`, saving the - # modified text to the path the job should run in - specialize_template("./input_template.py", config, script_path) - - target_opt = "" - arena_size_opt = "" - mode_opt = "" - strat_opt = "" - caching_opt = "" - - # Disable caching if the settings indicate so - if cache != "never": - caching_opt = "--caching" - - # Handle options that should be supplied for each strat - if strat == "python": - target_opt = "--target=cpu" - mode_opt = "--mode=python" - elif strat == "numba": - target_opt = "--target=cpu" - mode_opt = "--mode=numba" - elif strat == "event": - target_opt = "--target=gpu" - strat_opt = "--gpu_strat=event" - mode_opt = "--mode=numba" - elif strat == "async": - target_opt = "--target=gpu" - strat_opt = "--gpu_strat=async" - mode_opt = "--mode=numba" - else: - print(f"Unrecognized strat '{strat}'") - - # The actual python command we care about running - base_cmd = f"python3 {script_path} {mode_opt} {target_opt} {arena_size_opt} {strat_opt} {caching_opt}" - - launch_cmd = launch_preamble(out_path) - - # Print the command for diagnostic purposes, then run it - cmd = f"{launch_cmd} {base_cmd}" - - # If we need to prep the cache, perform a prior foreground run with caching off - if cache_needs_refresh: - - wait_all(quiet=True) - - # Clear out the old cache - if os.path.exists(cache_path): - shutil.rmtree(cache_path) - - # Run the command in the foreground - print("Refreshing cache.") - cache_launch_cmd = launch_preamble(out_path, immediate=False) - cache_cmd = f"{cache_launch_cmd} {base_cmd} --clear_cache" - go_run(cache_cmd, cwd=job_path) - - cache_needs_refresh = False - last_cache = cache_path - - # If we didn't already just produce the cache, either copy it over - # from our previous cache-making run or (in the case of cache="never") - # remove the current cache without replacing it. - if (mode == "run") and (cache_path != last_cache): - # Copy over the __harmonize_cache__, if applicable - if os.path.exists(cache_path): - shutil.rmtree(cache_path) - if os.path.exists(last_cache) and (cache != "never"): - shutil.copytree(last_cache, cache_path) - - # Run the actual command - go_run(cmd, cwd=job_path) - - return {} - - -############################################################################### -# Waiting logic -############################################################################### -def wait_all(quiet=False): - wait_success = False - if machine == "tioga": - try: - result = go_run("flux job wait --all") - if result != None: - print(result) - wait_success = True - except subprocess.CalledProcessError as exc: - pass - elif machine == "lassen": - try: - result = go_run("jswait all") - if result != None: - print(result) - wait_success = True - except subprocess.CalledProcessError as exc: - pass - - if not quiet: - try: - if wait_success and (email != None): - subject = f"{batch_name} finished" - message = f"All jobs finished for scraper batch {batch_name}" - subprocess.check_output( - ["mail", "-s", subject, email], - stderr=subprocess.STDOUT, - input=str.encode(message), - ).decode() - except subprocess.CalledProcessError as exc: - pass - - -############################################################################### -# Logic for printing stats -############################################################################### -def print_stats(result_set): - global sample_count - - minim = None - maxim = None - avg = None - - if "each" in stats: - for key, val in result_set.items(): - print(f"{key}, {val}") - - some_key = None - - for key, val in result_set.items(): - - some_key = key - - if val == None: - minim = None - maxim = None - avg = None - break - - if minim == None: - minim = val - else: - minim = min(minim, val) - - if maxim == None: - maxim = val - else: - maxim = max(maxim, val) - - if avg == None: - avg = val - else: - avg += val - - if avg != None: - avg /= sample_count - - key_comps = some_key.split("_") - signature = "_".join(key_comps[:-1]) - - if "min" in stats: - print(f"{signature}_min, {minim}") - - if "max" in stats: - print(f"{signature}_max, {maxim}") - - if "avg" in stats: - print(f"{signature}_avg, {avg}") - - -############################################################################### -# Logic for re-caching as variables change -############################################################################### -last_config = None -last_cache = None - - -def param_broke_cache(last_config, config): - if last_config == None: - return True - - for param in reset_cache_on: - if last_config[param] != config[param]: - return True - - return False - - -############################################################################### -# Diagnostic info -############################################################################### - -print( - f""" -SCRAPER - -running on : '{machine}' -username : '{username}' -working dir : '{base_path}' -job dir : '{base_job_path}' -""" -) - - -############################################################################### -# Job launching loops -############################################################################### - - -for strat in strat_list: - - for node_count in node_count_list: - - cache_needs_refresh = True - - for config in unroll_param_space(param_space): - - if param_broke_cache(last_config, config): - cache_needs_refresh = True - - result_set = {} - for sample_index in range(sample_count): - result = handle_job(strat, node_count, sample_index, config) - last_config = config - - for key, val in result.items(): - result_set[key] = val - - if mode == "collect": - print_stats(result_set) - -if mode == "run": - wait_all() diff --git a/examples/fixed_source/pulsed_sphere/input.py b/examples/fixed_source/pulsed_sphere/input.py deleted file mode 100644 index 80a46794b..000000000 --- a/examples/fixed_source/pulsed_sphere/input.py +++ /dev/null @@ -1,70 +0,0 @@ -import h5py -import numpy as np - -import mcdc - -# ============================================================================= -# Materials -# ============================================================================= - -mat_iron = mcdc.material( - [ - ["Fe54", 4.82003e21 * 1e-24], - ["Fe56", 7.6223e22 * 1e-24], - ["Fe57", 1.82829e21 * 1e-24], - ["Fe58", 2.32691e20 * 1e-24], - ["C12", 1.02809e21 * 1e-24], - ["Mn55", 8.56743e20 * 1e-24], - ["P31", 5.9972e20 * 1e-24], - ["S32", 8.56743e19 * 1e-24], - ] -) -mat_air = mcdc.material( - [ - ["N14", 4.36848e19 * 1e-24], - ["O16", 1.02529e19 * 1e-24], - ] -) - -# ============================================================================= -# Materials -# ============================================================================= - -# Surfaces -s0 = mcdc.surface("sphere", center=[0.0, 0.0, 0.0], radius=4.46) -sout = mcdc.surface("sphere", center=[0.0, 0.0, 0.0], radius=1000, bc="vacuum") - -# Cells -cr1 = mcdc.cell(-s0, mat_iron) -void1 = mcdc.cell(+s0 & -sout, mat_air) - - -# ============================================================================= -# Source -# ============================================================================= - -mcdc.source( - point=[0.0, 0.0, 0.0], - energy=np.array([[14e6 - 1, 14e6 + 1], [1.0, 1.0]]), - isotropic=True, -) - -# ============================================================================= -# Tallies -# ============================================================================= -PStally = mcdc.tally.mesh_tally( - scores=["flux"], - x=[740.0, 760.0], - y=[-10.0, 10.0], - z=[-10.0, 10.0], - t=np.linspace(0.0, 500.0e-9, 250), -) - -# ============================================================================= -# Settings -# ============================================================================= - -mcdc.setting(N_particle=1e4) -mcdc.implicit_capture() - -mcdc.run() diff --git a/examples/fixed_source/pulsed_sphere/process.py b/examples/fixed_source/pulsed_sphere/process.py deleted file mode 100644 index fad25f418..000000000 --- a/examples/fixed_source/pulsed_sphere/process.py +++ /dev/null @@ -1,21 +0,0 @@ -import matplotlib.pyplot as plt -import h5py - -# Get results -with h5py.File("output.h5", "r") as f: - t = f["tallies/mesh_tally_0/grid/t"][:] - dt = t[1:] - t[:-1] - t_mid = 0.5 * (t[1:] + t[:-1]) - K = len(t) - 1 - - phi = f["tallies/mesh_tally_0/flux/mean"][:] - phi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] - - # Normalize - for k in range(K): - phi[k] /= dt[k] - phi_sd[k] /= dt[k] - -plt.plot(t_mid, phi) -plt.yscale("log") -plt.show() diff --git a/examples/fixed_source/slab_absorbium/input.py b/examples/fixed_source/slab_absorbium/input.py deleted file mode 100644 index 846a6ab3f..000000000 --- a/examples/fixed_source/slab_absorbium/input.py +++ /dev/null @@ -1,48 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different purely-absorbing materials - -# Set materials -m1 = mcdc.material(capture=np.array([1.0])) -m2 = mcdc.material(capture=np.array([1.5])) -m3 = mcdc.material(capture=np.array([2.0])) - -# Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="vacuum") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=4.0) -s4 = mcdc.surface("plane-z", z=6.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m2) -mcdc.cell(+s2 & -s3, m3) -mcdc.cell(+s3 & -s4, m1) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source(z=[0.0, 6.0], isotropic=True) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: cell-average fluxes and currents -mcdc.tally.mesh_tally( - scores=["flux"], - z=np.linspace(0.0, 6.0, 61), - mu=np.linspace(-1.0, 1.0, 32 + 1), -) - -# Setting -mcdc.setting(N_particle=1e3) - -# Run -mcdc.run() diff --git a/examples/fixed_source/slab_absorbium/process.py b/examples/fixed_source/slab_absorbium/process.py deleted file mode 100644 index 5430282ca..000000000 --- a/examples/fixed_source/slab_absorbium/process.py +++ /dev/null @@ -1,73 +0,0 @@ -import matplotlib.pyplot as plt -import h5py -import numpy as np - -from reference import reference - - -# Load results -with h5py.File("output.h5", "r") as f: - z = f["tallies/mesh_tally_0/grid/z"][:] - dz = z[1:] - z[:-1] - z_mid = 0.5 * (z[:-1] + z[1:]) - - mu = f["tallies/mesh_tally_0/grid/mu"][:] - dmu = mu[1:] - mu[:-1] - mu_mid = 0.5 * (mu[:-1] + mu[1:]) - - psi = f["tallies/mesh_tally_0/flux/mean"][:] - psi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] - psi = np.transpose(psi) - psi_sd = np.transpose(psi_sd) - -I = len(z) - 1 -N = len(mu) - 1 - -# Scalar flux -phi = np.zeros(I) -phi_sd = np.zeros(I) -for i in range(I): - phi[i] += np.sum(psi[i, :]) - phi_sd[i] += np.linalg.norm(psi_sd[i, :]) - -# Normalize -phi /= dz -phi_sd /= dz -for n in range(N): - psi[:, n] = psi[:, n] / dz / dmu[n] - psi_sd[:, n] = psi_sd[:, n] / dz / dmu[n] - -# Reference solution -phi_ref, _, psi_ref = reference(z, mu) - -# Flux - spatial average -plt.plot(z_mid, phi, "-b", label="MC") -plt.fill_between(z_mid, phi - phi_sd, phi + phi_sd, alpha=0.2, color="b") -plt.plot(z_mid, phi_ref, "--r", label="Ref.") -plt.xlabel(r"$z$, cm") -plt.ylabel("Flux") -plt.ylim([0.06, 0.16]) -plt.grid() -plt.legend() -plt.title(r"$\bar{\phi}_i$") -plt.show() - -# Angular flux - spatial average -vmin = min(np.min(psi_ref), np.min(psi)) -vmax = max(np.max(psi_ref), np.max(psi)) -fig, ax = plt.subplots(1, 2, sharey=True) -Z, MU = np.meshgrid(z_mid, mu_mid) -im = ax[0].pcolormesh(MU.T, Z.T, psi_ref, vmin=vmin, vmax=vmax) -ax[0].set_xlabel(r"Polar cosine, $\mu$") -ax[0].set_ylabel(r"$z$") -ax[0].set_title(r"\psi") -ax[0].set_title(r"$\bar{\psi}_i(\mu)$ [Ref.]") -ax[1].pcolormesh(MU.T, Z.T, psi, vmin=vmin, vmax=vmax) -ax[1].set_xlabel(r"Polar cosine, $\mu$") -ax[1].set_ylabel(r"$z$") -ax[1].set_title(r"$\bar{\psi}_i(\mu)$ [MC]") -fig.subplots_adjust(right=0.8) -cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7]) -cbar = fig.colorbar(im, cax=cbar_ax) -cbar.set_label("Angular flux") -plt.show() diff --git a/examples/fixed_source/slab_absorbium/reference.py b/examples/fixed_source/slab_absorbium/reference.py deleted file mode 100644 index 64759c5e2..000000000 --- a/examples/fixed_source/slab_absorbium/reference.py +++ /dev/null @@ -1,130 +0,0 @@ -import numpy as np -from scipy.integrate import quad - - -def reference(x, mu): - dx = x[1:] - x[:-1] - dmu = mu[1:] - mu[:-1] - I = len(x) - 1 - N = len(mu) - 1 - - # Parameters - SigmaT3 = 1.0 - SigmaT1 = 1.5 - SigmaT2 = 2.0 - q1 = 1.0 / 6.0 / 2 - q2 = 1.0 / 6.0 / 2 - q3 = 1.0 / 6.0 / 2 - x1 = 2.0 - x2 = 4.0 - x3 = 6.0 - tau1 = SigmaT1 * x1 - tau2 = SigmaT2 * (x2 - x1) - tau3 = SigmaT3 * (x3 - x2) - - # Angular flux - def psi1(mu, x): - if mu > 0.0: - return q1 / SigmaT1 * (1.0 - np.exp(-SigmaT1 * x / mu)) - elif mu < 0.0: - return (psi2(mu, x1) - q1 / SigmaT1) * np.exp( - -SigmaT1 * (x1 - x) / np.abs(mu) - ) + q1 / SigmaT1 - - def psi2(mu, x): - if mu > 0.0: - return (psi1(mu, x1) - q2 / SigmaT2) * np.exp( - -SigmaT2 * (x - x1) / mu - ) + q2 / SigmaT2 - elif mu < 0.0: - return (psi3(mu, x2) - q2 / SigmaT2) * np.exp( - -SigmaT2 * (x2 - x) / np.abs(mu) - ) + q2 / SigmaT2 - - def psi3(mu, x): - if mu > 0.0: - return (psi2(mu, x2) - q3 / SigmaT3) * np.exp( - -SigmaT3 * (x - x2) / mu - ) + q3 / SigmaT3 - elif mu < 0.0: - return q3 / SigmaT3 * (1.0 - np.exp(-SigmaT3 * (x3 - x) / np.abs(mu))) - - # Flux - def phi1(x): - return quad(psi1, -1, 1, args=(x), points=[0.0])[0] - - def phi2(x): - return quad(psi2, -1, 1, args=(x), points=[0.0])[0] - - def phi3(x): - return quad(psi3, -1, 1, args=(x), points=[0.0])[0] - - # Integrands for current - def mu_psi1(mu, x): - if mu > 0.0: - return mu * psi1(mu, x) - elif mu < 0.0: - return mu * psi1(mu, x) - - def mu_psi2(mu, x): - if mu > 0.0: - return mu * psi2(mu, x) - elif mu < 0.0: - return mu * psi2(mu, x) - - def mu_psi3(mu, x): - if mu > 0.0: - return mu * psi3(mu, x) - elif mu < 0.0: - return mu * psi3(mu, x) - - # Current - def J1(x): - return quad(mu_psi1, -1, 1, args=(x), points=[0.0])[0] - - def J2(x): - return quad(mu_psi2, -1, 1, args=(x), points=[0.0])[0] - - def J3(x): - return quad(mu_psi3, -1, 1, args=(x), points=[0.0])[0] - - # Angular flux - def psi1_(x, mu0, mu1): - return quad(psi1, mu0, mu1, args=(x), points=[0.0])[0] - - def psi2_(x, mu0, mu1): - return quad(psi2, mu0, mu1, args=(x), points=[0.0])[0] - - def psi3_(x, mu0, mu1): - return quad(psi3, mu0, mu1, args=(x), points=[0.0])[0] - - phi = np.zeros(I) - psi = np.zeros((I, N)) - J = np.zeros(I) - - for i in range(int(I / 3)): - phi[i] = quad(phi1, x[i], x[i + 1])[0] / dx[i] - J[i] = quad(J1, x[i], x[i + 1])[0] / dx[i] - for n in range(N): - mu0 = mu[n] - mu1 = mu[n + 1] - psi[i, n] = quad(psi1_, x[i], x[i + 1], args=(mu0, mu1))[0] / dx[i] / dmu[n] - for i in range(int(I / 3), int(2 * I / 3)): - phi[i] = quad(phi2, x[i], x[i + 1])[0] / dx[i] - J[i] = quad(J2, x[i], x[i + 1])[0] / dx[i] - for n in range(N): - mu0 = mu[n] - mu1 = mu[n + 1] - psi[i, n] = quad(psi2_, x[i], x[i + 1], args=(mu0, mu1))[0] / dx[i] / dmu[n] - for i in range(int(2 * I / 3), I): - phi[i] = quad(phi3, x[i], x[i + 1])[0] / dx[i] - J[i] = quad(J3, x[i], x[i + 1])[0] / dx[i] - for n in range(N): - mu0 = mu[n] - mu1 = mu[n + 1] - psi[i, n] = quad(psi3_, x[i], x[i + 1], args=(mu0, mu1))[0] / dx[i] / dmu[n] - for n in range(N): - mu0 = mu[n] - mu1 = mu[n + 1] - - return phi, J, psi diff --git a/examples/fixed_source/slab_ce/input.py b/examples/fixed_source/slab_ce/input.py deleted file mode 100644 index 023c0f122..000000000 --- a/examples/fixed_source/slab_ce/input.py +++ /dev/null @@ -1,84 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= - -rho_uo2 = 10.97 -rho_h2o = 0.997 -rho_b4c = 2.52 - -a_u235 = 0.05 -a_u238 = 1.0 - a_u235 - -A_uo2 = 270.03 -A_h2o = 18.01528 -A_b4c = 55.255 - -N_avo = 6.023e23 - -N_uo2 = rho_uo2 * N_avo / A_uo2 * 1e-24 -N_h2o = rho_h2o * N_avo / A_h2o * 1e-24 -N_b4c = rho_b4c * N_avo / A_b4c * 1e-24 - -N_u235 = a_u235 * N_uo2 -N_u238 = a_u238 * N_uo2 -N_o16_uo2 = 2.0 * N_uo2 - -N_h1 = 2.0 * N_h2o -N_o16_h2o = N_h2o - -N_b10 = 4.0 * N_b4c -N_c12 = N_b4c - -# Set materials -uo2 = mcdc.material( - [ - ["U235", N_u235], - ["U238", N_u238], - ["O16", N_o16_uo2], - ] -) -h2o = mcdc.material( - [ - ["H1", N_h1], - ["O16", N_o16_h2o], - ] -) -b4c = mcdc.material( - [ - ["B10", N_b10], - ["C12", N_c12], - ] -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -s2 = mcdc.surface("plane-x", x=0.5) -s3 = mcdc.surface("plane-x", x=1.5) -s4 = mcdc.surface("plane-x", x=2.0, bc="reflective") - -# Set cells -mcdc.cell(+s1 & -s2, uo2) -mcdc.cell(+s2 & -s3, h2o) -mcdc.cell(+s3 & -s4, b4c) - -# ============================================================================= -# Set source -# ============================================================================= - -mcdc.source( - x=[0.95, 1.05], energy=np.array([[14e6 - 1, 14e6 + 1], [1.0, 1.0]]), isotropic=True -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], x=np.linspace(0.0, 2.0, 21), E=np.array([0.0, 1.0, 20e6]) -) -mcdc.setting(N_particle=1e3) -mcdc.run() diff --git a/examples/fixed_source/slab_ce/process.py b/examples/fixed_source/slab_ce/process.py deleted file mode 100644 index 5fc54fcb9..000000000 --- a/examples/fixed_source/slab_ce/process.py +++ /dev/null @@ -1,47 +0,0 @@ -import matplotlib.pyplot as plt -import h5py, sys -import numpy as np - - -# Load results -with h5py.File("output.h5", "r") as f: - # Grid - x = f["tallies/mesh_tally_0/grid/x"][:] - dx = x[1:] - x[:-1] - x_mid = 0.5 * (x[:-1] + x[1:]) - # Fluks - phi_fast = f["tallies/mesh_tally_0/flux/mean"][1, :] / dx - phi_fast_sd = f["tallies/mesh_tally_0/flux/sdev"][1, :] / dx - phi_thermal = f["tallies/mesh_tally_0/flux/mean"][0, :] / dx - phi_thermal_sd = f["tallies/mesh_tally_0/flux/sdev"][0, :] / dx - -# Plot results -fig, ax1 = plt.subplots(figsize=(5, 3)) -ax2 = ax1.twinx() - -y = phi_fast -y_sd = phi_fast_sd -p1 = ax1.step(x_mid, y, "-b", where="mid", label="Fast flux") -ax1.fill_between(x_mid, y - y_sd, y + y_sd, alpha=0.2, color="b", step="mid") - -y = phi_thermal -y_sd = phi_thermal_sd -p2 = ax2.step(x_mid, y, "--r", where="mid", label="Thermal flux") -ax2.fill_between(x_mid, y - y_sd, y + y_sd, alpha=0.2, color="r", step="mid") - -ax1.set_xlabel(r"$x$ [cm]") -ax1.set_ylabel("Fast flux [/cm-s]", color="b") -ax1.tick_params(axis="y", colors="b") -ax2.set_ylabel("Thermal flux [/cm-s]", color="r") -ax2.tick_params(axis="y", colors="r") - -""" -lim1 = ax1.get_ylim() -lim2 = ax2.get_ylim() -max_range = max(lim1[1]-lim1[0], lim2[1]-lim2[0]) -ax1.set_ylim(top=lim1[0]+max_range) -ax2.set_ylim(top=lim2[0]+max_range) -""" - -ax1.legend(handles=p1 + p2, loc="lower left") -plt.show() diff --git a/examples/fixed_source/slab_reed_dd/input.py b/examples/fixed_source/slab_reed_dd/input.py deleted file mode 100644 index bf4826ac7..000000000 --- a/examples/fixed_source/slab_reed_dd/input.py +++ /dev/null @@ -1,51 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different materials -# Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 - -# Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=3.0) -s4 = mcdc.surface("plane-z", z=5.0) -s5 = mcdc.surface("plane-z", z=8.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) -mcdc.cell(+s3 & -s4, m3) -mcdc.cell(+s4 & -s5, m4) - -# ============================================================================= -# Set source -# ============================================================================= - -# Isotropic source in the absorbing medium -mcdc.source(z=[0.0, 2.0], isotropic=True, prob=50.0) - -# Isotropic source in the first half of the outermost medium, -# with 1/100 strength -mcdc.source(z=[5.0, 6.0], isotropic=True, prob=0.5) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally(scores=["flux"], z=np.linspace(0.0, 8.0, 81)) - -# Setting -mcdc.setting(N_particle=5000) -mcdc.domain_decomposition(z=np.linspace(0.0, 8.0, 5)) -# Run -mcdc.run() diff --git a/examples/fixed_source/slab_reed_dd/process.py b/examples/fixed_source/slab_reed_dd/process.py deleted file mode 100644 index 81639ed4f..000000000 --- a/examples/fixed_source/slab_reed_dd/process.py +++ /dev/null @@ -1,122 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py -from scipy.integrate import quad - -# ============================================================================= -# Reference solution (not accurate enough for N_hist > 1E7) -# ============================================================================= - - -def phi1(x): - return ( - 1.0 - - 5.96168047527760 * 10 ** (-47) * np.cosh(52.06761235859028 * x) - - 6.78355315350872 * 10 ** (-56) * np.cosh(62.76152118553390 * x) - - 7.20274049646598 * 10 ** (-84) * np.cosh(95.14161078659372 * x) - - 6.34541150517664 * 10 ** (-238) * np.cosh(272.5766481169758 * x) - ) - - -def phi2(x): - return ( - 1.685808767651539 * 10**3 * np.exp(-5.206761235859028 * x) - + 3.143867366942945 * 10**4 * np.exp(-6.276152118553390 * x) - + 2.879977113018352 * 10**7 * np.exp(-9.514161078659372 * x) - + 8.594190506002560 * 10**22 * np.exp(-27.25766481169758 * x) - + 1.298426035202193 * 10 ** (-36) * np.exp(27.25766481169758 * x) - + 1.432344656303454 * 10 ** (-13) * np.exp(9.514161078659372 * x) - + 1.514562265056083 * 10 ** (-9) * np.exp(6.276152118553390 * x) - + 1.594431209450755 * 10 ** (-8) * np.exp(5.206761235859028 * x) - ) - - -def phi3(x): - return 1.105109108062394 - - -def phi4(x): - return ( - 10.0 - - 0.1983746883968300 * np.exp(0.5254295183311557 * x) - - 7.824765332896027 * 10 ** (-5) * np.exp(1.108937229227813 * x) - - 9.746660212187006 * 10 ** (-6) * np.exp(1.615640334315550 * x) - - 2.895098351422132 * 10 ** (-13) * np.exp(4.554850586269065 * x) - - 75.34793864805979 * np.exp(-0.5254295183311557 * x) - - 20.42874998426011 * np.exp(-1.108937229227813 * x) - - 7.129175418204712 * 10 ** (2) * np.exp(-1.615640334315550 * x) - - 2.716409367577795 * 10 ** (9) * np.exp(-4.554850586269065 * x) - ) - - -def phi5(x): - return ( - 31.53212162577067 * np.exp(-0.5254295183311557 * x) - + 26.25911060454856 * np.exp(-1.108937229227813 * x) - + 1.841223066417334 * 10 ** (3) * np.exp(-1.615640334315550 * x) - + 1.555593549394869 * 10 ** (11) * np.exp(-4.554850586269065 * x) - - 3.119310353653182 * 10 ** (-3) * np.exp(0.5254295183311557 * x) - - 6.336401143340483 * 10 ** (-7) * np.exp(1.108937229227813 * x) - - 3.528757679361232 * 10 ** (-8) * np.exp(1.615640334315550 * x) - - 4.405514335746888 * 10 ** (-18) * np.exp(4.554850586269065 * x) - ) - - -def f_phi(x1, x2): - dx = x2 - x1 - if x2 <= 2.0: - return quad(phi1, x1, x2)[0] / dx - if x2 <= 3.0: - return quad(phi2, x1, x2)[0] / dx - if x2 <= 5.0: - return quad(phi3, x1, x2)[0] / dx - if x2 <= 6.0: - return quad(phi4, x1, x2)[0] / dx - return quad(phi5, x1, x2)[0] / dx - - -def f_phi_x(x): - if x <= 2.0: - return phi1(x) - if x <= 3.0: - return phi2(x) - if x <= 5.0: - return phi3(x) - if x <= 6.0: - return phi4(x) - return phi5(x) - - -x = np.linspace(0.0, 8.0, 81) -dx = x[1] - x[0] -x_mid = 0.5 * (x[:-1] + x[1:]) - -phi_ref = np.zeros_like(x_mid) -phi_x_ref = np.zeros_like(x) - -for i in range(len(x)): - phi_x_ref[i] = f_phi_x(x[i]) - -for i in range(len(x_mid)): - phi_ref[i] = f_phi(x[i], x[i + 1]) - -# ============================================================================= -# Plot -# ============================================================================= - -# Load output -with h5py.File("output.h5", "r") as f: - # Note the spatial (dx) and source strength (100+1) normalization - phi = f["tallies/mesh_tally_0/flux/mean"][:] / dx * 101.0 - phi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] / dx * 101.0 - -# Flux - spatial average -plt.plot(x_mid, phi, "-b", label="MC") -plt.fill_between(x_mid, phi - phi_sd, phi + phi_sd, alpha=0.2, color="b") -plt.plot(x_mid, phi_ref, "--r", label="ref.") -plt.xlabel(r"$x$, cm") -plt.ylabel("Flux") -plt.grid() -plt.legend() -plt.title(r"$\bar{\phi}_i$") -plt.show() diff --git a/examples/fixed_source/slab_reed_iqmc/input.py b/examples/fixed_source/slab_reed_iqmc/input.py deleted file mode 100644 index 5863fd4a1..000000000 --- a/examples/fixed_source/slab_reed_iqmc/input.py +++ /dev/null @@ -1,98 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different materials -# Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 - -# Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=-8.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=-5.0) -s3 = mcdc.surface("plane-x", x=-3.0) -s4 = mcdc.surface("plane-x", x=-2.0) -s5 = mcdc.surface("plane-x", x=2.0) -s6 = mcdc.surface("plane-x", x=3.0) -s7 = mcdc.surface("plane-x", x=5.0) -s8 = mcdc.surface("plane-x", x=8.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m4) -mcdc.cell(+s2 & -s3, m3) -mcdc.cell(+s3 & -s4, m2) -mcdc.cell(+s4 & -s5, m1) -mcdc.cell(+s5 & -s6, m2) -mcdc.cell(+s6 & -s7, m3) -mcdc.cell(+s7 & -s8, m4) - - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 1000 -Nx = 64 -maxit = 20 -tol = 1e-1 -x = np.linspace(-8, 8, num=Nx + 1) -solver = "gmres" - - -def reeds_source(Nx, LB=-8.0, RB=8.0): - source = np.empty(Nx) - dx = (RB - LB) / Nx - xspan = np.linspace(LB + dx / 2, RB - dx / 2, num=Nx) - count = 0 - for x in xspan: - if x < -6: - source[count] = 0.0 - elif (-6.0 < x) and (x < -5.0): - source[count] = 1.0 - elif -5.0 < x < -3.0: # vacuum region 1 - source[count] = 0.0 - elif -3.0 < x < -2.0: - source[count] = 0.0 - elif -2.0 < x < 2.0: - source[count] = 50.0 - elif 2.0 < x < 3.0: - source[count] = 0.0 - elif 3.0 < x < 5.0: # vacuum region 2 - source[count] = 0.0 - elif 5.0 < x < 6.0: - source[count] = 1.0 - elif 6.0 < x: - source[count] = 0.0 - count += 1 - - return source - - -fixed_source = reeds_source(Nx) -phi0 = np.ones((Nx)) - -mcdc.iQMC( - x=x, - fixed_source=fixed_source, - phi0=phi0, - maxit=maxit, - tol=tol, - fixed_source_solver=solver, - scores=["source-x"], -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Setting -mcdc.setting(N_particle=N) - -# Run -mcdc.run() diff --git a/examples/fixed_source/slab_reed_iqmc/process.py b/examples/fixed_source/slab_reed_iqmc/process.py deleted file mode 100644 index 1db225a34..000000000 --- a/examples/fixed_source/slab_reed_iqmc/process.py +++ /dev/null @@ -1,134 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import h5py -from scipy.integrate import quad - -# ============================================================================= -# Import data -# ============================================================================= - -with h5py.File("output.h5", "r") as f: - phi = f["iqmc/tally/flux/mean"][:] - x = f["iqmc/grid/x"][:] - mesh = f["iqmc/grid/x"][:] - dx = x[1] - x[0] - x_mid = 0.5 * (x[:-1] + x[1:]) - f.close() - -# ============================================================================= -# Reference solution (not accurate enough for N_hist > 1E7) -# ============================================================================= - - -def reeds_sol(Nx=80, LB=-8.0, RB=8.0): - # ========================================================================= - # Reference solution - # ========================================================================= - def phi1(x): - return ( - 1.0 - - 5.96168047527760 * 10 ** (-47) * np.cosh(52.06761235859028 * x) - - 6.78355315350872 * 10 ** (-56) * np.cosh(62.76152118553390 * x) - - 7.20274049646598 * 10 ** (-84) * np.cosh(95.14161078659372 * x) - - 6.34541150517664 * 10 ** (-238) * np.cosh(272.5766481169758 * x) - ) - - def phi2(x): - return ( - 1.685808767651539 * 10**3 * np.exp(-5.206761235859028 * x) - + 3.143867366942945 * 10**4 * np.exp(-6.276152118553390 * x) - + 2.879977113018352 * 10**7 * np.exp(-9.514161078659372 * x) - + 8.594190506002560 * 10**22 * np.exp(-27.25766481169758 * x) - + 1.298426035202193 * 10 ** (-36) * np.exp(27.25766481169758 * x) - + 1.432344656303454 * 10 ** (-13) * np.exp(9.514161078659372 * x) - + 1.514562265056083 * 10 ** (-9) * np.exp(6.276152118553390 * x) - + 1.594431209450755 * 10 ** (-8) * np.exp(5.206761235859028 * x) - ) - - def phi3(x): - return 1.105109108062394 - - def phi4(x): - return ( - 10.0 - - 0.1983746883968300 * np.exp(0.5254295183311557 * x) - - 7.824765332896027 * 10 ** (-5) * np.exp(1.108937229227813 * x) - - 9.746660212187006 * 10 ** (-6) * np.exp(1.615640334315550 * x) - - 2.895098351422132 * 10 ** (-13) * np.exp(4.554850586269065 * x) - - 75.34793864805979 * np.exp(-0.5254295183311557 * x) - - 20.42874998426011 * np.exp(-1.108937229227813 * x) - - 7.129175418204712 * 10 ** (2) * np.exp(-1.615640334315550 * x) - - 2.716409367577795 * 10 ** (9) * np.exp(-4.554850586269065 * x) - ) - - def phi5(x): - return ( - 31.53212162577067 * np.exp(-0.5254295183311557 * x) - + 26.25911060454856 * np.exp(-1.108937229227813 * x) - + 1.841223066417334 * 10 ** (3) * np.exp(-1.615640334315550 * x) - + 1.555593549394869 * 10 ** (11) * np.exp(-4.554850586269065 * x) - - 3.119310353653182 * 10 ** (-3) * np.exp(0.5254295183311557 * x) - - 6.336401143340483 * 10 ** (-7) * np.exp(1.108937229227813 * x) - - 3.528757679361232 * 10 ** (-8) * np.exp(1.615640334315550 * x) - - 4.405514335746888 * 10 ** (-18) * np.exp(4.554850586269065 * x) - ) - - def f_phi(x1, x2): - midpoint = (x2 + x1) * 0.5 - x1 = abs(x1) - x2 = abs(x2) - dx = abs(x2 - x1) - if x1 > x2: - a = x2 - b = x1 - else: - a = x1 - b = x2 - if midpoint < -6.0: - return quad(phi5, a, b)[0] / dx - elif -6.0 < midpoint < -5.0: - return quad(phi4, a, b)[0] / dx - elif -5.0 < midpoint < -3.0: # vacuum region 1 - return quad(phi3, a, b)[0] / dx - elif -3.0 < midpoint < -2.0: - return quad(phi2, a, b)[0] / dx - elif -2.0 < midpoint < 0.0: - return quad(phi1, a, b)[0] / dx - elif 0.0 < midpoint < 2.0: - return quad(phi1, a, b)[0] / dx - elif 2.0 < midpoint < 3.0: - return quad(phi2, a, b)[0] / dx - elif 3.0 < midpoint < 5.0: # vacuum region 2 - return quad(phi3, a, b)[0] / dx - elif 5.0 < midpoint < 6.0: - return quad(phi4, a, b)[0] / dx - elif 6.0 < midpoint: - return quad(phi5, a, b)[0] / dx - - phi_ref = np.zeros(Nx) - dx = (RB - LB) / Nx - left_edges = np.linspace(LB, RB - dx, num=Nx) - right_edges = left_edges + dx - - for i in range(Nx): - phi_ref[i] = f_phi(left_edges[i], right_edges[i]) - phi_ref = np.reshape(phi_ref, (Nx, 1)) - - return phi_ref - - -phi_ref = reeds_sol(Nx=x_mid.size, LB=-8.0, RB=8.0) - - -# ============================================================================= -# Plot -# ============================================================================= - -# Flux - spatial average -plt.plot(x_mid, phi_ref, label="Sol") -plt.plot(x_mid, phi, label="iQMC") -plt.ylabel(r"$\phi(x)$") -plt.xlabel(r"$x$") -plt.grid() -plt.legend() -plt.show() diff --git a/examples/fixed_source/sphere_in_cube/input.py b/examples/fixed_source/sphere_in_cube/input.py deleted file mode 100644 index 3a8585823..000000000 --- a/examples/fixed_source/sphere_in_cube/input.py +++ /dev/null @@ -1,64 +0,0 @@ -import numpy as np -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Homogeneous pure-fission sphere inside a pure-scattering cube - -# Set materials -pure_f = mcdc.material(fission=np.array([1.0]), nu_p=np.array([1.1])) -pure_s = mcdc.material(scatter=np.array([[1.0]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -sx2 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="vacuum") -sy2 = mcdc.surface("plane-y", y=4.0, bc="vacuum") -sz1 = mcdc.surface("plane-z", z=0.0, bc="vacuum") -sz2 = mcdc.surface("plane-z", z=4.0, bc="vacuum") -sphere = mcdc.surface("sphere", center=[2.0, 2.0, 2.0], radius=1.5) -inside_sphere = -sphere -inside_box = +sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2 - -# Set cells -# Source -mcdc.cell(inside_box & ~inside_sphere, pure_s) - -# Sphere -sphere_cell = mcdc.cell(inside_sphere, pure_f) - -# ============================================================================= -# Set source -# ============================================================================= -# The source pulses in t=[0,5] - -mcdc.source(x=[0.0, 4.0], y=[0.0, 4.0], z=[0.0, 4.0], time=[0.0, 50.0], isotropic=True) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= -mcdc.tally.mesh_tally( - scores=["fission"], - x=np.linspace(0.0, 4.0, 41), - y=np.linspace(0.0, 4.0, 41), - # z=np.linspace(0.0, 4.0, 41), - # t=np.linspace(0.0, 200.0, 2), -) - -mcdc.tally.cell_tally(sphere_cell, scores=["fission"]) - -mcdc.tally.cs_tally( - N_cs_bins=[150], - cs_bin_size=np.array([3.0, 3.0]), - x=np.linspace(0.0, 4.0, 41), - y=np.linspace(0.0, 4.0, 41), - scores=["fission"], -) - -# Setting -mcdc.setting(N_particle=1e3) -mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/examples/fixed_source/sphere_in_cube/process.py b/examples/fixed_source/sphere_in_cube/process.py deleted file mode 100644 index c77451d04..000000000 --- a/examples/fixed_source/sphere_in_cube/process.py +++ /dev/null @@ -1,62 +0,0 @@ -import h5py -import numpy as np -import matplotlib.pyplot as plt -import scipy.fft as spfft -import cvxpy as cp - -# Note: there are some lines in main.py with np.save(...) that I added -# for ease of post-processing, like getting the center points used and -# the sampling matrix S. None are required for the input file and this -# script to run, but may be useful for debugging purposes - -with h5py.File("output.h5", "r") as f: - S = f["tallies"]["cs_tally_0"]["S"][:] - recon = f["tallies"]["cs_tally_0"]["fission"]["reconstruction"] - plt.imshow(recon) - plt.title("Reconstruction, $\lambda$ = 0.5") # assuming l in main.py remains at 0.5 - plt.colorbar() - plt.show() - - cs_results = f["tallies"]["cs_tally_0"]["fission"]["mean"][:] - - mesh_results = f["tallies"]["mesh_tally_0"]["fission"]["mean"][:] - plt.imshow(mesh_results) - plt.title("mesh results") - plt.colorbar() - plt.show() - -Nx = 40 -Ny = 40 -N_fine_cells = Nx * Ny - -# Can use this for post-processing -# mesh_b = S @ mesh_results.flatten() -# b = mesh_b - -# Use this for analyzing the in-situ results -cs_b = cs_results -b = cs_b - -# Constructing T and A -idct_basis_x = spfft.idct(np.identity(Nx), axis=0) -idct_basis_y = spfft.idct(np.identity(Ny), axis=0) - -T_inv = np.kron(idct_basis_y, idct_basis_x) -A = S @ T_inv - -# Basis pursuit denoising solver - change l to get different results -vx = cp.Variable(N_fine_cells) -l = 10 -objective = cp.Minimize(0.5 * cp.norm(A @ vx - b, 2) + l * cp.norm(vx, 1)) -prob = cp.Problem(objective) -result = prob.solve(verbose=False) -sparse_solution = np.array(vx.value).squeeze() - -# Obtaining the reconstruction -recon = T_inv @ sparse_solution -recon_reshaped = recon.reshape(Ny, Nx) - -plt.imshow(recon_reshaped) -plt.title(f"Reconstruction, $\lambda$ = {l}") -plt.colorbar() -plt.show() diff --git a/examples/fuel_array_packaged/input.py b/examples/fuel_array_packaged/input.py new file mode 100644 index 000000000..9a7fe04df --- /dev/null +++ b/examples/fuel_array_packaged/input.py @@ -0,0 +1,109 @@ +import numpy as np +import mcdc + + +# ====================================================================================== +# Materials +# ====================================================================================== + +fuel = mcdc.MaterialMG( + capture=np.array([0.45]), + fission=np.array([0.55]), + nu_p=np.array([2.5]), +) + +cover = mcdc.MaterialMG( + capture=np.array([0.05]), + scatter=np.array([[0.95]]), +) + +water = mcdc.MaterialMG( + capture=np.array([0.02]), + scatter=np.array([[0.08]]), +) + +# ====================================================================================== +# The assembly +# ====================================================================================== + +# Surfaces +cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0) +cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0) + +top_z = mcdc.Surface.PlaneZ(z=2.5) +bot_z = mcdc.Surface.PlaneZ(z=-2.5) +top_x = mcdc.Surface.PlaneX(x=2.5) +bot_x = mcdc.Surface.PlaneX(x=-2.5) + +sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0) + +# Cells +pellet_z = -cylinder_z & +bot_z & -top_z +pellet_x = -cylinder_x & +bot_x & -top_x +shooting_star = pellet_z | pellet_x +fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel) +cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover) +water_tank = mcdc.Cell(region=+sphere, fill=water) + +# ====================================================================================== +# Copy the assembly via universe cells +# ====================================================================================== + +# Set the universe +assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank]) + +# Set container cell surfaces +min_x = mcdc.Surface.PlaneX(x=-10.0, boundary_condition="vacuum") +mid_x = mcdc.Surface.PlaneX(x=0.0) +max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum") +min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum") +max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum") +min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum") +max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum") + +# Make copies via universe cells +container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x +container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x +assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0]) +assembly_right = mcdc.Cell( + region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0] +) + +# Root universe +mcdc.simulation.set_root_universe(cells=[assembly_left, assembly_right]) + +# ====================================================================================== +# Set source +# ====================================================================================== + +mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy_group=0) + +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== + +# Tallies +mesh = mcdc.MeshStructured( + x=np.linspace(-10, 10, 201), + z=np.linspace(-5, 5, 101), +) +mcdc.TallyMesh(mesh=mesh, scores=["fission"]) + +# Settings +mcdc.settings.N_particle = 1000 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 + +# Run (or visualize) +visualize = False +if not visualize: + mcdc.run() +else: + colors = { + fuel: "red", + cover: "gray", + water: "blue", + } + mcdc.visualize( + "xz", y=0.0, x=[-11.0, 11.0], z=[-6, 6], pixels=(400, 400), colors=colors + ) diff --git a/examples/fuel_array_packaged/process-output.py b/examples/fuel_array_packaged/process-output.py new file mode 100644 index 000000000..6aaa31242 --- /dev/null +++ b/examples/fuel_array_packaged/process-output.py @@ -0,0 +1,38 @@ +import matplotlib.pyplot as plt +import h5py, sys +import numpy as np + + +# Load result +with h5py.File("output.h5", "r") as f: + x = f["tallies/mesh_tally_0/grid/x"][:] + z = f["tallies/mesh_tally_0/grid/z"][:] + dx = [x[1:] - x[:-1]][-1] + x_mid = 0.5 * (x[:-1] + x[1:]) + dz = [z[1:] - z[:-1]][-1] + z_mid = 0.5 * (z[:-1] + z[1:]) + + phi = f["tallies/mesh_tally_0/fission/mean"][:] + phi_sd = f["tallies/mesh_tally_0/fission/sdev"][:] + + +# Plot result +fig, ax = plt.subplots(2, 1, figsize=(4, 9)) +X, Y = np.meshgrid(z_mid, x_mid) +Z = phi +flux_plot = ax[0].pcolormesh(Y, X, Z) +ax[0].set_aspect("equal") +ax[0].set_ylabel(r"$x$ [cm]") +ax[0].set_xlabel(r"$z$ [cm]") +fig.colorbar(flux_plot, ax=ax[0], orientation="horizontal") +ax[0].set_title("Flux") +# +Z = phi_sd / phi +sdev_plot = ax[1].pcolormesh(Y, X, Z) +ax[1].set_aspect("equal") +ax[1].set_ylabel(r"$x$ [cm]") +ax[1].set_xlabel(r"$z$ [cm]") +fig.colorbar(sdev_plot, ax=ax[1], orientation="horizontal") +ax[1].set_title("Standard Deviation [%]") + +plt.show() diff --git a/examples/kobayashi-TD/input.py b/examples/kobayashi-TD/input.py new file mode 100644 index 000000000..174366cac --- /dev/null +++ b/examples/kobayashi-TD/input.py @@ -0,0 +1,78 @@ +import numpy as np +import mcdc + + +# ====================================================================================== +# Set model +# ====================================================================================== +# Based on Kobayashi dog-leg benchmark problem +# (PNE 2001, https://doi.org/10.1016/S0149-1970(01)00007-5) + +# Set materials +m = mcdc.MaterialMG(capture=np.array([0.05]), scatter=np.array([[0.05]])) +m_void = mcdc.MaterialMG(capture=np.array([5e-5]), scatter=np.array([[5e-5]])) + +# Set surfaces +sx1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +sx2 = mcdc.Surface.PlaneX(x=10.0) +sx3 = mcdc.Surface.PlaneX(x=30.0) +sx4 = mcdc.Surface.PlaneX(x=40.0) +sx5 = mcdc.Surface.PlaneX(x=60.0, boundary_condition="vacuum") +sy1 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") +sy2 = mcdc.Surface.PlaneY(y=10.0) +sy3 = mcdc.Surface.PlaneY(y=50.0) +sy4 = mcdc.Surface.PlaneY(y=60.0) +sy5 = mcdc.Surface.PlaneY(y=100.0, boundary_condition="vacuum") +sz1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="reflective") +sz2 = mcdc.Surface.PlaneZ(z=10.0) +sz3 = mcdc.Surface.PlaneZ(z=30.0) +sz4 = mcdc.Surface.PlaneZ(z=40.0) +sz5 = mcdc.Surface.PlaneZ(z=60.0, boundary_condition="vacuum") + +# Set cells +# Source +mcdc.Cell(region=+sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2, fill=m) +# Voids +channel_1 = +sx1 & -sx2 & +sy2 & -sy3 & +sz1 & -sz2 +channel_2 = +sx1 & -sx3 & +sy3 & -sy4 & +sz1 & -sz2 +channel_3 = +sx3 & -sx4 & +sy3 & -sy4 & +sz1 & -sz3 +channel_4 = +sx3 & -sx4 & +sy3 & -sy5 & +sz3 & -sz4 +void_channel = channel_1 | channel_2 | channel_3 | channel_4 +mcdc.Cell(region=void_channel, fill=m_void) +# Shield +box = +sx1 & -sx5 & +sy1 & -sy5 & +sz1 & -sz5 +mcdc.Cell(region=box & ~void_channel, fill=m) + +# ====================================================================================== +# Set source +# ====================================================================================== +# The source pulses in t=[0,5] + +mcdc.Source( + x=[0.0, 10.0], + y=[0.0, 10.0], + z=[0.0, 10.0], + isotropic=True, + energy_group=0, + time=[0.0, 50.0], +) + +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== + +# Tallies +time_grid = np.linspace(0.0, 200.0, 21) +mesh = mcdc.MeshUniform(x=(0.0, 1.0, 60), y=(0.0, 1.0, 100)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], time=time_grid) +mcdc.TallyGlobal(scores=["density"], time=time_grid) + +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 + +# Techniques +mcdc.simulation.implicit_capture() + +# Run +mcdc.run() diff --git a/examples/kobayashi-TD/process-output.py b/examples/kobayashi-TD/process-output.py new file mode 100644 index 000000000..1dc81641f --- /dev/null +++ b/examples/kobayashi-TD/process-output.py @@ -0,0 +1,55 @@ +import numpy as np +import matplotlib.pyplot as plt +import h5py +import matplotlib.animation as animation + +# Load result +with h5py.File("output.h5", "r") as f: + x = f["tallies/mesh_tally_0/grid/x"][:] + x_mid = 0.5 * (x[:-1] + x[1:]) + y = f["tallies/mesh_tally_0/grid/y"][:] + y_mid = 0.5 * (y[:-1] + y[1:]) + t = f["tallies/mesh_tally_0/grid/time"][:] + t_mid = 0.5 * (t[:-1] + t[1:]) + X, Y = np.meshgrid(y, x) + + phi = f["tallies/mesh_tally_0/flux/mean"][:] + phi_sd = f["tallies/mesh_tally_0/flux/sdev"][:] + + phi_total = f["tallies/global_tally_0/density/mean"][:] + phi_total_sd = f["tallies/global_tally_0/density/sdev"][:] + +# Animate result +fig, ax = plt.subplots(1, 2, figsize=(8, 4), gridspec_kw={"width_ratios": [1.0, 2]}) +# +cax = ax[1].pcolormesh(X, Y, phi[0], vmin=phi[0].min(), vmax=phi[0].max()) +ax[1].set_aspect("equal", "box") +ax[1].set_xlabel("$y$ [cm]") +ax[1].set_ylabel("$x$ [cm]") +# +ax[0].plot(t_mid, phi_total) +ax[0].set_xlabel("$t$ [s]") +ax[0].set_ylabel("Neutron density") +ax[0].set_yscale("log") +ax[0].plot(t_mid, phi_total, "b-") +ax[0].fill_between( + t_mid, phi_total - phi_total_sd, phi_total + phi_total_sd, alpha=0.2, color="b" +) +ax[0].grid() +ax[0].set_box_aspect(1) +(line,) = ax[0].plot([], [], "ok", fillstyle="none") + + +# +def animate(i): + n = np.zeros_like(t_mid) + n[i] = phi_total[i] + line.set_data(t_mid, n) + cax.set_array(phi[i]) + cax.set_clim(phi[i].min(), phi[i].max()) + + +# +K = len(t) - 1 +anim = animation.FuncAnimation(fig, animate, frames=K) +plt.show() diff --git a/examples/moving_pellet/input.py b/examples/moving_pellet/input.py new file mode 100644 index 000000000..89feaf427 --- /dev/null +++ b/examples/moving_pellet/input.py @@ -0,0 +1,96 @@ +import numpy as np + +import mcdc + + +# ====================================================================================== +# Set model +# ====================================================================================== + +# Set materials +fuel = mcdc.MaterialMG( + capture=np.array([0.5]), + fission=np.array([0.25]), + nu_p=np.array([1.5]), + speed=np.array([200000.0]), +) +air = mcdc.MaterialMG( + capture=np.array([0.002]), + scatter=np.array([[0.008]]), + speed=np.array([200000.0]), +) + +# Set surfaces +cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0) +top_z = mcdc.Surface.PlaneZ(z=9.0) +bot_z = mcdc.Surface.PlaneZ(z=6.0) + +# Move surfaces +cylinder_z.move([[-0.5, 0.0, 0.0], [1.0, 0.0, 0.0], [-2.0, 0.0, 0.0]], [2.0, 5.0, 1.0]) +top_z.move([[0.0, 0.0, -2.0], [0.0, 0.0, 4.0], [0.0, 0.0, -10.0]], [5.0, 2.0, 1.0]) +bot_z.move([[0.0, 0.0, -2.0], [0.0, 0.0, 4.0], [0.0, 0.0, -10.0]], [5.0, 2.0, 1.0]) + +# Set container cell surfaces +min_x = mcdc.Surface.PlaneX(x=-5.0, boundary_condition="vacuum") +max_x = mcdc.Surface.PlaneX(x=5.0, boundary_condition="vacuum") +min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum") +max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum") +min_z = mcdc.Surface.PlaneZ(z=-10.0, boundary_condition="vacuum") +max_z = mcdc.Surface.PlaneZ(z=10.0, boundary_condition="vacuum") + +# Make cells +fuel_pellet_region = +bot_z & -top_z & -cylinder_z +mcdc.Cell(region=fuel_pellet_region, fill=fuel) +mcdc.Cell( + region=~fuel_pellet_region & +min_x & -max_x & +min_y & -max_y & +min_z & -max_z, + fill=air, +) + +# ====================================================================================== +# Set source +# ====================================================================================== + +mcdc.Source( + x=[2.0, 3.0], + y=[-0.5, 0.5], + z=[-0.5, 0.5], + isotropic=True, + energy_group=0, + time=[0.0, 9.0], +) + +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== + +# Tallies +mesh = mcdc.MeshStructured( + x=np.linspace(-5, 5, 201), + z=np.linspace(-10, 10, 201), +) +mcdc.TallyMesh(mesh=mesh, scores=["fission"], time=np.linspace(0, 9, 46)) + +# Settings +mcdc.settings.N_particle = 100000 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 + +# Run (or visualize) +visualize = False +if not visualize: + mcdc.run() +else: + colors = { + fuel: "red", + air: "blue", + } + mcdc.visualize( + "xz", + y=0.0, + x=[-5.0, 5.0], + z=[-10, 10], + pixels=(100, 100), + colors=colors, + time=np.linspace(0.0, 9.0, 19), + save_as="figure", + ) diff --git a/test/regression/moving_pellet/process.py b/examples/moving_pellet/process-output.py similarity index 94% rename from test/regression/moving_pellet/process.py rename to examples/moving_pellet/process-output.py index 1df6d887f..41a1d555d 100644 --- a/test/regression/moving_pellet/process.py +++ b/examples/moving_pellet/process-output.py @@ -15,15 +15,13 @@ x_mid = 0.5 * (x[:-1] + x[1:]) z = f["tallies/mesh_tally_0/grid/z"][:] z_mid = 0.5 * (z[:-1] + z[1:]) - t = f["tallies/mesh_tally_0/grid/t"][:] + t = f["tallies/mesh_tally_0/grid/time"][:] t_mid = 0.5 * (t[:-1] + t[1:]) X, Y = np.meshgrid(z, x) phi = f["tallies/mesh_tally_0/fission/mean"][:] phi_sd = f["tallies/mesh_tally_0/fission/sdev"][:] -print(np.max(phi)) - fig, ax = plt.subplots() cax = ax.pcolormesh(X, Y, phi[0]) text = ax.text(0.02, 1.02, "", transform=ax.transAxes) diff --git a/examples/c5g7/3d/k-eigenvalue/input.py b/examples/need_update/c5g7/3d/k-eigenvalue/input.py similarity index 100% rename from examples/c5g7/3d/k-eigenvalue/input.py rename to examples/need_update/c5g7/3d/k-eigenvalue/input.py diff --git a/examples/fixed_source/azurv1_pl_super/input.py b/examples/need_update/fixed_source/azurv1_pl_super/input.py similarity index 100% rename from examples/fixed_source/azurv1_pl_super/input.py rename to examples/need_update/fixed_source/azurv1_pl_super/input.py diff --git a/examples/fixed_source/kobayashi3-TD/input.py b/examples/need_update/fixed_source/kobayashi3-TD/input.py similarity index 100% rename from examples/fixed_source/kobayashi3-TD/input.py rename to examples/need_update/fixed_source/kobayashi3-TD/input.py diff --git a/examples/fixed_source/inf_pin_ce/energy_grid.txt b/examples/pincell/energy_grid.txt similarity index 100% rename from examples/fixed_source/inf_pin_ce/energy_grid.txt rename to examples/pincell/energy_grid.txt diff --git a/examples/pincell/input.py b/examples/pincell/input.py new file mode 100644 index 000000000..fa44ed37e --- /dev/null +++ b/examples/pincell/input.py @@ -0,0 +1,64 @@ +import numpy as np +import mcdc + + +# ============================================================================= +# Set model +# ============================================================================= + +# Set materials +fuel = mcdc.Material( + nuclide_composition={ + "U235": 0.0005581658948833916, + "U238": 0.022404594715383263, + "O16": 0.045831301393656466, + } +) + +water = mcdc.Material( + nuclide_composition={ + "B10": 0.0001357003217727274, + "H1": 0.0684556951587359, + "O16": 0.032785655643293984, + } +) + +# Set surfaces +cy = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=0.45720) +pitch = 1.25984 +x1 = mcdc.Surface.PlaneX(x=-pitch / 2, boundary_condition="reflective") +x2 = mcdc.Surface.PlaneX(x=pitch / 2, boundary_condition="reflective") +y1 = mcdc.Surface.PlaneY(y=-pitch / 2, boundary_condition="reflective") +y2 = mcdc.Surface.PlaneY(y=pitch / 2, boundary_condition="reflective") + +# Set cells +mcdc.Cell(region=-cy & +x1 & -x2 & +y1 & -y2, fill=fuel) +mcdc.Cell(region=+cy & +x1 & -x2 & +y1 & -y2, fill=water) + +# ============================================================================= +# Set source +# ============================================================================= + +mcdc.Source( + x=[-pitch / 2, pitch / 2], + y=[-pitch / 2, pitch / 2], + isotropic=True, + energy=1e6, +) + +# ============================================================================= +# Set tallies, settings, and run MC/DC +# ============================================================================= + +# Tallies +mcdc.TallyGlobal( + scores=["flux"], + energy=np.loadtxt("energy_grid.txt"), +) + +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.set_eigenmode(N_inactive=10, N_active=50) + +# Run +mcdc.run() diff --git a/examples/fixed_source/inf_pin_ce/process.py b/examples/pincell/process.py similarity index 100% rename from examples/fixed_source/inf_pin_ce/process.py rename to examples/pincell/process.py diff --git a/examples/sphere_in_cube/input.py b/examples/sphere_in_cube/input.py new file mode 100644 index 000000000..441125f9c --- /dev/null +++ b/examples/sphere_in_cube/input.py @@ -0,0 +1,56 @@ +import numpy as np +import mcdc + +# ====================================================================================== +# Set model +# ====================================================================================== +# Homogeneous pure-fission sphere inside a pure-scattering cube + +# Set materials +pure_f = mcdc.MaterialMG(fission=np.array([1.0]), nu_p=np.array([1.2])) +pure_s = mcdc.MaterialMG(scatter=np.array([[1.0]])) + +# Set surfaces +sx1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="vacuum") +sx2 = mcdc.Surface.PlaneX(x=4.0, boundary_condition="vacuum") +sy1 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="vacuum") +sy2 = mcdc.Surface.PlaneY(y=4.0, boundary_condition="vacuum") +sz1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="vacuum") +sz2 = mcdc.Surface.PlaneZ(z=4.0, boundary_condition="vacuum") +sphere = mcdc.Surface.Sphere(center=[2.0, 2.0, 2.0], radius=1.5) +inside_sphere = -sphere +inside_box = +sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2 + +# Set cells +mcdc.Cell(name="Box cover", region=inside_box & ~inside_sphere, fill=pure_s) +sphere_cell = mcdc.Cell(name="The sphere", region=inside_sphere, fill=pure_f) + +# ====================================================================================== +# Set source +# ====================================================================================== + +mcdc.Source( + x=[0.0, 4.0], + y=[0.0, 4.0], + z=[0.0, 4.0], + isotropic=True, + energy_group=0, + time=[0.0, 50.0], +) + +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== + +# Tallies +mcdc.TallyCell(name="Spherical fission detector", cell=sphere_cell, scores=["fission"]) + +# Settings +mcdc.settings.N_particle = 1000 +mcdc.settings.N_batch = 2 + +# Techniques +mcdc.simulation.implicit_capture() + +# Run +mcdc.run() diff --git a/examples/sphere_in_cube/process-output.py b/examples/sphere_in_cube/process-output.py new file mode 100644 index 000000000..6df13fa48 --- /dev/null +++ b/examples/sphere_in_cube/process-output.py @@ -0,0 +1,9 @@ +import h5py + +tally_name = "Spherical fission detector" + +with h5py.File("output.h5", "r") as file: + mean = file[f"tallies/{tally_name}/fission/mean"][()] + sdev = file[f"tallies/{tally_name}/fission/sdev"][()] + +print(f"\n{tally_name}: {mean} +/- {sdev}\n") diff --git a/install.sh b/install.sh index 7d3f6a505..5fa341272 100755 --- a/install.sh +++ b/install.sh @@ -46,6 +46,3 @@ pip install -e . # Install pre-commit hook pre-commit install - -# Installing visualization dependencies (required via pip for osx-arm64) -pip install ngsolve distinctipy diff --git a/mcdc/__init__.py b/mcdc/__init__.py index 6851a6f44..ef57dd260 100644 --- a/mcdc/__init__.py +++ b/mcdc/__init__.py @@ -1,37 +1,30 @@ -import importlib.metadata +# ====================================================================================== +# Simulation building blocks +# ====================================================================================== -from mcdc.input_ import ( - nuclide, - material, - surface, - cell, - universe, - lattice, - source, - setting, - eigenmode, - implicit_capture, - weighted_emission, - population_control, - branchless_collision, - time_census, - weight_window, - iQMC, - weight_roulette, - IC_generator, - uq, - reset, - domain_decomposition, - make_particle_bank, - save_particle_bank, -) -import mcdc.tally -from mcdc.main import ( - prepare, - run, - visualize, - recombine_tallies, -) +# The simulation +from mcdc.object_.simulation import simulation -# Temporarily commenting out so docs will build -# __version__ = importlib.metadata.version("mcdc") +# The settings +settings = simulation.settings + +# The objects +from mcdc.object_.cell import Cell, Universe, Lattice +from mcdc.object_.material import Material, MaterialMG +from mcdc.object_.mesh import MeshUniform, MeshStructured +from mcdc.object_.source import Source +from mcdc.object_.surface import Surface +from mcdc.object_.tally import TallyGlobal, TallyCell, TallySurface, TallyMesh + +# ====================================================================================== +# Runners +# ====================================================================================== + +from mcdc.main import run, visualize + +# ====================================================================================== +# Misc. +# ====================================================================================== + +import mcdc.config +from mcdc.output import recombine_tallies diff --git a/mcdc/card.py b/mcdc/card.py deleted file mode 100644 index 91af4a9a8..000000000 --- a/mcdc/card.py +++ /dev/null @@ -1,429 +0,0 @@ -import numpy as np -import sympy - -from mcdc.constant import ( - BOOL_AND, - BOOL_OR, - BOOL_NOT, - INF, - PI, -) - -# Get the global variable container -import mcdc.global_ as global_ - - -class InputCard: - def __init__(self, tag): - self.tag = tag - - def __str__(self): - text = "%s card\n" % self.tag - - for name in [ - a - for a in dir(self) - if not a.startswith("__") - and not callable(getattr(self, a)) - and a != "tag" - and not a.startswith("_") - ]: - text += " %s : %s\n" % (name, str(getattr(self, name))) - return text - - -class NuclideCard(InputCard): - def __init__(self, G=1, J=0, name=None): - InputCard.__init__(self, "Nuclide") - - # Continuous energy? - if name is not None: - G = 0 - J = 0 - - # Set card data - self.ID = None - self.name = name - self.G = G - self.J = J - self.fissionable = False - self.speed = np.ones(G) - self.decay = np.ones(J) * INF - self.capture = np.zeros(G) - self.scatter = np.zeros(G) - self.fission = np.zeros(G) - self.total = np.zeros(G) - self.nu_s = np.ones(G) - self.nu_p = np.zeros(G) - self.nu_d = np.zeros([G, J]) - self.nu_f = np.zeros(G) - self.chi_s = np.zeros([G, G]) - self.chi_p = np.zeros([G, G]) - self.chi_d = np.zeros([J, G]) - self.uq = False - self.flags = [] - self.distribution = "" - self.name = "" - - -class MaterialCard(InputCard): - def __init__(self, N_nuclide, G=1, J=0): - InputCard.__init__(self, "Material") - - # Set card data - self.ID = None - self.N_nuclide = N_nuclide - self.nuclide_IDs = np.zeros(N_nuclide, dtype=int) - self.nuclide_densities = np.zeros(N_nuclide, dtype=float) - self.G = G - self.J = J - self.speed = np.zeros(G) - self.capture = np.zeros(G) - self.scatter = np.zeros(G) - self.fission = np.zeros(G) - self.total = np.zeros(G) - self.nu_s = np.ones(G) - self.nu_p = np.zeros(G) - self.nu_d = np.zeros([G, J]) - self.nu_f = np.zeros(G) - self.chi_s = np.zeros([G, G]) - self.chi_p = np.zeros([G, G]) - self.uq = False - self.flags = [] - self.distribution = "" - - -class RegionCard(InputCard): - def __init__(self, type_): - InputCard.__init__(self, "Region") - - # Set card data - self.ID = None - self.type = type_ - self.A = None - self.B = None - - def __and__(self, other): - region = RegionCard("intersection") - region.A = self.ID - region.B = other.ID - # Set ID and push to deck - region.ID = len(global_.input_deck.regions) - global_.input_deck.regions.append(region) - return region - - def __or__(self, other): - region = RegionCard("union") - region.A = self.ID - region.B = other.ID - # Set ID and push to deck - region.ID = len(global_.input_deck.regions) - global_.input_deck.regions.append(region) - return region - - def __invert__(self): - region = RegionCard("complement") - region.A = self.ID - # Set ID and push to deck - region.ID = len(global_.input_deck.regions) - global_.input_deck.regions.append(region) - return region - - def __str__(self): - if self.type == "halfspace": - if self.B > 0: - return "+s%i" % self.A - else: - return "-s%i" % self.A - elif self.type == "intersection": - return "r%i & r%i" % (self.A, self.B) - elif self.type == "union": - return "r%i | r%i" % (self.A, self.B) - elif self.type == "complement": - return "~r%i" % (self.A) - elif self.type == "all": - return "all" - - -class SurfaceCard(InputCard): - def __init__(self): - InputCard.__init__(self, "Surface") - - # Set card data - self.ID = None - self.type = "" - self.boundary_type = "interface" - self.linear = False - self.A = 0.0 - self.B = 0.0 - self.C = 0.0 - self.D = 0.0 - self.E = 0.0 - self.F = 0.0 - self.G = 0.0 - self.H = 0.0 - self.I = 0.0 - self.J = 0.0 - self.nx = 0.0 - self.ny = 0.0 - self.nz = 0.0 - self.N_tally = 0 - self.tally_IDs = [] - self.moving = False - self.N_move = 1 - self.move_velocities = [(0.0, 0.0, 0.0)] - self.move_durations = [INF] - - def _create_halfspace(self, positive): - region = RegionCard("halfspace") - region.A = self.ID - if positive: - region.B = 1 - else: - region.B = -1 - - # Check if an identical halfspace region already existed - for idx, existing_region in enumerate(global_.input_deck.regions): - if ( - existing_region.type == "halfspace" - and region.A == existing_region.A - and region.B == existing_region.B - ): - return global_.input_deck.regions[idx] - - # Set ID and push to deck - region.ID = len(global_.input_deck.regions) - global_.input_deck.regions.append(region) - return region - - def __pos__(self): - return self._create_halfspace(True) - - def __neg__(self): - return self._create_halfspace(False) - - def move(self, velocities, durations): - self.moving = True - self.N_move = len(durations) + 1 - - if isinstance(velocities, np.ndarray): - velocities = velocities.tolist() - durations = durations.tolist() - - self.move_velocities = velocities - self.move_velocities.append([0.0, 0.0, 0.0]) - self.move_velocities = np.array(self.move_velocities) - - self.move_durations = durations - self.move_durations.append(INF) - self.move_durations = np.array(self.move_durations) - - -class CellCard(InputCard): - def __init__(self): - InputCard.__init__(self, "Cell") - - # Set card data - self.ID = None - self.region_ID = None - self.region = "all" - self.fill_type = "material" - self.fill_ID = None - self.translation = np.array([0.0, 0.0, 0.0]) - self.rotation = np.array([0.0, 0.0, 0.0]) - self.surface_IDs = np.zeros(0, dtype=int) - self.N_tally = 0 - self.tally_IDs = [] - self._region_RPN = [] # Reverse Polish Notation - - def set_region_RPN(self): - # Make alias and reset - rpn = self._region_RPN - rpn.clear() - - # Build RPN based on the assigned region - region = global_.input_deck.regions[self.region_ID] - stack = [region] - while len(stack) > 0: - token = stack.pop() - if isinstance(token, RegionCard): - if token.type == "halfspace": - rpn.append(token.ID) - elif token.type == "intersection": - region_A = global_.input_deck.regions[token.A] - region_B = global_.input_deck.regions[token.B] - stack += ["&", region_A, region_B] - elif token.type == "union": - region_A = global_.input_deck.regions[token.A] - region_B = global_.input_deck.regions[token.B] - stack += ["|", region_A, region_B] - elif token.type == "complement": - region = global_.input_deck.regions[token.A] - stack += ["~", region] - else: - if token == "&": - rpn.append(BOOL_AND) - elif token == "|": - rpn.append(BOOL_OR) - elif token == "~": - rpn.append(BOOL_NOT) - else: - print_error("Something is wrong with cell RPN creation.") - - def set_region(self): - stack = [] - - for token in self._region_RPN: - if token >= 0: - stack.append(token) - else: - if token == BOOL_AND or token == BOOL_OR: - item_1 = stack.pop() - if isinstance(item_1, int): - item_1 = sympy.symbols(str(global_.input_deck.regions[item_1])) - - item_2 = stack.pop() - if isinstance(item_2, int): - item_2 = sympy.symbols(str(global_.input_deck.regions[item_2])) - - if token == BOOL_AND: - stack.append(item_1 & item_2) - else: - stack.append(item_1 | item_2) - - elif token == BOOL_NOT: - item = stack.pop() - if isinstance(item, int): - item = sympy.symbols(str(global_.input_deck.regions[item])) - stack.append(~item) - - self.region = sympy.logic.boolalg.simplify_logic(stack[0]) - - def set_surface_IDs(self): - surface_IDs = [] - - for token in self._region_RPN: - if token >= 0: - ID = global_.input_deck.regions[token].A - if not ID in surface_IDs: - surface_IDs.append(ID) - - self.surface_IDs = np.sort(np.array(surface_IDs)) - - -class UniverseCard(InputCard): - def __init__(self): - InputCard.__init__(self, "Universe") - - # Set card data - self.ID = None - self.cell_IDs = np.zeros(0, dtype=int) - - -class LatticeCard(InputCard): - def __init__(self): - InputCard.__init__(self, "Lattice") - - # Set card data - self.ID = None - self.universe_IDs = np.array([[[[0]]]]) - self.x0 = -INF - self.x0 = -INF - self.dx = 2 * INF - self.Nx = 1 - self.y0 = -INF - self.dy = 2 * INF - self.Ny = 1 - self.z0 = -INF - self.dz = 2 * INF - self.Nz = 1 - - -class SourceCard(InputCard): - def __init__(self): - InputCard.__init__(self, "Source") - - # Set card data - self.ID = None - self.box = False - self.isotropic = True - self.white = False - self.x = 0.0 - self.y = 0.0 - self.z = 0.0 - self.box_x = np.array([0.0, 0.0]) - self.box_y = np.array([0.0, 0.0]) - self.box_z = np.array([0.0, 0.0]) - self.ux = 0.0 - self.uy = 0.0 - self.uz = 0.0 - self.white_x = 0.0 - self.white_y = 0.0 - self.white_z = 0.0 - self.group = np.array([1.0]) - self.energy = np.array([[1e6 - 1.0, 1e6 + 1.0], [1.0, 1.0]]) - self.time = np.array([0.0, 0.0]) - self.prob = 1.0 - - -# ====================================================================================== -# Tally cards -# ====================================================================================== - - -class TallyCard(InputCard): - def __init__(self, type_): - InputCard.__init__(self, type_) - - # Set card data - self.ID = None - self.scores = [] - self.N_bin = 0 - - # Filters - self.t = np.array([-INF, INF]) - self.mu = np.array([-1.0, 1.0]) - self.azi = np.array([-PI, PI]) - self.g = np.array([-INF, INF]) - - -class MeshTallyCard(TallyCard): - def __init__(self): - TallyCard.__init__(self, "Mesh tally") - - # Set card data - self.x = np.array([-INF, INF]) - self.y = np.array([-INF, INF]) - self.z = np.array([-INF, INF]) - self.N_bin = 1 - - -class SurfaceTallyCard(TallyCard): - def __init__(self, surface_ID): - TallyCard.__init__(self, "Surface tally") - - # Set card data - self.surface_ID = surface_ID - self.N_bin = 1 - - -class CellTallyCard(TallyCard): - def __init__(self, cell_ID): - TallyCard.__init__(self, "Cell tally") - - # Set card data - self.cell_ID = cell_ID - self.N_bin = 1 - - -class CSTallyCard(TallyCard): - def __init__(self): - TallyCard.__init__(self, "CS tally") - - # Set card data - self.x = np.array([-INF, INF]) - self.y = np.array([-INF, INF]) - self.z = np.array([-INF, INF]) - self.N_bin = 1 - self.N_cs_bins = 1 - self.cs_bin_size = np.array([1.0, 1.0]) diff --git a/mcdc/adapt.py b/mcdc/code_factory/adapt.py similarity index 82% rename from mcdc/adapt.py rename to mcdc/code_factory/adapt.py index 515cd9efd..29ac44b69 100644 --- a/mcdc/adapt.py +++ b/mcdc/code_factory/adapt.py @@ -1,12 +1,10 @@ import importlib -import numpy as np -from numba import njit, jit, objmode, literal_unroll, types -from numba.extending import intrinsic +import inspect import numba -import mcdc.type_ as type_ -import mcdc.kernel as kernel -import mcdc.config as config +import numpy as np +from numba import njit, jit, types +from numba.extending import intrinsic if importlib.util.find_spec("harmonize") is None: HAS_HARMONIZE = False @@ -15,13 +13,12 @@ HAS_HARMONIZE = True +#### -import math -import inspect -from mcdc.print_ import print_error +import mcdc.config as config -import mcdc.adapt as adapt +from mcdc.print_ import print_error # ============================================================================= @@ -414,11 +411,6 @@ def nopython_mode(is_on): # ============================================================================= -@numba.njit() -def alloc_bytes_placeholder(size): - return uintp_to_voidptr(0) - - SIMPLE_ASYNC = True none_type = None @@ -438,12 +430,12 @@ def alloc_bytes_placeholder(size): tally_width = None tally_length = None tally_size = None -alloc_managed_bytes = alloc_bytes_placeholder -alloc_device_bytes = alloc_bytes_placeholder tally_shape_literal = None -def gpu_forward_declare(args, tally_shape): +def gpu_forward_declare( + args, data_shape, global_type, particle_type, particle_data_type +): if args.gpu_rocm_path != None: harm.config.set_rocm_path(args.gpu_rocm_path) @@ -459,16 +451,16 @@ def gpu_forward_declare(args, tally_shape): global step_async, find_cell_async, halt_early global tally_width, tally_length, tally_size - tally_size = tally_shape[0] * tally_shape[1] * 8 + tally_size = data_shape[0] * 8 global tally_shape_literal - tally_shape_literal = tally_shape + tally_shape_literal = data_shape none_type = numba.from_dtype(np.dtype([])) - mcdc_global_type = numba.types.Array(numba.from_dtype(type_.global_), (1,), "C") - # mcdc_global_type = numba.from_dtype(type_.global_) + mcdc_global_type = numba.types.Array(numba.from_dtype(global_type), (1,), "C") + # mcdc_global_type = numba.from_dtype(global_type) - tally_dims = len(tally_shape) + tally_dims = len(data_shape) mcdc_data_type = numba.types.Array(numba.float64, tally_dims, "C") state_spec = ( { @@ -483,8 +475,8 @@ def gpu_forward_declare(args, tally_shape): mcdc_data_gpu = access_fns["device"]["data"]["direct"] group_gpu = access_fns["group"] thread_gpu = access_fns["thread"] - particle_gpu = numba.from_dtype(type_.particle) - particle_record_gpu = numba.from_dtype(type_.particle_record) + particle_gpu = numba.from_dtype(particle_type) + particle_record_gpu = numba.from_dtype(particle_data_type) def step(prog: numba.uintp, P: particle_gpu): pass @@ -492,49 +484,11 @@ def step(prog: numba.uintp, P: particle_gpu): def find_cell(prog: numba.uintp, P: particle_gpu): pass - step_async, find_cell_async = adapt.harm.RuntimeSpec.async_dispatch(step, find_cell) - interface = adapt.harm.RuntimeSpec.program_interface() - halt_early = interface["halt_early"] - - global alloc_managed_bytes - global alloc_device_bytes - alloc_managed_bytes = harm.alloc_managed_bytes - alloc_device_bytes = harm.alloc_device_bytes + import harmonize - -# ============================================================================= -# Global GPU/CPU Arry Variable Constructors -# ============================================================================= - - -@numba.njit() -def create_tally_array(width, length): - if config.target == "gpu": - if config.gpu_state_storage == "managed": - data_tally_ptr = alloc_managed_bytes(tally_size) - else: - data_tally_ptr = alloc_device_bytes(tally_size) - data_tally_uint = voidptr_to_uintp(data_tally_ptr) - data_tally = numba.carray(data_tally_ptr, (width, length), type_.float64) - return data_tally, data_tally_uint - else: - data_tally = np.zeros((width, length), dtype=type_.float64) - return data_tally, 0 - - -@numba.njit() -def create_mcdc_array(): - if config.target == "gpu": - if config.gpu_state_storage == "managed": - mcdc_ptr = alloc_managed_bytes(type_.global_size) - else: - mcdc_ptr = alloc_device_bytes(type_.global_size) - mcdc_uint = voidptr_to_uintp(mcdc_ptr) - mcdc_array = numba.carray(mcdc_ptr, (1,), type_.global_) - return mcdc_array, mcdc_uint - else: - mcdc_array = np.zeros((1,), dtype=type_.global_) - return mcdc_array, 0 + step_async, find_cell_async = harmonize.RuntimeSpec.async_dispatch(step, find_cell) + interface = harmonize.RuntimeSpec.program_interface() + halt_early = interface["halt_early"] # ============================================================================= @@ -586,65 +540,6 @@ def thread(prog): return thread_gpu(prog) -@for_cpu() -def add_active(P_arr, prog): - kernel.add_particle(P_arr, prog["bank_active"]) - - -@for_gpu() -def add_active(P_rec_arr, prog): - P_arr = local_array(1, type_.particle) - kernel.recordlike_to_particle(P_arr, P_rec_arr) - if SIMPLE_ASYNC: - step_async(prog, P_arr[0]) - else: - find_cell_async(prog, P_arr[0]) - - -@for_cpu() -def add_source(P_arr, prog): - kernel.add_particle(P_arr, prog["bank_source"]) - - -@for_gpu() -def add_source(P_arr, prog): - mcdc = mcdc_global(prog) - kernel.add_particle(P_arr, mcdc["bank_source"]) - - -@for_cpu() -def add_census(P_arr, prog): - kernel.add_particle(P_arr, prog["bank_census"]) - - -@for_gpu() -def add_census(P_arr, prog): - mcdc = mcdc_global(prog) - kernel.add_particle(P_arr, mcdc["bank_census"]) - - -@for_cpu() -def add_future(P_arr, prog): - kernel.add_particle(P_arr, prog["bank_future"]) - - -@for_gpu() -def add_future(P_arr, prog): - mcdc = mcdc_global(prog) - kernel.add_particle(P_arr, mcdc["bank_future"]) - - -@for_cpu() -def add_IC(P_arr, prog): - kernel.add_particle(P_arr, prog["technique"]["IC_bank_neutron_local"]) - - -@for_gpu() -def add_IC(P_arr, prog): - mcdc = mcdc_global(prog) - kernel.add_particle(P_arr, mcdc["technique"]["IC_bank_neutron_local"]) - - @for_cpu() def global_add(ary, idx, val): result = ary[idx] diff --git a/mcdc/code_factory/code_factory.py b/mcdc/code_factory/code_factory.py new file mode 100644 index 000000000..2b7d97c11 --- /dev/null +++ b/mcdc/code_factory/code_factory.py @@ -0,0 +1,1163 @@ +from __future__ import annotations + +#### + +import numpy as np + +from pathlib import Path +from mpi4py import MPI + +#### + +import mcdc +import mcdc.code_factory.adapt as adapt +import mcdc.config as config +import mcdc.object_ as object_module +import mcdc.object_.base as base + +from mcdc.object_.base import ( + ObjectBase, + ObjectNonSingleton, + ObjectPolymorphic, + ObjectSingleton, +) +from mcdc.object_.particle import Particle, ParticleBank, ParticleData +from mcdc.object_.tally import TallyBase +from mcdc.print_ import print_error +from mcdc.util import flatten + +type_map = { + bool: "?", + float: "f8", + int: "i8", + str: "U32", + np.bool_: "?", + np.float64: "f8", + np.int64: "i8", + np.uint64: "u8", + np.str_: "U32", +} + +bank_names = ["bank_active", "bank_census", "bank_source", "bank_future"] + +# ====================================================================================== +# Gather and group the classes +# ====================================================================================== + +base_classes = [ + getattr(base, x) + for x in dir(base) + if isinstance(getattr(base, x), type) and issubclass(getattr(base, x), ObjectBase) +] + +all_classes = [ParticleData, Particle] +mcdc_classes = [ParticleData, Particle] +polymorphic_bases = [] + +file_names = [x for x in dir(object_module) if x[:2] != "__" and x != "base"] +for file_name in file_names: + file = getattr(object_module, file_name) + item_names = dir(file) + for item_name in item_names: + item = getattr(file, item_name) + if ( + isinstance(item, type) + and issubclass(item, ObjectBase) + and item not in all_classes + ): + all_classes.append(item) + + if ( + item not in base_classes + and "label" in dir(item) + and item not in mcdc_classes + ): + mcdc_classes.append(item) + +polymorphic_bases = [ + x for x in all_classes if x.__name__[-4:] == "Base" and "label" in dir(x) +] + +# ====================================================================================== +# Numba object creation +# ====================================================================================== + + +def generate_numba_objects(simulation): + # ================================================================================== + # Allocate key items for the Numba object: + # - Python annotations + # - Numba structures + # - Records + # - Data: flattened vector to store arbitrary-size arrays + # - Accessor targets: to generate getter/setter helpers to easily access data + # ================================================================================== + + annotations = {} + structures = {} + records = {} + data = {"size": 0} + accessor_targets = {} + + for mcdc_class in mcdc_classes: + annotations[mcdc_class.label] = {} + structures[mcdc_class.label] = [] + accessor_targets[mcdc_class.label] = [] + if issubclass(mcdc_class, ObjectNonSingleton): + records[mcdc_class.label] = [] + else: + records[mcdc_class.label] = {} + + # Particle banks + for name in bank_names: + annotations[name] = {} + structures[name] = [] + accessor_targets[name] = [] + + # Move simulation to last + annotations["simulation"] = annotations.pop("simulation") + structures["simulation"] = structures.pop("simulation") + records["simulation"] = records.pop("simulation") + accessor_targets["simulation"] = accessor_targets.pop("simulation") + + # ================================================================================== + # Gather the annotations from the classes + # ================================================================================== + + for mcdc_class in mcdc_classes: + # Include all ancestors, but stop at the MC/DC base classes + classes = [] + for item in mcdc_class.__mro__: + if item in base_classes: + break + classes.append(item) + + # If polymorphic, don't include the polymorphic base + if issubclass(mcdc_class, ObjectPolymorphic): + classes = [mcdc_class] + + # Get the annotations + for class_ in classes: + new_annotations = { + k: v + for k, v in class_.__annotations__.items() + if k not in ["label", "non_numba"] + and ( + "non_numba" not in dir(class_) + or ("non_numba" in dir(class_) and k not in class_.non_numba) + ) + } + # Evaluate stringified annotation + if ( + len(new_annotations) > 0 + and type(next(iter(new_annotations.values()))) == str + ): + new_annotations = parse_annotations_dict(new_annotations) + + annotations[mcdc_class.label].update(new_annotations) + + # Particle banks + for name in bank_names: + annotations[name] = { + k: v + for k, v in ParticleBank.__annotations__.items() + if k not in ["label", "non_numba"] + and ( + "non_numba" not in dir(ParticleBank) + or ( + "non_numba" in dir(ParticleBank) and k not in ParticleBank.non_numba + ) + ) + } + + # ================================================================================== + # Set the structures and accessor targets based on the annotations + # ================================================================================== + + # Temporary simulation object structure + simulation_object_structure = [] + for field in annotations["simulation"]: + hint = annotations["simulation"][field] + hint_origin = get_origin(hint) + hint_args = get_args(hint) + + if hint in all_classes: + simulation_object_structure.append((field, hint)) + continue + if hint_origin == list and hint_args[0] in all_classes: + simulation_object_structure.append((field, list, hint_args[0])) + continue + + # Set the structures and accessor targets + for label in annotations.keys(): + set_structure(label, structures, accessor_targets, annotations) + + # Generate the accessor helper + if MPI.COMM_WORLD.Get_rank() == 0: + generate_mcdc_access(accessor_targets) + + # Add ID for non-singleton + for class_ in mcdc_classes: + if issubclass(class_, ObjectNonSingleton): + structures[class_.label].append(("ID", "i8")) + # Set parent and child ID and type if polymorphic + if issubclass(class_, ObjectPolymorphic): + if class_.__name__[-4:] == "Base": + structures[class_.label].append(("child_type", "i8")) + structures[class_.label].append(("child_ID", "i8")) + else: + structures[class_.label].append(("parent_ID", "i8")) + + # Add particles to particle banks and add particle banks to the simulation + for name in bank_names: + bank = getattr(simulation, name) + size = int(bank.size[0]) + structures[name] += [ + ("particles", into_dtype(structures["particle_data"]), (size,)) + ] + # + structures["simulation"] = [(name, into_dtype(structures[name]))] + structures[ + "simulation" + ] + + # ================================================================================== + # Set records and data based on the simulation structures and objects + # ================================================================================== + + # Allocate object containers + objects = [] + + # Gather the objects from the simulation + attribute_names = [ + x + for x in dir(simulation) + if ( + not x.startswith("__") + and ( + isinstance(getattr(simulation, x), ObjectBase) + or not callable(getattr(simulation, x)) + ) + and x not in simulation.non_numba + ) + ] + for attribute_name in attribute_names: + attribute = getattr(simulation, attribute_name) + if type(attribute) in mcdc_classes: + objects.append(attribute) + if type(attribute) == list: + for item in attribute: + if type(item) in mcdc_classes: + objects.append(item) + + # Set the objects + for object_ in objects: + set_object(object_, annotations, structures, records, data) + set_object(simulation, annotations, structures, records, data) + + # Allocate the flattened data and re-set the objects + data["array"], data["pointer"] = create_data_array(data["size"], type_map[float]) + + data["size"] = 0 + records = {} + for mcdc_class in mcdc_classes: + if issubclass(mcdc_class, ObjectNonSingleton): + records[mcdc_class.label] = [] + else: + records[mcdc_class.label] = {} + records["simulation"] = records.pop("simulation") + + for object_ in objects: + set_object(object_, annotations, structures, records, data, set_data=True) + set_object(simulation, annotations, structures, records, data, set_data=True) + + # ================================================================================== + # Finalize the simulation object structure and set record + # ================================================================================== + + new_structure = [] + record = records["simulation"] + for item in simulation_object_structure: + field = item[0] + type_1 = item[1] + + # List of objects + if type_1 == list: + type_2 = item[2] + + # List of non-polymorphics + if item[2] not in polymorphic_bases: + N = len(records[item[2].label]) + new_structure.append( + (field, into_dtype(structures[item[2].label]), (N,)) + ) + new_structure.append((f"N_{plural_to_singular(field)}", "i8")) + record[f"N_{plural_to_singular(field)}"] = N + + # List of polymorphics + else: + for class_ in mcdc_classes: + if issubclass(class_, type_2): + N = len(records[class_.label]) + new_structure.append( + ( + singular_to_plural(class_.label), + into_dtype(structures[class_.label]), + (N,), + ) + ) + new_structure.append((f"N_{class_.label}", "i8")) + record[f"N_{class_.label}"] = N + + # Singleton + elif item[1] in mcdc_classes and issubclass(item[1], ObjectSingleton): + new_structure.append((field, into_dtype(structures[item[1].label]))) + + else: + print_error(f"Unknown type: {item}") + + structures["simulation"] = new_structure + structures["simulation"] + + # Print the fields + if MPI.COMM_WORLD.Get_rank() == 0: + with open(f"{Path(mcdc.__file__).parent}/object_/numba_types.py", "w") as f: + text = "# The following is automatically generated by code_factory.py\n\n" + text += "from mcdc.code_factory.code_factory import into_dtype\n\n" + + for label in structures.keys(): + text += f"{label} = into_dtype([\n" + structure = structures[label] + for item in structure: + if type(item[1]) != np.dtypes.VoidDType: + text += f" {item},\n" + else: + if len(item) == 3: + text += f" ('{item[0]}', {plural_to_singular(item[0])}, {item[2]}),\n" + else: + text += f" ('{item[0]}', {item[0]}),\n" + text += "])\n\n" + + f.write(text) + + # ================================================================================== + # Set with records + # ================================================================================== + + # The global structure/variable container + mcdc_simulation_arr, mcdc_simulation_pointer = create_mcdc_array( + into_dtype(structures["simulation"]) + ) + mcdc_simulation = mcdc_simulation_arr[0] + + record = records["simulation"] + structure = structures["simulation"] + for item in structure: + field = item[0] + field_type = item[1] + size = -1 + if len(item) == 3: + size = item[2][0] + + # Skip particular attributes + if field in bank_names: + continue + + # Simple attribute + if type(field_type) != np.dtypes.VoidDType: + mcdc_simulation[field] = record[field] + + # MC/DC objects + else: + # Singleton + if size == -1: + for sub_item in structures[field]: + mcdc_simulation[field][sub_item[0]] = records[field][sub_item[0]] + # Non-singleton + else: + singular_field = plural_to_singular(field) + for i in range(size): + for sub_item in structures[singular_field]: + mcdc_simulation[field][i][sub_item[0]] = records[ + singular_field + ][i][sub_item[0]] + + # Manually set particle bank attributes + for name in bank_names: + mcdc_simulation[name]["tag"] = getattr(simulation, name).tag + + return mcdc_simulation_arr, data["array"] + + +def set_structure(label, structures, accessor_targets, annotations): + structure = structures[label] + annotation = annotations[label] + accessor_target = accessor_targets[label] + + for field in annotation: + hint = annotation[field] + hint_origin = get_origin(hint) + hint_args = get_args(hint) + hint_origin_shape = None + hint_inner_dtype = None + fixed_size_array = False + + # Process annotation + if hint_origin is Annotated: + hint_decoded = decode_annotated_ndarray(hint) + hint_origin = hint_decoded["origin"] + hint_origin_shape = hint_decoded["shape"] + hint_inner_dtype = get_args(hint_decoded["dtype"])[0] + fixed_size_array = True + + # Mark as arbitrary size if string is used in shape + for dim_size in hint_origin_shape: + if type(dim_size) == str: + fixed_size_array = False + break + + # Skip simulation object structure + if label == "simulation": + if hint in all_classes: + continue + if hint_origin == list and hint_args[0] in all_classes: + hint_origin = np.ndarray + continue + + # ========================================================================== + # Get the type + # ========================================================================== + + # Basics + simple_scalar = hint in type_map.keys() + simple_list = hint_origin == list and hint_args[0] in type_map.keys() + numpy_array = hint_origin == np.ndarray + + # MC/DC class + non_polymorphic = ( + lambda x: issubclass(x, ObjectNonSingleton) and x not in polymorphic_bases + ) + polymorphic_base = lambda x: x in polymorphic_bases + + # List of MC/DC classes + list_of_non_polymorphics = hint_origin == list and non_polymorphic(hint_args[0]) + list_of_polymorphic_bases = hint_origin == list and polymorphic_base( + hint_args[0] + ) + + # ========================================================================== + # Set the structure + # ========================================================================== + + # Basics + if fixed_size_array: + structure.append((field, type_map[hint_inner_dtype], hint_origin_shape)) + elif simple_scalar: + structure.append((field, type_map[hint])) + elif simple_list or numpy_array: + structure.append((f"{field}_offset", "i8")) + structure.append((f"{field}_length", "i8")) + if hint_origin_shape is not None: + accessor_target.append((f"{field}", hint_origin_shape)) + else: + accessor_target.append((f"{field}", (f"{field}_length",))) + + # MC/DC classes + elif non_polymorphic(hint) or polymorphic_base(hint): + structure.append((f"{field}_ID", "i8")) + + # List of MC/DC classes + elif list_of_non_polymorphics or list_of_polymorphic_bases: + singular = plural_to_singular(field) + structure.append((f"N_{singular}", "i8")) + structure.append((f"{singular}_IDs_offset", "i8")) + if hint_origin_shape is not None: + accessor_target.append((f"{singular}_IDs", hint_origin_shape)) + else: + accessor_target.append((f"{singular}_IDs", (f"N_{singular}",))) + + # Unknown type + else: + print_error(f"Unknown type hint for {label}/{field}: {hint}") + + +def set_object( + object_, annotations, structures, records, data, class_=None, set_data=False +): + if class_ == None: + class_ = object_.__class__ + + # Set the parent first if polymorphics + if isinstance(object_, ObjectPolymorphic) and class_ not in polymorphic_bases: + for parent_class in polymorphic_bases: + if issubclass(class_, parent_class): + set_object( + object_, + annotations, + structures, + records, + data, + parent_class, + set_data, + ) + + annotation = annotations[class_.label] + structure = structures[class_.label] + record = {} + + if class_.label == "simulation": + record = records["simulation"] + + # Straightforwardly set up attributes + for key in [x[0] for x in structure]: + if key in dir(object_): + # Skip if set already + if key in record.keys(): + continue + record[key] = getattr(object_, key) + + # Loop over the supported attributes + attribute_names = [ + x for x in dir(object_) if (x[:2] != "__" and not callable(getattr(object_, x))) + ] + if "non_numba" in dir(object_): + attribute_names = list(set(attribute_names) - set(object_.non_numba)) + for attribute_name in attribute_names: + # Skip if set already + if attribute_name in record.keys(): + continue + + # Skip if not in annotation + if attribute_name not in annotation.keys(): + continue + attribute = getattr(object_, attribute_name) + + # Convert list of supported types into Numpy array + if type(attribute) == list: + if get_args(annotation[attribute_name])[0] in type_map.keys(): + attribute = np.array(attribute) + + # Numpy array + if type(attribute) == np.ndarray: + attribute_flatten = attribute.flatten() + record[f"{attribute_name}_offset"] = data["size"] + record[f"{attribute_name}_length"] = len(attribute_flatten) + if set_data: + data["array"][data["size"] : data["size"] + len(attribute_flatten)] = ( + attribute_flatten[:] + ) + data["size"] += len(attribute_flatten) + + # Non-singleton object + elif isinstance(attribute, ObjectNonSingleton): + if ( + not isinstance(attribute, ObjectPolymorphic) + or annotation[attribute_name] in polymorphic_bases + ): + record[f"{attribute_name}_ID"] = attribute.ID + else: + record[f"{attribute_name}_ID"] = attribute.child_ID + + # List of Non-singleton objects + elif type(attribute) == list: + inner_type = get_args(annotation[attribute_name])[0] + + # Flatten the list + attribute_flatten = list(flatten(attribute)) + singular_name = plural_to_singular(attribute_name) + + if not issubclass(inner_type, ObjectNonSingleton): + print_error( + f"[ERROR] Get a list of non-object for {attribute_name}: {attribute}" + ) + + record[f"N_{singular_name}"] = len(attribute_flatten) + record[f"{singular_name}_IDs_offset"] = data["size"] + if set_data: + if ( + not issubclass(inner_type, ObjectPolymorphic) + or inner_type in polymorphic_bases + ): + data["array"][ + data["size"] : data["size"] + len(attribute_flatten) + ] = [x.ID for x in attribute_flatten] + else: + data["array"][ + data["size"] : data["size"] + len(attribute_flatten) + ] = [x.child_ID for x in attribute_flatten] + data["size"] += len(attribute_flatten) + + # Complete for simulation object + if class_.label == "simulation": + return + + # Set ID of non-singleton + if isinstance(object_, ObjectNonSingleton): + if not isinstance(object_, ObjectPolymorphic): + record["ID"] = object_.ID + + # Set parent and child ID and type if polymorphic + else: + # Parent + if class_ in polymorphic_bases: + record["ID"] = object_.ID + record["child_ID"] = object_.child_ID + record["child_type"] = object_.type + # Child + else: + record["ID"] = object_.child_ID + record["parent_ID"] = object_.ID + + # Set tally bins + if class_ == TallyBase: + tally_size = np.prod(object_.bin_shape) + record[f"bin_offset"] = data["size"] + record[f"bin_sum_offset"] = data["size"] + tally_size + record[f"bin_sum_square_offset"] = data["size"] + tally_size * 2 + record[f"bin_length"] = tally_size + record[f"bin_sum_length"] = tally_size + record[f"bin_sum_square_length"] = tally_size + data["size"] += 3 * tally_size + + # Check structure-record compatibility + missing = set([x[0] for x in structure]) - set(record.keys()) + if len(missing) > 0: + print_error(f"Missing structure keys in record for {class_.label}: {missing}") + + # Register the record + if isinstance(object_, ObjectSingleton): + records[class_.label] = record + elif isinstance(object_, ObjectNonSingleton): + records[class_.label].append(record) + + +# ============================================================================= +# Global GPU/CPU Array Variable Constructors +# ============================================================================= + + +def create_data_array(size, dtype): + if config.target == "gpu": + import harmonize, numba + + if config.gpu_state_storage == "managed": + data_tally_ptr = harmonize.alloc_managed_bytes(size) + else: + data_tally_ptr = harmonize.alloc_device_bytes(size) + data_tally_uint = adapt.voidptr_to_uintp(data_tally_ptr) + data_tally = numba.carray(data_tally_ptr, (size,), dtype) + return data_tally, data_tally_uint + else: + data_tally = np.zeros(size, dtype=dtype) + return data_tally, 0 + + +def create_mcdc_array(dtype): + if config.target == "gpu": + import harmonize, numba + + if config.gpu_state_storage == "managed": + mcdc_ptr = harmonize.alloc_managed_bytes(dtype.itemsize) + else: + mcdc_ptr = harmonize.alloc_device_bytes(dtype.itemsize) + mcdc_uint = adapt.voidptr_to_uintp(mcdc_ptr) + mcdc_array = numba.carray(mcdc_ptr, (1,), dtype) + return mcdc_array, mcdc_uint + else: + mcdc_array = np.zeros((1,), dtype=dtype) + return mcdc_array, 0 + + +# ====================================================================================== +# Alignment Logic +# ====================================================================================== +# While CPU execution can robustly handle all sorts of Numba types, GPU +# execution requires structs to follow some of the basic properties expected of +# C-style structs with standard layout: +# +# - Every primitive field is aligned by its size, and padding is inserted +# between fields to ensure alignment in arrays and nested data structures +# +# - Every field has a unique address +# +# If these rules are violated, memory accesses made in GPUs may encounter +# problems. For example, in cases where an access is not at an address aligned +# by their size, a segfault or similar fault will occur, or information will be +# lost. These issues were fixed by providing a function, align, which ensures the +# field lists fed to np.dtype fulfill these requirements. +# +# The align function does the following: +# +# - Tracks the cumulative offset of fields as they appear in the input list. +# +# - Inserts additional padding fields to ensure that primitive fields are +# aligned by their size +# +# - Re-sizes arrays to have at least one element in their array (this ensure +# they have a non-zero size, and hence cannot overlap base addresses with +# other fields. +# + + +def fixup_dims(dim_tuple): + return tuple([max(d, 1) for d in dim_tuple]) + + +def align(field_list): + result = [] + offset = 0 + pad_id = 0 + for field in field_list: + if len(field) > 3: + print_error( + "Unexpected struct field specification. Specifications \ + usually only consist of 3 or fewer members" + ) + multiplier = 1 + if len(field) == 3: + field = (field[0], field[1], fixup_dims(field[2])) + for d in field[2]: + multiplier *= d + kind = np.dtype(field[1]) + size = kind.itemsize + + if kind.isbuiltin == 0: + alignment = 8 + elif kind.isbuiltin == 1: + alignment = size + else: + print_error("Unexpected field item type") + + size *= multiplier + + if offset % alignment != 0: + pad_size = alignment - (offset % alignment) + result.append((f"padding_{pad_id}", np.uint8, (pad_size,))) + pad_id += 1 + offset += pad_size + + result.append(field) + offset += size + + if offset % 8 != 0: + pad_size = 8 - (offset % 8) + result.append((f"padding_{pad_id}", np.uint8, (pad_size,))) + pad_id += 1 + + return result + + +def into_dtype(field_list): + result = np.dtype(align(field_list), align=True) + return result + + +# ====================================================================================== +# Type parser +# ====================================================================================== + +from typing import Annotated, Any, ForwardRef, Optional, Union, get_args, get_origin +import numpy as np +from numpy.typing import NDArray + + +# --- Safe locals for eval + ForwardRef fallback --- +class _FwdRefDict(dict): + """If a symbol isn't in the whitelist, treat it as a ForwardRef('Symbol').""" + + def __missing__(self, key): + for class_ in all_classes: + if key == class_.__name__: + return class_ + return ForwardRef(key) + + +_SAFE_GLOBALS = {"__builtins__": {}} # no builtins +_SAFE_LOCALS = _FwdRefDict( + { + # builtins + "str": str, + "int": int, + "float": float, + "bool": bool, + "bytes": bytes, + "object": object, + "list": list, + "dict": dict, + "tuple": tuple, + "set": set, + # typing + "Any": Any, + "Annotated": Annotated, + "Union": Union, + "Optional": Optional, + # numpy typing + "NDArray": NDArray, + # numpy dtypes (extend if you need more) + "float64": np.float64, + "float32": np.float32, + "int64": np.int64, + "int32": np.int32, + } +) + + +def parse_type_hint_str(s: str): + """ + Parse a stringified type hint into a runtime type/typing object. + Unknown identifiers become ForwardRef('Name') so we don't import/resolve. + """ + s = s.strip() + # Special-case empty or 'None' if you ever pass those + if s in {"None", "NoneType"}: + return type(None) + return eval(s, _SAFE_GLOBALS, _SAFE_LOCALS) + + +def parse_annotations_dict(ann: dict[str, str]) -> dict[str, object]: + return {k: parse_type_hint_str(v) for k, v in ann.items()} + + +def decode_annotated_ndarray(hint): + inner, metadata = get_args(hint) + inner_origin = get_origin(inner) + inner_args = get_args(inner) + shape_type, dtype_type = inner_args + return { + "origin": inner_origin, + "shape": metadata, + "shape_type": shape_type, + "dtype": dtype_type, + } + + +# ====================================================================================== +# Helpers for mcdc_get generators +# ====================================================================================== + + +def generate_mcdc_access(targets): + for object_name in targets.keys(): + path = f"{Path(mcdc.__file__).parent}" + file_getter = open(f"{path}/mcdc_get/{object_name}.py", "w") + file_setter = open(f"{path}/mcdc_set/{object_name}.py", "w") + + text_getter = ( + "# The following is automatically generated by code_factory.py\n\n" + ) + text_setter = ( + "# The following is automatically generated by code_factory.py\n\n" + ) + + text_getter += "from numba import njit\n\n\n" + text_setter += "from numba import njit\n\n\n" + + for attribute in targets[object_name]: + attribute_name = attribute[0] + shape = attribute[1] + + if len(shape) == 1: + text_getter += _accessor_1d_element(object_name, attribute_name) + text_getter += _accessor_1d_all(object_name, attribute_name, shape[0]) + text_getter += _accessor_1d_last(object_name, attribute_name, shape[0]) + + text_setter += _accessor_1d_element(object_name, attribute_name, True) + text_setter += _accessor_1d_all( + object_name, attribute_name, shape[0], True + ) + text_setter += _accessor_1d_last( + object_name, attribute_name, shape[0], True + ) + + elif len(shape) == 2: + text_getter += _accessor_2d_vector( + object_name, attribute_name, shape[1] + ) + text_getter += _accessor_2d_element( + object_name, attribute_name, shape[1] + ) + + text_setter += _accessor_2d_vector( + object_name, attribute_name, shape[1], True + ) + text_setter += _accessor_2d_element( + object_name, attribute_name, shape[1], True + ) + + elif len(shape) == 3: + text_getter += _accessor_3d_element( + object_name, attribute_name, shape[1], shape[2] + ) + + text_setter += _accessor_3d_element( + object_name, attribute_name, shape[1], shape[2], True + ) + + text_getter += _accessor_chunk(object_name, attribute_name) + text_setter += _accessor_chunk(object_name, attribute_name, True) + + file_getter.write(text_getter[:-2]) + file_setter.write(text_setter[:-2]) + + file_getter.close() + file_setter.close() + + for key in ["get", "set"]: + with open(f"{Path(mcdc.__file__).parent}/mcdc_{key}/__init__.py", "w") as f: + text = "# The following is automatically generated by code_factory.py\n\n" + for i, object_name in enumerate(targets.keys()): + text += f"import mcdc.mcdc_{key}.{object_name} as {object_name}\n" + if i < len(targets.keys()) - 1: + text += "\n" + f.write(text) + + +def _accessor_1d_element(object_name, attribute_name, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}(index, {object_name}, data, value):\n" + else: + text += f"def {attribute_name}(index, {object_name}, data):\n" + text += f' offset = {object_name}["{attribute_name}_offset"]\n' + if setter: + text += f" data[offset + index] = value\n\n\n" + else: + text += f" return data[offset + index]\n\n\n" + return text + + +def _accessor_1d_all(object_name, attribute_name, size, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}_all({object_name}, data, value):\n" + else: + text += f"def {attribute_name}_all({object_name}, data):\n" + text += f' start = {object_name}["{attribute_name}_offset"]\n' + if type(size) == str: + text += f' size = {object_name}["{size}"]\n' + else: + text += f" size = {size}\n" + text += f" end = start + size\n" + if setter: + text += f" data[start:end] = value\n\n\n" + else: + text += f" return data[start:end]\n\n\n" + return text + + +def _accessor_1d_last(object_name, attribute_name, size, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}_last({object_name}, data, value):\n" + else: + text += f"def {attribute_name}_last({object_name}, data):\n" + text += f' start = {object_name}["{attribute_name}_offset"]\n' + if type(size) == str: + text += f' size = {object_name}["{size}"]\n' + else: + text += f" size = {size}\n" + text += f" end = start + size\n" + if setter: + text += f" data[end - 1] = value\n\n\n" + else: + text += f" return data[end - 1]\n\n\n" + return text + + +def _accessor_chunk(object_name, attribute_name, setter=False): + text = f"@njit\n" + if setter: + text += ( + f"def {attribute_name}_chunk(start, length, {object_name}, data, value):\n" + ) + else: + text += f"def {attribute_name}_chunk(start, length, {object_name}, data):\n" + text += f' start += {object_name}["{attribute_name}_offset"]\n' + text += f" end = start + length\n" + if setter: + text += f" data[start:end] = value\n\n\n" + else: + text += f" return data[start:end]\n\n\n" + return text + + +def _accessor_2d_element(object_name, attribute_name, stride, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}(index_1, index_2, {object_name}, data, value):\n" + else: + text += f"def {attribute_name}(index_1, index_2, {object_name}, data):\n" + text += f' offset = {object_name}["{attribute_name}_offset"]\n' + if isinstance(stride, str): + text += f' stride = {object_name}["{stride}"]\n' + else: + text += f" stride = {stride}\n" + if setter: + text += f" data[offset + index_1 * stride + index_2] = value\n\n\n" + else: + text += f" return data[offset + index_1 * stride + index_2]\n\n\n" + return text + + +def _accessor_2d_vector(object_name, attribute_name, stride, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}_vector(index_1, {object_name}, data, value):\n" + else: + text += f"def {attribute_name}_vector(index_1, {object_name}, data):\n" + text += f' offset = {object_name}["{attribute_name}_offset"]\n' + if isinstance(stride, str): + text += f' stride = {object_name}["{stride}"]\n' + else: + text += f" stride = {stride}\n" + text += f" start = offset + index_1 * stride\n" + text += f" end = start + stride\n" + if setter: + text += f" data[start:end] - value\n\n\n" + else: + text += f" return data[start:end]\n\n\n" + return text + + +def _accessor_3d_element(object_name, attribute_name, stride_2, stride_3, setter=False): + text = f"@njit\n" + if setter: + text += f"def {attribute_name}(index_1, index_2, index_3, {object_name}, data, value):\n" + else: + text += ( + f"def {attribute_name}(index_1, index_2, index_3, {object_name}, data):\n" + ) + text += f' offset = {object_name}["{attribute_name}_offset"]\n' + text += f' stride_2 = {object_name}["{stride_2}"]\n' + text += f' stride_3 = {object_name}["{stride_3}"]\n' + if setter: + text += f" data[offset + index_1 * stride_2 * stride_3 + index_2 * stride_3 + index_3] = value\n\n\n" + else: + text += f" return data[offset + index_1 * stride_2 * stride_3 + index_2 * stride_3 + index_3]\n\n\n" + return text + + +# ====================================================================================== +# Misc. +# ====================================================================================== + + +def plural_to_singular(word: str) -> str: + """ + Convert a plural English noun (possibly underscore-separated) to singular. + Applies only to the last word and handles common irregulars. + """ + irregulars = { + "universes": "universe", + "children": "child", + "men": "man", + "women": "woman", + "people": "person", + "mice": "mouse", + "geese": "goose", + "teeth": "tooth", + "feet": "foot", + "indices": "index", + "matrices": "matrix", + "criteria": "criterion", + "data": "data", # invariant + "spectra": "spectrum", + } + + parts = word.lower().split("_") + w = parts[-1] + + if w in irregulars: + parts[-1] = irregulars[w] + elif w.endswith("ies") and len(w) > 3: + parts[-1] = w[:-3] + "y" + elif w.endswith("ves") and len(w) > 3: + parts[-1] = w[:-3] + "f" + elif w.endswith("oes"): + parts[-1] = w[:-2] + elif any(w.endswith(suffix) for suffix in ("ses", "xes", "zes", "ches", "shes")): + parts[-1] = w[:-2] + elif w.endswith("s") and not w.endswith("ss"): + parts[-1] = w[:-1] + + return "_".join(parts) + + +def singular_to_plural(word: str) -> str: + """ + Convert a singular English noun (possibly underscore-separated) to plural. + Applies only to the last word and handles common irregulars. + """ + irregulars = { + "universe": "universes", + "child": "children", + "man": "men", + "woman": "women", + "person": "people", + "mouse": "mice", + "goose": "geese", + "tooth": "teeth", + "foot": "feet", + "index": "indices", + "matrix": "matrices", + "criterion": "criteria", + "data": "data", # invariant + "spectrum": "spectra", + } + + parts = word.lower().split("_") + w = parts[-1] + + if w in irregulars: + parts[-1] = irregulars[w] + elif w.endswith("y") and w[-2:] not in ("ay", "ey", "iy", "oy", "uy"): + parts[-1] = w[:-1] + "ies" + elif w.endswith("f"): + parts[-1] = w[:-1] + "ves" + elif w.endswith("fe"): + parts[-1] = w[:-2] + "ves" + elif w.endswith(("s", "x", "z", "ch", "sh")): + parts[-1] = w + "es" + else: + parts[-1] = w + "s" + + return "_".join(parts) + + +# ============================================================================== +# MC/DC Member Array Sizes +# ============================================================================== + + +def literalize(value): + jit_str = f"@njit\ndef impl():\n return {value}\n" + exec(jit_str, globals(), locals()) + return eval("impl") + + +def rpn_buffer_size(): + pass + + +def make_size_rpn(cells): + global rpn_buffer_size + size = max([np.sum(np.array(x.region_RPN_tokens) >= 0.0) for x in cells]) + rpn_buffer_size = literalize(size) + + +# ====================================================================================== +# Make literals +# ====================================================================================== + + +def make_literals(simulation): + # Sizes + rpn_evaluation_buffer_size = int( + max([np.sum(np.array(x.region_RPN_tokens) >= 0.0) for x in simulation.cells]) + ) + + path = f"{Path(mcdc.__file__).parent}" + with open(f"{path}/transport/literals.py", "w") as f: + text = "# The following is automatically generated by code_factory.py\n\n" + + text += f"rpn_evaluation_buffer_size = {rpn_evaluation_buffer_size}\n" + + f.write(text) diff --git a/mcdc/config.py b/mcdc/config.py index 046373dbd..a96fe4b81 100644 --- a/mcdc/config.py +++ b/mcdc/config.py @@ -1,8 +1,11 @@ -import argparse, os, sys -import importlib.metadata +import argparse, os -# Parse command-line arguments parser = argparse.ArgumentParser(description="MC/DC: Monte Carlo Dynamic Code") + +# ====================================================================================== +# Run mode +# ====================================================================================== + parser.add_argument( "--mode", type=str, @@ -15,6 +18,30 @@ "--target", type=str, help="Target", choices=["cpu", "gpu"], default="cpu" ) +# ====================================================================================== +# Settings +# ====================================================================================== + +parser.add_argument("--N_particle", type=int, help="Number of particles") +parser.add_argument("--N_batch", type=int, help="Number of batches") +parser.add_argument("--output", type=str, help="Output file name") +parser.add_argument("--progress_bar", default=True, action="store_true") +parser.add_argument("--no-progress_bar", dest="progress_bar", action="store_false") +parser.add_argument("--runtime_output", default=False, action="store_true") + + +# ====================================================================================== +# Numba +# ====================================================================================== + +parser.add_argument("--clear_cache", action="store_true") +parser.add_argument("--caching", action="store_true", default=False) +parser.add_argument("--no_caching", dest="caching", action="store_false") + +# ====================================================================================== +# GPU mode +# ====================================================================================== + parser.add_argument( "--gpu_state_storage", type=str, @@ -67,17 +94,11 @@ ) -parser.add_argument("--N_particle", type=int, help="Number of particles") -parser.add_argument("--output", type=str, help="Output file name") -parser.add_argument("--progress_bar", default=True, action="store_true") -parser.add_argument("--no-progress_bar", dest="progress_bar", action="store_false") -parser.add_argument("--clear_cache", action="store_true") -parser.add_argument("--caching", action="store_true") -parser.add_argument("--no_caching", dest="caching", action="store_false") -parser.add_argument("--runtime_output", default=False, action="store_true") -parser.set_defaults(caching=False) -args, unargs = parser.parse_known_args() +# ====================================================================================== +# Config processor +# ====================================================================================== +args, unargs = parser.parse_known_args() mode = args.mode target = args.target @@ -100,15 +121,8 @@ if MPI.COMM_WORLD.Get_size() > 1: MPI.COMM_WORLD.Barrier() - -from mcdc.card import UniverseCard from mcdc.print_ import ( - print_banner, - print_msg, - print_runtime, - print_header_eigenvalue, print_warning, - print_error, ) import numba as nb diff --git a/mcdc/constant.py b/mcdc/constant.py index 1667f65cd..695ee4a5c 100644 --- a/mcdc/constant.py +++ b/mcdc/constant.py @@ -1,32 +1,35 @@ import math -import numpy as np -import numba as nb - # Data index TALLY = 0 -# Tally bins -TALLY_SCORE = 0 -TALLY_SUM = 1 -TALLY_SUM_SQ = 2 -TALLY_UQ_BATCH = 3 -TALLY_UQ_BATCH_VAR = 4 +# Tallies +TALLY_GLOBAL = 0 +TALLY_CELL = 1 +TALLY_SURFACE = 2 +TALLY_MESH = 3 + +# Meshes +MESH_UNIFORM = 0 +MESH_STRUCTURED = 1 # Tally scores SCORE_FLUX = 0 SCORE_DENSITY = 1 -SCORE_TOTAL = 2 -SCORE_FISSION = 3 -SCORE_NET_CURRENT = 4 -SCORE_MU_SQ = 5 -SCORE_TIME_MOMENT_FLUX = 6 -SCORE_SPACE_MOMENT_FLUX = 7 -SCORE_TIME_MOMENT_CURRENT = 8 -SCORE_SPACE_MOMENT_CURRENT = 9 -SCORE_TIME_MOMENT_MU_SQ = 10 -SCORE_SPACE_MOMENT_MU_SQ = 11 - +SCORE_COLLISION = 2 +SCORE_CAPTURE = 3 +SCORE_FISSION = 4 +SCORE_NET_CURRENT = 5 +SCORE_MU_SQ = 6 +SCORE_TIME_MOMENT_FLUX = 7 +SCORE_SPACE_MOMENT_FLUX = 8 +SCORE_TIME_MOMENT_CURRENT = 9 +SCORE_SPACE_MOMENT_CURRENT = 10 +SCORE_TIME_MOMENT_MU_SQ = 11 +SCORE_SPACE_MOMENT_MU_SQ = 12 + +# Tally multipliers +MULTIPLIER_ENERGY = 0 # Boundary condition BC_NONE = 0 @@ -37,6 +40,7 @@ FILL_MATERIAL = 0 FILL_UNIVERSE = 1 FILL_LATTICE = 2 +FILL_NONE = 3 # Region REGION_HALFSPACE = 0 @@ -46,17 +50,15 @@ REGION_ALL = 4 # Surface type -SURFACE_LINEAR = 1 << 1 -SURFACE_QUADRATIC = 1 << 2 -SURFACE_PLANE_X = 1 << 3 -SURFACE_PLANE_Y = 1 << 4 -SURFACE_PLANE_Z = 1 << 5 -SURFACE_PLANE = 1 << 6 -SURFACE_CYLINDER_X = 1 << 7 -SURFACE_CYLINDER_Y = 1 << 8 -SURFACE_CYLINDER_Z = 1 << 9 -SURFACE_SPHERE = 1 << 10 -SURFACE_QUADRIC = 1 << 11 +SURFACE_PLANE_X = 0 +SURFACE_PLANE_Y = 2 +SURFACE_PLANE_Z = 3 +SURFACE_PLANE = 4 +SURFACE_CYLINDER_X = 5 +SURFACE_CYLINDER_Y = 6 +SURFACE_CYLINDER_Z = 7 +SURFACE_SPHERE = 8 +SURFACE_QUADRIC = 9 # Boolean operator BOOL_AND = -1 @@ -67,22 +69,65 @@ UNIVERSE_ROOT = 0 # Events -# The << operator represents a bitshift. Each event is assigned 1 << X, which is equal to 2 to the power of X. +# The << operator represents a bitshift. +# Each event is assigned 1 << X, which is equal to 2 to the power of X. EVENT_NONE = 1 << 0 # Geometry events EVENT_SURFACE_CROSSING = 1 << 1 EVENT_LATTICE_CROSSING = 1 << 2 -EVENT_DOMAIN_CROSSING = 1 << 3 -EVENT_LOST = 1 << 4 +EVENT_LOST = 1 << 3 # Collision/reaction events -EVENT_COLLISION = 1 << 5 -EVENT_SCATTERING = 1 << 6 -EVENT_FISSION = 1 << 7 -EVENT_CAPTURE = 1 << 8 +EVENT_COLLISION = 1 << 4 # Miscellanies -EVENT_TIME_CENSUS = 1 << 9 -EVENT_TIME_BOUNDARY = 1 << 10 -EVENT_IQMC_MESH = 1 << 11 +EVENT_TIME_CENSUS = 1 << 5 +EVENT_TIME_BOUNDARY = 1 << 6 + +# Materials +MATERIAL = 0 +MATERIAL_MG = 1 +MATERIAL_ELEMENTAL = 2 + +# Reactions +REACTION_TOTAL = 0 +REACTION_NEUTRON_ELASTIC_SCATTERING = 1 +REACTION_NEUTRON_CAPTURE = 2 +REACTION_NEUTRON_INELASTIC_SCATTERING = 3 +REACTION_NEUTRON_FISSION = 4 +REACTION_NEUTRON_FISSION_PROMPT = 5 +REACTION_NEUTRON_FISSION_DELAYED = 6 + +# Particle types +PARTICLE_NEUTRON = 0 + +# Data +DATA_NONE = 0 +DATA_TABLE = 1 +DATA_POLYNOMIAL = 2 + +# Distribution +DISTRIBUTION_NONE = 0 +DISTRIBUTION_PMF = 1 +DISTRIBUTION_TABULATED = 2 +DISTRIBUTION_MULTITABLE = 3 +DISTRIBUTION_LEVEL_SCATTERING = 4 +DISTRIBUTION_EVAPORATION = 5 +DISTRIBUTION_MAXWELLIAN = 6 +DISTRIBUTION_KALBACH_MANN = 7 +DISTRIBUTION_TABULATED_ENERGY_ANGLE = 8 +DISTRIBUTION_N_BODY = 9 + +# Anguler distribution type +ANGLE_ISOTROPIC = 0 +ANGLE_DISTRIBUTED = 1 +ANGLE_ENERGY_CORRELATED = 2 + +# Referance frame +REFERENCE_FRAME_LAB = 0 +REFERENCE_FRAME_COM = 1 + +# Interpolation law +INTERPOLATION_LINEAR = 2 +INTERPOLATION_LOG = 5 # Gyration raius type GYRATION_RADIUS_ALL = 0 @@ -102,56 +147,27 @@ # Misc. TINY = 1e-10 -COINCIDENCE_TOLERANCE = TINY * 1e1 +COINCIDENCE_TOLERANCE = TINY +COINCIDENCE_TOLERANCE_DIRECTION = 1e-5 +COINCIDENCE_TOLERANCE_ENERGY = 1e-5 COINCIDENCE_TOLERANCE_TIME = TINY * 1e-2 INF = 1e10 -PI = math.acos(-1.0) +PI = math.pi PI_SQRT = math.sqrt(PI) PI_HALF = PI / 2.0 BANKMAX = 100 # Default maximum active bank -# Mesh crossing flags -MESH_X = 0 -MESH_Y = 1 -MESH_Z = 2 -MESH_T = 3 -MESH_NONE = 0 - -# RNG LCG parameters -RNG_G = nb.uint64(2806196910506780709) -RNG_C = nb.uint64(1) -RNG_MOD_MASK = nb.uint64(0x7FFFFFFFFFFFFFFF) -RNG_MOD = nb.uint64(0x8000000000000000) - -# RNG splitter seeds -SEED_SPLIT_CENSUS = nb.uint64(0x43454D654E54) -SEED_SPLIT_SOURCE = nb.uint64(0x43616D696C6C65) -SEED_SPLIT_SOURCE_PRECURSOR = nb.uint64(0x546F6464) -SEED_SPLIT_BANK = nb.uint64(0x5279616E) -SEED_SPLIT_PARTICLE = nb.uint64(0) -SEED_SPLIT_UQ = nb.uint64(0x5368656261) +# Axes +AXIS_X = 0 +AXIS_Y = 1 +AXIS_Z = 2 +AXIS_T = 3 # Physics -NEUTRON_MASS = 1.67492749804e-27 # kg -EV_TO_J = 1.6022e-19 -SQRT_E_TO_SPEED = math.sqrt(2.0 * EV_TO_J / NEUTRON_MASS) * 100 +LIGHT_SPEED = 2.99792458e10 # cm/s +NEUTRON_MASS = 939.565413e6 # eV/c^2 BOLTZMANN_K = 8.61733326e-5 # eV/K -T_ROOM = 294 # K -E_THERMAL_THRESHOLD = 400 * BOLTZMANN_K * T_ROOM - -# Cross Section Type -XS_TOTAL = 0 -XS_SCATTER = 1 -XS_CAPTURE = 2 -XS_FISSION = 3 -XS_NU_FISSION = 4 -XS_NU_FISSION_PROMPT = 5 -XS_NU_FISSION_DELAYED = 6 -XS_NU_SCATTER = 7 - -NU_FISSION = 0 -NU_FISSION_PROMPT = 1 -NU_FISSION_DELAYED = 2 +THERMAL_THRESHOLD_FACTOR = 400 # Weight Windows Methods WW_USER = 0 diff --git a/mcdc/global_.py b/mcdc/global_.py deleted file mode 100644 index 64895cca7..000000000 --- a/mcdc/global_.py +++ /dev/null @@ -1,166 +0,0 @@ -import numpy as np - -from mcdc.constant import INF, GYRATION_RADIUS_ALL, PI - - -# ====================================================================================== -# Input Deck -# ====================================================================================== - - -def make_card_mesh(): - return { - "x": np.array([-INF, INF]), - "y": np.array([-INF, INF]), - "z": np.array([-INF, INF]), - "t": np.array([-INF, INF]), - "mu": np.array([-1.0, 1.0]), - "azi": np.array([-PI, PI]), - "g": np.array([-INF, INF]), - } - - -class InputDeck: - def __init__(self): - self.reset() - - def reset(self): - self.nuclides = [] - self.materials = [] - self.surfaces = [] - self.regions = [] - self.cells = [] - self.universes = [None] # Placeholder for the root universe - self.lattices = [] - self.sources = [] - self.mesh_tallies = [] - self.surface_tallies = [] - self.cell_tallies = [] - self.cs_tallies = [] - - self.setting = { - "tag": "Setting", - "mode_MG": True, - "mode_CE": False, - "N_particle": 0, - "N_batch": 1, - "rng_seed": 1, - "time_boundary": INF, - "progress_bar": True, - "output_name": "output", - "save_input_deck": True, - "mode_eigenvalue": False, - "k_init": 1.0, - "N_inactive": 0, - "N_active": 0, - "N_cycle": 0, - "save_particle": False, - "gyration_radius": False, - "gyration_radius_type": GYRATION_RADIUS_ALL, - "N_census": 1, - "census_time": np.array([INF]), - "census_based_tally": False, - "census_tally_frequency": 0, - "source_file": False, - "source_file_name": "", - "IC_file": False, - "IC_file_name": "", - "N_precursor": 0, - # Below are parameters not copied to mcdc.setting - "bank_active_buff": 100, - "bank_census_buff": 1.0, - "bank_source_buff": 1.0, - "bank_future_buff": 0.5, - # Portability - "target": "cpu", - } - - self.technique = { - "tag": "Technique", - "weighted_emission": True, - "implicit_capture": False, - "population_control": False, - "pct": "none", - "pc_factor": 1.0, - "weight_window": False, - "ww": { - "center": np.ones([1, 1, 1, 1]), - "width": 2.5, - "mesh": make_card_mesh(), - "auto": 0, - "epsilon": np.zeros(3), - "save": False, - "tally_idx": 0, - }, - "domain_decomposition": False, - "dd_idx": 0, - "dd_local_rank": 0, - "dd_mesh": make_card_mesh(), - "dd_exchange_rate": 0, - "dd_exchange_rate_padding": 0, - "dd_work_ratio": np.array([1]), - "weight_roulette": False, - "wr_threshold": 0.0, - "wr_survive": 1.0, - "iQMC": False, - "iqmc": { - "sample_method": "halton", - "mode": "fixed", - "fixed_source_solver": "source iteration", - "krylov_restart": 5, - "krylov_vector_size": 1, - "tol": 1e-6, - "residual": 1.0, - "iteration_count": 0, - "iterations_max": 5, - "fixed_source": np.ones([1, 1, 1, 1, 1]), - "material_idx": np.ones([1, 1, 1, 1]), - "source": np.ones([1, 1, 1, 1, 1]), - "score": { - "flux": np.ones([1, 1, 1, 1]), - "source-x": np.zeros([1, 1, 1, 1]), - "source-y": np.zeros([1, 1, 1, 1]), - "source-z": np.zeros([1, 1, 1, 1]), - "fission-source": np.zeros([1, 1, 1, 1]), - }, - "score_list": { - "flux": True, - "effective-scattering": True, - "effective-fission": True, - "source-x": False, - "source-y": False, - "source-z": False, - "fission-power": False, - "fission-source": False, - }, - "mesh": { - "g": np.array([-INF, INF]), - "t": np.array([-INF, INF]), - "x": np.array([-INF, INF]), - "y": np.array([-INF, INF]), - "z": np.array([-INF, INF]), - "mu": np.array([-1.0, 1.0]), - "azi": np.array([-PI, PI]), - }, - }, - "IC_generator": False, - "IC_N_neutron": 0, - "IC_N_precursor": 0, - "IC_neutron_density": 0.0, - "IC_precursor_density": 0.0, - "IC_neutron_density_max": 0.0, - "IC_precursor_density_max": 0.0, - "IC_cycle_stretch": 1.0, - "branchless_collision": False, - "uq": False, - } - - self.uq_deltas = { - "tag": "Uq", - "nuclides": [], - "materials": [], - "surfaces": [], - } - - -input_deck = InputDeck() diff --git a/mcdc/input_.py b/mcdc/input_.py deleted file mode 100644 index fa29af356..000000000 --- a/mcdc/input_.py +++ /dev/null @@ -1,1944 +0,0 @@ -""" -This module contains functions for setting MC/DC input deck. -Docstrings use NumPy formatting. -""" - -# Instantiate and get the global variable container -import mcdc.global_ as global_ - -import h5py, math, mpi4py, os -import numpy as np -import scipy as sp - -from pathlib import Path - -from mcdc.card import ( - NuclideCard, - MaterialCard, - RegionCard, - SurfaceCard, - CellCard, - UniverseCard, - LatticeCard, - SourceCard, - MeshTallyCard, -) -from mcdc.constant import ( - GYRATION_RADIUS_ALL, - GYRATION_RADIUS_INFINITE_X, - GYRATION_RADIUS_INFINITE_Y, - GYRATION_RADIUS_INFINITE_Z, - GYRATION_RADIUS_ONLY_X, - GYRATION_RADIUS_ONLY_Y, - GYRATION_RADIUS_ONLY_Z, - INF, - PCT_NONE, - PCT_COMBING, - PCT_COMBING_WEIGHT, - PCT_SPLITTING_ROULETTE, - PCT_SPLITTING_ROULETTE_WEIGHT, - PI, - REGION_ALL, - TINY, - WW_MIN, - WW_PREVIOUS, - WW_USER, - WW_WOLLABER, -) -from mcdc.print_ import print_error -import mcdc.type_ as type_ - - -def nuclide( - capture=None, - scatter=None, - fission=None, - nu_s=None, - nu_p=None, - nu_d=None, - chi_p=None, - chi_d=None, - speed=None, - decay=None, -): - """ - Create a nuclide - - Parameters - ---------- - capture : numpy.ndarray (1D), optional - Capture microscopic cross-section [barn]. - scatter : numpy.ndarray (2D), optional - Differential scattering microscopic cross-section [gout, gin] [barn]. - fission : numpy.ndarray (1D), optional - Fission microscopic cross-section [barn]. - nu_s : numpy.ndarray (1D), optional - Scattering multiplication. - nu_p : numpy.ndarray (1D), optional - Prompt fission neutron yield. - nu_d : numpy.ndarray (2D), optional - Delayed neutron precursor yield [dg, gin]. - chi_p : numpy.ndarray (2D), optional - Prompt fission spectrum [gout, gin]. - chi_d : numpy.ndarray (2D), optional - Delayed neutron spectrum [gout, dg]. - speed : numpy.ndarray (1D), optional - Energy group speed [cm/s]. - decay : numpy.ndarray (1D), optional - Precursor group decay constant [/s]. - - Returns - ------- - NuclideCard - The nuclide - - Notes - ----- - Parameters are set to zeros by default. Energy group size G is determined by the - size of `capture`, `scatter`, or `fission`. Thus, at least `capture`, `scatter`, - or `fission` needs to be provided. `nu_p` or `nu_d` is needed if `fission` is - provided. `chi_p` and `chi_d` are needed if `nu_p` and `nu_d` are provided, - respectively, and G > 1. Delayed neutron precursor group size J is determined by - the size of `nu_d`; if `nu_d` is not given, J = 0. - - See also - -------- - mcdc.material : A material can be defined as a collection of nuclides. - """ - # Energy group size - if capture is not None: - G = len(capture) - elif scatter is not None: - G = len(scatter) - elif fission is not None: - G = len(fission) - else: - print_error("Need to supply capture, scatter, or fission to mcdc.nuclide") - - # Delayed group size - J = 0 - if nu_d is not None: - J = len(nu_d) - - # Make nuclide card - card = NuclideCard(G, J) - - # Set ID - card.ID = len(global_.input_deck.nuclides) - - # Speed (vector of size G) - if speed is not None: - card.speed[:] = speed[:] - - # Decay constant (vector of size J) - if decay is not None: - card.decay[:] = decay[:] - - # Cross-sections (vector of size G) - if capture is not None: - card.capture[:] = capture[:] - if scatter is not None: - card.scatter[:] = np.sum(scatter, 0)[:] - if fission is not None: - card.fission[:] = fission[:] - card.fissionable = True - card.total[:] = card.capture + card.scatter + card.fission - - # Scattering multiplication (vector of size G) - if nu_s is not None: - card.nu_s[:] = nu_s[:] - - # Check if nu_p or nu_d is not provided, give fission - if fission is not None: - if nu_p is None and nu_d is None: - print_error("Need to supply nu_p or nu_d for fissionable mcdc.nuclide") - - # Prompt fission production (vector of size G) - if nu_p is not None: - card.nu_p[:] = nu_p[:] - - # Delayed fission production (matrix of size GxJ) - if nu_d is not None: - # Transpose: [dg, gin] -> [gin, dg] - card.nu_d[:, :] = np.swapaxes(nu_d, 0, 1)[:, :] - - # Total fission production (vector of size G) - card.nu_f += card.nu_p - for j in range(J): - card.nu_f += card.nu_d[:, j] - - # Scattering spectrum (matrix of size GxG) - if scatter is not None: - # Transpose: [gout, gin] -> [gin, gout] - card.chi_s[:, :] = np.swapaxes(scatter, 0, 1)[:, :] - for g in range(G): - if card.scatter[g] > 0.0: - card.chi_s[g, :] /= card.scatter[g] - - # Prompt fission spectrum (matrix of size GxG) - if nu_p is not None: - if G == 1: - card.chi_p[:, :] = np.array([[1.0]]) - elif chi_p is None: - print_error("Need to supply chi_p if nu_p is provided and G > 1") - else: - # Convert 1D spectrum to 2D - if chi_p.ndim == 1: - tmp = np.zeros((G, G)) - for g in range(G): - tmp[:, g] = chi_p - chi_p = tmp - # Transpose: [gout, gin] -> [gin, gout] - card.chi_p[:, :] = np.swapaxes(chi_p, 0, 1)[:, :] - # Normalize - for g in range(G): - if np.sum(card.chi_p[g, :]) > 0.0: - card.chi_p[g, :] /= np.sum(card.chi_p[g, :]) - - # Delayed fission spectrum (matrix of size JxG) - if nu_d is not None: - if G == 1: - card.chi_d[:, :] = np.ones([J, G]) - else: - if chi_d is None: - print_error("Need to supply chi_d if nu_d is provided and G > 1") - # Transpose: [gout, dg] -> [dg, gout] - card.chi_d[:, :] = np.swapaxes(chi_d, 0, 1)[:, :] - # Normalize - for dg in range(J): - if np.sum(card.chi_d[dg, :]) > 0.0: - card.chi_d[dg, :] /= np.sum(card.chi_d[dg, :]) - - # Add to deck - global_.input_deck.nuclides.append(card) - - return card - - -def material( - nuclides=None, - capture=None, - scatter=None, - fission=None, - nu_s=None, - nu_p=None, - nu_d=None, - chi_p=None, - chi_d=None, - speed=None, - decay=None, -): - """ - Create a material - - A material is defined either as a collection of nuclides or directly by its - macroscopic constants. - - Parameters - ---------- - nuclides : list of tuple of (dictionary, float), optional - List of pairs of nuclide card and its density [/barn-cm]. - capture : numpy.ndarray (1D), optional - Capture macroscopic cross-section [/cm]. - scatter : numpy.ndarray (2D), optional - Differential scattering macroscopic cross-section [gout, gin] [/cm]. - fission : numpy.ndarray (1D), optional - Fission macroscopic cross-section [/cm]. - nu_s : numpy.ndarray (1D), optional - Scattering multiplication. - nu_p : numpy.ndarray (1D), optional - Prompt fission neutron yield. - nu_d : numpy.ndarray (2D), optional - Delayed neutron precursor yield [dg, gin]. - chi_p : numpy.ndarray (2D), optional - Prompt fission spectrum [gout, gin]. - chi_d : numpy.ndarray (2D), optional - Delayed neutron spectrum [gout, dg]. - speed : numpy.ndarray (1D), optional - Energy group speed [cm/s]. - decay : numpy.ndarray (1D), optional - Precursor group decay constant [/s]. - - Returns - ------- - MaterialCard - The material - - See also - -------- - mcdc.nuclide : A material can be defined as a collection of nuclides. - """ - # If nuclides are not given, and macroscopic constants are given instead, - # create a nuclide card and set a single-nuclide material - if nuclides is None: - card_nuclide = nuclide( - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ) - nuclides = [[card_nuclide, 1.0]] - - # Number of nuclides - N_nuclide = len(nuclides) - - # Continuous energy mode? - if isinstance(nuclides[0][0], str): - global_.input_deck.setting["mode_CE"] = True - global_.input_deck.setting["mode_MG"] = False - - # Make material card - card = MaterialCard(N_nuclide) - - # Set ID - card.ID = len(global_.input_deck.materials) - - # Default values - card.J = 6 - - # Set the nuclides - for i in range(N_nuclide): - nuc_name = nuclides[i][0] - density = nuclides[i][1] - - # Create nuclide card if not defined yet - if not nuclide_registered(nuc_name): - nuc_card = NuclideCard() - nuc_card.name = nuc_name - - # Set ID - nuc_card.ID = len(global_.input_deck.nuclides) - - # Default values - nuc_card.J = 6 - - # Check if the nuclide is available in the nuclear data library - dir_name = os.getenv("MCDC_XSLIB") - if dir_name == None: - print_error( - "Continuous energy data directory not configured \n " - "see https://cement-psaapgithubio.readthedocs.io/en/latest" - "/install.html#configuring-continuous-energy-library \n" - ) - - # Fissionable flag - lib_file_name = dir_name + "/" + nuc_name + ".h5" - if not Path(lib_file_name).is_file(): - print_error(f"Nuclide data not found: {nuc_name}") - with h5py.File(lib_file_name, "r") as f: - if max(f["fission"][:]) > 0.0: - nuc_card.fissionable = True - card.fissionable = True - - # Add to deck - global_.input_deck.nuclides.append(nuc_card) - else: - nuc_card = get_nuclide(nuc_name) - - card.nuclide_IDs[i] = nuc_card.ID - card.nuclide_densities[i] = density - - # Check if there is a material with identical composition already - if global_.input_deck.setting["mode_CE"]: - for card_registered in global_.input_deck.materials: - identical = True - for i in range(len(card_registered.nuclide_IDs)): - if not card_registered.nuclide_IDs[i] == card.nuclide_IDs[i]: - identical = False - break - if ( - not card_registered.nuclide_densities[i] - == card.nuclide_densities[i] - ): - identical = False - break - - if identical: - return card_registered - - # Add to deck - global_.input_deck.materials.append(card) - return card - - # Nuclide and group sizes - G = nuclides[0][0].G - J = nuclides[0][0].J - - # Make material card - card = MaterialCard(N_nuclide, G, J) - - # Set ID - card.ID = len(global_.input_deck.materials) - - # Calculate basic XS - for i in range(N_nuclide): - nuc = nuclides[i][0] - density = nuclides[i][1] - card.nuclide_IDs[i] = nuc.ID - card.nuclide_densities[i] = density - - card.capture += nuc.capture * density - card.scatter += nuc.scatter * density - card.fission += nuc.fission * density - card.total += nuc.total * density - - # Calculate effective speed - # Current approach: weighted by nuclide macroscopic total cross section - # TODO: other more appropriate way? - for i in range(N_nuclide): - nuc = nuclides[i][0] - density = nuclides[i][1] - card.speed += nuc.speed * nuc.total * density - # If vacuum material, just pick the last nuclide - if max(card.total) == 0.0: - card.speed[:] = nuc.speed - else: - card.speed /= card.total - - # Calculate effective spectra and multiplicities of scattering and prompt fission - if max(card.scatter) > 0.0: - nuSigmaS = np.zeros((G, G), dtype=float) - for i in range(N_nuclide): - nuc = nuclides[i][0] - density = nuclides[i][1] - SigmaS = np.diag(nuc.scatter) * density - nu_s = np.diag(nuc.nu_s) - chi_s = np.transpose(nuc.chi_s) - nuSigmaS += chi_s.dot(nu_s.dot(SigmaS)) - chi_nu_s = nuSigmaS.dot(np.diag(1.0 / card.scatter)) - card.nu_s = np.sum(chi_nu_s, axis=0) - card.chi_s = np.transpose(chi_nu_s.dot(np.diag(1.0 / card.nu_s))) - if max(card.fission) > 0.0: - nuSigmaF = np.zeros((G, G), dtype=float) - for i in range(N_nuclide): - nuc = nuclides[i][0] - density = nuclides[i][1] - SigmaF = np.diag(nuc.fission) * density - nu_p = np.diag(nuc.nu_p) - chi_p = np.transpose(nuc.chi_p) - nuSigmaF += chi_p.dot(nu_p.dot(SigmaF)) - chi_nu_p = nuSigmaF.dot(np.diag(1.0 / card.fission)) - card.nu_p = np.sum(chi_nu_p, axis=0) - card.chi_p = np.transpose(chi_nu_p.dot(np.diag(1.0 / card.nu_p))) - - # Calculate delayed and total fission multiplicities - if max(card.fission) > 0.0: - card.nu_f[:] = card.nu_p[:] - for j in range(J): - total = np.zeros(G) - for i in range(N_nuclide): - nuc = nuclides[i][0] - density = nuclides[i][1] - total += nuc.nu_d[:, j] * nuc.fission * density - card.nu_d[:, j] = total / card.fission - card.nu_f += card.nu_d[:, j] - - # Add to deck - global_.input_deck.materials.append(card) - - return card - - -def surface(type_, bc="interface", **kw): - """ - Create a surface to define the region of a cell. - - Parameters - ---------- - type\_ : {"plane-x", "plane-y", "plane-z", "plane", "cylinder-x", "cylinder-y", - "cylinder-z", "sphere", "quadric"} - Surface type. - bc : {"interface", "vacuum", "reflective"} - Surface boundary condition. - - Other Parameters - ---------------- - x : {float, array_like[float]} - x-position [cm] for `"plane-x"`. - y : {float, array_like[float]} - y-position [cm] for `"plane-y"`. - z : {float, array_like[float]} - z-position [cm] for `"plane-z"`. - center : array_like[float] - Center point [cm] for `"cylinder-x"` (y,z), `"cylinder-y"` (x,z), - `"cylinder-z"` (x,y), or `"sphere"` (x,y,z). - radius : float - Radius [cm] for `"cylinder-x"`, `"cylinder-y"`, `"cylinder-z"`, and `"sphere"`. - A, B, C, D : float - Coefficients [cm] for `"plane"`. - A, B, C, D, E, F, G, H, I, J : float - Coefficients [cm] for `"quadric"`. - - Returns - ------- - SurfaceCard - The surface card - - See also - -------- - mcdc.cell : Create a cell whose region is defined by surfaces. - """ - # Make surface card - card = SurfaceCard() - - # Set ID - card.ID = len(global_.input_deck.surfaces) - - # Check if the selected type is supported - type_ = check_support( - "surface type", - type_, - [ - "plane-x", - "plane-y", - "plane-z", - "plane", - "cylinder-x", - "cylinder-y", - "cylinder-z", - "sphere", - "quadric", - ], - ) - card.type = type_ - - # Boundary condition - bc = check_support( - "surface boundary condition", - bc, - [ - "interface", - "vacuum", - "reflective", - ], - ) - card.boundary_type = bc - - # ========================================================================== - # Surface attributes - # ========================================================================== - # Axx + Byy + Czz + Dxy + Exz + Fyz + Gx + Hy + Iz + J = 0 - - card.type = type_ - - # Set up surface attributes - if type_ == "plane-x": - check_requirement("surface plane-x", kw, ["x"]) - card.G = 1.0 - card.J = -kw.get("x") - card.linear = True - elif type_ == "plane-y": - check_requirement("surface plane-y", kw, ["y"]) - card.H = 1.0 - card.J = -kw.get("y") - card.linear = True - elif type_ == "plane-z": - check_requirement("surface plane-z", kw, ["z"]) - card.I = 1.0 - card.J = -kw.get("z") - card.linear = True - elif type_ == "plane": - check_requirement("surface plane", kw, ["A", "B", "C", "D"]) - card.G = kw.get("A") - card.H = kw.get("B") - card.I = kw.get("C") - card.J = kw.get("D") - card.linear = True - elif type_ == "cylinder-x": - check_requirement("surface cylinder-x", kw, ["center", "radius"]) - y, z = kw.get("center")[:] - r = kw.get("radius") - card.B = 1.0 - card.C = 1.0 - card.H = -2.0 * y - card.I = -2.0 * z - card.J = y**2 + z**2 - r**2 - elif type_ == "cylinder-y": - check_requirement("surface cylinder-y", kw, ["center", "radius"]) - x, z = kw.get("center")[:] - r = kw.get("radius") - card.A = 1.0 - card.C = 1.0 - card.G = -2.0 * x - card.I = -2.0 * z - card.J = x**2 + z**2 - r**2 - elif type_ == "cylinder-z": - check_requirement("surface cylinder-z", kw, ["center", "radius"]) - x, y = kw.get("center")[:] - r = kw.get("radius") - card.A = 1.0 - card.B = 1.0 - card.G = -2.0 * x - card.H = -2.0 * y - card.J = x**2 + y**2 - r**2 - elif type_ == "sphere": - check_requirement("surface sphere", kw, ["center", "radius"]) - x, y, z = kw.get("center")[:] - r = kw.get("radius") - card.A = 1.0 - card.B = 1.0 - card.C = 1.0 - card.G = -2.0 * x - card.H = -2.0 * y - card.I = -2.0 * z - card.J = x**2 + y**2 + z**2 - r**2 - elif type_ == "quadric": - check_requirement( - "surface quadric", kw, ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] - ) - card.A = kw.get("A") - card.B = kw.get("B") - card.C = kw.get("C") - card.D = kw.get("D") - card.E = kw.get("E") - card.F = kw.get("F") - card.G = kw.get("G") - card.H = kw.get("H") - card.I = kw.get("I") - card.J = kw.get("J") - - # Normalize linear surfaces - if card.linear: - G = card.G - H = card.H - I = card.I - norm = (G**2 + H**2 + I**2) ** 0.5 - card.G /= norm - card.H /= norm - card.I /= norm - card.J /= norm - card.nx = card.G - card.ny = card.H - card.nz = card.I - - # Add to deck - global_.input_deck.surfaces.append(card) - - return card - - -def cell(region=None, fill=None, translation=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0)): - """ - Create a cell as model building block. - - Parameters - ---------- - region : RegionCard - Region that defines the cell geometry. - fill : MaterialCard or UniverseCard or LatticeCard - Material/universe/lattice that fills the cell. - translation : array_like[float], optional - To translate the origin of the fill (if universe or lattice). - rotation : array_like[float], optional - To rotate the the fill (if universe or lattice). - - Returns - ------- - CellCard - The cell card. - - See also - -------- - mcdc.surface : Create a surface to define the region of a cell. - mcdc.material : Create a material to fill a cell. - mcdc.universe : Create a universe to fill a cell. - mcdc.lattice : Create a lattice to fill a cell. - """ - - # Make cell card - card = CellCard() - - # Set ID - card.ID = len(global_.input_deck.cells) - - # If region is not assigned, create a region that encompass all - if region is None: - region = RegionCard("all") - region.ID = len(global_.input_deck.regions) - global_.input_deck.regions.append(region) - - # Assign region - card.region_ID = region.ID - - # Set region Reverse Polish Notation and region description - if region.type != "all": - card.set_region_RPN() - card.set_region() - - # Assign fill type and ID - if fill.tag == "Material": - card.fill_type = "material" - elif fill.tag == "Universe": - card.fill_type = "universe" - elif fill.tag == "Lattice": - card.fill_type = "lattice" - card.fill_ID = fill.ID - - # Translation - card.translation[:] = translation - - # Rotation - card.rotation[:] = rotation - - # Get all surface IDs - card.set_surface_IDs() - - # Add to deck - global_.input_deck.cells.append(card) - - return card - - -def universe(cells, root=False): - """ - Define a list of cells as a universe. - - Parameters - ---------- - cells : list of CellCard - List of cells that comprise the universe. - root : bool - Flag to edit the root universe - - Returns - ------- - UniverseCard - The universe card - - See also - -------- - mcdc.cell : Creates a cell that can be used to define a universe. - """ - - # Edit root universe - if root: - # Create and replace placeholder if root is not yet created - if global_.input_deck.universes[0] == None: - card = UniverseCard() - card.ID = 0 - global_.input_deck.universes[0] = card - else: - card = global_.input_deck.universes[0] - - # Create new universe - else: - card = UniverseCard() - card.ID = len(global_.input_deck.universes) - - # Cells - N_cell = len(cells) - card.cell_IDs = np.zeros(N_cell, dtype=int) - for i in range(N_cell): - card.cell_IDs[i] = cells[i].ID - - # Push card - if not root: - global_.input_deck.universes.append(card) - - return card - - -def lattice(x=None, y=None, z=None, universes=None): - """ - Create a lattice card. - - Parameters - ---------- - x : array_like[float], optional - x-coordinates that define the lattice grid (default None). - y : array_like[float], optional - y-coordinates that define the lattice grid (default None). - z : array_like[float], optional - z-coordinates that define the lattice grid (default None). - universes : list of (list of dictionary), optional - List of lists of universe cards that fill the lattice (default None). - - Returns - ------- - dictionary - Lattice card. - """ - # Make lattice card - card = LatticeCard() - card.ID = len(global_.input_deck.lattices) - - # Set grid - if x is not None: - card.x0 = x[0] - card.dx = x[1] - card.Nx = x[2] - if y is not None: - card.y0 = y[0] - card.dy = y[1] - card.Ny = y[2] - if z is not None: - card.z0 = z[0] - card.dz = z[1] - card.Nz = z[2] - - # Set universe IDs - get_ID = np.vectorize(lambda obj: obj.ID) - universe_IDs = get_ID(universes) - ax_expand = [] - if x is None: - ax_expand.append(2) - if y is None: - ax_expand.append(1) - if z is None: - ax_expand.append(0) - for ax in ax_expand: - universe_IDs = np.expand_dims(universe_IDs, axis=ax) - - # Change indexing structure: [z(flip), y(flip), x] --> [x, y, z] - tmp = np.transpose(universe_IDs) - tmp = np.flip(tmp, axis=1) - card.universe_IDs = np.flip(tmp, axis=2) - - # Push card - global_.input_deck.lattices.append(card) - return card - - -def source(**kw): - """ - Create a source card. - - Other Parameters - ---------------- - point : array_like - [x, y, z] point position for point source. - x : array_like - [x_min and x_max] for uniform source. - y : array_like - [y_min and y_max] for uniform source. - z : array_like - [z_min and z_max] for uniform source. - isotropic : bool - Flag for whether source is isotropic. - direction : array_like - [ux, uy, uz] unit vector for parallel beam source. - white_direction : array_like - [nx, ny, nz] unit vector of the normal outward direction of the surface - at which isotropic surface source is emitted. Note that it is similar to the - mechanics of the typical white boundary condition in reactor physics. - energy : array_like - [MG] Probability mass function of the energy group for multigroup source. - [CE] 2D array of piecewise linear pdf [eV, value]. - time : array_like - [t_min and t_max] in/at which source is emitted. - prob : float - Relative probability (or strength) of the source. - - Returns - ------- - dictionary - A source card. - """ - # Check the supplied keyword arguments - for key in kw.keys(): - check_support( - "source parameter", - key, - [ - "point", - "x", - "y", - "z", - "isotropic", - "direction", - "white_direction", - "energy", - "time", - "prob", - ], - False, - ) - - # Get keyword arguments - point = kw.get("point") - x = kw.get("x") - y = kw.get("y") - z = kw.get("z") - isotropic = kw.get("isotropic") - direction = kw.get("direction") - white = kw.get("white_direction") - energy = kw.get("energy") - time = kw.get("time") - prob = kw.get("prob") - - # Make source card - card = SourceCard() - - # Set ID - card.ID = len(global_.input_deck.sources) - - # Set position - if point is not None: - card.x = point[0] - card.y = point[1] - card.z = point[2] - else: - card.box = True - if x is not None: - card.box_x = np.array(x) - if y is not None: - card.box_y = np.array(y) - if z is not None: - card.box_z = np.array(z) - - # Set direction - if white is not None: - card.isotropic = False - card.white = True - ux = white[0] - uy = white[1] - uz = white[2] - # Normalize - norm = (ux**2 + uy**2 + uz**2) ** 0.5 - card.white_x = ux / norm - card.white_y = uy / norm - card.white_z = uz / norm - elif direction is not None: - card.isotropic = False - ux = direction[0] - uy = direction[1] - uz = direction[2] - # Normalize - norm = (ux**2 + uy**2 + uz**2) ** 0.5 - card.ux = ux / norm - card.uy = uy / norm - card.uz = uz / norm - - # Set energy - if energy is not None: - if global_.input_deck.setting["mode_MG"]: - group = np.array(energy) - # Normalize - card.group = group / np.sum(group) - if global_.input_deck.setting["mode_CE"]: - energy = np.array(energy) - # Resize - card.energy = np.zeros(energy.shape) - # Set energy - card.energy[0, :] = energy[0, :] - # Normalize pdf - card.energy[1, :] = energy[1, :] / np.trapz(energy[1, :], x=energy[0, :]) - # Make cdf - card.energy[1, :] = sp.integrate.cumulative_trapezoid( - card.energy[1], x=card.energy[0], initial=0.0 - ) - else: - # Default for MG - if global_.input_deck.setting["mode_MG"]: - G = global_.input_deck.materials[0].G - group = np.ones(G) - card.group = group / np.sum(group) - # Default for CE - if global_.input_deck.setting["mode_CE"]: - # Normalize pdf - card.energy[1, :] = card.energy[1, :] / np.trapz( - card.energy[1, :], x=card.energy[0, :] - ) - # Make cdf - card.energy[1, :] = sp.integrate.cumulative_trapezoid( - card.energy[1], x=card.energy[0], initial=0.0 - ) - - # Set time - if time is not None: - card.time = np.array(time) - - # Set probability - if prob is not None: - card.prob = prob - - # Push card - global_.input_deck.sources.append(card) - - return card - - -# ============================================================================== -# Setting -# ============================================================================== - - -def setting(**kw): - """ - Create a setting card. - - Other Parameters - ---------------- - N_particle : int - Number of MC particle histories to run (for k-eigen and iQMC its /iteration). - N_batch : int - Number of batches to run. - rng_seed : int - Random number seed. - time_boundary : float - The time edge of the problem, after which all particles will be killed. - progress_bar : bool - Whether to display the progress bar (default True; disable when running MC/DC in a loop). - output_name : str - Name of the output file MC/DC should save data in (default "output.h5"). - save_input_deck : bool - Whether to save the input deck information to the output file (default False). - k_eff : str - Whether to run a k-eigenvalue problem. - source_file : str - Source file path and name. - IC_file : str - Path to a file containing a description of an initial condition. - active_bank_buff : int - Size of the particle active bank buffer. - census_bank_buff : int - Size of the particle census bank buffer (in multiples of N_particle). - source_bank_buff : int - Size of the particle source bank buffer (in multiples of N_particle). - future_bank_buff : int - Size of the particle future bank buffer (in multiples of N_particle). - - Returns - ------- - dictionary - A setting card. - """ - - # Check the supplied keyword arguments - for key in kw.keys(): - check_support( - "setting parameter", - key, - [ - "N_particle", - "N_batch", - "rng_seed", - "time_boundary", - "progress_bar", - "output_name", - "save_input_deck", - "k_eff", - "source_file", - "IC_file", - "active_bank_buff", - "census_bank_buff", - "source_bank_buff", - "future_bank_buff", - ], - False, - ) - - # Get keyword arguments - N_particle = kw.get("N_particle") - N_batch = kw.get("N_batch") - rng_seed = kw.get("rng_seed") - time_boundary = kw.get("time_boundary") - progress_bar = kw.get("progress_bar") - output = kw.get("output_name") - save_input_deck = kw.get("save_input_deck") - k_eff = kw.get("k_eff") - source_file = kw.get("source_file") - IC_file = kw.get("IC_file") - bank_active_buff = kw.get("active_bank_buff") - bank_census_buff = kw.get("census_bank_buff") - bank_source_buff = kw.get("source_bank_buff") - bank_future_buff = kw.get("future_bank_buff") - - # Check if setting card has been initialized - card = global_.input_deck.setting - - # Number of particles - if N_particle is not None: - card["N_particle"] = int(N_particle) - - # Number of batches - if N_batch is not None: - card["N_batch"] = int(N_batch) - - # Time boundary - if time_boundary is not None: - card["time_boundary"] = time_boundary - - # RNG seed and stride - if rng_seed is not None: - card["rng_seed"] = rng_seed - - # Output .h5 file name - if output is not None: - card["output_name"] = output - - # Progress bar - if progress_bar is not None: - card["progress_bar"] = progress_bar - - # k effective - if k_eff is not None: - card["k_init"] = k_eff - - # Maximum active bank size - if bank_active_buff is not None: - card["bank_active_buff"] = int(bank_active_buff) - - # Census bank size multiplier - if bank_census_buff is not None: - card["bank_census_buff"] = int(bank_census_buff) - - # Source bank size multiplier - if bank_source_buff is not None: - card["bank_source_buff"] = int(bank_source_buff) - - # Future bank size multiplier - if bank_future_buff is not None: - card["bank_future_buff"] = int(bank_future_buff) - - # Save input deck? - if save_input_deck is not None: - card["save_input_deck"] = save_input_deck - - # Source file - if source_file is not None: - card["source_file"] = True - card["source_file_name"] = source_file - - # Set number of particles - card_setting = global_.input_deck.setting - with h5py.File(source_file, "r") as f: - card_setting["N_particle"] = f["particles_size"][()] - - # IC file - if IC_file is not None: - card["IC_file"] = True - card["IC_file_name"] = IC_file - - # Set number of particles - card_setting = global_.input_deck.setting - with h5py.File(IC_file, "r") as f: - card_setting["N_particle"] = f["IC/neutrons_size"][()] - card_setting["N_precursor"] = f["IC/precursors_size"][()] - - # TODO: Allow both source and IC files - if IC_file and source_file: - print_error("Using both source and IC files is not supported yet.") - - -def eigenmode( - N_inactive=0, N_active=0, k_init=1.0, gyration_radius=None, save_particle=False -): - """ - Create an eigenmode card. - - Parameters - ---------- - N_inactive : int - Number of cycles not included when averaging the k-eigenvalue (default 0). - N_active : int - Number of cycles to include for statistics of the k-eigenvalue (default 0). - k_init : float - Initial k value to iterate on (default 1.0). - gyration_radius : float, optional - Specify a gyration radius (default None). - save_particle : bool - Whether final particle bank outputs (default False). - - Returns - ------- - dictionary - A eigenmode card. - """ - - # Update setting card - card = global_.input_deck.setting - card["N_inactive"] = N_inactive - card["N_active"] = N_active - card["N_cycle"] = N_inactive + N_active - card["mode_eigenvalue"] = True - card["k_init"] = k_init - card["save_particle"] = save_particle - - # Gyration radius setup - if gyration_radius is not None: - card["gyration_radius"] = True - if gyration_radius == "all": - card["gyration_radius_type"] = GYRATION_RADIUS_ALL - elif gyration_radius == "infinite-x": - card["gyration_radius_type"] = GYRATION_RADIUS_INFINITE_X - elif gyration_radius == "infinite-y": - card["gyration_radius_type"] = GYRATION_RADIUS_INFINITE_Y - elif gyration_radius == "infinite-z": - card["gyration_radius_type"] = GYRATION_RADIUS_INFINITE_Z - elif gyration_radius == "only-x": - card["gyration_radius_type"] = GYRATION_RADIUS_ONLY_X - elif gyration_radius == "only-y": - card["gyration_radius_type"] = GYRATION_RADIUS_ONLY_Y - elif gyration_radius == "only-z": - card["gyration_radius_type"] = GYRATION_RADIUS_ONLY_Z - else: - print_error("Unknown gyration radius type") - - -# ============================================================================== -# Technique -# ============================================================================== - - -def implicit_capture(): - """ - Activate implicit capture (implies no weighted emission). - """ - card = global_.input_deck.technique - card["implicit_capture"] = True - card["weighted_emission"] = False - - -def weighted_emission(flag): - """ - Activate weighted emission variance reduction technique. - - Parameters - ---------- - flag : bool - True to activate weighted emission. - """ - - card = global_.input_deck.technique - card["weighted_emission"] = flag - - -def population_control(pct="splitting-roulette"): - """ - Set population control techniques. - - Parameters - ---------- - pct : str, optional - Population control method (default "spliting-roulette"). - """ - # Check if the selected technique is supported - pct = check_support( - "population control technique", - pct, - [ - "combing", - "combing-weight", - "splitting-roulette", - "splitting-roulette-weight", - ], - ) - card = global_.input_deck.technique - card["pct"] = pct - card["population_control"] = True - card["weighted_emission"] = False - - -def branchless_collision(): - """ - Activate branchless collision variance reduction technique (implies no weighted emission). - """ - card = global_.input_deck.technique - card["branchless_collision"] = True - card["weighted_emission"] = False - - -def time_census(t, tally_frequency=None): - """ - Set time-census boundaries. - - Parameters - ---------- - t : array_like[float] - The time-census boundaries. - tally_frecuency : integer, optional - Number of uniform tally time mesh bins in census-based tallying. - This overrides manual tally time mesh definitions. - - Returns - ------- - None (in-place card alterations). - """ - - # Make sure that the time grid points are sorted - if not is_sorted(t): - print_error("Time census: Time grid points have to be sorted.") - - # Make sure that the starting point is larger than zero - if t[0] <= 0.0: - print_error("Time census: First census time should be larger than zero.") - - # Add the default, final census-at-infinity - t = np.append(t, INF) - - # Set the time census parameters - card = global_.input_deck.setting - card["census_time"] = t - card["N_census"] = len(t) - - # Set the census-based tallying - if tally_frequency is not None and tally_frequency > 0: - # Reset all tallies' time grids: - card["census_based_tally"] = True - card["census_tally_frequency"] = tally_frequency - - -def weight_window( - x=np.array([-INF, INF]), - y=np.array([-INF, INF]), - z=np.array([-INF, INF]), - mu=np.array([-1.0, 1.0]), - azi=np.array([-PI, PI]), - g=np.array([-INF, INF]), - E=np.array([0.0, INF]), - window=None, - width=2.5, - method={"user"}, - modifications={}, - save_ww_data=True, -): - """ - Activate weight window variance reduction technique. - - Parameters - ---------- - x : array_like[float], optional - Location of the weight window in x (default None). - y : array_like[float], optional - Location of the weight window in y (default None). - z : array_like[float], optional - Location of the weight window in z (default None). - t : array_like[float], optional - Location of the weight window in t (default None). - window : array_like[float], optional - Center of the weight windows (default None). - width : float, optional - Width of the window (default 2.5). - epsilon : float, optional - Small values used for techniques (default empty list). - techniques : list of str, optional - List of techniques to use for ww - {'user','previous','alpha','min_center','wollaber'} (default {'user'}). - Returns - ------- - A weight window card. - - """ - - t = global_.input_deck.setting["census_time"] - card = global_.input_deck.technique - card["weight_window"] = True - N_update = 0 - - card["ww"]["save"] = save_ww_data - # Set width - if width is not None: - card["ww"]["width"] = width - - # Checking WW method - method_checked = check_support( - "Weight window method", - method, - ["user", "previous"], - ) - if method_checked == "user": - card["ww"]["auto"] = WW_USER - elif method_checked == "previous": - card["ww"]["auto"] = WW_PREVIOUS - - scores = (["flux"],) - # Make tally card - tcard = MeshTallyCard() - - # Set ID - tcard.ID = len(global_.input_deck.mesh_tallies) - card["ww"]["tally_idx"] = tcard.ID - - # Set mesh - tcard.x = x - tcard.y = y - tcard.z = z - - # Set other filters - tcard.t = t - tcard.mu = mu - tcard.azi = azi - - # Set energy group grid - if type(g) == type("string") and g == "all": - G = global_.input_deck.materials[0].G - tcard.g = np.linspace(0, G, G + 1) - 0.5 - else: - tcard.g = g - if global_.input_deck.setting["mode_CE"]: - tcard.g = E - - # Calculate total number bins - Nx = len(tcard.x) - 1 - Ny = len(tcard.y) - 1 - Nz = len(tcard.z) - 1 - Nt = len(tcard.t) - 1 - Nmu = len(tcard.mu) - 1 - N_azi = len(tcard.azi) - 1 - Ng = len(tcard.g) - 1 - tcard.N_bin = Nx * Ny * Nz * Nt * Nmu * N_azi * Ng - tcard.scores.append("flux") - # Add to deck - global_.input_deck.mesh_tallies.append(tcard) - - # Checking techniques - for mod in modifications: - mod_checked = check_support( - "Weight window modification", - mod[0], - ["min-center", "wollaber"], - ) - if mod_checked == "min-center": - card["ww"]["epsilon"][WW_MIN] = mod[1] - if mod_checked == "wollaber": - card["ww"]["epsilon"][WW_WOLLABER] = mod[1] - card["ww"]["epsilon"][WW_WOLLABER + 1] = mod[2] - - # Set mesh - card["ww"]["mesh"]["x"] = x - card["ww"]["mesh"]["y"] = y - card["ww"]["mesh"]["z"] = z - card["ww"]["mesh"]["t"] = t - card["ww"]["mesh"]["mu"] = mu - card["ww"]["mesh"]["azi"] = azi - - # Set energy group grid - if type(g) == type("string") and g == "all": - G = global_.input_deck.materials[0].G - card["ww"]["mesh"]["g"] = np.linspace(0, G, G + 1) - 0.5 - else: - tcard.g = g - if global_.input_deck.setting["mode_CE"]: - card["ww"]["mesh"]["g"] = E - - if window is None: - window = np.ones((Nt, Nx, Ny, Nz)) - """ - # Set window - ax_expand = [] - if t is None: - ax_expand.append(0) - if x is None: - ax_expand.append(1) - if y is None: - ax_expand.append(2) - if z is None: - ax_expand.append(3) - for ax in ax_expand: - window = np.expand_dims(window, axis=ax) - """ - card["ww"]["center"] = window - return card, tcard - - -def domain_decomposition( - x=None, - y=None, - z=None, - exchange_rate=100000, - exchange_rate_padding=None, - work_ratio=None, -): - """ - Activate domain decomposition. - - Parameters - ---------- - x : array_like[float], optional - Location of subdomain boundaries in x (default None). - y : array_like[float], optional - Location of subdomain boundaries in y (default None). - z : array_like[float], optional - Location of subdomain boundaries in z (default None). - exchange_rate : float, optional - Number of particles to acumulate in the domain banks before sending. - work_ratio : array_like[integer], optional - Number of processors in each domain - - Returns - ------- - A domain decomposition card. - - """ - card = global_.input_deck.technique - card["domain_decomposition"] = True - card["dd_exchange_rate"] = int(exchange_rate) - card["dd_exchange_rate_padding"] = exchange_rate_padding - dom_num = 1 - # Set mesh - if x is not None: - card["dd_mesh"]["x"] = x - dom_num *= len(x) - if y is not None: - card["dd_mesh"]["y"] = y - dom_num *= len(y) - if z is not None: - card["dd_mesh"]["z"] = z - dom_num += len(z) - - card["dd_work_ratio"] = work_ratio - card["dd_idx"] = 0 - card["dd_xp_neigh"] = [] - card["dd_xn_neigh"] = [] - card["dd_yp_neigh"] = [] - card["dd_yn_neigh"] = [] - card["dd_zp_neigh"] = [] - card["dd_zn_neigh"] = [] - return card - - -def iQMC( - phi0=None, - g=None, - t=None, - x=None, - y=None, - z=None, - source0=None, - source_x0=None, - source_y0=None, - source_z0=None, - krylov_restart=None, - fixed_source=None, - maxit=25, - tol=1e-6, - fixed_source_solver="source iteration", - sample_method="halton", - mode="fixed", - scores=[], -): - """ - Activate the iterative Quasi-Monte Carlo (iQMC) neutron transport method. - - Parameters - ---------- - phi0 : array_like[float], optional - Initial scalar flux approximation (default None). - g : array_like[float], optional - Energy values that define energy mesh (default None). - t : array_like[float], optional - Time values that define time mesh (default None). - x : array_like[float], optional - x-coordinates that define spacial mesh (default None). - y : array_like[float], optional - y-coordinates that define spacial mesh (default None). - z : array_like[float], optional - z-coordinates that define spacial mesh (default None). - - Other Parameters - ---------- - source0 : array_like[float], optional - Initial particle source (default None). - source_x0 : array_like[float], optional - Initial source for source-x (default None). - source_y0 : array_like[float], optional - Initial source for source-y (default None). - source_z0 : array_like[float], optional - Initial source for source-z (default None). - krylov_restart : int, optional - Max number of iterations for Krylov iteration (default same as maxit). - fixed_source : array_like[float], optional - Fixed source (default same as phi0). - iterations_max : int, optional - Maximum number of iterations allowed before termination (default 25). - tol : float, optional - Convergence tolerance (default 1e-6). - fixed_source_solver : {'source iteration', 'gmres'} - Deterministic solver for fixed-source problem (default "source iteration"). - Solver for k-eigenvalue problem (default "power_iteration"). - sample_method: {'halton', 'random'} - Method for generating particle samples. - mode: {'fixed', batched} - Set iQMC to run with a fixed-seed or batched iteration scheme. - scores : list of str, optional - List of tallies to score in addition to the mandatory flux and - source strength. Additional scores include - {'source-x', 'source-y', 'source-z', 'fission-power'} (default empty list). - - Returns - ------- - None (in-place card alterations). - - Notes - ----- - phi0 is used to estimate the initial source strength. If source0 is - provided, source0 will be used instead of phi0. Either phi0 or - source0 must be provided as they are used to initialize particle - weights. - """ - - card = global_.input_deck.technique - card["iQMC"] = True - card["iqmc"]["tol"] = tol - card["iqmc"]["iterations_max"] = maxit - card["iqmc"]["sample_method"] = sample_method - card["iqmc"]["mode"] = mode - - # Set mesh - if g is not None: - card["iqmc"]["mesh"]["g"] = g - if t is not None: - card["iqmc"]["mesh"]["t"] = t - if x is not None: - card["iqmc"]["mesh"]["x"] = x - if y is not None: - card["iqmc"]["mesh"]["y"] = y - if z is not None: - card["iqmc"]["mesh"]["z"] = z - - ax_expand = [] - if g is None: - ax_expand.append(0) - if t is None: - ax_expand.append(1) - if x is None: - ax_expand.append(2) - if y is None: - ax_expand.append(3) - if z is None: - ax_expand.append(4) - for ax in ax_expand: - phi0 = np.expand_dims(phi0, axis=ax) - if fixed_source is not None: - fixed_source = np.expand_dims(fixed_source, axis=ax) - else: - fixed_source = np.zeros_like(phi0) - - if krylov_restart is None: - krylov_restart = maxit - - if source0 is None: - source0 = np.zeros_like(phi0) - - score_list = card["iqmc"]["score_list"] - for name in scores: - score_list[name] = True - - if score_list["source-x"]: - card["iqmc"]["krylov_vector_size"] += 1 - if source_x0 is None: - source_x0 = np.zeros_like(phi0) - - if score_list["source-y"]: - card["iqmc"]["krylov_vector_size"] += 1 - if source_y0 is None: - source_y0 = np.zeros_like(phi0) - - if score_list["source-z"]: - card["iqmc"]["krylov_vector_size"] += 1 - if source_z0 is None: - source_z0 = np.zeros_like(phi0) - - card["iqmc"]["score"]["flux"] = phi0 - card["iqmc"]["score"]["source-x"] = source_x0 - card["iqmc"]["score"]["source-y"] = source_y0 - card["iqmc"]["score"]["source-z"] = source_z0 - card["iqmc"]["source"] = source0 - card["iqmc"]["fixed_source"] = fixed_source - card["iqmc"]["fixed_source_solver"] = fixed_source_solver - card["iqmc"]["krylov_restart"] = krylov_restart - - -def weight_roulette(w_threshold=0.2, w_survive=1.0): - """ - Activate weight roulette technique. - - If neutron weight is below `w_threshold`, then enter weight roulette - technique with survival weight `w_survive`. - - Parameters - ---------- - w_threshold : float - Weight_roulette() is called on a particle if P['w'] <= wr_threshold. - w_survive : float - Weight of surviving particle. - - Returns - ------- - None (in-place card alterations). - """ - card = global_.input_deck.technique - card["weight_roulette"] = True - card["wr_threshold"] = w_threshold - card["wr_survive"] = w_survive - - -def IC_generator( - N_neutron=0, - N_precursor=0, - cycle_stretch=1.0, - neutron_density=None, - max_neutron_density=None, - precursor_density=None, - max_precursor_density=None, -): - """ - Activate initial condition generator. - - The initial condition generator samples initial neutrons and precursors - during an eigenvalue simulation. - - Parameters - ---------- - N_neutron : int - Neutron target size. - N_precursor : int - Delayed neutron precursor target size. - cycle_stretch : float - Factor to stretch number of cycles. Higher cycle stretch reduces inter-cycle - correlation. - neutron_density, max_neutron_density : float - Total and maximum neutron density, required if `N_neutron` > 0. - precursor_density, max_precursor_density : float - Total and maximum precursor density, required if `N_precursor` > 0. - - Returns - ------- - None (in-place card alterations). - """ - - # Turn on eigenmode and population control - eigenmode() - population_control() - - # Set parameters - card = global_.input_deck.technique - card["IC_generator"] = True - card["IC_N_neutron"] = N_neutron - card["IC_N_precursor"] = N_precursor - - # Setting parameters - card_setting = global_.input_deck.setting - N_particle = card_setting["N_particle"] - - # Check optional parameters - if N_neutron > 0.0: - if neutron_density is None or max_neutron_density is None: - print_error("IC generator requires neutron_density and max_neutron_density") - card["IC_neutron_density"] = N_particle * neutron_density - card["IC_neutron_density_max"] = max_neutron_density - if N_precursor > 0.0: - if precursor_density is None: - print_error( - "IC generator requires precursor_density and max_precursor_density" - ) - card["IC_precursor_density"] = N_particle * precursor_density - card["IC_precursor_density_max"] = max_precursor_density - - # Set number of active cycles - n = card["IC_neutron_density"] - n_max = card["IC_neutron_density_max"] - C = card["IC_precursor_density"] - C_max = card["IC_precursor_density_max"] - N_cycle1 = 0.0 - N_cycle2 = 0.0 - if N_neutron > 0: - N_cycle1 = math.ceil(cycle_stretch * math.ceil(n_max / n * N_neutron)) - if N_precursor > 0: - N_cycle2 = math.ceil(cycle_stretch * math.ceil(C_max / C * N_precursor)) - N_cycle = max(N_cycle1, N_cycle2) - card_setting["N_cycle"] = N_cycle - card_setting["N_active"] = N_cycle - - -def uq(**kw): - """ - Activate uncertainty quantification. - - Other Parameters - ---------------- - material : dictionary, optional - Material card of material with uncertain parameters. - nuclide : dictionary, optional - Nuclear card of nuclide with uncertain parameters. - distribution : {"uniform"} - Probability distribution of uncertain parameters. - - Returns - ------- - None (in-place card alterations). - """ - - def append_card(delta_card, global_tag): - delta_card.distribution = dist - delta_card.flags = [] - for key in kw.keys(): - check_support(parameter.tag + " parameter", key, parameter_list, False) - delta_card.flags.append(key) - setattr(delta_card, key, kw[key]) - global_.input_deck.uq_deltas[global_tag].append(delta_card) - - global_.input_deck.technique["uq"] = True - # Make sure N_batch > 1 - if global_.input_deck.setting["N_batch"] <= 1: - print_error( - "Must set N_batch>1 with global_.setting() prior to global_.uq() call." - ) - - # Check uq parameter - parameter_ = check_support( - "uq parameter", - list(kw)[0], - ["nuclide", "material", "surface", "source"], - False, - ) - parameter = kw[parameter_] - del kw[parameter_] - parameter.uq = True - - # Confirm supplied distribution - check_requirement("uq", kw, ["distribution"]) - dist = check_support("distribution", kw["distribution"], ["uniform"], False) - del kw["distribution"] - - # Only remaining keywords should be the parameter delta(s) - - if parameter.tag == "Material": - parameter_list = [ - "capture", - "scatter", - "fission", - "nu_s", - "nu_p", - "nu_d", - "chi_p", - "chi_d", - "speed", - "decay", - ] - global_tag = "materials" - if parameter.N_nuclide == 1: - nuc_card = NuclideCard(parameter.G, parameter.J) - nuc_card.ID = parameter.nuclide_IDs[0] - append_card(nuc_card, "nuclides") - delta_card = MaterialCard(parameter.N_nuclide, parameter.G, parameter.J) - for name in ["ID", "nuclide_IDs", "nuclide_densities"]: - setattr(delta_card, name, getattr(parameter, name)) - elif parameter.tag == "Nuclide": - parameter_list = [ - "capture", - "scatter", - "fission", - "nu_s", - "nu_p", - "nu_d", - "chi_p", - "chi_d", - "speed", - "decay", - ] - global_tag = "nuclides" - delta_card = make_card_nuclide(parameter.G, parameter.J) - delta_card["ID"] = parameter.ID - append_card(delta_card, global_tag) - - -# ============================================================================== -# Util -# ============================================================================== - - -def nuclide_registered(name): - for card in global_.input_deck.nuclides: - if name == card.name: - return True - return False - - -def get_nuclide(name): - for card in global_.input_deck.nuclides: - if name == card.name: - return card - - -def print_card(card): - if isinstance(card, SurfaceHandle): - card = card.card - for key in card: - if key == "tag": - print(card[key] + " card") - else: - print(" " + key + " : " + str(card[key])) - - -def check_support(label, value, supported, replace=True): - if replace: - value = value.replace("_", "-").replace(" ", "-").lower() - supported_str = "{" - for str_ in supported: - supported_str += str_ + ", " - supported_str = supported_str[:-2] + "}" - if value not in supported: - print_error("Unsupported " + label + ": " + value + "\n" + supported_str) - return value - - -def check_requirement(label, kw, required): - missing = "{" - error = False - for req in required: - if req not in kw.keys(): - error = True - missing += req + ", " - missing = missing[:-2] + "}" - if error: - print_error("Parameters " + missing + " are required for" + label) - - -def make_particle_bank(size): - struct = [ - ("x", np.float64), - ("y", np.float64), - ("z", np.float64), - ("t", np.float64), - ("ux", np.float64), - ("uy", np.float64), - ("uz", np.float64), - ("g", np.uint64), - ("E", np.float64), - ("w", np.float64), - ("rng_seed", np.uint64), - ] - iqmc_struct = [("w", np.float64, (1,))] - struct += [("iqmc", iqmc_struct)] - - bank = np.zeros(size, dtype=np.dtype(struct)) - - # Set default values - for i in range(size): - bank[i]["ux"] = 1.0 - bank[i]["w"] = 1.0 - bank[i]["rng_seed"] = 1 - - return bank - - -def save_particle_bank(bank, name): - with h5py.File(name + ".h5", "w") as f: - f.create_dataset("particles", data=bank[:]) - f.create_dataset("particles_size", data=len(bank[:])) - - -# ============================================================================== -# Reset -# ============================================================================== - - -def reset(): - global_.input_deck.reset() - - -# ============================================================================== -# Misc -# ============================================================================== - - -def is_sorted(a): - return np.all(a[:-1] <= a[1:]) diff --git a/mcdc/iqmc/__init__.py b/mcdc/iqmc/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mcdc/iqmc/iqmc_kernel.py b/mcdc/iqmc/iqmc_kernel.py deleted file mode 100644 index f7a89a34a..000000000 --- a/mcdc/iqmc/iqmc_kernel.py +++ /dev/null @@ -1,847 +0,0 @@ -import math -import numpy as np - -from mpi4py import MPI -from numba import objmode, literal_unroll - -import mcdc.type_ as type_ -import mcdc.adapt as adapt -import mcdc.src.geometry as geometry -import mcdc.src.mesh as mesh_ -import mcdc.src.physics as physics -import mcdc.src.surface as surface_ - -from mcdc.adapt import toggle -from mcdc.constant import * -from mcdc.kernel import ( - allreduce_array, - move_particle, -) -from mcdc.type_ import iqmc_score_list - - -# ========================================================================= -# Sampling Operations -# ========================================================================= - - -@toggle("iQMC") -def samples_init(mcdc): - N, dim = mcdc["technique"]["iqmc"]["samples"].shape - N_start = mcdc["mpi_work_start"] - if mcdc["technique"]["iqmc"]["sample_method"] == "halton": - mcdc["technique"]["iqmc"]["samples"] = halton(N, dim, skip=N_start) - if mcdc["technique"]["iqmc"]["sample_method"] == "random": - mcdc["technique"]["iqmc"]["samples"] = random(N, dim) - - -@toggle("iQMC") -def scramble_samples(mcdc): - # TODO: use MCDC seed system - seed_batch = np.int64(mcdc["setting"]["N_particle"] * mcdc["idx_cycle"] + 1) - iqmc = mcdc["technique"]["iqmc"] - N, dim = iqmc["samples"].shape - N_start = mcdc["mpi_work_start"] - - if iqmc["sample_method"] == "halton": - iqmc["samples"] = rhalton(N, dim, seed=seed_batch, skip=N_start) - if iqmc["sample_method"] == "random": - iqmc["samples"] = random(N, dim, seed=seed_batch) - - -@toggle("iQMC") -def rhalton(N, dim, seed=12345, skip=0): - np.random.seed(seed) - primes = np.array((2, 3, 5, 7, 11, 13, 17, 19, 23, 29), dtype=np.int64) - halton = np.zeros((N, dim), dtype=np.float64) - - for D in range(dim): - b = primes[D] - # b = np.int64(2) - ind = np.arange(skip, skip + N, dtype=np.int64) - b2r = 1 / b - ans = np.zeros(ind.shape, dtype=np.float64) - res = ind.copy() - while (1.0 - b2r) < 1.0: - dig = np.mod(res, b) - perm = np.random.permutation(b) - pdig = perm[dig] - ans = ans + pdig.astype(np.float64) * b2r - b2r = b2r / np.float64(b) - res = ((res - dig) / b).astype(np.int64) - halton[:, D] = ans - - return halton - - -@toggle("iQMC") -def halton(N, dim, skip=0): - # TODO: find more efficient implementation of Halton Sequence - primes = np.array((2, 3, 5, 7, 11, 13, 17, 19, 23, 29), dtype=np.int64) - halton = np.zeros((N, dim), dtype=np.float64) - - for D in range(dim): - b = primes[D] - n, d = 0, 1 - for i in range(skip + N): - x = d - n - if x == 1: - n = 1 - d *= b - else: - y = d // b - while x <= y: - y //= b - n = (b + 1) * y - x - if i >= skip: - halton[i - skip, D] = n / d - - return halton - - -@toggle("iQMC") -def random(N, dim, seed=123456): - np.random.seed(seed) - return np.random.rand(N, dim) - - -# ============================================================================= -# Preprocess functions -# ============================================================================= - - -@toggle("iQMC") -def iqmc_preprocess(mcdc): - # set bank source - iqmc = mcdc["technique"]["iqmc"] - eigenmode = mcdc["setting"]["mode_eigenvalue"] - # generate material index - iqmc_generate_material_idx(mcdc) - if iqmc["source"].all() == 0.0: - # use material index to generate a first guess for the source - iqmc_prepare_source(mcdc) - iqmc_update_source(mcdc) - if eigenmode: - iqmc_prepare_nusigmaf(mcdc) - - iqmc_consolidate_sources(mcdc) - - -@toggle("iQMC") -def iqmc_generate_material_idx(mcdc): - """ - This algorithm is meant to loop through every spatial cell of the - iQMC mesh and assign a material index according to the material_ID at - the center of the cell. - - Therefore, the whole cell is treated as the material located at the - center of the cell, regardless of whethere there are more materials - present. - - A crude but quick approximation. - """ - mesh = mcdc["technique"]["iqmc"]["mesh"] - Nt = len(mesh["t"]) - 1 - Nx = len(mesh["x"]) - 1 - Ny = len(mesh["y"]) - 1 - Nz = len(mesh["z"]) - 1 - # create particle to utilize cell finding functions - P_temp_arr = adapt.local_array(1, type_.particle) - P_temp = P_temp_arr[0] - # set default attributes - P_temp["alive"] = True - - x_mid = 0.5 * (mesh["x"][1:] + mesh["x"][:-1]) - y_mid = 0.5 * (mesh["y"][1:] + mesh["y"][:-1]) - z_mid = 0.5 * (mesh["z"][1:] + mesh["z"][:-1]) - - # loop through every cell - for t in range(Nt): - for i in range(Nx): - x = x_mid[i] - for j in range(Ny): - y = y_mid[j] - for k in range(Nz): - z = z_mid[k] - - # assign cell center position - P_temp["t"] = t - P_temp["x"] = x - P_temp["y"] = y - P_temp["z"] = z - P_temp["material_ID"] = -1 - P_temp["cell_ID"] = -1 - P_temp["g"] = 0 - - # set material_ID - geometry.locate_particle(P_temp_arr, mcdc) - - # assign material index - mcdc["technique"]["iqmc"]["material_idx"][t, i, j, k] = P_temp[ - "material_ID" - ] - - -@toggle("iQMC") -def iqmc_prepare_nusigmaf(mcdc): - iqmc = mcdc["technique"]["iqmc"] - mesh = iqmc["mesh"] - flux = iqmc["score"]["flux"]["bin"] - fission_source = iqmc["score"]["fission-source"]["bin"] - Nt = len(mesh["t"]) - 1 - Nx = len(mesh["x"]) - 1 - Ny = len(mesh["y"]) - 1 - Nz = len(mesh["z"]) - 1 - # calculate nu*SigmaF for every cell - for t in range(Nt): - for i in range(Nx): - for j in range(Ny): - for k in range(Nz): - t = 0 - mat_idx = iqmc["material_idx"][t, i, j, k] - material = mcdc["materials"][mat_idx] - fission_source += iqmc_fission_source(flux[:, t, i, j, k], material) - - -@toggle("iQMC") -def iqmc_prepare_source(mcdc): - """ - Iterates trhough all spatial cells to calculate the iQMC source. The source - is a combination of the user input Fixed-Source plus the calculated - Scattering-Source and Fission-Sources. Resutls are stored in - mcdc['technique']['iqmc_source'], a matrix of size [G,Nt,Nx,Ny,Nz]. - - """ - iqmc = mcdc["technique"]["iqmc"] - mesh = iqmc["mesh"] - Nt = len(mesh["t"]) - 1 - Nx = len(mesh["x"]) - 1 - Ny = len(mesh["y"]) - 1 - Nz = len(mesh["z"]) - 1 - - fission = np.zeros_like(iqmc["source"]) - scatter = np.zeros_like(iqmc["source"]) - - # calculate source for every cell and group in the iqmc_mesh - for t in range(Nt): - for i in range(Nx): - for j in range(Ny): - for k in range(Nz): - mat_idx = iqmc["material_idx"][t, i, j, k] - # we can vectorize the multigroup calculation here - flux = iqmc["score"]["flux"]["bin"][:, t, i, j, k] - fission[:, t, i, j, k] = iqmc_effective_fission(flux, mat_idx, mcdc) - scatter[:, t, i, j, k] = iqmc_effective_scattering( - flux, mat_idx, mcdc - ) - iqmc["score"]["effective-scattering"]["bin"] = scatter - iqmc["score"]["effective-fission"]["bin"] = fission - iqmc["score"]["effective-fission-outter"] = fission - - -# ============================================================================= -# Particle Operations -# ============================================================================= - - -@toggle("iQMC") -def iqmc_prepare_particles(mcdc): - """ - Create N_particles assigning the position, direction, and group from the - QMC Low-Discrepency Sequence. Particles are added to the bank_source. - - Particles are prepared as a batch in iQMC so that we only have to call the - low-discprenecy sequence function once for fixed-seed mode or once per sweep - for batched mode. - - """ - iqmc = mcdc["technique"]["iqmc"] - # total number of particles - N_particle = mcdc["setting"]["N_particle"] - # number of particles this processor will handle - N_work = mcdc["mpi_work_size"] - - # low discrepency sequence - samples = iqmc["samples"] - # source - Q = iqmc["source"] - mesh = iqmc["mesh"] - Nx = len(mesh["x"]) - 1 - Ny = len(mesh["y"]) - 1 - Nz = len(mesh["z"]) - 1 - # total number of spatial cells - N_total = Nx * Ny * Nz - # outter mesh boundaries for sampling position - xa = mesh["x"][0] - xb = mesh["x"][-1] - ya = mesh["y"][0] - yb = mesh["y"][-1] - za = mesh["z"][0] - zb = mesh["z"][-1] - - for n in range(N_work): - # Create new particle - P_new_arr = adapt.local_array(1, type_.particle_record) - P_new = P_new_arr[0] - # assign initial group, time, and rng_seed (not used) - P_new["g"] = 0 - P_new["t"] = 0 - P_new["rng_seed"] = 0 - # assign direction - P_new["x"] = iqmc_sample_position(xa, xb, samples[n, 0]) - P_new["y"] = iqmc_sample_position(ya, yb, samples[n, 4]) - P_new["z"] = iqmc_sample_position(za, zb, samples[n, 3]) - # Sample isotropic direction - P_new["ux"], P_new["uy"], P_new["uz"] = iqmc_sample_isotropic_direction( - samples[n, 1], samples[n, 5] - ) - x, y, z, t, outside = mesh_.structured.get_indices(P_new_arr, mesh) - q = Q[:, t, x, y, z].copy() - dV = iqmc_cell_volume(x, y, z, mesh) - # Source tilt - iqmc_tilt_source(t, x, y, z, P_new_arr, q, mcdc) - # set particle weight - P_new["iqmc"]["w"] = q * dV * N_total / N_particle - P_new["w"] = P_new["iqmc"]["w"].sum() - # add to source bank - adapt.add_source(P_new_arr, mcdc) - - -@toggle("iQMC") -def iqmc_cell_volume(x, y, z, mesh): - """ - Calculate the volume of the cartesian spatial cell. - - """ - dx = dy = dz = 1 - if (mesh["x"][x] != -INF) and (mesh["x"][x] != INF): - dx = mesh["x"][x + 1] - mesh["x"][x] - if (mesh["y"][y] != -INF) and (mesh["y"][y] != INF): - dy = mesh["y"][y + 1] - mesh["y"][y] - if (mesh["z"][z] != -INF) and (mesh["z"][z] != INF): - dz = mesh["z"][z + 1] - mesh["z"][z] - dV = dx * dy * dz - return dV - - -@toggle("iQMC") -def iqmc_sample_position(a, b, sample): - return a + (b - a) * sample - - -@toggle("iQMC") -def iqmc_sample_isotropic_direction(sample1, sample2): - """ - Sample the an isotropic direction using samples between [0,1]. - - """ - # Sample polar cosine and azimuthal angle uniformly - mu = 2.0 * sample1 - 1.0 - azi = 2.0 * PI * sample2 - - # Convert to Cartesian coordinates - c = (1.0 - mu**2) ** 0.5 - uy = math.cos(azi) * c - uz = math.sin(azi) * c - ux = mu - return ux, uy, uz - - -@toggle("iQMC") -def iqmc_sample_group(sample, G): - """ - Uniformly sample energy group using a random sample between [0,1]. - - """ - return int(np.floor(sample * G)) - - -# ========================================================================= -# Move to Event -# ========================================================================= - - -@toggle("iQMC") -def iqmc_move_to_event(P_arr, mcdc): - # ================================================================================== - # Preparation (as needed) - # ================================================================================== - - P = P_arr[0] - - # Multigroup preparation - # In MG mode, particle speed is material-dependent. - if mcdc["setting"]["mode_MG"]: - # If material is not identified yet, locate the particle - if P["material_ID"] == -1: - if not geometry.locate_particle(P_arr, mcdc): - # Particle is lost - P["event"] = EVENT_LOST - return - - # ================================================================================== - # Geometry inspection - # ================================================================================== - # - Set particle top cell and material IDs (if not lost) - # - Set surface ID (if surface hit) - # - Return distance to boundary (surface or lattice) - # - Return geometry event type (surface or lattice crossing or particle lost) - - d_boundary = geometry.inspect_geometry(P_arr, mcdc) - - # Particle is lost? - if P["event"] == EVENT_LOST: - return - - # ================================================================================== - # Get distances to other events - # ================================================================================== - - # Distance to domain decomposition mesh - d_domain = INF - speed = physics.get_speed(P_arr, mcdc) - if mcdc["technique"]["domain_decomposition"]: - d_domain = mesh_.structured.get_crossing_distance( - P_arr, speed, mcdc["technique"]["dd_mesh"] - ) - - # Distance to iqmc mesh - d_mesh = mesh_.structured.get_crossing_distance( - P_arr, speed, mcdc["technique"]["iqmc"]["mesh"] - ) - - # ========================================================================= - # Determine event(s) - # ========================================================================= - # TODO: Make a function to better maintain the repeating operation - - distance = d_boundary - - # Check distance to domain - if d_domain < distance - COINCIDENCE_TOLERANCE: - distance = d_domain - P["event"] = EVENT_DOMAIN_CROSSING - P["surface_ID"] = -1 - elif geometry.check_coincidence(d_domain, distance): - P["event"] += EVENT_DOMAIN_CROSSING - - # Check distance to mesh - if d_mesh < distance - COINCIDENCE_TOLERANCE: - distance = d_mesh - P["event"] = EVENT_IQMC_MESH - P["surface_ID"] = -1 - elif geometry.check_coincidence(d_mesh, distance): - P["event"] += EVENT_IQMC_MESH - - # ========================================================================= - # Move particle - # ========================================================================= - - # score iQMC tallies - iqmc_score_tallies(P_arr, distance, mcdc) - # attenuate particle weight - iqmc_continuous_weight_reduction(P_arr, distance, mcdc) - # kill particle if it falls below weight threshold - if abs(P["w"]) <= mcdc["technique"]["iqmc"]["w_min"]: - P["alive"] = False - - # Move particle - move_particle(P_arr, distance, mcdc) - - -@toggle("iQMC") -def iqmc_continuous_weight_reduction(P_arr, distance, mcdc): - """ - Continuous weight reduction technique based on particle track-length. - """ - P = P_arr[0] - material = mcdc["materials"][P["material_ID"]] - SigmaT = material["total"][:] - w = P["iqmc"]["w"] - P["iqmc"]["w"] = w * np.exp(-distance * SigmaT) - P["w"] = P["iqmc"]["w"].sum() - - -# ============================================================================= -# Surface crossing -# ============================================================================= - - -@toggle("iQMC") -def iqmc_surface_crossing(P_arr, prog): - mcdc = adapt.mcdc_global(prog) - P = P_arr[0] - surface = mcdc["surfaces"][P["surface_ID"]] - if surface["BC"] == BC_VACUUM: - P["alive"] = False - elif surface["BC"] == BC_REFLECTIVE: - surface_.reflect(P_arr, surface) - - # Need to check new cell later? - if P["alive"] and not surface["BC"] == BC_REFLECTIVE: - P["cell_ID"] = -1 - - -# ============================================================================= -# iQMC Source Operations -# ============================================================================= - - -@toggle("iQMC") -def iqmc_update_source(mcdc): - iqmc = mcdc["technique"]["iqmc"] - keff = mcdc["k_eff"] - scatter = iqmc["score"]["effective-scattering"]["bin"] - fixed = iqmc["fixed_source"] - if mcdc["setting"]["mode_eigenvalue"]: - fission = iqmc["score"]["effective-fission-outter"] - else: - fission = iqmc["score"]["effective-fission"]["bin"] - iqmc["source"] = scatter + (fission / keff) + fixed - - -@toggle("iQMC") -def iqmc_tilt_source(t, x, y, z, P_arr, Q, mcdc): - P = P_arr[0] - iqmc = mcdc["technique"]["iqmc"] - score_list = iqmc["score_list"] - score_bin = iqmc["score"] - mesh = iqmc["mesh"] - dx = mesh["x"][x + 1] - mesh["x"][x] - dy = mesh["y"][y + 1] - mesh["y"][y] - dz = mesh["z"][z + 1] - mesh["z"][z] - x_mid = mesh["x"][x] + (0.5 * dx) - y_mid = mesh["y"][y] + (0.5 * dy) - z_mid = mesh["z"][z] + (0.5 * dz) - # linear x-component - if score_list["source-x"]: - Q += score_bin["source-x"]["bin"][:, t, x, y, z] * (P["x"] - x_mid) - # linear y-component - if score_list["source-y"]: - Q += score_bin["source-y"]["bin"][:, t, x, y, z] * (P["y"] - y_mid) - # linear z-component - if score_list["source-z"]: - Q += score_bin["source-z"]["bin"][:, t, x, y, z] * (P["z"] - z_mid) - - -@toggle("iQMC") -def iqmc_distribute_sources(mcdc): - """ - This function is meant to distribute iqmc_total_source to the relevant - invidual source contributions, e.x. source_total -> source, source-x, - source-y, source-z, etc. - - """ - iqmc = mcdc["technique"]["iqmc"] - total_source = iqmc["total_source"].copy() - shape = iqmc["source"].shape - size = iqmc["source"].size - score_list = iqmc["score_list"] - score_bin = iqmc["score"] - Vsize = 0 - - # effective source - iqmc["source"] = np.reshape(total_source[Vsize : (Vsize + size)].copy(), shape) - Vsize += size - - # source tilting arrays - tilt_list = [ - "source-x", - "source-y", - "source-z", - ] - for name in literal_unroll(tilt_list): - if score_list[name]: - score_bin[name]["bin"] = np.reshape( - total_source[Vsize : (Vsize + size)], shape - ) - Vsize += size - - -@toggle("iQMC") -def iqmc_consolidate_sources(mcdc): - """ - This function is meant to collect the relevant invidual source - contributions, e.x. source, source-x, source-y, source-z, source-xy, etc. - and combine them into one vector (source_total) - - """ - iqmc = mcdc["technique"]["iqmc"] - total_source = iqmc["total_source"] - size = iqmc["source"].size - score_list = iqmc["score_list"] - score_bin = iqmc["score"] - Vsize = 0 - - # effective source - total_source[Vsize : (Vsize + size)] = np.reshape(iqmc["source"].copy(), size) - Vsize += size - - # source tilting arrays - tilt_list = [ - "source-x", - "source-y", - "source-z", - ] - for name in literal_unroll(tilt_list): - if score_list[name]: - total_source[Vsize : (Vsize + size)] = np.reshape( - score_bin[name]["bin"], size - ) - Vsize += size - - -# ============================================================================= -# Tally Operations -# ============================================================================= -# TODO: Not all ST tallies have been built for case where SigmaT = 0.0 - - -@toggle("iQMC") -def iqmc_score_tallies(P_arr, distance, mcdc): - """ - Tally the scalar flux and linear source tilt. - - """ - P = P_arr[0] - iqmc = mcdc["technique"]["iqmc"] - score_list = iqmc["score_list"] - score_bin = iqmc["score"] - # Get indices - mesh = iqmc["mesh"] - material = mcdc["materials"][P["material_ID"]] - w = P["iqmc"]["w"] - SigmaT = material["total"] - mat_id = P["material_ID"] - - x, y, z, t, outside = mesh_.structured.get_indices(P_arr, mesh) - if outside: - return - - dt = dx = dy = dz = 1.0 - if (mesh["t"][t] != -INF) and (mesh["t"][t] != INF): - dt = mesh["t"][t + 1] - mesh["t"][t] - if (mesh["x"][x] != -INF) and (mesh["x"][x] != INF): - dx = mesh["x"][x + 1] - mesh["x"][x] - if (mesh["y"][y] != -INF) and (mesh["y"][y] != INF): - dy = mesh["y"][y + 1] - mesh["y"][y] - if (mesh["z"][z] != -INF) and (mesh["z"][z] != INF): - dz = mesh["z"][z + 1] - mesh["z"][z] - - dV = dx * dy * dz * dt - - flux = iqmc_flux(SigmaT, w, distance, dV) - score_bin["flux"]["bin"][:, t, x, y, z] += flux - - # Score effective source tallies - score_bin["effective-scattering"]["bin"][ - :, t, x, y, z - ] += iqmc_effective_scattering(flux, mat_id, mcdc) - score_bin["effective-fission"]["bin"][:, t, x, y, z] += iqmc_effective_fission( - flux, mat_id, mcdc - ) - - if score_list["fission-source"]: - score_bin["fission-source"]["bin"] += iqmc_fission_source(flux, material) - - if score_list["fission-power"]: - score_bin["fission-power"]["bin"][:, t, x, y, z] += iqmc_fission_power( - flux, material - ) - - if score_list["source-x"]: - x_mid = mesh["x"][x] + (dx * 0.5) - tilt = iqmc_linear_tilt(P["ux"], P["x"], dx, x_mid, dy, dz, w, distance, SigmaT) - score_bin["source-x"]["bin"][:, t, x, y, z] += iqmc_effective_source( - tilt, mat_id, mcdc - ) - - if score_list["source-y"]: - y_mid = mesh["y"][y] + (dy * 0.5) - tilt = iqmc_linear_tilt(P["uy"], P["y"], dy, y_mid, dx, dz, w, distance, SigmaT) - score_bin["source-y"]["bin"][:, t, x, y, z] += iqmc_effective_source( - tilt, mat_id, mcdc - ) - - if score_list["source-z"]: - z_mid = mesh["z"][z] + (dz * 0.5) - tilt = iqmc_linear_tilt(P["uz"], P["z"], dz, z_mid, dx, dy, w, distance, SigmaT) - score_bin["source-z"]["bin"][:, t, x, y, z] += iqmc_effective_source( - tilt, mat_id, mcdc - ) - - -@toggle("iQMC") -def iqmc_flux(SigmaT, w, distance, dV): - # Score Flux - if SigmaT.all() > 0.0: - return w * (1 - np.exp(-(distance * SigmaT))) / (SigmaT * dV) - else: - return distance * w / dV - - -@toggle("iQMC") -def iqmc_fission_source(phi, material): - SigmaF = material["fission"] - nu_f = material["nu_f"] - return np.sum(nu_f * SigmaF * phi) - - -@toggle("iQMC") -def iqmc_fission_power(phi, material): - SigmaF = material["fission"] - return SigmaF * phi - - -@toggle("iQMC") -def iqmc_effective_fission(phi, mat_id, mcdc): - """ - Calculate the fission source for use with iQMC. - - """ - # TODO: Now, only single-nuclide material is allowed - material = mcdc["nuclides"][mat_id] - chi_p = material["chi_p"] - chi_d = material["chi_d"] - nu_p = material["nu_p"] - nu_d = material["nu_d"] - SigmaF = material["fission"] - F_p = np.dot(chi_p.T, nu_p * SigmaF * phi) - F_d = np.dot(chi_d.T, (nu_d.T * SigmaF * phi).sum(axis=1)) - F = F_p + F_d - - return F - - -@toggle("iQMC") -def iqmc_effective_scattering(phi, mat_id, mcdc): - """ - Calculate the scattering source for use with iQMC. - - """ - material = mcdc["materials"][mat_id] - chi_s = material["chi_s"] - SigmaS = material["scatter"] - return np.dot(chi_s.T, SigmaS * phi) - - -@toggle("iQMC") -def iqmc_effective_source(phi, mat_id, mcdc): - S = iqmc_effective_scattering(phi, mat_id, mcdc) - F = iqmc_effective_fission(phi, mat_id, mcdc) - return S + F - - -@toggle("iQMC") -def iqmc_linear_tilt(mu, x, dx, x_mid, dy, dz, w, distance, SigmaT): - if SigmaT.all() > 1e-12: - a = mu * ( - w * (1 - (1 + distance * SigmaT) * np.exp(-SigmaT * distance)) / SigmaT**2 - ) - b = (x - x_mid) * (w * (1 - np.exp(-SigmaT * distance)) / SigmaT) - Q = 12 * (a + b) / (dx**3 * dy * dz) - else: - Q = mu * w * distance ** (2) / 2 + w * (x - x_mid) * distance - return Q - - -@toggle("iQMC") -def iqmc_reset_tallies(iqmc): - score_bin = iqmc["score"] - score_list = iqmc["score_list"] - - iqmc["source"].fill(0.0) - for name in literal_unroll(iqmc_score_list): - if score_list[name]: - score_bin[name]["bin"].fill(0.0) - - -@toggle("iQMC") -def iqmc_reduce_tallies(iqmc): - score_bin = iqmc["score"] - score_list = iqmc["score_list"] - - for name in literal_unroll(iqmc_score_list): - if score_list[name]: - allreduce_array(score_bin[name]["bin"]) - - -# ============================================================================= -# Tally History Operations -# ============================================================================= - - -@toggle("iQMC") -def iqmc_tally_closeout_history(mcdc): - iqmc = mcdc["technique"]["iqmc"] - score_bin = iqmc["score"] - score_list = iqmc["score_list"] - - for name in literal_unroll(iqmc_score_list): - if score_list[name]: - score_bin[name]["mean"] += score_bin[name]["bin"] - score_bin[name]["sdev"] += np.square(score_bin[name]["bin"]) - - -@toggle("iQMC") -def iqmc_tally_closeout(mcdc): - iqmc = mcdc["technique"]["iqmc"] - score_bin = iqmc["score"] - score_list = iqmc["score_list"] - - if iqmc["mode"] == "fixed": - for name in literal_unroll(iqmc_score_list): - if score_list[name]: - score_bin[name]["mean"] = score_bin[name]["bin"] - - if iqmc["mode"] == "batched": - N_history = mcdc["setting"]["N_active"] - for name in literal_unroll(iqmc_score_list): - if score_list[name]: - score_bin[name]["mean"] /= N_history - allreduce_array(score_bin[name]["sdev"]) - score_bin[name]["sdev"] = np.sqrt( - ( - score_bin[name]["sdev"] / N_history - - np.square(score_bin[name]["mean"]) - ) - / (N_history - 1) - ) - - -@toggle("iQMC") -def iqmc_eigenvalue_tally_closeout_history(mcdc): - idx_cycle = mcdc["idx_cycle"] - - # store outter iteration values - mcdc["k_cycle"][idx_cycle] = mcdc["k_eff"] - - # Accumulate running average - if mcdc["cycle_active"]: - mcdc["k_avg"] += mcdc["k_eff"] - mcdc["k_sdv"] += mcdc["k_eff"] * mcdc["k_eff"] - N = mcdc["idx_cycle"] - mcdc["setting"]["N_inactive"] - mcdc["k_avg_running"] = mcdc["k_avg"] / N - if N == 1: - mcdc["k_sdv_running"] = 0.0 - else: - mcdc["k_sdv_running"] = math.sqrt( - (mcdc["k_sdv"] / N - mcdc["k_avg_running"] ** 2) / (N - 1) - ) - - -# ============================================================================= -# Misc -# ============================================================================= - - -@toggle("iQMC") -def iqmc_res(source_new, source_old): - """ - Calculate residual between iterations. - - """ - size = source_new.size - source_new = np.linalg.norm(source_new.reshape((size,)), ord=2) - source_old = np.linalg.norm(source_old.reshape((size,)), ord=2) - return (source_new - source_old) / source_old diff --git a/mcdc/iqmc/iqmc_loop.py b/mcdc/iqmc/iqmc_loop.py deleted file mode 100644 index 0ef238bba..000000000 --- a/mcdc/iqmc/iqmc_loop.py +++ /dev/null @@ -1,470 +0,0 @@ -import numpy as np - -from numpy import ascontiguousarray as cga -from numba import njit, objmode - -import mcdc.adapt as adapt -import mcdc.iqmc.iqmc_kernel as iqmc_kernel -import mcdc.kernel as kernel -import mcdc.src.geometry as geometry -import mcdc.type_ as type_ - -from mcdc.constant import * -from mcdc.print_ import ( - print_error, - print_iqmc_eigenvalue_exit_code, - print_iqmc_eigenvalue_progress, - print_msg, - print_progress, - print_progress_iqmc, -) -from mcdc.type_ import iqmc_score_list - - -# ========================================================================= -# Validate inputs -# ========================================================================= - - -def iqmc_validate_inputs(input_deck): - iqmc = input_deck.technique["iqmc"] - eigenmode = input_deck.setting["mode_eigenvalue"] - - # Batched mode has only been built for eigenvalue problems (so far) - if iqmc["mode"] == "batched" and not eigenmode: - print_error( - "Invalid run mode. iQMC batched mode has not been built for fixed source problems." - ) - - # Check fixed source solver - if iqmc["fixed_source_solver"] not in ["source iteration", "gmres"]: - print_error( - f"Invalid fixed source solver, '{iqmc['fixed_source_solver']}'. Available iteration solvers inlcude ['source iteration', 'gmres']" - ) - - # Check sample method - if iqmc["sample_method"] not in ["random", "halton"]: - print_error( - f"Unsupported sample method, '{iqmc['sample_method']}'. Available sample methods: ['halton', 'random']." - ) - - # Check run mode - if iqmc["mode"] not in ["fixed", "batched"]: - with objmode(): - print_error( - f"Unsupported run mode, '{iqmc['mode']}'. Available iQMC modes are ['fixed', 'batched']" - ) - - # Check scores - for score in list(iqmc["score_list"].keys()): - if score not in iqmc_score_list: - print_error( - f"Unsupported score, '{score}'. Available iQMC scores are {iqmc_score_list}" - ) - - # Check N_inactive & N_active batches for batched mode - if eigenmode and iqmc["mode"] == "batched": - if ( - input_deck.setting["N_inactive"] == 0 - and input_deck.setting["N_active"] == 0 - ): - print_error( - "Specify N_inactive and N_active batches for iQMC batched mode." - ) - - -# ============================================================================= -# iQMC Simulation -# ============================================================================= - - -@njit -def iqmc_simulation(mcdc_arr): - # Ensure `mcdc` exists for the lifetime of the program - # by intentionally leaking their memory - adapt.leak(mcdc_arr) - mcdc = mcdc_arr[0] - - # Preprocessing - iqmc = mcdc["technique"]["iqmc"] - iqmc_kernel.iqmc_preprocess(mcdc) - iqmc_kernel.samples_init(mcdc) - - if iqmc["mode"] == "batched": - iqmc["iterations_max"] = ( - mcdc["setting"]["N_active"] + mcdc["setting"]["N_inactive"] - 1 - ) - - # Iterative Solve - if mcdc["setting"]["mode_eigenvalue"]: - power_iteration(mcdc) - else: - if iqmc["fixed_source_solver"] == "source iteration": - source_iteration(mcdc) - if iqmc["fixed_source_solver"] == "gmres": - gmres(mcdc) - - # Post processing - iqmc_kernel.iqmc_tally_closeout(mcdc) - - -# ============================================================================= -# Iterative Solvers -# ============================================================================= - - -@njit -def source_iteration(mcdc): - simulation_end = False - iqmc = mcdc["technique"]["iqmc"] - total_source_old = iqmc["total_source"].copy() - - while not simulation_end: - iqmc_sweep(mcdc) - iqmc["iteration_count"] += 1 - # calculate norm of sources - iqmc["residual"] = iqmc_kernel.iqmc_res(iqmc["total_source"], total_source_old) - # iQMC convergence criteria - if (iqmc["iteration_count"] == iqmc["iterations_max"]) or ( - iqmc["residual"] <= iqmc["tol"] - ): - simulation_end = True - - # Print progress - if not mcdc["setting"]["mode_eigenvalue"]: - with objmode(): - print_progress_iqmc(mcdc) - - # set source_old = current source - total_source_old = iqmc["total_source"].copy() - - -@njit -def power_iteration(mcdc): - simulation_end = False - iqmc = mcdc["technique"]["iqmc"] - tol = iqmc["tol"] - maxit = iqmc["iterations_max"] - score_bin = iqmc["score"] - k_old = mcdc["k_eff"] - fission_source_old = score_bin["fission-source"]["bin"].copy() - - while not simulation_end: - # Scramble samples if in batched mode - if iqmc["mode"] == "batched": - iqmc_kernel.scramble_samples(mcdc) - # Run sweep - iqmc_sweep(mcdc) - # Reset counter for inner iteration - iqmc["iteration_count"] += 1 - # Update k_eff - mcdc["k_eff"] *= score_bin["fission-source"]["bin"][0] / fission_source_old[0] - # Calculate diff in keff - iqmc["residual"] = abs(mcdc["k_eff"] - k_old) / k_old - k_old = mcdc["k_eff"] - # Store outter iteration values - score_bin["effective-fission-outter"] = score_bin["effective-fission"][ - "bin" - ].copy() - fission_source_old = score_bin["fission-source"]["bin"].copy() - - # Batch mode - if iqmc["mode"] == "batched": - mcdc["idx_cycle"] += 1 - iqmc_kernel.iqmc_eigenvalue_tally_closeout_history(mcdc) - if mcdc["cycle_active"]: - # Only accumulate statistics - iqmc_kernel.iqmc_tally_closeout_history(mcdc) - # Entering active cycle ? - if mcdc["idx_cycle"] >= mcdc["setting"]["N_inactive"]: - mcdc["cycle_active"] = True - - # Print progress - with objmode(): - if iqmc["mode"] == "fixed": - print_iqmc_eigenvalue_progress(mcdc) - else: - print_iqmc_eigenvalue_progress(mcdc) - - # iQMC convergence criteria - if (iqmc["iteration_count"] == maxit) or (iqmc["residual"] <= tol): - simulation_end = True - if iqmc["mode"] == "fixed": - with objmode(): - print_iqmc_eigenvalue_exit_code(mcdc) - - -@njit -def gmres(mcdc): - """ - GMRES solver. - ---------- - Linear Krylov solver. Solves problem of the form Ax = b. - This function is almost entirely linear algebra operations and does not - directly use any functions in mcdc/kernel.py or mcdc/loop.py - - References - ---------- - .. [1] Yousef Saad, "Iterative Methods for Sparse Linear Systems, - Second Edition", SIAM, pp. 151-172, pp. 272-275, 2003 - http://www-users.cs.umn.edu/~saad/books.html - .. [2] C. T. Kelley, http://www4.ncsu.edu/~ctk/matlab_roots.html - - code adapted from: https://github.com/pygbe/pygbe/blob/master/pygbe/gmres.py - - """ - iqmc = mcdc["technique"]["iqmc"] - max_iter = iqmc["iterations_max"] - R = iqmc["krylov_restart"] - tol = iqmc["tol"] - - fixed_source = iqmc["fixed_source"] - single_vector = iqmc["fixed_source"].size - b = np.zeros_like(iqmc["total_source"]) - b[:single_vector] = np.reshape(fixed_source, fixed_source.size) - X = iqmc["total_source"].copy() - # initial residual - r = b - AxV(X, b, mcdc) - normr = np.linalg.norm(r) - - # Defining dimension - dimen = X.size - # Set number of outer and inner iterations - if R > dimen: - # set number of outter iterations to max allowable (A.shape[0]) - R = dimen - max_inner = R - xtype = np.float64 - - # max_outer should be max_iter/max_inner but this might not be an integer - # so we get the ceil of the division. - # In the inner loop there is a if statement to break in case max_iter is - # reached. - max_outer = int(np.ceil(max_iter / max_inner)) - - # Check initial guess ( scaling by b, if b != 0, must account for - # case when norm(b) is very small) - normb = np.linalg.norm(b) - if normb == 0.0: - normb = 1.0 - if normr < tol * normb: - return X, 0 - - iteration = 0 - - # GMRES starts here - for outer in range(max_outer): - # Preallocate for Givens Rotations, Hessenberg matrix and Krylov Space - Q = [] - H = np.zeros((max_inner + 1, max_inner + 1), dtype=xtype) - V = np.zeros((max_inner + 1, dimen), dtype=xtype) - - # vs store the pointers to each column of V. - # This saves a considerable amount of time. - vs = [] - V[0, :] = (1.0 / normr) * r - vs.append(V[0, :]) - - # Saving initial residual to be used to calculate the rel_resid - if iteration == 0: - res_0 = normb - - # RHS vector in the Krylov space - g = np.zeros((dimen,), dtype=xtype) - g[0] = normr - - for inner in range(max_inner): - # New search direction - v = V[inner + 1, :] - v[:] = AxV(vs[-1], b, mcdc) - vs.append(v) - - # Modified Gram Schmidt - for k in range(inner + 1): - vk = vs[k] - alpha = np.dot(vk, v) - H[inner, k] = alpha - v[:] = vk * (-alpha) + v[:] - - normv = np.linalg.norm(v) - H[inner, inner + 1] = normv - - # Check for breakdown - if H[inner, inner + 1] != 0.0: - v[:] = (1.0 / H[inner, inner + 1]) * v - - # Apply for Givens rotations to H - if inner > 0: - for j in range(inner): - Qloc = Q[j] - H[inner, :][j : j + 2] = np.dot(Qloc, H[inner, :][j : j + 2]) - - # Calculate and apply next complex-valued Givens rotations - - # If max_inner = dimen, we don't need to calculate, this - # is unnecessary for the last inner iteration when inner = dimen -1 - if inner != dimen - 1: - if H[inner, inner + 1] != 0: - # Caclulate matrix rotations - c, s, _ = kernel.lartg(H[inner, inner], H[inner, inner + 1]) - Qblock = np.array([[c, s], [-np.conjugate(s), c]], dtype=xtype) - Q.append(Qblock) - - # Apply Givens Rotations to RHS for the linear system in - # the krylov space. - g[inner : inner + 2] = np.dot(Qblock, g[inner : inner + 2]) - - # Apply Givens rotations to H - H[inner, inner] = np.dot(Qblock[0, :], H[inner, inner : inner + 2]) - H[inner, inner + 1] = 0.0 - - iteration += 1 - - if inner < max_inner - 1: - normr = abs(g[inner + 1]) - rel_resid = normr / res_0 - iqmc["residual"] = rel_resid - - iqmc["iteration_count"] += 1 - if not mcdc["setting"]["mode_eigenvalue"]: - with objmode(): - print_progress_iqmc(mcdc) - - if rel_resid < tol: - break - if iqmc["iteration_count"] >= max_iter: - break - - # end inner loop, back to outer loop - # Find best update to X in Krylov Space V. Solve inner X inner system. - y = np.linalg.solve(H[0 : inner + 1, 0 : inner + 1].T, g[0 : inner + 1]) - update = np.ravel(np.dot(cga(V[: inner + 1, :].T), y.reshape(-1, 1))) - X = X + update - aux = AxV(X, b, mcdc) - r = b - aux - normr = np.linalg.norm(r) - rel_resid = normr / res_0 - iqmc["residual"] = rel_resid - if rel_resid < tol: - break - if iqmc["iteration_count"] >= max_iter: - return - - -# ============================================================================= -# Lower Level loops -# ============================================================================= - - -@njit -def iqmc_loop_particle(P_arr, prog): - mcdc = adapt.mcdc_global(prog) - P = P_arr[0] - while P["alive"]: - iqmc_step_particle(P_arr, prog) - - -@njit -def iqmc_step_particle(P_arr, prog): - mcdc = adapt.mcdc_global(prog) - P = P_arr[0] - - # Determine and move to event - iqmc_kernel.iqmc_move_to_event(P_arr, mcdc) - event = P["event"] - - # The & operator here is a bitwise and. - # It is used to determine if an event type is part of the particle event. - - # Surface crossing - if event & EVENT_SURFACE_CROSSING: - iqmc_kernel.iqmc_surface_crossing(P_arr, prog) - if event & EVENT_DOMAIN_CROSSING: - if not ( - mcdc["surfaces"][P["surface_ID"]]["BC"] == BC_REFLECTIVE - or mcdc["surfaces"][P["surface_ID"]]["BC"] == BC_VACUUM - ): - kernel.domain_crossing(P_arr, mcdc) - - # Lattice or mesh crossing (skipped if surface crossing) - elif event & EVENT_LATTICE_CROSSING or event & EVENT_IQMC_MESH: - if event & EVENT_DOMAIN_CROSSING: - kernel.domain_crossing(P_arr, mcdc) - - # Apply weight roulette - if P["alive"] and mcdc["technique"]["weight_roulette"]: - # check if weight has fallen below threshold - if abs(P["w"]) <= mcdc["technique"]["wr_threshold"]: - kernel.weight_roulette(P_arr, mcdc) - - -@njit -def iqmc_loop_source(mcdc): - work_size = mcdc["bank_source"]["size"][0] - N_prog = 0 - # loop over particles - for idx_work in range(work_size): - P_arr = mcdc["bank_source"]["particles"][idx_work : (idx_work + 1)] - P = P_arr[0] - mcdc["bank_source"]["size"] -= 1 - kernel.add_particle(P_arr, mcdc["bank_active"]) - - # Loop until active bank is exhausted - while mcdc["bank_active"]["size"] > 0: - P_arr = adapt.local_array(1, type_.particle) - P = P_arr[0] - # Get particle from active bank - kernel.get_particle(P_arr, mcdc["bank_active"], mcdc) - # Particle loop - iqmc_loop_particle(P_arr, mcdc) - - # Progress printout - percent = (idx_work + 1.0) / work_size - if mcdc["setting"]["progress_bar"] and int(percent * 100.0) > N_prog: - N_prog += 1 - with objmode(): - print_progress(percent, mcdc) - - -@njit -def iqmc_sweep(mcdc): - iqmc = mcdc["technique"]["iqmc"] - # tally sweep count - iqmc["sweep_count"] += 1 - # reset particle bank size - kernel.set_bank_size(mcdc["bank_source"], 0) - # initialize particles with LDS - iqmc_kernel.iqmc_prepare_particles(mcdc) - # reset tallies for next loop - iqmc_kernel.iqmc_reset_tallies(iqmc) - # sweep particles - iqmc_loop_source(mcdc) - # sum resultant flux on all processors - iqmc_kernel.iqmc_reduce_tallies(iqmc) - # update source = scattering + fission/keff + fixed - iqmc_kernel.iqmc_update_source(mcdc) - # combine source tallies into one vector - iqmc_kernel.iqmc_consolidate_sources(mcdc) - - -# ============================================================================= -# GMRES Linear operator -# ============================================================================= - - -@njit -def AxV(V, b, mcdc): - """ - Linear operator to be used with GMRES. - Calculate action of A on input vector V, where A is a transport sweep - and V is the total source (constant and tilted). - """ - iqmc = mcdc["technique"]["iqmc"] - iqmc["total_source"] = V.copy() - # distribute segments of V to appropriate sources - iqmc_kernel.iqmc_distribute_sources(mcdc) - iqmc_sweep(mcdc) - v_out = iqmc["total_source"].copy() - axv = V - (v_out - b) - - return axv diff --git a/mcdc/kernel.py b/mcdc/kernel.py deleted file mode 100644 index e80c74b18..000000000 --- a/mcdc/kernel.py +++ /dev/null @@ -1,4206 +0,0 @@ -import h5py, math, numba - -from mpi4py import MPI -from numba import ( - int64, - literal_unroll, - njit, - objmode, - uint64, -) - -import mcdc.adapt as adapt -import mcdc.src.geometry as geometry -import mcdc.src.mesh as mesh_ -import mcdc.src.physics as physics -import mcdc.src.surface as surface_ -import mcdc.type_ as type_ - -from mcdc.adapt import toggle, for_cpu, for_gpu -from mcdc.constant import * -from mcdc.print_ import print_error, print_msg -from mcdc.src.algorithm import binary_search, binary_search_with_length - -import cffi - -ffi = cffi.FFI() - - -@njit -def round(float_val): - return float_val - # int_val = np.float64(float_val).view(np.uint64) - # if (int_val & 0x10) != 0: - # int_val += 0x10 - # int_val = int_val & ~0x0F - # return np.uint64(int_val).view(np.float64) - - -# ============================================================================= -# Domain Decomposition -# ============================================================================= - -# ============================================================================= -# Domain crossing event -# ============================================================================= - - -@toggle("domain_decomp") -def domain_crossing(P_arr, prog): - mcdc = adapt.mcdc_global(prog) - P = P_arr[0] - # Domain mesh crossing - seed = P["rng_seed"] - max_size = mcdc["technique"]["dd_exchange_rate"] - if mcdc["technique"]["domain_decomposition"]: - mesh = mcdc["technique"]["dd_mesh"] - # Determine which dimension is crossed - ix, iy, iz, it, outside = mesh_.structured.get_indices(P_arr, mesh) - - d_idx = mcdc["dd_idx"] - d_Nx = mcdc["technique"]["dd_mesh"]["x"].size - 1 - d_Ny = mcdc["technique"]["dd_mesh"]["y"].size - 1 - d_Nz = mcdc["technique"]["dd_mesh"]["z"].size - 1 - - d_iz = int(d_idx / (d_Nx * d_Ny)) - d_iy = int((d_idx - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(d_idx - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - flag = MESH_NONE - if d_ix != ix: - flag = MESH_X - elif d_iy != iy: - flag = MESH_Y - elif d_iz != iz: - flag = MESH_Z - - # Score on tally - if flag == MESH_X and P["ux"] > 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_xp"]) - if get_bank_size(mcdc["domain_decomp"]["bank_xp"]) == max_size: - dd_initiate_particle_send(prog) - if flag == MESH_X and P["ux"] < 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_xn"]) - if get_bank_size(mcdc["domain_decomp"]["bank_xn"]) == max_size: - dd_initiate_particle_send(prog) - if flag == MESH_Y and P["uy"] > 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_yp"]) - if get_bank_size(mcdc["domain_decomp"]["bank_yp"]) == max_size: - dd_initiate_particle_send(prog) - if flag == MESH_Y and P["uy"] < 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_yn"]) - if get_bank_size(mcdc["domain_decomp"]["bank_yn"]) == max_size: - dd_initiate_particle_send(prog) - if flag == MESH_Z and P["uz"] > 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_zp"]) - if get_bank_size(mcdc["domain_decomp"]["bank_zp"]) == max_size: - dd_initiate_particle_send(prog) - if flag == MESH_Z and P["uz"] < 0: - add_particle(P_arr, mcdc["domain_decomp"]["bank_zn"]) - if get_bank_size(mcdc["domain_decomp"]["bank_zn"]) == max_size: - dd_initiate_particle_send(prog) - P["alive"] = False - - -# ============================================================================= -# Send full domain bank -# ============================================================================= - - -requests = [] - - -def save_request(req_pair): - global requests - - updated_requests = [] - - status = MPI.Status() - for req, buf in requests: - if not req.Test(status): - updated_requests.append((req, buf)) - - updated_requests.append(req_pair) - requests = updated_requests - - -def clear_requests(): - global requests - for req, buf in requests: - req.Free() - - requests = [] - - -@njit -def dd_check_halt(mcdc): - return mcdc["domain_decomp"]["work_done"] - - -@njit -def dd_check_in(mcdc): - mcdc["domain_decomp"]["send_count"] = 0 - mcdc["domain_decomp"]["recv_count"] = 0 - mcdc["domain_decomp"]["send_total"] = 0 - mcdc["domain_decomp"]["rank_busy"] = True - - with objmode(rank="int64", total="int64"): - rank = MPI.COMM_WORLD.Get_rank() - total = MPI.COMM_WORLD.Get_size() - - if rank == 0: - mcdc["domain_decomp"]["busy_total"] = total - else: - mcdc["domain_decomp"]["busy_total"] = 0 - - -@njit -def dd_check_out(mcdc): - with objmode(): - rank = MPI.COMM_WORLD.Get_rank() - send_count = mcdc["domain_decomp"]["send_count"] - recv_count = mcdc["domain_decomp"]["recv_count"] - send_total = mcdc["domain_decomp"]["send_total"] - busy_total = mcdc["domain_decomp"]["busy_total"] - rank_busy = mcdc["domain_decomp"]["rank_busy"] - - if send_count != 0: - print( - f"Domain decomposed loop closed out with non-zero send count {send_count} in rank {rank}" - ) - mcdc["domain_decomp"]["send_count"] = 0 - - if recv_count != 0: - print( - f"Domain decomposed loop closed out with non-zero recv count {recv_count} in rank {rank}" - ) - mcdc["domain_decomp"]["recv_count"] = 0 - - if send_total != 0: - print( - f"Domain decomposed loop closed out with non-zero send total {send_total} in rank {rank}" - ) - mcdc["domain_decomp"]["send_total"] = 0 - - if busy_total != 0: - print( - f"Domain decomposed loop closed out with non-zero busy total {busy_total} in rank {rank}" - ) - mcdc["domain_decomp"]["busy_total"] = 0 - - if rank_busy: - print( - f"Domain decomposed loop closed out with rank {rank} still marked as busy" - ) - mcdc["domain_decomp"]["rank_busy"] = 0 - - clear_requests() - - -@njit -def dd_signal_halt(mcdc): - - with objmode(): - for rank in range(1, MPI.COMM_WORLD.Get_size()): - dummy_buff = np.zeros((1,), dtype=np.int32) - MPI.COMM_WORLD.Send(dummy_buff, dest=rank, tag=3) - - mcdc["domain_decomp"]["work_done"] = True - - -@njit -def dd_signal_block(mcdc): - - with objmode(rank="int64"): - rank = MPI.COMM_WORLD.Get_rank() - - send_delta = ( - mcdc["domain_decomp"]["send_count"] - mcdc["domain_decomp"]["recv_count"] - ) - if rank == 0: - mcdc["domain_decomp"]["send_total"] += send_delta - mcdc["domain_decomp"]["busy_total"] -= 1 - else: - with objmode(): - buff = np.zeros((1,), dtype=type_.dd_turnstile_event) - buff[0]["busy_delta"] = -1 - buff[0]["send_delta"] = send_delta - req = MPI.COMM_WORLD.Isend( - [buff, type_.dd_turnstile_event_mpi], dest=0, tag=2 - ) - save_request((req, buff)) - - mcdc["domain_decomp"]["send_count"] = 0 - mcdc["domain_decomp"]["recv_count"] = 0 - - if ( - (rank == 0) - and (mcdc["domain_decomp"]["busy_total"] == 0) - and (mcdc["domain_decomp"]["send_total"] == 0) - ): - dd_signal_halt(mcdc) - - -@njit -def dd_signal_unblock(mcdc): - - with objmode(rank="int64"): - rank = MPI.COMM_WORLD.Get_rank() - - send_delta = ( - mcdc["domain_decomp"]["send_count"] - mcdc["domain_decomp"]["recv_count"] - ) - - if rank == 0: - mcdc["domain_decomp"]["send_total"] += send_delta - mcdc["domain_decomp"]["busy_total"] += 1 - if (mcdc["domain_decomp"]["busy_total"] == 0) and ( - mcdc["domain_decomp"]["send_total"] == 0 - ): - dd_signal_halt(mcdc) - else: - with objmode(): - buff = np.zeros((1,), dtype=type_.dd_turnstile_event) - buff[0]["busy_delta"] = 1 - buff[0]["send_delta"] = send_delta - req = MPI.COMM_WORLD.Isend( - [buff, type_.dd_turnstile_event_mpi], dest=0, tag=2 - ) - save_request((req, buff)) - mcdc["domain_decomp"]["send_count"] = 0 - mcdc["domain_decomp"]["recv_count"] = 0 - - -@njit -def dd_distribute_bank(mcdc, bank, dest_list): - - with objmode(send_delta="int64"): - dest_count = len(dest_list) - send_delta = 0 - - for i, dest in enumerate(dest_list): - size = get_bank_size(bank) - ratio = int(size / dest_count) - start = ratio * i - end = start + ratio - if i == dest_count - 1: - end = size - sub_bank = np.array(bank["particles"][start:end]) - if sub_bank.shape[0] > 0: - req = MPI.COMM_WORLD.Isend( - [sub_bank, type_.particle_record_mpi], dest=dest, tag=1 - ) - save_request((req, sub_bank)) - send_delta += end - start - - mcdc["domain_decomp"]["send_count"] += send_delta - set_bank_size(bank, 0) - - -@for_gpu() -def dd_initiate_particle_send(prog): - adapt.halt_early(prog) - - -@for_cpu() -def dd_initiate_particle_send(prog): - dd_particle_send(prog) - - -@njit -def dd_particle_send(prog): - mcdc = adapt.mcdc_global(prog) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_xp"], mcdc["technique"]["dd_xp_neigh"] - ) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_xn"], mcdc["technique"]["dd_xn_neigh"] - ) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_yp"], mcdc["technique"]["dd_yp_neigh"] - ) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_yn"], mcdc["technique"]["dd_yn_neigh"] - ) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_zp"], mcdc["technique"]["dd_zp_neigh"] - ) - dd_distribute_bank( - mcdc, mcdc["domain_decomp"]["bank_zn"], mcdc["technique"]["dd_zn_neigh"] - ) - - -# ============================================================================= -# Receive particles and clear banks -# ============================================================================= - - -@njit -def dd_get_recv_tag(): - - with objmode(tag="int64"): - status = MPI.Status() - MPI.COMM_WORLD.Probe(status=status) - tag = status.Get_tag() - - return tag - - -@njit -def dd_recv_particles(mcdc): - - buff = np.zeros( - mcdc["domain_decomp"]["bank_zp"]["particles"].shape[0], - dtype=type_.particle_record, - ) - - with objmode(size="int64"): - status = MPI.Status() - MPI.COMM_WORLD.Recv([buff, type_.particle_record_mpi], status=status) - size = status.Get_count(type_.particle_record_mpi) - rank = MPI.COMM_WORLD.Get_rank() - - mcdc["domain_decomp"]["recv_count"] += size - - # Set source bank from buffer - for i in range(size): - add_particle(buff[i : i + 1], mcdc["bank_active"]) - - if ( - mcdc["domain_decomp"]["recv_count"] > 0 - and not mcdc["domain_decomp"]["rank_busy"] - ): - dd_signal_unblock(mcdc) - mcdc["domain_decomp"]["rank_busy"] = True - - -@njit -def dd_recv_turnstile(mcdc): - - with objmode(busy_delta="int64", send_delta="int64"): - event_buff = np.zeros((1,), dtype=type_.dd_turnstile_event) - MPI.COMM_WORLD.Recv([event_buff, type_.dd_turnstile_event_mpi]) - busy_delta = event_buff[0]["busy_delta"] - send_delta = event_buff[0]["send_delta"] - rank = MPI.COMM_WORLD.Get_rank() - busy_total = mcdc["domain_decomp"]["busy_total"] - send_total = mcdc["domain_decomp"]["send_total"] - - mcdc["domain_decomp"]["busy_total"] += busy_delta - mcdc["domain_decomp"]["send_total"] += send_delta - - if (mcdc["domain_decomp"]["busy_total"] == 0) and ( - mcdc["domain_decomp"]["send_total"] == 0 - ): - dd_signal_halt(mcdc) - - -@njit -def dd_recv_halt(mcdc): - - with objmode(): - dummy_buff = np.zeros((1,), dtype=np.int32) - MPI.COMM_WORLD.Recv(dummy_buff) - work_done = 1 - rank = MPI.COMM_WORLD.Get_rank() - - mcdc["domain_decomp"]["work_done"] = True - - -@njit -def dd_recv(mcdc): - - if mcdc["domain_decomp"]["rank_busy"]: - dd_signal_block(mcdc) - mcdc["domain_decomp"]["rank_busy"] = False - - if not mcdc["domain_decomp"]["work_done"]: - tag = dd_get_recv_tag() - - if tag == 1: - dd_recv_particles(mcdc) - elif tag == 2: - dd_recv_turnstile(mcdc) - elif tag == 3: - dd_recv_halt(mcdc) - - -# ============================================================================= -# Particle in domain -# ============================================================================= - - -# Check if particle is in domain -@njit -def particle_in_domain(P_arr, mcdc): - P = P_arr[0] - d_idx = mcdc["dd_idx"] - d_Nx = mcdc["technique"]["dd_mesh"]["x"].size - 1 - d_Ny = mcdc["technique"]["dd_mesh"]["y"].size - 1 - d_Nz = mcdc["technique"]["dd_mesh"]["z"].size - 1 - - d_iz = int(d_idx / (d_Nx * d_Ny)) - d_iy = int((d_idx - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(d_idx - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - mesh = mcdc["technique"]["dd_mesh"] - x_cell, y_cell, z_cell, t_cell, outside = mesh_.structured.get_indices(P_arr, mesh) - - if d_ix == x_cell: - if d_iy == y_cell: - if d_iz == z_cell: - return True - return False - - -# ============================================================================= -# Source in domain -# ============================================================================= - - -# Check for source in domain -@njit -def source_in_domain(source, domain_mesh, d_idx): - d_Nx = domain_mesh["x"].size - 1 - d_Ny = domain_mesh["y"].size - 1 - d_Nz = domain_mesh["z"].size - 1 - - d_iz = int(d_idx / (d_Nx * d_Ny)) - d_iy = int((d_idx - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(d_idx - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - d_x = [domain_mesh["x"][d_ix], domain_mesh["x"][d_ix + 1]] - d_y = [domain_mesh["y"][d_iy], domain_mesh["y"][d_iy + 1]] - d_z = [domain_mesh["z"][d_iz], domain_mesh["z"][d_iz + 1]] - - if ( - d_x[0] <= source["box_x"][0] <= d_x[1] - or d_x[0] <= source["box_x"][1] <= d_x[1] - or (source["box_x"][0] < d_x[0] and source["box_x"][1] > d_x[1]) - ): - if ( - d_y[0] <= source["box_y"][0] <= d_y[1] - or d_y[0] <= source["box_y"][1] <= d_y[1] - or (source["box_y"][0] < d_y[0] and source["box_y"][1] > d_y[1]) - ): - if ( - d_z[0] <= source["box_z"][0] <= d_z[1] - or d_z[0] <= source["box_z"][1] <= d_z[1] - or (source["box_z"][0] < d_z[0] and source["box_z"][1] > d_z[1]) - ): - return True - else: - return False - else: - return False - else: - return False - - -# ============================================================================= -# Compute domain load -# ============================================================================= - - -@njit -def domain_work(mcdc, domain, N): - domain_mesh = mcdc["technique"]["dd_mesh"] - - d_Nx = domain_mesh["x"].size - 1 - d_Ny = domain_mesh["y"].size - 1 - d_Nz = domain_mesh["z"].size - 1 - work_start = 0 - for d_idx in range(domain): - d_iz = int(d_idx / (d_Nx * d_Ny)) - d_iy = int((d_idx - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(d_idx - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - d_x = [domain_mesh["x"][d_ix], domain_mesh["x"][d_ix + 1]] - d_y = [domain_mesh["y"][d_iy], domain_mesh["y"][d_iy + 1]] - d_z = [domain_mesh["z"][d_iz], domain_mesh["z"][d_iz + 1]] - # Compute volumes of sources and numbers of particles - - Psum = 0 - - Nm = 0 - num_source = 0 - for source in mcdc["sources"]: - Psum += source["prob"] - num_source += 1 - Vi = np.zeros(num_source) - Vim = np.zeros(num_source) - Ni = np.zeros(num_source) - i = 0 - for source in mcdc["sources"]: - Ni[i] = N * source["prob"] / Psum - Vi[i] = 1 - Vim[i] = 1 - if source["box"] == True: - xV = source["box_x"][1] - source["box_x"][0] - if xV != 0: - Vi[i] *= xV - Vim[i] *= min(source["box_x"][1], d_x[1]) - max( - source["box_x"][0], d_x[0] - ) - yV = source["box_y"][1] - source["box_y"][0] - if yV != 0: - Vi[i] *= yV - Vim[i] *= min(source["box_y"][1], d_y[1]) - max( - source["box_y"][0], d_y[0] - ) - zV = source["box_z"][1] - source["box_z"][0] - if zV != 0: - Vi[i] *= zV - Vim[i] *= min(source["box_z"][1], d_z[1]) - max( - source["box_z"][0], d_z[0] - ) - if not source_in_domain(source, domain_mesh, d_idx): - Vim[i] = 0 - i += 1 - for source in range(num_source): - Nm += Ni[source] * Vim[source] / Vi[source] - work_start += Nm - d_idx = domain - d_iz = int(mcdc["dd_idx"] / (d_Nx * d_Ny)) - d_iy = int((mcdc["dd_idx"] - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(mcdc["dd_idx"] - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - d_x = [domain_mesh["x"][d_ix], domain_mesh["x"][d_ix + 1]] - d_y = [domain_mesh["y"][d_iy], domain_mesh["y"][d_iy + 1]] - d_z = [domain_mesh["z"][d_iz], domain_mesh["z"][d_iz + 1]] - # Compute volumes of sources and numbers of particles - num_source = len(mcdc["sources"]) - Vi = np.zeros(num_source) - Vim = np.zeros(num_source) - Ni = np.zeros(num_source) - Psum = 0 - - Nm = 0 - for source in mcdc["sources"]: - Psum += source["prob"] - i = 0 - for source in mcdc["sources"]: - Ni[i] = N * source["prob"] / Psum - Vi[i] = 1 - Vim[i] = 1 - - if source["box"] == True: - xV = source["box_x"][1] - source["box_x"][0] - if xV != 0: - Vi[i] *= xV - Vim[i] *= min(source["box_x"][1], d_x[1]) - max( - source["box_x"][0], d_x[0] - ) - yV = source["box_y"][1] - source["box_y"][0] - if yV != 0: - Vi[i] *= yV - Vim[i] *= min(source["box_y"][1], d_y[1]) - max( - source["box_y"][0], d_y[0] - ) - zV = source["box_z"][1] - source["box_z"][0] - if zV != 0: - Vi[i] *= zV - Vim[i] *= min(source["box_z"][1], d_z[1]) - max( - source["box_z"][0], d_z[0] - ) - i += 1 - for source in range(num_source): - Nm += Ni[source] * Vim[source] / Vi[source] - Nm /= mcdc["technique"]["dd_work_ratio"][domain] - rank = mcdc["mpi_rank"] - if mcdc["technique"]["dd_work_ratio"][domain] > 1: - work_start += Nm * (rank - np.sum(mcdc["technique"]["dd_work_ratio"][0:d_idx])) - total_v = 0 - for source in range(len(mcdc["sources"])): - total_v += Vim[source] - i = 0 - for source in mcdc["sources"]: - if total_v != 0: - source["prob"] *= 2 * Vim[i] / total_v - i += 1 - return (int(Nm), int(work_start)) - - -# ============================================================================= -# Source particle in domain only -# ============================================================================= - - -@njit() -def source_particle_dd(seed, mcdc): - domain_mesh = mcdc["technique"]["dd_mesh"] - d_idx = mcdc["dd_idx"] - - d_Nx = domain_mesh["x"].size - 1 - d_Ny = domain_mesh["y"].size - 1 - d_Nz = domain_mesh["z"].size - 1 - - d_iz = int(mcdc["dd_idx"] / (d_Nx * d_Ny)) - d_iy = int((mcdc["dd_idx"] - d_Nx * d_Ny * d_iz) / d_Nx) - d_ix = int(mcdc["dd_idx"] - d_Nx * d_Ny * d_iz - d_Nx * d_iy) - - d_x = [domain_mesh["x"][d_ix], domain_mesh["x"][d_ix + 1]] - d_y = [domain_mesh["y"][d_iy], domain_mesh["y"][d_iy + 1]] - d_z = [domain_mesh["z"][d_iz], domain_mesh["z"][d_iz + 1]] - - P_arr = np.zeros(1, dtype=type_.particle_record) - P = P_arr[0] - - P["rng_seed"] = seed - # Sample source - xi = rng(P_arr) - tot = 0.0 - for source in mcdc["sources"]: - if source_in_domain(source, domain_mesh, d_idx): - tot += source["prob"] - if tot >= xi: - break - - # Position - if source["box"]: - x = sample_uniform( - max(source["box_x"][0], d_x[0]), min(source["box_x"][1], d_x[1]), P_arr - ) - y = sample_uniform( - max(source["box_y"][0], d_y[0]), min(source["box_y"][1], d_y[1]), P_arr - ) - z = sample_uniform( - max(source["box_z"][0], d_z[0]), min(source["box_z"][1], d_z[1]), P_arr - ) - - else: - x = source["x"] - y = source["y"] - z = source["z"] - - # Direction - if source["isotropic"]: - ux, uy, uz = sample_isotropic_direction(P_arr) - elif source["white"]: - ux, uy, uz = sample_white_direction( - source["white_x"], source["white_y"], source["white_z"], P - ) - else: - ux = source["ux"] - uy = source["uy"] - uz = source["uz"] - - # Energy and time - g = sample_discrete(source["group"], P_arr) - t = sample_uniform(source["time"][0], source["time"][1], P_arr) - - # Make and return particle - P["x"] = x - P["y"] = y - P["z"] = z - P["t"] = t - P["ux"] = ux - P["uy"] = uy - P["uz"] = uz - P["g"] = g - P["w"] = 1 - return P - - -@njit -def distribute_work_dd(N, mcdc, precursor=False): - work_start = 0 - work_size = N - work_size_total = N - - if not precursor: - mcdc["mpi_work_start"] = work_start - mcdc["mpi_work_size"] = work_size - mcdc["mpi_work_size_total"] = work_size_total - else: - mcdc["mpi_work_start_precursor"] = work_start - mcdc["mpi_work_size_precursor"] = work_size - mcdc["mpi_work_size_total_precursor"] = work_size_total - - -# ============================================================================= -# Random sampling -# ============================================================================= - - -@njit -def sample_isotropic_direction(P_arr): - P = P_arr[0] - # Sample polar cosine and azimuthal angle uniformly - mu = 2.0 * rng(P_arr) - 1.0 - azi = 2.0 * PI * rng(P_arr) - - # Convert to Cartesian coordinates - c = (1.0 - mu**2) ** 0.5 - y = math.cos(azi) * c - z = math.sin(azi) * c - x = mu - return x, y, z - - -@njit -def sample_white_direction(nx, ny, nz, P_arr): - P = P_arr[0] - # Sample polar cosine - mu = math.sqrt(rng(P_arr)) - - # Sample azimuthal direction - azi = 2.0 * PI * rng(P_arr) - cos_azi = math.cos(azi) - sin_azi = math.sin(azi) - Ac = (1.0 - mu**2) ** 0.5 - - if nz != 1.0: - B = (1.0 - nz**2) ** 0.5 - C = Ac / B - - x = nx * mu + (nx * nz * cos_azi - ny * sin_azi) * C - y = ny * mu + (ny * nz * cos_azi + nx * sin_azi) * C - z = nz * mu - cos_azi * Ac * B - - # If dir = 0i + 0j + k, interchange z and y in the formula - else: - B = (1.0 - ny**2) ** 0.5 - C = Ac / B - - x = nx * mu + (nx * ny * cos_azi - nz * sin_azi) * C - z = nz * mu + (nz * ny * cos_azi + nx * sin_azi) * C - y = ny * mu - cos_azi * Ac * B - return x, y, z - - -@njit -def sample_uniform(a, b, P_arr): - P = P_arr[0] - return a + rng(P_arr) * (b - a) - - -# TODO: use cummulative density function and binary search -@njit -def sample_discrete(group, P_arr): - P = P_arr[0] - tot = 0.0 - xi = rng(P_arr) - for i in range(group.shape[0]): - tot += group[i] - if tot > xi: - return i - - -@njit -def sample_piecewise_linear(cdf, P_arr): - P = P_arr[0] - xi = rng(P_arr) - - # Get bin - idx = binary_search(xi, cdf[1]) - - # Linear interpolation - x1 = cdf[1, idx] - x2 = cdf[1, idx + 1] - y1 = cdf[0, idx] - y2 = cdf[0, idx + 1] - return y1 + (xi - x1) * (y2 - y1) / (x2 - x1) - - -# ============================================================================= -# Random number generator -# LCG with hash seed-split -# ============================================================================= - - -@njit -def wrapping_mul(a, b): - return a * b - - -@njit -def wrapping_add(a, b): - return a + b - - -def wrapping_mul_python(a, b): - a = uint64(a) - b = uint64(b) - with np.errstate(all="ignore"): - return a * b - - -def wrapping_add_python(a, b): - a = uint64(a) - b = uint64(b) - with np.errstate(all="ignore"): - return a + b - - -def adapt_rng(object_mode=False): - global wrapping_add, wrapping_mul - if object_mode: - wrapping_add = wrapping_add_python - wrapping_mul = wrapping_mul_python - - -@njit -def split_seed(key, seed): - """murmur_hash64a""" - multiplier = uint64(0xC6A4A7935BD1E995) - length = uint64(8) - rotator = uint64(47) - key = uint64(key) - seed = uint64(seed) - - hash_value = uint64(seed) ^ wrapping_mul(length, multiplier) - - key = wrapping_mul(key, multiplier) - key ^= key >> rotator - key = wrapping_mul(key, multiplier) - hash_value ^= key - hash_value = wrapping_mul(hash_value, multiplier) - - hash_value ^= hash_value >> rotator - hash_value = wrapping_mul(hash_value, multiplier) - hash_value ^= hash_value >> rotator - return hash_value - - -@njit -def rng_(seed): - seed = uint64(seed) - return wrapping_add(wrapping_mul(RNG_G, seed), RNG_C) & RNG_MOD_MASK - - -@njit -def rng(state_arr): - state = state_arr[0] - state["rng_seed"] = rng_(state["rng_seed"]) - return state["rng_seed"] / RNG_MOD - - -@njit -def rng_from_seed(seed): - return rng_(seed) / RNG_MOD - - -@njit -def rng_array(seed, shape, size): - xi = np.zeros(size) - for i in range(size): - xi_seed = split_seed(i, seed) - xi[i] = rng_from_seed(xi_seed) - xi = xi.reshape(shape) - return xi - - -# ============================================================================= -# Particle source operations -# ============================================================================= - - -@njit -def source_particle(P_rec_arr, seed, mcdc): - P_rec = P_rec_arr[0] - P_rec["rng_seed"] = seed - - # Sample source - xi = rng(P_rec_arr) - tot = 0.0 - for source in mcdc["sources"]: - tot += source["prob"] - if tot >= xi: - break - - # Position - if source["box"]: - x = sample_uniform(source["box_x"][0], source["box_x"][1], P_rec_arr) - y = sample_uniform(source["box_y"][0], source["box_y"][1], P_rec_arr) - z = sample_uniform(source["box_z"][0], source["box_z"][1], P_rec_arr) - else: - x = source["x"] - y = source["y"] - z = source["z"] - - # Direction - if source["isotropic"]: - ux, uy, uz = sample_isotropic_direction(P_rec_arr) - elif source["white"]: - ux, uy, uz = sample_white_direction( - source["white_x"], source["white_y"], source["white_z"], P_rec_arr - ) - else: - ux = source["ux"] - uy = source["uy"] - uz = source["uz"] - - # Energy and time - if mcdc["setting"]["mode_MG"]: - g = sample_discrete(source["group"], P_rec_arr) - E = 0.0 - else: - g = 0 - E = sample_piecewise_linear(source["energy"], P_rec_arr) - - # Time - t = sample_uniform(source["time"][0], source["time"][1], P_rec_arr) - - # Make and return particle - P_rec["x"] = x - P_rec["y"] = y - P_rec["z"] = z - P_rec["t"] = t - P_rec["ux"] = ux - P_rec["uy"] = uy - P_rec["uz"] = uz - P_rec["g"] = g - P_rec["E"] = E - P_rec["w"] = 1.0 - - -# ============================================================================= -# Particle bank operations -# ============================================================================= - - -@njit -def get_bank_size(bank): - return bank["size"][0] - - -@njit -def set_bank_size(bank, value): - bank["size"][0] = value - - -@njit -def add_bank_size(bank, value): - return adapt.global_add(bank["size"], 0, value) - - -@for_cpu() -def full_bank_print(bank): - with objmode(): - print_error( - "Particle %s bank is full at count %d." % (bank["tag"], bank["size"]) - ) - - -@for_gpu() -def full_bank_print(bank): - pass - - -@njit -def add_full_particle(P_arr, bank): - P = P_arr[0] - - idx = add_bank_size(bank, 1) - - # Check if bank is full - if idx >= bank["particles"].shape[0]: - full_bank_print(bank) - - # Set particle - copy_particle(bank["particles"][idx : idx + 1], P_arr) - - -@njit -def add_particle(P_arr, bank): - P = P_arr[0] - - idx = add_bank_size(bank, 1) - - # Check if bank is full - if idx >= bank["particles"].shape[0]: - full_bank_print(bank) - - # Set particle - copy_recordlike(bank["particles"][idx : idx + 1], P_arr) - - -@njit -def get_particle(P_arr, bank, mcdc): - P = P_arr[0] - - idx = add_bank_size(bank, -1) - 1 - - # Check if bank is empty - if idx < 0: - return False - # with objmode(): - # print_error("Particle %s bank is empty." % bank["tag"]) - - # Set attribute - P_rec = bank["particles"][idx] - P["x"] = P_rec["x"] - P["y"] = P_rec["y"] - P["z"] = P_rec["z"] - P["t"] = P_rec["t"] - P["ux"] = P_rec["ux"] - P["uy"] = P_rec["uy"] - P["uz"] = P_rec["uz"] - P["g"] = P_rec["g"] - P["E"] = P_rec["E"] - P["w"] = P_rec["w"] - P["rng_seed"] = P_rec["rng_seed"] - - if mcdc["technique"]["iQMC"]: - P["iqmc"]["w"] = P_rec["iqmc"]["w"] - - P["alive"] = True - - # Set default IDs and event - P["material_ID"] = -1 - P["cell_ID"] = -1 - P["surface_ID"] = -1 - P["event"] = -1 - return True - - -@njit -def check_future_bank(mcdc): - # Get the data needed - bank_future = mcdc["bank_future"] - bank_census = mcdc["bank_census"] - next_census_time = mcdc["setting"]["census_time"][mcdc["idx_census"] + 1] - - # Particle container - P_arr = adapt.local_array(1, type_.particle_record) - P = P_arr[0] - - # Loop over all particles in future bank - N = get_bank_size(bank_future) - for i in range(N): - # Get the next future particle index - idx = i - get_bank_size(bank_census) - copy_recordlike(P_arr, bank_future["particles"][idx : idx + 1]) - - # Promote the future particle to census bank - if P["t"] < next_census_time: - adapt.add_census(P_arr, mcdc) - add_bank_size(bank_future, -1) - - # Consolidate the emptied space in the future bank - j = get_bank_size(bank_future) - copy_recordlike( - bank_future["particles"][idx : idx + 1], - bank_future["particles"][j : j + 1], - ) - - -@njit -def manage_particle_banks(seed, mcdc): - # Record time - if mcdc["mpi_master"]: - with objmode(time_start="float64"): - time_start = MPI.Wtime() - - # Reset source bank - set_bank_size(mcdc["bank_source"], 0) - - # Normalize weight - if mcdc["setting"]["mode_eigenvalue"]: - normalize_weight(mcdc["bank_census"], mcdc["setting"]["N_particle"]) - - # Population control - if mcdc["technique"]["population_control"]: - population_control(seed, mcdc) - else: - # Swap census and source bank - size = get_bank_size(mcdc["bank_census"]) - set_bank_size(mcdc["bank_source"], size) - mcdc["bank_source"]["particles"][:size] = mcdc["bank_census"]["particles"][ - :size - ] - # TODO: Population control future bank? - - # MPI rebalance - if not mcdc["technique"]["domain_decomposition"]: - bank_rebalance(mcdc) - - # Zero out census bank - set_bank_size(mcdc["bank_census"], 0) - - # Manage IC bank - if mcdc["technique"]["IC_generator"] and mcdc["cycle_active"]: - manage_IC_bank(mcdc) - - # Accumulate time - if mcdc["mpi_master"]: - with objmode(time_end="float64"): - time_end = MPI.Wtime() - mcdc["runtime_bank_management"] += time_end - time_start - - -@njit -def manage_IC_bank(mcdc): - # Buffer bank - buff_n = np.zeros( - mcdc["technique"]["IC_bank_neutron_local"]["particles"].shape[0], - dtype=type_.particle_record, - ) - buff_p = np.zeros( - mcdc["technique"]["IC_bank_precursor_local"]["precursors"].shape[0], - dtype=type_.precursor, - ) - - with objmode(Nn="int64", Np="int64"): - # Create MPI-supported numpy object - Nn = get_bank_size(mcdc["technique"]["IC_bank_neutron_local"]) - Np = get_bank_size(mcdc["technique"]["IC_bank_precursor_local"]) - - neutrons = MPI.COMM_WORLD.gather( - mcdc["technique"]["IC_bank_neutron_local"]["particles"][:Nn] - ) - precursors = MPI.COMM_WORLD.gather( - mcdc["technique"]["IC_bank_precursor_local"]["precursors"][:Np] - ) - - if mcdc["mpi_master"]: - neutrons = np.concatenate(neutrons[:]) - precursors = np.concatenate(precursors[:]) - - # Set output buffer - Nn = neutrons.shape[0] - Np = precursors.shape[0] - for i in range(Nn): - buff_n[i] = neutrons[i] - for i in range(Np): - buff_p[i] = precursors[i] - - # Set global bank from buffer - if mcdc["mpi_master"]: - start_n = add_bank_size(mcdc["technique"]["IC_bank_neutron"], Nn) - start_p = add_bank_size(mcdc["technique"]["IC_bank_precursor"], Np) - for i in range(Nn): - mcdc["technique"]["IC_bank_neutron"]["particles"][start_n + i] = buff_n[i] - for i in range(Np): - mcdc["technique"]["IC_bank_precursor"]["precursors"][start_p + i] = buff_p[ - i - ] - - # Reset local banks - set_bank_size(mcdc["technique"]["IC_bank_neutron_local"], 0) - set_bank_size(mcdc["technique"]["IC_bank_precursor_local"], 0) - - -@njit -def bank_scanning(bank, mcdc): - N_local = get_bank_size(bank) - - # Starting index - buff = np.zeros(1, dtype=np.int64) - with objmode(): - MPI.COMM_WORLD.Exscan(np.array([N_local]), buff, MPI.SUM) - idx_start = buff[0] - - # Global size - buff[0] += N_local - with objmode(): - MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) - N_global = buff[0] - - return idx_start, N_local, N_global - - -@njit -def bank_scanning_weight(bank, mcdc): - # Local weight CDF - N_local = get_bank_size(bank) - w_cdf = np.zeros(N_local + 1) - for i in range(N_local): - w_cdf[i + 1] = w_cdf[i] + bank["particles"][i]["w"] - W_local = w_cdf[-1] - - # Starting weight - buff = np.zeros(1, dtype=np.float64) - with objmode(): - MPI.COMM_WORLD.Exscan(np.array([W_local]), buff, MPI.SUM) - w_start = buff[0] - w_cdf += w_start - - # Global weight - buff[0] = w_cdf[-1] - with objmode(): - MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) - W_global = buff[0] - - return w_start, w_cdf, W_global - - -@njit -def bank_scanning_DNP(bank, mcdc): - N_DNP_local = get_bank_size(bank) - - # Get sum of ceil-ed local DNP weights - N_local = 0 - for i in range(N_DNP_local): - DNP = bank["precursors"][i] - N_local += math.ceil(DNP["w"]) - - # Starting index - buff = np.zeros(1, dtype=np.int64) - with objmode(): - MPI.COMM_WORLD.Exscan(np.array([N_local]), buff, MPI.SUM) - idx_start = buff[0] - - # Global size - buff[0] += N_local - with objmode(): - MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) - N_global = buff[0] - - return idx_start, N_local, N_global - - -@njit -def normalize_weight(bank, norm): - # Get total weight - W = total_weight(bank) - - # Normalize weight - for P in bank["particles"]: - P["w"] *= norm / W - - -@njit -def total_weight(bank): - # Local total weight - W_local = np.zeros(1) - for i in range(get_bank_size(bank)): - W_local[0] += bank["particles"][i]["w"] - - # MPI Allreduce - buff = np.zeros(1, np.float64) - with objmode(): - MPI.COMM_WORLD.Allreduce(W_local, buff, MPI.SUM) - return buff[0] - - -@njit -def allreduce(value): - total = np.zeros(1, np.float64) - with objmode(): - MPI.COMM_WORLD.Allreduce(np.array([value], np.float64), total, MPI.SUM) - return total[0] - - -@njit -def allreduce_array(array): - buff = np.zeros_like(array) - with objmode(): - MPI.COMM_WORLD.Allreduce(np.array(array), buff, op=MPI.SUM) - array[:] = buff - - -@njit -def bank_rebalance(mcdc): - # Scan the bank - idx_start, N_local, N = bank_scanning(mcdc["bank_source"], mcdc) - idx_end = idx_start + N_local - - # Abort if source bank is empty - if N == 0: - return - - distribute_work(N, mcdc) - - # Rebalance not needed if there is only one rank - if mcdc["mpi_size"] <= 1: - return - - # Some constants - work_start = mcdc["mpi_work_start"] - work_end = work_start + mcdc["mpi_work_size"] - left = mcdc["mpi_rank"] - 1 - right = mcdc["mpi_rank"] + 1 - - # Need more or less? - more_left = idx_start < work_start - less_left = idx_start > work_start - more_right = idx_end > work_end - less_right = idx_end < work_end - - # Offside? - offside_left = idx_end <= work_start - offside_right = idx_start >= work_end - - # MPI nearest-neighbor send/receive - buff = np.zeros( - mcdc["bank_source"]["particles"].shape[0], dtype=type_.particle_record - ) - - with objmode(size="int64"): - # Create MPI-supported numpy object - size = get_bank_size(mcdc["bank_source"]) - bank = np.array(mcdc["bank_source"]["particles"][:size]) - - # If offside, need to receive first - if offside_left: - # Receive from right - bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) - less_right = False - if offside_right: - # Receive from left - bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) - less_left = False - - # Send - if more_left: - n = work_start - idx_start - request_left = MPI.COMM_WORLD.isend(bank[:n], dest=left) - bank = bank[n:] - if more_right: - n = idx_end - work_end - request_right = MPI.COMM_WORLD.isend(bank[-n:], dest=right) - bank = bank[:-n] - - # Receive - if less_left: - bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) - if less_right: - bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) - - # Wait until sent massage is received - if more_left: - request_left.Wait() - if more_right: - request_right.Wait() - - # Set output buffer - size = bank.shape[0] - for i in range(size): - buff[i] = bank[i] - - # Set source bank from buffer - set_bank_size(mcdc["bank_source"], size) - for i in range(size): - mcdc["bank_source"]["particles"][i] = buff[i] - - -@njit -def distribute_work(N, mcdc, precursor=False): - size = mcdc["mpi_size"] - rank = mcdc["mpi_rank"] - - # Total # of work - work_size_total = N - - # Evenly distribute work - work_size = math.floor(N / size) - - # Starting index (based on even distribution) - work_start = work_size * rank - - # Count reminder - rem = N % size - - # Assign reminder and update starting index - if rank < rem: - work_size += 1 - work_start += rank - else: - work_start += rem - - if not precursor: - mcdc["mpi_work_start"] = work_start - mcdc["mpi_work_size"] = work_size - mcdc["mpi_work_size_total"] = work_size_total - else: - mcdc["mpi_work_start_precursor"] = work_start - mcdc["mpi_work_size_precursor"] = work_size - mcdc["mpi_work_size_total_precursor"] = work_size_total - - -# ============================================================================= -# IC generator -# ============================================================================= - - -@for_cpu() -def pn_over_one(): - with objmode(): - print_error("Pn > 1.0.") - - -@for_gpu() -def pn_over_one(): - pass - - -@for_cpu() -def pp_over_one(): - with objmode(): - print_error("Pp > 1.0.") - - -@for_gpu() -def pp_over_one(): - pass - - -@njit -def bank_IC(P_arr, prog): - P = P_arr[0] - - mcdc = adapt.mcdc_global(prog) - - # TODO: Consider multi-nuclide material - material = mcdc["nuclides"][P["material_ID"]] - - # ========================================================================= - # Neutron - # ========================================================================= - - # Neutron weight - g = P["g"] - SigmaT = material["total"][g] - weight = P["w"] - flux = weight / SigmaT - v = material["speed"][g] - wn = flux / v - - # Neutron target weight - Nn = mcdc["technique"]["IC_N_neutron"] - tally_n = mcdc["technique"]["IC_neutron_density"] - N_cycle = mcdc["setting"]["N_active"] - wn_prime = tally_n * N_cycle / Nn - - # Sampling probability - Pn = wn / wn_prime - - # TODO: Splitting for Pn > 1.0 - if Pn > 1.0: - pn_over_one() - - # Sample particle - if rng(P_arr) < Pn: - P_new_arr = adapt.local_array(1, type_.particle) - P_new = P_new_arr[0] - split_as_record(P_new_arr, P_arr) - P_new["w"] = 1.0 - P_new["t"] = 0.0 - adapt.add_IC(P_new_arr, prog) - - # Accumulate fission - SigmaF = material["fission"][g] - # mcdc["technique"]["IC_fission_score"][0] += v * SigmaF - - # HAZARD - adapt.global_add(mcdc["technique"]["IC_fission_score"], 0, round(v * SigmaF)) - - # ========================================================================= - # Precursor - # ========================================================================= - - # Sample precursor? - Np = mcdc["technique"]["IC_N_precursor"] - if Np == 0: - return - - # Precursor weight - J = material["J"] - nu_d = material["nu_d"][g] - SigmaF = material["fission"][g] - decay = material["decay"] - total = 0.0 - for j in range(J): - total += nu_d[j] / decay[j] - wp = flux * total * SigmaF / mcdc["k_eff"] - - # HAZARD (with loop above) - # Material has no precursor - if total == 0.0: - return - - # Precursor target weight - tally_C = mcdc["technique"]["IC_precursor_density"] - wp_prime = tally_C * N_cycle / Np - - # Sampling probability - Pp = wp / wp_prime - - # TODO: Splitting for Pp > 1.0 - if Pp > 1.0: - pp_over_one() - - # Sample precursor - if rng(P_arr) < Pp: - idx = add_bank_size(mcdc["technique"]["IC_bank_precursor_local"], 1) - precursor = mcdc["technique"]["IC_bank_precursor_local"]["precursors"][idx] - precursor["x"] = P["x"] - precursor["y"] = P["y"] - precursor["z"] = P["z"] - precursor["w"] = wp_prime / wn_prime - - # Sample group - xi = rng(P_arr) * total - total = 0.0 - for j in range(J): - total += nu_d[j] / decay[j] - if total > xi: - break - precursor["g"] = j - - # Set inducing neutron group - precursor["n_g"] = g - - -# ============================================================================= -# Population control techniques -# ============================================================================= -# TODO: Make it a stand-alone function that takes (bank_init, bank_final, M). -# The challenge is in the use of type-dependent copy_record which is -# required due to pure-Python behavior of taking things by reference. - - -@njit -def population_control(seed, mcdc): - if mcdc["technique"]["pct"] == PCT_COMBING: - pct_combing(seed, mcdc) - elif mcdc["technique"]["pct"] == PCT_COMBING_WEIGHT: - pct_combing_weight(seed, mcdc) - elif mcdc["technique"]["pct"] == PCT_SPLITTING_ROULETTE: - pct_splitting_roulette(seed, mcdc) - elif mcdc["technique"]["pct"] == PCT_SPLITTING_ROULETTE_WEIGHT: - pct_splitting_roulette_weight(seed, mcdc) - - -@njit -def pct_combing(seed, mcdc): - bank_census = mcdc["bank_census"] - M = mcdc["setting"]["N_particle"] - bank_source = mcdc["bank_source"] - - # Scan the bank - idx_start, N_local, N = bank_scanning(bank_census, mcdc) - idx_end = idx_start + N_local - - # Abort if census bank is empty - if N == 0: - return - - # Teeth distance - td = N / M - - # Update population control factor - mcdc["technique"]["pc_factor"] *= td - - xi = rng_from_seed(seed) - offset = xi * td - - # First hiting tooth - tooth_start = math.ceil((idx_start - offset) / td) - - # Last hiting tooth - tooth_end = math.floor((idx_end - offset) / td) + 1 - - P_rec_arr = adapt.local_array(1, type_.particle_record) - P_rec = P_rec_arr[0] - - # Locally sample particles from census bank - set_bank_size(bank_source, 0) - for i in range(tooth_start, tooth_end): - tooth = i * td + offset - idx = math.floor(tooth) - idx_start - split_as_record(P_rec_arr, bank_census["particles"][idx : idx + 1]) - # Set weight - P_rec["w"] *= td - adapt.add_source(P_rec_arr, mcdc) - - -@njit -def pct_combing_weight(seed, mcdc): - bank_census = mcdc["bank_census"] - M = mcdc["setting"]["N_particle"] - bank_source = mcdc["bank_source"] - - # Scan the bank based on weight - w_start, w_cdf, W = bank_scanning_weight(bank_census, mcdc) - w_end = w_cdf[-1] - - # Abort if census bank is empty - if W == 0.0: - return - - # Teeth distance - td = W / M - - # Update population control factor - mcdc["technique"]["pc_factor"] *= td # This may be incorrect - - # Tooth offset - xi = rng_from_seed(seed) - offset = xi * td - - # First hiting tooth - tooth_start = math.ceil((w_start - offset) / td) - - # Last hiting tooth - tooth_end = math.floor((w_end - offset) / td) + 1 - - P_rec_arr = adapt.local_array(1, type_.particle_record) - P_rec = P_rec_arr[0] - - # Locally sample particles from census bank - set_bank_size(bank_source, 0) - idx = 0 - for i in range(tooth_start, tooth_end): - tooth = i * td + offset - idx += binary_search(tooth, w_cdf[idx:]) - split_as_record(P_rec_arr, bank_census["particles"][idx : idx + 1]) - # Set weight - P_rec["w"] = td - adapt.add_source(P_rec_arr, mcdc) - - -@njit -def pct_splitting_roulette(seed, mcdc): - bank_census = mcdc["bank_census"] - M = mcdc["setting"]["N_particle"] - bank_source = mcdc["bank_source"] - - # Scan the bank - idx_start, N_local, N = bank_scanning(bank_census, mcdc) - idx_end = idx_start + N_local - - # Abort if census bank is empty - if N == 0: - return - - # Weight scaling - ws = float(N) / float(M) - - # Splitting Number - sn = 1.0 / ws - - # Update population control factor - mcdc["technique"]["pc_factor"] *= ws - - P_rec_arr = adapt.local_array(1, type_.particle_record) - P_rec = P_rec_arr[0] - - # Perform split-roulette to all particles in local bank - set_bank_size(bank_source, 0) - for idx in range(N_local): - # Weight of the surviving particles - w = bank_census["particles"][idx]["w"] - w_survive = w * ws - - # Determine number of guaranteed splits - N_split = math.floor(sn) - - # Survive the russian roulette? - xi = rng(bank_census["particles"][idx : idx + 1]) - if xi < sn - N_split: - N_split += 1 - - # Split the particle - for i in range(N_split): - split_as_record(P_rec_arr, bank_census["particles"][idx : idx + 1]) - # Set weight - P_rec["w"] = w_survive - adapt.add_source(P_rec_arr, mcdc) - - -@njit -def pct_splitting_roulette_weight(seed, mcdc): - bank_census = mcdc["bank_census"] - M = mcdc["setting"]["N_particle"] - bank_source = mcdc["bank_source"] - - # Scan the bank based on weight - N_local = get_bank_size(bank_census) - w_start, w_cdf, W = bank_scanning_weight(bank_census, mcdc) - w_end = w_cdf[-1] - - # Abort if census bank is empty - if W == 0.0: - return - - # Weight of the surviving particles - w_survive = W / M - - # Update population control factor - mcdc["technique"]["pc_factor"] *= w_survive # This may be incorrect - - P_rec_arr = adapt.local_array(1, type_.particle_record) - P_rec = P_rec_arr[0] - - # Perform split-roulette to all particles in local bank - set_bank_size(bank_source, 0) - for idx in range(N_local): - # Splitting number - w = bank_census["particles"][idx]["w"] - sn = w / w_survive - - # Determine number of guaranteed splits - N_split = math.floor(sn) - - # Survive the russian roulette? - xi = rng(bank_census["particles"][idx : idx + 1]) - if xi < sn - N_split: - N_split += 1 - - # Split the particle - for i in range(N_split): - split_as_record(P_rec_arr, bank_census["particles"][idx : idx + 1]) - # Set weight - P_rec["w"] = w_survive - adapt.add_source(P_rec_arr, mcdc) - - -# ============================================================================= -# Particle operations -# ============================================================================= - - -@njit -def move_particle(P_arr, distance, mcdc): - P = P_arr[0] - P["x"] += P["ux"] * distance - P["y"] += P["uy"] * distance - P["z"] += P["uz"] * distance - P["t"] += distance / physics.get_speed(P_arr, mcdc) - - -@njit -def copy_recordlike(P_new_arr, P_rec_arr): - P_new = P_new_arr[0] - P_rec = P_rec_arr[0] - P_new["x"] = P_rec["x"] - P_new["y"] = P_rec["y"] - P_new["z"] = P_rec["z"] - P_new["t"] = P_rec["t"] - P_new["ux"] = P_rec["ux"] - P_new["uy"] = P_rec["uy"] - P_new["uz"] = P_rec["uz"] - P_new["g"] = P_rec["g"] - P_new["E"] = P_rec["E"] - P_new["w"] = P_rec["w"] - P_new["rng_seed"] = P_rec["rng_seed"] - P_new["iqmc"]["w"] = P_rec["iqmc"]["w"] - - -@njit -def copy_particle(P_new_arr, P_arr): - P_new = P_new_arr[0] - P = P_arr[0] - P_new = P_new_arr[0] - P_new["x"] = P["x"] - P_new["y"] = P["y"] - P_new["z"] = P["z"] - P_new["t"] = P["t"] - P_new["ux"] = P["ux"] - P_new["uy"] = P["uy"] - P_new["uz"] = P["uz"] - P_new["g"] = P["g"] - P_new["w"] = P["w"] - P_new["alive"] = P["alive"] - P_new["fresh"] = P["fresh"] - P_new["material_ID"] = P["material_ID"] - P_new["cell_ID"] = P["cell_ID"] - P_new["surface_ID"] = P["surface_ID"] - P_new["event"] = P["event"] - P_new["rng_seed"] = P["rng_seed"] - P_new["iqmc"]["w"] = P["iqmc"]["w"] - - -@njit -def recordlike_to_particle(P_new_arr, P_rec_arr): - P_new = P_new_arr[0] - P_rec = P_rec_arr[0] - copy_recordlike(P_new_arr, P_rec_arr) - P_new["fresh"] = True - P_new["alive"] = True - P_new["material_ID"] = -1 - P_new["cell_ID"] = -1 - P_new["surface_ID"] = -1 - P_new["event"] = -1 - - -@njit -def split_as_record(P_new_rec_arr, P_rec_arr): - P_rec = P_rec_arr[0] - P_new_rec = P_new_rec_arr[0] - copy_recordlike(P_new_rec_arr, P_rec_arr) - P_new_rec["rng_seed"] = split_seed(P_rec["rng_seed"], SEED_SPLIT_PARTICLE) - rng(P_rec_arr) - - -# ============================================================================= -# Mesh operations -# ============================================================================= - - -@njit -def mesh_get_angular_index(P_arr, mesh): - P = P_arr[0] - ux = P["ux"] - uy = P["uy"] - uz = P["uz"] - - P_mu = uz - P_azi = math.acos(ux / math.sqrt(ux * ux + uy * uy)) - if uy < 0.0: - P_azi *= -1 - - mu = binary_search(P_mu, mesh["mu"]) - azi = binary_search(P_azi, mesh["azi"]) - return mu, azi - - -@njit -def mesh_get_energy_index(P_arr, mesh, mode_MG): - P = P_arr[0] - # Check if outside grid - outside = False - - Ng = mesh["Ng"] - - if mode_MG: - return binary_search_with_length(P["g"], mesh["g"], Ng), outside - - else: - E = P["E"] - if E < mesh["g"][0] or E > mesh["g"][Ng]: - outside = True - return 0, outside - return binary_search_with_length(P["E"], mesh["g"], Ng), outside - - -# ============================================================================= -# Tally operations -# ============================================================================= - - -@njit -def score_mesh_tally(P_arr, distance, tally, data_tally, mcdc): - P = P_arr[0] - material = mcdc["materials"][P["material_ID"]] - mesh = tally["filter"] - stride = tally["stride"] - - # Particle 4D direction - ux = P["ux"] - uy = P["uy"] - uz = P["uz"] - ut = 1.0 / physics.get_speed(P_arr, mcdc) - - # Particle initial and final coordinate - x = P["x"] - y = P["y"] - z = P["z"] - t = P["t"] - x_final = x + ux * distance - y_final = y + uy * distance - z_final = z + uz * distance - t_final = t + ut * distance - - # Easily identified tally bin indices - mu, azi = mesh_get_angular_index(P_arr, mesh) - g, outside_energy = mesh_get_energy_index(P_arr, mesh, mcdc["setting"]["mode_MG"]) - - # Get starting indices - ix, iy, iz, it, outside = mesh_.structured.get_indices(P_arr, mesh) - - # Outside grid? - if outside or outside_energy: - return - - # The tally index - idx = ( - stride["tally"] - + mu * stride["mu"] - + azi * stride["azi"] - + g * stride["g"] - + it * stride["t"] - + ix * stride["x"] - + iy * stride["y"] - + iz * stride["z"] - ) - - # Sweep through the distance - distance_swept = 0.0 - while distance_swept < distance - COINCIDENCE_TOLERANCE: - # Find distances to the mesh grids - if ux == 0.0: - dx = INF - else: - if ux > 0.0: - x_next = min(mesh["x"][ix + 1], x_final) - else: - x_next = max(mesh["x"][ix], x_final) - dx = (x_next - x) / ux - if uy == 0.0: - dy = INF - else: - if uy > 0.0: - y_next = min(mesh["y"][iy + 1], y_final) - else: - y_next = max(mesh["y"][iy], y_final) - dy = (y_next - y) / uy - if uz == 0.0: - dz = INF - else: - if uz > 0.0: - z_next = min(mesh["z"][iz + 1], z_final) - else: - z_next = max(mesh["z"][iz], z_final) - dz = (z_next - z) / uz - dt = (min(mesh["t"][it + 1], t_final) - t) / ut - - # Get the grid crossed - distance_scored = INF - mesh_crossed = MESH_NONE - if dx <= distance_scored: - mesh_crossed = MESH_X - distance_scored = dx - if dy <= distance_scored: - mesh_crossed = MESH_Y - distance_scored = dy - if dz <= distance_scored: - mesh_crossed = MESH_Z - distance_scored = dz - if dt <= distance_scored: - mesh_crossed = MESH_T - distance_scored = dt - - # Score - flux = distance_scored * P["w"] - mu = P["ux"] - for i in range(tally["N_score"]): - score_type = tally["scores"][i] - score = 0 - if score_type == SCORE_FLUX: - score = flux - elif score_type == SCORE_DENSITY: - score = flux * ut - elif score_type == SCORE_TOTAL: - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - score = flux * SigmaT - elif score_type == SCORE_FISSION: - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - score = flux * SigmaF - if score_type == SCORE_NET_CURRENT: - score = flux * mu - if score_type == SCORE_MU_SQ: - score = flux * mu * mu - elif score_type == SCORE_TIME_MOMENT_FLUX: - score = flux * (t - (mesh["t"][it - 1] + mesh["t"][it]) / 2) - elif score_type == SCORE_SPACE_MOMENT_FLUX: - score = flux * (x - (mesh["x"][ix + 1] + mesh["x"][ix]) / 2) - elif score_type == SCORE_TIME_MOMENT_CURRENT: - score = flux * mu * (t - (mesh["t"][it - 1] + mesh["t"][it]) / 2) - elif score_type == SCORE_SPACE_MOMENT_CURRENT: - score = flux * mu * (x - (mesh["x"][ix + 1] + mesh["x"][ix]) / 2) - elif score_type == SCORE_TIME_MOMENT_MU_SQ: - score = flux * mu * mu * (t - (mesh["t"][it - 1] + mesh["t"][it]) / 2) - elif score_type == SCORE_SPACE_MOMENT_MU_SQ: - score = flux * mu * mu * (x - (mesh["x"][ix + 1] + mesh["x"][ix]) / 2) - adapt.global_add(data_tally, (TALLY_SCORE, idx + i), round(score)) - - # Accumulate distance swept - distance_swept += distance_scored - - # Move the 4D position - x += distance_scored * ux - y += distance_scored * uy - z += distance_scored * uz - t += distance_scored * ut - - # Increment index and check if out of bound - if mesh_crossed == MESH_X: - if ux > 0.0: - ix += 1 - if ix == mesh["Nx"]: - break - idx += stride["x"] - else: - ix -= 1 - if ix == -1: - break - idx -= stride["x"] - elif mesh_crossed == MESH_Y: - if uy > 0.0: - iy += 1 - if iy == mesh["Ny"]: - break - idx += stride["y"] - else: - iy -= 1 - if iy == -1: - break - idx -= stride["y"] - elif mesh_crossed == MESH_Z: - if uz > 0.0: - iz += 1 - if iz == mesh["Nz"]: - break - idx += stride["z"] - else: - iz -= 1 - if iz == -1: - break - idx -= stride["z"] - elif mesh_crossed == MESH_T: - it += 1 - if it == mesh["Nt"]: - break - idx += stride["t"] - - -@njit -def score_surface_tally(P_arr, surface, tally, data_tally, mcdc): - # TODO: currently not supporting filters - P = P_arr[0] - - stride = tally["stride"] - - # The tally index - idx = stride["tally"] - - # Flux - speed = physics.get_speed(P_arr, mcdc) - mu = surface_.get_normal_component(P_arr, speed, surface) - flux = P["w"] / abs(mu) - - # Score - for i in range(tally["N_score"]): - score_type = tally["scores"][i] - if score_type == SCORE_FLUX: - score = flux - elif score_type == SCORE_NET_CURRENT: - score = flux * mu - adapt.global_add(data_tally, (TALLY_SCORE, idx + i), round(score)) - - -@njit -def score_cell_tally(P_arr, distance, tally, data_tally, mcdc): - P = P_arr[0] - material = mcdc["materials"][P["material_ID"]] - mesh = tally["filter"] - stride = tally["stride"] - - # Particle/track properties - ut = 1.0 / physics.get_speed(P_arr, mcdc) - t = P["t"] - t_final = t + ut * distance - Nt = mesh["Nt"] - - # Get starting indices - g, outside_energy = mesh_get_energy_index(P_arr, mesh, mcdc["setting"]["mode_MG"]) - - # Outside grid? - if ( - t < mesh["t"][0] - COINCIDENCE_TOLERANCE_TIME - or t > mesh["t"][Nt] + COINCIDENCE_TOLERANCE_TIME - or (abs(t - mesh["t"][Nt]) < COINCIDENCE_TOLERANCE_TIME) - or outside_energy - ): - return - - it = mesh_.structured._grid_index( - t, 1.0, mesh["t"], Nt + 1, COINCIDENCE_TOLERANCE_TIME - ) - - # Tally index - idx = stride["tally"] + g * stride["g"] + it * stride["t"] - - # Sweep through the distance - distance_swept = 0.0 - while distance_swept < distance - COINCIDENCE_TOLERANCE: - - # Find distance to mesh grids - dt = (min(mesh["t"][it + 1], t_final) - t) / ut - - # Get the grid crossed - distance_scored = INF - mesh_crossed = MESH_NONE - if dt <= distance_scored: - mesh_crossed = MESH_T - distance_scored = dt - - # Score - flux = distance_scored * P["w"] - for i in range(tally["N_score"]): - score_type = tally["scores"][i] - score = 0 - if score_type == SCORE_FLUX: - score = flux - elif score_type == SCORE_TOTAL: - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - score = flux * SigmaT - elif score_type == SCORE_FISSION: - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - score = flux * SigmaF - adapt.global_add(data_tally, (TALLY_SCORE, idx + i), round(score)) - - # Accumulate distance swept - distance_swept += distance_scored - - # Move the 4D (just t for this tally) position - t += distance_scored * ut - - # Increment index and check if out of bounds - if mesh_crossed == MESH_T: - it += 1 - if it == Nt: - break - idx += stride["t"] - - -@njit -def score_cs_tally(P_arr, distance, tally, data_tally, mcdc): - # Each time that this function is called, EVERY cs bin needs to be checked to see if the particle is in it. - # The particle needs to score into all the bins that it is within - P = P_arr[0] - material = mcdc["materials"][P["material_ID"]] - N_cs_bins = tally["filter"]["N_cs_bins"] - - cs_bin_size = tally["filter"]["cs_bin_size"] - cs_centers = tally["filter"]["cs_centers"] - - stride = tally["stride"] - bin_idx = stride["tally"] - - # Particle 4D direction - ux = P["ux"] - uy = P["uy"] - uz = P["uz"] - ut = 1.0 / physics.get_speed(P_arr, mcdc) - - # Particle initial and final coordinate - x = P["x"] - y = P["y"] - z = P["z"] - t = P["t"] - x_final = x + ux * distance - y_final = y + uy * distance - z_final = z + uz * distance - t_final = t + ut * distance - - # Check each coarse bin - for j in range(N_cs_bins): - center = adapt.local_array(2, type_.float64) - start = adapt.local_array(2, type_.float64) - end = adapt.local_array(2, type_.float64) - # - center[0] = cs_centers[0][j] - center[1] = cs_centers[1][j] - start[0] = x - start[1] = y - end[0] = x_final - end[1] = y_final - - distance_inside = calculate_distance_in_coarse_bin( - start, end, distance, center, cs_bin_size - ) - - # Last bin covers the whole problem - if j == N_cs_bins - 1: - cs_bin_size_full_problem = adapt.local_array(2, type_.float64) - cs_bin_size_full_problem[0] = INF - cs_bin_size_full_problem[1] = INF - distance_inside = calculate_distance_in_coarse_bin( - start, end, distance, center, cs_bin_size_full_problem - ) - - if distance < distance_inside: - distance_in_bin = distance - else: - distance_in_bin = distance_inside - - # Calculate flux and other scores - flux = distance_in_bin * P["w"] - for i in range(tally["N_score"]): - score_type = tally["scores"][i] - if score_type == SCORE_FLUX: - score = flux - elif score_type == SCORE_DENSITY: - score = flux / physics.get_speed(P_arr, mcdc) - elif score_type == SCORE_TOTAL: - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - score = flux * SigmaT - elif score_type == SCORE_FISSION: - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - score = flux * SigmaF - - adapt.global_add( - data_tally, - (TALLY_SCORE, bin_idx + j * tally["N_score"] + i), - round(score), - ) - - -@njit -def cs_clip(p, q, t): - if p < 0: - tc = q / p - if tc > t[1]: - return False - if tc > t[0]: - t[0] = tc - elif p > 0: - tc = q / p - if tc < t[0]: - return False - if tc < t[1]: - t[1] = tc - elif q < 0: - return False - return True - - -@njit -def cs_tracklength_in_box(base_start, base_end, x_min, x_max, y_min, y_max): - - start = adapt.local_array(2, type_.float64) - end = adapt.local_array(2, type_.float64) - start[0] = base_start[0] - start[1] = base_start[1] - end[0] = base_end[0] - end[1] = base_end[1] - - # Uses Liang-Barsky algorithm for finding tracklength in box - t = adapt.local_array(2, type_.float64) - t[0] = 0.0 - t[1] = 1.0 - dx = end[0] - start[0] - dy = end[1] - start[1] - - # Perform clipping for each boundary - # result = cs_clip(-dx, start[0] - x_min, t) - # if not result: - # return 0.0 - result = cs_clip(dx, x_max - start[1], t) - if not result: - return 0.0 - result = cs_clip(-dy, start[1] - y_min, t) - if not result: - return 0.0 - result = cs_clip(dy, y_max - start[1], t) - if not result: - return 0.0 - - ## Update start and end points based on clipping results - # if t[1] < 1: - # end[0] = start[0] + t[1] * dx - # end[1] = start[1] + t[1] * dy - # if t[0] > 0: - # start[0] = start[0] + t[0] * dx - # start[1] = start[1] + t[0] * dx - - # if t[0] > 0: - # start[0] = start[0] + t[0] * dx - # start[1] = start[1] + t[0] * dx - - # start[0] = start[0] + t[0] - # end[0] = start[0] - - ## Return the norm - # X = end[0] - start[0] - # Y = end[1] - start[1] - # return math.sqrt(X**2 + Y**2) - if t[0] == 0: - return 1 - else: - return 0 - - -@njit -def calculate_distance_in_coarse_bin(start, end, distance, center, cs_bin_size): - # Edges of the coarse bin - x_min = center[0] - cs_bin_size[0] / 2 - x_max = center[0] + cs_bin_size[0] / 2 - y_min = center[1] - cs_bin_size[1] / 2 - y_max = center[1] + cs_bin_size[1] / 2 - - distance_inside = cs_tracklength_in_box(start, end, x_min, x_max, y_min, y_max) - - return distance_inside - - -@njit -def dd_reduce(data_tally, mcdc): - - # find number of subdomains - d_Nx = mcdc["technique"]["dd_mesh"]["x"].size - 1 - d_Ny = mcdc["technique"]["dd_mesh"]["y"].size - 1 - d_Nz = mcdc["technique"]["dd_mesh"]["z"].size - 1 - - with objmode(): - # assign processors to their subdomain group - i = 0 - for n in range(d_Nx * d_Ny * d_Nz): - dd_group = [] - for r in range(int(mcdc["technique"]["dd_work_ratio"][n])): - dd_group.append(i) - i += 1 - # create MPI Comm group out of subdomain processors - dd_group = MPI.COMM_WORLD.group.Incl(dd_group) - dd_comm = MPI.COMM_WORLD.Create(dd_group) - # MPI Reduce on subdomain processors - buff = np.zeros_like(data_tally[TALLY_SCORE]) - if MPI.COMM_NULL != dd_comm: - dd_comm.Reduce(data_tally[TALLY_SCORE], buff, MPI.SUM, 0) - if mcdc["dd_idx"] == n: - data_tally[TALLY_SCORE][:] = buff - # free comm group - dd_group.Free() - if MPI.COMM_NULL != dd_comm: - dd_comm.Free() - - -@njit -def tally_reduce(data_tally, mcdc): - N_bin = data_tally.shape[1] - - # Normalize - N_particle = mcdc["setting"]["N_particle"] - for i in range(N_bin): - data_tally[TALLY_SCORE][i] /= N_particle - - if not mcdc["technique"]["domain_decomposition"]: - # MPI Reduce - buff = np.zeros_like(data_tally[TALLY_SCORE]) - with objmode(): - MPI.COMM_WORLD.Reduce(data_tally[TALLY_SCORE], buff, MPI.SUM, 0) - data_tally[TALLY_SCORE][:] = buff - - else: - # find number of subdomains - N_dd = 1 - N_dd *= mcdc["technique"]["dd_mesh"]["x"].size - 1 - N_dd *= mcdc["technique"]["dd_mesh"]["y"].size - 1 - N_dd *= mcdc["technique"]["dd_mesh"]["z"].size - 1 - # DD Reduce if multiple processors per subdomain - if N_dd != mcdc["mpi_size"]: - dd_reduce(data_tally, mcdc) - - -@njit -def tally_accumulate(data_tally, mcdc): - N_bin = data_tally.shape[1] - - for i in range(N_bin): - # Accumulate score and square of score into sum and sum_sq - score = data_tally[TALLY_SCORE, i] - data_tally[TALLY_SUM, i] += score - data_tally[TALLY_SUM_SQ, i] += score * score - - # Reset score bin - data_tally[TALLY_SCORE, i] = 0.0 - - -@njit -def census_based_tally_output(data_tally, mcdc): - idx_batch = mcdc["idx_batch"] - idx_census = mcdc["idx_census"] - N_bin = data_tally.shape[1] - - for i in range(N_bin): - # Store score and square of score - score = data_tally[TALLY_SCORE, i] - data_tally[TALLY_SUM, i] = score - data_tally[TALLY_SUM_SQ, i] = score * score - - # Reset score bin - data_tally[TALLY_SCORE, i] = 0.0 - - for ID, tally in enumerate(mcdc["mesh_tallies"]): - mesh = tally["filter"] - - # Get grid - Nx = mesh["Nx"] - Ny = mesh["Ny"] - Nz = mesh["Nz"] - Nt = mesh["Nt"] - Nmu = mesh["Nmu"] - N_azi = mesh["N_azi"] - Ng = mesh["Ng"] - # - grid_x = mesh["x"][: Nx + 1] - grid_y = mesh["y"][: Ny + 1] - grid_z = mesh["z"][: Nz + 1] - grid_t = mesh["t"][: Nt + 1] - grid_mu = mesh["mu"][: Nmu + 1] - grid_azi = mesh["azi"][: N_azi + 1] - grid_g = mesh["g"][: Ng + 1] - #''' - with objmode(): - if ID == 0: - f = h5py.File( - mcdc["setting"]["output_name"] - + "-batch_%i-census_%i.h5" % (idx_batch, idx_census), - "w", - ) - else: - f = h5py.File( - mcdc["setting"]["output_name"] - + "-batch_%i-census_%i.h5" % (idx_batch, idx_census), - "a", - ) - # Save to dataset - f.create_dataset("tallies/mesh_tally_%i/grid/x" % ID, data=grid_x) - f.create_dataset("tallies/mesh_tally_%i/grid/y" % ID, data=grid_y) - f.create_dataset("tallies/mesh_tally_%i/grid/z" % ID, data=grid_z) - f.create_dataset("tallies/mesh_tally_%i/grid/t" % ID, data=grid_t) - f.create_dataset("tallies/mesh_tally_%i/grid/mu" % ID, data=grid_mu) - f.create_dataset("tallies/mesh_tally_%i/grid/azi" % ID, data=grid_azi) - f.create_dataset("tallies/mesh_tally_%i/grid/g" % ID, data=grid_g) - - # Set tally shape - N_score = tally["N_score"] - if not mcdc["technique"]["uq"]: - shape = (3, Nmu, N_azi, Ng, Nt, Nx, Ny, Nz, N_score) - else: - shape = (5, Nmu, N_azi, Ng, Nt, Nx, Ny, Nz, N_score) - - # Reshape tally - N_bin = tally["N_bin"] - start = tally["stride"]["tally"] - tally_bin = data_tally[:, start : start + N_bin] - tally_bin = tally_bin.reshape(shape) - - # Roll tally so that score is in the front - tally_bin = np.rollaxis(tally_bin, 8, 0) - - # Iterate over scores - for i in range(N_score): - score_type = tally["scores"][i] - score_tally_bin = np.squeeze(tally_bin[i]) - score_name = "" - if score_type == SCORE_FLUX: - score_name = "flux" - elif score_type == SCORE_DENSITY: - score_name = "density" - elif score_type == SCORE_TOTAL: - score_name = "total" - elif score_type == SCORE_FISSION: - score_name = "fission" - group_name = "tallies/mesh_tally_%i/%s/" % (ID, score_name) - - tally_sum = score_tally_bin[TALLY_SUM] - tally_sum_sq = score_tally_bin[TALLY_SUM_SQ] - - f.create_dataset(group_name + "score", data=tally_sum) - f.create_dataset(group_name + "score_sq", data=tally_sum_sq) - if mcdc["technique"]["uq"]: - mc_var = score_tally_bin[TALLY_UQ_BATCH_VAR] - tot_var = score_tally_bin[TALLY_UQ_BATCH] - uq_var = tot_var - mc_var - f.create_dataset(group_name + "uq_var", data=uq_var) - f.close() - - -@njit -def dd_closeout(data_tally, mcdc): - # find number of subdomains - d_Nx = mcdc["technique"]["dd_mesh"]["x"].size - 1 - d_Ny = mcdc["technique"]["dd_mesh"]["y"].size - 1 - d_Nz = mcdc["technique"]["dd_mesh"]["z"].size - 1 - - with objmode(): - # assign processors to their subdomain group - i = 0 - for n in range(d_Nx * d_Ny * d_Nz): - dd_ranks = [] - for r in range(int(mcdc["technique"]["dd_work_ratio"][n])): - dd_ranks.append(i) - i += 1 - # create MPI Comm group out of subdomain processors - dd_group = MPI.COMM_WORLD.group.Incl(dd_ranks) - dd_comm = MPI.COMM_WORLD.Create(dd_group) - # MPI Reduce on subdomain processors - buff = np.zeros_like(data_tally[TALLY_SUM]) - buff_sq = np.zeros_like(data_tally[TALLY_SUM_SQ]) - if MPI.COMM_NULL != dd_comm: - dd_comm.Reduce(data_tally[TALLY_SUM], buff, MPI.SUM, 0) - dd_comm.Reduce(data_tally[TALLY_SUM_SQ], buff_sq, MPI.SUM, 0) - if mcdc["dd_idx"] == n: - data_tally[TALLY_SUM] = buff - data_tally[TALLY_SUM_SQ] = buff_sq - - # free comm group - dd_group.Free() - if MPI.COMM_NULL != dd_comm: - dd_comm.Free() - - -@njit -def tally_closeout(data_tally, mcdc): - N_history = mcdc["setting"]["N_particle"] - - if mcdc["setting"]["N_batch"] > 1: - N_history = mcdc["setting"]["N_batch"] - - elif mcdc["setting"]["mode_eigenvalue"]: - N_history = mcdc["setting"]["N_active"] - - elif not mcdc["technique"]["domain_decomposition"]: - # MPI Reduce - buff = np.zeros_like(data_tally[TALLY_SUM]) - buff_sq = np.zeros_like(data_tally[TALLY_SUM_SQ]) - with objmode(): - MPI.COMM_WORLD.Reduce(data_tally[TALLY_SUM], buff, MPI.SUM, 0) - MPI.COMM_WORLD.Reduce(data_tally[TALLY_SUM_SQ], buff_sq, MPI.SUM, 0) - data_tally[TALLY_SUM] = buff - data_tally[TALLY_SUM_SQ] = buff_sq - - else: - # find number of subdomains - N_dd = 1 - N_dd *= mcdc["technique"]["dd_mesh"]["x"].size - 1 - N_dd *= mcdc["technique"]["dd_mesh"]["y"].size - 1 - N_dd *= mcdc["technique"]["dd_mesh"]["z"].size - 1 - # DD Reduce if multiple processors per subdomain - if N_dd != mcdc["mpi_size"]: - dd_closeout(data_tally, mcdc) - # Calculate and store statistics - # sum --> mean - # sum_sq --> standard deviation - N_bin = data_tally.shape[1] - for i in range(N_bin): - data_tally[TALLY_SUM][i] = data_tally[TALLY_SUM][i] / N_history - radicand = ( - data_tally[TALLY_SUM_SQ][i] / N_history - - np.square(data_tally[TALLY_SUM][i]) - ) / (N_history - 1) - # Check for round-off error - if abs(radicand) < 1e-18: - data_tally[TALLY_SUM_SQ][i] = 0.0 - else: - data_tally[TALLY_SUM_SQ][i] = np.sqrt(radicand) - - -# ============================================================================= -# Eigenvalue tally operations -# ============================================================================= - - -@njit -def eigenvalue_tally(P_arr, distance, mcdc): - P = P_arr[0] - material = mcdc["materials"][P["material_ID"]] - flux = distance * P["w"] - - # Get nu-fission - nuSigmaF = get_MacroXS(XS_NU_FISSION, material, P_arr, mcdc) - - # Fission production (needed even during inactive cycle) - # mcdc["eigenvalue_tally_nuSigmaF"][0] += flux * nuSigmaF - adapt.global_add(mcdc["eigenvalue_tally_nuSigmaF"], 0, round(flux * nuSigmaF)) - - if mcdc["cycle_active"]: - # Neutron density - v = physics.get_speed(P_arr, mcdc) - n_density = flux / v - # mcdc["eigenvalue_tally_n"][0] += n_density - adapt.global_add(mcdc["eigenvalue_tally_n"], 0, round(n_density)) - # Maximum neutron density - if mcdc["n_max"] < n_density: - mcdc["n_max"] = n_density - - # Precursor density - J = material["J"] - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - # Get the decay-wighted multiplicity - total = 0.0 - if mcdc["setting"]["mode_MG"]: - g = P["g"] - for i in range(material["N_nuclide"]): - ID_nuclide = material["nuclide_IDs"][i] - nuclide = mcdc["nuclides"][ID_nuclide] - for j in range(J): - nu_d = nuclide["nu_d"][g, j] - decay = nuclide["decay"][j] - total += nu_d / decay - else: - E = P["E"] - for i in range(material["N_nuclide"]): - ID_nuclide = material["nuclide_IDs"][i] - nuclide = mcdc["nuclides"][ID_nuclide] - if not nuclide["fissionable"]: - continue - for j in range(J): - # HAZARD - nu_d = get_nu_group(NU_FISSION_DELAYED, nuclide, E, j) - decay = nuclide["ce_decay"][j] - total += nu_d / decay - C_density = flux * total * SigmaF / mcdc["k_eff"] - # mcdc["eigenvalue_tally_C"][0] += C_density - adapt.global_add(mcdc["eigenvalue_tally_C"], 0, round(C_density)) - # Maximum precursor density - if mcdc["C_max"] < C_density: - mcdc["C_max"] = C_density - - -@njit -def eigenvalue_tally_closeout_history(mcdc): - N_particle = mcdc["setting"]["N_particle"] - - idx_cycle = mcdc["idx_cycle"] - - # MPI Allreduce - buff_nuSigmaF = np.zeros(1, np.float64) - buff_n = np.zeros(1, np.float64) - buff_nmax = np.zeros(1, np.float64) - buff_C = np.zeros(1, np.float64) - buff_Cmax = np.zeros(1, np.float64) - buff_IC_fission = np.zeros(1, np.float64) - with objmode(): - MPI.COMM_WORLD.Allreduce( - np.array(mcdc["eigenvalue_tally_nuSigmaF"]), buff_nuSigmaF, MPI.SUM - ) - if mcdc["cycle_active"]: - MPI.COMM_WORLD.Allreduce( - np.array(mcdc["eigenvalue_tally_n"]), buff_n, MPI.SUM - ) - MPI.COMM_WORLD.Allreduce(np.array([mcdc["n_max"]]), buff_nmax, MPI.MAX) - MPI.COMM_WORLD.Allreduce( - np.array(mcdc["eigenvalue_tally_C"]), buff_C, MPI.SUM - ) - MPI.COMM_WORLD.Allreduce(np.array([mcdc["C_max"]]), buff_Cmax, MPI.MAX) - if mcdc["technique"]["IC_generator"]: - MPI.COMM_WORLD.Allreduce( - np.array(mcdc["technique"]["IC_fission_score"]), - buff_IC_fission, - MPI.SUM, - ) - - # Update and store k_eff - mcdc["k_eff"] = buff_nuSigmaF[0] / N_particle - mcdc["k_cycle"][idx_cycle] = mcdc["k_eff"] - - # Normalize other eigenvalue/global tallies - tally_n = buff_n[0] / N_particle - tally_C = buff_C[0] / N_particle - tally_IC_fission = buff_IC_fission[0] - - # Maximum densities - mcdc["n_max"] = buff_nmax[0] - mcdc["C_max"] = buff_Cmax[0] - - # Accumulate running average - if mcdc["cycle_active"]: - mcdc["k_avg"] += mcdc["k_eff"] - mcdc["k_sdv"] += mcdc["k_eff"] * mcdc["k_eff"] - mcdc["n_avg"] += tally_n - mcdc["n_sdv"] += tally_n * tally_n - mcdc["C_avg"] += tally_C - mcdc["C_sdv"] += tally_C * tally_C - - N = 1 + mcdc["idx_cycle"] - mcdc["setting"]["N_inactive"] - mcdc["k_avg_running"] = mcdc["k_avg"] / N - if N == 1: - mcdc["k_sdv_running"] = 0.0 - else: - mcdc["k_sdv_running"] = math.sqrt( - (mcdc["k_sdv"] / N - mcdc["k_avg_running"] ** 2) / (N - 1) - ) - - if mcdc["technique"]["IC_generator"]: - mcdc["technique"]["IC_fission"] += tally_IC_fission - - # Reset accumulators - mcdc["eigenvalue_tally_nuSigmaF"][0] = 0.0 - mcdc["eigenvalue_tally_n"][0] = 0.0 - mcdc["eigenvalue_tally_C"][0] = 0.0 - mcdc["technique"]["IC_fission_score"][0] = 0.0 - - # ===================================================================== - # Gyration radius - # ===================================================================== - - if mcdc["setting"]["gyration_radius"]: - # Center of mass - N_local = get_bank_size(mcdc["bank_census"]) - total_local = np.zeros(4, np.float64) # [x,y,z,W] - total = np.zeros(4, np.float64) - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - total_local[0] += P["x"] * P["w"] - total_local[1] += P["y"] * P["w"] - total_local[2] += P["z"] * P["w"] - total_local[3] += P["w"] - # MPI Allreduce - with objmode(): - MPI.COMM_WORLD.Allreduce(total_local, total, MPI.SUM) - # COM - W = total[3] - com_x = total[0] / W - com_y = total[1] / W - com_z = total[2] / W - - # Distance RMS - rms_local = np.zeros(1, np.float64) - rms = np.zeros(1, np.float64) - gr_type = mcdc["setting"]["gyration_radius_type"] - if gr_type == GYRATION_RADIUS_ALL: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ( - (P["x"] - com_x) ** 2 - + (P["y"] - com_y) ** 2 - + (P["z"] - com_z) ** 2 - ) * P["w"] - elif gr_type == GYRATION_RADIUS_INFINITE_X: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["y"] - com_y) ** 2 + (P["z"] - com_z) ** 2) * P["w"] - elif gr_type == GYRATION_RADIUS_INFINITE_Y: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["x"] - com_x) ** 2 + (P["z"] - com_z) ** 2) * P["w"] - elif gr_type == GYRATION_RADIUS_INFINITE_Z: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["x"] - com_x) ** 2 + (P["y"] - com_y) ** 2) * P["w"] - elif gr_type == GYRATION_RADIUS_ONLY_X: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["x"] - com_x) ** 2) * P["w"] - elif gr_type == GYRATION_RADIUS_ONLY_Y: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["y"] - com_y) ** 2) * P["w"] - elif gr_type == GYRATION_RADIUS_ONLY_Z: - for i in range(N_local): - P = mcdc["bank_census"]["particles"][i] - rms_local[0] += ((P["z"] - com_z) ** 2) * P["w"] - - # MPI Allreduce - with objmode(): - MPI.COMM_WORLD.Allreduce(rms_local, rms, MPI.SUM) - rms = math.sqrt(rms[0] / W) - - # Gyration radius - mcdc["gyration_radius"][idx_cycle] = rms - - -@njit -def eigenvalue_tally_closeout(mcdc): - N = mcdc["setting"]["N_active"] - mcdc["n_avg"] /= N - mcdc["C_avg"] /= N - if N > 1: - mcdc["n_sdv"] = math.sqrt((mcdc["n_sdv"] / N - mcdc["n_avg"] ** 2) / (N - 1)) - mcdc["C_sdv"] = math.sqrt((mcdc["C_sdv"] / N - mcdc["C_avg"] ** 2) / (N - 1)) - else: - mcdc["n_sdv"] = 0.0 - mcdc["C_sdv"] = 0.0 - - -# ====================================================================================== -# Move to event -# ====================================================================================== - - -@njit -def move_to_event(P_arr, data_tally, mcdc): - # ================================================================================== - # Preparation (as needed) - # ================================================================================== - P = P_arr[0] - - # Multigroup preparation - # In MG mode, particle speed is material-dependent. - if mcdc["setting"]["mode_MG"]: - # If material is not identified yet, locate the particle - if P["material_ID"] == -1: - if not geometry.locate_particle(P_arr, mcdc): - # Particle is lost - P["event"] = EVENT_LOST - return - - # ================================================================================== - # Geometry inspection - # ================================================================================== - # - Set particle top cell and material IDs (if not lost) - # - Set surface ID (if surface hit) - # - Set particle boundary event (surface or lattice crossing, or lost) - # - Return distance to boundary (surface or lattice) - - d_boundary = geometry.inspect_geometry(P_arr, mcdc) - - # Particle is lost? - if P["event"] == EVENT_LOST: - return - - # ================================================================================== - # Get distances to other events - # ================================================================================== - - # Distance to domain - speed = physics.get_speed(P_arr, mcdc) - d_domain = INF - if mcdc["technique"]["domain_decomposition"]: - d_domain = mesh_.structured.get_crossing_distance( - P_arr, speed, mcdc["technique"]["dd_mesh"] - ) - - # Distance to time boundary - d_time_boundary = speed * (mcdc["setting"]["time_boundary"] - P["t"]) - - # Distance to census time - idx = mcdc["idx_census"] - d_time_census = speed * (mcdc["setting"]["census_time"][idx] - P["t"]) - - # Distance to next collision - d_collision = distance_to_collision(P_arr, mcdc) - - # ========================================================================= - # Determine event(s) - # ========================================================================= - # TODO: Make a function to better maintain the repeating operation - - distance = d_boundary - - # Check distance to domain - if d_domain < distance - COINCIDENCE_TOLERANCE: - distance = d_domain - P["event"] = EVENT_DOMAIN_CROSSING - P["surface_ID"] = -1 - elif geometry.check_coincidence(d_domain, distance): - P["event"] += EVENT_DOMAIN_CROSSING - - # Check distance to collision - if d_collision < distance - COINCIDENCE_TOLERANCE: - distance = d_collision - P["event"] = EVENT_COLLISION - P["surface_ID"] = -1 - elif geometry.check_coincidence(d_collision, distance): - P["event"] += EVENT_COLLISION - - # Check distance to time census - if d_time_census < distance - COINCIDENCE_TOLERANCE: - distance = d_time_census - P["event"] = EVENT_TIME_CENSUS - P["surface_ID"] = -1 - elif geometry.check_coincidence(d_time_census, distance): - P["event"] += EVENT_TIME_CENSUS - - # Check distance to time boundary (exclusive event) - if d_time_boundary < distance + COINCIDENCE_TOLERANCE: - distance = d_time_boundary - P["event"] = EVENT_TIME_BOUNDARY - P["surface_ID"] = -1 - - # ========================================================================= - # Move particle - # ========================================================================= - - # Score tracklength tallies - if mcdc["cycle_active"]: - # Mesh tallies - for tally in mcdc["mesh_tallies"]: - score_mesh_tally(P_arr, distance, tally, data_tally, mcdc) - - # Cell tallies - cell = mcdc["cells"][P["cell_ID"]] - for i in range(cell["N_tally"]): - ID = cell["tally_IDs"][i] - tally = mcdc["cell_tallies"][ID] - score_cell_tally(P_arr, distance, tally, data_tally, mcdc) - - # CS tallies - # HAZARD - for tally in mcdc["cs_tallies"]: - score_cs_tally(P_arr, distance, tally, data_tally, mcdc) - - if mcdc["setting"]["mode_eigenvalue"]: - eigenvalue_tally(P_arr, distance, mcdc) - - # Move particle - move_particle(P_arr, distance, mcdc) - - -@njit -def distance_to_collision(P_arr, mcdc): - P = P_arr[0] - # Get total cross-section - material = mcdc["materials"][P["material_ID"]] - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - - # Vacuum material? - if SigmaT == 0.0: - return INF - - # Sample collision distance - xi = rng(P_arr) - distance = -math.log(xi) / SigmaT - return distance - - -# ============================================================================= -# Surface crossing -# ============================================================================= - - -@njit -def surface_crossing(P_arr, data_tally, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - # Apply BC - surface = mcdc["surfaces"][P["surface_ID"]] - if surface["BC"] == BC_VACUUM: - P["alive"] = False - elif surface["BC"] == BC_REFLECTIVE: - surface_.reflect(P_arr, surface) - - # Score tally - # N_tally is an int64, tally_IDs is a numpy.ndarray - for i in range(surface["N_tally"]): - ID = surface["tally_IDs"][i] - tally = mcdc["surface_tallies"][ID] - score_surface_tally(P_arr, surface, tally, data_tally, mcdc) - - # Need to check new cell later? - if P["alive"] and not surface["BC"] == BC_REFLECTIVE: - P["cell_ID"] = -1 - P["material_ID"] = -1 - - -# ============================================================================= -# Collision -# ============================================================================= - - -@njit -def collision(P_arr, mcdc): - P = P_arr[0] - # Get the reaction cross-sections - material = mcdc["materials"][P["material_ID"]] - g = P["g"] - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - SigmaS = get_MacroXS(XS_SCATTER, material, P_arr, mcdc) - SigmaC = get_MacroXS(XS_CAPTURE, material, P_arr, mcdc) - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - - # Implicit capture - if mcdc["technique"]["implicit_capture"]: - P["w"] *= (SigmaT - SigmaC) / SigmaT - SigmaT -= SigmaC - - # Sample collision type - xi = rng(P_arr) * SigmaT - tot = SigmaS - if tot > xi: - P["event"] += EVENT_SCATTERING - else: - tot += SigmaF - if tot > xi: - P["event"] += EVENT_FISSION - else: - P["event"] += EVENT_CAPTURE - - -# ============================================================================= -# Scattering -# ============================================================================= - - -@njit -def scattering(P_arr, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - # Kill the current particle - P["alive"] = False - - # Get effective and new weight - if mcdc["technique"]["weighted_emission"]: - weight_eff = P["w"] - weight_new = 1.0 - else: - weight_eff = 1.0 - weight_new = P["w"] - - # Get number of secondaries - material = mcdc["materials"][P["material_ID"]] - g = P["g"] - if mcdc["setting"]["mode_MG"]: - nu_s = material["nu_s"][g] - N = int(math.floor(weight_eff * nu_s + rng(P_arr))) - else: - N = 1 - - P_new_arr = adapt.local_array(1, type_.particle_record) - P_new = P_new_arr[0] - - for n in range(N): - # Create new particle - split_as_record(P_new_arr, P_arr) - - # Set weight - P_new["w"] = weight_new - - # Sample scattering phase space - sample_phasespace_scattering(P_arr, material, P_new_arr, mcdc) - - # Bank, but keep it if it is the last particle - if n == N - 1: - P["alive"] = True - P["ux"] = P_new["ux"] - P["uy"] = P_new["uy"] - P["uz"] = P_new["uz"] - P["g"] = P_new["g"] - P["E"] = P_new["E"] - P["w"] = P_new["w"] - else: - adapt.add_active(P_new_arr, prog) - - -@njit -def sample_phasespace_scattering(P_arr, material, P_new_arr, mcdc): - P_new = P_new_arr[0] - P = P_arr[0] - # Copy relevant attributes - P_new["x"] = P["x"] - P_new["y"] = P["y"] - P_new["z"] = P["z"] - P_new["t"] = P["t"] - - if mcdc["setting"]["mode_MG"]: - scattering_MG(P_arr, material, P_new_arr) - else: - scattering_CE(P_arr, material, P_new_arr, mcdc) - - -@njit -def sample_phasespace_scattering_nuclide(P_arr, nuclide, P_new_arr): - P_new = P_new_arr[0] - P = P_arr[0] - # Copy relevant attributes - P_new["x"] = P["x"] - P_new["y"] = P["y"] - P_new["z"] = P["z"] - P_new["t"] = P["t"] - - scattering_MG(P_arr, nuclide, P_new_arr) - - -@njit -def scattering_MG(P_arr, material, P_new_arr): - P_new = P_new_arr[0] - P = P_arr[0] - # Sample scattering angle - mu0 = 2.0 * rng(P_new_arr) - 1.0 - - # Scatter direction - azi = 2.0 * PI * rng(P_new_arr) - P_new["ux"], P_new["uy"], P_new["uz"] = scatter_direction( - P["ux"], P["uy"], P["uz"], mu0, azi - ) - - # Get outgoing spectrum - g = P["g"] - G = material["G"] - chi_s = material["chi_s"][g] - - # Sample outgoing energy - xi = rng(P_new_arr) - tot = 0.0 - for g_out in range(G): - tot += chi_s[g_out] - if tot > xi: - break - P_new["g"] = g_out - - -@njit -def scattering_CE(P_arr, material, P_new_arr, mcdc): - P_new = P_new_arr[0] - P = P_arr[0] - """ - Scatter with sampled scattering angle mu0, with nucleus mass A - Scattering is treated in Center of mass (COM) frame - Current model: - - Free gas scattering - - Constant thermal cross section - - Isotropic in COM - """ - # Sample nuclide - nuclide = sample_nuclide(material, P_arr, XS_SCATTER, mcdc) - xi = rng(P_arr) * get_MacroXS(XS_SCATTER, material, P_arr, mcdc) - tot = 0.0 - for i in range(material["N_nuclide"]): - ID_nuclide = material["nuclide_IDs"][i] - nuclide = mcdc["nuclides"][ID_nuclide] - N = material["nuclide_densities"][i] - tot += N * get_microXS(XS_SCATTER, nuclide, P["E"]) - if tot > xi: - break - - # Sample nucleus thermal speed - A = nuclide["A"] - if P["E"] > E_THERMAL_THRESHOLD: - Vx = 0.0 - Vy = 0.0 - Vz = 0.0 - else: - Vx, Vy, Vz = sample_nucleus_speed(A, P_arr, mcdc) - - # ========================================================================= - # COM kinematics - # ========================================================================= - - # Particle speed - P_speed = physics.get_speed(P_arr, mcdc) - - # Neutron velocity - LAB - vx = P_speed * P["ux"] - vy = P_speed * P["uy"] - vz = P_speed * P["uz"] - - # COM velocity - COM_x = (vx + A * Vx) / (1.0 + A) - COM_y = (vy + A * Vy) / (1.0 + A) - COM_z = (vz + A * Vz) / (1.0 + A) - - # Neutron velocity - COM - vx = vx - COM_x - vy = vy - COM_y - vz = vz - COM_z - - # Neutron speed - COM - P_speed = math.sqrt(vx * vx + vy * vy + vz * vz) - - # Neutron initial direction - COM - ux = vx / P_speed - uy = vy / P_speed - uz = vz / P_speed - - # Scatter the direction in COM - mu0 = 2.0 * rng(P_arr) - 1.0 - azi = 2.0 * PI * rng(P_arr) - ux_new, uy_new, uz_new = scatter_direction(ux, uy, uz, mu0, azi) - - # Neutron final velocity - COM - vx = P_speed * ux_new - vy = P_speed * uy_new - vz = P_speed * uz_new - - # ========================================================================= - # COM to LAB - # ========================================================================= - - # Final velocity - LAB - vx = vx + COM_x - vy = vy + COM_y - vz = vz + COM_z - - # Final energy - LAB - P_speed = math.sqrt(vx * vx + vy * vy + vz * vz) - P_new["E"] = 5.2270376e-13 * P_speed * P_speed - # constant: 0.5 / (1.60217662e-19 J/eV) * (1.674927471e-27 kg) / (10000 cm^2/m^2) - - # Final direction - LAB - P_new["ux"] = vx / P_speed - P_new["uy"] = vy / P_speed - P_new["uz"] = vz / P_speed - - -@njit -def sample_nucleus_speed(A, P_arr, mcdc): - P = P_arr[0] - # Particle speed - P_speed = physics.get_speed(P_arr, mcdc) - - # Maxwellian parameter - beta = math.sqrt(2.0659834e-11 * A) - # The constant above is - # (1.674927471e-27 kg) / (1.38064852e-19 cm^2 kg s^-2 K^-1) / (293.6 K)/2 - - # Sample nuclide speed candidate V_tilda and - # nuclide-neutron polar cosine candidate mu_tilda via - # rejection sampling - y = beta * P_speed - while True: - if rng(P_arr) < 2.0 / (2.0 + PI_SQRT * y): - x = math.sqrt(-math.log(rng(P_arr) * rng(P_arr))) - else: - cos_val = math.cos(PI_HALF * rng(P_arr)) - x = math.sqrt( - -math.log(rng(P_arr)) - math.log(rng(P_arr)) * cos_val * cos_val - ) - V_tilda = x / beta - mu_tilda = 2.0 * rng(P_arr) - 1.0 - - # Accept candidate V_tilda and mu_tilda? - if rng(P_arr) > math.sqrt( - P_speed * P_speed + V_tilda * V_tilda - 2.0 * P_speed * V_tilda * mu_tilda - ) / (P_speed + V_tilda): - break - - # Set nuclide velocity - LAB - azi = 2.0 * PI * rng(P_arr) - ux, uy, uz = scatter_direction(P["ux"], P["uy"], P["uz"], mu_tilda, azi) - Vx = ux * V_tilda - Vy = uy * V_tilda - Vz = uz * V_tilda - - return Vx, Vy, Vz - - -@njit -def scatter_direction(ux, uy, uz, mu0, azi): - cos_azi = math.cos(azi) - sin_azi = math.sin(azi) - Ac = (1.0 - mu0**2) ** 0.5 - - if uz != 1.0: - B = (1.0 - uz**2) ** 0.5 - C = Ac / B - - ux_new = ux * mu0 + (ux * uz * cos_azi - uy * sin_azi) * C - uy_new = uy * mu0 + (uy * uz * cos_azi + ux * sin_azi) * C - uz_new = uz * mu0 - cos_azi * Ac * B - - # If dir = 0i + 0j + k, interchange z and y in the scattering formula - else: - B = (1.0 - uy**2) ** 0.5 - C = Ac / B - - ux_new = ux * mu0 + (ux * uy * cos_azi - uz * sin_azi) * C - uz_new = uz * mu0 + (uz * uy * cos_azi + ux * sin_azi) * C - uy_new = uy * mu0 - cos_azi * Ac * B - - return ux_new, uy_new, uz_new - - -# ============================================================================= -# Fission -# ============================================================================= - - -@njit -def fission(P_arr, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - # Kill the current particle - P["alive"] = False - - # Get effective and new weight - if mcdc["technique"]["weighted_emission"]: - weight_eff = P["w"] - weight_new = 1.0 - else: - weight_eff = 1.0 - weight_new = P["w"] - - # Sample nuclide if CE - material = mcdc["materials"][P["material_ID"]] - nuclide = mcdc["nuclides"][0] # Default nuclide, will be resampled for CE - - # Get number of secondaries - if mcdc["setting"]["mode_MG"]: - g = P["g"] - nu = material["nu_f"][g] - else: - nuclide = sample_nuclide(material, P_arr, XS_FISSION, mcdc) - E = P["E"] - nu = get_nu(NU_FISSION, nuclide, E) - N = int(math.floor(weight_eff * nu / mcdc["k_eff"] + rng(P_arr))) - - P_new_arr = adapt.local_array(1, type_.particle_record) - P_new = P_new_arr[0] - - for n in range(N): - # Create new particle - split_as_record(P_new_arr, P_arr) - - # Set weight - P_new["w"] = weight_new - - # Sample fission neutron phase space - if mcdc["setting"]["mode_MG"]: - sample_phasespace_fission(P_arr, material, P_new_arr, mcdc) - else: - sample_phasespace_fission_nuclide(P_arr, nuclide, P_new_arr, mcdc) - - # Eigenvalue mode: bank right away - if mcdc["setting"]["mode_eigenvalue"]: - adapt.add_census(P_new_arr, prog) - continue - # Below is only relevant for fixed-source problem - - # Skip if it's beyond time boundary - if P_new["t"] > mcdc["setting"]["time_boundary"]: - continue - - # Check if it is beyond current or next census times - hit_census = False - hit_next_census = False - idx_census = mcdc["idx_census"] - if idx_census < mcdc["setting"]["N_census"] - 1: - if P["t"] > mcdc["setting"]["census_time"][idx_census + 1]: - hit_census = True - hit_next_census = True - elif P_new["t"] > mcdc["setting"]["census_time"][idx_census]: - hit_census = True - - if not hit_census: - # Keep it if it is the last particle - if n == N - 1: - P["alive"] = True - P["ux"] = P_new["ux"] - P["uy"] = P_new["uy"] - P["uz"] = P_new["uz"] - P["t"] = P_new["t"] - P["g"] = P_new["g"] - P["E"] = P_new["E"] - P["w"] = P_new["w"] - else: - adapt.add_active(P_new_arr, prog) - elif not hit_next_census: - # Particle will participate after the current census - adapt.add_census(P_new_arr, prog) - else: - # Particle will participate in the future - adapt.add_future(P_new_arr, prog) - - -@njit -def sample_phasespace_fission(P_arr, material, P_new_arr, mcdc): - P_new = P_new_arr[0] - P = P_arr[0] - # Get constants - G = material["G"] - J = material["J"] - g = P["g"] - nu = material["nu_f"][g] - nu_p = material["nu_p"][g] - if J > 0: - nu_d = material["nu_d"][g] - - # Copy relevant attributes - P_new["x"] = P["x"] - P_new["y"] = P["y"] - P_new["z"] = P["z"] - P_new["t"] = P["t"] - - # Sample isotropic direction - P_new["ux"], P_new["uy"], P_new["uz"] = sample_isotropic_direction(P_new_arr) - - # Prompt or delayed? - xi = rng(P_new_arr) * nu - tot = nu_p - if xi < tot: - prompt = True - spectrum = material["chi_p"][g] - else: - prompt = False - - # Determine delayed group and nuclide-dependent decay constant and spectrum - for j in range(J): - tot += nu_d[j] - if xi < tot: - # Delayed group determined, now determine nuclide - N_nuclide = material["N_nuclide"] - if N_nuclide == 1: - nuclide = mcdc["nuclides"][material["nuclide_IDs"][0]] - spectrum = nuclide["chi_d"][j] - decay = nuclide["decay"][j] - break - SigmaF = get_MacroXS(XS_FISSION, material, P_arr, mcdc) - xi = rng(P_new_arr) * nu_d[j] * SigmaF - tot = 0.0 - for i in range(N_nuclide): - nuclide = mcdc["nuclides"][material["nuclide_IDs"][i]] - density = material["nuclide_densities"][i] - tot += density * nuclide["nu_d"][g, j] * nuclide["fission"][g] - if xi < tot: - # Nuclide determined, now get the constant and spectruum - spectrum = nuclide["chi_d"][j] - decay = nuclide["decay"][j] - break - break - - # Sample outgoing energy - xi = rng(P_new_arr) - tot = 0.0 - for g_out in range(G): - tot += spectrum[g_out] - if tot > xi: - break - P_new["g"] = g_out - - # Sample emission time - if not prompt: - xi = rng(P_new_arr) - P_new["t"] -= math.log(xi) / decay - - -@njit -def sample_phasespace_fission_nuclide(P_arr, nuclide, P_new_arr, mcdc): - P_new = P_new_arr[0] - P = P_arr[0] - # Copy relevant attributes - P_new["x"] = P["x"] - P_new["y"] = P["y"] - P_new["z"] = P["z"] - P_new["t"] = P["t"] - - # Sample isotropic direction - P_new["ux"], P_new["uy"], P_new["uz"] = sample_isotropic_direction(P_new_arr) - - if mcdc["setting"]["mode_MG"]: - fission_MG(P_arr, nuclide, P_new_arr) - else: - fission_CE(P_arr, nuclide, P_new_arr, mcdc) - - -@njit -def fission_MG(P_arr, nuclide, P_new_arr): - P_new = P_new_arr[0] - P = P_arr[0] - # Get constants - G = nuclide["G"] - J = nuclide["J"] - g = P["g"] - nu = nuclide["nu_f"][g] - nu_p = nuclide["nu_p"][g] - if J > 0: - nu_d = nuclide["nu_d"][g] - - # Prompt or delayed? - xi = rng(P_new_arr) * nu - tot = nu_p - if xi < tot: - prompt = True - spectrum = nuclide["chi_p"][g] - else: - prompt = False - - # Determine delayed group - for j in range(J): - tot += nu_d[j] - if xi < tot: - spectrum = nuclide["chi_d"][j] - decay = nuclide["decay"][j] - break - - # Sample outgoing energy - xi = rng(P_new_arr) - tot = 0.0 - for g_out in range(G): - tot += spectrum[g_out] - if tot > xi: - break - P_new["g"] = g_out - - # Sample emission time - if not prompt: - xi = rng(P_new_arr) - P_new["t"] -= math.log(xi) / decay - - -@njit -def fission_CE(P_arr, nuclide, P_new_arr, mcdc): - P_new = P_new_arr[0] - P = P_arr[0] - # Get constants - E = P["E"] - J = 6 - nu = get_nu(NU_FISSION, nuclide, E) - nu_p = get_nu(NU_FISSION_PROMPT, nuclide, E) - nu_d = adapt.local_array(J, type_.float64) - for j in range(J): - nu_d[j] = get_nu_group(NU_FISSION_DELAYED, nuclide, E, j) - - # Delayed? - prompt = True - delayed_group = -1 - xi = rng(P_new_arr) * nu - tot = nu_p - if xi > tot: - prompt = False - - # Determine delayed group - for j in range(J): - tot += nu_d[j] - if xi < tot: - delayed_group = j - break - - # Sample outgoing energy - if prompt: - E_chi = nuclide["E_chi_p"] - NE_chi = nuclide["NE_chi_p"] - chi = nuclide["ce_chi_p"] - P_new["E"] = sample_Eout( - P_new_arr, nuclide["E_chi_p"], nuclide["NE_chi_p"], nuclide["ce_chi_p"] - ) - else: - if delayed_group == 0: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d1"], - nuclide["NE_chi_d1"], - nuclide["ce_chi_d1"], - ) - elif delayed_group == 1: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d2"], - nuclide["NE_chi_d2"], - nuclide["ce_chi_d2"], - ) - elif delayed_group == 2: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d3"], - nuclide["NE_chi_d3"], - nuclide["ce_chi_d3"], - ) - elif delayed_group == 3: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d4"], - nuclide["NE_chi_d4"], - nuclide["ce_chi_d4"], - ) - elif delayed_group == 4: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d5"], - nuclide["NE_chi_d5"], - nuclide["ce_chi_d5"], - ) - else: - P_new["E"] = sample_Eout( - P_new_arr, - nuclide["E_chi_d6"], - nuclide["NE_chi_d6"], - nuclide["ce_chi_d6"], - ) - - # Sample emission time - if not prompt: - xi = rng(P_new_arr) - P_new["t"] -= math.log(xi) / nuclide["ce_decay"][delayed_group] - - -# ============================================================================= -# Branchless collision -# ============================================================================= - - -@njit -def branchless_collision(P_arr, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - material = mcdc["materials"][P["material_ID"]] - - # Adjust weight - SigmaT = get_MacroXS(XS_TOTAL, material, P_arr, mcdc) - n_scatter = get_MacroXS(XS_NU_SCATTER, material, P_arr, mcdc) - n_fission = get_MacroXS(XS_NU_FISSION, material, P_arr, mcdc) / mcdc["k_eff"] - n_total = n_fission + n_scatter - P["w"] *= n_total / SigmaT - - P_rec_arr = adapt.local_array(1, type_.particle_record) - - # Set spectrum and decay rate - if rng(P_arr) < n_scatter / n_total: - sample_phasespace_scattering(P_arr, material, P_arr, mcdc) - else: - if mcdc["setting"]["mode_MG"]: - sample_phasespace_fission(P_arr, material, P_arr, mcdc) - else: - nuclide = sample_nuclide(material, P_arr, XS_NU_FISSION, mcdc) - sample_phasespace_fission_nuclide(P_arr, nuclide, P_arr, mcdc) - - # Beyond time census or time boundary? - idx_census = mcdc["idx_census"] - if P["t"] > mcdc["setting"]["census_time"][idx_census]: - P["alive"] = False - split_as_record(P_rec_arr, P_arr) - adapt.add_active(P_rec_arr, prog) - elif P["t"] > mcdc["setting"]["time_boundary"]: - P["alive"] = False - - -# ============================================================================= -# Weight window -# ============================================================================= - - -@njit -def weight_window(P_arr, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - # Get indices - ix, iy, iz, it, outside = mesh_.structured.get_indices( - P_arr, mcdc["technique"]["ww"]["mesh"] - ) - - # Target weight - w_target = mcdc["technique"]["ww"]["center"][it, ix, iy, iz] - - # Population control factor - w_target *= mcdc["technique"]["pc_factor"] - - # Surviving probability - p = P["w"] / w_target - - # Window width - width = mcdc["technique"]["ww"]["width"] - - P_new_arr = adapt.local_array(1, type_.particle_record) - - # If above target - if p > width: - # Set target weight - P["w"] = w_target - - # Splitting (keep the original particle) - n_split = math.floor(p) - for i in range(n_split - 1): - split_as_record(P_new_arr, P_arr) - adapt.add_active(P_new_arr, prog) - - # Russian roulette - p -= n_split - xi = rng(P_arr) - if xi <= p: - split_as_record(P_new_arr, P_arr) - adapt.add_active(P_new_arr, prog) - - # Below target - elif p < 1.0 / width: - # Russian roulette - xi = rng(P_arr) - if xi > p: - P["alive"] = False - else: - P["w"] = w_target - - -@njit -def update_weight_windows(data, mcdc): - idx_batch = mcdc["idx_batch"] - idx_census = mcdc["idx_census"] - epsilon = mcdc["technique"]["ww"]["epsilon"] - # accessing most recent tally dump - with objmode(): - f = h5py.File( - mcdc["setting"]["output_name"] - + "-batch_%i-census_%i.h5" % (idx_batch, idx_census), - "r", - ) - tallies = f["tallies/mesh_tally_" + str(mcdc["technique"]["ww"]["tally_idx"])] - if mcdc["setting"]["census_tally_frequency"] > 1: - old_flux = tallies["flux"]["score"][-1] - else: - old_flux = tallies["flux"]["score"] - Nx = mcdc["technique"]["ww"]["mesh"]["Nx"] - Ny = mcdc["technique"]["ww"]["mesh"]["Ny"] - Nz = mcdc["technique"]["ww"]["mesh"]["Nz"] - Nt = mcdc["technique"]["ww"]["mesh"]["Nt"] - - ax_expand = [] - if Nx == 1: - ax_expand.append(0) - if Ny == 1: - ax_expand.append(1) - if Nz == 1: - ax_expand.append(2) - for ax in ax_expand: - old_flux = np.expand_dims(old_flux, axis=ax) - center = old_flux - - if epsilon[WW_WOLLABER] > 0: - w_min = epsilon[WW_WOLLABER + 1] - center = (center) * ( - 1 - + (1 / epsilon[WW_WOLLABER] - 1) - * np.exp(-(center - w_min) / epsilon[WW_WOLLABER]) - ) - if epsilon[WW_MIN] > 0: - center = center * (1 - epsilon[WW_MIN]) + epsilon[WW_MIN] - center[center <= 0] = epsilon[WW_MIN] - center /= np.max(center) - mcdc["technique"]["ww"]["center"][idx_census + 1] = center - - -# ============================================================================= -# Weight Roulette -# ============================================================================= - - -@njit -def weight_roulette(P_arr, mcdc): - P = P_arr[0] - w_survive = mcdc["technique"]["wr_survive"] - prob_survive = P["w"] / w_survive - if rng(P_arr) <= prob_survive: - P["w"] = w_survive - if mcdc["technique"]["iQMC"]: - P["iqmc"]["w"][:] = w_survive - else: - P["alive"] = False - - -# ============================================================================= -# Continuous Energy Physics -# ============================================================================= - - -@njit -def get_MacroXS(type_, material, P_arr, mcdc): - P = P_arr[0] - # Multigroup XS - g = P["g"] - if mcdc["setting"]["mode_MG"]: - # Cross sections - if type_ == XS_TOTAL: - return material["total"][g] - elif type_ == XS_SCATTER: - return material["scatter"][g] - elif type_ == XS_CAPTURE: - return material["capture"][g] - elif type_ == XS_FISSION: - return material["fission"][g] - - # Productions - elif type_ == XS_NU_SCATTER: - nu = material["nu_s"][g] - scatter = material["scatter"][g] - return nu * scatter - elif type_ == XS_NU_FISSION: - nu = material["nu_f"][g] - fission = material["fission"][g] - return nu * fission - elif type_ == XS_NU_FISSION_PROMPT: - nu_p = material["nu_p"][g] - fission = material["fission"][g] - return nu_p * fission - elif type_ == XS_NU_FISSION_DELAYED: - nu_d = 0.0 - for j in range(material["J"]): - nu_d += material["nu_d"][g, j] - fission = material["fission"][g] - return nu_d * fission - - # Continuous-energy XS - MacroXS = 0.0 - E = P["E"] - - # Sum over all nuclides - for i in range(material["N_nuclide"]): - ID_nuclide = material["nuclide_IDs"][i] - nuclide = mcdc["nuclides"][ID_nuclide] - - # Get nuclide density - N = material["nuclide_densities"][i] - - # Get microscopic cross-section - microXS = get_microXS(type_, nuclide, E) - - # Accumulate - MacroXS += N * microXS - - return MacroXS - - -@njit -def get_microXS(type_, nuclide, E): - # Cross sections - if type_ == XS_TOTAL: - data = nuclide["ce_total"] - return get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - elif type_ == XS_SCATTER: - data = nuclide["ce_scatter"] - return get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - elif type_ == XS_CAPTURE: - data = nuclide["ce_capture"] - return get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - elif type_ == XS_FISSION: - if not nuclide["fissionable"]: - return 0.0 - data = nuclide["ce_fission"] - return get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - - # Binary Multiplicities - elif type_ == XS_NU_SCATTER: - data = nuclide["ce_scatter"] - xs = get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - nu = 1.0 - return nu * xs - elif type_ == XS_NU_FISSION: - if not nuclide["fissionable"]: - return 0.0 - data = nuclide["ce_fission"] - xs = get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - nu = get_nu(NU_FISSION, nuclide, E) - return nu * xs - elif type_ == XS_NU_FISSION_PROMPT: - if not nuclide["fissionable"]: - return 0.0 - data = nuclide["ce_fission"] - xs = get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - nu = get_nu(NU_FISSION_PROMPT, nuclide, E) - return nu * xs - elif type_ == XS_NU_FISSION_DELAYED: - if not nuclide["fissionable"]: - return 0.0 - data = nuclide["ce_fission"] - xs = get_XS(data, E, nuclide["E_xs"], nuclide["NE_xs"]) - nu = get_nu(NU_FISSION_DELAYED, nuclide, E) - return nu * xs - - -@njit -def get_XS(data, E, E_grid, NE): - # Search XS energy bin index - idx = binary_search_with_length(E, E_grid, NE) - - # Extrapolate if E is outside the given data - if idx == -1: - idx = 0 - elif idx + 1 == NE: - idx -= 1 - - # Linear interpolation - E1 = E_grid[idx] - E2 = E_grid[idx + 1] - XS1 = data[idx] - XS2 = data[idx + 1] - - return XS1 + (E - E1) * (XS2 - XS1) / (E2 - E1) - - -@njit -def get_nu_group(type_, nuclide, E, group): - if type_ == NU_FISSION: - nu = get_XS(nuclide["ce_nu_p"], E, nuclide["E_nu_p"], nuclide["NE_nu_p"]) - for i in range(6): - nu += get_XS( - nuclide["ce_nu_d"][i], E, nuclide["E_nu_d"], nuclide["NE_nu_d"] - ) - return nu - - if type_ == NU_FISSION_PROMPT: - return get_XS(nuclide["ce_nu_p"], E, nuclide["E_nu_p"], nuclide["NE_nu_p"]) - - if type_ == NU_FISSION_DELAYED and group == -1: - tot = 0.0 - for i in range(6): - tot += get_XS( - nuclide["ce_nu_d"][i], E, nuclide["E_nu_d"], nuclide["NE_nu_d"] - ) - return tot - - if type_ == NU_FISSION_DELAYED and group != -1: - return get_XS( - nuclide["ce_nu_d"][group], E, nuclide["E_nu_d"], nuclide["NE_nu_d"] - ) - - -@njit -def get_nu(type_, nuclide, E): - return get_nu_group(type_, nuclide, E, -1) - - -@njit -def sample_nuclide(material, P_arr, type_, mcdc): - P = P_arr[0] - xi = rng(P_arr) * get_MacroXS(type_, material, P_arr, mcdc) - tot = 0.0 - for i in range(material["N_nuclide"]): - ID_nuclide = material["nuclide_IDs"][i] - nuclide = mcdc["nuclides"][ID_nuclide] - - N = material["nuclide_densities"][i] - tot += N * get_microXS(type_, nuclide, P["E"]) - if tot > xi: - break - - return nuclide - - -@njit -def sample_Eout(P_new_arr, E_grid, NE, chi): - P_new = P_new_arr[0] - xi = rng(P_new_arr) - - # Determine bin index - idx = binary_search_with_length(xi, chi, NE) - - # Linear interpolation - # HAZARD? - E1 = E_grid[idx] - E2 = E_grid[idx + 1] - chi1 = chi[idx] - chi2 = chi[idx + 1] - return E1 + (xi - chi1) * (E2 - E1) / (chi2 - chi1) - - -# ============================================================================= -# Miscellany -# ============================================================================= - - -@njit -def lartg(f, g): - """ - Originally a Lapack routine to generate a plane rotation with - real cosine and real sine. - - Reference - ---------- - https://netlib.org/lapack/explore-html/df/dd1/group___o_t_h_e_rauxiliary_ga86f8f877eaea0386cdc2c3c175d9ea88.html#:~:text=DLARTG%20generates%20a%20plane%20rotation%20with%20real%20cosine,%3D%20G%20%2F%20R%20Hence%20C%20%3E%3D%200. - - Parameters - ---------- - f : The first component of vector to be rotated. - g : The second component of vector to be rotated. - - Returns - ------- - c : The cosine of the rotation. - s : The sine of the rotation. - r : The nonzero component of the rotated vector. - - """ - r = np.sign(f) * np.sqrt(f * f + g * g) - c = f / r - s = g / r - return c, s, r - - -@njit -def modified_gram_schmidt(V, u): - """ - Modified Gram Schmidt routine - - """ - u = np.reshape(u, (u.size, 1)) - V = np.ascontiguousarray(V) - w1 = u - np.dot(V, np.dot(V.T, u)) - v1 = w1 / np.linalg.norm(w1) - w2 = v1 - np.dot(V, np.dot(V.T, v1)) - v2 = w2 / np.linalg.norm(w2) - V = np.append(V, v2, axis=1) - return V - - -# ============================================================================= -# Variance Deconvolution -# ============================================================================= - - -@njit -def uq_resample(mean, delta, info): - # Currently only uniform distribution - shape = mean.shape - size = mean.size - xi = rng_array(info["rng_seed"], shape, size) - - return mean + (2 * xi - 1) * delta - - -@njit -def reset_material(mcdc, idm, material_uq): - # Assumes all nuclides have already been re-sampled - # Basic XS - material = mcdc["materials"][idm] - for tag in literal_unroll(("capture", "scatter", "fission", "total")): - if material_uq["flags"][tag]: - material[tag][:] = 0.0 - for n in range(material["N_nuclide"]): - nuc1 = mcdc["nuclides"][material["nuclide_IDs"][n]] - density = material["nuclide_densities"][n] - material[tag] += nuc1[tag] * density - - # Effective speed - if material_uq["flags"]["speed"]: - material["speed"][:] = 0.0 - for n in range(material["N_nuclide"]): - nuc2 = mcdc["nuclides"][material["nuclide_IDs"][n]] - density = material["nuclide_densities"][n] - material["speed"] += nuc2["speed"] * nuc2["total"] * density - if max(material["total"]) == 0.0: - material["speed"][:] = nuc2["speed"][:] - else: - material["speed"] /= material["total"] - - # Calculate effective spectra and multiplicities of scattering and prompt fission - G = material["G"] - if max(material["scatter"]) > 0.0: - shape = material["chi_s"].shape - nuSigmaS = np.zeros(shape) - for i in range(material["N_nuclide"]): - nuc3 = mcdc["nuclides"][material["nuclide_IDs"][i]] - density = material["nuclide_densities"][i] - SigmaS = np.diag(nuc3["scatter"]) * density - nu_s = np.diag(nuc3["nu_s"]) - chi_s = np.ascontiguousarray(nuc3["chi_s"].transpose()) - nuSigmaS += chi_s.dot(nu_s.dot(SigmaS)) - chi_nu_s = nuSigmaS.dot(np.diag(1.0 / material["scatter"])) - material["nu_s"] = np.sum(chi_nu_s, axis=0) - material["chi_s"] = np.ascontiguousarray( - chi_nu_s.dot(np.diag(1.0 / material["nu_s"])).transpose() - ) - if max(material["fission"]) > 0.0: - nuSigmaF = np.zeros((G, G), dtype=float) - for n in range(material["N_nuclide"]): - nuc4 = mcdc["nuclides"][material["nuclide_IDs"][n]] - density = material["nuclide_densities"][n] - SigmaF = np.diag(nuc4["fission"]) * density - nu_p = np.diag(nuc4["nu_p"]) - chi_p = np.ascontiguousarray(np.transpose(nuc4["chi_p"])) - nuSigmaF += chi_p.dot(nu_p.dot(SigmaF)) - chi_nu_p = nuSigmaF.dot(np.diag(1.0 / material["fission"])) - material["nu_p"] = np.sum(chi_nu_p, axis=0) - # Required because the below function otherwise returns an F-contiguous array - material["chi_p"] = np.ascontiguousarray( - np.transpose(chi_nu_p.dot(np.diag(1.0 / material["nu_p"]))) - ) - - # Calculate delayed and total fission multiplicities - if max(material["fission"]) > 0.0: - material["nu_f"][:] = material["nu_p"][:] - for j in range(material["J"]): - total = np.zeros(material["G"]) - for n in range(material["N_nuclide"]): - nuc5 = mcdc["nuclides"][material["nuclide_IDs"][n]] - density = material["nuclide_densities"][n] - total += nuc5["nu_d"][:, j] * nuc5["fission"] * density - material["nu_d"][:, j] = total / material["fission"] - material["nu_f"] += material["nu_d"][:, j] - - -@njit -def reset_nuclide(nuclide, nuclide_uq): - for name in literal_unroll( - ("speed", "decay", "capture", "fission", "nu_s", "nu_p") - ): - if nuclide_uq["flags"][name]: - nuclide[name] = uq_resample( - nuclide_uq["mean"][name], nuclide_uq["delta"][name], nuclide_uq["info"] - ) - - if nuclide_uq["flags"]["scatter"]: - scatter = uq_resample( - nuclide_uq["mean"]["scatter"], - nuclide_uq["delta"]["scatter"], - nuclide_uq["info"], - ) - nuclide["scatter"] = np.sum(scatter, 0) - nuclide["chi_s"][:, :] = np.swapaxes(scatter, 0, 1)[:, :] - for g in range(nuclide["G"]): - if nuclide["scatter"][g] > 0.0: - nuclide["chi_s"][g, :] /= nuclide["scatter"][g] - - if nuclide_uq["flags"]["total"]: - nuclide["total"][:] = ( - nuclide["capture"] + nuclide["scatter"] + nuclide["fission"] - ) - - if nuclide_uq["flags"]["nu_d"]: - nu_d = uq_resample( - nuclide_uq["mean"]["nu_d"], nuclide_uq["delta"]["nu_d"], nuclide_uq["info"] - ) - nuclide["nu_d"][:, :] = np.swapaxes(nu_d, 0, 1)[:, :] - - if nuclide_uq["flags"]["nu_f"]: # True if either nu_p or nu_d is true - nuclide["nu_f"] = nuclide["nu_p"] - for j in range(nuclide["J"]): - nuclide["nu_f"] += nuclide["nu_d"][:, j] - - # Prompt fission spectrum (If G == 1, all ones) - if nuclide_uq["flags"]["chi_p"]: - chi_p = uq_resample( - nuclide_uq["mean"]["chi_p"], - nuclide_uq["delta"]["chi_p"], - nuclide_uq["info"], - ) - nuclide["chi_p"][:, :] = np.swapaxes(chi_p, 0, 1)[:, :] - # Normalize - for g in range(nuclide["G"]): - if np.sum(nuclide["chi_p"][g, :]) > 0.0: - nuclide["chi_p"][g, :] /= np.sum(nuclide["chi_p"][g, :]) - - # Delayed fission spectrum (matrix of size JxG) - if nuclide_uq["flags"]["chi_d"]: - chi_d = uq_resample( - nuclide_uq["mean"]["chi_d"], - nuclide_uq["delta"]["chi_d"], - nuclide_uq["info"], - ) - # Transpose: [gout, dg] -> [dg, gout] - nuclide["chi_d"][:, :] = np.swapaxes(chi_d, 0, 1)[:, :] - # Normalize - for dg in range(nuclide["J"]): - if np.sum(nuclide["chi_d"][dg, :]) > 0.0: - nuclide["chi_d"][dg, :] /= np.sum(nuclide["chi_d"][dg, :]) - - -@njit -def uq_reset(mcdc, seed): - # Types of uq parameters: materials, nuclides - N = len(mcdc["technique"]["uq_"]["nuclides"]) - for i in range(N): - mcdc["technique"]["uq_"]["nuclides"][i]["info"]["rng_seed"] = split_seed( - i, seed - ) - idn = mcdc["technique"]["uq_"]["nuclides"][i]["info"]["ID"] - reset_nuclide(mcdc["nuclides"][idn], mcdc["technique"]["uq_"]["nuclides"][i]) - - M = len(mcdc["technique"]["uq_"]["materials"]) - for i in range(M): - mcdc["technique"]["uq_"]["materials"][i]["info"]["rng_seed"] = split_seed( - i, seed - ) - idm = mcdc["technique"]["uq_"]["materials"][i]["info"]["ID"] - reset_material(mcdc, idm, mcdc["technique"]["uq_"]["materials"][i]) - - -@njit -def uq_tally_closeout_history(data_tally, mcdc): - # Assumes N_batch > 1 - # Accumulate square of history score, but continue to accumulate bin - history_bin = data_tally[TALLY_SCORE] - data_tally[TALLY_UQ_BATCH] - data_tally[TALLY_UQ_BATCH_VAR] += history_bin**2 - data_tally[TALLY_UQ_BATCH] = data_tally[TALLY_SCORE] - - -@njit -def uq_tally_closeout_batch(data_tally, mcdc): - # Reset bin - N_bin = data_tally.shape[1] - for i in range(N_bin): - # Reset score bin - data_tally[TALLY_UQ_BATCH, i] = 0.0 - - # MPI Reduce - buff = np.zeros(N_bin) - with objmode(): - MPI.COMM_WORLD.Reduce( - np.array(data_tally[TALLY_UQ_BATCH_VAR]), buff, MPI.SUM, 0 - ) - data_tally[TALLY_UQ_BATCH_VAR][:] = buff - - -@njit -def uq_tally_closeout(data_tally, mcdc): - N_history = mcdc["setting"]["N_particle"] - - data_tally[TALLY_UQ_BATCH_VAR] = ( - data_tally[TALLY_UQ_BATCH_VAR] / N_history - data_tally[TALLY_SUM_SQ] - ) / (N_history - 1) - - # If we're here, N_batch > 1 - N_history = mcdc["setting"]["N_batch"] - - # Store results - mean = data_tally[TALLY_SUM] / N_history - data_tally[TALLY_UQ_BATCH_VAR] /= N_history - data_tally[TALLY_UQ_BATCH] = ( - data_tally[TALLY_SUM_SQ] - N_history * np.square(mean) - ) / (N_history - 1) diff --git a/mcdc/loop.py b/mcdc/loop.py deleted file mode 100644 index 3c59e9472..000000000 --- a/mcdc/loop.py +++ /dev/null @@ -1,1044 +0,0 @@ -from mpi4py import MPI -from numba import njit, objmode -from numba.misc.special import literally - -import shutil - -import mcdc.config as config -import mcdc.adapt as adapt -import mcdc.src.geometry as geometry -import mcdc.kernel as kernel -import mcdc.print_ as print_module -import mcdc.type_ as type_ - -from mcdc.constant import * -from mcdc.print_ import ( - print_header_batch, - print_iqmc_eigenvalue_progress, - print_iqmc_eigenvalue_exit_code, - print_msg, - print_progress, - print_progress_eigenvalue, - print_progress_iqmc, -) - -caching = config.caching - - -# ============================================================================= -# Functions for GPU Interop -# ============================================================================= - -# The symbols declared below will be overwritten to reference external code that -# manages GPU execution (if GPU execution is supported and selected) -alloc_state, free_state = [None] * 2 - -src_alloc_program, src_free_program = [None] * 2 -( - src_load_global, - src_load_constant, - src_store_global, - src_store_data, - src_store_pointer_data, -) = [None] * 5 -src_init_program, src_exec_program, src_complete, src_clear_flags = [None] * 4 - -pre_alloc_program, pre_free_program = [None] * 2 -pre_load_global, pre_load_data, pre_store_global, pre_store_data = [None] * 4 -pre_init_program, pre_exec_program, pre_complete, pre_clear_flags = [None] * 4 - - -# If GPU execution is supported and selected, the functions shown below will -# be redefined to overwrite the above symbols and perform initialization/ -# finalization of GPU state -@njit -def setup_gpu(mcdc, data_tally): - pass - - -@njit -def teardown_gpu(mcdc): - pass - - -# ========================================================================= -# Fixed-source loop -# ========================================================================= - - -@njit -def loop_fixed_source(data_tally, mcdc_arr): - - # Ensure `mcdc` exist for the lifetime of the program - # by intentionally leaking their memory - # adapt.leak(mcdc_arr) - mcdc = mcdc_arr[0] - - # Loop over batches - for idx_batch in range(mcdc["setting"]["N_batch"]): - if not mcdc["technique"]["domain_decomposition"]: - kernel.distribute_work(N=mcdc["setting"]["N_particle"], mcdc=mcdc) - else: - kernel.distribute_work_dd(N=mcdc["setting"]["N_particle"], mcdc=mcdc) - mcdc["idx_batch"] = idx_batch - seed_batch = kernel.split_seed(idx_batch, mcdc["setting"]["rng_seed"]) - - # Print multi-batch header - if mcdc["setting"]["N_batch"] > 1: - with objmode(): - print_header_batch(mcdc) - if mcdc["technique"]["uq"]: - seed_uq = kernel.split_seed(seed_batch, SEED_SPLIT_UQ) - kernel.uq_reset(mcdc, seed_uq) - - # Loop over time censuses - for idx_census in range(mcdc["setting"]["N_census"]): - mcdc["idx_census"] = idx_census - seed_census = kernel.split_seed(seed_batch, SEED_SPLIT_CENSUS) - - # Set census-based tally time grids - if mcdc["setting"]["census_based_tally"]: - N_bin = mcdc["setting"]["census_tally_frequency"] - if idx_census == 0: - t_start = 0.0 - else: - t_start = mcdc["setting"]["census_time"][idx_census - 1] - t_end = mcdc["setting"]["census_time"][idx_census] - dt = (t_end - t_start) / N_bin - for tally in mcdc["mesh_tallies"]: - tally["filter"]["t"][0] = t_start - for i in range(N_bin): - tally["filter"]["t"][i + 1] = tally["filter"]["t"][i] + dt - - # Check and accordingly promote future particles to censused particle - if kernel.get_bank_size(mcdc["bank_future"]) > 0: - kernel.check_future_bank(mcdc) - if ( - idx_census > 0 - and kernel.get_bank_size(mcdc["bank_source"]) == 0 - and kernel.get_bank_size(mcdc["bank_census"]) == 0 - and kernel.get_bank_size(mcdc["bank_future"]) == 0 - ): - # No more particle to work on - break - # Loop over source particles - seed_source = kernel.split_seed(seed_census, SEED_SPLIT_SOURCE) - - loop_source(seed_source, data_tally, mcdc) - - # Loop over source precursors - if kernel.get_bank_size(mcdc["bank_precursor"]) > 0: - seed_source_precursor = kernel.split_seed( - seed_census, SEED_SPLIT_SOURCE_PRECURSOR - ) - loop_source_precursor(seed_source_precursor, data_tally, mcdc) - - # Manage particle banks: population control and work rebalance - seed_bank = kernel.split_seed(seed_census, SEED_SPLIT_BANK) - kernel.manage_particle_banks(seed_bank, mcdc) - - # Time census-based tally closeout - if mcdc["setting"]["census_based_tally"]: - kernel.tally_reduce(data_tally, mcdc) - if mcdc["mpi_master"]: - kernel.census_based_tally_output(data_tally, mcdc) - if ( - mcdc["technique"]["weight_window"] - and idx_census < mcdc["setting"]["N_census"] - 2 - ): - kernel.update_weight_windows(data_tally, mcdc) - # TODO: UQ tally - - # Multi-batch closeout - if mcdc["setting"]["N_batch"] > 1: - # Reset banks - kernel.set_bank_size(mcdc["bank_active"], 0) - kernel.set_bank_size(mcdc["bank_census"], 0) - kernel.set_bank_size(mcdc["bank_source"], 0) - kernel.set_bank_size(mcdc["bank_future"], 0) - - # DD closeout - if mcdc["technique"]["domain_decomposition"]: - mcdc["dd_N_local_source"] = 0 - mcdc["domain_decomp"]["work_done"] = False - - if not mcdc["setting"]["census_based_tally"]: - # Tally history closeout - kernel.tally_reduce(data_tally, mcdc) - kernel.tally_accumulate(data_tally, mcdc) - - # Uq closeout - if mcdc["technique"]["uq"]: - kernel.uq_tally_closeout_batch(data_tally, mcdc) - - # Tally closeout - if not mcdc["setting"]["census_based_tally"]: - if mcdc["technique"]["uq"]: - kernel.uq_tally_closeout(data_tally, mcdc) - kernel.tally_closeout(data_tally, mcdc) - - -# ========================================================================= -# Eigenvalue loop -# ========================================================================= - - -@njit -def loop_eigenvalue(data_tally, mcdc_arr): - # Ensure `mcdc` exist for the lifetime of the program - # by intentionally leaking their memory - # adapt.leak(mcdc_arr) - mcdc = mcdc_arr[0] - - # Loop over power iteration cycles - for idx_cycle in range(mcdc["setting"]["N_cycle"]): - seed_cycle = kernel.split_seed(idx_cycle, mcdc["setting"]["rng_seed"]) - - # Loop over source particles - seed_source = kernel.split_seed(seed_cycle, SEED_SPLIT_SOURCE) - loop_source(seed_source, data_tally, mcdc) - - # Tally "history" closeout - kernel.eigenvalue_tally_closeout_history(mcdc) - if mcdc["cycle_active"]: - kernel.tally_reduce(data_tally, mcdc) - kernel.tally_accumulate(data_tally, mcdc) - - # DD closeout - if mcdc["technique"]["domain_decomposition"]: - mcdc["dd_N_local_source"] = 0 - mcdc["domain_decomp"]["work_done"] = False - - # Print progress - with objmode(): - print_progress_eigenvalue(mcdc) - - # Manage particle banks - seed_bank = kernel.split_seed(seed_cycle, SEED_SPLIT_BANK) - kernel.manage_particle_banks(seed_bank, mcdc) - - # Entering active cycle? - mcdc["idx_cycle"] += 1 - if mcdc["idx_cycle"] >= mcdc["setting"]["N_inactive"]: - mcdc["cycle_active"] = True - - # Tally closeout - kernel.tally_closeout(data_tally, mcdc) - kernel.eigenvalue_tally_closeout(mcdc) - - -# ============================================================================= -# Source loop -# ============================================================================= - - -@njit -def generate_source_particle(work_start, idx_work, seed, prog): - mcdc = adapt.mcdc_global(prog) - - seed_work = kernel.split_seed(work_start + idx_work, seed) - - # ===================================================================== - # Get a source particle and put into active bank - # ===================================================================== - - P_arr = adapt.local_array(1, type_.particle_record) - P = P_arr[0] - - # Get from fixed-source? - if kernel.get_bank_size(mcdc["bank_source"]) == 0: - # Sample source - kernel.source_particle(P_arr, seed_work, mcdc) - - # Get from source bank - else: - P_arr = mcdc["bank_source"]["particles"][idx_work : (idx_work + 1)] - P = P_arr[0] - - # Skip if beyond time boundary - if P["t"] > mcdc["setting"]["time_boundary"]: - return - - # If domain is decomposed, check if particle is in the domain - if mcdc["technique"]["domain_decomposition"]: - if not kernel.particle_in_domain(P_arr, mcdc): - return - - # Also check if it belongs to the current rank - mcdc["dd_N_local_source"] += 1 - if mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] > 1: - if ( - mcdc["dd_N_local_source"] - % mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] - != mcdc["dd_local_rank"] - ): - return - - # Check if it is beyond current or next census times - hit_census = False - hit_next_census = False - idx_census = mcdc["idx_census"] - if idx_census < mcdc["setting"]["N_census"] - 1: - if P["t"] > mcdc["setting"]["census_time"][idx_census + 1]: - hit_census = True - hit_next_census = True - elif P["t"] > mcdc["setting"]["census_time"][idx_census]: - hit_census = True - - # Put into the right bank - if not hit_census: - adapt.add_active(P_arr, prog) - elif not hit_next_census: - # Particle will participate after the current census - adapt.add_census(P_arr, prog) - else: - # Particle will participate in the future - adapt.add_future(P_arr, prog) - - """ - if mcdc["technique"]["domain_decomposition"]: - if mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] > 0: - P["w"] /= mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] - if kernel.particle_in_domain(P_arr, mcdc): - adapt.add_census(P_arr, prog) - else: - adapt.add_census(P_arr, prog) - else: - P_new_arr = adapt.local_array(1, type_.particle) - P_new = P_new_arr[0] - # Add the source particle into the active bank - if mcdc["technique"]["domain_decomposition"]: - if mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] > 0: - P["w"] /= mcdc["technique"]["dd_work_ratio"][mcdc["dd_idx"]] - if kernel.particle_in_domain(P_arr, mcdc): - kernel.recordlike_to_particle(P_new_arr, P_arr) - adapt.add_active(P_new_arr, prog) - else: - kernel.recordlike_to_particle(P_new_arr, P_arr) - adapt.add_active(P_new_arr, prog) - """ - - -@njit -def prep_particle(P_arr, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - # Apply weight window - if mcdc["technique"]["weight_window"]: - kernel.weight_window(P_arr, prog) - - -@njit -def exhaust_active_bank(data_tally, prog): - mcdc = adapt.mcdc_global(prog) - P_arr = adapt.local_array(1, type_.particle) - P = P_arr[0] - - # Loop until active bank is exhausted - while kernel.get_bank_size(mcdc["bank_active"]) > 0: - # Get particle from active bank - kernel.get_particle(P_arr, mcdc["bank_active"], mcdc) - - prep_particle(P_arr, prog) - - # Particle loop - loop_particle(P_arr, data_tally, mcdc) - - -@njit -def source_closeout(prog, idx_work, N_prog, data_tally): - mcdc = adapt.mcdc_global(prog) - - # Tally history closeout for one-batch fixed-source simulation - if not mcdc["setting"]["mode_eigenvalue"] and mcdc["setting"]["N_batch"] == 1: - if not mcdc["setting"]["census_based_tally"]: - kernel.tally_accumulate(data_tally, mcdc) - - # Tally history closeout for multi-batch uq simulation - if mcdc["technique"]["uq"]: - kernel.uq_tally_closeout_history(data_tally, mcdc) - - # Progress printout - percent = (idx_work + 1.0) / mcdc["mpi_work_size"] - if mcdc["setting"]["progress_bar"] and int(percent * 100.0) > N_prog: - N_prog += 1 - with objmode(): - print_progress(percent, mcdc) - - -@njit -def source_dd_resolution(data, prog): - mcdc = adapt.mcdc_global(prog) - - kernel.dd_particle_send(mcdc) - terminated = False - max_work = 1 - kernel.dd_recv(mcdc) - if mcdc["domain_decomp"]["work_done"]: - terminated = True - - P_arr = adapt.local_array(1, type_.particle) - P = P_arr[0] - - while not terminated: - if kernel.get_bank_size(mcdc["bank_active"]) > 0: - # Loop until active bank is exhausted - while kernel.get_bank_size(mcdc["bank_active"]) > 0: - - kernel.get_particle(P_arr, mcdc["bank_active"], mcdc) - if not kernel.particle_in_domain(P_arr, mcdc) and P["alive"] == True: - print(f"recieved particle not in domain") - - # Apply weight window - if mcdc["technique"]["weight_window"]: - kernel.weight_window(P_arr, mcdc) - - # Particle loop - loop_particle(P_arr, data, mcdc) - - # Tally history closeout for one-batch fixed-source simulation - if ( - not mcdc["setting"]["mode_eigenvalue"] - and mcdc["setting"]["N_batch"] == 1 - ): - kernel.tally_accumulate(data, mcdc) - - # Send all domain particle banks - kernel.dd_particle_send(mcdc) - - kernel.dd_recv(mcdc) - - # Progress printout - """ - percent = 1 - work_remaining / max_work - if mcdc["setting"]["progress_bar"] and int(percent * 100.0) > N_prog: - N_prog += 1 - with objmode(): - print_progress(percent, mcdc) - """ - if kernel.dd_check_halt(mcdc): - kernel.dd_check_out(mcdc) - terminated = True - - -@njit -def loop_source(seed, data_tally, mcdc): - # Progress bar indicator - N_prog = 0 - - if mcdc["technique"]["domain_decomposition"]: - kernel.dd_check_in(mcdc) - - # Loop over particle sources - work_start = mcdc["mpi_work_start"] - work_size = mcdc["mpi_work_size"] - work_end = work_start + work_size - - for idx_work in range(work_size): - generate_source_particle(work_start, idx_work, seed, mcdc) - - # Run the source particle and its secondaries - exhaust_active_bank(data_tally, mcdc) - - source_closeout(mcdc, idx_work, N_prog, data_tally) - - if mcdc["technique"]["domain_decomposition"]: - source_dd_resolution(data_tally, mcdc) - - -def gpu_sources_spec(): - def make_work(prog: nb.uintp) -> nb.boolean: - mcdc = adapt.mcdc_global(prog) - - idx_work = adapt.global_add(mcdc["mpi_work_iter"], 0, 1) - - if idx_work >= mcdc["mpi_work_size"]: - return False - - generate_source_particle( - mcdc["mpi_work_start"], nb.uint64(idx_work), mcdc["source_seed"], prog - ) - return True - - def initialize(prog: nb.uintp): - pass - - def finalize(prog: nb.uintp): - pass - - base_fns = (initialize, finalize, make_work) - - shape = eval(f"{adapt.tally_shape_literal}") - - # Just do exec/eval - def step(prog: nb.uintp, P_input: adapt.particle_gpu): - mcdc = adapt.mcdc_global(prog) - data_ptr = adapt.mcdc_data(prog) - data = adapt.harm.array_from_ptr(data_ptr, shape, nb.float64) - P_arr = adapt.local_array(1, type_.particle) - P_arr[0] = P_input - P = P_arr[0] - if P["fresh"]: - prep_particle(P_arr, prog) - P["fresh"] = False - step_particle(P_arr, data, prog) - if P["alive"]: - adapt.step_async(prog, P) - - async_fns = [step] - return adapt.harm.RuntimeSpec("mcdc_source", adapt.state_spec, base_fns, async_fns) - - -BLOCK_COUNT = config.args.gpu_block_count - -ASYNC_EXECUTION = config.args.gpu_strat == "async" - - -@njit(cache=caching) -def gpu_loop_source(seed, data, mcdc): - - # Progress bar indicator - N_prog = 0 - - if mcdc["technique"]["domain_decomposition"]: - kernel.dd_check_in(mcdc) - - # ===================================================================== - # GPU Interop - # ===================================================================== - - # For async execution - iter_count = 655360000 - # For event-based execution - batch_size = 64 - - full_work_size = mcdc["mpi_work_size"] - if ASYNC_EXECUTION: - phase_size = 1000000000 - else: - phase_size = 1000000 - phase_count = (full_work_size + phase_size - 1) // phase_size - - for phase in range(phase_count): - - mcdc["mpi_work_iter"][0] = phase_size * phase - mcdc["mpi_work_size"] = min(phase_size * (phase + 1), full_work_size) - mcdc["source_seed"] = seed - - # Store the global state to the GPU - if config.gpu_state_storage == "separate": - adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], mcdc) - adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], data) - - # Execute the program, and continue to do so until it is done - if ASYNC_EXECUTION: - src_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count - ) - while not src_complete(mcdc["gpu_meta"]["source_program_pointer"]): - kernel.dd_particle_send(mcdc) - src_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count - ) - else: - src_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size - ) - while not src_complete(mcdc["gpu_meta"]["source_program_pointer"]): - kernel.dd_particle_send(mcdc) - src_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size - ) - src_clear_flags(mcdc["gpu_meta"]["source_program_pointer"]) - # Recover the original program state - - if config.gpu_state_storage == "separate": - adapt.harm.memcpy_device_to_host(mcdc, mcdc["gpu_meta"]["state_pointer"]) - adapt.harm.memcpy_device_to_host(data, mcdc["gpu_meta"]["state_pointer"]) - - src_clear_flags(mcdc["gpu_meta"]["source_program_pointer"]) - - mcdc["mpi_work_size"] = full_work_size - - kernel.set_bank_size(mcdc["bank_active"], 0) - - # ===================================================================== - # Closeout (Moved out of the typical particle loop) - # ===================================================================== - - source_closeout(mcdc, 1, 1, data) - - if mcdc["technique"]["domain_decomposition"]: - source_dd_resolution(data, mcdc) - - -# ========================================================================= -# Particle loop -# ========================================================================= - - -@njit -def loop_particle(P_arr, data_tally, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - while P["alive"]: - step_particle(P_arr, data_tally, prog) - - -@njit -def step_particle(P_arr, data_tally, prog): - P = P_arr[0] - mcdc = adapt.mcdc_global(prog) - - # Determine and move to event - kernel.move_to_event(P_arr, data_tally, mcdc) - - # Execute events - if P["event"] == EVENT_LOST: - return - - # Collision - if P["event"] & EVENT_COLLISION: - # Generate IC? - if mcdc["technique"]["IC_generator"] and mcdc["cycle_active"]: - kernel.bank_IC(P_arr, prog) - - # Branchless collision? - if mcdc["technique"]["branchless_collision"]: - kernel.branchless_collision(P_arr, prog) - - # Analog collision - else: - # Get collision type - kernel.collision(P_arr, mcdc) - - # Perform collision - if P["event"] & EVENT_CAPTURE: - P["alive"] = False - - elif P["event"] & EVENT_SCATTERING: - kernel.scattering(P_arr, prog) - - elif P["event"] & EVENT_FISSION: - kernel.fission(P_arr, prog) - - # Surface and domain crossing - if P["event"] & EVENT_SURFACE_CROSSING: - kernel.surface_crossing(P_arr, data_tally, prog) - if P["event"] & EVENT_DOMAIN_CROSSING: - if mcdc["surfaces"][P["surface_ID"]]["BC"] == BC_NONE: - kernel.domain_crossing(P_arr, prog) - - elif P["event"] & EVENT_DOMAIN_CROSSING: - kernel.domain_crossing(P_arr, prog) - - # Census time crossing - if P["event"] & EVENT_TIME_CENSUS: - adapt.add_census(P_arr, prog) - P["alive"] = False - - # Time boundary crossing - if P["event"] & EVENT_TIME_BOUNDARY: - P["alive"] = False - - # Apply weight window - if P["alive"] and mcdc["technique"]["weight_window"]: - kernel.weight_window(P_arr, prog) - - # Apply weight roulette - if P["alive"] and mcdc["technique"]["weight_roulette"]: - # check if weight has fallen below threshold - if abs(P["w"]) <= mcdc["technique"]["wr_threshold"]: - kernel.weight_roulette(P_arr, mcdc) - - -# ============================================================================= -# Precursor source loop -# ============================================================================= - - -@njit -def generate_precursor_particle(DNP_arr, particle_idx, seed, prog): - mcdc = adapt.mcdc_global(prog) - DNP = DNP_arr[0] - - # Set groups - j = DNP["g"] - g = DNP["n_g"] - - # Create new particle - P_new_arr = adapt.local_array(1, type_.particle) - P_new = P_new_arr[0] - part_seed = kernel.split_seed(particle_idx, seed) - P_new["rng_seed"] = part_seed - P_new["alive"] = True - P_new["w"] = 1.0 - - # Set position - P_new["x"] = DNP["x"] - P_new["y"] = DNP["y"] - P_new["z"] = DNP["z"] - P_new["t"] = 0.0 - - # Sample direction - P_new["ux"], P_new["uy"], P_new["uz"] = kernel.sample_isotropic_direction(P_new_arr) - - # Get cell and material - P_new["cell_ID"] = -1 - P_new["material_ID"] = -1 - _ = geometry.locate_particle(P_new_arr, mcdc) - - # Skip if particle is lost - if P_new["material_ID"] == -1: - return - - material_ID = P_new["material_ID"] - material = mcdc["materials"][material_ID] - G = material["G"] - - # Sample nuclide and get spectrum and decay constant - N_nuclide = material["N_nuclide"] - if N_nuclide == 1: - nuclide = mcdc["nuclides"][material["nuclide_IDs"][0]] - spectrum = nuclide["chi_d"][j] - decay = nuclide["decay"][j] - else: - SigmaF = material["fission"][g] # MG only - nu_d = material["nu_d"][g] - xi = kernel.rng(P_new_arr) * nu_d[j] * SigmaF - tot = 0.0 - for i in range(N_nuclide): - nuclide = mcdc["nuclides"][material["nuclide_IDs"][i]] - density = material["nuclide_densities"][i] - tot += density * nuclide["nu_d"][g, j] * nuclide["fission"][g] - if xi < tot: - # Nuclide determined, now get the constant and spectruum - spectrum = nuclide["chi_d"][j] - decay = nuclide["decay"][j] - break - - # Sample emission time - P_new["t"] = -math.log(kernel.rng(P_new_arr)) / decay - idx_census = mcdc["idx_census"] - if idx_census > 0: - P_new["t"] += mcdc["setting"]["census_time"][idx_census - 1] - - # Accept if it is inside current census index - if P_new["t"] < mcdc["setting"]["census_time"][idx_census]: - # Skip if it's beyond time boundary - if P_new["t"] > mcdc["setting"]["time_boundary"]: - return - - # Sample energy - xi = kernel.rng(P_new_arr) - tot = 0.0 - for g_out in range(G): - tot += spectrum[g_out] - if tot > xi: - break - P_new["g"] = g_out - - # Push to active bank - adapt.add_active(P_new_arr, prog) - - -@njit -def source_precursor_closeout(prog, idx_work, N_prog, data): - mcdc = adapt.mcdc_global(prog) - - # Tally history closeout for fixed-source simulation - if not mcdc["setting"]["mode_eigenvalue"]: - kernel.tally_accumulate(data, mcdc) - - # Progress printout - percent = (idx_work + 1.0) / mcdc["mpi_work_size_precursor"] - if mcdc["setting"]["progress_bar"] and int(percent * 100.0) > N_prog: - N_prog += 1 - with objmode(): - print_progress(percent, mcdc) - - -@njit -def loop_source_precursor(seed, data, mcdc): - # Progress bar indicator - N_prog = 0 - - # TODO: Domain decomposition (see loop_source) - - # Loop over precursor sources - work_start = mcdc["mpi_work_start_precursor"] - work_size = mcdc["mpi_work_size_precursor"] - work_end = work_start + work_size - - for idx_work in range(work_size): - # Get precursor - DNP_arr = mcdc["bank_precursor"]["precursors"][idx_work : (idx_work + 1)] - DNP = DNP_arr[0] - seed_precursor = kernel.split_seed(work_start + idx_work, seed) - # Note the seed is only used once - - # Determine number of particles to be generated - nu = DNP["w"] - xi = kernel.rng_from_seed(seed_precursor) - N = int(math.floor(nu + xi)) - - # Loop over source particles from the source precursor - for particle_idx in range(N): - generate_precursor_particle(DNP_arr, particle_idx, seed_precursor, mcdc) - exhaust_active_bank(data, mcdc) - - source_precursor_closeout(mcdc, idx_work, N_prog, data) - - -# ========================================================================= -# GPU Runtime Specifications and Function Re-definitions -# ========================================================================= - - -def gpu_precursor_spec(): - def make_work(prog: nb.uintp) -> nb.boolean: - mcdc = adapt.mcdc_global(prog) - - idx_work = adapt.global_add(mcdc["mpi_work_iter"], 0, 1) - - if idx_work >= mcdc["mpi_work_size_precursor"]: - return False - - seed = mcdc["source_seed"] - - # Get precursor - DNP_arr = mcdc["bank_precursor"]["precursors"][idx_work : (idx_work + 1)] - DNP = DNP_arr[0] - - # Determine number of particles to be generated - w = DNP["w"] - N = math.floor(w) - # "Roulette" the last particle - seed_work = kernel.split_seed(idx_work, seed) - if kernel.rng_from_seed(seed_work) < w - N: - N += 1 - DNP["w"] = N - - # ===================================================================== - # Loop over source particles from the source precursor - # ===================================================================== - - for particle_idx in range(N): - generate_precursor_particle(DNP_arr, particle_idx, seed_work, prog) - - return True - - def initialize(prog: nb.uintp): - pass - - def finalize(prog: nb.uintp): - pass - - base_fns = (initialize, finalize, make_work) - - shape = eval(f"{adapt.tally_shape_literal}") - - def step(prog: nb.uintp, P_input: adapt.particle_gpu): - mcdc = adapt.mcdc_global(prog) - data_ptr = adapt.mcdc_data(prog) - data = adapt.harm.array_from_ptr(data_ptr, shape, nb.float64) - P_arr = adapt.local_array(1, type_.particle) - P_arr[0] = P_input - P = P_arr[0] - if P["fresh"]: - prep_particle(P_arr, prog) - P["fresh"] = False - step_particle(P_arr, data, prog) - if P["alive"]: - adapt.step_async(prog, P) - - async_fns = [step] - return adapt.harm.RuntimeSpec( - "mcdc_precursor", adapt.state_spec, base_fns, async_fns - ) - - -@njit(cache=caching) -def gpu_loop_source_precursor(seed, data, mcdc): - - # Progress bar indicator - N_prog = 0 - - # ========================================================================= - # Sync. RNG skip ahead for reproducibility - # ========================================================================= - - # Exscan upper estimate of number of particles generated locally - idx_start, N_local, N_global = kernel.bank_scanning_DNP( - mcdc["bank_precursor"], mcdc - ) - - # ===================================================================== - # GPU Interop - # ===================================================================== - - # Number of blocks to launch and number of iterations to run - - # For async execution - iter_count = 655360000 - # For event-based execution - batch_size = 1 - - mcdc["mpi_work_iter"][0] = 0 - mcdc["source_seed"] = seed - - # Store the global state to the GPU - if config.gpu_state_storage == "separate": - adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], mcdc) - adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], data) - - # Execute the program, and continue to do so until it is done - - # Execute the program, and continue to do so until it is done - if ASYNC_EXECUTION: - pre_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count - ) - while not pre_complete(mcdc["gpu_meta"]["source_program_pointer"]): - kernel.dd_particle_send(mcdc) - pre_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count - ) - else: - pre_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size - ) - while not pre_complete(mcdc["gpu_meta"]["source_program_pointer"]): - kernel.dd_particle_send(mcdc) - pre_exec_program( - mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size - ) - - # Recover the original program state - if config.gpu_state_storage == "separate": - adapt.harm.memcpy_device_to_host(mcdc, mcdc["gpu_meta"]["state_pointer"]) - adapt.harm.memcpy_device_to_host(data, mcdc["gpu_meta"]["state_pointer"]) - - pre_clear_flags(mcdc["gpu_meta"]["source_program_pointer"]) - - kernel.set_bank_size(mcdc["bank_active"], 0) - - # ===================================================================== - # Closeout (moved out of loop) - # ===================================================================== - - source_precursor_closeout(mcdc, 1, 1, data) - - -def build_gpu_progs(input_deck, args): - - STRAT = args.gpu_strat - - src_spec = gpu_sources_spec() - pre_spec = gpu_precursor_spec() - - adapt.harm.RuntimeSpec.bind_specs() - - rank = MPI.COMM_WORLD.Get_rank() - device_id = rank % args.gpu_share_stride - - if MPI.COMM_WORLD.Get_size() > 1: - MPI.COMM_WORLD.Barrier() - - adapt.harm.RuntimeSpec.load_specs() - - if STRAT == "async": - args.gpu_arena_size = args.gpu_arena_size // 32 - src_fns = src_spec.async_functions() - pre_fns = pre_spec.async_functions() - else: - src_fns = src_spec.event_functions() - pre_fns = pre_spec.event_functions() - - ARENA_SIZE = args.gpu_arena_size - BLOCK_COUNT = args.gpu_block_count - - global alloc_state, free_state - alloc_state = src_fns["alloc_state"] - free_state = src_fns["free_state"] - - global src_alloc_program, src_free_program - global src_load_global, src_store_global, src_load_data, src_store_data, src_store_pointer_data - global src_init_program, src_exec_program, src_complete, src_clear_flags - src_alloc_program = src_fns["alloc_program"] - src_free_program = src_fns["free_program"] - src_load_global = src_fns["load_state_device_global"] - src_store_global = src_fns["store_state_device_global"] - src_store_pointer_global = src_fns["store_pointer_state_device_global"] - src_load_data = src_fns["load_state_device_data"] - src_store_data = src_fns["store_state_device_data"] - src_store_pointer_data = src_fns["store_pointer_state_device_data"] - src_init_program = src_fns["init_program"] - src_exec_program = src_fns["exec_program"] - src_complete = src_fns["complete"] - src_clear_flags = src_fns["clear_flags"] - src_set_device = src_fns["set_device"] - - global pre_alloc_program, pre_free_program - global pre_load_global, pre_store_global, pre_load_data, pre_store_data - global pre_init_program, pre_exec_program, pre_complete, pre_clear_flags - pre_alloc_state = pre_fns["alloc_state"] - pre_free_state = pre_fns["free_state"] - pre_alloc_program = pre_fns["alloc_program"] - pre_free_program = pre_fns["free_program"] - pre_load_global = pre_fns["load_state_device_global"] - pre_store_global = pre_fns["store_state_device_global"] - pre_load_data = pre_fns["load_state_device_data"] - pre_store_data = pre_fns["store_state_device_data"] - pre_init_program = pre_fns["init_program"] - pre_exec_program = pre_fns["exec_program"] - pre_complete = pre_fns["complete"] - pre_clear_flags = pre_fns["clear_flags"] - - @njit - def real_setup_gpu(mcdc_array, data_tally): - mcdc = mcdc_array[0] - src_set_device(device_id) - arena_size = ARENA_SIZE - mcdc["gpu_meta"]["state_pointer"] = adapt.cast_voidptr_to_uintp(alloc_state()) - # src_store_global(mcdc["gpu_meta"]["state_pointer"], mcdc_array[0]) - if config.gpu_state_storage == "separate": - src_store_pointer_global( - mcdc["gpu_meta"]["state_pointer"], mcdc["gpu_meta"]["global_pointer"] - ) - src_store_pointer_data( - mcdc["gpu_meta"]["state_pointer"], mcdc["gpu_meta"]["tally_pointer"] - ) - else: - src_store_pointer_global(mcdc["gpu_meta"]["state_pointer"], mcdc_array) - src_store_pointer_data(mcdc["gpu_meta"]["state_pointer"], data_tally) - - mcdc["gpu_meta"]["source_program_pointer"] = adapt.cast_voidptr_to_uintp( - src_alloc_program(mcdc["gpu_meta"]["state_pointer"], ARENA_SIZE) - ) - src_init_program(mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT) - mcdc["gpu_meta"]["precursor_program_pointer"] = adapt.cast_voidptr_to_uintp( - pre_alloc_program(mcdc["gpu_meta"]["state_pointer"], ARENA_SIZE) - ) - pre_init_program(mcdc["gpu_meta"]["precursor_program_pointer"], BLOCK_COUNT) - return - - @njit - def real_teardown_gpu(mcdc): - src_free_program( - adapt.cast_uintp_to_voidptr(mcdc["gpu_meta"]["source_program_pointer"]) - ) - pre_free_program( - adapt.cast_uintp_to_voidptr(mcdc["gpu_meta"]["precursor_program_pointer"]) - ) - free_state(adapt.cast_uintp_to_voidptr(mcdc["gpu_meta"]["state_pointer"])) - - global setup_gpu, teardown_gpu - setup_gpu = real_setup_gpu - teardown_gpu = real_teardown_gpu - - global loop_source, loop_source_precursor - loop_source = gpu_loop_source - loop_source_precursor = gpu_loop_source_precursor diff --git a/mcdc/main.py b/mcdc/main.py index b06801ebb..2b8aa0071 100644 --- a/mcdc/main.py +++ b/mcdc/main.py @@ -1,1155 +1,238 @@ -import argparse, os, sys -import importlib.metadata -import mcdc.config as config -import matplotlib.pyplot as plt -import numba as nb -from matplotlib import colors as mpl_colors -import scipy.fft as spfft -from scipy.stats.qmc import Halton -import cvxpy as cp - -from mcdc.card import UniverseCard -from mcdc.print_ import ( - print_banner, - print_msg, - print_runtime, - print_header_eigenvalue, - print_warning, - print_error, -) - -import h5py -import numpy as np - -from mpi4py import MPI - -import mcdc.kernel as kernel -import mcdc.type_ as type_ - -import mcdc.adapt as adapt -from mcdc.constant import * -from mcdc.loop import ( - loop_fixed_source, - loop_eigenvalue, - build_gpu_progs, -) -from mcdc.iqmc.iqmc_loop import iqmc_simulation, iqmc_validate_inputs -import mcdc.src.geometry as geometry - -import mcdc.loop as loop -from mcdc.print_ import print_banner, print_msg, print_runtime, print_header_eigenvalue - -# Get input_deck -import mcdc.global_ as mcdc_ - -input_deck = mcdc_.input_deck - - -def run(): - # Override input deck with command-line argument, if given - if config.args.N_particle is not None: - input_deck.setting["N_particle"] = config.args.N_particle - if config.args.output is not None: - input_deck.setting["output_name"] = config.args.output - if config.args.progress_bar is not None: - input_deck.setting["progress_bar"] = config.args.progress_bar - - # Start timer - total_start = MPI.Wtime() - - # Preparation - # Set up and get the global variable container `mcdc` based on - # input deck - preparation_start = MPI.Wtime() - if input_deck.technique["iQMC"]: - iqmc_validate_inputs(input_deck) - - data_tally, mcdc_arr = prepare() - mcdc = mcdc_arr[0] - mcdc["runtime_preparation"] = MPI.Wtime() - preparation_start - - # Print banner, hardware configuration, and header - print_banner(mcdc) +# ====================================================================================== +# Run +# ====================================================================================== - print_msg(" Now running TNT...") - if mcdc["setting"]["mode_eigenvalue"]: - print_header_eigenvalue(mcdc) - # Run simulation - simulation_start = MPI.Wtime() - if mcdc["technique"]["iQMC"]: - iqmc_simulation(mcdc_arr) - elif mcdc["setting"]["mode_eigenvalue"]: - loop_eigenvalue(data_tally, mcdc_arr) - else: - print_msg("Starting fixed source") - loop_fixed_source(data_tally, mcdc_arr) - mcdc["runtime_simulation"] = MPI.Wtime() - simulation_start +from mcdc import mcdc_get +from mcdc.print_ import print_error, print_structure - # Compressed sensing reconstruction - N_cs_bins = mcdc["cs_tallies"]["filter"]["N_cs_bins"][0] - if N_cs_bins != 0: - cs_reconstruct(data_tally, mcdc) - # Output: generate hdf5 output files - output_start = MPI.Wtime() - generate_hdf5(data_tally, mcdc) - mcdc["runtime_output"] = MPI.Wtime() - output_start +def run(): + import mcdc.print_ as print_module + from mpi4py import MPI - # Stop timer - MPI.COMM_WORLD.Barrier() - mcdc["runtime_total"] = MPI.Wtime() - total_start - - # for i in range(mcdc["bank_log"]["size"][0]): - # print(mcdc["bank_log"]["particles"][i]) + # Timer: total + time_total_start = MPI.Wtime() - # Closout - closeout(mcdc) - - -def calculate_cs_A(data, mcdc): - x_grid = mcdc["mesh_tallies"]["filter"]["x"][0] - y_grid = mcdc["mesh_tallies"]["filter"]["y"][0] - Nx = len(x_grid) - 1 - Ny = len(y_grid) - 1 - - N_cs_bins = mcdc["cs_tallies"]["filter"]["N_cs_bins"][0] - cs_bin_size = mcdc["cs_tallies"]["filter"]["cs_bin_size"][0] - - S = [[] for _ in range(N_cs_bins)] - - [x_centers, y_centers] = mcdc["cs_tallies"]["filter"]["cs_centers"][0] - x_centers[-1] = (x_grid[-1] + x_grid[0]) / 2 - y_centers[-1] = (y_grid[-1] + y_grid[0]) / 2 + from mcdc.object_.simulation import simulation - # Calculate the overlap grid for each bin, and flatten into a row of S - for ibin in range(N_cs_bins): - if ibin == N_cs_bins - 1: - # could just change to -INF, INF - cs_bin_size = np.array([x_grid[-1] + x_grid[0], y_grid[-1] + y_grid[0]]) + settings = simulation.settings + master = MPI.COMM_WORLD.Get_rank() == 0 - bin_x_min = x_centers[ibin] - cs_bin_size[0] / 2 - bin_x_max = x_centers[ibin] + cs_bin_size[0] / 2 - bin_y_min = y_centers[ibin] - cs_bin_size[1] / 2 - bin_y_max = y_centers[ibin] + cs_bin_size[1] / 2 + # Override settings with command-line arguments + import mcdc.config as config - overlap = np.zeros((len(y_grid) - 1, len(x_grid) - 1)) + if config.args.N_particle is not None: + settings.N_particle = config.args.N_particle + if config.args.N_batch is not None: + settings.N_batch = config.args.N_batch + if config.args.output is not None: + settings.output_name = config.args.output + if config.args.progress_bar is not None: + settings.use_progress_bar = config.args.progress_bar - for i in range(len(y_grid) - 1): - for j in range(len(x_grid) - 1): - cell_x_min = x_grid[j] - cell_x_max = x_grid[j + 1] - cell_y_min = y_grid[i] - cell_y_max = y_grid[i + 1] + # ================================================================================== + # Preparation + # ================================================================================== - # Calculate overlap in x and y directions - overlap_x = np.maximum( - 0, - np.minimum(bin_x_max, cell_x_max) - - np.maximum(bin_x_min, cell_x_min), - ) - overlap_y = np.maximum( - 0, - np.minimum(bin_y_max, cell_y_max) - - np.maximum(bin_y_min, cell_y_min), - ) + # Timer: preparation + time_prep_start = MPI.Wtime() - # Calculate fractional overlap - cell_area = (cell_x_max - cell_x_min) * (cell_y_max - cell_y_min) - overlap[i, j] = (overlap_x * overlap_y) / cell_area + mcdc_arr, data = preparation() + mcdc = mcdc_arr[0] - S[ibin] = overlap.flatten() - S = np.array(S) - mcdc["cs_tallies"]["filter"]["cs_S"] = S + # Print headers + if master: + print_module.print_banner() + print_module.print_configuration() + print(" Now running TNT...") + if settings.eigenvalue_mode: + print_module.print_eigenvalue_header(mcdc) - assert np.allclose(S[-1], np.ones(Nx * Ny)), "Last row of S must be all ones" - assert S.shape[1] == Nx * Ny, "Size of S must match Nx * Ny." - assert ( - S.shape[1] == mcdc["cs_tallies"]["N_bin"][0] - ), "Size of S must match number of cells in desired mesh tally" + # Timer: preparation + time_prep_end = MPI.Wtime() - # TODO: can this be done in a different way? idk - # Construct the DCT matrix T - idct_basis_x = spfft.idct(np.identity(Nx), axis=0) - idct_basis_y = spfft.idct(np.identity(Ny), axis=0) + # ================================================================================== + # Running the simulation + # ================================================================================== - T_inv = np.kron(idct_basis_y, idct_basis_x) - A = S @ T_inv - return A, T_inv + # Timer: simulation + time_simulation_start = MPI.Wtime() + # Run simulation + import mcdc.transport.simulation as simulation_module -def calculate_cs_sparse_solution(data, mcdc, A, b): - N_fine_cells = mcdc["cs_tallies"]["N_bin"][0] + if settings.eigenvalue_mode: + simulation_module.eigenvalue_simulation(mcdc_arr, data) + else: + simulation_module.fixed_source_simulation(mcdc_arr, data) - # setting up the problem with CVXPY - vx = cp.Variable(N_fine_cells) + # Timer: simulation + time_simulation_end = MPI.Wtime() - # Basis pursuit denoising - l = 0.5 - objective = cp.Minimize(0.5 * cp.norm(A @ vx - b, 2) + l * cp.norm(vx, 1)) - prob = cp.Problem(objective) - result = prob.solve(verbose=False) + # ================================================================================== + # Working on the output + # ================================================================================== - # # Basis pursuit - # objective = cp.Minimize(cp.norm(vx, 1)) - # constraints = [A @ vx == b] - # prob = cp.Problem(objective, constraints) - # result = prob.solve(verbose=True) - # print(f'vx.value = {vx.value}') + import mcdc.output as output_module - # formatting the sparse solution - sparse_solution = np.array(vx.value).squeeze() + # Timer: output + time_output_start = MPI.Wtime() - return sparse_solution + # Generate hdf5 output file + output_module.generate_output(mcdc, data) + # Timer: output + time_output_end = MPI.Wtime() -def cs_reconstruct(data, mcdc): - tally_bin = data - tally = mcdc["cs_tallies"][0] - stride = tally["stride"] - bin_idx = stride["tally"] - N_cs_bins = tally["filter"]["N_cs_bins"] - Nx = len(mcdc["mesh_tallies"]["filter"]["x"][0]) - 1 - Ny = len(mcdc["mesh_tallies"]["filter"]["y"][0]) - 1 + # Final barrier + MPI.COMM_WORLD.Barrier() - b = tally_bin[TALLY_SUM, bin_idx : bin_idx + N_cs_bins] + # Timer: total + time_total_end = MPI.Wtime() - A, T_inv = calculate_cs_A(data, mcdc) - x = calculate_cs_sparse_solution(data, mcdc, A, b) + # Manage timers + mcdc["runtime_total"] = time_total_end - time_total_start + mcdc["runtime_preparation"] = time_prep_end - time_prep_start + mcdc["runtime_simulation"] = time_simulation_end - time_simulation_start + mcdc["runtime_output"] = time_output_end - time_output_start + output_module.create_runtime_datasets(mcdc) + if master: + print_module.print_runtime(mcdc) - recon = T_inv @ x - recon_reshaped = recon.reshape(Ny, Nx) + # ================================================================================== + # Finalizing + # ================================================================================== - tally["filter"]["cs_reconstruction"] = recon_reshaped + # GPU teardowns + from mcdc.transport.simulation import teardown_gpu - -# ============================================================================= -# utilities for handling discrepancies between input and program types -# ============================================================================= + teardown_gpu(mcdc) -def copy_field(dst, src, name): - if "padding" in name: - return +# ====================================================================================== +# Preparation +# ====================================================================================== - if isinstance(src, dict): - data = src[name] - else: - data = getattr(src, name) - - if isinstance(dst[name], np.ndarray): - if isinstance(data, np.ndarray) and dst[name].shape != data.shape: - for dim in data.shape: - if dim == 0: - return - print( - f"Warning: Dimension mismatch between input deck and global state for field '{name}'." - ) - print( - f"State dimension {dst[name].shape} does not match input dimension {src[name].shape}" - ) - elif isinstance(data, list) and dst[name].shape[0] != len(data): - if len(src[name]) == 0: - return - print( - f"Warning: Dimension mismatch between input deck and global state for field '{name}'." - ) - print( - f"State dimension {dst[name].shape} does not match input dimension {len(src[name])}" - ) - dst[name] = data +def preparation(): + import math + import numpy as np + from mpi4py import MPI -# ============================================================================= -# prepare domain decomposition -# ============================================================================= -def get_d_idx(i, j, k, ni, nj): - N = i + j * ni + k * ni * nj - return N + from mcdc.object_.simulation import simulation + from mcdc.object_.material import MaterialMG + # ================================================================================== + # Simulation settings + # ================================================================================== -def get_indexes(N, nx, ny): - k = int(N / (nx * ny)) - j = int((N - nx * ny * k) / nx) - i = int(N - nx * ny * k - nx * j) - return i, j, k + # Get settings + settings = simulation.settings + # Set physics mode + settings.multigroup_mode = isinstance(simulation.materials[0], MaterialMG) -def get_neighbors(N, nx, ny, nz): - i, j, k = get_indexes(N, nx, ny) - if i > 0: - xn = get_d_idx(i - 1, j, k, nx, ny) - else: - xn = None - if i < (nx - 1): - xp = get_d_idx(i + 1, j, k, nx, ny) - else: - xp = None - if j > 0: - yn = get_d_idx(i, j - 1, k, nx, ny) - else: - yn = None - if j < (ny - 1): - yp = get_d_idx(i, j + 1, k, nx, ny) - else: - yp = None - if k > 0: - zn = get_d_idx(i, j, k - 1, nx, ny) - else: - zn = None - if k < (nz - 1): - zp = get_d_idx(i, j, k + 1, nx, ny) - else: - zp = None - return xn, xp, yn, yp, zn, zp - - -def prepare_domain_decomposition(): - # Key parameters - work_ratio = input_deck.technique["dd_work_ratio"] - N_proc = MPI.COMM_WORLD.Get_size() - # Decomposition mesh sizes - d_Nx = input_deck.technique["dd_mesh"]["x"].size - 1 - d_Ny = input_deck.technique["dd_mesh"]["y"].size - 1 - d_Nz = input_deck.technique["dd_mesh"]["z"].size - 1 - - # Default parameters - if input_deck.technique["dd_exchange_rate"] == None: - input_deck.technique["dd_exchange_rate"] = 100 - if work_ratio is None: - work_ratio = np.ones(d_Nx * d_Ny * d_Nz, dtype=int) - input_deck.technique["dd_work_ratio"] = work_ratio - if input_deck.technique["dd_exchange_rate_padding"] == None: - if config.args.target == "gpu": - padding = config.args.gpu_block_count * 64 * 16 - else: - padding = 0 - input_deck.technique["dd_exchange_rate_padding"] = padding - - # Check if the combination of work_ratio and MPI rank size is acceptable - if ( - input_deck.technique["domain_decomposition"] - and N_proc % np.sum(work_ratio) != 0 - ): - print_msg( - "Number of MPI processes (%i) should be a multiple of the sum of the decomposed domain work ratio (%i)" - % (N_proc, np.sum(work_ratio)) - ) - exit() - N_ratio = int(N_proc / np.sum(work_ratio)) - work_ratio *= N_ratio - - # Assign domain index and processors' numbers in each domain - if input_deck.technique["domain_decomposition"]: - i = 0 - rank_info = [] - for n in range(d_Nx * d_Ny * d_Nz): - ranks = [] - for r in range(work_ratio[n]): - ranks.append(i) - if MPI.COMM_WORLD.Get_rank() == i: - d_idx = n - local_rank = r - i += 1 - rank_info.append(ranks) - input_deck.technique["dd_idx"] = d_idx - input_deck.technique["dd_local_rank"] = local_rank - xn, xp, yn, yp, zn, zp = get_neighbors(d_idx, d_Nx, d_Ny, d_Nz) - else: - input_deck.technique["dd_idx"] = 0 - input_deck.technique["dd_local_rank"] = 0 - input_deck.technique["dd_xp_neigh"] = [] - input_deck.technique["dd_xn_neigh"] = [] - input_deck.technique["dd_yp_neigh"] = [] - input_deck.technique["dd_yn_neigh"] = [] - input_deck.technique["dd_zp_neigh"] = [] - input_deck.technique["dd_zn_neigh"] = [] - return - - # Assign neighbor processor numbers in all 3x2 sides - if xp is not None: - input_deck.technique["dd_xp_neigh"] = rank_info[xp] - else: - input_deck.technique["dd_xp_neigh"] = [] - if xn is not None: - input_deck.technique["dd_xn_neigh"] = rank_info[xn] - else: - input_deck.technique["dd_xn_neigh"] = [] - - if yp is not None: - input_deck.technique["dd_yp_neigh"] = rank_info[yp] - else: - input_deck.technique["dd_yp_neigh"] = [] - if yn is not None: - input_deck.technique["dd_yn_neigh"] = rank_info[yn] - else: - input_deck.technique["dd_yn_neigh"] = [] - - if zp is not None: - input_deck.technique["dd_zp_neigh"] = rank_info[zp] - else: - input_deck.technique["dd_zp_neigh"] = [] - if zn is not None: - input_deck.technique["dd_zn_neigh"] = rank_info[zn] - else: - input_deck.technique["dd_zn_neigh"] = [] - - -def dd_mesh_bounds(idx): - """ - Defining mesh tally boundaries for domain decomposition. - Used in prepare() when domain decomposition is active. - """ - # find DD mesh index of subdomain - d_idx = input_deck.technique["dd_idx"] # subdomain index - d_Nx = input_deck.technique["dd_mesh"]["x"].size - 1 - d_Ny = input_deck.technique["dd_mesh"]["y"].size - 1 - d_Nz = input_deck.technique["dd_mesh"]["z"].size - 1 - zmesh_idx = d_idx // (d_Nx * d_Ny) - ymesh_idx = (d_idx % (d_Nx * d_Ny)) // d_Nx - xmesh_idx = d_idx % d_Nx - - # find spatial boundaries of subdomain - xn = input_deck.technique["dd_mesh"]["x"][xmesh_idx] - xp = input_deck.technique["dd_mesh"]["x"][xmesh_idx + 1] - yn = input_deck.technique["dd_mesh"]["y"][ymesh_idx] - yp = input_deck.technique["dd_mesh"]["y"][ymesh_idx + 1] - zn = input_deck.technique["dd_mesh"]["z"][zmesh_idx] - zp = input_deck.technique["dd_mesh"]["z"][zmesh_idx + 1] - - # find boundary indices in tally mesh - mesh_xn = int(np.where(input_deck.mesh_tallies[idx].x == xn)[0]) - mesh_xp = int(np.where(input_deck.mesh_tallies[idx].x == xp)[0]) + 1 - mesh_yn = int(np.where(input_deck.mesh_tallies[idx].y == yn)[0]) - mesh_yp = int(np.where(input_deck.mesh_tallies[idx].y == yp)[0]) + 1 - mesh_zn = int(np.where(input_deck.mesh_tallies[idx].z == zn)[0]) - mesh_zp = int(np.where(input_deck.mesh_tallies[idx].z == zp)[0]) + 1 - - return mesh_xn, mesh_xp, mesh_yn, mesh_yp, mesh_zn, mesh_zp - - -def generate_cs_centers(mcdc, N_dim=3, seed=123456789): - N_cs_bins = int(mcdc["cs_tallies"]["filter"]["N_cs_bins"]) - x_lims = ( - mcdc["cs_tallies"]["filter"]["x"][0][-1], - mcdc["cs_tallies"]["filter"]["x"][0][0], - ) - y_lims = ( - mcdc["cs_tallies"]["filter"]["y"][0][-1], - mcdc["cs_tallies"]["filter"]["y"][0][0], + # Set appropriate time boundary + settings.time_boundary = min( + [settings.time_boundary] + [tally.time[-1] for tally in simulation.tallies] ) - # Generate Halton sequence according to the seed - halton_seq = Halton(d=N_dim, seed=seed) - points = halton_seq.random(n=N_cs_bins) - - # Extract x and y coordinates as tuples separately, scaled to the problem dimensions - x_coords = tuple(points[:, 0] * (x_lims[1] - x_lims[0]) + x_lims[0]) - y_coords = tuple(points[:, 1] * (y_lims[1] - y_lims[0]) + y_lims[0]) - - return (x_coords, y_coords) - - -def prepare(): - """ - Preparing the MC transport simulation: - (1) Adapt kernels - (2) Make types - (3) Create and set up global variable container `mcdc` - """ - - prepare_domain_decomposition() + # Reset time grid size of all tallies if census-based tally is desired + if settings.use_census_based_tally: + N_bin = settings.census_tally_frequency + for tally in simulation.tallies: + tally._use_census_based_tally(N_bin) + + # ================================================================================== + # Simulation parameters + # ================================================================================== + + # Normalize source probability + norm = 0.0 + for source in simulation.sources: + norm += source.probability + for source in simulation.sources: + source.probability /= norm - # ========================================================================= # Create root universe if not defined - # ========================================================================= - - if input_deck.universes[0] == None: - N_cell = len(input_deck.cells) - root_universe = UniverseCard() - root_universe.ID = 0 - root_universe.cell_IDs = np.zeros(N_cell, int) - for i, cell in enumerate(input_deck.cells): - root_universe.cell_IDs[i] = cell.ID - input_deck.universes[0] = root_universe - - # ========================================================================= - # Prepare cell region RPN (Reverse Polish Notation) - # - Replace halfspace region ID with its surface and insert - # complement operator if the sense is negative. - # ========================================================================= - - for cell in input_deck.cells: - i = 0 - while i < len(cell._region_RPN): - token = cell._region_RPN[i] - if token >= 0: - surface_ID = input_deck.regions[token].A - sense = input_deck.regions[token].B - cell._region_RPN[i] = surface_ID - if sense < 0: - cell._region_RPN.insert(i + 1, BOOL_NOT) - i += 1 - - # ========================================================================= - # Time census-based tally - # ========================================================================= - # Reset time grid size of all tallies if census-based tally is desired + if len(simulation.universes[0].cells) == 0: + simulation.universes[0].cells = simulation.cells - if input_deck.setting["census_based_tally"]: - N_bin = input_deck.setting["census_tally_frequency"] - for tally in input_deck.mesh_tallies: - tally.N_bin *= N_bin / (len(tally.t) - 1) - tally.t = np.zeros(N_bin + 1) + # Initial guess + simulation.k_eff = settings.k_init - # ========================================================================= - # Adapt kernels - # ========================================================================= - - kernel.adapt_rng(nb.config.DISABLE_JIT) - - # ========================================================================= - # Make types - # ========================================================================= - - type_.make_type_particle(input_deck) - type_.make_type_particle_record(input_deck) - type_.make_type_nuclide(input_deck) - type_.make_type_material(input_deck) - type_.make_type_surface(input_deck) - type_.make_type_cell(input_deck) - type_.make_type_lattice(input_deck) - type_.make_type_source(input_deck) - type_.make_type_mesh_tally(input_deck) - type_.make_type_surface_tally(input_deck) - type_.make_type_cell_tally(input_deck) - type_.make_type_cs_tally(input_deck) - type_.make_type_setting(input_deck) - type_.make_type_uq(input_deck) - type_.make_type_domain_decomp(input_deck) - type_.make_type_dd_turnstile_event(input_deck) - type_.make_type_technique(input_deck) - type_.make_type_gpu_meta() - type_.make_type_global(input_deck) - type_.make_size_rpn(input_deck) - kernel.adapt_rng(nb.config.DISABLE_JIT) - - input_deck.setting["target"] = config.target - - # ========================================================================= - # Create the global variable container - # TODO: Better alternative? - # ========================================================================= - - mcdc_arr = np.zeros(1, dtype=type_.global_) + # Activate tally scoring for fixed-source + if not settings.eigenvalue_mode: + simulation.cycle_active = True + # All active eigenvalue cycle? + elif settings.N_inactive == 0: + simulation.cycle_active = True + + # ================================================================================== + # Set particle bank sizes + # ================================================================================== + + # Some sizes + N_particle = settings.N_particle + N_work = math.ceil(N_particle / MPI.COMM_WORLD.Get_size()) + N_census = settings.N_census + + # Determine bank size + if settings.eigenvalue_mode or N_census == 1: + settings.future_bank_buffer_ratio = 0.0 + if not settings.eigenvalue_mode and N_census == 1: + settings.census_bank_buffer_ratio = 0.0 + settings.source_bank_buffer_ratio = 0.0 + size_active = settings.active_bank_buffer + size_census = int((settings.census_bank_buffer_ratio) * N_work) + size_source = int((settings.source_bank_buffer_ratio) * N_work) + size_future = int((settings.future_bank_buffer_ratio) * N_work) + + # Set bank size + simulation.bank_active.size[0] = size_active + simulation.bank_census.size[0] = size_census + simulation.bank_source.size[0] = size_source + simulation.bank_future.size[0] = size_future + + # ================================================================================== + # Generate Numba-supported "Objects" + # ================================================================================== + + import mcdc.code_factory.code_factory as code_factory + + if MPI.COMM_WORLD.Get_rank() == 0: + code_factory.make_literals(simulation) + mcdc_arr, data = code_factory.generate_numba_objects(simulation) mcdc = mcdc_arr[0] - # Now, set up the global variable container - - # Get modes - mode_CE = input_deck.setting["mode_CE"] - mode_MG = input_deck.setting["mode_MG"] - - # ========================================================================= - # Nuclides - # ========================================================================= - - N_nuclide = len(input_deck.nuclides) - for i in range(N_nuclide): - # General data - for name in ["ID", "fissionable"]: - copy_field(mcdc["nuclides"][i], input_deck.nuclides[i], name) - - # MG data - if mode_MG: - for name in [ - "G", - "J", - "speed", - "decay", - "total", - "capture", - "scatter", - "fission", - "nu_s", - "nu_f", - "nu_p", - "nu_d", - "chi_s", - "chi_p", - "chi_d", - ]: - copy_field(mcdc["nuclides"][i], input_deck.nuclides[i], name) - - # CE data (load data from XS library) - dir_name = os.getenv("MCDC_XSLIB") - if mode_CE: - nuc_name = input_deck.nuclides[i].name - with h5py.File(dir_name + "/" + nuc_name + ".h5", "r") as f: - # Atomic weight ratio - mcdc["nuclides"][i]["A"] = f["A"][()] - # Energy grids - for name in [ - "E_xs", - "E_nu_p", - "E_nu_d", - "E_chi_p", - "E_chi_d1", - "E_chi_d2", - "E_chi_d3", - "E_chi_d4", - "E_chi_d5", - "E_chi_d6", - ]: - mcdc["nuclides"][i]["N" + name] = len(f[name][:]) - mcdc["nuclides"][i][name][: len(f[name][:])] = f[name][:] - - # XS - for name in ["capture", "scatter", "fission"]: - mcdc["nuclides"][i]["ce_" + name][: len(f[name][:])] = f[name][:] - mcdc["nuclides"][i]["ce_total"][: len(f[name][:])] += f[name][:] - - # Fission production - mcdc["nuclides"][i]["ce_nu_p"][: len(f["nu_p"][:])] = f["nu_p"][:] - for j in range(6): - mcdc["nuclides"][i]["ce_nu_d"][j][: len(f["nu_d"][j, :])] = f[ - "nu_d" - ][j, :] - - # Fission spectrum - mcdc["nuclides"][i]["ce_chi_p"][: len(f["chi_p"][:])] = f["chi_p"][:] - for j in range(6): - mcdc["nuclides"][i]["ce_chi_d%i" % (j + 1)][ - : len(f["chi_d%i" % (j + 1)][:]) - ] = f["chi_d%i" % (j + 1)][:] - - # Decay - mcdc["nuclides"][i]["ce_decay"][: len(f["decay_rate"][:])] = f[ - "decay_rate" - ][:] - - # ========================================================================= - # Materials - # ========================================================================= - - N_material = len(input_deck.materials) - for i in range(N_material): - for name in type_.material.names: - if name in ["nuclide_IDs", "nuclide_densities"]: - mcdc["materials"][i][name][: mcdc["materials"][i]["N_nuclide"]] = ( - getattr(input_deck.materials[i], name) - ) - else: - copy_field(mcdc["materials"][i], input_deck.materials[i], name) - - # ========================================================================= - # Surfaces - # ========================================================================= - - N_surface = len(input_deck.surfaces) - for i in range(N_surface): - surface = mcdc["surfaces"][i] - surface_input = input_deck.surfaces[i] - - # Direct assignment - for name in type_.surface.names: - if name not in [ - "type", - "BC", - "tally_IDs", - "move_velocities", - "move_translations", - "move_time_grid", - ]: - copy_field(surface, surface_input, name) - - # Type - if surface_input.type == "plane-x": - surface["type"] = SURFACE_LINEAR - surface["type"] += SURFACE_PLANE_X - elif surface_input.type == "plane-y": - surface["type"] = SURFACE_LINEAR - surface["type"] += SURFACE_PLANE_Y - elif surface_input.type == "plane-z": - surface["type"] = SURFACE_LINEAR - surface["type"] += SURFACE_PLANE_Z - elif surface_input.type == "plane": - surface["type"] = SURFACE_LINEAR - surface["type"] += SURFACE_PLANE - elif surface_input.type == "cylinder-x": - surface["type"] = SURFACE_QUADRATIC - surface["type"] += SURFACE_CYLINDER_X - elif surface_input.type == "cylinder-y": - surface["type"] = SURFACE_QUADRATIC - surface["type"] += SURFACE_CYLINDER_Y - elif surface_input.type == "cylinder-z": - surface["type"] = SURFACE_QUADRATIC - surface["type"] += SURFACE_CYLINDER_Z - elif surface_input.type == "sphere": - surface["type"] = SURFACE_QUADRATIC - surface["type"] += SURFACE_SPHERE - elif surface_input.type == "quadric": - surface["type"] = SURFACE_QUADRATIC - surface["type"] += SURFACE_SPHERE - - # Boundary condition - if input_deck.surfaces[i].boundary_type == "interface": - mcdc["surfaces"][i]["BC"] = BC_NONE - elif input_deck.surfaces[i].boundary_type == "vacuum": - mcdc["surfaces"][i]["BC"] = BC_VACUUM - elif input_deck.surfaces[i].boundary_type == "reflective": - mcdc["surfaces"][i]["BC"] = BC_REFLECTIVE - - # Variables with possible different sizes - for name in ["tally_IDs"]: - N = len(getattr(input_deck.surfaces[i], name)) - mcdc["surfaces"][i][name][:N] = getattr(input_deck.surfaces[i], name) - - # Moves - if surface["moving"]: - for n in range(surface["N_move"]): - duration = surface_input.move_durations[n] - velocity = surface_input.move_velocities[n] - - surface["move_velocities"][n] = velocity - - t_start = surface["move_time_grid"][n] - surface["move_time_grid"][n + 1] = t_start + duration - - trans_start = surface["move_translations"][n] - surface["move_translations"][n + 1] = trans_start + velocity * duration - - # ========================================================================= - # Set cells - # ========================================================================= - - N_cell = len(input_deck.cells) - surface_data_idx = 0 - region_data_idx = 0 - for i in range(N_cell): - cell = mcdc["cells"][i] - cell_input = input_deck.cells[i] - - # Directly transferables - for name in ["ID", "fill_ID", "translation", "rotation", "N_tally"]: - copy_field(cell, cell_input, name) - - # Fill type - if cell_input.fill_type == "material": - cell["fill_type"] = FILL_MATERIAL - elif cell_input.fill_type == "universe": - cell["fill_type"] = FILL_UNIVERSE - elif cell_input.fill_type == "lattice": - cell["fill_type"] = FILL_LATTICE - - # Fill translation - if np.max(np.abs(cell["translation"])) > 0.0: - cell["fill_translated"] = True - - # Fill rotation - if np.max(np.abs(cell["rotation"])) > 0.0: - cell["fill_rotated"] = True - - # Convert rotation - cell["rotation"][0] *= PI / 180.0 - cell["rotation"][1] *= PI / 180.0 - cell["rotation"][2] *= PI / 180.0 - - # Surface IDs - cell["surface_data_idx"] = surface_data_idx - cell["N_surface"] = len(cell_input.surface_IDs) - # The data - start = surface_data_idx - end = start + cell["N_surface"] - mcdc["cells_data_surface"][start:end] = cell_input.surface_IDs - surface_data_idx += cell["N_surface"] - - # Region RPN tokens - cell["region_data_idx"] = region_data_idx - cell["N_region"] = len(cell_input._region_RPN) - # The data - start = region_data_idx - end = start + cell["N_region"] - mcdc["cells_data_region"][start:end] = cell_input._region_RPN - region_data_idx += cell["N_region"] - - # Variables with possible different sizes - for name in ["tally_IDs"]: - N = len(getattr(input_deck.cells[i], name)) - mcdc["cells"][i][name][:N] = getattr(input_deck.cells[i], name) - - # ========================================================================= - # Set universes - # ========================================================================= - - N_universe = len(input_deck.universes) - cell_data_idx = 0 - for i in range(N_universe): - universe = mcdc["universes"][i] - universe_input = input_deck.universes[i] - - # Directly transferables - for name in ["ID"]: - copy_field(universe, universe_input, name) - - # Cells IDs - universe["cell_data_idx"] = cell_data_idx - universe["N_cell"] = len(universe_input.cell_IDs) - # Cell ID data - start = cell_data_idx - end = start + universe["N_cell"] - mcdc["universes_data_cell"][start:end] = universe_input.cell_IDs - cell_data_idx += universe["N_cell"] - - # ========================================================================= - # Lattices - # ========================================================================= - - N_lattice = len(input_deck.lattices) - for i in range(N_lattice): - for name in type_.lattice.names: - if name not in ["universe_IDs", "t0", "dt", "Nt"]: - mcdc["lattices"][i][name] = getattr(input_deck.lattices[i], name) - - # Universe IDs - Nx = mcdc["lattices"][i]["Nx"] - Ny = mcdc["lattices"][i]["Ny"] - Nz = mcdc["lattices"][i]["Nz"] - mcdc["lattices"][i]["universe_IDs"][:Nx, :Ny, :Nz] = input_deck.lattices[ - i - ].universe_IDs - - # Default for time grid - mcdc["lattices"][i]["t0"] = 0.0 - mcdc["lattices"][i]["dt"] = INF - mcdc["lattices"][i]["Nt"] = 1 - - # ========================================================================= - # Source - # ========================================================================= - - N_source = len(input_deck.sources) - for i in range(N_source): - for name in type_.source.names: - copy_field(mcdc["sources"][i], input_deck.sources[i], name) - - # Normalize source probabilities - tot = 1e-16 - for S in mcdc["sources"]: - tot += S["prob"] - for S in mcdc["sources"]: - S["prob"] /= tot - - # ========================================================================= - # Tally - # ========================================================================= - - N_mesh_tally = len(input_deck.mesh_tallies) - N_surface_tally = len(input_deck.surface_tallies) - N_cell_tally = len(input_deck.cell_tallies) - N_cs_tally = len(input_deck.cs_tallies) - tally_bin_size = 0 - - # Mesh tallies - for i in range(N_mesh_tally): - # Direct assignment - copy_field(mcdc["mesh_tallies"][i], input_deck.mesh_tallies[i], "N_bin") - - # Filters (variables with possible different sizes) - if not input_deck.technique["domain_decomposition"]: - for name in ["x", "y", "z", "t", "mu", "azi", "g"]: - N = len(getattr(input_deck.mesh_tallies[i], name)) - mcdc["mesh_tallies"][i]["filter"][name][:N] = getattr( - input_deck.mesh_tallies[i], name - ) - - else: # decomposed mesh filters - mcdc["technique"]["dd_xsum"] = len(input_deck.mesh_tallies[i].x) - 1 - mcdc["technique"]["dd_ysum"] = len(input_deck.mesh_tallies[i].y) - 1 - mcdc["technique"]["dd_zsum"] = len(input_deck.mesh_tallies[i].z) - 1 - - mxn, mxp, myn, myp, mzn, mzp = dd_mesh_bounds(i) - - # Filters - new_x = input_deck.mesh_tallies[i].x[mxn:mxp] - new_y = input_deck.mesh_tallies[i].y[myn:myp] - new_z = input_deck.mesh_tallies[i].z[mzn:mzp] - xlen = len(new_x) - ylen = len(new_y) - zlen = len(new_z) - mcdc["mesh_tallies"][i]["filter"]["x"][:xlen] = new_x - mcdc["mesh_tallies"][i]["filter"]["y"][:ylen] = new_y - mcdc["mesh_tallies"][i]["filter"]["z"][:zlen] = new_z - mcdc["technique"]["dd_xlen"] = xlen - 1 - mcdc["technique"]["dd_ylen"] = ylen - 1 - mcdc["technique"]["dd_zlen"] = zlen - 1 - for name in ["t", "mu", "azi", "g"]: - N = len(getattr(input_deck.mesh_tallies[i], name)) - mcdc["mesh_tallies"][i]["filter"][name][:N] = getattr( - input_deck.mesh_tallies[i], name - ) - - # Set tally scores - N_score = len(input_deck.mesh_tallies[i].scores) - mcdc["mesh_tallies"][i]["N_score"] = N_score - for j in range(N_score): - score_name = input_deck.mesh_tallies[i].scores[j] - score_type = None - if score_name == "flux": - score_type = SCORE_FLUX - elif score_name == "density": - score_type = SCORE_DENSITY - elif score_name == "total": - score_type = SCORE_TOTAL - elif score_name == "fission": - score_type = SCORE_FISSION - elif score_name == "net-current": - score_type = SCORE_NET_CURRENT - elif score_name == "mu-sq": - score_type = SCORE_MU_SQ - elif score_name == "time-moment-flux": - score_type = SCORE_TIME_MOMENT_FLUX - elif score_name == "space-moment-flux": - score_type = SCORE_SPACE_MOMENT_FLUX - elif score_name == "time-moment-current": - score_type = SCORE_TIME_MOMENT_CURRENT - elif score_name == "space-moment-current": - score_type = SCORE_SPACE_MOMENT_CURRENT - elif score_name == "time-moment-mu-sq": - score_type = SCORE_TIME_MOMENT_MU_SQ - elif score_name == "space-moment-mu-sq": - score_type = SCORE_SPACE_MOMENT_MU_SQ - mcdc["mesh_tallies"][i]["scores"][j] = score_type - - # Filter grid sizes - Nmu = len(input_deck.mesh_tallies[i].mu) - 1 - N_azi = len(input_deck.mesh_tallies[i].azi) - 1 - Ng = len(input_deck.mesh_tallies[i].g) - 1 - Nx = len(input_deck.mesh_tallies[i].x) - 1 - Ny = len(input_deck.mesh_tallies[i].y) - 1 - Nz = len(input_deck.mesh_tallies[i].z) - 1 - Nt = len(input_deck.mesh_tallies[i].t) - 1 - mcdc["mesh_tallies"][i]["filter"]["Nmu"] = Nmu - mcdc["mesh_tallies"][i]["filter"]["N_azi"] = N_azi - mcdc["mesh_tallies"][i]["filter"]["Ng"] = Ng - mcdc["mesh_tallies"][i]["filter"]["Nx"] = Nx - mcdc["mesh_tallies"][i]["filter"]["Ny"] = Ny - mcdc["mesh_tallies"][i]["filter"]["Nz"] = Nz - mcdc["mesh_tallies"][i]["filter"]["Nt"] = Nt - - # Decompose mesh tallies - if input_deck.technique["domain_decomposition"]: - Nmu = len(input_deck.mesh_tallies[i].mu) - 1 - N_azi = len(input_deck.mesh_tallies[i].azi) - 1 - Ng = len(input_deck.mesh_tallies[i].g) - 1 - Nx = len(input_deck.mesh_tallies[i].x[mxn:mxp]) - 1 - Ny = len(input_deck.mesh_tallies[i].y[myn:myp]) - 1 - Nz = len(input_deck.mesh_tallies[i].z[mzn:mzp]) - 1 - Nt = len(input_deck.mesh_tallies[i].t) - 1 - mcdc["mesh_tallies"][i]["N_bin"] = Nx * Ny * Nz * Nt * Nmu * N_azi * Ng - mcdc["mesh_tallies"][i]["filter"]["Nx"] = Nx - mcdc["mesh_tallies"][i]["filter"]["Ny"] = Ny - mcdc["mesh_tallies"][i]["filter"]["Nz"] = Nz - - # Update N_bin - mcdc["mesh_tallies"][i]["N_bin"] *= N_score - - # Filter strides - stride = N_score - if Nz > 1: - mcdc["mesh_tallies"][i]["stride"]["z"] = stride - stride *= Nz - if Ny > 1: - mcdc["mesh_tallies"][i]["stride"]["y"] = stride - stride *= Ny - if Nx > 1: - mcdc["mesh_tallies"][i]["stride"]["x"] = stride - stride *= Nx - if Nt > 1: - mcdc["mesh_tallies"][i]["stride"]["t"] = stride - stride *= Nt - if Ng > 1: - mcdc["mesh_tallies"][i]["stride"]["g"] = stride - stride *= Ng - if N_azi > 1: - mcdc["mesh_tallies"][i]["stride"]["azi"] = stride - stride *= N_azi - if Nmu > 1: - mcdc["mesh_tallies"][i]["stride"]["mu"] = stride - stride *= Nmu - - # Set tally stride and accumulate total tally size - mcdc["mesh_tallies"][i]["stride"]["tally"] = tally_bin_size - tally_bin_size += mcdc["mesh_tallies"][i]["N_bin"] - - # Surface tallies - for i in range(N_surface_tally): - # Direct assignment - copy_field(mcdc["surface_tallies"][i], input_deck.surface_tallies[i], "N_bin") - - # Filters (variables with possible different sizes) - for name in ["t", "mu", "azi", "g"]: - N = len(getattr(input_deck.surface_tallies[i], name)) - mcdc["surface_tallies"][i]["filter"][name][:N] = getattr( - input_deck.surface_tallies[i], name - ) + # Reload mcdc getters and setters + import importlib + import mcdc.mcdc_get as mcdc_get + import mcdc.mcdc_set as mcdc_set - # Set tally scores and their strides - N_score = len(input_deck.surface_tallies[i].scores) - mcdc["surface_tallies"][i]["N_score"] = N_score - for j in range(N_score): - score_name = input_deck.surface_tallies[i].scores[j] - mcdc["surface_tallies"][i]["scores"][j] = SCORE_NET_CURRENT - - # Filter grid sizes - Nmu = len(input_deck.surface_tallies[i].mu) - 1 - N_azi = len(input_deck.surface_tallies[i].azi) - 1 - Ng = len(input_deck.surface_tallies[i].g) - 1 - Nt = len(input_deck.surface_tallies[i].t) - 1 - - # Update N_bin - mcdc["surface_tallies"][i]["N_bin"] *= N_score - - # Filter strides - stride = N_score - if Nt > 1: - mcdc["surface_tallies"][i]["stride"]["t"] = stride - stride *= Nt - if Ng > 1: - mcdc["surface_tallies"][i]["stride"]["g"] = stride - stride *= Ng - if N_azi > 1: - mcdc["surface_tallies"][i]["stride"]["azi"] = stride - stride *= N_azi - if Nmu > 1: - mcdc["surface_tallies"][i]["stride"]["mu"] = stride - stride *= Nmu - - # Set tally stride and accumulate total tally size - mcdc["surface_tallies"][i]["stride"]["tally"] = tally_bin_size - tally_bin_size += mcdc["surface_tallies"][i]["N_bin"] - - # Cell tallies - for i in range(N_cell_tally): - copy_field(mcdc["cell_tallies"][i], input_deck.cell_tallies[i], "N_bin") - - # Filters (variables with possible different sizes) - for name in ["t", "mu", "azi", "g"]: - N = len(getattr(input_deck.cell_tallies[i], name)) - mcdc["cell_tallies"][i]["filter"][name][:N] = getattr( - input_deck.cell_tallies[i], name - ) + importlib.reload(mcdc_get) + importlib.reload(mcdc_set) - # Differentiating the tallies by cell_ID - mcdc["cell_tallies"][i]["filter"]["cell_ID"] = getattr( - input_deck.cell_tallies[i], "cell_ID" - ) + # ================================================================================== + # Platform Targeting, Adapters, Toggles, etc + # ================================================================================== - # Set tally scores and their strides - N_score = len(input_deck.cell_tallies[i].scores) - mcdc["cell_tallies"][i]["N_score"] = N_score - for j in range(N_score): - score_name = input_deck.cell_tallies[i].scores[j] - score_type = None - if score_name == "flux": - score_type = SCORE_FLUX - elif score_name == "fission": - score_type = SCORE_FISSION - elif score_name == "net-current": - score_type = SCORE_NET_CURRENT - mcdc["cell_tallies"][i]["scores"][j] = score_type - - # Filter grid sizes - Nmu = len(input_deck.cell_tallies[i].mu) - 1 - N_azi = len(input_deck.cell_tallies[i].azi) - 1 - Ng = len(input_deck.cell_tallies[i].g) - 1 - Nt = len(input_deck.cell_tallies[i].t) - 1 - mcdc["cell_tallies"][i]["filter"]["Ng"] = Ng - mcdc["cell_tallies"][i]["filter"]["Nt"] = Nt - - # Update N_bin - mcdc["cell_tallies"][i]["N_bin"] *= N_score - - # Filter strides - stride = N_score - if Nt > 1: - mcdc["cell_tallies"][i]["stride"]["t"] = stride - stride *= Nt - if Ng > 1: - mcdc["cell_tallies"][i]["stride"]["g"] = stride - stride *= Ng - if N_azi > 1: - mcdc["cell_tallies"][i]["stride"]["azi"] = stride - stride *= N_azi - if Nmu > 1: - mcdc["cell_tallies"][i]["stride"]["mu"] = stride - stride *= Nmu - - # Set tally stride and accumulate total tally size - mcdc["cell_tallies"][i]["stride"]["tally"] = tally_bin_size - tally_bin_size += mcdc["cell_tallies"][i]["N_bin"] - - # CS tallies - for i in range(N_cs_tally): - # Direct assignment - copy_field(mcdc["cs_tallies"][i], input_deck.cs_tallies[i], "N_bin") - - mcdc["cs_tallies"][i]["filter"]["N_cs_bins"] = input_deck.cs_tallies[ - i - ].N_cs_bins[0] - mcdc["cs_tallies"][i]["filter"]["cs_bin_size"] = input_deck.cs_tallies[ - i - ].cs_bin_size[0] - - # Filters (variables with possible different sizes) - if not input_deck.technique["domain_decomposition"]: - for name in ["x", "y", "z", "t", "mu", "azi", "g"]: - N = len(getattr(input_deck.cs_tallies[i], name)) - mcdc["cs_tallies"][i]["filter"][name][:N] = getattr( - input_deck.cs_tallies[i], name - ) - - mcdc["cs_tallies"][i]["filter"]["cs_centers"] = generate_cs_centers(mcdc) - - # Set tally scores - N_score = len(input_deck.cs_tallies[i].scores) - mcdc["cs_tallies"][i]["N_score"] = N_score - for j in range(N_score): - score_name = input_deck.cs_tallies[i].scores[j] - score_type = None - if score_name == "flux": - score_type = SCORE_FLUX - elif score_name == "density": - score_type = SCORE_DENSITY - elif score_name == "total": - score_type = SCORE_TOTAL - elif score_name == "fission": - score_type = SCORE_FISSION - elif score_name == "net-current": - score_type = SCORE_NET_CURRENT - mcdc["cs_tallies"][i]["scores"][j] = score_type - - # Update N_bin - mcdc["cs_tallies"][i]["N_bin"] *= N_score - - # Set tally stride and accumulate total tally size - mcdc["cs_tallies"][i]["stride"]["tally"] = tally_bin_size - tally_bin_size += mcdc["cs_tallies"][i]["filter"]["N_cs_bins"] - - # Set tally data - if not input_deck.technique["uq"]: - tally_bin_N_copies = 3 - else: - tally_bin_N_copies = 5 + # Adapt kernels + import numba as nb + import mcdc.code_factory.adapt as adapt + import mcdc.config as config + import mcdc.transport.mpi as mpi - tally_shape = (tally_bin_N_copies, tally_bin_size) + # TODO: Find out why the following is needed to avoid circular import + import mcdc.transport.particle_bank as particle_bank_module - # ========================================================================= - # Platform Targeting, Adapters, Toggles, etc - # ========================================================================= + settings.target_gpu = True if config.target == "gpu" else False if config.target == "gpu": + import object_.numba_types as type_ + if MPI.COMM_WORLD.Get_rank() != 0: adapt.harm.config.should_compile(adapt.harm.config.ShouldCompile.NEVER) elif config.caching == False: @@ -1158,370 +241,37 @@ def prepare(): print_error( "No module named 'harmonize' - GPU functionality not available. " ) - adapt.gpu_forward_declare(config.args, tally_shape) + adapt.gpu_forward_declare( + config.args, + data.shape, + type_.simulation, + type_.particle, + type_.particle_data, + ) - adapt.set_toggle("iQMC", input_deck.technique["iQMC"]) - adapt.set_toggle("domain_decomp", input_deck.technique["domain_decomposition"]) adapt.eval_toggle() adapt.target_for(config.target) if config.target == "gpu": build_gpu_progs(input_deck, config.args) adapt.nopython_mode((config.mode == "numba") or (config.mode == "numba_debug")) - # ========================================================================= - # Allocate Tally Storage - # ========================================================================= - - data_tally, data_tally_uint = adapt.create_tally_array( - tally_shape[0], tally_shape[1] - ) - - mcdc_arr, mcdc_uint = adapt.create_mcdc_array() - mcdc_arr[0] = mcdc - mcdc = mcdc_arr[0] - - # ========================================================================= - # Setting - # ========================================================================= - - for name in type_.setting.names: - copy_field(mcdc["setting"], input_deck.setting, name) - - t_limit = max( - [ - tally["filter"]["t"][-1] - for tally in list(mcdc["mesh_tallies"]) - + list(mcdc["surface_tallies"]) - + list(mcdc["cell_tallies"]) - ] - ) - - if ( - len(input_deck.mesh_tallies) - + len(input_deck.surface_tallies) - + len(input_deck.cell_tallies) - == 0 - ): - t_limit = INF - - # Replace the time limit if time census-based tally is used - if mcdc["setting"]["census_based_tally"]: - t_limit = mcdc["setting"]["census_time"][-2] - - # Set appropriate time boundary - if mcdc["setting"]["time_boundary"] > t_limit: - mcdc["setting"]["time_boundary"] = t_limit - - if input_deck.technique["iQMC"]: - if len(mcdc["technique"]["iqmc"]["mesh"]["t"]) - 1 > 1: - if ( - mcdc["setting"]["time_boundary"] - > input_deck.technique["iqmc"]["mesh"]["t"][-1] - ): - mcdc["setting"]["time_boundary"] = input_deck.technique["iqmc"]["mesh"][ - "t" - ][-1] - - # ========================================================================= - # Technique - # ========================================================================= - - # Flags - for name in [ - "weighted_emission", - "implicit_capture", - "population_control", - "weight_window", - "domain_decomposition", - "weight_roulette", - "iQMC", - "IC_generator", - "branchless_collision", - "uq", - ]: - copy_field(mcdc["technique"], input_deck.technique, name) - - # ========================================================================= - # Population control - # ========================================================================= - - # Population control technique (PCT) - pct = input_deck.technique["pct"] - if pct == "combing": - mcdc["technique"]["pct"] = PCT_COMBING - elif pct == "combing-weight": - mcdc["technique"]["pct"] = PCT_COMBING_WEIGHT - elif pct == "splitting-roulette": - mcdc["technique"]["pct"] = PCT_SPLITTING_ROULETTE - elif pct == "splitting-roulette-weight": - mcdc["technique"]["pct"] = PCT_SPLITTING_ROULETTE_WEIGHT - mcdc["technique"]["pc_factor"] = input_deck.technique["pc_factor"] - - # ========================================================================= - # IC generator - # ========================================================================= - - for name in [ - "IC_N_neutron", - "IC_N_precursor", - "IC_neutron_density", - "IC_neutron_density_max", - "IC_precursor_density", - "IC_precursor_density_max", - ]: - copy_field(mcdc["technique"], input_deck.technique, name) - - # ========================================================================= - # Weight window (WW) - # ========================================================================= - - # WW mesh - for name in type_.mesh_names[:-1]: - copy_field( - mcdc["technique"]["ww"]["mesh"], input_deck.technique["ww"]["mesh"], name - ) - - mcdc["technique"]["ww"]["mesh"]["Nx"] = ( - len(input_deck.technique["ww"]["mesh"]["x"]) - 1 - ) - mcdc["technique"]["ww"]["mesh"]["Ny"] = ( - len(input_deck.technique["ww"]["mesh"]["y"]) - 1 - ) - mcdc["technique"]["ww"]["mesh"]["Nz"] = ( - len(input_deck.technique["ww"]["mesh"]["z"]) - 1 - ) - mcdc["technique"]["ww"]["mesh"]["Nt"] = ( - len(input_deck.technique["ww"]["mesh"]["t"]) - 1 - ) - - # WW parameters - mcdc["technique"]["ww"]["width"] = input_deck.technique["ww"]["width"] - mcdc["technique"]["ww"]["auto"] = input_deck.technique["ww"]["auto"] - mcdc["technique"]["ww"]["epsilon"] = input_deck.technique["ww"]["epsilon"] - mcdc["technique"]["ww"]["center"] = input_deck.technique["ww"]["center"] - mcdc["technique"]["ww"]["save"] = input_deck.technique["ww"]["save"] - mcdc["technique"]["ww"]["tally_idx"] = input_deck.technique["ww"]["tally_idx"] - # ========================================================================= - # Weight roulette - # ========================================================================= - - # Threshold - mcdc["technique"]["wr_threshold"] = input_deck.technique["wr_threshold"] - - # Survival probability - mcdc["technique"]["wr_survive"] = input_deck.technique["wr_survive"] - - # ========================================================================= - # Domain Decomposition - # ========================================================================= - - # Set domain mesh - if input_deck.technique["domain_decomposition"]: - for name in ["x", "y", "z", "t", "mu", "azi"]: - copy_field( - mcdc["technique"]["dd_mesh"], input_deck.technique["dd_mesh"], name - ) - mcdc["technique"]["dd_mesh"]["Nx"] = ( - input_deck.technique["dd_mesh"]["x"].size - 1 - ) - mcdc["technique"]["dd_mesh"]["Ny"] = ( - input_deck.technique["dd_mesh"]["y"].size - 1 - ) - mcdc["technique"]["dd_mesh"]["Nz"] = ( - input_deck.technique["dd_mesh"]["z"].size - 1 - ) - mcdc["technique"]["dd_mesh"]["Nt"] = ( - input_deck.technique["dd_mesh"]["t"].size - 1 - ) - mcdc["technique"]["dd_mesh"]["Nmu"] = ( - input_deck.technique["dd_mesh"]["mu"].size - 1 - ) - mcdc["technique"]["dd_mesh"]["N_azi"] = ( - input_deck.technique["dd_mesh"]["azi"].size - 1 - ) - # Set exchange rate - for name in ["dd_exchange_rate"]: - copy_field(mcdc["technique"], input_deck.technique, name) - # Set domain index - copy_field(mcdc, input_deck.technique, "dd_idx") - copy_field(mcdc, input_deck.technique, "dd_local_rank") - for name in ["xp", "xn", "yp", "yn", "zp", "zn"]: - copy_field(mcdc["technique"], input_deck.technique, f"dd_{name}_neigh") - copy_field(mcdc["technique"], input_deck.technique, "dd_work_ratio") - - # ========================================================================= - # Quasi Monte Carlo - # ========================================================================= - - for name in type_.technique["iqmc"].names: - if name not in [ - "mesh", - "residual", - "samples", - "sweep_count", - "total_source", - "material_idx", - "w_min", - "score_list", - "score", - ]: - copy_field(mcdc["technique"]["iqmc"], input_deck.technique["iqmc"], name) - - if input_deck.technique["iQMC"]: - # pass in mesh - iqmc = mcdc["technique"]["iqmc"] - for name in ["x", "y", "z", "t"]: - copy_field(iqmc["mesh"], input_deck.technique["iqmc"]["mesh"], name) - Nx = len(input_deck.technique["iqmc"]["mesh"]["x"]) - 1 - Ny = len(input_deck.technique["iqmc"]["mesh"]["y"]) - 1 - Nz = len(input_deck.technique["iqmc"]["mesh"]["z"]) - 1 - Nt = len(input_deck.technique["iqmc"]["mesh"]["t"]) - 1 - iqmc["mesh"]["Nx"] = Nx - iqmc["mesh"]["Ny"] = Ny - iqmc["mesh"]["Nz"] = Nz - iqmc["mesh"]["Nt"] = Nt - # pass in score list - for name, value in input_deck.technique["iqmc"]["score_list"].items(): - copy_field( - iqmc["score_list"], input_deck.technique["iqmc"]["score_list"], name - ) - # pass in initial tallies - for name, value in input_deck.technique["iqmc"]["score"].items(): - mcdc["technique"]["iqmc"]["score"][name]["bin"] = value - # minimum particle weight - iqmc["w_min"] = 1e-13 - - # ========================================================================= - # Variance Deconvolution - UQ - # ========================================================================= - if mcdc["technique"]["uq"]: - M = len(input_deck.uq_deltas["materials"]) - for i in range(M): - idm = input_deck.uq_deltas["materials"][i].ID - mcdc["technique"]["uq_"]["materials"][i]["info"]["ID"] = idm - mcdc["technique"]["uq_"]["materials"][i]["info"]["distribution"] = ( - input_deck.uq_deltas["materials"][i].distribution - ) - for name in input_deck.uq_deltas["materials"][i].flags: - mcdc["technique"]["uq_"]["materials"][i]["flags"][name] = True - mcdc["technique"]["uq_"]["materials"][i]["delta"][name] = getattr( - input_deck.uq_deltas["materials"][i], name - ) - flags = mcdc["technique"]["uq_"]["materials"][i]["flags"] - if flags["capture"] or flags["scatter"] or flags["fission"]: - flags["total"] = True - flags["speed"] = True - if flags["nu_p"] or flags["nu_d"]: - flags["nu_f"] = True - if mcdc["materials"][idm]["N_nuclide"] > 1: - for name in type_.uq_mat.names: - mcdc["technique"]["uq_"]["materials"][i]["mean"][name] = ( - input_deck.materials[idm][name] - ) - - N = len(input_deck.uq_deltas["nuclides"]) - for i in range(N): - mcdc["technique"]["uq_"]["nuclides"][i]["info"]["distribution"] = ( - input_deck.uq_deltas["nuclides"][i].distribution - ) - idn = input_deck.uq_deltas["nuclides"][i].ID - mcdc["technique"]["uq_"]["nuclides"][i]["info"]["ID"] = idn - for name in type_.uq_nuc.names: - if name == "scatter": - G = input_deck.nuclides[idn].G - chi_s = input_deck.nuclides[idn].chi_s - scatter = input_deck.nuclides[idn].scatter - scatter_matrix = np.zeros((G, G)) - for g in range(G): - scatter_matrix[g, :] = chi_s[g, :] * scatter[g] - - mcdc["technique"]["uq_"]["nuclides"][i]["mean"][ - name - ] = scatter_matrix - else: - copy_field( - mcdc["technique"]["uq_"]["nuclides"][i]["mean"], - input_deck.nuclides[idn], - name, - ) - - for name in input_deck.uq_deltas["nuclides"][i].flags: - if "padding" in name: - continue - mcdc["technique"]["uq_"]["nuclides"][i]["flags"][name] = True - copy_field( - mcdc["technique"]["uq_"]["nuclides"][i]["delta"], - input_deck.uq_deltas["nuclides"][i], - name, - ) - flags = mcdc["technique"]["uq_"]["nuclides"][i]["flags"] - if flags["capture"] or flags["scatter"] or flags["fission"]: - flags["total"] = True - if flags["nu_p"] or flags["nu_d"]: - flags["nu_f"] = True - - # ========================================================================= - # MPI - # ========================================================================= - - # MPI parameters - mcdc["mpi_size"] = MPI.COMM_WORLD.Get_size() - mcdc["mpi_rank"] = MPI.COMM_WORLD.Get_rank() - mcdc["mpi_master"] = mcdc["mpi_rank"] == 0 - - # Distribute work to MPI ranks - if mcdc["technique"]["domain_decomposition"]: - kernel.distribute_work_dd(mcdc["setting"]["N_particle"], mcdc) - else: - kernel.distribute_work(mcdc["setting"]["N_particle"], mcdc) - - # ========================================================================= - # Particle banks - # ========================================================================= - - # Particle bank tags - mcdc["bank_active"]["tag"] = "active" - mcdc["bank_census"]["tag"] = "census" - mcdc["bank_source"]["tag"] = "source" - mcdc["bank_future"]["tag"] = "future" - - # IC generator banks - if mcdc["technique"]["IC_generator"]: - mcdc["technique"]["IC_bank_neutron_local"]["tag"] = "neutron" - mcdc["technique"]["IC_bank_precursor_local"]["tag"] = "precursor" - mcdc["technique"]["IC_bank_neutron"]["tag"] = "neutron" - mcdc["technique"]["IC_bank_precursor"]["tag"] = "precursor" - - # ========================================================================= - # Eigenvalue (or fixed-source) - # ========================================================================= - - # Initial guess - mcdc["k_eff"] = mcdc["setting"]["k_init"] - - # Activate tally scoring for fixed-source - if not mcdc["setting"]["mode_eigenvalue"]: - mcdc["cycle_active"] = True - - # All active eigenvalue cycle? - elif mcdc["setting"]["N_inactive"] == 0: - mcdc["cycle_active"] = True - - # ========================================================================= + # ================================================================================== # Source file # TODO: Use parallel h5py - # ========================================================================= + # ================================================================================== + + import h5py # All ranks, take turn for i in range(mcdc["mpi_size"]): if mcdc["mpi_rank"] == i: - if mcdc["setting"]["source_file"]: - with h5py.File(mcdc["setting"]["source_file_name"], "r") as f: + if settings.use_source_file: + with h5py.File(settings.source_file_name, "r") as f: # Get source particle size N_particle = f["particles_size"][()] # Redistribute work - kernel.distribute_work(N_particle, mcdc) + mpi.distribute_work(N_particle, mcdc) N_local = mcdc["mpi_work_size"] start = mcdc["mpi_work_start"] end = start + N_local @@ -1533,889 +283,37 @@ def prepare(): mcdc["bank_source"]["size"] = N_local MPI.COMM_WORLD.Barrier() - # ========================================================================= - # IC file - # ========================================================================= - - if mcdc["setting"]["IC_file"]: - with h5py.File(mcdc["setting"]["IC_file_name"], "r") as f: - # ================================================================= - # Set neutron source - # ================================================================= - - # Get source particle size - N_particle = f["IC/neutrons_size"][()] - - # Redistribute work - kernel.distribute_work(N_particle, mcdc) - N_local = mcdc["mpi_work_size"] - start = mcdc["mpi_work_start"] - end = start + N_local - - # Add particles to source bank - mcdc["bank_source"]["particles"][:N_local] = f["IC/neutrons"][start:end] - mcdc["bank_source"]["size"] = N_local - - # ================================================================= - # Set precursor source - # ================================================================= - - # Get source particle size - N_precursor = f["IC/precursors_size"][()] - - # Redistribute work - kernel.distribute_work(N_precursor, mcdc, True) # precursor = True - N_local = mcdc["mpi_work_size_precursor"] - start = mcdc["mpi_work_start_precursor"] - end = start + N_local - - # Add particles to source bank - mcdc["bank_precursor"]["precursors"][:N_local] = f["IC/precursors"][ - start:end - ] - mcdc["bank_precursor"]["size"] = N_local - - # Set precursor strength - if N_precursor > 0 and N_particle > 0: - mcdc["precursor_strength"] = mcdc["bank_precursor"]["precursors"][0][ - "w" - ] - - loop.setup_gpu(mcdc_arr, data_tally) - - # ========================================================================= - # Finalize data: wrapping into a tuple - # ========================================================================= + # ================================================================================== + # Adapt functions + # ================================================================================== - return data_tally, mcdc_arr + # Pick physics model + import mcdc.transport.physics as physics + if settings.multigroup_mode: + physics.neutron.particle_speed = physics.neutron.multigroup.particle_speed + physics.neutron.macro_xs = physics.neutron.multigroup.macro_xs + physics.neutron.neutron_production_xs = ( + physics.neutron.multigroup.neutron_production_xs + ) + physics.neutron.collision = physics.neutron.multigroup.collision -def cardlist_to_h5group(dictlist, input_group, name): - if name[-1] != "s": - main_group = input_group.create_group(name + "s") - else: - main_group = input_group.create_group(name) - for item in dictlist: - group = main_group.create_group(name + "_%i" % getattr(item, "ID")) - card_to_h5group(item, group) - - -def card_to_h5group(card, group): - for name in [ - a - for a in dir(card) - if not a.startswith("__") and not callable(getattr(card, a)) and a != "tag" - ]: - value = getattr(card, name) - if type(value) == dict: - dict_to_h5group(value, group.create_group(name)) - elif value is None: - next - else: - if name not in ["region"]: - group[name] = value + # Pick Python-version RNG if needed + import mcdc.transport.rng as rng - elif name == "region": - group[name] = str(value) + if config.mode == "python": + rng.wrapping_add = rng.wrapping_add_python + rng.wrapping_mul = rng.wrapping_mul_python + # ================================================================================== + # Finalize data: wrapping into a tuple + # ================================================================================== -def dictlist_to_h5group(dictlist, input_group, name): - if name[-1] != "s": - main_group = input_group.create_group(name + "s") - else: - main_group = input_group.create_group(name) - for item in dictlist: - group = main_group.create_group(name + "_%i" % item["ID"]) - dict_to_h5group(item, group) - - -def dict_to_h5group(dict_, group): - for k, v in dict_.items(): - if type(v) == dict: - dict_to_h5group(dict_[k], group.create_group(k)) - elif v is None: - next - else: - group[k] = v + from mcdc.transport.simulation import setup_gpu + setup_gpu(mcdc) -def dd_mergetally(mcdc, data_tally): - """ - Performs tally recombination on domain-decomposed mesh tallies. - Gathers and re-organizes tally data into a single array as it - would appear in a non-decomposed simulation. - """ - - # create bin for recomposed tallies - d_Nx = input_deck.technique["dd_mesh"]["x"].size - 1 - d_Ny = input_deck.technique["dd_mesh"]["y"].size - 1 - d_Nz = input_deck.technique["dd_mesh"]["z"].size - 1 - - # capture tally lengths for reorganizing later - xlen = mcdc["technique"]["dd_xlen"] - ylen = mcdc["technique"]["dd_ylen"] - zlen = mcdc["technique"]["dd_zlen"] - - # MPI gather - if (d_Nx * d_Ny * d_Nz) == MPI.COMM_WORLD.Get_size(): - sendcounts = np.array(MPI.COMM_WORLD.gather(len(data_tally[0]), root=0)) - if mcdc["mpi_master"]: - dd_tally = np.zeros((data_tally.shape[0], sum(sendcounts))) - else: - dd_tally = np.empty(data_tally.shape[0]) # dummy tally - # gather tallies - for i, t in enumerate(data_tally): - MPI.COMM_WORLD.Gatherv( - sendbuf=data_tally[i], recvbuf=(dd_tally[i], sendcounts), root=0 - ) - # gather tally lengths for proper recombination - xlens = MPI.COMM_WORLD.gather(xlen, root=0) - ylens = MPI.COMM_WORLD.gather(ylen, root=0) - zlens = MPI.COMM_WORLD.gather(zlen, root=0) - - # MPI gather for multiprocessor subdomains - else: - i = 0 - dd_ranks = [] - # find nonzero tally processor IDs - for n in range(d_Nx * d_Ny * d_Nz): - dd_ranks.append(i) - i += int(mcdc["technique"]["dd_work_ratio"][n]) - # create MPI comm group for nonzero tallies - dd_group = MPI.COMM_WORLD.group.Incl(dd_ranks) - dd_comm = MPI.COMM_WORLD.Create(dd_group) - dd_tally = np.empty(data_tally.shape[0]) # dummy tally - - if MPI.COMM_NULL != dd_comm: - sendcounts = np.array(dd_comm.gather(len(data_tally[0]), root=0)) - if mcdc["mpi_master"]: - dd_tally = np.zeros((data_tally.shape[0], sum(sendcounts))) - # gather tallies - for i, t in enumerate(data_tally): - dd_comm.Gatherv(data_tally[i], (dd_tally[i], sendcounts), root=0) - # gather tally lengths for proper recombination - xlens = dd_comm.gather(xlen, root=0) - ylens = dd_comm.gather(ylen, root=0) - zlens = dd_comm.gather(zlen, root=0) - dd_group.Free() - if MPI.COMM_NULL != dd_comm: - dd_comm.Free() - - if mcdc["mpi_master"]: - buff = np.zeros_like(dd_tally) - # reorganize tally data - # TODO: find/develop a more efficient algorithm for this - tally_idx = 0 - offset = 0 - ysum = mcdc["technique"]["dd_ysum"] - zsum = mcdc["technique"]["dd_zsum"] - for di in range(0, d_Nx * d_Ny * d_Nz): - dz = di // (d_Nx * d_Ny) - dy = (di % (d_Nx * d_Ny)) // d_Nx - dx = di % d_Nx - - offset = 0 - # calculate subdomain offset - for i in range(0, dx): - offset += xlens[i] * ysum * zsum - - for i in range(0, dy): - y_ind = i * d_Nx - offset += ylens[y_ind] * zsum - - for i in range(0, dz): - z_ind = i * d_Nx * d_Ny - offset += zlens[z_ind] - - # calculate index within subdomain - xlen = xlens[di] - ylen = ylens[di] - zlen = zlens[di] - for xi in range(0, xlen): - for yi in range(0, ylen): - for zi in range(0, zlen): - # calculate reorganized index - ind_x = xi * ysum * zsum - ind_y = yi * zsum - ind_z = zi - buff_idx = offset + ind_x + ind_y + ind_z - # place tally value in correct position - buff[:, buff_idx] = dd_tally[:, tally_idx] - tally_idx += 1 - # replace old tally with reorganized tally - dd_tally = buff - - return dd_tally - - -def dd_mergemesh(mcdc, data_tally): - """ - Performs mesh recombination on domain-decomposed mesh tallies. - Gathers and re-organizes mesh data into a single array as it - would appear in a non-decomposed simulation. - """ - d_Nx = input_deck.technique["dd_mesh"]["x"].size - 1 - d_Ny = input_deck.technique["dd_mesh"]["y"].size - 1 - d_Nz = input_deck.technique["dd_mesh"]["z"].size - 1 - # gather mesh filter - if d_Nx > 1: - sendcounts = np.array( - MPI.COMM_WORLD.gather(len(mcdc["mesh_tallies"][0]["filter"]["x"]), root=0) - ) - if mcdc["mpi_master"]: - x_filter = np.zeros((mcdc["mesh_tallies"].shape[0], sum(sendcounts))) - else: - x_filter = np.empty((mcdc["mesh_tallies"].shape[0])) # dummy tally - # gather mesh - for i in range(mcdc["mesh_tallies"].shape[0]): - MPI.COMM_WORLD.Gatherv( - sendbuf=mcdc["mesh_tallies"][i]["filter"]["x"], - recvbuf=(x_filter[i], sendcounts), - root=0, - ) - if mcdc["mpi_master"]: - x_final = np.zeros((mcdc["mesh_tallies"].shape[0], x_filter.shape[1] + 1)) - x_final[:, 0] = mcdc["mesh_tallies"][:]["filter"]["x"][0][0] - x_final[:, 1:] = x_filter - - if d_Ny > 1: - sendcounts = np.array( - MPI.COMM_WORLD.gather(len(mcdc["mesh_tallies"][0]["filter"]["y"]), root=0) - ) - if mcdc["mpi_master"]: - y_filter = np.zeros((mcdc["mesh_tallies"].shape[0], sum(sendcounts))) - else: - y_filter = np.empty((mcdc["mesh_tallies"].shape[0])) # dummy tally - # gather mesh - for i in range(mcdc["mesh_tallies"].shape[0]): - MPI.COMM_WORLD.Gatherv( - sendbuf=mcdc["mesh_tallies"][i]["filter"]["y"], - recvbuf=(y_filter[i], sendcounts), - root=0, - ) - if mcdc["mpi_master"]: - y_final = np.zeros((mcdc["mesh_tallies"].shape[0], y_filter.shape[1] + 1)) - y_final[:, 0] = mcdc["mesh_tallies"][:]["filter"]["y"][0][0] - y_final[:, 1:] = y_filter - - if d_Nz > 1: - sendcounts = np.array( - MPI.COMM_WORLD.gather( - len(mcdc["mesh_tallies"][0]["filter"]["z"]) - 1, root=0 - ) - ) - if mcdc["mpi_master"]: - z_filter = np.zeros((mcdc["mesh_tallies"].shape[0], sum(sendcounts))) - else: - z_filter = np.empty((mcdc["mesh_tallies"].shape[0])) # dummy tally - # gather mesh - for i in range(mcdc["mesh_tallies"].shape[0]): - MPI.COMM_WORLD.Gatherv( - sendbuf=mcdc["mesh_tallies"][i]["filter"]["z"][1:], - recvbuf=(z_filter[i], sendcounts), - root=0, - ) - if mcdc["mpi_master"]: - z_final = np.zeros((mcdc["mesh_tallies"].shape[0], z_filter.shape[1] + 1)) - z_final[:, 0] = mcdc["mesh_tallies"][:]["filter"]["z"][0][0] - z_final[:, 1:] = z_filter - - dd_mesh = [] - if mcdc["mpi_master"]: - if d_Nx > 1: - dd_mesh.append(x_final) - else: - dd_mesh.append(mcdc["mesh_tallies"][:]["filter"]["x"]) - if d_Ny > 1: - dd_mesh.append(y_final) - else: - dd_mesh.append(mcdc["mesh_tallies"][:]["filter"]["y"]) - if d_Nz > 1: - dd_mesh.append(z_final) - else: - dd_mesh.append(mcdc["mesh_tallies"][:]["filter"]["z"]) - return dd_mesh - - -def generate_hdf5(data_tally, mcdc): - - if mcdc["technique"]["domain_decomposition"]: - dd_tally = dd_mergetally(mcdc, data_tally) - dd_mesh = dd_mergemesh(mcdc, data_tally) - - if mcdc["mpi_master"]: - if mcdc["setting"]["progress_bar"]: - print_msg("") - print_msg(" Generating output HDF5 files...") - - with h5py.File(mcdc["setting"]["output_name"] + ".h5", "w") as f: - # Version - version = importlib.metadata.version("mcdc") - f["version"] = version - - # Input deck - if mcdc["setting"]["save_input_deck"]: - input_group = f.create_group("input_deck") - cardlist_to_h5group(input_deck.nuclides, input_group, "nuclide") - cardlist_to_h5group(input_deck.materials, input_group, "material") - cardlist_to_h5group(input_deck.surfaces, input_group, "surface") - cardlist_to_h5group(input_deck.cells, input_group, "cell") - cardlist_to_h5group(input_deck.universes, input_group, "universe") - cardlist_to_h5group(input_deck.lattices, input_group, "lattice") - cardlist_to_h5group(input_deck.sources, input_group, "source") - cardlist_to_h5group( - input_deck.mesh_tallies, input_group, "mesh_tallies" - ) - cardlist_to_h5group( - input_deck.surface_tallies, input_group, "surface_tallies" - ) - cardlist_to_h5group( - input_deck.cell_tallies, input_group, "cell_tallies" - ) - cardlist_to_h5group(input_deck.cs_tallies, input_group, "cs_tallies") - dict_to_h5group(input_deck.setting, input_group.create_group("setting")) - dict_to_h5group( - input_deck.technique, input_group.create_group("technique") - ) - - # No need to output tally if time census-based tally is used - if input_deck.setting["census_based_tally"]: - return - - # Mesh tallies - for ID, tally in enumerate(mcdc["mesh_tallies"]): - if mcdc["technique"]["iQMC"]: - break - - mesh = tally["filter"] - - # Get grid - Nx = mesh["Nx"] - Ny = mesh["Ny"] - Nz = mesh["Nz"] - Nt = mesh["Nt"] - Nmu = mesh["Nmu"] - N_azi = mesh["N_azi"] - Ng = mesh["Ng"] - # - grid_x = mesh["x"][: Nx + 1] - grid_y = mesh["y"][: Ny + 1] - grid_z = mesh["z"][: Nz + 1] - grid_t = mesh["t"][: Nt + 1] - grid_mu = mesh["mu"][: Nmu + 1] - grid_azi = mesh["azi"][: N_azi + 1] - grid_g = mesh["g"][: Ng + 1] - # Domain decomposed? - if mcdc["technique"]["domain_decomposition"]: - grid_x = dd_mesh[0][ID] - grid_y = dd_mesh[1][ID] - grid_z = dd_mesh[2][ID] - - # Save to dataset - f.create_dataset("tallies/mesh_tally_%i/grid/x" % ID, data=grid_x) - f.create_dataset("tallies/mesh_tally_%i/grid/y" % ID, data=grid_y) - f.create_dataset("tallies/mesh_tally_%i/grid/z" % ID, data=grid_z) - f.create_dataset("tallies/mesh_tally_%i/grid/t" % ID, data=grid_t) - f.create_dataset("tallies/mesh_tally_%i/grid/mu" % ID, data=grid_mu) - f.create_dataset("tallies/mesh_tally_%i/grid/azi" % ID, data=grid_azi) - f.create_dataset("tallies/mesh_tally_%i/grid/g" % ID, data=grid_g) - - # Set tally shape - N_score = tally["N_score"] - if mcdc["technique"]["domain_decomposition"]: - Nx = mcdc["technique"]["dd_xsum"] - Ny = mcdc["technique"]["dd_ysum"] - Nz = mcdc["technique"]["dd_zsum"] - if not mcdc["technique"]["uq"]: - shape = (3, Nmu, N_azi, Ng, Nt, Nx, Ny, Nz, N_score) - else: - shape = (5, Nmu, N_azi, Ng, Nt, Nx, Ny, Nz, N_score) - - # Reshape tally - N_bin = tally["N_bin"] - if mcdc["technique"]["domain_decomposition"]: - # use recomposed N_bin - N_bin = 1 - for elem in shape: - N_bin *= elem - start = tally["stride"]["tally"] - tally_bin = data_tally[:, start : start + N_bin] - if mcdc["technique"]["domain_decomposition"]: - # substitute recomposed tally - tally_bin = dd_tally[:, start : start + N_bin] - tally_bin = tally_bin.reshape(shape) - - # Roll tally so that score is in the front - tally_bin = np.rollaxis(tally_bin, 8, 0) - - # Iterate over scores - for i in range(N_score): - score_type = tally["scores"][i] - score_tally_bin = np.squeeze(tally_bin[i]) - if score_type == SCORE_FLUX: - score_name = "flux" - elif score_type == SCORE_DENSITY: - score_name = "density" - elif score_type == SCORE_TOTAL: - score_name = "total" - elif score_type == SCORE_FISSION: - score_name = "fission" - elif score_type == SCORE_NET_CURRENT: - score_name = "current" - elif score_type == SCORE_MU_SQ: - score_name = "mu-sq" - elif score_type == SCORE_TIME_MOMENT_FLUX: - score_name = "time-moment-flux" - elif score_type == SCORE_SPACE_MOMENT_FLUX: - score_name = "space-moment-flux" - elif score_type == SCORE_TIME_MOMENT_CURRENT: - score_name = "time-moment-current" - elif score_type == SCORE_SPACE_MOMENT_CURRENT: - score_name = "space-moment-current" - elif score_type == SCORE_TIME_MOMENT_MU_SQ: - score_name = "time-moment-mu-sq" - elif score_type == SCORE_SPACE_MOMENT_MU_SQ: - score_name = "space-moment-mu-sq" - group_name = "tallies/mesh_tally_%i/%s/" % (ID, score_name) - - mean = score_tally_bin[TALLY_SUM] - sdev = score_tally_bin[TALLY_SUM_SQ] - - f.create_dataset(group_name + "mean", data=mean) - f.create_dataset(group_name + "sdev", data=sdev) - if mcdc["technique"]["uq"]: - mc_var = score_tally_bin[TALLY_UQ_BATCH_VAR] - tot_var = score_tally_bin[TALLY_UQ_BATCH] - uq_var = tot_var - mc_var - f.create_dataset(group_name + "uq_var", data=uq_var) - - # Surface tallies - for ID, tally in enumerate(mcdc["surface_tallies"]): - if mcdc["technique"]["iQMC"]: - break - - # Shape - N_score = tally["N_score"] - - if not mcdc["technique"]["uq"]: - shape = (3, N_score) - else: - shape = (5, N_score) - - # Reshape tally - N_bin = tally["N_bin"] - start = tally["stride"]["tally"] - tally_bin = data_tally[:, start : start + N_bin] - tally_bin = tally_bin.reshape(shape) - - # Roll tally so that score is in the front - tally_bin = np.rollaxis(tally_bin, 1, 0) - - # Iterate over scores - for i in range(N_score): - score_type = tally["scores"][i] - score_tally_bin = np.squeeze(tally_bin[i]) - score_name = "net-current" - group_name = "tallies/surface_tally_%i/%s/" % (ID, score_name) - - mean = score_tally_bin[TALLY_SUM] - sdev = score_tally_bin[TALLY_SUM_SQ] - - f.create_dataset(group_name + "mean", data=mean) - f.create_dataset(group_name + "sdev", data=sdev) - if mcdc["technique"]["uq"]: - mc_var = score_tally_bin[TALLY_UQ_BATCH_VAR] - tot_var = score_tally_bin[TALLY_UQ_BATCH] - uq_var = tot_var - mc_var - f.create_dataset(group_name + "uq_var", data=uq_var) - - # Cell tallies - for ID, tally in enumerate(mcdc["cell_tallies"]): - if mcdc["technique"]["iQMC"]: - break - - mesh = tally["filter"] - - # Get grid - Nt = mesh["Nt"] - Ng = mesh["Ng"] - # - grid_t = mesh["t"][: Nt + 1] - grid_g = mesh["g"][: Ng + 1] - - # Save to dataset - f.create_dataset("tallies/cell_tally_%i/grid/t" % ID, data=grid_t) - f.create_dataset("tallies/cell_tally_%i/grid/g" % ID, data=grid_g) - - # Shape - N_score = tally["N_score"] - - if not mcdc["technique"]["uq"]: - shape = (3, Ng, Nt, N_score) - else: - shape = (5, Ng, Nt, N_score) - - # Reshape tally - N_bin = tally["N_bin"] - start = tally["stride"]["tally"] - tally_bin = data_tally[:, start : start + N_bin] - tally_bin = tally_bin.reshape(shape) - - # Roll tally so that score is in the front - tally_bin = np.rollaxis(tally_bin, 3, 0) - - # Iterate over scores - for i in range(N_score): - score_type = tally["scores"][i] - score_tally_bin = np.squeeze(tally_bin[i]) - if score_type == SCORE_FLUX: - score_name = "flux" - elif score_type == SCORE_NET_CURRENT: - score_name = "net-current" - elif score_type == SCORE_FISSION: - score_name = "fission" - group_name = "tallies/cell_tally_%i/%s/" % (ID, score_name) - - mean = score_tally_bin[TALLY_SUM] - sdev = score_tally_bin[TALLY_SUM_SQ] - - f.create_dataset(group_name + "mean", data=mean) - f.create_dataset(group_name + "sdev", data=sdev) - if mcdc["technique"]["uq"]: - mc_var = score_tally_bin[TALLY_UQ_BATCH_VAR] - tot_var = score_tally_bin[TALLY_UQ_BATCH] - uq_var = tot_var - mc_var - f.create_dataset(group_name + "uq_var", data=uq_var) - - # CS tallies - for ID, tally in enumerate(mcdc["cs_tallies"]): - if mcdc["technique"]["iQMC"]: - break - N_cs_bins = tally["filter"]["N_cs_bins"] - - # Shape - N_score = tally["N_score"] - - if not mcdc["technique"]["uq"]: - shape = (3, N_cs_bins, N_score) - else: - shape = (5, N_cs_bins, N_score) - - # Reshape tally - start = tally["stride"]["tally"] - tally_bin = data_tally[:, start : start + N_cs_bins] - tally_bin = tally_bin.reshape(shape) - - # Roll tally so that score is in the front - tally_bin = np.rollaxis(tally_bin, 2, 0) - - # Iterate over scores - for i in range(N_score): - score_type = tally["scores"][i] - score_tally_bin = np.squeeze(tally_bin[i]) - if score_type == SCORE_FLUX: - score_name = "flux" - elif score_type == SCORE_NET_CURRENT: - score_name = "net-current" - elif score_type == SCORE_FISSION: - score_name = "fission" - group_name = "tallies/cs_tally_%i/%s/" % (ID, score_name) - - center_points = tally["filter"]["cs_centers"] - S = tally["filter"]["cs_S"] - reconstruction = tally["filter"]["cs_reconstruction"] - - f.create_dataset( - "tallies/cs_tally_%i/center_points" % (ID), data=center_points - ) - f.create_dataset("tallies/cs_tally_%i/S" % (ID), data=S) - f.create_dataset(group_name + "reconstruction", data=reconstruction) - - mean = score_tally_bin[TALLY_SUM] - sdev = score_tally_bin[TALLY_SUM_SQ] - - f.create_dataset(group_name + "mean", data=mean) - f.create_dataset(group_name + "sdev", data=sdev) - if mcdc["technique"]["uq"]: - mc_var = score_tally_bin[TALLY_UQ_BATCH_VAR] - tot_var = score_tally_bin[TALLY_UQ_BATCH] - uq_var = tot_var - mc_var - f.create_dataset(group_name + "uq_var", data=uq_var) - - # Eigenvalues - if mcdc["setting"]["mode_eigenvalue"]: - if mcdc["technique"]["iQMC"]: - f.create_dataset("k_eff", data=mcdc["k_eff"]) - if mcdc["technique"]["iqmc"]["mode"] == "batched": - N_cycle = mcdc["setting"]["N_cycle"] - f.create_dataset("k_cycle", data=mcdc["k_cycle"][:N_cycle]) - f.create_dataset("k_mean", data=mcdc["k_avg_running"]) - f.create_dataset("k_sdev", data=mcdc["k_sdv_running"]) - else: - N_cycle = mcdc["setting"]["N_cycle"] - f.create_dataset("k_cycle", data=mcdc["k_cycle"][:N_cycle]) - f.create_dataset("k_mean", data=mcdc["k_avg_running"]) - f.create_dataset("k_sdev", data=mcdc["k_sdv_running"]) - f.create_dataset("global_tally/neutron/mean", data=mcdc["n_avg"]) - f.create_dataset("global_tally/neutron/sdev", data=mcdc["n_sdv"]) - f.create_dataset("global_tally/neutron/max", data=mcdc["n_max"]) - f.create_dataset("global_tally/precursor/mean", data=mcdc["C_avg"]) - f.create_dataset("global_tally/precursor/sdev", data=mcdc["C_sdv"]) - f.create_dataset("global_tally/precursor/max", data=mcdc["C_max"]) - if mcdc["setting"]["gyration_radius"]: - f.create_dataset( - "gyration_radius", data=mcdc["gyration_radius"][:N_cycle] - ) - - # iQMC - if mcdc["technique"]["iQMC"]: - # iQMC mesh - T = mcdc["technique"] - f.create_dataset("iqmc/grid/t", data=T["iqmc"]["mesh"]["t"]) - f.create_dataset("iqmc/grid/x", data=T["iqmc"]["mesh"]["x"]) - f.create_dataset("iqmc/grid/y", data=T["iqmc"]["mesh"]["y"]) - f.create_dataset("iqmc/grid/z", data=T["iqmc"]["mesh"]["z"]) - # Scores - for name in [ - "flux", - "source-x", - "source-y", - "source-z", - "fission-power", - ]: - if T["iqmc"]["score_list"][name]: - name_h5 = name.replace("-", "_") - f.create_dataset( - f"iqmc/tally/{name_h5}/mean", - data=np.squeeze(T["iqmc"]["score"][name]["mean"]), - ) - f.create_dataset( - f"iqmc/tally/{name_h5}/sdev", - data=np.squeeze(T["iqmc"]["score"][name]["sdev"]), - ) - # iQMC source strength - f.create_dataset( - "iqmc/tally/source_constant/mean", - data=np.squeeze(T["iqmc"]["source"]), - ) - # Iteration data - f.create_dataset( - "iqmc/iteration_count", data=T["iqmc"]["iteration_count"] - ) - f.create_dataset("iqmc/sweep_count", data=T["iqmc"]["sweep_count"]) - f.create_dataset("iqmc/final_residual", data=T["iqmc"]["residual"]) - - # IC generator - if mcdc["technique"]["IC_generator"]: - Nn = mcdc["technique"]["IC_bank_neutron"]["size"][0] - Np = mcdc["technique"]["IC_bank_precursor"]["size"][0] - f.create_dataset( - "IC/neutrons", - data=mcdc["technique"]["IC_bank_neutron"]["particles"][:Nn], - ) - f.create_dataset( - "IC/precursors", - data=mcdc["technique"]["IC_bank_precursor"]["precursors"][:Np], - ) - f.create_dataset("IC/neutrons_size", data=Nn) - f.create_dataset("IC/precursors_size", data=Np) - f.create_dataset( - "IC/fission", data=mcdc["technique"]["IC_fission"] / Nn - ) - - # Save particle? - if mcdc["setting"]["save_particle"]: - # Gather source bank - # TODO: Parallel HDF5 and mitigation of large data passing - N = mcdc["bank_source"]["size"][0] - neutrons = MPI.COMM_WORLD.gather(mcdc["bank_source"]["particles"][:N]) - - # Master saves the particle - if mcdc["mpi_master"]: - # Remove unwanted particle fields - neutrons = np.concatenate(neutrons[:]) - - # Create dataset - with h5py.File(mcdc["setting"]["output_name"] + ".h5", "a") as f: - f.create_dataset("particles", data=neutrons[:]) - f.create_dataset("particles_size", data=len(neutrons[:])) - - -def replace_dataset(file_, field, data): - if field in file_: - del file_[field] - file_.create_dataset(field, data=data) - - -def recombine_tallies(file="output.h5"): - if MPI.COMM_WORLD.Get_rank() == 0: - # Load main output file and read input params - with h5py.File(file, "r") as f: - output_name = str(f["input_deck/setting/output_name"][()])[2:-1] - N_particle = f["input_deck/setting/N_particle"][()] - N_census = f["input_deck/setting/N_census"][()] - 1 - N_batch = f["input_deck/setting/N_batch"][()] - N_frequency = f["input_deck/setting/census_tally_frequency"][()] - Nt = N_census * N_frequency - # Combine the tally output into a single file - - collected_tallies = [] - collected_tally_names = [] - # Collecting info on number and types of tallies - for i_census in range(N_census): - for i_batch in range(N_batch): - with h5py.File( - output_name + "-batch_%i-census_%i.h5" % (i_batch, i_census), "r" - ) as f: - tallies = f["tallies"] - for tally in tallies: - if tally not in collected_tally_names: - grid = tallies[tally]["grid"] - tally_list = [tally] - for tally_type in tallies[tally]: - if tally_type != "grid": - tally_list.append(tally_type) - collected_tallies.append(tally_list) - collected_tally_names.append(tally) - - for i, tally_info in enumerate(collected_tallies): - print(tally_info) - tally_type = tally_info[0].split("_")[0] - tally_number = tally_info[0].split("_")[-1] - with h5py.File(output_name + ".h5", "a") as f: - grid = f[ - "input_deck/" - + tally_type - + "_tallies/" - + tally_type - + "_tallies_" - + tally_number - ] - t_final = f["input_deck/setting/census_time"][()][-2] - t = np.linspace(0, t_final, N_census * N_frequency + 1) - Nx = len(grid["x"][()]) - 1 - Ny = len(grid["y"][()]) - 1 - Nz = len(grid["z"][()]) - 1 - Nmu = len(grid["mu"][()]) - 1 - N_azi = len(grid["azi"][()]) - 1 - Ng = len(grid["g"][()]) - 1 - - # Creating structure of correct size to hold combined tally - for tally_type in tally_info[1:]: - print(" ", tally_type) - tally_score = np.zeros((Nt, Nmu, N_azi, Ng, Nx, Ny, Nz)) - print(" ", tally_score.shape) - tally_score = np.squeeze(tally_score) - tally_score_sq = np.zeros_like(tally_score) - - # Number of shift of time index - N_shift = 0 - if Nmu > 1: - N_shift += 1 - if N_azi > 1: - N_shift += 1 - if Ng > 1: - N_shift += 1 - - for i_census in range(N_census): - print(" ", i_census) - idx_start = i_census * N_frequency - idx_end = idx_start + N_frequency - for i_batch in range(N_batch): - with h5py.File( - output_name - + "-batch_%i-census_%i.h5" % (i_batch, i_census), - "r", - ) as f1: - score = f1[ - "tallies/" - + tally_info[0] - + "/" - + tally_type - + "/score" - ][:] - if N_shift > 0: - score = np.rollaxis(score, N_shift, 0) - tally_score[idx_start:idx_end] += score - tally_score_sq[idx_start:idx_end] += score * score - tally_score /= N_batch - if N_batch > 0: - tally_score_sq = np.sqrt( - (tally_score_sq / N_batch - np.square(tally_score)) - / (N_batch - 1) - ) - - field_base = "tallies/" + tally_info[0] + "/" + tally_type - replace_dataset(f, field_base + "/mean", tally_score) - replace_dataset(f, field_base + "/sdev", tally_score_sq) - - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/x", grid["x"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/y", grid["y"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/z", grid["z"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/t", grid["t"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/mu", grid["mu"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/azi", grid["azi"][()] - ) - replace_dataset( - f, "tallies/" + tally_info[0] + "/grid/g", grid["g"][()] - ) - """ - for i_census in range(N_census): - for i_batch in range(N_batch): - file_name = ( - output_name - + "-batch_" - + str(i_batch) - + "-census_" - + str(i_census) - + ".h5" - ) - os.system("rm " + file_name) - """ - - -def closeout(mcdc): - - loop.teardown_gpu(mcdc) - - # Runtime - if mcdc["mpi_master"]: - with h5py.File(mcdc["setting"]["output_name"] + ".h5", "a") as f: - for name in [ - "total", - "preparation", - "simulation", - "output", - "bank_management", - ]: - f.create_dataset( - "runtime/" + name, data=np.array([mcdc["runtime_" + name]]) - ) - - if config.args.runtime_output: - with h5py.File(mcdc["setting"]["output_name"] + "-runtime.h5", "w") as f: - for name in [ - "total", - "preparation", - "simulation", - "output", - "bank_management", - ]: - f.create_dataset(name, data=np.array([mcdc["runtime_" + name]])) - - print_runtime(mcdc) - input_deck.reset() + return mcdc_arr, data # ====================================================================================== @@ -2430,7 +328,7 @@ def visualize( z=0.0, pixels=(100, 100), colors=None, - time=np.array([0.0]), + time=[0.0], save_as=None, ): """ @@ -2453,11 +351,20 @@ def visualize( colors : array_like List of pairs of material and its color """ - # TODO: add input error checkers + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib import colors as mpl_colors + + #### - _, mcdc_container = prepare() + from mcdc.transport.distribution import sample_isotropic_direction + + mcdc_container, data = preparation() mcdc = mcdc_container[0] + import mcdc.object_.numba_types as type_ + # Color assignment for materials (by material ID) if colors is not None: new_colors = {} @@ -2512,7 +419,9 @@ def visualize( second_midpoint = 0.5 * (second_grid[1:] + second_grid[:-1]) # Set dummy particle - particle_container = adapt.local_array(1, type_.particle) + import mcdc.code_factory.adapt as adapt + + particle_container = np.zeros(1, type_.particle) particle = particle_container[0] particle[reference_key] = reference particle["g"] = 0 @@ -2523,12 +432,14 @@ def visualize( particle["t"] = t # Random direction - particle["ux"], particle["uy"], particle["uz"] = ( - kernel.sample_isotropic_direction(particle_container) + particle["ux"], particle["uy"], particle["uz"] = sample_isotropic_direction( + particle_container ) # RGB color data for each pixels - data = np.zeros(pixels + (3,)) + pixel_data = np.zeros(pixels + (3,)) + + import mcdc.transport.geometry as geometry # Loop over the two axes for i in range(pixels[0]): @@ -2539,18 +450,21 @@ def visualize( # Get material particle["cell_ID"] = -1 particle["material_ID"] = -1 - if geometry.locate_particle(particle_container, mcdc): - data[i, j] = colors[particle["material_ID"]] + if geometry.locate_particle(particle_container, mcdc, data): + pixel_data[i, j] = colors[particle["material_ID"]] else: - data[i, j] = WHITE + pixel_data[i, j] = WHITE - data = np.transpose(data, (1, 0, 2)) - plt.imshow(data, origin="lower", extent=first + second) + pixel_data = np.transpose(pixel_data, (1, 0, 2)) + plt.imshow(pixel_data, origin="lower", extent=first + second) plt.xlabel(first_key + " [cm]") plt.ylabel(second_key + " [cm]") plt.title(reference_key + " = %.2f cm" % reference + ", time = %.2f s" % t) if save_as is not None: - plt.savefig(save_as + "_%.2f.png" % t) + if len(time) > 1: + plt.savefig(f"{save_as}_{t:03}.png") + else: + plt.savefig(save_as + ".png") plt.clf() else: plt.show() diff --git a/mcdc/mcdc_get/__init__.py b/mcdc/mcdc_get/__init__.py new file mode 100644 index 000000000..31cde0a60 --- /dev/null +++ b/mcdc/mcdc_get/__init__.py @@ -0,0 +1,103 @@ +# The following is automatically generated by code_factory.py + +import mcdc.mcdc_get.particle_data as particle_data + +import mcdc.mcdc_get.particle as particle + +import mcdc.mcdc_get.cell as cell + +import mcdc.mcdc_get.lattice as lattice + +import mcdc.mcdc_get.material as material + +import mcdc.mcdc_get.cell_tally as cell_tally + +import mcdc.mcdc_get.universe as universe + +import mcdc.mcdc_get.data as data + +import mcdc.mcdc_get.none_data as none_data + +import mcdc.mcdc_get.polynomial_data as polynomial_data + +import mcdc.mcdc_get.table_data as table_data + +import mcdc.mcdc_get.distribution as distribution + +import mcdc.mcdc_get.evaporation_distribution as evaporation_distribution + +import mcdc.mcdc_get.kalbach_mann_distribution as kalbach_mann_distribution + +import mcdc.mcdc_get.level_scattering_distribution as level_scattering_distribution + +import mcdc.mcdc_get.maxwellian_distribution as maxwellian_distribution + +import mcdc.mcdc_get.multi_table_distribution as multi_table_distribution + +import mcdc.mcdc_get.nbody_distribution as nbody_distribution + +import mcdc.mcdc_get.none_distribution as none_distribution + +import mcdc.mcdc_get.pmf_distribution as pmf_distribution + +import mcdc.mcdc_get.tabulated_distribution as tabulated_distribution + +import mcdc.mcdc_get.tabulated_energy_angle_distribution as tabulated_energy_angle_distribution + +import mcdc.mcdc_get.gpu_meta as gpu_meta + +import mcdc.mcdc_get.native_material as native_material + +import mcdc.mcdc_get.multigroup_material as multigroup_material + +import mcdc.mcdc_get.nuclide as nuclide + +import mcdc.mcdc_get.mesh as mesh + +import mcdc.mcdc_get.structured_mesh as structured_mesh + +import mcdc.mcdc_get.uniform_mesh as uniform_mesh + +import mcdc.mcdc_get.neutron_capture_reaction as neutron_capture_reaction + +import mcdc.mcdc_get.neutron_elastic_scattering_reaction as neutron_elastic_scattering_reaction + +import mcdc.mcdc_get.neutron_fission_reaction as neutron_fission_reaction + +import mcdc.mcdc_get.neutron_inelastic_scattering_reaction as neutron_inelastic_scattering_reaction + +import mcdc.mcdc_get.particle_bank as particle_bank + +import mcdc.mcdc_get.reaction as reaction + +import mcdc.mcdc_get.settings as settings + +import mcdc.mcdc_get.implicit_capture as implicit_capture + +import mcdc.mcdc_get.population_control as population_control + +import mcdc.mcdc_get.weight_roulette as weight_roulette + +import mcdc.mcdc_get.weighted_emission as weighted_emission + +import mcdc.mcdc_get.source as source + +import mcdc.mcdc_get.surface as surface + +import mcdc.mcdc_get.surface_tally as surface_tally + +import mcdc.mcdc_get.tally as tally + +import mcdc.mcdc_get.global_tally as global_tally + +import mcdc.mcdc_get.mesh_tally as mesh_tally + +import mcdc.mcdc_get.bank_active as bank_active + +import mcdc.mcdc_get.bank_census as bank_census + +import mcdc.mcdc_get.bank_source as bank_source + +import mcdc.mcdc_get.bank_future as bank_future + +import mcdc.mcdc_get.simulation as simulation diff --git a/mcdc/mcdc_get/bank_active.py b/mcdc/mcdc_get/bank_active.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/bank_active.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/bank_census.py b/mcdc/mcdc_get/bank_census.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/bank_census.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/bank_future.py b/mcdc/mcdc_get/bank_future.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/bank_future.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/bank_source.py b/mcdc/mcdc_get/bank_source.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/bank_source.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/cell.py b/mcdc/mcdc_get/cell.py new file mode 100644 index 000000000..1aaa320fd --- /dev/null +++ b/mcdc/mcdc_get/cell.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def region_RPN_tokens(index, cell, data): + offset = cell["region_RPN_tokens_offset"] + return data[offset + index] + + +@njit +def region_RPN_tokens_all(cell, data): + start = cell["region_RPN_tokens_offset"] + size = cell["region_RPN_tokens_length"] + end = start + size + return data[start:end] + + +@njit +def region_RPN_tokens_last(cell, data): + start = cell["region_RPN_tokens_offset"] + size = cell["region_RPN_tokens_length"] + end = start + size + return data[end - 1] + + +@njit +def region_RPN_tokens_chunk(start, length, cell, data): + start += cell["region_RPN_tokens_offset"] + end = start + length + return data[start:end] + + +@njit +def surface_IDs(index, cell, data): + offset = cell["surface_IDs_offset"] + return data[offset + index] + + +@njit +def surface_IDs_all(cell, data): + start = cell["surface_IDs_offset"] + size = cell["N_surface"] + end = start + size + return data[start:end] + + +@njit +def surface_IDs_last(cell, data): + start = cell["surface_IDs_offset"] + size = cell["N_surface"] + end = start + size + return data[end - 1] + + +@njit +def surface_IDs_chunk(start, length, cell, data): + start += cell["surface_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def tally_IDs(index, cell, data): + offset = cell["tally_IDs_offset"] + return data[offset + index] + + +@njit +def tally_IDs_all(cell, data): + start = cell["tally_IDs_offset"] + size = cell["N_tally"] + end = start + size + return data[start:end] + + +@njit +def tally_IDs_last(cell, data): + start = cell["tally_IDs_offset"] + size = cell["N_tally"] + end = start + size + return data[end - 1] + + +@njit +def tally_IDs_chunk(start, length, cell, data): + start += cell["tally_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/cell_tally.py b/mcdc/mcdc_get/cell_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/cell_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/data.py b/mcdc/mcdc_get/data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/distribution.py b/mcdc/mcdc_get/distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/evaporation_distribution.py b/mcdc/mcdc_get/evaporation_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/evaporation_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/global_tally.py b/mcdc/mcdc_get/global_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/global_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/gpu_meta.py b/mcdc/mcdc_get/gpu_meta.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/gpu_meta.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/implicit_capture.py b/mcdc/mcdc_get/implicit_capture.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/implicit_capture.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/kalbach_mann_distribution.py b/mcdc/mcdc_get/kalbach_mann_distribution.py new file mode 100644 index 000000000..456942a01 --- /dev/null +++ b/mcdc/mcdc_get/kalbach_mann_distribution.py @@ -0,0 +1,206 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def energy(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["energy_offset"] + return data[offset + index] + + +@njit +def energy_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["energy_offset"] + size = kalbach_mann_distribution["energy_length"] + end = start + size + return data[start:end] + + +@njit +def energy_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["energy_offset"] + size = kalbach_mann_distribution["energy_length"] + end = start + size + return data[end - 1] + + +@njit +def energy_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["energy_offset"] + end = start + length + return data[start:end] + + +@njit +def offset(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["offset_offset"] + return data[offset + index] + + +@njit +def offset_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["offset_offset"] + size = kalbach_mann_distribution["offset_length"] + end = start + size + return data[start:end] + + +@njit +def offset_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["offset_offset"] + size = kalbach_mann_distribution["offset_length"] + end = start + size + return data[end - 1] + + +@njit +def offset_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["offset_offset"] + end = start + length + return data[start:end] + + +@njit +def energy_out(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["energy_out_offset"] + return data[offset + index] + + +@njit +def energy_out_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["energy_out_offset"] + size = kalbach_mann_distribution["energy_out_length"] + end = start + size + return data[start:end] + + +@njit +def energy_out_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["energy_out_offset"] + size = kalbach_mann_distribution["energy_out_length"] + end = start + size + return data[end - 1] + + +@njit +def energy_out_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["energy_out_offset"] + end = start + length + return data[start:end] + + +@njit +def pdf(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["pdf_offset"] + return data[offset + index] + + +@njit +def pdf_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["pdf_offset"] + size = kalbach_mann_distribution["pdf_length"] + end = start + size + return data[start:end] + + +@njit +def pdf_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["pdf_offset"] + size = kalbach_mann_distribution["pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def pdf_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cdf(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["cdf_offset"] + return data[offset + index] + + +@njit +def cdf_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["cdf_offset"] + size = kalbach_mann_distribution["cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cdf_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["cdf_offset"] + size = kalbach_mann_distribution["cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cdf_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["cdf_offset"] + end = start + length + return data[start:end] + + +@njit +def precompound_factor(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["precompound_factor_offset"] + return data[offset + index] + + +@njit +def precompound_factor_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["precompound_factor_offset"] + size = kalbach_mann_distribution["precompound_factor_length"] + end = start + size + return data[start:end] + + +@njit +def precompound_factor_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["precompound_factor_offset"] + size = kalbach_mann_distribution["precompound_factor_length"] + end = start + size + return data[end - 1] + + +@njit +def precompound_factor_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["precompound_factor_offset"] + end = start + length + return data[start:end] + + +@njit +def angular_slope(index, kalbach_mann_distribution, data): + offset = kalbach_mann_distribution["angular_slope_offset"] + return data[offset + index] + + +@njit +def angular_slope_all(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["angular_slope_offset"] + size = kalbach_mann_distribution["angular_slope_length"] + end = start + size + return data[start:end] + + +@njit +def angular_slope_last(kalbach_mann_distribution, data): + start = kalbach_mann_distribution["angular_slope_offset"] + size = kalbach_mann_distribution["angular_slope_length"] + end = start + size + return data[end - 1] + + +@njit +def angular_slope_chunk(start, length, kalbach_mann_distribution, data): + start += kalbach_mann_distribution["angular_slope_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/lattice.py b/mcdc/mcdc_get/lattice.py new file mode 100644 index 000000000..437f5be40 --- /dev/null +++ b/mcdc/mcdc_get/lattice.py @@ -0,0 +1,18 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def universe_IDs(index_1, index_2, index_3, lattice, data): + offset = lattice["universe_IDs_offset"] + stride_2 = lattice["Ny"] + stride_3 = lattice["Nz"] + return data[offset + index_1 * stride_2 * stride_3 + index_2 * stride_3 + index_3] + + +@njit +def universe_IDs_chunk(start, length, lattice, data): + start += lattice["universe_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/level_scattering_distribution.py b/mcdc/mcdc_get/level_scattering_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/level_scattering_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/material.py b/mcdc/mcdc_get/material.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/material.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/maxwellian_distribution.py b/mcdc/mcdc_get/maxwellian_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/maxwellian_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/mesh.py b/mcdc/mcdc_get/mesh.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/mesh.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/mesh_tally.py b/mcdc/mcdc_get/mesh_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/mesh_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/multi_table_distribution.py b/mcdc/mcdc_get/multi_table_distribution.py new file mode 100644 index 000000000..adc740bdc --- /dev/null +++ b/mcdc/mcdc_get/multi_table_distribution.py @@ -0,0 +1,148 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def grid(index, multi_table_distribution, data): + offset = multi_table_distribution["grid_offset"] + return data[offset + index] + + +@njit +def grid_all(multi_table_distribution, data): + start = multi_table_distribution["grid_offset"] + size = multi_table_distribution["grid_length"] + end = start + size + return data[start:end] + + +@njit +def grid_last(multi_table_distribution, data): + start = multi_table_distribution["grid_offset"] + size = multi_table_distribution["grid_length"] + end = start + size + return data[end - 1] + + +@njit +def grid_chunk(start, length, multi_table_distribution, data): + start += multi_table_distribution["grid_offset"] + end = start + length + return data[start:end] + + +@njit +def offset(index, multi_table_distribution, data): + offset = multi_table_distribution["offset_offset"] + return data[offset + index] + + +@njit +def offset_all(multi_table_distribution, data): + start = multi_table_distribution["offset_offset"] + size = multi_table_distribution["offset_length"] + end = start + size + return data[start:end] + + +@njit +def offset_last(multi_table_distribution, data): + start = multi_table_distribution["offset_offset"] + size = multi_table_distribution["offset_length"] + end = start + size + return data[end - 1] + + +@njit +def offset_chunk(start, length, multi_table_distribution, data): + start += multi_table_distribution["offset_offset"] + end = start + length + return data[start:end] + + +@njit +def value(index, multi_table_distribution, data): + offset = multi_table_distribution["value_offset"] + return data[offset + index] + + +@njit +def value_all(multi_table_distribution, data): + start = multi_table_distribution["value_offset"] + size = multi_table_distribution["value_length"] + end = start + size + return data[start:end] + + +@njit +def value_last(multi_table_distribution, data): + start = multi_table_distribution["value_offset"] + size = multi_table_distribution["value_length"] + end = start + size + return data[end - 1] + + +@njit +def value_chunk(start, length, multi_table_distribution, data): + start += multi_table_distribution["value_offset"] + end = start + length + return data[start:end] + + +@njit +def pdf(index, multi_table_distribution, data): + offset = multi_table_distribution["pdf_offset"] + return data[offset + index] + + +@njit +def pdf_all(multi_table_distribution, data): + start = multi_table_distribution["pdf_offset"] + size = multi_table_distribution["pdf_length"] + end = start + size + return data[start:end] + + +@njit +def pdf_last(multi_table_distribution, data): + start = multi_table_distribution["pdf_offset"] + size = multi_table_distribution["pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def pdf_chunk(start, length, multi_table_distribution, data): + start += multi_table_distribution["pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cdf(index, multi_table_distribution, data): + offset = multi_table_distribution["cdf_offset"] + return data[offset + index] + + +@njit +def cdf_all(multi_table_distribution, data): + start = multi_table_distribution["cdf_offset"] + size = multi_table_distribution["cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cdf_last(multi_table_distribution, data): + start = multi_table_distribution["cdf_offset"] + size = multi_table_distribution["cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cdf_chunk(start, length, multi_table_distribution, data): + start += multi_table_distribution["cdf_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/multigroup_material.py b/mcdc/mcdc_get/multigroup_material.py new file mode 100644 index 000000000..12f63912c --- /dev/null +++ b/mcdc/mcdc_get/multigroup_material.py @@ -0,0 +1,385 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def mgxs_speed(index, multigroup_material, data): + offset = multigroup_material["mgxs_speed_offset"] + return data[offset + index] + + +@njit +def mgxs_speed_all(multigroup_material, data): + start = multigroup_material["mgxs_speed_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_speed_last(multigroup_material, data): + start = multigroup_material["mgxs_speed_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_speed_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_speed_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_decay_rate(index, multigroup_material, data): + offset = multigroup_material["mgxs_decay_rate_offset"] + return data[offset + index] + + +@njit +def mgxs_decay_rate_all(multigroup_material, data): + start = multigroup_material["mgxs_decay_rate_offset"] + size = multigroup_material["J"] + end = start + size + return data[start:end] + + +@njit +def mgxs_decay_rate_last(multigroup_material, data): + start = multigroup_material["mgxs_decay_rate_offset"] + size = multigroup_material["J"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_decay_rate_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_decay_rate_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_capture(index, multigroup_material, data): + offset = multigroup_material["mgxs_capture_offset"] + return data[offset + index] + + +@njit +def mgxs_capture_all(multigroup_material, data): + start = multigroup_material["mgxs_capture_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_capture_last(multigroup_material, data): + start = multigroup_material["mgxs_capture_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_capture_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_capture_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_scatter(index, multigroup_material, data): + offset = multigroup_material["mgxs_scatter_offset"] + return data[offset + index] + + +@njit +def mgxs_scatter_all(multigroup_material, data): + start = multigroup_material["mgxs_scatter_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_scatter_last(multigroup_material, data): + start = multigroup_material["mgxs_scatter_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_scatter_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_scatter_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_fission(index, multigroup_material, data): + offset = multigroup_material["mgxs_fission_offset"] + return data[offset + index] + + +@njit +def mgxs_fission_all(multigroup_material, data): + start = multigroup_material["mgxs_fission_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_fission_last(multigroup_material, data): + start = multigroup_material["mgxs_fission_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_fission_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_fission_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_total(index, multigroup_material, data): + offset = multigroup_material["mgxs_total_offset"] + return data[offset + index] + + +@njit +def mgxs_total_all(multigroup_material, data): + start = multigroup_material["mgxs_total_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_total_last(multigroup_material, data): + start = multigroup_material["mgxs_total_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_total_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_total_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_nu_s(index, multigroup_material, data): + offset = multigroup_material["mgxs_nu_s_offset"] + return data[offset + index] + + +@njit +def mgxs_nu_s_all(multigroup_material, data): + start = multigroup_material["mgxs_nu_s_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_nu_s_last(multigroup_material, data): + start = multigroup_material["mgxs_nu_s_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_nu_s_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_nu_s_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_nu_p(index, multigroup_material, data): + offset = multigroup_material["mgxs_nu_p_offset"] + return data[offset + index] + + +@njit +def mgxs_nu_p_all(multigroup_material, data): + start = multigroup_material["mgxs_nu_p_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_nu_p_last(multigroup_material, data): + start = multigroup_material["mgxs_nu_p_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_nu_p_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_nu_p_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_nu_d_vector(index_1, multigroup_material, data): + offset = multigroup_material["mgxs_nu_d_offset"] + stride = multigroup_material["J"] + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def mgxs_nu_d(index_1, index_2, multigroup_material, data): + offset = multigroup_material["mgxs_nu_d_offset"] + stride = multigroup_material["J"] + return data[offset + index_1 * stride + index_2] + + +@njit +def mgxs_nu_d_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_nu_d_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_nu_d_total(index, multigroup_material, data): + offset = multigroup_material["mgxs_nu_d_total_offset"] + return data[offset + index] + + +@njit +def mgxs_nu_d_total_all(multigroup_material, data): + start = multigroup_material["mgxs_nu_d_total_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_nu_d_total_last(multigroup_material, data): + start = multigroup_material["mgxs_nu_d_total_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_nu_d_total_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_nu_d_total_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_nu_f(index, multigroup_material, data): + offset = multigroup_material["mgxs_nu_f_offset"] + return data[offset + index] + + +@njit +def mgxs_nu_f_all(multigroup_material, data): + start = multigroup_material["mgxs_nu_f_offset"] + size = multigroup_material["G"] + end = start + size + return data[start:end] + + +@njit +def mgxs_nu_f_last(multigroup_material, data): + start = multigroup_material["mgxs_nu_f_offset"] + size = multigroup_material["G"] + end = start + size + return data[end - 1] + + +@njit +def mgxs_nu_f_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_nu_f_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_chi_s_vector(index_1, multigroup_material, data): + offset = multigroup_material["mgxs_chi_s_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def mgxs_chi_s(index_1, index_2, multigroup_material, data): + offset = multigroup_material["mgxs_chi_s_offset"] + stride = multigroup_material["G"] + return data[offset + index_1 * stride + index_2] + + +@njit +def mgxs_chi_s_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_chi_s_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_chi_p_vector(index_1, multigroup_material, data): + offset = multigroup_material["mgxs_chi_p_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def mgxs_chi_p(index_1, index_2, multigroup_material, data): + offset = multigroup_material["mgxs_chi_p_offset"] + stride = multigroup_material["G"] + return data[offset + index_1 * stride + index_2] + + +@njit +def mgxs_chi_p_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_chi_p_offset"] + end = start + length + return data[start:end] + + +@njit +def mgxs_chi_d_vector(index_1, multigroup_material, data): + offset = multigroup_material["mgxs_chi_d_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def mgxs_chi_d(index_1, index_2, multigroup_material, data): + offset = multigroup_material["mgxs_chi_d_offset"] + stride = multigroup_material["G"] + return data[offset + index_1 * stride + index_2] + + +@njit +def mgxs_chi_d_chunk(start, length, multigroup_material, data): + start += multigroup_material["mgxs_chi_d_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/native_material.py b/mcdc/mcdc_get/native_material.py new file mode 100644 index 000000000..94d16114a --- /dev/null +++ b/mcdc/mcdc_get/native_material.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def nuclide_IDs(index, native_material, data): + offset = native_material["nuclide_IDs_offset"] + return data[offset + index] + + +@njit +def nuclide_IDs_all(native_material, data): + start = native_material["nuclide_IDs_offset"] + size = native_material["N_nuclide"] + end = start + size + return data[start:end] + + +@njit +def nuclide_IDs_last(native_material, data): + start = native_material["nuclide_IDs_offset"] + size = native_material["N_nuclide"] + end = start + size + return data[end - 1] + + +@njit +def nuclide_IDs_chunk(start, length, native_material, data): + start += native_material["nuclide_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def nuclide_densities(index, native_material, data): + offset = native_material["nuclide_densities_offset"] + return data[offset + index] + + +@njit +def nuclide_densities_all(native_material, data): + start = native_material["nuclide_densities_offset"] + size = native_material["nuclide_densities_length"] + end = start + size + return data[start:end] + + +@njit +def nuclide_densities_last(native_material, data): + start = native_material["nuclide_densities_offset"] + size = native_material["nuclide_densities_length"] + end = start + size + return data[end - 1] + + +@njit +def nuclide_densities_chunk(start, length, native_material, data): + start += native_material["nuclide_densities_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/nbody_distribution.py b/mcdc/mcdc_get/nbody_distribution.py new file mode 100644 index 000000000..08d5197b1 --- /dev/null +++ b/mcdc/mcdc_get/nbody_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, nbody_distribution, data): + offset = nbody_distribution["value_offset"] + return data[offset + index] + + +@njit +def value_all(nbody_distribution, data): + start = nbody_distribution["value_offset"] + size = nbody_distribution["value_length"] + end = start + size + return data[start:end] + + +@njit +def value_last(nbody_distribution, data): + start = nbody_distribution["value_offset"] + size = nbody_distribution["value_length"] + end = start + size + return data[end - 1] + + +@njit +def value_chunk(start, length, nbody_distribution, data): + start += nbody_distribution["value_offset"] + end = start + length + return data[start:end] + + +@njit +def pdf(index, nbody_distribution, data): + offset = nbody_distribution["pdf_offset"] + return data[offset + index] + + +@njit +def pdf_all(nbody_distribution, data): + start = nbody_distribution["pdf_offset"] + size = nbody_distribution["pdf_length"] + end = start + size + return data[start:end] + + +@njit +def pdf_last(nbody_distribution, data): + start = nbody_distribution["pdf_offset"] + size = nbody_distribution["pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def pdf_chunk(start, length, nbody_distribution, data): + start += nbody_distribution["pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cdf(index, nbody_distribution, data): + offset = nbody_distribution["cdf_offset"] + return data[offset + index] + + +@njit +def cdf_all(nbody_distribution, data): + start = nbody_distribution["cdf_offset"] + size = nbody_distribution["cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cdf_last(nbody_distribution, data): + start = nbody_distribution["cdf_offset"] + size = nbody_distribution["cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cdf_chunk(start, length, nbody_distribution, data): + start += nbody_distribution["cdf_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/neutron_capture_reaction.py b/mcdc/mcdc_get/neutron_capture_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/neutron_capture_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/neutron_elastic_scattering_reaction.py b/mcdc/mcdc_get/neutron_elastic_scattering_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/neutron_elastic_scattering_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/neutron_fission_reaction.py b/mcdc/mcdc_get/neutron_fission_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/neutron_fission_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/neutron_inelastic_scattering_reaction.py b/mcdc/mcdc_get/neutron_inelastic_scattering_reaction.py new file mode 100644 index 000000000..1677db2be --- /dev/null +++ b/mcdc/mcdc_get/neutron_inelastic_scattering_reaction.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def spectrum_probability_grid(index, neutron_inelastic_scattering_reaction, data): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + return data[offset + index] + + +@njit +def spectrum_probability_grid_all(neutron_inelastic_scattering_reaction, data): + start = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + size = neutron_inelastic_scattering_reaction["spectrum_probability_grid_length"] + end = start + size + return data[start:end] + + +@njit +def spectrum_probability_grid_last(neutron_inelastic_scattering_reaction, data): + start = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + size = neutron_inelastic_scattering_reaction["spectrum_probability_grid_length"] + end = start + size + return data[end - 1] + + +@njit +def spectrum_probability_grid_chunk( + start, length, neutron_inelastic_scattering_reaction, data +): + start += neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + end = start + length + return data[start:end] + + +@njit +def spectrum_probability_vector(index_1, neutron_inelastic_scattering_reaction, data): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + stride = neutron_inelastic_scattering_reaction["N_spectrum"] + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def spectrum_probability(index_1, index_2, neutron_inelastic_scattering_reaction, data): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + stride = neutron_inelastic_scattering_reaction["N_spectrum"] + return data[offset + index_1 * stride + index_2] + + +@njit +def spectrum_probability_chunk( + start, length, neutron_inelastic_scattering_reaction, data +): + start += neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + end = start + length + return data[start:end] + + +@njit +def energy_spectrum_IDs(index, neutron_inelastic_scattering_reaction, data): + offset = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + return data[offset + index] + + +@njit +def energy_spectrum_IDs_all(neutron_inelastic_scattering_reaction, data): + start = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + size = neutron_inelastic_scattering_reaction["N_energy_spectrum"] + end = start + size + return data[start:end] + + +@njit +def energy_spectrum_IDs_last(neutron_inelastic_scattering_reaction, data): + start = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + size = neutron_inelastic_scattering_reaction["N_energy_spectrum"] + end = start + size + return data[end - 1] + + +@njit +def energy_spectrum_IDs_chunk( + start, length, neutron_inelastic_scattering_reaction, data +): + start += neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/none_data.py b/mcdc/mcdc_get/none_data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/none_data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/none_distribution.py b/mcdc/mcdc_get/none_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/none_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/nuclide.py b/mcdc/mcdc_get/nuclide.py new file mode 100644 index 000000000..782482850 --- /dev/null +++ b/mcdc/mcdc_get/nuclide.py @@ -0,0 +1,380 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def xs_energy_grid(index, nuclide, data): + offset = nuclide["xs_energy_grid_offset"] + return data[offset + index] + + +@njit +def xs_energy_grid_all(nuclide, data): + start = nuclide["xs_energy_grid_offset"] + size = nuclide["xs_energy_grid_length"] + end = start + size + return data[start:end] + + +@njit +def xs_energy_grid_last(nuclide, data): + start = nuclide["xs_energy_grid_offset"] + size = nuclide["xs_energy_grid_length"] + end = start + size + return data[end - 1] + + +@njit +def xs_energy_grid_chunk(start, length, nuclide, data): + start += nuclide["xs_energy_grid_offset"] + end = start + length + return data[start:end] + + +@njit +def total_xs(index, nuclide, data): + offset = nuclide["total_xs_offset"] + return data[offset + index] + + +@njit +def total_xs_all(nuclide, data): + start = nuclide["total_xs_offset"] + size = nuclide["total_xs_length"] + end = start + size + return data[start:end] + + +@njit +def total_xs_last(nuclide, data): + start = nuclide["total_xs_offset"] + size = nuclide["total_xs_length"] + end = start + size + return data[end - 1] + + +@njit +def total_xs_chunk(start, length, nuclide, data): + start += nuclide["total_xs_offset"] + end = start + length + return data[start:end] + + +@njit +def elastic_xs(index, nuclide, data): + offset = nuclide["elastic_xs_offset"] + return data[offset + index] + + +@njit +def elastic_xs_all(nuclide, data): + start = nuclide["elastic_xs_offset"] + size = nuclide["elastic_xs_length"] + end = start + size + return data[start:end] + + +@njit +def elastic_xs_last(nuclide, data): + start = nuclide["elastic_xs_offset"] + size = nuclide["elastic_xs_length"] + end = start + size + return data[end - 1] + + +@njit +def elastic_xs_chunk(start, length, nuclide, data): + start += nuclide["elastic_xs_offset"] + end = start + length + return data[start:end] + + +@njit +def capture_xs(index, nuclide, data): + offset = nuclide["capture_xs_offset"] + return data[offset + index] + + +@njit +def capture_xs_all(nuclide, data): + start = nuclide["capture_xs_offset"] + size = nuclide["capture_xs_length"] + end = start + size + return data[start:end] + + +@njit +def capture_xs_last(nuclide, data): + start = nuclide["capture_xs_offset"] + size = nuclide["capture_xs_length"] + end = start + size + return data[end - 1] + + +@njit +def capture_xs_chunk(start, length, nuclide, data): + start += nuclide["capture_xs_offset"] + end = start + length + return data[start:end] + + +@njit +def inelastic_xs(index, nuclide, data): + offset = nuclide["inelastic_xs_offset"] + return data[offset + index] + + +@njit +def inelastic_xs_all(nuclide, data): + start = nuclide["inelastic_xs_offset"] + size = nuclide["inelastic_xs_length"] + end = start + size + return data[start:end] + + +@njit +def inelastic_xs_last(nuclide, data): + start = nuclide["inelastic_xs_offset"] + size = nuclide["inelastic_xs_length"] + end = start + size + return data[end - 1] + + +@njit +def inelastic_xs_chunk(start, length, nuclide, data): + start += nuclide["inelastic_xs_offset"] + end = start + length + return data[start:end] + + +@njit +def fission_xs(index, nuclide, data): + offset = nuclide["fission_xs_offset"] + return data[offset + index] + + +@njit +def fission_xs_all(nuclide, data): + start = nuclide["fission_xs_offset"] + size = nuclide["fission_xs_length"] + end = start + size + return data[start:end] + + +@njit +def fission_xs_last(nuclide, data): + start = nuclide["fission_xs_offset"] + size = nuclide["fission_xs_length"] + end = start + size + return data[end - 1] + + +@njit +def fission_xs_chunk(start, length, nuclide, data): + start += nuclide["fission_xs_offset"] + end = start + length + return data[start:end] + + +@njit +def elastic_scattering_reaction_IDs(index, nuclide, data): + offset = nuclide["elastic_scattering_reaction_IDs_offset"] + return data[offset + index] + + +@njit +def elastic_scattering_reaction_IDs_all(nuclide, data): + start = nuclide["elastic_scattering_reaction_IDs_offset"] + size = nuclide["N_elastic_scattering_reaction"] + end = start + size + return data[start:end] + + +@njit +def elastic_scattering_reaction_IDs_last(nuclide, data): + start = nuclide["elastic_scattering_reaction_IDs_offset"] + size = nuclide["N_elastic_scattering_reaction"] + end = start + size + return data[end - 1] + + +@njit +def elastic_scattering_reaction_IDs_chunk(start, length, nuclide, data): + start += nuclide["elastic_scattering_reaction_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def capture_reaction_IDs(index, nuclide, data): + offset = nuclide["capture_reaction_IDs_offset"] + return data[offset + index] + + +@njit +def capture_reaction_IDs_all(nuclide, data): + start = nuclide["capture_reaction_IDs_offset"] + size = nuclide["N_capture_reaction"] + end = start + size + return data[start:end] + + +@njit +def capture_reaction_IDs_last(nuclide, data): + start = nuclide["capture_reaction_IDs_offset"] + size = nuclide["N_capture_reaction"] + end = start + size + return data[end - 1] + + +@njit +def capture_reaction_IDs_chunk(start, length, nuclide, data): + start += nuclide["capture_reaction_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def inelastic_scattering_reaction_IDs(index, nuclide, data): + offset = nuclide["inelastic_scattering_reaction_IDs_offset"] + return data[offset + index] + + +@njit +def inelastic_scattering_reaction_IDs_all(nuclide, data): + start = nuclide["inelastic_scattering_reaction_IDs_offset"] + size = nuclide["N_inelastic_scattering_reaction"] + end = start + size + return data[start:end] + + +@njit +def inelastic_scattering_reaction_IDs_last(nuclide, data): + start = nuclide["inelastic_scattering_reaction_IDs_offset"] + size = nuclide["N_inelastic_scattering_reaction"] + end = start + size + return data[end - 1] + + +@njit +def inelastic_scattering_reaction_IDs_chunk(start, length, nuclide, data): + start += nuclide["inelastic_scattering_reaction_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def fission_reaction_IDs(index, nuclide, data): + offset = nuclide["fission_reaction_IDs_offset"] + return data[offset + index] + + +@njit +def fission_reaction_IDs_all(nuclide, data): + start = nuclide["fission_reaction_IDs_offset"] + size = nuclide["N_fission_reaction"] + end = start + size + return data[start:end] + + +@njit +def fission_reaction_IDs_last(nuclide, data): + start = nuclide["fission_reaction_IDs_offset"] + size = nuclide["N_fission_reaction"] + end = start + size + return data[end - 1] + + +@njit +def fission_reaction_IDs_chunk(start, length, nuclide, data): + start += nuclide["fission_reaction_IDs_offset"] + end = start + length + return data[start:end] + + +@njit +def fission_delayed_fractions(index, nuclide, data): + offset = nuclide["fission_delayed_fractions_offset"] + return data[offset + index] + + +@njit +def fission_delayed_fractions_all(nuclide, data): + start = nuclide["fission_delayed_fractions_offset"] + size = nuclide["fission_delayed_fractions_length"] + end = start + size + return data[start:end] + + +@njit +def fission_delayed_fractions_last(nuclide, data): + start = nuclide["fission_delayed_fractions_offset"] + size = nuclide["fission_delayed_fractions_length"] + end = start + size + return data[end - 1] + + +@njit +def fission_delayed_fractions_chunk(start, length, nuclide, data): + start += nuclide["fission_delayed_fractions_offset"] + end = start + length + return data[start:end] + + +@njit +def fission_delayed_decay_rates(index, nuclide, data): + offset = nuclide["fission_delayed_decay_rates_offset"] + return data[offset + index] + + +@njit +def fission_delayed_decay_rates_all(nuclide, data): + start = nuclide["fission_delayed_decay_rates_offset"] + size = nuclide["fission_delayed_decay_rates_length"] + end = start + size + return data[start:end] + + +@njit +def fission_delayed_decay_rates_last(nuclide, data): + start = nuclide["fission_delayed_decay_rates_offset"] + size = nuclide["fission_delayed_decay_rates_length"] + end = start + size + return data[end - 1] + + +@njit +def fission_delayed_decay_rates_chunk(start, length, nuclide, data): + start += nuclide["fission_delayed_decay_rates_offset"] + end = start + length + return data[start:end] + + +@njit +def fission_delayed_spectrum_IDs(index, nuclide, data): + offset = nuclide["fission_delayed_spectrum_IDs_offset"] + return data[offset + index] + + +@njit +def fission_delayed_spectrum_IDs_all(nuclide, data): + start = nuclide["fission_delayed_spectrum_IDs_offset"] + size = nuclide["N_fission_delayed_spectrum"] + end = start + size + return data[start:end] + + +@njit +def fission_delayed_spectrum_IDs_last(nuclide, data): + start = nuclide["fission_delayed_spectrum_IDs_offset"] + size = nuclide["N_fission_delayed_spectrum"] + end = start + size + return data[end - 1] + + +@njit +def fission_delayed_spectrum_IDs_chunk(start, length, nuclide, data): + start += nuclide["fission_delayed_spectrum_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/particle.py b/mcdc/mcdc_get/particle.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/particle.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/particle_bank.py b/mcdc/mcdc_get/particle_bank.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/particle_bank.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/particle_data.py b/mcdc/mcdc_get/particle_data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/particle_data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/pmf_distribution.py b/mcdc/mcdc_get/pmf_distribution.py new file mode 100644 index 000000000..e5f4a259d --- /dev/null +++ b/mcdc/mcdc_get/pmf_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, pmf_distribution, data): + offset = pmf_distribution["value_offset"] + return data[offset + index] + + +@njit +def value_all(pmf_distribution, data): + start = pmf_distribution["value_offset"] + size = pmf_distribution["value_length"] + end = start + size + return data[start:end] + + +@njit +def value_last(pmf_distribution, data): + start = pmf_distribution["value_offset"] + size = pmf_distribution["value_length"] + end = start + size + return data[end - 1] + + +@njit +def value_chunk(start, length, pmf_distribution, data): + start += pmf_distribution["value_offset"] + end = start + length + return data[start:end] + + +@njit +def pmf(index, pmf_distribution, data): + offset = pmf_distribution["pmf_offset"] + return data[offset + index] + + +@njit +def pmf_all(pmf_distribution, data): + start = pmf_distribution["pmf_offset"] + size = pmf_distribution["pmf_length"] + end = start + size + return data[start:end] + + +@njit +def pmf_last(pmf_distribution, data): + start = pmf_distribution["pmf_offset"] + size = pmf_distribution["pmf_length"] + end = start + size + return data[end - 1] + + +@njit +def pmf_chunk(start, length, pmf_distribution, data): + start += pmf_distribution["pmf_offset"] + end = start + length + return data[start:end] + + +@njit +def cmf(index, pmf_distribution, data): + offset = pmf_distribution["cmf_offset"] + return data[offset + index] + + +@njit +def cmf_all(pmf_distribution, data): + start = pmf_distribution["cmf_offset"] + size = pmf_distribution["cmf_length"] + end = start + size + return data[start:end] + + +@njit +def cmf_last(pmf_distribution, data): + start = pmf_distribution["cmf_offset"] + size = pmf_distribution["cmf_length"] + end = start + size + return data[end - 1] + + +@njit +def cmf_chunk(start, length, pmf_distribution, data): + start += pmf_distribution["cmf_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/polynomial_data.py b/mcdc/mcdc_get/polynomial_data.py new file mode 100644 index 000000000..05e4d1a9f --- /dev/null +++ b/mcdc/mcdc_get/polynomial_data.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def coefficients(index, polynomial_data, data): + offset = polynomial_data["coefficients_offset"] + return data[offset + index] + + +@njit +def coefficients_all(polynomial_data, data): + start = polynomial_data["coefficients_offset"] + size = polynomial_data["coefficients_length"] + end = start + size + return data[start:end] + + +@njit +def coefficients_last(polynomial_data, data): + start = polynomial_data["coefficients_offset"] + size = polynomial_data["coefficients_length"] + end = start + size + return data[end - 1] + + +@njit +def coefficients_chunk(start, length, polynomial_data, data): + start += polynomial_data["coefficients_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/population_control.py b/mcdc/mcdc_get/population_control.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/population_control.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/reaction.py b/mcdc/mcdc_get/reaction.py new file mode 100644 index 000000000..b231d122f --- /dev/null +++ b/mcdc/mcdc_get/reaction.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def xs(index, reaction, data): + offset = reaction["xs_offset"] + return data[offset + index] + + +@njit +def xs_all(reaction, data): + start = reaction["xs_offset"] + size = reaction["xs_length"] + end = start + size + return data[start:end] + + +@njit +def xs_last(reaction, data): + start = reaction["xs_offset"] + size = reaction["xs_length"] + end = start + size + return data[end - 1] + + +@njit +def xs_chunk(start, length, reaction, data): + start += reaction["xs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/settings.py b/mcdc/mcdc_get/settings.py new file mode 100644 index 000000000..cb06d70e9 --- /dev/null +++ b/mcdc/mcdc_get/settings.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def census_time(index, settings, data): + offset = settings["census_time_offset"] + return data[offset + index] + + +@njit +def census_time_all(settings, data): + start = settings["census_time_offset"] + size = settings["census_time_length"] + end = start + size + return data[start:end] + + +@njit +def census_time_last(settings, data): + start = settings["census_time_offset"] + size = settings["census_time_length"] + end = start + size + return data[end - 1] + + +@njit +def census_time_chunk(start, length, settings, data): + start += settings["census_time_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/simulation.py b/mcdc/mcdc_get/simulation.py new file mode 100644 index 000000000..043b87361 --- /dev/null +++ b/mcdc/mcdc_get/simulation.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def k_cycle(index, simulation, data): + offset = simulation["k_cycle_offset"] + return data[offset + index] + + +@njit +def k_cycle_all(simulation, data): + start = simulation["k_cycle_offset"] + size = simulation["k_cycle_length"] + end = start + size + return data[start:end] + + +@njit +def k_cycle_last(simulation, data): + start = simulation["k_cycle_offset"] + size = simulation["k_cycle_length"] + end = start + size + return data[end - 1] + + +@njit +def k_cycle_chunk(start, length, simulation, data): + start += simulation["k_cycle_offset"] + end = start + length + return data[start:end] + + +@njit +def gyration_radius(index, simulation, data): + offset = simulation["gyration_radius_offset"] + return data[offset + index] + + +@njit +def gyration_radius_all(simulation, data): + start = simulation["gyration_radius_offset"] + size = simulation["gyration_radius_length"] + end = start + size + return data[start:end] + + +@njit +def gyration_radius_last(simulation, data): + start = simulation["gyration_radius_offset"] + size = simulation["gyration_radius_length"] + end = start + size + return data[end - 1] + + +@njit +def gyration_radius_chunk(start, length, simulation, data): + start += simulation["gyration_radius_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/source.py b/mcdc/mcdc_get/source.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/source.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/structured_mesh.py b/mcdc/mcdc_get/structured_mesh.py new file mode 100644 index 000000000..971cb8942 --- /dev/null +++ b/mcdc/mcdc_get/structured_mesh.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def x(index, structured_mesh, data): + offset = structured_mesh["x_offset"] + return data[offset + index] + + +@njit +def x_all(structured_mesh, data): + start = structured_mesh["x_offset"] + size = structured_mesh["x_length"] + end = start + size + return data[start:end] + + +@njit +def x_last(structured_mesh, data): + start = structured_mesh["x_offset"] + size = structured_mesh["x_length"] + end = start + size + return data[end - 1] + + +@njit +def x_chunk(start, length, structured_mesh, data): + start += structured_mesh["x_offset"] + end = start + length + return data[start:end] + + +@njit +def y(index, structured_mesh, data): + offset = structured_mesh["y_offset"] + return data[offset + index] + + +@njit +def y_all(structured_mesh, data): + start = structured_mesh["y_offset"] + size = structured_mesh["y_length"] + end = start + size + return data[start:end] + + +@njit +def y_last(structured_mesh, data): + start = structured_mesh["y_offset"] + size = structured_mesh["y_length"] + end = start + size + return data[end - 1] + + +@njit +def y_chunk(start, length, structured_mesh, data): + start += structured_mesh["y_offset"] + end = start + length + return data[start:end] + + +@njit +def z(index, structured_mesh, data): + offset = structured_mesh["z_offset"] + return data[offset + index] + + +@njit +def z_all(structured_mesh, data): + start = structured_mesh["z_offset"] + size = structured_mesh["z_length"] + end = start + size + return data[start:end] + + +@njit +def z_last(structured_mesh, data): + start = structured_mesh["z_offset"] + size = structured_mesh["z_length"] + end = start + size + return data[end - 1] + + +@njit +def z_chunk(start, length, structured_mesh, data): + start += structured_mesh["z_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/surface.py b/mcdc/mcdc_get/surface.py new file mode 100644 index 000000000..4a0230d76 --- /dev/null +++ b/mcdc/mcdc_get/surface.py @@ -0,0 +1,136 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def move_velocities_vector(index_1, surface, data): + offset = surface["move_velocities_offset"] + stride = 3 + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def move_velocities(index_1, index_2, surface, data): + offset = surface["move_velocities_offset"] + stride = 3 + return data[offset + index_1 * stride + index_2] + + +@njit +def move_velocities_chunk(start, length, surface, data): + start += surface["move_velocities_offset"] + end = start + length + return data[start:end] + + +@njit +def move_durations(index, surface, data): + offset = surface["move_durations_offset"] + return data[offset + index] + + +@njit +def move_durations_all(surface, data): + start = surface["move_durations_offset"] + size = surface["N_move"] + end = start + size + return data[start:end] + + +@njit +def move_durations_last(surface, data): + start = surface["move_durations_offset"] + size = surface["N_move"] + end = start + size + return data[end - 1] + + +@njit +def move_durations_chunk(start, length, surface, data): + start += surface["move_durations_offset"] + end = start + length + return data[start:end] + + +@njit +def move_time_grid(index, surface, data): + offset = surface["move_time_grid_offset"] + return data[offset + index] + + +@njit +def move_time_grid_all(surface, data): + start = surface["move_time_grid_offset"] + size = surface["N_move_grid"] + end = start + size + return data[start:end] + + +@njit +def move_time_grid_last(surface, data): + start = surface["move_time_grid_offset"] + size = surface["N_move_grid"] + end = start + size + return data[end - 1] + + +@njit +def move_time_grid_chunk(start, length, surface, data): + start += surface["move_time_grid_offset"] + end = start + length + return data[start:end] + + +@njit +def move_translations_vector(index_1, surface, data): + offset = surface["move_translations_offset"] + stride = 3 + start = offset + index_1 * stride + end = start + stride + return data[start:end] + + +@njit +def move_translations(index_1, index_2, surface, data): + offset = surface["move_translations_offset"] + stride = 3 + return data[offset + index_1 * stride + index_2] + + +@njit +def move_translations_chunk(start, length, surface, data): + start += surface["move_translations_offset"] + end = start + length + return data[start:end] + + +@njit +def tally_IDs(index, surface, data): + offset = surface["tally_IDs_offset"] + return data[offset + index] + + +@njit +def tally_IDs_all(surface, data): + start = surface["tally_IDs_offset"] + size = surface["N_tally"] + end = start + size + return data[start:end] + + +@njit +def tally_IDs_last(surface, data): + start = surface["tally_IDs_offset"] + size = surface["N_tally"] + end = start + size + return data[end - 1] + + +@njit +def tally_IDs_chunk(start, length, surface, data): + start += surface["tally_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/surface_tally.py b/mcdc/mcdc_get/surface_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/surface_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/table_data.py b/mcdc/mcdc_get/table_data.py new file mode 100644 index 000000000..854f9f357 --- /dev/null +++ b/mcdc/mcdc_get/table_data.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def x(index, table_data, data): + offset = table_data["x_offset"] + return data[offset + index] + + +@njit +def x_all(table_data, data): + start = table_data["x_offset"] + size = table_data["x_length"] + end = start + size + return data[start:end] + + +@njit +def x_last(table_data, data): + start = table_data["x_offset"] + size = table_data["x_length"] + end = start + size + return data[end - 1] + + +@njit +def x_chunk(start, length, table_data, data): + start += table_data["x_offset"] + end = start + length + return data[start:end] + + +@njit +def y(index, table_data, data): + offset = table_data["y_offset"] + return data[offset + index] + + +@njit +def y_all(table_data, data): + start = table_data["y_offset"] + size = table_data["y_length"] + end = start + size + return data[start:end] + + +@njit +def y_last(table_data, data): + start = table_data["y_offset"] + size = table_data["y_length"] + end = start + size + return data[end - 1] + + +@njit +def y_chunk(start, length, table_data, data): + start += table_data["y_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/tabulated_distribution.py b/mcdc/mcdc_get/tabulated_distribution.py new file mode 100644 index 000000000..d8e356bf4 --- /dev/null +++ b/mcdc/mcdc_get/tabulated_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, tabulated_distribution, data): + offset = tabulated_distribution["value_offset"] + return data[offset + index] + + +@njit +def value_all(tabulated_distribution, data): + start = tabulated_distribution["value_offset"] + size = tabulated_distribution["value_length"] + end = start + size + return data[start:end] + + +@njit +def value_last(tabulated_distribution, data): + start = tabulated_distribution["value_offset"] + size = tabulated_distribution["value_length"] + end = start + size + return data[end - 1] + + +@njit +def value_chunk(start, length, tabulated_distribution, data): + start += tabulated_distribution["value_offset"] + end = start + length + return data[start:end] + + +@njit +def pdf(index, tabulated_distribution, data): + offset = tabulated_distribution["pdf_offset"] + return data[offset + index] + + +@njit +def pdf_all(tabulated_distribution, data): + start = tabulated_distribution["pdf_offset"] + size = tabulated_distribution["pdf_length"] + end = start + size + return data[start:end] + + +@njit +def pdf_last(tabulated_distribution, data): + start = tabulated_distribution["pdf_offset"] + size = tabulated_distribution["pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def pdf_chunk(start, length, tabulated_distribution, data): + start += tabulated_distribution["pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cdf(index, tabulated_distribution, data): + offset = tabulated_distribution["cdf_offset"] + return data[offset + index] + + +@njit +def cdf_all(tabulated_distribution, data): + start = tabulated_distribution["cdf_offset"] + size = tabulated_distribution["cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cdf_last(tabulated_distribution, data): + start = tabulated_distribution["cdf_offset"] + size = tabulated_distribution["cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cdf_chunk(start, length, tabulated_distribution, data): + start += tabulated_distribution["cdf_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/tabulated_energy_angle_distribution.py b/mcdc/mcdc_get/tabulated_energy_angle_distribution.py new file mode 100644 index 000000000..aeb1fe914 --- /dev/null +++ b/mcdc/mcdc_get/tabulated_energy_angle_distribution.py @@ -0,0 +1,264 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def energy(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["energy_offset"] + return data[offset + index] + + +@njit +def energy_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["energy_offset"] + size = tabulated_energy_angle_distribution["energy_length"] + end = start + size + return data[start:end] + + +@njit +def energy_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["energy_offset"] + size = tabulated_energy_angle_distribution["energy_length"] + end = start + size + return data[end - 1] + + +@njit +def energy_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["energy_offset"] + end = start + length + return data[start:end] + + +@njit +def offset(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["offset_offset"] + return data[offset + index] + + +@njit +def offset_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["offset_offset"] + size = tabulated_energy_angle_distribution["offset_length"] + end = start + size + return data[start:end] + + +@njit +def offset_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["offset_offset"] + size = tabulated_energy_angle_distribution["offset_length"] + end = start + size + return data[end - 1] + + +@njit +def offset_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["offset_offset"] + end = start + length + return data[start:end] + + +@njit +def energy_out(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["energy_out_offset"] + return data[offset + index] + + +@njit +def energy_out_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["energy_out_offset"] + size = tabulated_energy_angle_distribution["energy_out_length"] + end = start + size + return data[start:end] + + +@njit +def energy_out_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["energy_out_offset"] + size = tabulated_energy_angle_distribution["energy_out_length"] + end = start + size + return data[end - 1] + + +@njit +def energy_out_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["energy_out_offset"] + end = start + length + return data[start:end] + + +@njit +def pdf(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["pdf_offset"] + return data[offset + index] + + +@njit +def pdf_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["pdf_offset"] + size = tabulated_energy_angle_distribution["pdf_length"] + end = start + size + return data[start:end] + + +@njit +def pdf_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["pdf_offset"] + size = tabulated_energy_angle_distribution["pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def pdf_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cdf(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["cdf_offset"] + return data[offset + index] + + +@njit +def cdf_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cdf_offset"] + size = tabulated_energy_angle_distribution["cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cdf_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cdf_offset"] + size = tabulated_energy_angle_distribution["cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cdf_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["cdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cosine_offset_(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["cosine_offset__offset"] + return data[offset + index] + + +@njit +def cosine_offset__all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_offset__offset"] + size = tabulated_energy_angle_distribution["cosine_offset__length"] + end = start + size + return data[start:end] + + +@njit +def cosine_offset__last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_offset__offset"] + size = tabulated_energy_angle_distribution["cosine_offset__length"] + end = start + size + return data[end - 1] + + +@njit +def cosine_offset__chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["cosine_offset__offset"] + end = start + length + return data[start:end] + + +@njit +def cosine(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["cosine_offset"] + return data[offset + index] + + +@njit +def cosine_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_offset"] + size = tabulated_energy_angle_distribution["cosine_length"] + end = start + size + return data[start:end] + + +@njit +def cosine_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_offset"] + size = tabulated_energy_angle_distribution["cosine_length"] + end = start + size + return data[end - 1] + + +@njit +def cosine_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["cosine_offset"] + end = start + length + return data[start:end] + + +@njit +def cosine_pdf(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["cosine_pdf_offset"] + return data[offset + index] + + +@njit +def cosine_pdf_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_pdf_offset"] + size = tabulated_energy_angle_distribution["cosine_pdf_length"] + end = start + size + return data[start:end] + + +@njit +def cosine_pdf_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_pdf_offset"] + size = tabulated_energy_angle_distribution["cosine_pdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cosine_pdf_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["cosine_pdf_offset"] + end = start + length + return data[start:end] + + +@njit +def cosine_cdf(index, tabulated_energy_angle_distribution, data): + offset = tabulated_energy_angle_distribution["cosine_cdf_offset"] + return data[offset + index] + + +@njit +def cosine_cdf_all(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_cdf_offset"] + size = tabulated_energy_angle_distribution["cosine_cdf_length"] + end = start + size + return data[start:end] + + +@njit +def cosine_cdf_last(tabulated_energy_angle_distribution, data): + start = tabulated_energy_angle_distribution["cosine_cdf_offset"] + size = tabulated_energy_angle_distribution["cosine_cdf_length"] + end = start + size + return data[end - 1] + + +@njit +def cosine_cdf_chunk(start, length, tabulated_energy_angle_distribution, data): + start += tabulated_energy_angle_distribution["cosine_cdf_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/tally.py b/mcdc/mcdc_get/tally.py new file mode 100644 index 000000000..23e9e698e --- /dev/null +++ b/mcdc/mcdc_get/tally.py @@ -0,0 +1,293 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def scores(index, tally, data): + offset = tally["scores_offset"] + return data[offset + index] + + +@njit +def scores_all(tally, data): + start = tally["scores_offset"] + size = tally["scores_length"] + end = start + size + return data[start:end] + + +@njit +def scores_last(tally, data): + start = tally["scores_offset"] + size = tally["scores_length"] + end = start + size + return data[end - 1] + + +@njit +def scores_chunk(start, length, tally, data): + start += tally["scores_offset"] + end = start + length + return data[start:end] + + +@njit +def multipliers(index, tally, data): + offset = tally["multipliers_offset"] + return data[offset + index] + + +@njit +def multipliers_all(tally, data): + start = tally["multipliers_offset"] + size = tally["multipliers_length"] + end = start + size + return data[start:end] + + +@njit +def multipliers_last(tally, data): + start = tally["multipliers_offset"] + size = tally["multipliers_length"] + end = start + size + return data[end - 1] + + +@njit +def multipliers_chunk(start, length, tally, data): + start += tally["multipliers_offset"] + end = start + length + return data[start:end] + + +@njit +def mu(index, tally, data): + offset = tally["mu_offset"] + return data[offset + index] + + +@njit +def mu_all(tally, data): + start = tally["mu_offset"] + size = tally["mu_length"] + end = start + size + return data[start:end] + + +@njit +def mu_last(tally, data): + start = tally["mu_offset"] + size = tally["mu_length"] + end = start + size + return data[end - 1] + + +@njit +def mu_chunk(start, length, tally, data): + start += tally["mu_offset"] + end = start + length + return data[start:end] + + +@njit +def azi(index, tally, data): + offset = tally["azi_offset"] + return data[offset + index] + + +@njit +def azi_all(tally, data): + start = tally["azi_offset"] + size = tally["azi_length"] + end = start + size + return data[start:end] + + +@njit +def azi_last(tally, data): + start = tally["azi_offset"] + size = tally["azi_length"] + end = start + size + return data[end - 1] + + +@njit +def azi_chunk(start, length, tally, data): + start += tally["azi_offset"] + end = start + length + return data[start:end] + + +@njit +def energy(index, tally, data): + offset = tally["energy_offset"] + return data[offset + index] + + +@njit +def energy_all(tally, data): + start = tally["energy_offset"] + size = tally["energy_length"] + end = start + size + return data[start:end] + + +@njit +def energy_last(tally, data): + start = tally["energy_offset"] + size = tally["energy_length"] + end = start + size + return data[end - 1] + + +@njit +def energy_chunk(start, length, tally, data): + start += tally["energy_offset"] + end = start + length + return data[start:end] + + +@njit +def time(index, tally, data): + offset = tally["time_offset"] + return data[offset + index] + + +@njit +def time_all(tally, data): + start = tally["time_offset"] + size = tally["time_length"] + end = start + size + return data[start:end] + + +@njit +def time_last(tally, data): + start = tally["time_offset"] + size = tally["time_length"] + end = start + size + return data[end - 1] + + +@njit +def time_chunk(start, length, tally, data): + start += tally["time_offset"] + end = start + length + return data[start:end] + + +@njit +def bin(index, tally, data): + offset = tally["bin_offset"] + return data[offset + index] + + +@njit +def bin_all(tally, data): + start = tally["bin_offset"] + size = tally["bin_length"] + end = start + size + return data[start:end] + + +@njit +def bin_last(tally, data): + start = tally["bin_offset"] + size = tally["bin_length"] + end = start + size + return data[end - 1] + + +@njit +def bin_chunk(start, length, tally, data): + start += tally["bin_offset"] + end = start + length + return data[start:end] + + +@njit +def bin_sum(index, tally, data): + offset = tally["bin_sum_offset"] + return data[offset + index] + + +@njit +def bin_sum_all(tally, data): + start = tally["bin_sum_offset"] + size = tally["bin_sum_length"] + end = start + size + return data[start:end] + + +@njit +def bin_sum_last(tally, data): + start = tally["bin_sum_offset"] + size = tally["bin_sum_length"] + end = start + size + return data[end - 1] + + +@njit +def bin_sum_chunk(start, length, tally, data): + start += tally["bin_sum_offset"] + end = start + length + return data[start:end] + + +@njit +def bin_sum_square(index, tally, data): + offset = tally["bin_sum_square_offset"] + return data[offset + index] + + +@njit +def bin_sum_square_all(tally, data): + start = tally["bin_sum_square_offset"] + size = tally["bin_sum_square_length"] + end = start + size + return data[start:end] + + +@njit +def bin_sum_square_last(tally, data): + start = tally["bin_sum_square_offset"] + size = tally["bin_sum_square_length"] + end = start + size + return data[end - 1] + + +@njit +def bin_sum_square_chunk(start, length, tally, data): + start += tally["bin_sum_square_offset"] + end = start + length + return data[start:end] + + +@njit +def bin_shape(index, tally, data): + offset = tally["bin_shape_offset"] + return data[offset + index] + + +@njit +def bin_shape_all(tally, data): + start = tally["bin_shape_offset"] + size = tally["bin_shape_length"] + end = start + size + return data[start:end] + + +@njit +def bin_shape_last(tally, data): + start = tally["bin_shape_offset"] + size = tally["bin_shape_length"] + end = start + size + return data[end - 1] + + +@njit +def bin_shape_chunk(start, length, tally, data): + start += tally["bin_shape_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/uniform_mesh.py b/mcdc/mcdc_get/uniform_mesh.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/uniform_mesh.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/universe.py b/mcdc/mcdc_get/universe.py new file mode 100644 index 000000000..5bfcf612d --- /dev/null +++ b/mcdc/mcdc_get/universe.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def cell_IDs(index, universe, data): + offset = universe["cell_IDs_offset"] + return data[offset + index] + + +@njit +def cell_IDs_all(universe, data): + start = universe["cell_IDs_offset"] + size = universe["N_cell"] + end = start + size + return data[start:end] + + +@njit +def cell_IDs_last(universe, data): + start = universe["cell_IDs_offset"] + size = universe["N_cell"] + end = start + size + return data[end - 1] + + +@njit +def cell_IDs_chunk(start, length, universe, data): + start += universe["cell_IDs_offset"] + end = start + length + return data[start:end] diff --git a/mcdc/mcdc_get/weight_roulette.py b/mcdc/mcdc_get/weight_roulette.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/weight_roulette.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_get/weighted_emission.py b/mcdc/mcdc_get/weighted_emission.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_get/weighted_emission.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/__init__.py b/mcdc/mcdc_set/__init__.py new file mode 100644 index 000000000..4df13dfc0 --- /dev/null +++ b/mcdc/mcdc_set/__init__.py @@ -0,0 +1,103 @@ +# The following is automatically generated by code_factory.py + +import mcdc.mcdc_set.particle_data as particle_data + +import mcdc.mcdc_set.particle as particle + +import mcdc.mcdc_set.cell as cell + +import mcdc.mcdc_set.lattice as lattice + +import mcdc.mcdc_set.material as material + +import mcdc.mcdc_set.cell_tally as cell_tally + +import mcdc.mcdc_set.universe as universe + +import mcdc.mcdc_set.data as data + +import mcdc.mcdc_set.none_data as none_data + +import mcdc.mcdc_set.polynomial_data as polynomial_data + +import mcdc.mcdc_set.table_data as table_data + +import mcdc.mcdc_set.distribution as distribution + +import mcdc.mcdc_set.evaporation_distribution as evaporation_distribution + +import mcdc.mcdc_set.kalbach_mann_distribution as kalbach_mann_distribution + +import mcdc.mcdc_set.level_scattering_distribution as level_scattering_distribution + +import mcdc.mcdc_set.maxwellian_distribution as maxwellian_distribution + +import mcdc.mcdc_set.multi_table_distribution as multi_table_distribution + +import mcdc.mcdc_set.nbody_distribution as nbody_distribution + +import mcdc.mcdc_set.none_distribution as none_distribution + +import mcdc.mcdc_set.pmf_distribution as pmf_distribution + +import mcdc.mcdc_set.tabulated_distribution as tabulated_distribution + +import mcdc.mcdc_set.tabulated_energy_angle_distribution as tabulated_energy_angle_distribution + +import mcdc.mcdc_set.gpu_meta as gpu_meta + +import mcdc.mcdc_set.native_material as native_material + +import mcdc.mcdc_set.multigroup_material as multigroup_material + +import mcdc.mcdc_set.nuclide as nuclide + +import mcdc.mcdc_set.mesh as mesh + +import mcdc.mcdc_set.structured_mesh as structured_mesh + +import mcdc.mcdc_set.uniform_mesh as uniform_mesh + +import mcdc.mcdc_set.neutron_capture_reaction as neutron_capture_reaction + +import mcdc.mcdc_set.neutron_elastic_scattering_reaction as neutron_elastic_scattering_reaction + +import mcdc.mcdc_set.neutron_fission_reaction as neutron_fission_reaction + +import mcdc.mcdc_set.neutron_inelastic_scattering_reaction as neutron_inelastic_scattering_reaction + +import mcdc.mcdc_set.particle_bank as particle_bank + +import mcdc.mcdc_set.reaction as reaction + +import mcdc.mcdc_set.settings as settings + +import mcdc.mcdc_set.implicit_capture as implicit_capture + +import mcdc.mcdc_set.population_control as population_control + +import mcdc.mcdc_set.weight_roulette as weight_roulette + +import mcdc.mcdc_set.weighted_emission as weighted_emission + +import mcdc.mcdc_set.source as source + +import mcdc.mcdc_set.surface as surface + +import mcdc.mcdc_set.surface_tally as surface_tally + +import mcdc.mcdc_set.tally as tally + +import mcdc.mcdc_set.global_tally as global_tally + +import mcdc.mcdc_set.mesh_tally as mesh_tally + +import mcdc.mcdc_set.bank_active as bank_active + +import mcdc.mcdc_set.bank_census as bank_census + +import mcdc.mcdc_set.bank_source as bank_source + +import mcdc.mcdc_set.bank_future as bank_future + +import mcdc.mcdc_set.simulation as simulation diff --git a/mcdc/mcdc_set/bank_active.py b/mcdc/mcdc_set/bank_active.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/bank_active.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/bank_census.py b/mcdc/mcdc_set/bank_census.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/bank_census.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/bank_future.py b/mcdc/mcdc_set/bank_future.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/bank_future.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/bank_source.py b/mcdc/mcdc_set/bank_source.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/bank_source.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/cell.py b/mcdc/mcdc_set/cell.py new file mode 100644 index 000000000..6fbb9a2cf --- /dev/null +++ b/mcdc/mcdc_set/cell.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def region_RPN_tokens(index, cell, data, value): + offset = cell["region_RPN_tokens_offset"] + data[offset + index] = value + + +@njit +def region_RPN_tokens_all(cell, data, value): + start = cell["region_RPN_tokens_offset"] + size = cell["region_RPN_tokens_length"] + end = start + size + data[start:end] = value + + +@njit +def region_RPN_tokens_last(cell, data, value): + start = cell["region_RPN_tokens_offset"] + size = cell["region_RPN_tokens_length"] + end = start + size + data[end - 1] = value + + +@njit +def region_RPN_tokens_chunk(start, length, cell, data, value): + start += cell["region_RPN_tokens_offset"] + end = start + length + data[start:end] = value + + +@njit +def surface_IDs(index, cell, data, value): + offset = cell["surface_IDs_offset"] + data[offset + index] = value + + +@njit +def surface_IDs_all(cell, data, value): + start = cell["surface_IDs_offset"] + size = cell["N_surface"] + end = start + size + data[start:end] = value + + +@njit +def surface_IDs_last(cell, data, value): + start = cell["surface_IDs_offset"] + size = cell["N_surface"] + end = start + size + data[end - 1] = value + + +@njit +def surface_IDs_chunk(start, length, cell, data, value): + start += cell["surface_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def tally_IDs(index, cell, data, value): + offset = cell["tally_IDs_offset"] + data[offset + index] = value + + +@njit +def tally_IDs_all(cell, data, value): + start = cell["tally_IDs_offset"] + size = cell["N_tally"] + end = start + size + data[start:end] = value + + +@njit +def tally_IDs_last(cell, data, value): + start = cell["tally_IDs_offset"] + size = cell["N_tally"] + end = start + size + data[end - 1] = value + + +@njit +def tally_IDs_chunk(start, length, cell, data, value): + start += cell["tally_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/cell_tally.py b/mcdc/mcdc_set/cell_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/cell_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/data.py b/mcdc/mcdc_set/data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/distribution.py b/mcdc/mcdc_set/distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/evaporation_distribution.py b/mcdc/mcdc_set/evaporation_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/evaporation_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/global_tally.py b/mcdc/mcdc_set/global_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/global_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/gpu_meta.py b/mcdc/mcdc_set/gpu_meta.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/gpu_meta.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/implicit_capture.py b/mcdc/mcdc_set/implicit_capture.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/implicit_capture.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/kalbach_mann_distribution.py b/mcdc/mcdc_set/kalbach_mann_distribution.py new file mode 100644 index 000000000..883f15846 --- /dev/null +++ b/mcdc/mcdc_set/kalbach_mann_distribution.py @@ -0,0 +1,206 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def energy(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["energy_offset"] + data[offset + index] = value + + +@njit +def energy_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["energy_offset"] + size = kalbach_mann_distribution["energy_length"] + end = start + size + data[start:end] = value + + +@njit +def energy_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["energy_offset"] + size = kalbach_mann_distribution["energy_length"] + end = start + size + data[end - 1] = value + + +@njit +def energy_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["energy_offset"] + end = start + length + data[start:end] = value + + +@njit +def offset(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["offset_offset"] + data[offset + index] = value + + +@njit +def offset_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["offset_offset"] + size = kalbach_mann_distribution["offset_length"] + end = start + size + data[start:end] = value + + +@njit +def offset_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["offset_offset"] + size = kalbach_mann_distribution["offset_length"] + end = start + size + data[end - 1] = value + + +@njit +def offset_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["offset_offset"] + end = start + length + data[start:end] = value + + +@njit +def energy_out(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["energy_out_offset"] + data[offset + index] = value + + +@njit +def energy_out_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["energy_out_offset"] + size = kalbach_mann_distribution["energy_out_length"] + end = start + size + data[start:end] = value + + +@njit +def energy_out_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["energy_out_offset"] + size = kalbach_mann_distribution["energy_out_length"] + end = start + size + data[end - 1] = value + + +@njit +def energy_out_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["energy_out_offset"] + end = start + length + data[start:end] = value + + +@njit +def pdf(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["pdf_offset"] + data[offset + index] = value + + +@njit +def pdf_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["pdf_offset"] + size = kalbach_mann_distribution["pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def pdf_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["pdf_offset"] + size = kalbach_mann_distribution["pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pdf_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cdf(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["cdf_offset"] + data[offset + index] = value + + +@njit +def cdf_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["cdf_offset"] + size = kalbach_mann_distribution["cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cdf_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["cdf_offset"] + size = kalbach_mann_distribution["cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cdf_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["cdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def precompound_factor(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["precompound_factor_offset"] + data[offset + index] = value + + +@njit +def precompound_factor_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["precompound_factor_offset"] + size = kalbach_mann_distribution["precompound_factor_length"] + end = start + size + data[start:end] = value + + +@njit +def precompound_factor_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["precompound_factor_offset"] + size = kalbach_mann_distribution["precompound_factor_length"] + end = start + size + data[end - 1] = value + + +@njit +def precompound_factor_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["precompound_factor_offset"] + end = start + length + data[start:end] = value + + +@njit +def angular_slope(index, kalbach_mann_distribution, data, value): + offset = kalbach_mann_distribution["angular_slope_offset"] + data[offset + index] = value + + +@njit +def angular_slope_all(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["angular_slope_offset"] + size = kalbach_mann_distribution["angular_slope_length"] + end = start + size + data[start:end] = value + + +@njit +def angular_slope_last(kalbach_mann_distribution, data, value): + start = kalbach_mann_distribution["angular_slope_offset"] + size = kalbach_mann_distribution["angular_slope_length"] + end = start + size + data[end - 1] = value + + +@njit +def angular_slope_chunk(start, length, kalbach_mann_distribution, data, value): + start += kalbach_mann_distribution["angular_slope_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/lattice.py b/mcdc/mcdc_set/lattice.py new file mode 100644 index 000000000..18a2f9076 --- /dev/null +++ b/mcdc/mcdc_set/lattice.py @@ -0,0 +1,18 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def universe_IDs(index_1, index_2, index_3, lattice, data, value): + offset = lattice["universe_IDs_offset"] + stride_2 = lattice["Ny"] + stride_3 = lattice["Nz"] + data[offset + index_1 * stride_2 * stride_3 + index_2 * stride_3 + index_3] = value + + +@njit +def universe_IDs_chunk(start, length, lattice, data, value): + start += lattice["universe_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/level_scattering_distribution.py b/mcdc/mcdc_set/level_scattering_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/level_scattering_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/material.py b/mcdc/mcdc_set/material.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/material.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/maxwellian_distribution.py b/mcdc/mcdc_set/maxwellian_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/maxwellian_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/mesh.py b/mcdc/mcdc_set/mesh.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/mesh.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/mesh_tally.py b/mcdc/mcdc_set/mesh_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/mesh_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/multi_table_distribution.py b/mcdc/mcdc_set/multi_table_distribution.py new file mode 100644 index 000000000..ad00d4019 --- /dev/null +++ b/mcdc/mcdc_set/multi_table_distribution.py @@ -0,0 +1,148 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def grid(index, multi_table_distribution, data, value): + offset = multi_table_distribution["grid_offset"] + data[offset + index] = value + + +@njit +def grid_all(multi_table_distribution, data, value): + start = multi_table_distribution["grid_offset"] + size = multi_table_distribution["grid_length"] + end = start + size + data[start:end] = value + + +@njit +def grid_last(multi_table_distribution, data, value): + start = multi_table_distribution["grid_offset"] + size = multi_table_distribution["grid_length"] + end = start + size + data[end - 1] = value + + +@njit +def grid_chunk(start, length, multi_table_distribution, data, value): + start += multi_table_distribution["grid_offset"] + end = start + length + data[start:end] = value + + +@njit +def offset(index, multi_table_distribution, data, value): + offset = multi_table_distribution["offset_offset"] + data[offset + index] = value + + +@njit +def offset_all(multi_table_distribution, data, value): + start = multi_table_distribution["offset_offset"] + size = multi_table_distribution["offset_length"] + end = start + size + data[start:end] = value + + +@njit +def offset_last(multi_table_distribution, data, value): + start = multi_table_distribution["offset_offset"] + size = multi_table_distribution["offset_length"] + end = start + size + data[end - 1] = value + + +@njit +def offset_chunk(start, length, multi_table_distribution, data, value): + start += multi_table_distribution["offset_offset"] + end = start + length + data[start:end] = value + + +@njit +def value(index, multi_table_distribution, data, value): + offset = multi_table_distribution["value_offset"] + data[offset + index] = value + + +@njit +def value_all(multi_table_distribution, data, value): + start = multi_table_distribution["value_offset"] + size = multi_table_distribution["value_length"] + end = start + size + data[start:end] = value + + +@njit +def value_last(multi_table_distribution, data, value): + start = multi_table_distribution["value_offset"] + size = multi_table_distribution["value_length"] + end = start + size + data[end - 1] = value + + +@njit +def value_chunk(start, length, multi_table_distribution, data, value): + start += multi_table_distribution["value_offset"] + end = start + length + data[start:end] = value + + +@njit +def pdf(index, multi_table_distribution, data, value): + offset = multi_table_distribution["pdf_offset"] + data[offset + index] = value + + +@njit +def pdf_all(multi_table_distribution, data, value): + start = multi_table_distribution["pdf_offset"] + size = multi_table_distribution["pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def pdf_last(multi_table_distribution, data, value): + start = multi_table_distribution["pdf_offset"] + size = multi_table_distribution["pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pdf_chunk(start, length, multi_table_distribution, data, value): + start += multi_table_distribution["pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cdf(index, multi_table_distribution, data, value): + offset = multi_table_distribution["cdf_offset"] + data[offset + index] = value + + +@njit +def cdf_all(multi_table_distribution, data, value): + start = multi_table_distribution["cdf_offset"] + size = multi_table_distribution["cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cdf_last(multi_table_distribution, data, value): + start = multi_table_distribution["cdf_offset"] + size = multi_table_distribution["cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cdf_chunk(start, length, multi_table_distribution, data, value): + start += multi_table_distribution["cdf_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/multigroup_material.py b/mcdc/mcdc_set/multigroup_material.py new file mode 100644 index 000000000..67224a700 --- /dev/null +++ b/mcdc/mcdc_set/multigroup_material.py @@ -0,0 +1,385 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def mgxs_speed(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_speed_offset"] + data[offset + index] = value + + +@njit +def mgxs_speed_all(multigroup_material, data, value): + start = multigroup_material["mgxs_speed_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_speed_last(multigroup_material, data, value): + start = multigroup_material["mgxs_speed_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_speed_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_speed_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_decay_rate(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_decay_rate_offset"] + data[offset + index] = value + + +@njit +def mgxs_decay_rate_all(multigroup_material, data, value): + start = multigroup_material["mgxs_decay_rate_offset"] + size = multigroup_material["J"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_decay_rate_last(multigroup_material, data, value): + start = multigroup_material["mgxs_decay_rate_offset"] + size = multigroup_material["J"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_decay_rate_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_decay_rate_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_capture(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_capture_offset"] + data[offset + index] = value + + +@njit +def mgxs_capture_all(multigroup_material, data, value): + start = multigroup_material["mgxs_capture_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_capture_last(multigroup_material, data, value): + start = multigroup_material["mgxs_capture_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_capture_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_capture_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_scatter(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_scatter_offset"] + data[offset + index] = value + + +@njit +def mgxs_scatter_all(multigroup_material, data, value): + start = multigroup_material["mgxs_scatter_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_scatter_last(multigroup_material, data, value): + start = multigroup_material["mgxs_scatter_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_scatter_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_scatter_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_fission(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_fission_offset"] + data[offset + index] = value + + +@njit +def mgxs_fission_all(multigroup_material, data, value): + start = multigroup_material["mgxs_fission_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_fission_last(multigroup_material, data, value): + start = multigroup_material["mgxs_fission_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_fission_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_fission_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_total(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_total_offset"] + data[offset + index] = value + + +@njit +def mgxs_total_all(multigroup_material, data, value): + start = multigroup_material["mgxs_total_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_total_last(multigroup_material, data, value): + start = multigroup_material["mgxs_total_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_total_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_total_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_nu_s(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_s_offset"] + data[offset + index] = value + + +@njit +def mgxs_nu_s_all(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_s_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_nu_s_last(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_s_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_nu_s_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_nu_s_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_nu_p(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_p_offset"] + data[offset + index] = value + + +@njit +def mgxs_nu_p_all(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_p_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_nu_p_last(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_p_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_nu_p_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_nu_p_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_nu_d_vector(index_1, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_d_offset"] + stride = multigroup_material["J"] + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def mgxs_nu_d(index_1, index_2, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_d_offset"] + stride = multigroup_material["J"] + data[offset + index_1 * stride + index_2] = value + + +@njit +def mgxs_nu_d_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_nu_d_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_nu_d_total(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_d_total_offset"] + data[offset + index] = value + + +@njit +def mgxs_nu_d_total_all(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_d_total_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_nu_d_total_last(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_d_total_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_nu_d_total_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_nu_d_total_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_nu_f(index, multigroup_material, data, value): + offset = multigroup_material["mgxs_nu_f_offset"] + data[offset + index] = value + + +@njit +def mgxs_nu_f_all(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_f_offset"] + size = multigroup_material["G"] + end = start + size + data[start:end] = value + + +@njit +def mgxs_nu_f_last(multigroup_material, data, value): + start = multigroup_material["mgxs_nu_f_offset"] + size = multigroup_material["G"] + end = start + size + data[end - 1] = value + + +@njit +def mgxs_nu_f_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_nu_f_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_chi_s_vector(index_1, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_s_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def mgxs_chi_s(index_1, index_2, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_s_offset"] + stride = multigroup_material["G"] + data[offset + index_1 * stride + index_2] = value + + +@njit +def mgxs_chi_s_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_chi_s_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_chi_p_vector(index_1, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_p_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def mgxs_chi_p(index_1, index_2, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_p_offset"] + stride = multigroup_material["G"] + data[offset + index_1 * stride + index_2] = value + + +@njit +def mgxs_chi_p_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_chi_p_offset"] + end = start + length + data[start:end] = value + + +@njit +def mgxs_chi_d_vector(index_1, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_d_offset"] + stride = multigroup_material["G"] + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def mgxs_chi_d(index_1, index_2, multigroup_material, data, value): + offset = multigroup_material["mgxs_chi_d_offset"] + stride = multigroup_material["G"] + data[offset + index_1 * stride + index_2] = value + + +@njit +def mgxs_chi_d_chunk(start, length, multigroup_material, data, value): + start += multigroup_material["mgxs_chi_d_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/native_material.py b/mcdc/mcdc_set/native_material.py new file mode 100644 index 000000000..c6094953a --- /dev/null +++ b/mcdc/mcdc_set/native_material.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def nuclide_IDs(index, native_material, data, value): + offset = native_material["nuclide_IDs_offset"] + data[offset + index] = value + + +@njit +def nuclide_IDs_all(native_material, data, value): + start = native_material["nuclide_IDs_offset"] + size = native_material["N_nuclide"] + end = start + size + data[start:end] = value + + +@njit +def nuclide_IDs_last(native_material, data, value): + start = native_material["nuclide_IDs_offset"] + size = native_material["N_nuclide"] + end = start + size + data[end - 1] = value + + +@njit +def nuclide_IDs_chunk(start, length, native_material, data, value): + start += native_material["nuclide_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def nuclide_densities(index, native_material, data, value): + offset = native_material["nuclide_densities_offset"] + data[offset + index] = value + + +@njit +def nuclide_densities_all(native_material, data, value): + start = native_material["nuclide_densities_offset"] + size = native_material["nuclide_densities_length"] + end = start + size + data[start:end] = value + + +@njit +def nuclide_densities_last(native_material, data, value): + start = native_material["nuclide_densities_offset"] + size = native_material["nuclide_densities_length"] + end = start + size + data[end - 1] = value + + +@njit +def nuclide_densities_chunk(start, length, native_material, data, value): + start += native_material["nuclide_densities_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/nbody_distribution.py b/mcdc/mcdc_set/nbody_distribution.py new file mode 100644 index 000000000..1539d143c --- /dev/null +++ b/mcdc/mcdc_set/nbody_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, nbody_distribution, data, value): + offset = nbody_distribution["value_offset"] + data[offset + index] = value + + +@njit +def value_all(nbody_distribution, data, value): + start = nbody_distribution["value_offset"] + size = nbody_distribution["value_length"] + end = start + size + data[start:end] = value + + +@njit +def value_last(nbody_distribution, data, value): + start = nbody_distribution["value_offset"] + size = nbody_distribution["value_length"] + end = start + size + data[end - 1] = value + + +@njit +def value_chunk(start, length, nbody_distribution, data, value): + start += nbody_distribution["value_offset"] + end = start + length + data[start:end] = value + + +@njit +def pdf(index, nbody_distribution, data, value): + offset = nbody_distribution["pdf_offset"] + data[offset + index] = value + + +@njit +def pdf_all(nbody_distribution, data, value): + start = nbody_distribution["pdf_offset"] + size = nbody_distribution["pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def pdf_last(nbody_distribution, data, value): + start = nbody_distribution["pdf_offset"] + size = nbody_distribution["pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pdf_chunk(start, length, nbody_distribution, data, value): + start += nbody_distribution["pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cdf(index, nbody_distribution, data, value): + offset = nbody_distribution["cdf_offset"] + data[offset + index] = value + + +@njit +def cdf_all(nbody_distribution, data, value): + start = nbody_distribution["cdf_offset"] + size = nbody_distribution["cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cdf_last(nbody_distribution, data, value): + start = nbody_distribution["cdf_offset"] + size = nbody_distribution["cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cdf_chunk(start, length, nbody_distribution, data, value): + start += nbody_distribution["cdf_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/neutron_capture_reaction.py b/mcdc/mcdc_set/neutron_capture_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/neutron_capture_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/neutron_elastic_scattering_reaction.py b/mcdc/mcdc_set/neutron_elastic_scattering_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/neutron_elastic_scattering_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/neutron_fission_reaction.py b/mcdc/mcdc_set/neutron_fission_reaction.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/neutron_fission_reaction.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/neutron_inelastic_scattering_reaction.py b/mcdc/mcdc_set/neutron_inelastic_scattering_reaction.py new file mode 100644 index 000000000..655095858 --- /dev/null +++ b/mcdc/mcdc_set/neutron_inelastic_scattering_reaction.py @@ -0,0 +1,96 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def spectrum_probability_grid( + index, neutron_inelastic_scattering_reaction, data, value +): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + data[offset + index] = value + + +@njit +def spectrum_probability_grid_all(neutron_inelastic_scattering_reaction, data, value): + start = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + size = neutron_inelastic_scattering_reaction["spectrum_probability_grid_length"] + end = start + size + data[start:end] = value + + +@njit +def spectrum_probability_grid_last(neutron_inelastic_scattering_reaction, data, value): + start = neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + size = neutron_inelastic_scattering_reaction["spectrum_probability_grid_length"] + end = start + size + data[end - 1] = value + + +@njit +def spectrum_probability_grid_chunk( + start, length, neutron_inelastic_scattering_reaction, data, value +): + start += neutron_inelastic_scattering_reaction["spectrum_probability_grid_offset"] + end = start + length + data[start:end] = value + + +@njit +def spectrum_probability_vector( + index_1, neutron_inelastic_scattering_reaction, data, value +): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + stride = neutron_inelastic_scattering_reaction["N_spectrum"] + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def spectrum_probability( + index_1, index_2, neutron_inelastic_scattering_reaction, data, value +): + offset = neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + stride = neutron_inelastic_scattering_reaction["N_spectrum"] + data[offset + index_1 * stride + index_2] = value + + +@njit +def spectrum_probability_chunk( + start, length, neutron_inelastic_scattering_reaction, data, value +): + start += neutron_inelastic_scattering_reaction["spectrum_probability_offset"] + end = start + length + data[start:end] = value + + +@njit +def energy_spectrum_IDs(index, neutron_inelastic_scattering_reaction, data, value): + offset = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + data[offset + index] = value + + +@njit +def energy_spectrum_IDs_all(neutron_inelastic_scattering_reaction, data, value): + start = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + size = neutron_inelastic_scattering_reaction["N_energy_spectrum"] + end = start + size + data[start:end] = value + + +@njit +def energy_spectrum_IDs_last(neutron_inelastic_scattering_reaction, data, value): + start = neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + size = neutron_inelastic_scattering_reaction["N_energy_spectrum"] + end = start + size + data[end - 1] = value + + +@njit +def energy_spectrum_IDs_chunk( + start, length, neutron_inelastic_scattering_reaction, data, value +): + start += neutron_inelastic_scattering_reaction["energy_spectrum_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/none_data.py b/mcdc/mcdc_set/none_data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/none_data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/none_distribution.py b/mcdc/mcdc_set/none_distribution.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/none_distribution.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/nuclide.py b/mcdc/mcdc_set/nuclide.py new file mode 100644 index 000000000..27811b3c8 --- /dev/null +++ b/mcdc/mcdc_set/nuclide.py @@ -0,0 +1,380 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def xs_energy_grid(index, nuclide, data, value): + offset = nuclide["xs_energy_grid_offset"] + data[offset + index] = value + + +@njit +def xs_energy_grid_all(nuclide, data, value): + start = nuclide["xs_energy_grid_offset"] + size = nuclide["xs_energy_grid_length"] + end = start + size + data[start:end] = value + + +@njit +def xs_energy_grid_last(nuclide, data, value): + start = nuclide["xs_energy_grid_offset"] + size = nuclide["xs_energy_grid_length"] + end = start + size + data[end - 1] = value + + +@njit +def xs_energy_grid_chunk(start, length, nuclide, data, value): + start += nuclide["xs_energy_grid_offset"] + end = start + length + data[start:end] = value + + +@njit +def total_xs(index, nuclide, data, value): + offset = nuclide["total_xs_offset"] + data[offset + index] = value + + +@njit +def total_xs_all(nuclide, data, value): + start = nuclide["total_xs_offset"] + size = nuclide["total_xs_length"] + end = start + size + data[start:end] = value + + +@njit +def total_xs_last(nuclide, data, value): + start = nuclide["total_xs_offset"] + size = nuclide["total_xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def total_xs_chunk(start, length, nuclide, data, value): + start += nuclide["total_xs_offset"] + end = start + length + data[start:end] = value + + +@njit +def elastic_xs(index, nuclide, data, value): + offset = nuclide["elastic_xs_offset"] + data[offset + index] = value + + +@njit +def elastic_xs_all(nuclide, data, value): + start = nuclide["elastic_xs_offset"] + size = nuclide["elastic_xs_length"] + end = start + size + data[start:end] = value + + +@njit +def elastic_xs_last(nuclide, data, value): + start = nuclide["elastic_xs_offset"] + size = nuclide["elastic_xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def elastic_xs_chunk(start, length, nuclide, data, value): + start += nuclide["elastic_xs_offset"] + end = start + length + data[start:end] = value + + +@njit +def capture_xs(index, nuclide, data, value): + offset = nuclide["capture_xs_offset"] + data[offset + index] = value + + +@njit +def capture_xs_all(nuclide, data, value): + start = nuclide["capture_xs_offset"] + size = nuclide["capture_xs_length"] + end = start + size + data[start:end] = value + + +@njit +def capture_xs_last(nuclide, data, value): + start = nuclide["capture_xs_offset"] + size = nuclide["capture_xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def capture_xs_chunk(start, length, nuclide, data, value): + start += nuclide["capture_xs_offset"] + end = start + length + data[start:end] = value + + +@njit +def inelastic_xs(index, nuclide, data, value): + offset = nuclide["inelastic_xs_offset"] + data[offset + index] = value + + +@njit +def inelastic_xs_all(nuclide, data, value): + start = nuclide["inelastic_xs_offset"] + size = nuclide["inelastic_xs_length"] + end = start + size + data[start:end] = value + + +@njit +def inelastic_xs_last(nuclide, data, value): + start = nuclide["inelastic_xs_offset"] + size = nuclide["inelastic_xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def inelastic_xs_chunk(start, length, nuclide, data, value): + start += nuclide["inelastic_xs_offset"] + end = start + length + data[start:end] = value + + +@njit +def fission_xs(index, nuclide, data, value): + offset = nuclide["fission_xs_offset"] + data[offset + index] = value + + +@njit +def fission_xs_all(nuclide, data, value): + start = nuclide["fission_xs_offset"] + size = nuclide["fission_xs_length"] + end = start + size + data[start:end] = value + + +@njit +def fission_xs_last(nuclide, data, value): + start = nuclide["fission_xs_offset"] + size = nuclide["fission_xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def fission_xs_chunk(start, length, nuclide, data, value): + start += nuclide["fission_xs_offset"] + end = start + length + data[start:end] = value + + +@njit +def elastic_scattering_reaction_IDs(index, nuclide, data, value): + offset = nuclide["elastic_scattering_reaction_IDs_offset"] + data[offset + index] = value + + +@njit +def elastic_scattering_reaction_IDs_all(nuclide, data, value): + start = nuclide["elastic_scattering_reaction_IDs_offset"] + size = nuclide["N_elastic_scattering_reaction"] + end = start + size + data[start:end] = value + + +@njit +def elastic_scattering_reaction_IDs_last(nuclide, data, value): + start = nuclide["elastic_scattering_reaction_IDs_offset"] + size = nuclide["N_elastic_scattering_reaction"] + end = start + size + data[end - 1] = value + + +@njit +def elastic_scattering_reaction_IDs_chunk(start, length, nuclide, data, value): + start += nuclide["elastic_scattering_reaction_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def capture_reaction_IDs(index, nuclide, data, value): + offset = nuclide["capture_reaction_IDs_offset"] + data[offset + index] = value + + +@njit +def capture_reaction_IDs_all(nuclide, data, value): + start = nuclide["capture_reaction_IDs_offset"] + size = nuclide["N_capture_reaction"] + end = start + size + data[start:end] = value + + +@njit +def capture_reaction_IDs_last(nuclide, data, value): + start = nuclide["capture_reaction_IDs_offset"] + size = nuclide["N_capture_reaction"] + end = start + size + data[end - 1] = value + + +@njit +def capture_reaction_IDs_chunk(start, length, nuclide, data, value): + start += nuclide["capture_reaction_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def inelastic_scattering_reaction_IDs(index, nuclide, data, value): + offset = nuclide["inelastic_scattering_reaction_IDs_offset"] + data[offset + index] = value + + +@njit +def inelastic_scattering_reaction_IDs_all(nuclide, data, value): + start = nuclide["inelastic_scattering_reaction_IDs_offset"] + size = nuclide["N_inelastic_scattering_reaction"] + end = start + size + data[start:end] = value + + +@njit +def inelastic_scattering_reaction_IDs_last(nuclide, data, value): + start = nuclide["inelastic_scattering_reaction_IDs_offset"] + size = nuclide["N_inelastic_scattering_reaction"] + end = start + size + data[end - 1] = value + + +@njit +def inelastic_scattering_reaction_IDs_chunk(start, length, nuclide, data, value): + start += nuclide["inelastic_scattering_reaction_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def fission_reaction_IDs(index, nuclide, data, value): + offset = nuclide["fission_reaction_IDs_offset"] + data[offset + index] = value + + +@njit +def fission_reaction_IDs_all(nuclide, data, value): + start = nuclide["fission_reaction_IDs_offset"] + size = nuclide["N_fission_reaction"] + end = start + size + data[start:end] = value + + +@njit +def fission_reaction_IDs_last(nuclide, data, value): + start = nuclide["fission_reaction_IDs_offset"] + size = nuclide["N_fission_reaction"] + end = start + size + data[end - 1] = value + + +@njit +def fission_reaction_IDs_chunk(start, length, nuclide, data, value): + start += nuclide["fission_reaction_IDs_offset"] + end = start + length + data[start:end] = value + + +@njit +def fission_delayed_fractions(index, nuclide, data, value): + offset = nuclide["fission_delayed_fractions_offset"] + data[offset + index] = value + + +@njit +def fission_delayed_fractions_all(nuclide, data, value): + start = nuclide["fission_delayed_fractions_offset"] + size = nuclide["fission_delayed_fractions_length"] + end = start + size + data[start:end] = value + + +@njit +def fission_delayed_fractions_last(nuclide, data, value): + start = nuclide["fission_delayed_fractions_offset"] + size = nuclide["fission_delayed_fractions_length"] + end = start + size + data[end - 1] = value + + +@njit +def fission_delayed_fractions_chunk(start, length, nuclide, data, value): + start += nuclide["fission_delayed_fractions_offset"] + end = start + length + data[start:end] = value + + +@njit +def fission_delayed_decay_rates(index, nuclide, data, value): + offset = nuclide["fission_delayed_decay_rates_offset"] + data[offset + index] = value + + +@njit +def fission_delayed_decay_rates_all(nuclide, data, value): + start = nuclide["fission_delayed_decay_rates_offset"] + size = nuclide["fission_delayed_decay_rates_length"] + end = start + size + data[start:end] = value + + +@njit +def fission_delayed_decay_rates_last(nuclide, data, value): + start = nuclide["fission_delayed_decay_rates_offset"] + size = nuclide["fission_delayed_decay_rates_length"] + end = start + size + data[end - 1] = value + + +@njit +def fission_delayed_decay_rates_chunk(start, length, nuclide, data, value): + start += nuclide["fission_delayed_decay_rates_offset"] + end = start + length + data[start:end] = value + + +@njit +def fission_delayed_spectrum_IDs(index, nuclide, data, value): + offset = nuclide["fission_delayed_spectrum_IDs_offset"] + data[offset + index] = value + + +@njit +def fission_delayed_spectrum_IDs_all(nuclide, data, value): + start = nuclide["fission_delayed_spectrum_IDs_offset"] + size = nuclide["N_fission_delayed_spectrum"] + end = start + size + data[start:end] = value + + +@njit +def fission_delayed_spectrum_IDs_last(nuclide, data, value): + start = nuclide["fission_delayed_spectrum_IDs_offset"] + size = nuclide["N_fission_delayed_spectrum"] + end = start + size + data[end - 1] = value + + +@njit +def fission_delayed_spectrum_IDs_chunk(start, length, nuclide, data, value): + start += nuclide["fission_delayed_spectrum_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/particle.py b/mcdc/mcdc_set/particle.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/particle.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/particle_bank.py b/mcdc/mcdc_set/particle_bank.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/particle_bank.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/particle_data.py b/mcdc/mcdc_set/particle_data.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/particle_data.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/pmf_distribution.py b/mcdc/mcdc_set/pmf_distribution.py new file mode 100644 index 000000000..aa4fe04e2 --- /dev/null +++ b/mcdc/mcdc_set/pmf_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, pmf_distribution, data, value): + offset = pmf_distribution["value_offset"] + data[offset + index] = value + + +@njit +def value_all(pmf_distribution, data, value): + start = pmf_distribution["value_offset"] + size = pmf_distribution["value_length"] + end = start + size + data[start:end] = value + + +@njit +def value_last(pmf_distribution, data, value): + start = pmf_distribution["value_offset"] + size = pmf_distribution["value_length"] + end = start + size + data[end - 1] = value + + +@njit +def value_chunk(start, length, pmf_distribution, data, value): + start += pmf_distribution["value_offset"] + end = start + length + data[start:end] = value + + +@njit +def pmf(index, pmf_distribution, data, value): + offset = pmf_distribution["pmf_offset"] + data[offset + index] = value + + +@njit +def pmf_all(pmf_distribution, data, value): + start = pmf_distribution["pmf_offset"] + size = pmf_distribution["pmf_length"] + end = start + size + data[start:end] = value + + +@njit +def pmf_last(pmf_distribution, data, value): + start = pmf_distribution["pmf_offset"] + size = pmf_distribution["pmf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pmf_chunk(start, length, pmf_distribution, data, value): + start += pmf_distribution["pmf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cmf(index, pmf_distribution, data, value): + offset = pmf_distribution["cmf_offset"] + data[offset + index] = value + + +@njit +def cmf_all(pmf_distribution, data, value): + start = pmf_distribution["cmf_offset"] + size = pmf_distribution["cmf_length"] + end = start + size + data[start:end] = value + + +@njit +def cmf_last(pmf_distribution, data, value): + start = pmf_distribution["cmf_offset"] + size = pmf_distribution["cmf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cmf_chunk(start, length, pmf_distribution, data, value): + start += pmf_distribution["cmf_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/polynomial_data.py b/mcdc/mcdc_set/polynomial_data.py new file mode 100644 index 000000000..cf058425d --- /dev/null +++ b/mcdc/mcdc_set/polynomial_data.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def coefficients(index, polynomial_data, data, value): + offset = polynomial_data["coefficients_offset"] + data[offset + index] = value + + +@njit +def coefficients_all(polynomial_data, data, value): + start = polynomial_data["coefficients_offset"] + size = polynomial_data["coefficients_length"] + end = start + size + data[start:end] = value + + +@njit +def coefficients_last(polynomial_data, data, value): + start = polynomial_data["coefficients_offset"] + size = polynomial_data["coefficients_length"] + end = start + size + data[end - 1] = value + + +@njit +def coefficients_chunk(start, length, polynomial_data, data, value): + start += polynomial_data["coefficients_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/population_control.py b/mcdc/mcdc_set/population_control.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/population_control.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/reaction.py b/mcdc/mcdc_set/reaction.py new file mode 100644 index 000000000..3b29d18e3 --- /dev/null +++ b/mcdc/mcdc_set/reaction.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def xs(index, reaction, data, value): + offset = reaction["xs_offset"] + data[offset + index] = value + + +@njit +def xs_all(reaction, data, value): + start = reaction["xs_offset"] + size = reaction["xs_length"] + end = start + size + data[start:end] = value + + +@njit +def xs_last(reaction, data, value): + start = reaction["xs_offset"] + size = reaction["xs_length"] + end = start + size + data[end - 1] = value + + +@njit +def xs_chunk(start, length, reaction, data, value): + start += reaction["xs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/settings.py b/mcdc/mcdc_set/settings.py new file mode 100644 index 000000000..7c876f2c2 --- /dev/null +++ b/mcdc/mcdc_set/settings.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def census_time(index, settings, data, value): + offset = settings["census_time_offset"] + data[offset + index] = value + + +@njit +def census_time_all(settings, data, value): + start = settings["census_time_offset"] + size = settings["census_time_length"] + end = start + size + data[start:end] = value + + +@njit +def census_time_last(settings, data, value): + start = settings["census_time_offset"] + size = settings["census_time_length"] + end = start + size + data[end - 1] = value + + +@njit +def census_time_chunk(start, length, settings, data, value): + start += settings["census_time_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/simulation.py b/mcdc/mcdc_set/simulation.py new file mode 100644 index 000000000..fc4b2b24e --- /dev/null +++ b/mcdc/mcdc_set/simulation.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def k_cycle(index, simulation, data, value): + offset = simulation["k_cycle_offset"] + data[offset + index] = value + + +@njit +def k_cycle_all(simulation, data, value): + start = simulation["k_cycle_offset"] + size = simulation["k_cycle_length"] + end = start + size + data[start:end] = value + + +@njit +def k_cycle_last(simulation, data, value): + start = simulation["k_cycle_offset"] + size = simulation["k_cycle_length"] + end = start + size + data[end - 1] = value + + +@njit +def k_cycle_chunk(start, length, simulation, data, value): + start += simulation["k_cycle_offset"] + end = start + length + data[start:end] = value + + +@njit +def gyration_radius(index, simulation, data, value): + offset = simulation["gyration_radius_offset"] + data[offset + index] = value + + +@njit +def gyration_radius_all(simulation, data, value): + start = simulation["gyration_radius_offset"] + size = simulation["gyration_radius_length"] + end = start + size + data[start:end] = value + + +@njit +def gyration_radius_last(simulation, data, value): + start = simulation["gyration_radius_offset"] + size = simulation["gyration_radius_length"] + end = start + size + data[end - 1] = value + + +@njit +def gyration_radius_chunk(start, length, simulation, data, value): + start += simulation["gyration_radius_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/source.py b/mcdc/mcdc_set/source.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/source.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/structured_mesh.py b/mcdc/mcdc_set/structured_mesh.py new file mode 100644 index 000000000..7825e32f8 --- /dev/null +++ b/mcdc/mcdc_set/structured_mesh.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def x(index, structured_mesh, data, value): + offset = structured_mesh["x_offset"] + data[offset + index] = value + + +@njit +def x_all(structured_mesh, data, value): + start = structured_mesh["x_offset"] + size = structured_mesh["x_length"] + end = start + size + data[start:end] = value + + +@njit +def x_last(structured_mesh, data, value): + start = structured_mesh["x_offset"] + size = structured_mesh["x_length"] + end = start + size + data[end - 1] = value + + +@njit +def x_chunk(start, length, structured_mesh, data, value): + start += structured_mesh["x_offset"] + end = start + length + data[start:end] = value + + +@njit +def y(index, structured_mesh, data, value): + offset = structured_mesh["y_offset"] + data[offset + index] = value + + +@njit +def y_all(structured_mesh, data, value): + start = structured_mesh["y_offset"] + size = structured_mesh["y_length"] + end = start + size + data[start:end] = value + + +@njit +def y_last(structured_mesh, data, value): + start = structured_mesh["y_offset"] + size = structured_mesh["y_length"] + end = start + size + data[end - 1] = value + + +@njit +def y_chunk(start, length, structured_mesh, data, value): + start += structured_mesh["y_offset"] + end = start + length + data[start:end] = value + + +@njit +def z(index, structured_mesh, data, value): + offset = structured_mesh["z_offset"] + data[offset + index] = value + + +@njit +def z_all(structured_mesh, data, value): + start = structured_mesh["z_offset"] + size = structured_mesh["z_length"] + end = start + size + data[start:end] = value + + +@njit +def z_last(structured_mesh, data, value): + start = structured_mesh["z_offset"] + size = structured_mesh["z_length"] + end = start + size + data[end - 1] = value + + +@njit +def z_chunk(start, length, structured_mesh, data, value): + start += structured_mesh["z_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/surface.py b/mcdc/mcdc_set/surface.py new file mode 100644 index 000000000..5ade2f533 --- /dev/null +++ b/mcdc/mcdc_set/surface.py @@ -0,0 +1,136 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def move_velocities_vector(index_1, surface, data, value): + offset = surface["move_velocities_offset"] + stride = 3 + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def move_velocities(index_1, index_2, surface, data, value): + offset = surface["move_velocities_offset"] + stride = 3 + data[offset + index_1 * stride + index_2] = value + + +@njit +def move_velocities_chunk(start, length, surface, data, value): + start += surface["move_velocities_offset"] + end = start + length + data[start:end] = value + + +@njit +def move_durations(index, surface, data, value): + offset = surface["move_durations_offset"] + data[offset + index] = value + + +@njit +def move_durations_all(surface, data, value): + start = surface["move_durations_offset"] + size = surface["N_move"] + end = start + size + data[start:end] = value + + +@njit +def move_durations_last(surface, data, value): + start = surface["move_durations_offset"] + size = surface["N_move"] + end = start + size + data[end - 1] = value + + +@njit +def move_durations_chunk(start, length, surface, data, value): + start += surface["move_durations_offset"] + end = start + length + data[start:end] = value + + +@njit +def move_time_grid(index, surface, data, value): + offset = surface["move_time_grid_offset"] + data[offset + index] = value + + +@njit +def move_time_grid_all(surface, data, value): + start = surface["move_time_grid_offset"] + size = surface["N_move_grid"] + end = start + size + data[start:end] = value + + +@njit +def move_time_grid_last(surface, data, value): + start = surface["move_time_grid_offset"] + size = surface["N_move_grid"] + end = start + size + data[end - 1] = value + + +@njit +def move_time_grid_chunk(start, length, surface, data, value): + start += surface["move_time_grid_offset"] + end = start + length + data[start:end] = value + + +@njit +def move_translations_vector(index_1, surface, data, value): + offset = surface["move_translations_offset"] + stride = 3 + start = offset + index_1 * stride + end = start + stride + data[start:end] - value + + +@njit +def move_translations(index_1, index_2, surface, data, value): + offset = surface["move_translations_offset"] + stride = 3 + data[offset + index_1 * stride + index_2] = value + + +@njit +def move_translations_chunk(start, length, surface, data, value): + start += surface["move_translations_offset"] + end = start + length + data[start:end] = value + + +@njit +def tally_IDs(index, surface, data, value): + offset = surface["tally_IDs_offset"] + data[offset + index] = value + + +@njit +def tally_IDs_all(surface, data, value): + start = surface["tally_IDs_offset"] + size = surface["N_tally"] + end = start + size + data[start:end] = value + + +@njit +def tally_IDs_last(surface, data, value): + start = surface["tally_IDs_offset"] + size = surface["N_tally"] + end = start + size + data[end - 1] = value + + +@njit +def tally_IDs_chunk(start, length, surface, data, value): + start += surface["tally_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/surface_tally.py b/mcdc/mcdc_set/surface_tally.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/surface_tally.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/table_data.py b/mcdc/mcdc_set/table_data.py new file mode 100644 index 000000000..16c422171 --- /dev/null +++ b/mcdc/mcdc_set/table_data.py @@ -0,0 +1,61 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def x(index, table_data, data, value): + offset = table_data["x_offset"] + data[offset + index] = value + + +@njit +def x_all(table_data, data, value): + start = table_data["x_offset"] + size = table_data["x_length"] + end = start + size + data[start:end] = value + + +@njit +def x_last(table_data, data, value): + start = table_data["x_offset"] + size = table_data["x_length"] + end = start + size + data[end - 1] = value + + +@njit +def x_chunk(start, length, table_data, data, value): + start += table_data["x_offset"] + end = start + length + data[start:end] = value + + +@njit +def y(index, table_data, data, value): + offset = table_data["y_offset"] + data[offset + index] = value + + +@njit +def y_all(table_data, data, value): + start = table_data["y_offset"] + size = table_data["y_length"] + end = start + size + data[start:end] = value + + +@njit +def y_last(table_data, data, value): + start = table_data["y_offset"] + size = table_data["y_length"] + end = start + size + data[end - 1] = value + + +@njit +def y_chunk(start, length, table_data, data, value): + start += table_data["y_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/tabulated_distribution.py b/mcdc/mcdc_set/tabulated_distribution.py new file mode 100644 index 000000000..91bd5cfcd --- /dev/null +++ b/mcdc/mcdc_set/tabulated_distribution.py @@ -0,0 +1,90 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def value(index, tabulated_distribution, data, value): + offset = tabulated_distribution["value_offset"] + data[offset + index] = value + + +@njit +def value_all(tabulated_distribution, data, value): + start = tabulated_distribution["value_offset"] + size = tabulated_distribution["value_length"] + end = start + size + data[start:end] = value + + +@njit +def value_last(tabulated_distribution, data, value): + start = tabulated_distribution["value_offset"] + size = tabulated_distribution["value_length"] + end = start + size + data[end - 1] = value + + +@njit +def value_chunk(start, length, tabulated_distribution, data, value): + start += tabulated_distribution["value_offset"] + end = start + length + data[start:end] = value + + +@njit +def pdf(index, tabulated_distribution, data, value): + offset = tabulated_distribution["pdf_offset"] + data[offset + index] = value + + +@njit +def pdf_all(tabulated_distribution, data, value): + start = tabulated_distribution["pdf_offset"] + size = tabulated_distribution["pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def pdf_last(tabulated_distribution, data, value): + start = tabulated_distribution["pdf_offset"] + size = tabulated_distribution["pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pdf_chunk(start, length, tabulated_distribution, data, value): + start += tabulated_distribution["pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cdf(index, tabulated_distribution, data, value): + offset = tabulated_distribution["cdf_offset"] + data[offset + index] = value + + +@njit +def cdf_all(tabulated_distribution, data, value): + start = tabulated_distribution["cdf_offset"] + size = tabulated_distribution["cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cdf_last(tabulated_distribution, data, value): + start = tabulated_distribution["cdf_offset"] + size = tabulated_distribution["cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cdf_chunk(start, length, tabulated_distribution, data, value): + start += tabulated_distribution["cdf_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/tabulated_energy_angle_distribution.py b/mcdc/mcdc_set/tabulated_energy_angle_distribution.py new file mode 100644 index 000000000..970402806 --- /dev/null +++ b/mcdc/mcdc_set/tabulated_energy_angle_distribution.py @@ -0,0 +1,266 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def energy(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["energy_offset"] + data[offset + index] = value + + +@njit +def energy_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["energy_offset"] + size = tabulated_energy_angle_distribution["energy_length"] + end = start + size + data[start:end] = value + + +@njit +def energy_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["energy_offset"] + size = tabulated_energy_angle_distribution["energy_length"] + end = start + size + data[end - 1] = value + + +@njit +def energy_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["energy_offset"] + end = start + length + data[start:end] = value + + +@njit +def offset(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["offset_offset"] + data[offset + index] = value + + +@njit +def offset_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["offset_offset"] + size = tabulated_energy_angle_distribution["offset_length"] + end = start + size + data[start:end] = value + + +@njit +def offset_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["offset_offset"] + size = tabulated_energy_angle_distribution["offset_length"] + end = start + size + data[end - 1] = value + + +@njit +def offset_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["offset_offset"] + end = start + length + data[start:end] = value + + +@njit +def energy_out(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["energy_out_offset"] + data[offset + index] = value + + +@njit +def energy_out_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["energy_out_offset"] + size = tabulated_energy_angle_distribution["energy_out_length"] + end = start + size + data[start:end] = value + + +@njit +def energy_out_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["energy_out_offset"] + size = tabulated_energy_angle_distribution["energy_out_length"] + end = start + size + data[end - 1] = value + + +@njit +def energy_out_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["energy_out_offset"] + end = start + length + data[start:end] = value + + +@njit +def pdf(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["pdf_offset"] + data[offset + index] = value + + +@njit +def pdf_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["pdf_offset"] + size = tabulated_energy_angle_distribution["pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def pdf_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["pdf_offset"] + size = tabulated_energy_angle_distribution["pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def pdf_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cdf(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["cdf_offset"] + data[offset + index] = value + + +@njit +def cdf_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cdf_offset"] + size = tabulated_energy_angle_distribution["cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cdf_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cdf_offset"] + size = tabulated_energy_angle_distribution["cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cdf_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["cdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cosine_offset_(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["cosine_offset__offset"] + data[offset + index] = value + + +@njit +def cosine_offset__all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_offset__offset"] + size = tabulated_energy_angle_distribution["cosine_offset__length"] + end = start + size + data[start:end] = value + + +@njit +def cosine_offset__last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_offset__offset"] + size = tabulated_energy_angle_distribution["cosine_offset__length"] + end = start + size + data[end - 1] = value + + +@njit +def cosine_offset__chunk( + start, length, tabulated_energy_angle_distribution, data, value +): + start += tabulated_energy_angle_distribution["cosine_offset__offset"] + end = start + length + data[start:end] = value + + +@njit +def cosine(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["cosine_offset"] + data[offset + index] = value + + +@njit +def cosine_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_offset"] + size = tabulated_energy_angle_distribution["cosine_length"] + end = start + size + data[start:end] = value + + +@njit +def cosine_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_offset"] + size = tabulated_energy_angle_distribution["cosine_length"] + end = start + size + data[end - 1] = value + + +@njit +def cosine_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["cosine_offset"] + end = start + length + data[start:end] = value + + +@njit +def cosine_pdf(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["cosine_pdf_offset"] + data[offset + index] = value + + +@njit +def cosine_pdf_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_pdf_offset"] + size = tabulated_energy_angle_distribution["cosine_pdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cosine_pdf_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_pdf_offset"] + size = tabulated_energy_angle_distribution["cosine_pdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cosine_pdf_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["cosine_pdf_offset"] + end = start + length + data[start:end] = value + + +@njit +def cosine_cdf(index, tabulated_energy_angle_distribution, data, value): + offset = tabulated_energy_angle_distribution["cosine_cdf_offset"] + data[offset + index] = value + + +@njit +def cosine_cdf_all(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_cdf_offset"] + size = tabulated_energy_angle_distribution["cosine_cdf_length"] + end = start + size + data[start:end] = value + + +@njit +def cosine_cdf_last(tabulated_energy_angle_distribution, data, value): + start = tabulated_energy_angle_distribution["cosine_cdf_offset"] + size = tabulated_energy_angle_distribution["cosine_cdf_length"] + end = start + size + data[end - 1] = value + + +@njit +def cosine_cdf_chunk(start, length, tabulated_energy_angle_distribution, data, value): + start += tabulated_energy_angle_distribution["cosine_cdf_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/tally.py b/mcdc/mcdc_set/tally.py new file mode 100644 index 000000000..71968b069 --- /dev/null +++ b/mcdc/mcdc_set/tally.py @@ -0,0 +1,293 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def scores(index, tally, data, value): + offset = tally["scores_offset"] + data[offset + index] = value + + +@njit +def scores_all(tally, data, value): + start = tally["scores_offset"] + size = tally["scores_length"] + end = start + size + data[start:end] = value + + +@njit +def scores_last(tally, data, value): + start = tally["scores_offset"] + size = tally["scores_length"] + end = start + size + data[end - 1] = value + + +@njit +def scores_chunk(start, length, tally, data, value): + start += tally["scores_offset"] + end = start + length + data[start:end] = value + + +@njit +def multipliers(index, tally, data, value): + offset = tally["multipliers_offset"] + data[offset + index] = value + + +@njit +def multipliers_all(tally, data, value): + start = tally["multipliers_offset"] + size = tally["multipliers_length"] + end = start + size + data[start:end] = value + + +@njit +def multipliers_last(tally, data, value): + start = tally["multipliers_offset"] + size = tally["multipliers_length"] + end = start + size + data[end - 1] = value + + +@njit +def multipliers_chunk(start, length, tally, data, value): + start += tally["multipliers_offset"] + end = start + length + data[start:end] = value + + +@njit +def mu(index, tally, data, value): + offset = tally["mu_offset"] + data[offset + index] = value + + +@njit +def mu_all(tally, data, value): + start = tally["mu_offset"] + size = tally["mu_length"] + end = start + size + data[start:end] = value + + +@njit +def mu_last(tally, data, value): + start = tally["mu_offset"] + size = tally["mu_length"] + end = start + size + data[end - 1] = value + + +@njit +def mu_chunk(start, length, tally, data, value): + start += tally["mu_offset"] + end = start + length + data[start:end] = value + + +@njit +def azi(index, tally, data, value): + offset = tally["azi_offset"] + data[offset + index] = value + + +@njit +def azi_all(tally, data, value): + start = tally["azi_offset"] + size = tally["azi_length"] + end = start + size + data[start:end] = value + + +@njit +def azi_last(tally, data, value): + start = tally["azi_offset"] + size = tally["azi_length"] + end = start + size + data[end - 1] = value + + +@njit +def azi_chunk(start, length, tally, data, value): + start += tally["azi_offset"] + end = start + length + data[start:end] = value + + +@njit +def energy(index, tally, data, value): + offset = tally["energy_offset"] + data[offset + index] = value + + +@njit +def energy_all(tally, data, value): + start = tally["energy_offset"] + size = tally["energy_length"] + end = start + size + data[start:end] = value + + +@njit +def energy_last(tally, data, value): + start = tally["energy_offset"] + size = tally["energy_length"] + end = start + size + data[end - 1] = value + + +@njit +def energy_chunk(start, length, tally, data, value): + start += tally["energy_offset"] + end = start + length + data[start:end] = value + + +@njit +def time(index, tally, data, value): + offset = tally["time_offset"] + data[offset + index] = value + + +@njit +def time_all(tally, data, value): + start = tally["time_offset"] + size = tally["time_length"] + end = start + size + data[start:end] = value + + +@njit +def time_last(tally, data, value): + start = tally["time_offset"] + size = tally["time_length"] + end = start + size + data[end - 1] = value + + +@njit +def time_chunk(start, length, tally, data, value): + start += tally["time_offset"] + end = start + length + data[start:end] = value + + +@njit +def bin(index, tally, data, value): + offset = tally["bin_offset"] + data[offset + index] = value + + +@njit +def bin_all(tally, data, value): + start = tally["bin_offset"] + size = tally["bin_length"] + end = start + size + data[start:end] = value + + +@njit +def bin_last(tally, data, value): + start = tally["bin_offset"] + size = tally["bin_length"] + end = start + size + data[end - 1] = value + + +@njit +def bin_chunk(start, length, tally, data, value): + start += tally["bin_offset"] + end = start + length + data[start:end] = value + + +@njit +def bin_sum(index, tally, data, value): + offset = tally["bin_sum_offset"] + data[offset + index] = value + + +@njit +def bin_sum_all(tally, data, value): + start = tally["bin_sum_offset"] + size = tally["bin_sum_length"] + end = start + size + data[start:end] = value + + +@njit +def bin_sum_last(tally, data, value): + start = tally["bin_sum_offset"] + size = tally["bin_sum_length"] + end = start + size + data[end - 1] = value + + +@njit +def bin_sum_chunk(start, length, tally, data, value): + start += tally["bin_sum_offset"] + end = start + length + data[start:end] = value + + +@njit +def bin_sum_square(index, tally, data, value): + offset = tally["bin_sum_square_offset"] + data[offset + index] = value + + +@njit +def bin_sum_square_all(tally, data, value): + start = tally["bin_sum_square_offset"] + size = tally["bin_sum_square_length"] + end = start + size + data[start:end] = value + + +@njit +def bin_sum_square_last(tally, data, value): + start = tally["bin_sum_square_offset"] + size = tally["bin_sum_square_length"] + end = start + size + data[end - 1] = value + + +@njit +def bin_sum_square_chunk(start, length, tally, data, value): + start += tally["bin_sum_square_offset"] + end = start + length + data[start:end] = value + + +@njit +def bin_shape(index, tally, data, value): + offset = tally["bin_shape_offset"] + data[offset + index] = value + + +@njit +def bin_shape_all(tally, data, value): + start = tally["bin_shape_offset"] + size = tally["bin_shape_length"] + end = start + size + data[start:end] = value + + +@njit +def bin_shape_last(tally, data, value): + start = tally["bin_shape_offset"] + size = tally["bin_shape_length"] + end = start + size + data[end - 1] = value + + +@njit +def bin_shape_chunk(start, length, tally, data, value): + start += tally["bin_shape_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/uniform_mesh.py b/mcdc/mcdc_set/uniform_mesh.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/uniform_mesh.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/universe.py b/mcdc/mcdc_set/universe.py new file mode 100644 index 000000000..a398e1a6b --- /dev/null +++ b/mcdc/mcdc_set/universe.py @@ -0,0 +1,32 @@ +# The following is automatically generated by code_factory.py + +from numba import njit + + +@njit +def cell_IDs(index, universe, data, value): + offset = universe["cell_IDs_offset"] + data[offset + index] = value + + +@njit +def cell_IDs_all(universe, data, value): + start = universe["cell_IDs_offset"] + size = universe["N_cell"] + end = start + size + data[start:end] = value + + +@njit +def cell_IDs_last(universe, data, value): + start = universe["cell_IDs_offset"] + size = universe["N_cell"] + end = start + size + data[end - 1] = value + + +@njit +def cell_IDs_chunk(start, length, universe, data, value): + start += universe["cell_IDs_offset"] + end = start + length + data[start:end] = value diff --git a/mcdc/mcdc_set/weight_roulette.py b/mcdc/mcdc_set/weight_roulette.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/weight_roulette.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/mcdc_set/weighted_emission.py b/mcdc/mcdc_set/weighted_emission.py new file mode 100644 index 000000000..fdbf8e750 --- /dev/null +++ b/mcdc/mcdc_set/weighted_emission.py @@ -0,0 +1,3 @@ +# The following is automatically generated by code_factory.py + +from numba import njit diff --git a/mcdc/object_/.gitignore b/mcdc/object_/.gitignore new file mode 100644 index 000000000..765e2d898 --- /dev/null +++ b/mcdc/object_/.gitignore @@ -0,0 +1 @@ +numba_types.py diff --git a/mcdc/object_/base.py b/mcdc/object_/base.py new file mode 100644 index 000000000..07ca30b58 --- /dev/null +++ b/mcdc/object_/base.py @@ -0,0 +1,378 @@ +from mcdc.print_ import print_error + + +# ====================================================================================== +# Object base classes +# ====================================================================================== + + +class ObjectBase: + def __init__(self, register): + if register and isinstance(self, ObjectNonSingleton): + register_object(self) + + if "non_numba" in dir(self): + self.non_numba += ["non_numba", "label"] + else: + self.non_numba = ["non_numba", "label"] + + def __setattr__(self, key, value): + hints = getattr(self.__class__, "__annotations__", {}) + if key in hints and not check_type(value, hints[key], self.__class__, self): + print_error(f"{key} must be {hints[key]!r}, got {value!r}") + super().__setattr__(key, value) + + +class ObjectSingleton(ObjectBase): + def __init__(self): + super().__init__(register=False) + + +class ObjectNonSingleton(ObjectBase): + ID: int + + def __init__(self, register=True): + self.ID = -1 + super().__init__(register) + + if "non_numba" in dir(self): + self.non_numba += ["ID"] + else: + self.non_numba = ["ID"] + + +class ObjectPolymorphic(ObjectNonSingleton): + child_ID: int + type: int + + def __init__(self, type_, register=True): + self.child_ID = -1 + self.type = type_ + super().__init__(register) + + self.non_numba += ["child_ID"] + + +# ====================================================================================== +# Helper functions +# ====================================================================================== + + +def register_object(object_): + from mcdc.object_.simulation import simulation + + from mcdc.object_.cell import Region, Cell + from mcdc.object_.universe import Universe, Lattice + from mcdc.object_.data import DataBase + from mcdc.object_.distribution import DistributionBase + from mcdc.object_.material import MaterialBase + from mcdc.object_.mesh import MeshBase + from mcdc.object_.nuclide import Nuclide + from mcdc.object_.reaction import ReactionBase + from mcdc.object_.source import Source + from mcdc.object_.surface import Surface + from mcdc.object_.tally import TallyBase + + object_list = [] + if isinstance(object_, Cell): + object_list = simulation.cells + elif isinstance(object_, DataBase): + object_list = simulation.data + elif isinstance(object_, DistributionBase): + object_list = simulation.distributions + elif isinstance(object_, Lattice): + object_list = simulation.lattices + elif isinstance(object_, MaterialBase): + object_list = simulation.materials + elif isinstance(object_, MeshBase): + object_list = simulation.meshes + elif isinstance(object_, Nuclide): + object_list = simulation.nuclides + elif isinstance(object_, ReactionBase): + object_list = simulation.reactions + elif isinstance(object_, Region): + object_list = simulation.regions + elif isinstance(object_, Source): + object_list = simulation.sources + elif isinstance(object_, Surface): + object_list = simulation.surfaces + elif isinstance(object_, TallyBase): + object_list = simulation.tallies + elif isinstance(object_, Universe): + object_list = simulation.universes + else: + print_error(f"Unidentified object list for object {object_}") + + object_.ID = len(object_list) + if isinstance(object_, ObjectPolymorphic): + object_.child_ID = sum([x.type == object_.type for x in object_list]) + object_list.append(object_) + + +# ====================================================================================== +# Type checker +# ====================================================================================== + + +import re +import numpy as np +from typing import get_origin, get_args, Union, Annotated + + +def _name_from_str(s: str) -> str: + s = _strip_prefixes(s) + # strip generic args like "NDArray[float64]" → "NDArray" + s = s.split("[", 1)[0] + return s.split(".")[-1].strip() + + +def _mro_name_match(value, want: str) -> bool: + """Subclass-friendly match without resolving: compare wanted name to any base in MRO.""" + want_name = _name_from_str(want) + return any(base.__name__ == want_name for base in value.__class__.mro()) + + +# ---------- helpers for STRING annotations ---------- +_ANN_RE = re.compile(r"^\s*(?:typing\.)?Annotated\[(.*)\]\s*$") + + +def _split_top_level(s: str, sep: str = ",", brackets: str = "[]()") -> list[str]: + out, buf, depth = [], [], 0 + opens = set(brackets[::2]) + closes = set(brackets[1::2]) + pairs = dict(zip(brackets[1::2], brackets[::2])) + for ch in s: + if ch in opens: + depth += 1 + elif ch in closes: + depth -= 1 + if ch == sep and depth == 0: + out.append("".join(buf).strip()) + buf = [] + else: + buf.append(ch) + if buf: + out.append("".join(buf).strip()) + return out + + +def _strip_prefixes(s: str) -> str: + # normalize common module prefixes used in annotations + return ( + s.replace("typing.", "") + .replace("numpy.typing.", "") + .replace("numpy.", "") + .replace("np.", "") + ) + + +def _parse_annotated_str(hint_str: str): + """ + If hint_str is 'Annotated[ ... ]', return (base_str, meta_list) else None. + meta_list items remain raw strings (no eval). + """ + m = _ANN_RE.match(_strip_prefixes(hint_str)) + if not m: + return None + inner = m.group(1) + parts = _split_top_level(inner, sep=",") + if not parts: + return None + base = parts[0].strip() + meta = [p.strip() for p in parts[1:]] + return base, meta + + +def _shape_tuple_from_str(s: str): + """ + Parse '(3,)', '(None, 3)', '(2,3,4)' → tuple[int|None, ...] or None if not a shape. + """ + s = s.strip() + if not (s.startswith("(") and s.endswith(")")): + return None + body = s[1:-1].strip() + if not body: + return () + items = _split_top_level(body, sep=",") + out = [] + for it in items: + it = it.strip() + if it == "": + continue # allow trailing comma + if it == "None": + out.append(None) + else: + try: + out.append(int(it)) + except ValueError: + return None + return tuple(out) + + +def _is_ndarray_base_str(base_str: str) -> bool: + base_norm = _strip_prefixes(base_str) + return base_norm.startswith("NDArray[") or base_norm.startswith("ndarray[") + + +def _extract_ndarray_dtype_key_from_str(base_str: str) -> str | None: + base_norm = _strip_prefixes(base_str) + if "[" not in base_norm or "]" not in base_norm: + return None + inside = base_norm[base_norm.find("[") + 1 : base_norm.rfind("]")].strip() + return _strip_prefixes(inside) # e.g. 'float' or 'float64' + + +def _dtype_matches(arr: np.ndarray, dtype_key: str | None) -> bool: + if dtype_key is None: + return True + key = dtype_key.lower() + if key == "float": + return np.issubdtype(arr.dtype, np.floating) + if key == "int": + return np.issubdtype(arr.dtype, np.integer) + try: + return arr.dtype == np.dtype(key) # e.g. 'float64', 'int32' + except TypeError: + return True # unknown key → do not fail hard + + +def _shape_matches(arr: np.ndarray, shape: tuple[int | None, ...]) -> bool: + if arr.ndim != len(shape): + return False + return all(dim is None or dim == s for s, dim in zip(arr.shape, shape)) + + +# ---------- main checker ---------- +def check_type(value, hint, cls, obj=None) -> bool: + """ + Best-effort runtime checker tolerant of *string* annotations (no eval). + Supports: + - typing objects: list[T], set[T], dict[K,V], tuple[...,], Union/|, Annotated + - string 'Annotated[NDArray[float], (shape,)]' (dtype+shape) + - plain string class names (accept subclasses via MRO) + - string unions 'A | B' + """ + # -------- STRING annotations path (no resolution) -------- + if isinstance(hint, str): + h = hint.strip() + + # Handle plain "NDArray[...]" (dtype-only) without Annotated + if _is_ndarray_base_str(h): + if not isinstance(value, np.ndarray): + return False + dtype_key = _extract_ndarray_dtype_key_from_str(h) + return _dtype_matches(value, dtype_key) + + # String Annotated[...] + parsed = _parse_annotated_str(h) + if parsed: + base_str, meta = parsed + + # NDArray with shape metadata + if _is_ndarray_base_str(base_str) and meta: + shape = _shape_tuple_from_str(meta[0]) + dtype_key = _extract_ndarray_dtype_key_from_str(base_str) + if not isinstance(value, np.ndarray): + return False + if shape is not None and not _shape_matches(value, shape): + return False + return _dtype_matches(value, dtype_key) + + # Otherwise treat base as class-like name → accept subclasses via MRO + return _mro_name_match(value, base_str) + + # String union: "A | B" + if "|" in h: + parts = _split_top_level(h, sep="|") + return any(check_type(value, p.strip(), cls) for p in parts) + + # Simple string container: "list[str]" (lightweight support) + if h.startswith("list[") and h.endswith("]"): + inner = _name_from_str(h[5:-1]) + if not isinstance(value, list): + return False + if inner == "str": + return all(isinstance(x, str) for x in value) + if inner in ("float", "float32", "float64"): + return all(isinstance(x, (float, int)) for x in value) + return True # permissive other inners + + # Plain forward-ref name → subclass-friendly check + return _mro_name_match(value, h) + + # -------- Structured typing objects path -------- + origin = get_origin(hint) + + # Annotated[T, meta...] (real object) + if origin is Annotated: + base, *meta = get_args(hint) + if isinstance(value, np.ndarray) and meta and isinstance(meta[0], tuple): + expected_shape = meta[0] + base_args = get_args(base) # e.g., NDArray[dtype] + dtype_key = None + if base_args: + dtype_arg = base_args[0] + if dtype_arg is float: + dtype_key = "float" + elif hasattr(dtype_arg, "name"): # np.float64 + dtype_key = dtype_arg.name + expected_shape_list = list(expected_shape) + for i, item in enumerate(expected_shape): + if type(item) == str: + expected_shape_list[i] = getattr(obj, item) + expected_shape = tuple(expected_shape_list) + return _shape_matches(value, expected_shape) and _dtype_matches( + value, dtype_key + ) + return check_type(value, base, cls) + + # NDArray[...] without shape meta + if origin is np.ndarray: + return isinstance(value, np.ndarray) + + # Builtins / classes + if origin is None: + try: + return isinstance(value, hint) + except TypeError: + return True + + # list[T] + if origin is list: + (t,) = get_args(hint) + return isinstance(value, list) and all(check_type(x, t, cls) for x in value) + + # set[T] + if origin is set: + (t,) = get_args(hint) + return isinstance(value, set) and all(check_type(x, t, cls) for x in value) + + # dict[K, V] + if origin is dict: + kt, vt = get_args(hint) + return isinstance(value, dict) and all( + check_type(k, kt, cls) and check_type(v, vt, cls) for k, v in value.items() + ) + + # tuple[T1, T2] or tuple[T, ...] + if origin is tuple: + args = get_args(hint) + if len(args) == 2 and args[1] is Ellipsis: + return isinstance(value, tuple) and all( + check_type(x, args[0], cls) for x in value + ) + return ( + isinstance(value, tuple) + and len(value) == len(args) + and all(check_type(x, t, cls) for x, t in zip(value, args)) + ) + + # Union[...] (incl Optional[T]) + if origin is Union: + return any(check_type(value, t, cls) for t in get_args(hint)) + + # Fallback: ABCs (Iterable, Sequence, etc.) + try: + return isinstance(value, origin) + except TypeError: + return True diff --git a/mcdc/object_/cell.py b/mcdc/object_/cell.py new file mode 100644 index 000000000..3b968eb40 --- /dev/null +++ b/mcdc/object_/cell.py @@ -0,0 +1,285 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from mcdc.object_.surface import Surface + +#### + +import numpy as np +import sympy + +from numpy import float64 +from numpy.typing import NDArray +from operator import attrgetter +from types import NoneType +from typing import Annotated, Iterable +from sympy.logic.boolalg import Boolean + +#### + +from mcdc.constant import ( + BOOL_AND, + BOOL_NOT, + BOOL_OR, + FILL_LATTICE, + FILL_MATERIAL, + FILL_NONE, + FILL_UNIVERSE, + PI, +) +from mcdc.object_.base import ObjectNonSingleton +from mcdc.object_.material import MaterialBase +from mcdc.object_.simulation import simulation +from mcdc.object_.tally import TallyCell +from mcdc.object_.universe import Universe, Lattice +from mcdc.print_ import print_error + +# ====================================================================================== +# Region +# ====================================================================================== + + +# Region-making helper that checks if an identical region is already created +def make_region(type_, A, B): + for existing_region in simulation.regions: + if ( + type_ == existing_region.type + and A == existing_region.A + and B == existing_region.B + ): + return existing_region + return Region(type_, A, B) + + +class Region(ObjectNonSingleton): + type: str + A: Surface | Region | NoneType + B: Region | int | NoneType + + def __init__(self, type_, A, B): + super().__init__() + + self.type = type_ + self.A = A + self.B = B + + @classmethod + def make_halfspace(cls, surface, sense): + region = make_region("halfspace", surface, sense) + return region + + def __and__(self, other): + return make_region("intersection", self, other) + + def __or__(self, other): + return make_region("union", self, other) + + def __invert__(self): + return make_region("complement", self, None) + + def __repr__(self): + text = "Region: " + if self.type == "halfspace": + if self.B > 0: + text += "+s%i" % self.A.ID + else: + text += "-s%i" % self.A.ID + elif self.type == "intersection": + text += "r%i & r%i" % (self.A.ID, self.B.ID) + elif self.type == "union": + text += "r%i | r%i" % (self.A.ID, self.B.ID) + elif self.type == "complement": + text += "~r%i" % (self.A.ID) + elif self.type == "all": + text += "all" + + return text + + +# ====================================================================================== +# Cell +# ====================================================================================== + + +class Cell(ObjectNonSingleton): + # Annotations for Numba mode + label: str = "cell" + non_numba: list[str] = ["region", "fill", "region_RPN"] + # + name: str + region: Region + fill: MaterialBase | Universe | Lattice | NoneType + fill_translated: bool + fill_rotated: bool + translation: Annotated[NDArray[float64], (3,)] + rotation: Annotated[NDArray[float64], (3,)] + region_RPN_tokens: list[int] + region_RPN: Boolean + surfaces: list[Surface] + tallies: list[TallyCell] + # + fill_type: int + fill_ID: int + + def __init__( + self, + region: Region | NoneType = None, + fill: MaterialBase | Universe | Lattice | NoneType = None, + name: str = "", + translation: Iterable[float] = [0.0, 0.0, 0.0], + rotation: Iterable[float] = [0.0, 0.0, 0.0], + ): + super().__init__() + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.ID}" + + # Set region + if region is None: + self.region = make_region("all", None, None) + else: + self.region = region + + # Set fill + self.fill = fill + + # Local coordinate modifier + self.translation = np.array(translation, dtype=float) + self.rotation = np.array(rotation, dtype=float) + self.fill_translated = False + self.fill_rotated = False + if (self.translation != 0.0).any(): + self.fill_translated = True + if (self.rotation != 0.0).any(): + self.fill_rotated = True + # Convert ritation + self.rotation *= PI / 180.0 + + # Set region Reversed Polished Notation (RPN) + if self.region.type != "all": + self.region_RPN_tokens = generate_RPN_tokens(self.region) + self.region_RPN = generate_RPN(self.region_RPN_tokens) + else: + self.region_RPN_tokens = [] + self.region_RPN = Boolean(True) + + # List surfaces + self.surfaces = list_surfaces(self.region_RPN_tokens) + + # Cell tallies + self.tallies = [] + + # ============================================================================== + # Numba attribute manual set up + # ============================================================================== + + # Numba representation of the cell fill + # (Because polymorphic Ffill object is not supported) + if isinstance(fill, MaterialBase): + self.fill_type = FILL_MATERIAL + self.fill_ID = fill.ID + elif isinstance(fill, Universe): + self.fill_type = FILL_UNIVERSE + self.fill_ID = fill.ID + elif isinstance(fill, Lattice): + self.fill_type = FILL_LATTICE + self.fill_ID = fill.ID + elif fill == None: + self.fill_type = FILL_NONE + self.fill_ID = -1 + else: + print_error(f"Unsupported cell fill: {fill}") + + def __repr__(self): + text = "\n" + text += f"Cell\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - {self.region}\n" + if isinstance(self.fill, MaterialBase): + text += f" - Fill (material): {self.fill.name}\n" + elif isinstance(self.fill, Lattice): + text += f" - Fill (lattice): {self.fill.name}\n" + elif isinstance(self.fill, Universe): + text += f" - Fill (universe): {self.fill.name}\n" + if self.fill_translated: + text += f" - Translation: {self.translation}\n" + if self.fill_rotated: + text += f" - Rotation: {self.rotation * 180 / PI}\n" + text += f" - Bounding surfaces: {[x.ID for x in self.surfaces]}\n" + if len(self.tallies) > 0: + text += f" - Tallies: {[x.ID for x in self.tallies]}\n" + return text + + +def generate_RPN_tokens(region): + # The RPN tokens + rpn_tokens = [] + + # Build RPN based on recursive evaluation of the region + stack = [region] + while len(stack) > 0: + token = stack.pop() + if isinstance(token, Region): + if token.type == "halfspace": + rpn_tokens.append(token.A.ID) + if token.B < 0: + rpn_tokens.append(BOOL_NOT) + elif token.type == "intersection": + stack += ["&", token.A, token.B] + elif token.type == "union": + stack += ["|", token.A, token.B] + elif token.type == "complement": + stack += ["~", token.A] + else: + if token == "&": + rpn_tokens.append(BOOL_AND) + elif token == "|": + rpn_tokens.append(BOOL_OR) + elif token == "~": + rpn_tokens.append(BOOL_NOT) + else: + print_error(f"Unrecognized token in the generating region RPN: {token}") + + return rpn_tokens + + +def generate_RPN(rpn_tokens): + stack = [] + + for token in rpn_tokens: + if token >= 0: + stack.append(sympy.symbols(f"s{token}")) + else: + if token == BOOL_AND or token == BOOL_OR: + item_1 = stack.pop() + item_2 = stack.pop() + if token == BOOL_AND: + stack.append(item_1 & item_2) + else: + stack.append(item_1 | item_2) + + elif token == BOOL_NOT: + item = stack.pop() + if isinstance(item, Region): + item = sympy.symbols(str(item)[8:]) + + stack.append(~item) + + return sympy.logic.boolalg.simplify_logic(stack[0]) + + +def list_surfaces(rpn_tokens): + surfaces = [] + + for token in rpn_tokens: + if token >= 0: + surface = simulation.surfaces[token] + if surface not in surfaces: + surfaces.append(surface) + + return sorted(surfaces, key=attrgetter("ID")) diff --git a/mcdc/object_/data.py b/mcdc/object_/data.py new file mode 100644 index 000000000..b7c50f39f --- /dev/null +++ b/mcdc/object_/data.py @@ -0,0 +1,114 @@ +from numpy import float64 +from numpy.typing import NDArray + +#### + +from mcdc.constant import ( + DATA_NONE, + DATA_TABLE, + DATA_POLYNOMIAL, + INTERPOLATION_LINEAR, + INTERPOLATION_LOG, +) +from mcdc.object_.base import ObjectPolymorphic +from mcdc.print_ import print_1d_array + + +# ====================================================================================== +# Data base class +# ====================================================================================== + + +class DataBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "data" + + def __init__(self, type_, register=True): + super().__init__(type_, register) + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + return text + + +def decode_type(type_): + if type_ == DATA_NONE: + return "Data (None)" + elif type_ == DATA_TABLE: + return "Data (Table)" + elif type_ == DATA_POLYNOMIAL: + return "Data (Polynomial function)" + + +# ====================================================================================== +# None +# ====================================================================================== +# Placeholder for data that does not need to store anything: +# - Fission multiplicity and delayed precursor data for non-fissionable nuclide + + +class DataNone(DataBase): + # Annotations for Numba mode + label: str = "none_data" + + def __init__(self): + type_ = DATA_NONE + super().__init__(type_, False) + self.ID = 0 + + +# ====================================================================================== +# Table data +# ====================================================================================== + + +class DataTable(DataBase): + # Annotations for Numba mode + label: str = "table_data" + # + x: NDArray[float64] + y: NDArray[float64] + interpolation: int + + def __init__(self, x, y, interpolation=INTERPOLATION_LINEAR): + type_ = DATA_TABLE + super().__init__(type_) + + self.x = x + self.y = y + self.interpolation = interpolation + + def __repr__(self): + text = super().__repr__() + text += f" - x {print_1d_array(self.x)}\n" + text += f" - y {print_1d_array(self.y)}\n" + if self.interpolation == INTERPOLATION_LINEAR: + text += f" - Interpolation: linear\n" + elif self.interpolation == INTERPOLATION_LOG: + text += f" - Interpolation: log\n" + return text + + +# ====================================================================================== +# Polynomial data +# ====================================================================================== + + +class DataPolynomial(DataBase): + # Annotations for Numba mode + label: str = "polynomial_data" + # + coefficients: NDArray[float64] + + def __init__(self, coeffs): + type_ = DATA_POLYNOMIAL + super().__init__(type_) + + self.coefficients = coeffs + + def __repr__(self): + text = super().__repr__() + text += f" - coefficients {print_1d_array(self.coefficients)}\n" + return text diff --git a/mcdc/object_/distribution.py b/mcdc/object_/distribution.py new file mode 100644 index 000000000..6f71d7d43 --- /dev/null +++ b/mcdc/object_/distribution.py @@ -0,0 +1,416 @@ +import numpy as np + +from numpy import float64, int64 +from numpy.typing import NDArray + +#### + +from mcdc.constant import ( + DISTRIBUTION_NONE, + DISTRIBUTION_PMF, + DISTRIBUTION_TABULATED, + DISTRIBUTION_MULTITABLE, + DISTRIBUTION_LEVEL_SCATTERING, + DISTRIBUTION_EVAPORATION, + DISTRIBUTION_MAXWELLIAN, + DISTRIBUTION_KALBACH_MANN, + DISTRIBUTION_TABULATED_ENERGY_ANGLE, + DISTRIBUTION_N_BODY, +) +from mcdc.object_.base import ObjectPolymorphic +from mcdc.object_.data import DataTable +from mcdc.object_.util import cdf_from_pdf, multi_cdf_from_pdf, cmf_from_pmf +from mcdc.print_ import print_1d_array + + +# ====================================================================================== +# Distribution base class +# ====================================================================================== + + +class DistributionBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "distribution" + + def __init__(self, type_, register=True): + super().__init__(type_, register) + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + return text + + +def decode_type(type_): + if type_ == DISTRIBUTION_NONE: + return "Distribution (None)" + elif type_ == DISTRIBUTION_PMF: + return "Distribution (PMF)" + elif type_ == DISTRIBUTION_TABULATED: + return "Distribution (Tabulated)" + elif type_ == DISTRIBUTION_MULTITABLE: + return "Distribution (Multi Table)" + elif type_ == DISTRIBUTION_LEVEL_SCATTERING: + return "Distribution (Level scattering)" + elif type_ == DISTRIBUTION_EVAPORATION: + return "Distribution (Evaporation)" + elif type_ == DISTRIBUTION_MAXWELLIAN: + return "Distribution (Maxwellian spectrum)" + elif type_ == DISTRIBUTION_KALBACH_MANN: + return "Distribution (Kalbach-Mann)" + elif type_ == DISTRIBUTION_TABULATED_ENERGY_ANGLE: + return "Distribution (Tabulated energy-angle)" + elif type_ == DISTRIBUTION_N_BODY: + return "Distribution (N-body)" + + +# ====================================================================================== +# None +# ====================================================================================== +# Placeholder for distribution that does not need to store data: +# - Isotropic +# - Energy-correlated angle (stored in the energy distribution) + + +class DistributionNone(DistributionBase): + # Annotations for Numba mode + label: str = "none_distribution" + + def __init__(self): + type_ = DISTRIBUTION_NONE + super().__init__(type_, False) + self.ID = 0 + + +# ====================================================================================== +# Probability Mass Function (PMF) +# ====================================================================================== + + +class DistributionPMF(DistributionBase): + # Annotations for Numba mode + label: str = "pmf_distribution" + # + value: NDArray[float64] + pmf: NDArray[float64] + cmf: NDArray[float64] + + def __init__(self, value, pmf): + type_ = DISTRIBUTION_PMF + super().__init__(type_) + + self.value = value + self.pmf = pmf + + self.pmf, self.cmf = cmf_from_pmf(pmf) + + def __repr__(self): + text = super().__repr__() + text += f" - value {print_1d_array(self.value)}\n" + text += f" - pmf {print_1d_array(self.pmf)}\n" + return text + + +# ====================================================================================== +# Tabulated +# ====================================================================================== + + +class DistributionTabulated(DistributionBase): + # Annotations for Numba mode + label: str = "tabulated_distribution" + # + value: NDArray[float64] + pdf: NDArray[float64] + cdf: NDArray[float64] + + def __init__(self, value, pdf): + type_ = DISTRIBUTION_TABULATED + super().__init__(type_) + + self.value = value + self.pdf = pdf + + self.pdf, self.cdf = cdf_from_pdf(value, pdf) + + def __repr__(self): + text = super().__repr__() + text += f" - value {print_1d_array(self.value)}\n" + text += f" - pdf {print_1d_array(self.pdf)}\n" + return text + + +# ====================================================================================== +# Multi-table +# ====================================================================================== + + +class DistributionMultiTable(DistributionBase): + # Annotations for Numba mode + label: str = "multi_table_distribution" + # + grid: NDArray[float64] + offset: NDArray[int64] + value: NDArray[float64] + pdf: NDArray[float64] + cdf: NDArray[float64] + + def __init__(self, grid, offset, value, pdf): + type_ = DISTRIBUTION_MULTITABLE + super().__init__(type_) + + self.grid = grid + self.offset = offset + self.value = value + self.pdf = pdf + + self.pdf, self.cdf = multi_cdf_from_pdf(offset, value, pdf) + + def __repr__(self): + text = super().__repr__() + text += f" - grid {print_1d_array(self.grid)}\n" + text += f" - offset {print_1d_array(self.offset)}\n" + text += f" - value {print_1d_array(self.value)}\n" + text += f" - pdf {print_1d_array(self.pdf)}\n" + return text + + +# ====================================================================================== +# Level scattering +# ====================================================================================== + + +class DistributionLevelScattering(DistributionBase): + # Annotations for Numba mode + label: str = "level_scattering_distribution" + # + C1: float + C2: float + + def __init__(self, C1, C2): + type_ = DISTRIBUTION_LEVEL_SCATTERING + super().__init__(type_) + + self.C1 = C1 + self.C2 = C2 + + def __repr__(self): + text = super().__repr__() + text += f" - C1 {print_1d_array(self.C1)} [/eV^l]\n" + text += f" - C2: {self.C2}\n" + return text + + +# ====================================================================================== +# Evaporation +# ====================================================================================== + + +class DistributionEvaporation(DistributionBase): + # Annotations for Numba mode + label: str = "evaporation_distribution" + # + nuclear_temperature: DataTable + restriction_energy: float + + def __init__( + self, + nuclear_temperature_energy_grid, + nuclear_temperature_value, + restriction_energy, + ): + type_ = DISTRIBUTION_EVAPORATION + super().__init__(type_) + + self.restriction_energy = restriction_energy + self.nuclear_temperature = DataTable( + nuclear_temperature_energy_grid, nuclear_temperature_value + ) + + def __repr__(self): + text = super().__repr__() + text += f" - Restriction energy: {self.restriction_energy} [eV]\n" + text += f" - Nuclear temperature {print_1d_array(self.nuclear_temperature.y)} [eV]\n" + text += f" - Nuclear temperature energy grid {print_1d_array(self.nuclear_temperature.x)} [eV]\n" + return text + + +# ====================================================================================== +# Maxwellian distribution +# ====================================================================================== + + +class DistributionMaxwellian(DistributionBase): + # Annotations for Numba mode + label: str = "maxwellian_distribution" + # + nuclear_temperature: DataTable + restriction_energy: float + + def __init__( + self, + nuclear_temperature_energy_grid, + nuclear_temperature_value, + restriction_energy, + temperature_interpolation, + ): + type_ = DISTRIBUTION_MAXWELLIAN + super().__init__(type_) + + self.restriction_energy = restriction_energy + self.nuclear_temperature = DataTable( + nuclear_temperature_energy_grid, + nuclear_temperature_value, + temperature_interpolation, + ) + + def __repr__(self): + text = super().__repr__() + text += f" - Restriction energy: {self.restriction_energy} [eV]\n" + text += f" - Nuclear temperature {print_1d_array(self.nuclear_temperature.y)} [eV]\n" + text += f" - Nuclear temperature energy grid {print_1d_array(self.nuclear_temperature.x)} [eV]\n" + return text + + +# ====================================================================================== +# Kalbach-Mann +# ====================================================================================== + + +class DistributionKalbachMann(DistributionBase): + # Annotations for Numba mode + label: str = "kalbach_mann_distribution" + # + energy: NDArray[float64] + offset: NDArray[int64] + energy_out: NDArray[float64] + pdf: NDArray[float64] + cdf: NDArray[float64] + precompound_factor: NDArray[float64] + angular_slope: NDArray[float64] + + def __init__( + self, energy, offset, energy_out, pdf, precompound_factor, angular_slope + ): + type_ = DISTRIBUTION_KALBACH_MANN + super().__init__(type_) + + self.energy = energy + self.offset = offset + + self.energy_out = energy_out + self.pdf = pdf + + self.precompound_factor = precompound_factor + self.angular_slope = angular_slope + + self.pdf, self.cdf = multi_cdf_from_pdf(offset, energy_out, pdf) + + def __repr__(self): + text = super().__repr__() + text += f" - grid {print_1d_array(self.energy)} [eV]\n" + text += f" - offset {print_1d_array(self.offset)}\n" + text += f" - energy {print_1d_array(self.energy_out)} [eV]\n" + text += f" - energy-pdf {print_1d_array(self.pdf)} [/eV]\n" + text += f" - precompound factor {print_1d_array(self.precompound_factor)}\n" + text += f" - angular slope {print_1d_array(self.angular_slope)}\n" + return text + + +# ====================================================================================== +# Tabulated energy-angle +# ====================================================================================== + + +class DistributionTabulatedEnergyAngle(DistributionBase): + # Annotations for Numba mode + label: str = "tabulated_energy_angle_distribution" + # + energy: NDArray[float64] + offset: NDArray[int64] + energy_out: NDArray[float64] + pdf: NDArray[float64] + cdf: NDArray[float64] + cosine_offset_: NDArray[int64] # "cosine_offset" is reserved to describe "cosine" + cosine: NDArray[float64] + cosine_pdf: NDArray[float64] + cosine_cdf: NDArray[float64] + + def __init__( + self, energy, offset, energy_out, pdf, cosine_offset, cosine, cosine_pdf + ): + type_ = DISTRIBUTION_TABULATED_ENERGY_ANGLE + super().__init__(type_) + + self.energy = energy + self.offset = offset + + self.energy_out = energy_out + self.pdf = pdf + self.cosine_offset_ = cosine_offset + + self.cosine = cosine + self.cosine_pdf = cosine_pdf + + self.pdf, self.cdf = multi_cdf_from_pdf(offset, energy_out, pdf) + + self.cosine_cdf = np.zeros_like(self.cosine_pdf) + for i in range(len(offset)): + start = offset[i] + if i + 1 < len(offset): + end = offset[i + 1] + else: + end = len(cosine) + inner_offset = cosine_offset[start:end] + + start = inner_offset[0] + if i + 1 < len(offset): + end = cosine_offset[end] + else: + end = len(cosine) + + inner_offset_local = inner_offset - inner_offset[0] + self.cosine_pdf[start:end], self.cosine_cdf[start:end] = multi_cdf_from_pdf( + inner_offset_local, cosine[start:end], cosine_pdf[start:end] + ) + + def __repr__(self): + text = super().__repr__() + text += f" - grid {print_1d_array(self.energy)} [eV]\n" + text += f" - offset {print_1d_array(self.offset)}\n" + text += f" - energy {print_1d_array(self.energy_out)} [eV]\n" + text += f" - energy-pdf {print_1d_array(self.pdf)} [/eV]\n" + text += f" - cosine-offset {print_1d_array(self.cosine_offset_)}\n" + text += f" - cosine {print_1d_array(self.cosine)}\n" + text += f" - cosine-pdf {print_1d_array(self.cosine_pdf)}\n" + return text + + +# ====================================================================================== +# N-Body +# ====================================================================================== + + +class DistributionNBody(DistributionBase): + # Annotations for Numba mode + label: str = "nbody_distribution" + # + value: NDArray[float64] + pdf: NDArray[float64] + cdf: NDArray[float64] + + def __init__(self, value, pdf): + type_ = DISTRIBUTION_N_BODY + super().__init__(type_) + + self.value = value + self.pdf = pdf + + self.pdf, self.cdf = cdf_from_pdf(value, pdf) + + def __repr__(self): + text = super().__repr__() + text += f" - value {print_1d_array(self.value)}\n" + text += f" - pdf {print_1d_array(self.pdf)}\n" + return text diff --git a/mcdc/object_/gpu_tools.py b/mcdc/object_/gpu_tools.py new file mode 100644 index 000000000..a7ad7d3cd --- /dev/null +++ b/mcdc/object_/gpu_tools.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass +from numpy import uint64 + +#### + +from mcdc.object_.base import ObjectSingleton + + +@dataclass +class GPUMeta(ObjectSingleton): + # Annotations for Numba mode + label: str = "gpu_meta" + # + state_pointer: uint64 = uint64(0) + source_program_pointer: uint64 = uint64(0) + precursor_program_pointer: uint64 = uint64(0) + structure_pointer: uint64 = uint64(0) + data_pointer: uint64 = uint64(0) diff --git a/mcdc/object_/material.py b/mcdc/object_/material.py new file mode 100644 index 000000000..cfbd7d47a --- /dev/null +++ b/mcdc/object_/material.py @@ -0,0 +1,323 @@ +import numpy as np +import os + +from numpy import float64 +from numpy.typing import NDArray +from types import NoneType +from typing import Annotated + +#### + +from mcdc.constant import MATERIAL, MATERIAL_MG +from mcdc.object_.base import ObjectPolymorphic +from mcdc.object_.nuclide import Nuclide +from mcdc.object_.simulation import simulation +from mcdc.print_ import print_1d_array, print_error + +# ====================================================================================== +# Material base class +# ====================================================================================== + + +class MaterialBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "material" + # + name: str + fissionable: bool + + def __init__(self, type_, name): + super().__init__(type_) + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.child_ID}" + + self.fissionable = False + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - Fissionable: {self.fissionable}\n" + return text + + +def decode_type(type_): + if type_ == MATERIAL: + return "Material" + elif type_ == MATERIAL_MG: + return "Multigroup material" + + +# ====================================================================================== +# Native material +# ====================================================================================== + + +class Material(MaterialBase): + # Annotations for Numba mode + label: str = "native_material" + non_numba: list[str] = ["nuclide_composition"] + # + nuclide_composition: dict[Nuclide, float] + # + nuclides: list[Nuclide] + nuclide_densities: NDArray[float64] + + def __init__( + self, + name: str = "", + nuclide_composition: dict[str, float] = {}, + temperature: float = 293.6, + ): + type_ = MATERIAL + super().__init__(type_, name) + + # Temperature + self.temperature = temperature + + # Dictionary connecting nuclides to respective densities + self.nuclide_composition = {} + + # Numba representation of nuclide_composition + self.nuclides = [] + self.nuclide_densities = np.zeros(len(nuclide_composition)) + + # Check if library directory is set + lib_dir = os.getenv("MCDC_LIB") + if lib_dir is None: + print_error("Environment variable MCDC_LIB is not set") + + # Loop over the items in the composition + for i, (key, value) in enumerate(nuclide_composition.items()): + nuclide_name = key + nuclide_density = value + + # Get supported temperature + nearest_temperature = min(TEMPERATURES, key=lambda x: abs(x - temperature)) + + # Check if nuclide-temperature is available in the library + file_name = f"{nuclide_name}-{nearest_temperature}K.h5" + if not file_name in os.listdir(lib_dir): + print_error( + f"Nuclide {nuclide_name} at temperature {nearest_temperature} K is not available in the library" + ) + + # Check if nuclide is already created + found = False + for nuclide in simulation.nuclides: + if ( + nuclide.name == nuclide_name + and nearest_temperature == nuclide.temperature + ): + found = True + break + + # Create the nuclide to objects if needed + if not found: + nuclide = Nuclide(nuclide_name, nearest_temperature) + + # Register the nuclide composition + self.nuclides.append(nuclide) + self.nuclide_densities[i] = nuclide_density + self.nuclide_composition[nuclide] = nuclide_density + + # Some flags + if nuclide.fissionable: + self.fissionable = True + + def __repr__(self): + text = super().__repr__() + text += f" - Temperature: {self.temperature} K\n" + text += f" - Nuclide composition [atoms/barn-cm]\n" + for nuclide in self.nuclide_composition.keys(): + text += f" - {nuclide.name:<5} | {self.nuclide_composition[nuclide]}\n" + return text + + +# Currently supported temperatures +TEMPERATURES = [0.1, 233.15, 273.15, 293.6, 600.0, 900.0, 1200.0, 2500.0] + + +# ====================================================================================== +# Multigroup material +# ====================================================================================== + + +class MaterialMG(MaterialBase): + # Annotations for Numba mode + label: str = "multigroup_material" + # + G: int + J: int + mgxs_speed: Annotated[NDArray[float64], ("G",)] + mgxs_decay_rate: Annotated[NDArray[float64], ("J",)] + mgxs_capture: Annotated[NDArray[float64], ("G",)] + mgxs_scatter: Annotated[NDArray[float64], ("G",)] + mgxs_fission: Annotated[NDArray[float64], ("G",)] + mgxs_total: Annotated[NDArray[float64], ("G",)] + mgxs_nu_s: Annotated[NDArray[float64], ("G",)] + mgxs_nu_p: Annotated[NDArray[float64], ("G",)] + mgxs_nu_d: Annotated[NDArray[float64], ("G", "J")] + mgxs_nu_d_total: Annotated[NDArray[float64], ("G",)] + mgxs_nu_f: Annotated[NDArray[float64], ("G",)] + mgxs_chi_s: Annotated[NDArray[float64], ("G", "G")] + mgxs_chi_p: Annotated[NDArray[float64], ("G", "G")] + mgxs_chi_d: Annotated[NDArray[float64], ("J", "G")] + + def __init__( + self, + name: str = "", + capture: NDArray[float64] | NoneType = None, + scatter: NDArray[float64] | NoneType = None, + fission: NDArray[float64] | NoneType = None, + nu_s: NDArray[float64] | NoneType = None, + nu_p: NDArray[float64] | NoneType = None, + nu_d: NDArray[float64] | NoneType = None, + chi_p: NDArray[float64] | NoneType = None, + chi_d: NDArray[float64] | NoneType = None, + speed: NDArray[float64] | NoneType = None, + decay_rate: NDArray[float64] | NoneType = None, + ): + type_ = MATERIAL_MG + super().__init__(type_, name) + + # Energy group size + if capture is not None: + G = len(capture) + elif scatter is not None: + G = len(scatter) + elif fission is not None: + G = len(fission) + else: + print_error("Need to supply capture, scatter, or fission for MaterialMG") + self.G = G + + # Delayed group size + J = 0 + if nu_d is not None: + J = len(nu_d) + self.J = J + + # Allocate the attributes + self.mgxs_speed = np.ones(G) + self.mgxs_decay_rate = np.ones(J) * np.inf + self.mgxs_capture = np.zeros(G) + self.mgxs_scatter = np.zeros(G) + self.mgxs_fission = np.zeros(G) + self.mgxs_total = np.zeros(G) + self.mgxs_nu_s = np.ones(G) + self.mgxs_nu_p = np.zeros(G) + self.mgxs_nu_d = np.zeros([G, J]) + self.mgxs_nu_d_total = np.zeros([G]) + self.mgxs_nu_f = np.zeros(G) + self.mgxs_chi_s = np.zeros([G, G]) + self.mgxs_chi_p = np.zeros([G, G]) + self.mgxs_chi_d = np.zeros([J, G]) + + # Speed (vector of size G) + if speed is not None: + self.mgxs_speed = speed + + # Decay constant (vector of size J) + if decay_rate is not None: + self.mgxs_decay_rate = decay_rate + + # Cross-sections (vector of size G) + if capture is not None: + self.mgxs_capture = capture + if scatter is not None: + self.mgxs_scatter = np.sum(scatter, 0) + if fission is not None: + self.mgxs_fission = fission + self.fissionable = True + self.mgxs_total = self.mgxs_capture + self.mgxs_scatter + self.mgxs_fission + + # Scattering multiplication (vector of size G) + if nu_s is not None: + self.mgxs_nu_s = nu_s + + # Check if nu_p or nu_d is not provided, give fission + if fission is not None: + if nu_p is None and nu_d is None: + print_error("Need to supply nu_p or nu_d for fissionable MaterialMG") + + # Prompt fission production (vector of size G) + if nu_p is not None: + self.mgxs_nu_p = nu_p + + # Delayed fission production (matrix of size GxJ) + if nu_d is not None: + # Transpose: [dg, gin] -> [gin, dg] + self.mgxs_nu_d = np.swapaxes(nu_d, 0, 1)[:, :] + self.mgxs_nu_d_total = np.sum(self.mgxs_nu_d, axis=1) + + # Total fission production (vector of size G) + self.mgxs_nu_f = np.zeros_like(self.mgxs_nu_p) + self.mgxs_nu_f += self.mgxs_nu_p + for j in range(J): + self.mgxs_nu_f += self.mgxs_nu_d[:, j] + + # Scattering spectrum (matrix of size GxG) + if scatter is not None: + # Transpose: [gout, gin] -> [gin, gout] + self.mgxs_chi_s = np.swapaxes(scatter, 0, 1)[:, :] + for g in range(G): + if self.mgxs_scatter[g] > 0.0: + self.mgxs_chi_s[g, :] /= self.mgxs_scatter[g] + + # Prompt fission spectrum (matrix of size GxG) + if nu_p is not None: + if G == 1: + self.mgxs_chi_p[:, :] = np.array([[1.0]]) + elif chi_p is None: + print_error("Need to supply chi_p if nu_p is provided and G > 1") + else: + # Convert 1D spectrum to 2D + if chi_p.ndim == 1: + tmp = np.zeros((G, G)) + for g in range(G): + tmp[:, g] = chi_p + chi_p = tmp + # Transpose: [gout, gin] -> [gin, gout] + self.mgxs_chi_p[:, :] = np.swapaxes(chi_p, 0, 1)[:, :] + # Normalize + for g in range(G): + if np.sum(self.mgxs_chi_p[g, :]) > 0.0: + self.mgxs_chi_p[g, :] /= np.sum(self.mgxs_chi_p[g, :]) + + # Delayed fission spectrum (matrix of size JxG) + if nu_d is not None: + if G == 1: + self.mgxs_chi_d = np.ones([J, G]) + else: + if chi_d is None: + print_error("Need to supply chi_d if nu_d is provided and G > 1") + # Transpose: [gout, dg] -> [dg, gout] + self.mgxs_chi_d = np.swapaxes(chi_d, 0, 1)[:, :] + # Normalize + for dg in range(J): + if np.sum(self.mgxs_chi_d[dg, :]) > 0.0: + self.mgxs_chi_d[dg, :] /= np.sum(self.mgxs_chi_d[dg, :]) + + def __repr__(self): + text = super().__repr__() + text += f" - Multigroup data\n" + text += f" - G: {self.G}\n" + text += f" - J: {self.J}\n" + text += f" - Sigma_c {print_1d_array(self.mgxs_capture)}\n" + text += f" - Sigma_s {print_1d_array(self.mgxs_scatter)}\n" + text += f" - Sigma_f {print_1d_array(self.mgxs_fission)}\n" + text += f" - nu_s {print_1d_array(self.mgxs_nu_s)}\n" + text += f" - nu_p {print_1d_array(self.mgxs_nu_p)}\n" + text += f" - nu_d {print_1d_array(self.mgxs_nu_d.flatten())}\n" + text += f" - chi_s {print_1d_array(self.mgxs_chi_s.flatten())}\n" + text += f" - chi_fp {print_1d_array(self.mgxs_chi_p.flatten())}\n" + text += f" - chi_fd {print_1d_array(self.mgxs_chi_d.flatten())}\n" + text += f" - speed {print_1d_array(self.mgxs_speed)}\n" + text += f" - lambda {print_1d_array(self.mgxs_decay_rate)}\n" + return text diff --git a/mcdc/object_/mesh.py b/mcdc/object_/mesh.py new file mode 100644 index 000000000..8d1ce9545 --- /dev/null +++ b/mcdc/object_/mesh.py @@ -0,0 +1,147 @@ +from typing import Iterable +import numpy as np + +from numpy import float64 +from numpy.typing import NDArray + +#### + +from mcdc.constant import INF, MESH_STRUCTURED, MESH_UNIFORM +from mcdc.object_.base import ObjectPolymorphic +from mcdc.print_ import print_1d_array + + +# ====================================================================================== +# Mesh base class +# ====================================================================================== + + +class MeshBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "mesh" + # + name: str + N_bin: int + Nx: int + Ny: int + Nz: int + + def __init__(self, type_, name): + super().__init__(type_) + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.child_ID}" + + self.N_bin = 0 + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - # of bins: {self.N_bin}\n" + return text + + +def decode_type(type_): + if type_ == MESH_UNIFORM: + return "Uniform mesh" + elif type_ == MESH_STRUCTURED: + return "Structured mesh" + + +# ====================================================================================== +# Uniform mesh +# ====================================================================================== + + +class MeshUniform(MeshBase): + # Annotations for Numba mode + label: str = "uniform_mesh" + # + x0: float + dx: float + Nx: int + y0: float + dy: float + Ny: int + z0: float + dz: float + Nz: int + + def __init__( + self, + name: str = "", + x: tuple[float, float, int] = (-INF, 2 * INF, 1), + y: tuple[float, float, int] = (-INF, 2 * INF, 1), + z: tuple[float, float, int] = (-INF, 2 * INF, 1), + ): + type_ = MESH_UNIFORM + super().__init__(type_, name) + + # Set the grid + self.x0 = x[0] + self.dx = x[1] + self.Nx = x[2] + self.y0 = y[0] + self.dy = y[1] + self.Ny = y[2] + self.z0 = z[0] + self.dz = z[1] + self.Nz = z[2] + + self.N_bin = self.Nx * self.Ny * self.Nz + + def __repr__(self): + text = super().__repr__() + text += f" - Grid specification\n" + text += f" - (x0, dx, Nx): ({self.x0}, {self.dx}, {self.Nx}) [cm]\n" + text += f" - (y0, dy, Ny): ({self.y0}, {self.dy}, {self.Ny}) [cm]\n" + text += f" - (z0, dz, Nz): ({self.z0}, {self.dz}, {self.Nz}) [cm]\n" + return text + + +# ====================================================================================== +# Structured mesh +# ====================================================================================== + + +class MeshStructured(MeshBase): + # Annotations for Numba mode + label: str = "structured_mesh" + # + x: NDArray[float64] + y: NDArray[float64] + z: NDArray[float64] + + def __init__( + self, + name: str = "", + x: Iterable[float] = [-INF, INF], + y: Iterable[float] = [-INF, INF], + z: Iterable[float] = [-INF, INF], + ): + type_ = MESH_STRUCTURED + super().__init__(type_, name) + + # Set the grid + self.x = np.array(x) + self.y = np.array(y) + self.z = np.array(z) + + self.Nx = len(self.x) - 1 + self.Ny = len(self.y) - 1 + self.Nz = len(self.z) - 1 + + self.N_bin = self.Nx * self.Ny * self.Nz + + def __repr__(self): + text = super().__repr__() + text += f" - Grid specification\n" + text += f" - x {print_1d_array(self.x)} cm\n" + text += f" - y {print_1d_array(self.y)} cm\n" + text += f" - z {print_1d_array(self.z)} cm\n" + return text diff --git a/mcdc/object_/nuclide.py b/mcdc/object_/nuclide.py new file mode 100644 index 000000000..db27f020f --- /dev/null +++ b/mcdc/object_/nuclide.py @@ -0,0 +1,243 @@ +import h5py +import numpy as np +import os + +from numpy import float64 +from numpy.typing import NDArray + +#### + +from mcdc.object_.base import ObjectNonSingleton +from mcdc.object_.data import DataBase, DataPolynomial, DataTable +from mcdc.object_.distribution import DistributionBase +from mcdc.object_.reaction import ( + ReactionNeutronCapture, + ReactionNeutronElasticScattering, + ReactionNeutronFission, + ReactionNeutronInelasticScattering, + decode_type, + set_energy_distribution, +) +from mcdc.object_.simulation import simulation +from mcdc.print_ import print_1d_array, print_error + +# ====================================================================================== +# Nuclide +# ====================================================================================== + + +class Nuclide(ObjectNonSingleton): + # Annotations for Numba mode + label: str = "nuclide" + # + name: str + temperature: float + atomic_weight_ratio: float + fissionable: bool + excitation_level: int + xs_energy_grid: NDArray[float64] + total_xs: NDArray[float64] + elastic_xs: NDArray[float64] + capture_xs: NDArray[float64] + inelastic_xs: NDArray[float64] + fission_xs: NDArray[float64] + elastic_scattering_reactions: list[ReactionNeutronElasticScattering] + capture_reactions: list[ReactionNeutronCapture] + inelastic_scattering_reactions: list[ReactionNeutronInelasticScattering] + fission_reactions: list[ReactionNeutronFission] + fission_prompt_multiplicity: DataBase + fission_delayed_multiplicity: DataBase + N_fission_delayed_precursor: int + fission_delayed_fractions: NDArray[float64] + fission_delayed_decay_rates: NDArray[float64] + fission_delayed_spectra: list[DistributionBase] + + def __init__(self, nuclide_name, temperature): + super().__init__() + + self.name = nuclide_name + self.temperature = temperature + + # Set attributes from the hdf5 file + dir_name = os.getenv("MCDC_LIB") + file_name = f"{nuclide_name}-{temperature}K.h5" + file = h5py.File(f"{dir_name}/{file_name}", "r") + + # Basic properties + self.atomic_weight_ratio = file["atomic_weight_ratio"][()] + self.fissionable = bool(file["fissionable"][()]) + self.excitation_level = int(file["excitation_level"][()]) + + # The reactions + rx_names = [ + "elastic_scattering", + "capture", + "inelastic_scattering", + "fission", + ] + + # The reaction MTs + MTs = {} + for name in rx_names: + if name not in file["neutron_reactions"]: + MTs[name] = [] + continue + + MTs[name] = [ + x for x in file[f"neutron_reactions/{name}"] if x.startswith("MT") + ] + + # ========================================================================== + # Reaction XS + # ========================================================================== + + # Energy grid + xs_energy = file["neutron_reactions/xs_energy_grid"][()] * 1e6 # MeV to eV + self.xs_energy_grid = xs_energy + + # The total XS + self.total_xs = np.zeros_like(self.xs_energy_grid) + self.elastic_xs = np.zeros_like(self.xs_energy_grid) + self.capture_xs = np.zeros_like(self.xs_energy_grid) + self.inelastic_xs = np.zeros_like(self.xs_energy_grid) + self.fission_xs = np.zeros_like(self.xs_energy_grid) + + xs_containers = [ + self.elastic_xs, + self.capture_xs, + self.inelastic_xs, + self.fission_xs, + ] + for xs_container, rx_name in list(zip(xs_containers, rx_names)): + for MT in MTs[rx_name]: + xs = file[f"neutron_reactions/{rx_name}/{MT}/xs"] + xs_container[xs.attrs["offset"] :] += xs[()] + + self.total_xs = ( + self.elastic_xs + self.capture_xs + self.inelastic_xs + self.fission_xs + ) + + # ========================================================================== + # The reactions + # ========================================================================== + + self.elastic_scattering_reactions = [] + self.capture_reactions = [] + self.inelastic_scattering_reactions = [] + self.fission_reactions = [] + + rx_containers = [ + self.elastic_scattering_reactions, + self.capture_reactions, + self.inelastic_scattering_reactions, + self.fission_reactions, + ] + rx_classes = [ + ReactionNeutronElasticScattering, + ReactionNeutronCapture, + ReactionNeutronInelasticScattering, + ReactionNeutronFission, + ] + for rx_container, rx_name, rx_class in list( + zip(rx_containers, rx_names, rx_classes) + ): + for MT in MTs[rx_name]: + h5_group = file[f"neutron_reactions/{rx_name}/{MT}"] + reaction = rx_class.from_h5_group(h5_group) + rx_container.append(reaction) + + # ============================================================================== + # Fission nuclide attributes + # ============================================================================== + + if not self.fissionable: + self.fission_prompt_multiplicity = simulation.data[0] + self.fission_delayed_multiplicity = simulation.data[0] + self.N_fission_delayed_precursor = 0 + self.fission_delayed_fractions = np.zeros(0) + self.fission_delayed_decay_rates = np.zeros(0) + self.fission_delayed_spectra = [] + else: + fission_group = file["neutron_reactions/fission"] + + # Multiplicities + self.fission_prompt_multiplicity = set_fission_multiplicity( + fission_group["prompt_multiplicity"] + ) + self.fission_delayed_multiplicity = set_fission_multiplicity( + fission_group["delayed_multiplicity"] + ) + + # Delayed fractions and decay rates + self.fission_delayed_fractions = fission_group[ + "delayed_neutron_precursors/fractions" + ][()] + self.fission_delayed_decay_rates = fission_group[ + "delayed_neutron_precursors/decay_rates" + ][()] + self.N_fission_delayed_precursor = len(self.fission_delayed_fractions) + + # Delayed spectra + self.fission_delayed_spectra = [] + spectrum_names = [ + x + for x in fission_group["delayed_neutron_precursors"] + if x.startswith("energy_spectrum-") + ] + for spectrum_name in spectrum_names: + self.fission_delayed_spectra.append( + set_energy_distribution( + fission_group[f"delayed_neutron_precursors/{spectrum_name}"] + ) + ) + + file.close() + + def __repr__(self): + text = "\n" + text += f"Nuclide\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - Atomic weight ratio: {self.atomic_weight_ratio}\n" + text += f" - Reaction MTs\n" + text += f" - Elastic scattering: {[int(x.MT) for x in self.elastic_scattering_reactions]}\n" + text += f" - Capture: {[int(x.MT) for x in self.capture_reactions]}\n" + text += f" - Inelastic scattering: {[int(x.MT) for x in self.inelastic_scattering_reactions]}\n" + if self.fissionable: + text += f" - Fission: {[int(x.MT) for x in self.fission_reactions]}\n" + text += f" - Reaction cross-sections (eV, barns)\n" + text += f" - Energy grid {print_1d_array(self.xs_energy_grid)}\n" + text += f" - Total {print_1d_array(self.total_xs)}\n" + text += f" - Elastic scattering {print_1d_array(self.elastic_xs)}\n" + text += f" - Capture {print_1d_array(self.capture_xs)}\n" + text += f" - Inelastic scattering {print_1d_array(self.inelastic_xs)}\n" + if self.fissionable: + text += f" - Fission {print_1d_array(self.fission_xs)}\n" + return text + + +# ====================================================================================== +# Helper functions +# ====================================================================================== + + +def set_fission_multiplicity(h5_group): + multiplicity_type = h5_group.attrs["type"] + + if multiplicity_type == "tabulated": + x = h5_group["energy"][()] * 1e6 # MeV to eV + y = h5_group["value"][()] + multiplicity = DataTable(x, y) + + elif multiplicity_type == "polynomial": + coefficient = h5_group["coefficient"][()] + + # MeV-based to eV-based + for l in range(len(coefficient)): + coefficient[l] /= 1e6**l + + multiplicity = DataPolynomial(coefficient) + else: + print_error(f"Unsupported multiplicity of type {multiplicity_type}") + + return multiplicity diff --git a/mcdc/object_/particle.py b/mcdc/object_/particle.py new file mode 100644 index 000000000..93c486b30 --- /dev/null +++ b/mcdc/object_/particle.py @@ -0,0 +1,52 @@ +import numpy as np + +from dataclasses import dataclass, field +from typing import Annotated +from numpy import int64, uint +from numpy.typing import NDArray + +#### + +from mcdc.constant import PARTICLE_NEUTRON +from mcdc.object_.base import ObjectBase, ObjectSingleton + + +@dataclass +class ParticleData(ObjectBase): + label: str = "particle_data" + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + t: float = 0.0 + ux: float = 0.0 + uy: float = 0.0 + uz: float = 0.0 + g: int = -1 + E: float = 0.0 + w: float = 0.0 + particle_type: int = PARTICLE_NEUTRON + rng_seed: uint = uint(1) + + +@dataclass +class Particle(ParticleData): + label: str = "particle" + cell_ID: int = -1 + material_ID: int = -1 + surface_ID: int = -1 + alive: bool = False + fresh: bool = False + event: int = -1 + + +class ParticleBank(ObjectSingleton): + label: str = "particle_bank" + non_numba: list[str] = ["particles"] + particles: list[ParticleData] = [] + size: Annotated[NDArray[int64], (1,)] + tag: str = "" + + def __init__(self, tag): + super().__init__() + self.tag = tag + self.size = np.zeros(1, dtype=int64) diff --git a/mcdc/object_/reaction.py b/mcdc/object_/reaction.py new file mode 100644 index 000000000..4b0c34c2e --- /dev/null +++ b/mcdc/object_/reaction.py @@ -0,0 +1,399 @@ +from typing import Annotated +from numpy import float64 +from numpy.typing import NDArray + +#### + +import mcdc.object_.distribution as distribution + +from mcdc.constant import ( + ANGLE_ISOTROPIC, + ANGLE_ENERGY_CORRELATED, + ANGLE_DISTRIBUTED, + INTERPOLATION_LINEAR, + INTERPOLATION_LOG, + REACTION_NEUTRON_CAPTURE, + REACTION_NEUTRON_ELASTIC_SCATTERING, + REACTION_NEUTRON_FISSION, + REACTION_NEUTRON_INELASTIC_SCATTERING, + REFERENCE_FRAME_COM, + REFERENCE_FRAME_LAB, +) +from mcdc.object_.base import ObjectPolymorphic +from mcdc.object_.distribution import ( + DistributionBase, + DistributionMultiTable, + DistributionLevelScattering, + DistributionEvaporation, + DistributionMaxwellian, + DistributionKalbachMann, + DistributionTabulatedEnergyAngle, + DistributionNBody, +) +from mcdc.object_.simulation import simulation +from mcdc.print_ import print_1d_array, print_error + + +# ====================================================================================== +# Reaction base class +# ====================================================================================== + + +class ReactionBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "reaction" + # + MT: int + xs: NDArray[float64] + xs_offset_: int # "xs_offset" ir reserved for "xs" + reference_frame: int + + def __init__(self, type_, MT, xs, xs_offset, reference_frame): + super().__init__(type_) + self.MT = MT + self.xs = xs + self.xs_offset_ = xs_offset + self.reference_frame = reference_frame + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + text += f" - MT: {self.MT}\n" + text += f" - XS {print_1d_array(self.xs)} barn\n" + text += f" - Reference frame: {decode_reference_frame(self.reference_frame)}\n" + return text + + +def decode_type(type_): + if type_ == REACTION_NEUTRON_ELASTIC_SCATTERING: + return "Neutron elastic scattering" + elif type_ == REACTION_NEUTRON_CAPTURE: + return "Neutron capture" + elif type_ == REACTION_NEUTRON_INELASTIC_SCATTERING: + return "Neutron inelastic scattering" + elif type_ == REACTION_NEUTRON_FISSION: + return "Neutron fission" + + +def decode_reference_frame(type_): + if type_ == REFERENCE_FRAME_LAB: + return "Laboratory" + elif type_ == REFERENCE_FRAME_COM: + return "Center of mass" + + +# ====================================================================================== +# Neutron elastic scattering +# ====================================================================================== + + +class ReactionNeutronElasticScattering(ReactionBase): + # Annotations for Numba mode + label: str = "neutron_elastic_scattering_reaction" + # + mu_table: DistributionMultiTable + + def __init__(self, MT, xs, xs_offset, reference_frame, mu): + type_ = REACTION_NEUTRON_ELASTIC_SCATTERING + super().__init__(type_, MT, xs, xs_offset, reference_frame) + self.mu_table = mu + + @classmethod + def from_h5_group(cls, h5_group): + MT, xs, xs_offset, reference_frame = set_basic_properties(h5_group) + _, mu = set_angular_distribution(h5_group["angular_cosine_distribution"]) + return cls(MT, xs, xs_offset, reference_frame, mu) + + def __repr__(self): + text = super().__repr__() + text += f" - Scattering cosine: {distribution.decode_type(self.mu_table.type)} [ID: {self.mu_table.ID}]\n" + return text + + +# ====================================================================================== +# Neutron capture +# ====================================================================================== + + +class ReactionNeutronCapture(ReactionBase): + # Annotations for Numba mode + label: str = "neutron_capture_reaction" + + def __init__(self, MT, xs, xs_offset, reference_frame): + type_ = REACTION_NEUTRON_CAPTURE + super().__init__(type_, MT, xs, xs_offset, reference_frame) + + @classmethod + def from_h5_group(cls, h5_group): + MT, xs, xs_offset, reference_frame = set_basic_properties(h5_group) + return cls(MT, xs, xs_offset, reference_frame) + + +# ====================================================================================== +# Neutron inelastic scattering +# ====================================================================================== + + +class ReactionNeutronInelasticScattering(ReactionBase): + # Annotations for Numba mode + label: str = "neutron_inelastic_scattering_reaction" + # + multiplicity: int + angle_type: int + mu: DistributionBase + N_spectrum_probability_bin: int + N_spectrum: int + spectrum_probability_grid: NDArray[float64] + spectrum_probability: Annotated[ + NDArray[float64], ("N_spectrum_probability_bin", "N_spectrum") + ] + energy_spectra: list[DistributionBase] + + def __init__( + self, + MT, + xs, + xs_offset, + reference_frame, + multiplicity, + angle_type, + mu, + spectrum_probability_grid, + spectrum_probability, + energy_spectra, + ): + type_ = REACTION_NEUTRON_INELASTIC_SCATTERING + super().__init__(type_, MT, xs, xs_offset, reference_frame) + + self.reference_frame = reference_frame + self.multiplicity = multiplicity + self.angle_type = angle_type + self.mu = mu + self.N_spectrum_probability_bin = len(spectrum_probability_grid) - 1 + self.N_spectrum = len(energy_spectra) + self.spectrum_probability_grid = spectrum_probability_grid + self.spectrum_probability = spectrum_probability + self.energy_spectra = energy_spectra + + @classmethod + def from_h5_group(cls, h5_group): + MT, xs, xs_offset, reference_frame = set_basic_properties(h5_group) + multiplicity = int(h5_group["multiplicity"][()]) + + angle_type, mu = set_angular_distribution( + h5_group["angular_cosine_distribution"] + ) + + # Energy spectra + spectrum_probability_grid = ( + h5_group[f"spectrum_probability_grid"][()] * 1e6 + ) # MeV to eV + spectrum_probability = h5_group[f"spectrum_probability"][()] + energy_spectra = [] + spectrum_names = [x for x in h5_group if x.startswith("energy_spectrum-")] + for spectrum_name in spectrum_names: + energy_spectra.append(set_energy_distribution(h5_group[f"{spectrum_name}"])) + + return cls( + MT, + xs, + xs_offset, + reference_frame, + multiplicity, + angle_type, + mu, + spectrum_probability_grid, + spectrum_probability, + energy_spectra, + ) + + def __repr__(self): + text = super().__repr__() + if self.angle_type == ANGLE_ISOTROPIC: + text += f" - Scattering cosine: Isotropic\n" + elif self.angle_type == ANGLE_ENERGY_CORRELATED: + text += f" - Scattering cosine: Energy-correlated\n" + else: + text += f" - Scattering cosine: {distribution.decode_type(self.mu.type)} [ID: {self.mu.ID}]\n" + text += f" - Energy spectra\n" + text += f" - Probability energy grid {print_1d_array(self.spectrum_probability_grid)}\n" + for i in range(len(self.energy_spectra)): + text += f" - Spectrum {i+1}: {distribution.decode_type(self.energy_spectra[i])} [{print_1d_array(self.spectrum_probability[:,i])}] [ID: {self.energy_spectra[i].ID}]\n" + return text + + +# ====================================================================================== +# Neutron fission +# ====================================================================================== + + +class ReactionNeutronFission(ReactionBase): + # Annotations for Numba mode + label: str = "neutron_fission_reaction" + # + angle_type: int + mu: DistributionBase + spectrum: DistributionBase + + def __init__( + self, + MT, + xs, + xs_offset, + reference_frame, + angle_type, + mu, + spectrum, + ): + type_ = REACTION_NEUTRON_FISSION + super().__init__(type_, MT, xs, xs_offset, reference_frame) + self.angle_type = angle_type + self.mu = mu + self.spectrum = spectrum + + @classmethod + def from_h5_group(cls, h5_group): + MT, xs, xs_offset, reference_frame = set_basic_properties(h5_group) + + # Prompt angular distribution + angle_type, mu = set_angular_distribution( + h5_group["angular_cosine_distribution"] + ) + + # Prompt spectrum + spectrum_names = [x for x in h5_group if x.startswith("energy_spectrum-")] + if len(spectrum_names) > 1: + print_error("Unsupported multi-distribution prompt fission spectrum") + spectrum = set_energy_distribution(h5_group[f"energy_spectrum-1"]) + + return cls(MT, xs, xs_offset, reference_frame, angle_type, mu, spectrum) + + def __repr__(self): + text = super().__repr__() + text += f" - Prompt neutron\n" + if self.angle_type == ANGLE_ISOTROPIC: + text += f" - Emission cosine: Isotropic\n" + elif self.angle_type == ANGLE_ENERGY_CORRELATED: + text += f" - Emission cosine: Energy-correlated\n" + else: + text += f" - Emission cosine: {distribution.decode_type(self.mu.type)} [ID: {self.mu.ID}]\n" + text += f" - Energy spectrum: {distribution.decode_type(self.spectrum)} [ID: {self.spectrum.ID}]\n" + + return text + + +# ====================================================================================== +# Helper functions +# ====================================================================================== + + +def set_basic_properties(h5_group): + MT = h5_group.attrs["MT"][()] + xs = h5_group["xs"][()] + xs_offset = h5_group["xs"].attrs["offset"] + reference_frame = h5_group["reference_frame"][()].decode("utf-8") + if reference_frame == "LAB": + reference_frame = REFERENCE_FRAME_LAB + elif reference_frame == "COM": + reference_frame = REFERENCE_FRAME_COM + return MT, xs, xs_offset, reference_frame + + +def set_angular_distribution(h5_group): + mu_type = h5_group.attrs["type"] + if mu_type == "isotropic": + angle_type = ANGLE_ISOTROPIC + mu = simulation.distributions[0] + elif mu_type == "energy-correlated": + angle_type = ANGLE_ENERGY_CORRELATED + mu = simulation.distributions[0] + else: + angle_type = ANGLE_DISTRIBUTED + grid = h5_group[f"energy"][()] * 1e6 # MeV to eV + offset = h5_group[f"offset"][()] + value = h5_group[f"value"][()] + pdf = h5_group[f"pdf"][()] + mu = DistributionMultiTable(grid, offset, value, pdf) + + return angle_type, mu + + +def set_energy_distribution(h5_group): + spectrum_type = h5_group.attrs["type"] + + if spectrum_type == "tabulated": + grid = h5_group[f"energy"][()] * 1e6 # MeV to eV + offset = h5_group[f"offset"][()] + value = h5_group[f"value"][()] * 1e6 # MeV to eV + pdf = h5_group[f"pdf"][()] / 1e6 # /MeV to /eV + energy_spectrum = DistributionMultiTable(grid, offset, value, pdf) + + elif spectrum_type == "level-scattering": + C1 = h5_group["C1"][()] * 1e6 # MeV to eV + C2 = h5_group["C2"][()] + + energy_spectrum = DistributionLevelScattering(C1, C2) + + elif spectrum_type == "evaporation": + energy = h5_group[f"temperature_energy_grid"][()] * 1e6 # MeV to eV + temperature = h5_group[f"temperature"][()] * 1e6 # MeV to eV + restriction_energy = h5_group[f"restriction_energy"][()] * 1e6 # MeV to eV + + energy_spectrum = DistributionEvaporation( + energy, temperature, restriction_energy + ) + + elif spectrum_type == "maxwellian": + energy = h5_group[f"temperature_energy_grid"][()] * 1e6 # MeV to eV + temperature = h5_group[f"temperature"][()] * 1e6 # MeV to eV + restriction_energy = h5_group[f"restriction_energy"][()] * 1e6 # MeV to eV + interpolation = h5_group[f"temperature_interpolation"][()].decode("utf-8") + if interpolation == "linear": + interpolation = INTERPOLATION_LINEAR + elif interpolation == "log": + interpolation = INTERPOLATION_LOG + + energy_spectrum = DistributionMaxwellian( + energy, temperature, restriction_energy, interpolation + ) + + elif spectrum_type == "kalbach-mann": + energy = h5_group[f"energy"][()] * 1e6 # MeV to eV + offset = h5_group[f"offset"][()] + + energy_out = h5_group[f"energy_out"][()] * 1e6 # MeV to eV + pdf = h5_group[f"pdf"][()] / 1e6 # /MeV to /eV + + precompound_factor = h5_group[f"precompound_factor"][()] + angular_slope = h5_group[f"angular_slope"][()] + + energy_spectrum = DistributionKalbachMann( + energy, offset, energy_out, pdf, precompound_factor, angular_slope + ) + + elif spectrum_type == "energy-angle-tabulated": + energy = h5_group[f"energy"][()] * 1e6 # MeV to eV + offset = h5_group[f"offset"][()] + + energy_out = h5_group[f"energy_out"][()] * 1e6 # MeV to eV + pdf = h5_group[f"pdf"][()] / 1e6 # /MeV to /eV + cosine_offset = h5_group[f"cosine_offset"][()] + + cosine = h5_group[f"cosine"][()] + cosine_pdf = h5_group[f"cosine_pdf"][()] + + energy_spectrum = DistributionTabulatedEnergyAngle( + energy, offset, energy_out, pdf, cosine_offset, cosine, cosine_pdf + ) + + elif spectrum_type == "N-body": + value = h5_group["value"][()] * 1e6 # MeV to eV + pdf = h5_group["pdf"][()] / 1e6 # /MeV to /eV + + energy_spectrum = DistributionNBody(value, pdf) + + else: + print_error(f"Unsupported energy spectrum of type {spectrum_type}") + + return energy_spectrum diff --git a/mcdc/object_/settings.py b/mcdc/object_/settings.py new file mode 100644 index 000000000..62a82eec1 --- /dev/null +++ b/mcdc/object_/settings.py @@ -0,0 +1,139 @@ +import h5py +import numpy as np + +from dataclasses import dataclass, field +from numpy.typing import NDArray + +#### + +from mcdc.constant import * +from mcdc.object_.base import ObjectSingleton +from mcdc.object_.util import is_sorted +from mcdc.print_ import print_error + +# ====================================================================================== +# Settings +# ====================================================================================== + + +@dataclass +class Settings(ObjectSingleton): + # Annotations for Numba mode + label: str = "settings" + + # Basic + N_particle: int = 0 + N_batch: int = 1 + rng_seed: int = 1 + + # Simulation mode + multigroup_mode: bool = False + eigenvalue_mode: bool = False + + # k-eigenvalue + N_inactive: int = 0 + N_active: int = 0 + N_cycle: int = 0 + k_init: float = 1.0 + use_gyration_radius: bool = False + gyration_radius_type: int = GYRATION_RADIUS_ALL + + # Particle source + use_source_file: bool = False + source_file_name: str = "" + + # Misc. + time_boundary: float = np.inf + output_name: str = "output" + use_progress_bar: bool = True + + # Time census + N_census: int = 1 + census_time: NDArray[np.float64] = field(default_factory=lambda: np.array([np.inf])) + use_census_based_tally: bool = False + census_tally_frequency: int = 0 + + # Particle bank-related + save_particle: bool = False + active_bank_buffer: int = 100 + census_bank_buffer_ratio: float = 2.0 + source_bank_buffer_ratio: float = 2.0 + future_bank_buffer_ratio: float = 1.5 + + # Portability + target_gpu: bool = False + + def __post_init__(self): + super().__init__() + + def set_time_census(self, time, tally_frequency=None): + # Make sure that the time grid points are sorted + if not is_sorted(time): + print_error("Time census: Time grid points have to be sorted.") + + # Make sure that the starting point is larger than zero + if time[0] <= 0.0: + print_error("Time census: First census time should be larger than zero.") + + # Add the default, final census-at-infinity + time = np.append(time, np.inf) + + # Set the time census parameters + self.census_time = time + self.N_census = len(self.census_time) + + # Set the census-based tallying + if tally_frequency is not None and tally_frequency > 0: + # Flag to reset all tallies' time grids (done in main.py) + self.use_census_based_tally = True + self.census_tally_frequency = tally_frequency + + def set_eigenmode( + self, + N_inactive=0, + N_active=0, + k_init=1.0, + gyration_radius=None, + save_particle=False, + ): + # Update setting self + self.N_inactive = N_inactive + self.N_active = N_active + self.N_cycle = self.N_inactive + self.N_active + self.eigenvalue_mode = True + self.k_init = k_init + self.save_particle = save_particle + + # Gyration radius setup + if gyration_radius is not None: + self.use_gyration_radius = True + if gyration_radius == "all": + self.gyration_radius_type = GYRATION_RADIUS_ALL + elif gyration_radius == "infinite-x": + self.gyration_radius_type = GYRATION_RADIUS_INFINITE_X + elif gyration_radius == "infinite-y": + self.gyration_radius_type = GYRATION_RADIUS_INFINITE_Y + elif gyration_radius == "infinite-z": + self.gyration_radius_type = GYRATION_RADIUS_INFINITE_Z + elif gyration_radius == "only-x": + self.gyration_radius_type = GYRATION_RADIUS_ONLY_X + elif gyration_radius == "only-y": + self.gyration_radius_type = GYRATION_RADIUS_ONLY_Y + elif gyration_radius == "only-z": + self.gyration_radius_type = GYRATION_RADIUS_ONLY_Z + else: + print_error("Unknown gyration radius type") + + # Allocate cycle-wise quantities + from mcdc.object_.simulation import simulation + + simulation.k_cycle = np.zeros(self.N_cycle) + simulation.gyration_radius = np.zeros(self.N_cycle) + + def set_source_file(self, source_file_name): + self.use_source_file = True + self.source_file_name = source_file_name + + # Set number of particles + with h5py.File(source_file_name, "r") as f: + self.N_particle = int(f["particles_size"][()]) diff --git a/mcdc/object_/simulation.py b/mcdc/object_/simulation.py new file mode 100644 index 000000000..89076d864 --- /dev/null +++ b/mcdc/object_/simulation.py @@ -0,0 +1,232 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Annotated + +from mcdc.object_.technique import ( + ImplicitCapture, + PopulationControl, + WeightRoulette, + WeightedEmission, +) + +if TYPE_CHECKING: + from mcdc.object_.cell import Cell, Region + from mcdc.object_.material import MaterialBase + from mcdc.object_.nuclide import Nuclide + from mcdc.object_.reaction import ReactionBase + from mcdc.object_.source import Source + from mcdc.object_.surface import Surface + from mcdc.object_.tally import TallyBase + +#### + +import numpy as np + +from mpi4py import MPI +from numpy import float64, int64 +from numpy.typing import NDArray + +#### + +from mcdc.object_.base import ObjectSingleton +from mcdc.object_.data import DataBase, DataNone +from mcdc.object_.distribution import DistributionBase, DistributionNone +from mcdc.object_.gpu_tools import GPUMeta +from mcdc.object_.mesh import MeshBase +from mcdc.object_.particle import ParticleBank +from mcdc.object_.settings import Settings +from mcdc.object_.universe import Universe, Lattice + + +# ====================================================================================== +# Simulation +# ====================================================================================== + + +class Simulation(ObjectSingleton): + # Annotations for Numba mode + label: str = "simulation" + non_numba: list[str] = [ + "regions", + "bank_active", + "bank_census", + "bank_source", + "bank_future", + ] + + # Physics + data: list[DataBase] + distributions: list[DistributionBase] + materials: list[MaterialBase] + nuclides: list[Nuclide] + reactions: list[ReactionBase] + sources: list[Source] + + # Geometry + cells: list[Cell] + lattices: list[Lattice] + regions: list[Region] + surfaces: list[Surface] + universes: list[Universe] + meshes: list[MeshBase] + + # Tallies + tallies: list[TallyBase] + + # Settings + settings: Settings + + # Techniques + implicit_capture: ImplicitCapture + weighted_emission: WeightedEmission + weight_roulette: WeightRoulette + population_control: PopulationControl + + # Particle banks + bank_active: ParticleBank + bank_census: ParticleBank + bank_source: ParticleBank + bank_future: ParticleBank + + # Simulation parameters + idx_work: int + idx_cycle: int + idx_census: int + idx_batch: int + dd_idx: int + dd_N_local_source: int + dd_local_rank: int + k_eff: float + k_cycle: NDArray[float64] + k_avg: float + k_sdv: float + n_avg: float + n_sdv: float + n_max: float + C_avg: float + C_sdv: float + C_max: float + k_avg_running: float + k_sdv_running: float + gyration_radius: NDArray[float64] + cycle_active: bool + eigenvalue_tally_nuSigmaF: Annotated[NDArray[float64], (1,)] + eigenvalue_tally_n: Annotated[NDArray[float64], (1,)] + eigenvalue_tally_C: Annotated[NDArray[float64], (1,)] + mpi_size: int + mpi_rank: int + mpi_master: bool + mpi_work_start: int + mpi_work_size: int + mpi_work_size_total: int + mpi_work_iter: Annotated[NDArray[int64], (1,)] + runtime_total: float + runtime_preparation: float + runtime_simulation: float + runtime_output: float + runtime_bank_management: float + + # GPU metadata + gpu_meta: GPUMeta + + def __init__(self): + super().__init__() + + # ============================================================================== + # Simulation objects + # ============================================================================== + + # Physics + self.data = [DataNone()] + self.distributions = [DistributionNone()] + self.materials = [] + self.nuclides = [] + self.reactions = [] + self.sources = [] + + # Geometry + self.cells = [] + self.lattices = [] + self.regions = [] + self.surfaces = [] + self.universes = [Universe("Root Universe", root=True)] + self.meshes = [] + + # Tallies + self.tallies = [] + + # Settings + self.settings = Settings() + + # Techniques + self.implicit_capture = ImplicitCapture() + self.weighted_emission = WeightedEmission() + self.weight_roulette = WeightRoulette() + self.population_control = PopulationControl() + + # ============================================================================== + # Particle banks + # ============================================================================== + + self.bank_active = ParticleBank(tag="active") + self.bank_census = ParticleBank(tag="census") + self.bank_source = ParticleBank(tag="source") + self.bank_future = ParticleBank(tag="future") + + # ============================================================================== + # Simulation parameters + # ============================================================================== + + # Simulation indices + self.idx_work = 0 + self.idx_cycle = 0 + self.idx_census = 0 + self.idx_batch = 0 + + # Domain decomposition + self.dd_idx = 0 + self.dd_N_local_source = 0 + self.dd_local_rank = 0 + + # Eigenvalue simulation + self.k_eff = 0.0 + self.k_cycle = np.ones(1) + self.k_avg = 0.0 + self.k_sdv = 0.0 + self.n_avg = 0.0 # Neutron density + self.n_sdv = 0.0 + self.n_max = 0.0 + self.C_avg = 0.0 # Precursor density + self.C_sdv = 0.0 + self.C_max = 0.0 + self.k_avg_running = 0.0 + self.k_sdv_running = 0.0 + self.gyration_radius = np.zeros(1) + self.cycle_active = False + self.eigenvalue_tally_nuSigmaF = np.zeros(1) + self.eigenvalue_tally_n = np.zeros(1) + self.eigenvalue_tally_C = np.zeros(1) + + # MPI parameters + self.mpi_size = MPI.COMM_WORLD.Get_size() + self.mpi_rank = MPI.COMM_WORLD.Get_rank() + self.mpi_master = self.mpi_rank == 0 + self.mpi_work_start = 0 + self.mpi_work_size = 0 + self.mpi_work_size_total = 0 + self.mpi_work_iter = np.zeros(1, dtype=int64) + + # Runtime records + self.runtime_total = 0.0 + self.runtime_preparation = 0.0 + self.runtime_simulation = 0.0 + self.runtime_output = 0.0 + self.runtime_bank_management = 0.0 + + # GPU metadata + self.gpu_meta = GPUMeta() + + def set_root_universe(self, cells=[]): + self.universes[0].cells = cells + + +simulation = Simulation() diff --git a/mcdc/object_/source.py b/mcdc/object_/source.py new file mode 100644 index 000000000..b45fc19fc --- /dev/null +++ b/mcdc/object_/source.py @@ -0,0 +1,205 @@ +import numpy as np + +from numpy import float64, int64 +from numpy.typing import NDArray +from types import NoneType +from typing import Annotated, Iterable + +#### + +import mcdc.object_.distribution as distribution + +from mcdc.object_.base import ObjectNonSingleton +from mcdc.constant import PARTICLE_NEUTRON +from mcdc.object_.distribution import DistributionTabulated, DistributionPMF +from mcdc.object_.simulation import simulation + + +def decode_particle_type(type_): + if type_ == PARTICLE_NEUTRON: + return "Neutron" + + +# ====================================================================================== +# Source +# ====================================================================================== + + +class Source(ObjectNonSingleton): + # Annotations for Numba mode + label: str = "source" + # + name: str + point_source: bool + point: Annotated[NDArray[float64], (3,)] + x: Annotated[NDArray[float64], (2,)] + y: Annotated[NDArray[float64], (2,)] + z: Annotated[NDArray[float64], (2,)] + isotropic_direction: bool + mono_direction: bool + white_direction: bool + direction: Annotated[NDArray[float64], (3,)] + mono_energetic: bool + energy_group: int + energy: float + energy_group_pmf: DistributionPMF + energy_pdf: DistributionTabulated + discrete_time: bool + time: float + time_range: Annotated[NDArray[float64], (2,)] + particle_type: int + probability: float + + def __init__( + self, + name: str = "", + position: Iterable[float] | NoneType = None, + x: Iterable[float] | NoneType = None, + y: Iterable[float] | NoneType = None, + z: Iterable[float] | NoneType = None, + # + direction: Iterable[float] | NoneType = None, + white_direction: Iterable[float] | NoneType = None, + isotropic: bool | NoneType = None, + # + energy: float | NDArray[float64] | NoneType = None, + energy_group: int | NDArray[int64] | NoneType = None, + # + time: float | Iterable[float] = 0.0, + probability: float = 1.0, + ): + + super().__init__() + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.ID}" + + # ============================================================================== + # Default attributes + # Point source at origin, isotropic, mono-energetic at 1 MeV or at group 0, + # time = 0, neutron + # ============================================================================== + + # Position + self.point_source = True + self.point = np.zeros(3) + self.x = np.array([0.0, 0.0]) + self.y = np.array([0.0, 0.0]) + self.z = np.array([0.0, 0.0]) + + # Direction + self.isotropic_direction = True + self.mono_direction = False + self.white_direction = False + self.direction = np.array([0.0, 0.0, 0.0]) + + # Energy + self.mono_energetic = True + self.energy_group = 0 + self.energy = 1.0e6 + self.energy_group_pmf = DistributionPMF(np.array([0.0]), np.array([1.0])) + self.energy_pdf = DistributionTabulated( + np.array([1.0e6 - 1.0, 1.0e6 + 1.0]), np.array([1.0, 1.0]) + ) + + # Time + self.discrete_time = True + self.time = 0.0 + self.time_range = np.array([0.0, 0.0]) + + # Particle type + self.particle_type = PARTICLE_NEUTRON + + # Probability + self.probability = probability + + # ============================================================================== + # Assignment + # ============================================================================== + + # Position + if position is not None: + self.point = np.array(position) + else: + self.point_source = False + if x is not None: + self.x = np.array(x) + if y is not None: + self.y = np.array(y) + if z is not None: + self.z = np.array(z) + + # Direction + if isotropic is not None: + pass + elif direction is not None: + self.isotropic_direction = False + self.mono_direction = True + self.direction = np.array(direction) + elif white_direction is not None: + self.isotropic_direction = False + self.white_direction = True + self.direction = np.array(white_direction) + + # Energy + if energy_group is not None: + if type(energy_group) == int: + self.energy_group = energy_group + else: + self.mono_energetic = False + self.energy_group_pmf = DistributionPMF( + energy_group[0], energy_group[1] + ) + elif energy is not None: + if type(energy) == float: + self.energy = energy + else: + self.mono_energetic = False + self.energy_pdf = DistributionTabulated(energy[0], energy[1]) + + # Time + if type(time) == float: + self.time = time + else: + self.discrete_time = False + self.time_range = np.array(time) + + def __repr__(self): + text = "\n" + text += f"Source\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - Particle: {decode_particle_type(self.particle_type)}\n" + text += f" - Probability: {self.probability * 100}%\n" + if self.point_source: + text += f" - Position [x, y, z]: {self.point} cm\n" + else: + text += f" - Position\n" + text += f" - x: {self.x} cm\n" + text += f" - y: {self.y} cm\n" + text += f" - z: {self.z} cm\n" + if self.isotropic_direction: + text += f" - Direction: Isotropic\n" + elif self.mono_direction: + text += f" - Direction [ux, uy, yz]: {self.direction}\n" + elif self.white_direction: + text += f" - Isotropic halfspace: {self.direction}\n" + if simulation.materials[0].label == "multigroup_material": + if self.mono_energetic: + text += f" - Energy group: {self.energy_group} \n" + else: + text += f" - Energy group: {distribution.decode_type(self.energy_group_pmf.type)} [ID: {self.energy_group_pmf.ID}]\n" + else: + if self.mono_energetic: + text += f" - Energy: {self.energy} eV\n" + else: + text += f" - Energy: {distribution.decode_type(self.energy_pdf)} [ID: {self.energy_pdf.ID}]\n" + if self.discrete_time: + text += f" - Time: {self.time} s\n" + else: + text += f" - Time: {self.time_range} s\n" + + return text diff --git a/mcdc/object_/surface.py b/mcdc/object_/surface.py new file mode 100644 index 000000000..1bdb9ef83 --- /dev/null +++ b/mcdc/object_/surface.py @@ -0,0 +1,707 @@ +from typing import Annotated, Iterable +import numpy as np + +from numpy import float64 +from numpy.typing import NDArray + +#### + +from mcdc.object_.cell import Region +from mcdc.constant import ( + BC_NONE, + BC_REFLECTIVE, + BC_VACUUM, + INF, + SURFACE_CYLINDER_X, + SURFACE_CYLINDER_Y, + SURFACE_CYLINDER_Z, + SURFACE_PLANE, + SURFACE_PLANE_X, + SURFACE_PLANE_Y, + SURFACE_PLANE_Z, + SURFACE_QUADRIC, + SURFACE_SPHERE, +) +from mcdc.object_.base import ObjectNonSingleton +from mcdc.object_.tally import TallySurface + + +# ====================================================================================== +# Surface +# ====================================================================================== + + +class Surface(ObjectNonSingleton): + """ + Geometric surface primitive with optional boundary condition and motion. + + Surfaces are registered non-singletons and receive a stable ``ID``. Factory + constructors (:meth:`PlaneX`, :meth:`CylinderZ`, etc.) set the quadric + coefficients (A..J) and linearity flag. Motion segments can be defined with + :meth:`move`. + + Parameters + ---------- + type_ : int + One of ``SURFACE_*`` constants (e.g., ``SURFACE_PLANE_X``). + name : str + Optional label for reporting. + boundary_condition : {"none","vacuum","reflective"} + Boundary behavior at the surface. + + Attributes + ---------- + ID : int + Index in the global registry (assigned on construction). + type : int + Surface type code (``SURFACE_*``). + name : str + User label. + boundary_condition : int + One of ``BC_NONE``, ``BC_VACUUM``, ``BC_REFLECTIVE``. + A,B,C,D,E,F,G,H,I,J : float + Quadric coefficients defining the implicit surface. + linear : bool + True for linear (plane) surfaces; False for general quadrics. + nx, ny, nz : float + Outward normal components for linear planes. + moving : bool + True if :meth:`move` has been called. + N_move : int + Number of motion segments plus the final static segment. + move_velocities : (N_move, 3) ndarray + Per-segment velocity vectors. + move_durations : (N_move,) ndarray + Per-segment durations (s). + move_time_grid : (N_move+1,) ndarray + Cumulative time breakpoints. + move_translations : (N_move+1, 3) ndarray + Cumulative translations at each breakpoint. + + See Also + -------- + Region + Use unary ``+`` / ``-`` to form half-spaces: ``+surface`` or ``-surface``. + decode_type + Human-readable surface type. + decode_BC_type + Human-readable boundary condition name. + """ + + # Annotations for Numba mode + label: str = "surface" + # + type: int + name: str + boundary_condition: int + A: float + B: float + C: float + D: float + E: float + F: float + G: float + H: float + I: float + J: float + linear: bool + nx: float + ny: float + nz: float + moving: bool + N_move: int + N_move_grid: int + move_velocities: Annotated[NDArray[float64], ("N_move", 3)] + move_durations: Annotated[NDArray[float64], ("N_move",)] + move_time_grid: Annotated[NDArray[float64], ("N_move_grid",)] + move_translations: Annotated[NDArray[float64], ("N_move_grid", 3)] + tallies: list[TallySurface] + + def __init__(self, type_, name, boundary_condition): + super().__init__() + + # Type and name + self.type = type_ + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.ID}" + + # Boundary condition + if boundary_condition == "none": + self.boundary_condition = BC_NONE + elif boundary_condition == "vacuum": + self.boundary_condition = BC_VACUUM + elif boundary_condition == "reflective": + self.boundary_condition = BC_REFLECTIVE + + # Quadric surface coefficients + self.A = 0.0 + self.B = 0.0 + self.C = 0.0 + self.D = 0.0 + self.E = 0.0 + self.F = 0.0 + self.G = 0.0 + self.H = 0.0 + self.I = 0.0 + self.J = 0.0 + + # Helpers + self.linear = True + # Surface normal direction (if linear) + self.nx = 0.0 + self.ny = 0.0 + self.nz = 0.0 + + # Moving surface parameters + self.moving = False + self.N_move = 1 + self.N_move_grid = 2 + self.move_velocities = np.zeros((1, 3)) + self.move_durations = np.array([INF]) + self.move_time_grid = np.array([0.0, INF]) + self.move_translations = np.zeros((2, 3)) + + # Surface tallies + self.tallies = [] + + def __repr__(self): + """ + Return a human-readable description including type-specific parameters. + + Returns + ------- + str + Multi-line formatted string with ID, name, BC, and geometry details. + """ + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - Boundary condition: {decode_BC_type(self.boundary_condition)}\n" + + # ============================================================================== + # Type-based repr + # ============================================================================== + + if self.type == SURFACE_PLANE_X: + text += f" - x0: {-self.J} cm\n" + elif self.type == SURFACE_PLANE_Y: + text += f" - y0: {-self.J} cm\n" + elif self.type == SURFACE_PLANE_Z: + text += f" - z0: {-self.J} cm\n" + elif self.type == SURFACE_PLANE: + text += f" - Coeffs.: {self.G}, {self.H}, {self.I}, {self.J}\n" + text += f" - Normal: ({self.nx}, {self.ny}, {self.nz})\n" + elif self.type == SURFACE_CYLINDER_X: + y = -0.5 * self.H + z = -0.5 * self.I + r = (y**2 + z**2 - self.J) ** 0.5 + text += f" - Center (y, z): ({y}, {z}) cm\n" + text += f" - Radius: {r} cm\n" + elif self.type == SURFACE_CYLINDER_Y: + x = -0.5 * self.G + z = -0.5 * self.I + r = (x**2 + z**2 - self.J) ** 0.5 + text += f" - Center (x, z): ({x}, {z}) cm\n" + text += f" - Radius: {r} cm\n" + elif self.type == SURFACE_CYLINDER_Z: + x = -0.5 * self.G + y = -0.5 * self.H + r = (x**2 + y**2 - self.J) ** 0.5 + text += f" - Center (x, y): ({x}, {y}) cm\n" + text += f" - Radius: {r} cm\n" + elif self.type == SURFACE_SPHERE: + x = -0.5 * self.G + y = -0.5 * self.H + z = -0.5 * self.I + r = (x**2 + y**2 + z**2 - self.J) ** 0.5 + text += f" - Center (x, y, z): ({x}, {y}, {z}) cm\n" + text += f" - Radius: {r} cm\n" + elif self.type == SURFACE_QUADRIC: + text += f" - Coeffs.: {self.A}, {self.B}, {self.C},\n" + text += f" {self.D}, {self.E}, {self.F},\n" + text += f" {self.G}, {self.H}, {self.I}, {self.J}\n" + + if len(self.tallies) > 0: + text += f" - Tallies: {[x.ID for x in self.tallies]}\n" + + return text + + # ================================================================================== + # Type-based creation methods + # ================================================================================== + + @classmethod + def PlaneX(cls, name: str = "", x: float = 0.0, boundary_condition: str = "none"): + """ + Create a plane perpendicular to +x at x = constant. + + Parameters + ---------- + name : str, optional + x : float, default 0.0 + Plane location (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Linear plane with normal ``(+1, 0, 0)``. + """ + type_ = SURFACE_PLANE_X + surface = cls(type_, name, boundary_condition) + + surface.linear = True + surface.G = 1.0 + surface.J = -x + surface.nx = 1.0 + + return surface + + @classmethod + def PlaneY(cls, name: str = "", y: float = 0.0, boundary_condition: str = "none"): + """ + Create a plane perpendicular to +y at y = constant. + + Parameters + ---------- + name : str, optional + y : float, default 0.0 + Plane location (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Linear plane with normal ``(0, +1, 0)``. + """ + type_ = SURFACE_PLANE_Y + surface = cls(type_, name, boundary_condition) + + surface.linear = True + surface.H = 1.0 + surface.J = -y + surface.ny = 1.0 + + return surface + + @classmethod + def PlaneZ(cls, name: str = "", z: float = 0.0, boundary_condition: str = "none"): + """ + Create a plane perpendicular to +z at z = constant. + + Parameters + ---------- + name : str, optional + z : float, default 0.0 + Plane location (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Linear plane with normal ``(0, 0, +1)``. + """ + type_ = SURFACE_PLANE_Z + surface = cls(type_, name, boundary_condition) + + surface.linear = True + surface.I = 1.0 + surface.J = -z + surface.nz = 1.0 + + return surface + + @classmethod + def Plane( + cls, + name: str = "", + A: float = 0.0, + B: float = 0.0, + C: float = 0.0, + D: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create a general plane defined by A x + B y + C z + D = 0. + + The normal is normalized to unit length and stored in ``(nx, ny, nz)``. + + Parameters + ---------- + name : str, optional + A, B, C, D : float + Plane coefficients. + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Linear plane with normalized normal vector. + """ + type_ = SURFACE_PLANE + surface = cls(type_, name, boundary_condition) + + surface.linear = True + + # Normalize + norm = (A**2 + B**2 + C**2) ** 0.5 + A /= norm + B /= norm + C /= norm + D /= norm + + # Coefficients + surface.G = A + surface.H = B + surface.I = C + surface.J = D + + # Surface normal direction + surface.nx = A + surface.ny = B + surface.nz = C + return surface + + @classmethod + def CylinderX( + cls, + name: str = "", + center: Iterable[float] = [0.0, 0.0], + radius: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create an infinite cylinder aligned with the x-axis. + + Parameters + ---------- + name : str, optional + center : (2,) array_like of float, default (0, 0) + Cylinder center in (y, z) (cm). + radius : float, default 1.0 + Cylinder radius (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Quadratic cylinder surface. + """ + type_ = SURFACE_CYLINDER_X + surface = cls(type_, name, boundary_condition) + + surface.linear = False + + # Center and radius + y, z = center + r = radius + + # Coefficients + surface.B = 1.0 + surface.C = 1.0 + surface.H = -2.0 * y + surface.I = -2.0 * z + surface.J = y**2 + z**2 - r**2 + return surface + + @classmethod + def CylinderY( + cls, + name: str = "", + center: Iterable[float] = [0.0, 0.0], + radius: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create an infinite cylinder aligned with the y-axis. + + Parameters + ---------- + name : str, optional + center : (2,) array_like of float + Cylinder center in (x, z) (cm). + radius : float + Cylinder radius (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Quadratic cylinder surface. + """ + type_ = SURFACE_CYLINDER_Y + surface = cls(type_, name, boundary_condition) + + surface.linear = False + + # Center and radius + x, z = center + r = radius + + # Coefficients + surface.A = 1.0 + surface.C = 1.0 + surface.G = -2.0 * x + surface.I = -2.0 * z + surface.J = x**2 + z**2 - r**2 + return surface + + @classmethod + def CylinderZ( + cls, + name: str = "", + center: Iterable[float] = [0.0, 0.0], + radius: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create an infinite cylinder aligned with the z-axis. + + Parameters + ---------- + name : str, optional + center : (2,) array_like of float + Cylinder center in (x, y) (cm). + radius : float + Cylinder radius (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Quadratic cylinder surface. + """ + type_ = SURFACE_CYLINDER_Z + surface = cls(type_, name, boundary_condition) + surface.linear = False + + # Center and radius + x, y = center + r = radius + + # Coefficients + surface.A = 1.0 + surface.B = 1.0 + surface.G = -2.0 * x + surface.H = -2.0 * y + surface.J = x**2 + y**2 - r**2 + + return surface + + @classmethod + def Sphere( + cls, + name: str = "", + center: Iterable[float] = [0.0, 0.0, 0.0], + radius: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create a sphere. + + Parameters + ---------- + name : str, optional + center : (3,) array_like of float + Sphere center (x, y, z) in cm. + radius : float + Radius (cm). + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + Quadratic spherical surface. + """ + type_ = SURFACE_SPHERE + surface = cls(type_, name, boundary_condition) + + surface.linear = False + + # Center and radius + x, y, z = center + r = radius + + # Coefficients + surface.A = 1.0 + surface.B = 1.0 + surface.C = 1.0 + surface.G = -2.0 * x + surface.H = -2.0 * y + surface.I = -2.0 * z + surface.J = x**2 + y**2 + z**2 - r**2 + return surface + + @classmethod + def Quadric( + cls, + name: str = "", + A: float = 0.0, + B: float = 0.0, + C: float = 0.0, + D: float = 0.0, + E: float = 0.0, + F: float = 0.0, + G: float = 0.0, + H: float = 0.0, + I: float = 0.0, + J: float = 0.0, + boundary_condition: str = "none", + ): + """ + Create a general quadric: + A x^2 + B y^2 + C z^2 + D xy + E yz + F zx + G x + H y + I z + J = 0 + + Parameters + ---------- + name : str, optional + A,B,C,D,E,F,G,H,I,J : float + Quadric coefficients. + boundary_condition : {"none","vacuum","reflective"}, optional + + Returns + ------- + Surface + General quadratic surface. + """ + type_ = SURFACE_QUADRIC + surface = cls(type_, name, boundary_condition) + + surface.linear = False + + # Coefficients + surface.A = A + surface.B = B + surface.C = C + surface.D = D + surface.E = E + surface.F = F + surface.G = G + surface.H = H + surface.I = I + surface.J = J + return surface + + # ================================================================================== + # Region building + # ================================================================================== + + def __pos__(self): + """ + Half-space on the **outward** side of the surface. + + Returns + ------- + Region + Region representing ``n · r + J >= 0`` (sign convention per type). + """ + return Region.make_halfspace(self, +1) + + def __neg__(self): + """ + Half-space on the **inward** side of the surface. + + Returns + ------- + Region + Region representing the complement half-space. + """ + return Region.make_halfspace(self, -1) + + # ================================================================================== + # Surface moving + # ================================================================================== + + def move(self, velocities, durations): + """ + Define piecewise-constant motion for the surface. + + Appends a final static segment (zero velocity, infinite duration) so that + the motion covers the whole simulation time. + + Parameters + ---------- + velocities : array_like, shape (N, 3) or list + Per-segment velocity vectors [cm/s]. + durations : array_like, shape (N,) or list + Per-segment durations [s]. + + Notes + ----- + - Internally converts lists to arrays and constructs + ``move_time_grid`` and cumulative ``move_translations``. + - Sets ``moving=True`` and ``N_move = len(durations) + 1``. + + Examples + -------- + >>> s = Surface.PlaneZ(z=0.0) + >>> s.move(velocities=[[0,0,1.0]], durations=[0.5]) # 0.5 s upward, then static + >>> s.N_move + 2 + """ + self.moving = True + self.N_move = len(durations) + 1 + self.N_move_grid = len(durations) + 2 + + if isinstance(velocities, np.ndarray): + velocities = velocities.tolist() + durations = durations.tolist() + + # Add the statics for the rest of the simulation + move_velocities = velocities + move_velocities.append([0.0, 0.0, 0.0]) + self.move_velocities = np.array(move_velocities) + # + move_durations = durations + move_durations.append(INF) + self.move_durations = np.array(move_durations) + + # Set time grid and translations + self.move_time_grid = np.zeros(self.N_move_grid) + self.move_translations = np.zeros((self.N_move_grid, 3)) + for n in range(self.N_move): + t_start = self.move_time_grid[n] + self.move_time_grid[n + 1] = t_start + self.move_durations[n] + + trans_start = self.move_translations[n] + self.move_translations[n + 1] = ( + trans_start + self.move_velocities[n] * self.move_durations[n] + ) + + +# ====================================================================================== +# Type decoder +# ====================================================================================== + + +def decode_type(type_): + if type_ == SURFACE_PLANE_X: + return "Plane-X surface" + elif type_ == SURFACE_PLANE_Y: + return "Plane-Y surface" + elif type_ == SURFACE_PLANE_Z: + return "Plane-Z surface" + elif type_ == SURFACE_PLANE: + return "Plane surface" + elif type_ == SURFACE_CYLINDER_X: + return "Infinite cylinder-X surface" + elif type_ == SURFACE_CYLINDER_Y: + return "Infinite cylinder-Y surface" + elif type_ == SURFACE_CYLINDER_Z: + return "Infinite cylinder-Z surface" + elif type_ == SURFACE_SPHERE: + return "Sphere surface" + elif type_ == SURFACE_QUADRIC: + return "Quadric surface" + + +def decode_BC_type(type_): + if type_ == BC_NONE: + return "None" + elif type_ == BC_VACUUM: + return "Vacuum" + elif type_ == BC_REFLECTIVE: + return "Reflective" diff --git a/mcdc/object_/tally.py b/mcdc/object_/tally.py new file mode 100644 index 000000000..a45f4a7a5 --- /dev/null +++ b/mcdc/object_/tally.py @@ -0,0 +1,411 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from mcdc.object_.cell import Cell + from mcdc.object_.surface import Surface + +#### + +import numpy as np +import operator + +from functools import reduce +from numpy import float64 +from numpy.typing import NDArray +from typing import Annotated, Iterable +from types import NoneType + +#### + +import mcdc.object_.mesh as mesh_module + +from mcdc.constant import ( + INF, + MULTIPLIER_ENERGY, + PI, + SCORE_FLUX, + SCORE_DENSITY, + SCORE_COLLISION, + SCORE_CAPTURE, + SCORE_FISSION, + SCORE_NET_CURRENT, + TALLY_GLOBAL, + TALLY_CELL, + TALLY_MESH, + TALLY_SURFACE, +) +from mcdc.object_.mesh import MeshBase +from mcdc.object_.base import ObjectPolymorphic +from mcdc.object_.simulation import simulation +from mcdc.print_ import print_1d_array, print_error + + +# ====================================================================================== +# Tally base class +# ====================================================================================== + + +class TallyBase(ObjectPolymorphic): + # Annotations for Numba mode + label: str = "tally" + # + name: str + scores: list[int] + multipliers: list[int] + mu: NDArray[float64] + azi: NDArray[float64] + polar_reference: Annotated[NDArray[float64], (3,)] + energy: NDArray[float64] + time: NDArray[float64] + filter_direction: bool + filter_energy: bool + filter_time: bool + bin: NDArray[float64] + bin_sum: NDArray[float64] + bin_sum_square: NDArray[float64] + bin_shape: list[int] + stride_mu: int + stride_azi: int + stride_energy: int + stride_time: int + + def __init__( + self, + type_, + name, + scores, + multipliers, + mu, + azi, + polar_reference, + energy, + time, + spatial_shape=None, + ): + super().__init__(type_) + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.child_ID}" + + # Set scores + self.scores = [] + for score in scores: + if score == "flux": + self.scores.append(SCORE_FLUX) + elif score == "density": + self.scores.append(SCORE_DENSITY) + elif score == "collision": + self.scores.append(SCORE_COLLISION) + elif score == "capture": + self.scores.append(SCORE_CAPTURE) + elif score == "fission": + self.scores.append(SCORE_FISSION) + elif score == "net-current": + self.scores.append(SCORE_NET_CURRENT) + else: + print_error(f"Unknown tally score: {score}") + + # Set multipliers + self.multipliers = [] + for multiplier in multipliers: + if multiplier == "energy": + self.multipliers.append(MULTIPLIER_ENERGY) + else: + print_error(f"Unknown tally multiplier: {multiplier}") + + # Phase-space filters + self.mu = np.array([-1.0, 1.0]) + self.azi = np.array([-PI, PI]) + self.polar_reference = np.array([0.0, 0.0, 1.0]) + self.energy = np.array([-1.0, INF]) + self.time = np.array([0.0, INF]) + self.filter_direction = False + self.filter_energy = False + self.filter_time = False + if mu is not None: + self.mu = np.array(mu) + self.filter_direction = True + if azi is not None: + self.azi = np.array(azi) + self.filter_direction = True + if polar_reference is not None: + polar_reference = np.array(polar_reference) + self.polar_reference /= polar_reference / np.linalg.norm(polar_reference) + if energy is not None: + if type(energy) == str and energy == "all_groups": + G = simulation.materials[0].G + self.energy = np.linspace(0, G, G + 1) - 0.5 + else: + self.energy = np.array(energy) + self.filter_energy = True + if time is not None: + self.time = np.array(time) + self.filter_time = True + + # Determine bin shape + N_mu = len(self.mu) - 1 + N_azi = len(self.azi) - 1 + N_energy = len(self.energy) - 1 + N_time = len(self.time) - 1 + N_score = len(self.scores) + # + if spatial_shape is None: + shape = (N_mu, N_azi, N_energy, N_time, N_score) + else: + shape = (N_mu, N_azi, N_energy, N_time) + spatial_shape + (N_score,) + + # Set bins and strides + self._set_bin_shape_and_strides(shape) + + def _set_bin_shape_and_strides(self, shape): + # Set bins + self.bin_shape = list(shape) + + # Set strides + self.stride_time = reduce(operator.mul, shape[4:]) + self.stride_energy = reduce(operator.mul, shape[3:]) + self.stride_azi = reduce(operator.mul, shape[2:]) + self.stride_mu = reduce(operator.mul, shape[1:]) + + def _use_census_based_tally(self, frequency): + first_census = simulation.settings.census_time[0] + self.time = np.linspace(0.0, first_census, frequency + 1) + + N_mu = len(self.mu) - 1 + N_azi = len(self.azi) - 1 + N_energy = len(self.energy) - 1 + N_score = len(self.scores) + + spatial_shape = None + if len(self.bin_shape) > 5: + spatial_shape = tuple(self.bin_shape[4:-1]) + + if spatial_shape is None: + shape = (N_mu, N_azi, N_energy, frequency, N_score) + else: + shape = (N_mu, N_azi, N_energy, frequency) + spatial_shape + (N_score,) + + self._set_bin_shape_and_strides(shape) + + def _phasespace_filter_text(self): + text = "" + text += f" - Scores: {[decode_score_type(x) for x in self.scores]}\n" + text += f" - Phase-space filters\n" + if self.filter_time: + text += f" - Time {print_1d_array(self.time)} s\n" + if self.filter_energy: + text += f" - Energy {print_1d_array(self.energy)} eV\n" + if self.filter_direction: + text += f" - Direction\n" + text += f" - Polar reference: {self.polar_reference}\n" + text += f" - Polar cosine {print_1d_array(self.mu)}\n" + text += f" - Azimuthal angle {print_1d_array(self.azi)}\n" + return text + + def __repr__(self): + text = "\n" + text += f"{decode_type(self.type)}\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + return text + + +def decode_type(type_): + if type_ == TALLY_GLOBAL: + return "Global tally" + elif type_ == TALLY_CELL: + return "Cell tally" + elif type_ == TALLY_SURFACE: + return "Surface tally" + elif type_ == TALLY_MESH: + return "Mesh tally" + + +def decode_score_type(type_, lower_case=False): + if type_ == SCORE_FLUX: + return "Flux" if not lower_case else "flux" + elif type_ == SCORE_DENSITY: + return "Density" if not lower_case else "density" + elif type_ == SCORE_COLLISION: + return "Collision" if not lower_case else "collision" + elif type_ == SCORE_CAPTURE: + return "Capture" if not lower_case else "capture" + elif type_ == SCORE_FISSION: + return "Fission" if not lower_case else "fission" + elif type_ == SCORE_NET_CURRENT: + return "Net current" if not lower_case else "net-current" + + +# ====================================================================================== +# Global tally +# ====================================================================================== + + +class TallyGlobal(TallyBase): + # Annotations for Numba mode + label: str = "global_tally" + + def __init__( + self, + name: str = "", + scores: list[str] = ["flux"], + multipliers: list[str] = [], + mu: Iterable[float] | NoneType = None, + azi: Iterable[float] | NoneType = None, + polar_reference: Iterable[float] | NoneType = None, + energy: Iterable[float] | str | NoneType = None, + time: Iterable[float] | NoneType = None, + ): + type_ = TALLY_GLOBAL + super().__init__( + type_, name, scores, multipliers, mu, azi, polar_reference, energy, time + ) + + def __repr__(self): + text = super().__repr__() + text += super()._phasespace_filter_text() + text += f" - Bin shape (mu, azi, energy, time, score): {self.bin.shape} \n" + return text + + +# ====================================================================================== +# Cell tally +# ====================================================================================== + + +class TallyCell(TallyBase): + # Annotations for Numba mode + label: str = "cell_tally" + # + cell: Cell + + def __init__( + self, + cell: Cell, + name: str = "", + scores: list[str] = ["flux"], + multipliers: list[str] = [], + mu: Iterable[float] | NoneType = None, + azi: Iterable[float] | NoneType = None, + polar_reference: Iterable[float] | NoneType = None, + energy: Iterable[float] | str | NoneType = None, + time: Iterable[float] | NoneType = None, + ): + type_ = TALLY_CELL + super().__init__( + type_, name, scores, multipliers, mu, azi, polar_reference, energy, time + ) + + # Attach cell and attach tally to the cell + self.cell = cell + cell.tallies.append(self) + + def __repr__(self): + text = super().__repr__() + text += f" - Cell: {self.cell.name}\n" + text += super()._phasespace_filter_text() + text += f" - Bin shape (mu, azi, energy, time, score): {self.bin.shape} \n" + return text + + +# ====================================================================================== +# Surface tally +# ====================================================================================== + + +class TallySurface(TallyBase): + # Annotations for Numba mode + label: str = "surface_tally" + # + surface: Surface + + def __init__( + self, + surface: Surface, + name: str = "", + scores: list[str] = ["flux"], + multipliers: list[str] = [], + mu: Iterable[float] | NoneType = None, + azi: Iterable[float] | NoneType = None, + polar_reference: Iterable[float] | NoneType = None, + energy: Iterable[float] | str | NoneType = None, + time: Iterable[float] | NoneType = None, + ): + type_ = TALLY_SURFACE + super().__init__( + type_, name, scores, multipliers, mu, azi, polar_reference, energy, time + ) + + # Set surface and attach tally to the surface + self.surface = surface + surface.tallies.append(self) + + def __repr__(self): + text = super().__repr__() + text += f" - Surface: {self.surface.name}\n" + text += super()._phasespace_filter_text() + text += f" - Bin shape (mu, azi, energy, time, score): {self.bin.shape} \n" + return text + + +# ====================================================================================== +# Mesh tally +# ====================================================================================== + + +class TallyMesh(TallyBase): + # Annotations for Numba mode + label: str = "mesh_tally" + # + mesh: MeshBase + stride_z: int + stride_y: int + stride_x: int + + def __init__( + self, + mesh: MeshBase, + name: str = "", + scores: list[str] = ["flux"], + multipliers: list[str] = [], + mu: Iterable[float] | NoneType = None, + azi: Iterable[float] | NoneType = None, + polar_reference: Iterable[float] | NoneType = None, + energy: Iterable[float] | str | NoneType = None, + time: Iterable[float] | NoneType = None, + ): + type_ = TALLY_MESH + spatial_shape = (mesh.Nx, mesh.Ny, mesh.Nz) + super().__init__( + type_, + name, + scores, + multipliers, + mu, + azi, + polar_reference, + energy, + time, + spatial_shape, + ) + + self.mesh = mesh + + # Set the strides + N_score = len(self.scores) + self.stride_z = N_score + self.stride_y = N_score * mesh.Nz + self.stride_x = N_score * mesh.Nz * mesh.Ny + + def __repr__(self): + text = super().__repr__() + text += ( + f" - Mesh: {mesh_module.decode_type(self.mesh.type)} (ID {self.mesh.ID})\n" + ) + text += super()._phasespace_filter_text() + text += f" - Bin shape (mu, azi, energy, time, x, y, z, score): {self.bin.shape} \n" + return text diff --git a/mcdc/object_/technique.py b/mcdc/object_/technique.py new file mode 100644 index 000000000..22d9fc07d --- /dev/null +++ b/mcdc/object_/technique.py @@ -0,0 +1,82 @@ +from mcdc.object_.base import ObjectSingleton +from mcdc.print_ import print_error + + +# ====================================================================================== +# Implicit capture +# ====================================================================================== + + +class ImplicitCapture(ObjectSingleton): + # Annotations for Numba mode + label: str = "implicit_capture" + active: bool + + def __init__(self): + self.active = False + + def __call__(self, active: bool = True): + self.active = active + + +# ====================================================================================== +# Weighted emission +# ====================================================================================== + + +class WeightedEmission(ObjectSingleton): + # Annotations for Numba mode + label: str = "weighted_emission" + + active: bool + weight_target: float + + def __init__(self): + self.active = False + self.weight_target = 0.0 + + def __call__(self, active: bool = True, weight_target: float = 1.0): + self.active = active + self.weight_target = weight_target + + +# ====================================================================================== +# Weight roulette +# ====================================================================================== + + +class WeightRoulette(ObjectSingleton): + # Annotations for Numba mode + label: str = "weight_roulette" + + weight_threshold: float + weight_target: float + + def __init__(self): + self.weight_threshold = 0.0 + self.weight_target = 1.0 + + def __call__(self, weight_threshold: float = 0.0, weight_target: float = 1.0): + if weight_threshold > weight_target: + print_error( + "For weight roulette, weight threshold has to be smaller than the target" + ) + self.weight_threshold = weight_threshold + self.weight_target = weight_target + + +# ====================================================================================== +# Population control +# ====================================================================================== + + +class PopulationControl(ObjectSingleton): + # Annotations for Numba mode + label: str = "population_control" + active: bool + + def __init__(self): + self.active = False + + def __call__(self, active: bool = True): + self.active = active diff --git a/mcdc/object_/universe.py b/mcdc/object_/universe.py new file mode 100644 index 000000000..4a1db3c1b --- /dev/null +++ b/mcdc/object_/universe.py @@ -0,0 +1,154 @@ +from __future__ import annotations +from types import NoneType +from typing import TYPE_CHECKING, Annotated + +if TYPE_CHECKING: + from mcdc.object_.cell import Cell + +#### + +import numpy as np + +from numpy import int64 +from numpy._typing import NDArray + +#### + +from mcdc.constant import INF +from mcdc.object_.base import ObjectNonSingleton +from mcdc.util import flatten + +# ====================================================================================== +# Universe +# ====================================================================================== + + +class Universe(ObjectNonSingleton): + # Annotations for Numba mode + label: str = "universe" + # + name: str + cells: list[Cell] + + def __init__(self, name: str = "", cells: list[Cell] = [], root: bool = False): + # Custom treatment for root universe + if root: + super().__init__(register=False) + self.ID = 0 + else: + super().__init__() + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.ID}" + + self.cells = cells + + def __repr__(self): + text = "\n" + text += f"Universe\n" + if self.ID == 0: + text += f" - ID: {self.ID} (root)\n" + else: + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f"Cells: {[x.ID for x in self.cells]}" + return text + + +# ====================================================================================== +# Lattice +# ====================================================================================== + + +class Lattice(ObjectNonSingleton): + # Annotations for Numba mode + label: str = "lattice" + # + name: str + x0: float + dx: float + Nx: int + y0: float + dy: float + Ny: int + z0: float + dz: float + Nz: int + universe_IDs: Annotated[NDArray[int64], ("Nx", "Ny", "Nz")] + + def __init__( + self, + name: str = "", + x: tuple[float, float, int] | NoneType = None, + y: tuple[float, float, int] | NoneType = None, + z: tuple[float, float, int] | NoneType = None, + universes: list[Universe] = None, + ): + super().__init__() + + # Set name + if name != "": + self.name = name + else: + self.name = f"{self.label}_{self.ID}" + + # Default uniform grids + self.x0 = -INF + self.dx = 2 * INF + self.Nx = 1 + self.y0 = -INF + self.dy = 2 * INF + self.Ny = 1 + self.z0 = -INF + self.dz = 2 * INF + self.Nz = 1 + self.t0 = 0.0 # Placeholder time grid is needed to use mesh indexing function + self.dt = INF + self.Nt = 1 + + # Set the grid + if x is not None: + self.x0 = x[0] + self.dx = x[1] + self.Nx = x[2] + if y is not None: + self.y0 = y[0] + self.dy = y[1] + self.Ny = y[2] + if z is not None: + self.z0 = z[0] + self.dz = z[1] + self.Nz = z[2] + + # Set universe IDs + get_ID = np.vectorize(lambda obj: obj.ID) + universe_IDs = get_ID(universes) + ax_expand = [] + if x is None: + ax_expand.append(2) + if y is None: + ax_expand.append(1) + if z is None: + ax_expand.append(0) + for ax in ax_expand: + universe_IDs = np.expand_dims(universe_IDs, axis=ax) + + # Change indexing structure: [z(flip), y(flip), x] --> [x, y, z] + universe_IDs = np.transpose(universe_IDs) + universe_IDs = np.flip(universe_IDs, axis=1) + universe_IDs = np.flip(universe_IDs, axis=2) + self.universe_IDs = np.array(universe_IDs) + + def __repr__(self): + text = "\n" + text += f"Lattice\n" + text += f" - ID: {self.ID}\n" + text += f" - Name: {self.name}\n" + text += f" - (x0, dx, Nx): ({self.x0}, {self.dx}, {self.Nx})\n" + text += f" - (y0, dy, Ny): ({self.y0}, {self.dy}, {self.Ny})\n" + text += f" - (z0, dz, Nz): ({self.z0}, {self.dz}, {self.Nz})\n" + text += f"Universes: {set([x.ID for x in list(flatten(self.universes))])}" + return text diff --git a/mcdc/object_/util.py b/mcdc/object_/util.py new file mode 100644 index 000000000..efa3e74c1 --- /dev/null +++ b/mcdc/object_/util.py @@ -0,0 +1,61 @@ +import numpy as np + + +def cmf_from_pmf(pmf): + cmf = np.zeros(len(pmf) + 1) + + # Build CMF incrementally + total = 0.0 + for idx in range(len(pmf)): + total += pmf[idx] + cmf[idx + 1] = total + + # Normalize this segment so CDF ends at 1 + norm = cmf[-1] + pmf /= norm + cmf /= norm + + return pmf, cmf + + +def cdf_from_pdf(value, pdf): + cdf = np.zeros_like(pdf) + + # Build CDF incrementally with trapezoidal integration + for idx in range(len(pdf) - 1): + cdf[idx + 1] = ( + cdf[idx] + (pdf[idx] + pdf[idx + 1]) * (value[idx + 1] - value[idx]) * 0.5 + ) + + # Normalize this segment so CDF ends at 1 + norm = cdf[-1] + pdf /= norm + cdf /= norm + + return pdf, cdf + + +def multi_cdf_from_pdf(offset, value, pdf): + cdf = np.zeros_like(pdf) + + for i in range(len(offset)): + start = offset[i] + end = offset[i + 1] if i < len(offset) - 1 else len(pdf) + + # Build CDF incrementally with trapezoidal integration + for idx in range(start, end - 1): + cdf[idx + 1] = ( + cdf[idx] + + (pdf[idx] + pdf[idx + 1]) * (value[idx + 1] - value[idx]) * 0.5 + ) + + # Normalize this segment so CDF ends at 1 + norm = cdf[end - 1] + pdf[start:end] /= norm + cdf[start:end] /= norm + + return pdf, cdf + + +def is_sorted(a): + return np.all(a[:-1] <= a[1:]) diff --git a/mcdc/output.py b/mcdc/output.py new file mode 100644 index 000000000..316f23004 --- /dev/null +++ b/mcdc/output.py @@ -0,0 +1,325 @@ +import h5py +import importlib.metadata +import numpy as np + +#### + +import mcdc.mcdc_get as mcdc_get +import mcdc.print_ as print_module + +from mcdc.constant import ( + MESH_UNIFORM, + MESH_STRUCTURED, + TALLY_MESH, +) + + +# ====================================================================================== +# Main output +# ====================================================================================== + + +def generate_output(mcdc, data): + from mcdc import simulation + + if not mcdc["mpi_master"]: + return + + settings = mcdc["settings"] + + # Header + if settings["use_progress_bar"]: + print_module.print_msg("") + print_module.print_msg(" Generating output HDF5 files...") + + # Create the file + file = h5py.File(settings["output_name"] + ".h5", "w") + + # Version + file["version"] = importlib.metadata.version("mcdc") + + # Settings + create_object_dataset(file, "settings", simulation.settings) + + # No need to output tally if time census-based tally is used + if mcdc["settings"]["use_census_based_tally"]: + return + + # Tallies + create_tally_dataset(file, mcdc, data) + + # Eigenvalues + if mcdc["settings"]["eigenvalue_mode"]: + N_cycle = mcdc["settings"]["N_cycle"] + file.create_dataset( + "k_cycle", data=mcdc_get.simulation.k_cycle_chunk(0, N_cycle, mcdc, data) + ) + file.create_dataset("k_mean", data=mcdc["k_avg_running"]) + file.create_dataset("k_sdev", data=mcdc["k_sdv_running"]) + file.create_dataset("global_tally/neutron/mean", data=mcdc["n_avg"]) + file.create_dataset("global_tally/neutron/sdev", data=mcdc["n_sdv"]) + file.create_dataset("global_tally/neutron/max", data=mcdc["n_max"]) + file.create_dataset("global_tally/precursor/mean", data=mcdc["C_avg"]) + file.create_dataset("global_tally/precursor/sdev", data=mcdc["C_sdv"]) + file.create_dataset("global_tally/precursor/max", data=mcdc["C_max"]) + if mcdc["settings"]["use_gyration_radius"]: + file.create_dataset( + "gyration_radius", + data=mcdc_get.simulation.gyration_radius_chunk(0, N_cycle, mcdc, data), + ) + + # Save particle? + if mcdc["settings"]["save_particle"]: + # Gather source bank + # TODO: Parallel HDF5 and mitigation of large data passing + N = mcdc["bank_source"]["size"][0] + neutrons = MPI.COMM_WORLD.gather(mcdc["bank_source"]["particles"][:N]) + + # Remove unwanted particle fields + neutrons = np.concatenate(neutrons[:]) + + # Create dataset + with h5py.File(mcdc["setting"]["output_name"] + ".h5", "a") as f: + file.create_dataset("particles", data=neutrons[:]) + file.create_dataset("particles_size", data=len(neutrons[:])) + + # Close the file + file.close() + + +# ====================================================================================== +# Input objects +# ====================================================================================== + + +def create_object_dataset(file, group_name, object_): + for name in [ + x + for x in dir(object_) + if (not x.startswith("__") and not callable(getattr(object_, x))) + ]: + file[f"{group_name}/{name}"] = getattr(object_, name) + + +# ====================================================================================== +# Runtimes +# ====================================================================================== + + +def create_runtime_datasets(mcdc): + import h5py + import mcdc.config as config + + if not mcdc["mpi_master"]: + return + + base_name = mcdc["settings"]["output_name"] + + main_output = h5py.File(f"{base_name}.h5", "a") + create_runtime_dataset(main_output, mcdc) + main_output.close() + + if config.args.runtime_output: + runtime_output = h5py.File(f"{base_name}.h5", "w") + create_runtime_dataset(runtime_output, mcdc) + runtime_output.close() + + +def create_runtime_dataset(file, mcdc): + for name in [ + "total", + "preparation", + "simulation", + "output", + "bank_management", + ]: + file.create_dataset(f"runtime/{name}", data=np.array([mcdc["runtime_" + name]])) + + +# ====================================================================================== +# Tally +# ====================================================================================== + + +def create_tally_dataset(file, mcdc, data): + from mcdc.object_.tally import decode_score_type + + # Loop over all tally types + for tally in mcdc["tallies"]: + tally_name = tally["name"] + + # Filter grids + file.create_dataset( + f"tallies/{tally_name}/grid/mu", data=mcdc_get.tally.mu_all(tally, data) + ) + file.create_dataset( + f"tallies/{tally_name}/grid/azi", + data=mcdc_get.tally.azi_all(tally, data), + ) + file.create_dataset( + f"tallies/{tally_name}/grid/energy", + data=mcdc_get.tally.energy_all(tally, data), + ) + file.create_dataset( + f"tallies/{tally_name}/grid/time", + data=mcdc_get.tally.time_all(tally, data), + ) + + # Mesh grid (TODO: Make mesh dataset in a separate group) + if tally["child_type"] == TALLY_MESH: + mesh_tally = mcdc["mesh_tallies"][tally["child_ID"]] + mesh_base = mcdc["meshes"][mesh_tally["mesh_ID"]] + mesh_type = mesh_base["child_type"] + mesh_ID = mesh_base["child_ID"] + if mesh_type == MESH_UNIFORM: + mesh = mcdc["uniform_meshes"][mesh_ID] + x = np.linspace( + mesh["x0"], mesh["x0"] + mesh["dx"] * mesh["Nx"], mesh["Nx"] + 1 + ) + y = np.linspace( + mesh["y0"], mesh["y0"] + mesh["dy"] * mesh["Ny"], mesh["Ny"] + 1 + ) + z = np.linspace( + mesh["z0"], mesh["z0"] + mesh["dz"] * mesh["Nz"], mesh["Nz"] + 1 + ) + elif mesh_type == MESH_STRUCTURED: + mesh = mcdc["structured_meshes"][mesh_ID] + x = mcdc_get.structured_mesh.x_all(mesh, data) + y = mcdc_get.structured_mesh.y_all(mesh, data) + z = mcdc_get.structured_mesh.z_all(mesh, data) + file.create_dataset(f"tallies/{tally_name}/grid/x", data=x) + file.create_dataset(f"tallies/{tally_name}/grid/y", data=y) + file.create_dataset(f"tallies/{tally_name}/grid/z", data=z) + + # Get and reshape tally + N_bin = tally["bin_length"] + start_mean = tally["bin_sum_offset"] + start_sdev = tally["bin_sum_square_offset"] + mean = data[start_mean : start_mean + N_bin] + sdev = data[start_sdev : start_sdev + N_bin] + shape = tuple([int(x) for x in mcdc_get.tally.bin_shape_all(tally, data)]) + mean = mean.reshape(shape) + sdev = sdev.reshape(shape) + + # Roll tally so that score is in the front + roll_reference = 4 + if tally["child_type"] == TALLY_MESH: + roll_reference = 7 + mean = np.rollaxis(mean, roll_reference, 0) + sdev = np.rollaxis(sdev, roll_reference, 0) + + # Iterate over scores + for i in range(tally["scores_length"]): + score_type = mcdc_get.tally.scores(i, tally, data) + score_mean = np.squeeze(mean[i]) + score_sdev = np.squeeze(sdev[i]) + score_name = decode_score_type(score_type, lower_case=True) + group_name = f"tallies/{tally_name}/{score_name}/" + file.create_dataset(group_name + "mean", data=score_mean) + file.create_dataset(group_name + "sdev", data=score_sdev) + + +def generate_census_based_tally(mcdc, data): + idx_batch = mcdc["idx_batch"] + idx_census = mcdc["idx_census"] + base_name = mcdc["settings"]["output_name"] + + # Create or get the file + file_name = f"{base_name}-batch_{idx_batch}-census_{idx_census}.h5" + file = h5py.File(file_name, "w") + create_tally_dataset(file, mcdc, data) + file.close() + + +def replace_dataset(file, field, data): + if field in file: + del file[field] + file.create_dataset(field, data=data) + + +def recombine_tallies(): + """Combine the tally output into a single file""" + import h5py + from mpi4py import MPI + from mcdc.object_.tally import decode_score_type + + if MPI.COMM_WORLD.Get_rank() > 0: + return + + # Get simulation and settings + from mcdc.object_.simulation import simulation + + settings = simulation.settings + if not settings.use_census_based_tally: + print("Census-based tally is not used, nothing to recombine.") + + # Settings parameters + base_name = settings.output_name + N_census = settings.N_census + N_batch = settings.N_batch + frequency = settings.census_tally_frequency + Nt = frequency * (N_census - 1) + + # Append the tally dataset structure to the main output + main_file = h5py.File(f"{base_name}.h5", "a") + reference_file = h5py.File(f"{base_name}-batch_0-census_0.h5", "r") + tally_group = main_file.create_group("tallies") + for tally in simulation.tallies: + name = f"tallies/{tally.name}" + reference_file.copy(name, tally_group) + reference_file.close() + + # Set the time grid + time_grid = np.zeros(Nt + 1) + for i in range(N_census - 1): + start = settings.census_time[i - 1] if i > 0 else 0.0 + end = settings.census_time[i] + new_grid = np.linspace(start, end, frequency + 1) + offset = i * frequency + 1 + time_grid[offset : offset + frequency] = new_grid[1:] + for tally in simulation.tallies: + name = f"tallies/{tally.name}/grid/time" + replace_dataset(main_file, name, time_grid) + + # Combine the tallies + for tally in simulation.tallies: + # The combined shape + shape = tally.bin_shape + shape[3] = Nt + + for score in tally.scores: + score_name = f"tallies/{tally.name}/{decode_score_type(score, True)}" + + mean = np.zeros(shape) + sdev = np.zeros(shape) + + # Selective squeeze + axes_to_squeeze = [x for x, size in enumerate(shape) if size == 1 and x > 3] + mean = np.squeeze(mean, axis=tuple(axes_to_squeeze)) + sdev = np.squeeze(sdev, axis=tuple(axes_to_squeeze)) + + for i_census in range(N_census - 1): + # Accumulate sum and sum of square + for i_batch in range(N_batch): + file_name = f"{base_name}-batch_{i_batch}-census_{i_census}.h5" + file = h5py.File(file_name, "r") + offset = i_census * frequency + + score = file[f"{score_name}/mean"][()] + mean[:, :, :, offset : offset + frequency] += score + sdev[:, :, :, offset : offset + frequency] += score * score + + file.close() + + # Squeeze + mean = np.squeeze(mean) + sdev = np.squeeze(sdev) + + # Compute statistics + mean /= N_batch + sdev = np.sqrt((sdev / N_batch - np.square(mean)) / (N_batch - 1)) + + replace_dataset(main_file, f"{score_name}/mean", mean) + replace_dataset(main_file, f"{score_name}/sdev", sdev) + + main_file.close() diff --git a/mcdc/print_.py b/mcdc/print_.py index 9ea000cb4..4da5824e3 100644 --- a/mcdc/print_.py +++ b/mcdc/print_.py @@ -1,5 +1,4 @@ import numba as nb -import numpy as np import sys from mpi4py import MPI from colorama import Fore, Back, Style @@ -7,6 +6,118 @@ master = MPI.COMM_WORLD.Get_rank() == 0 +import numba as nb +import sys + +from colorama import Fore, Style + +import mcdc.mcdc_get as mcdc_get + + +def print_1d_array(arr): + N = len(arr) + if N > 5: + return f"(size={len(arr)}): [{arr[0]:.5g}, {arr[1]:.5g}, ..., {arr[-2]:.5g}, {arr[-1]:.5g}]" + else: + text = f"(size={len(arr)}): [" + for i in range(N): + text += f"{arr[i]:.5g}, " + if N > 0: + text = text[:-2] + text += "]" + return text + + +def print_error(text): + print(Fore.RED + f"[ERROR]: {text}\n") + print(Style.RESET_ALL) + sys.stdout.flush() + sys.exit() + + +def print_warning(text): + print(Fore.YELLOW + f"[WARNING]: {text}\n") + print(Style.RESET_ALL) + sys.stdout.flush() + + +def print_banner(): + print( + "\n" + + r" __ __ ____ __ ____ ____ " + + "\n" + + r" | \/ |/ ___|/ /_ _ \ / ___|" + + "\n" + + r" | |\/| | | /_ / | | | | " + + "\n" + + r" | | | | |___ / /| |_| | |___ " + + "\n" + + r" |_| |_|\____|// |____/ \____|" + + "\n" + ) + sys.stdout.flush() + + +def print_configuration(): + mode = "Python" if nb.config.DISABLE_JIT else "Numba" + mpi_size = MPI.COMM_WORLD.Get_size() + + text = "" + text += f" Mode | {mode}\n" + text += f" MPI Processes | {mpi_size}\n" + print(text) + sys.stdout.flush() + + +def print_eigenvalue_header(mcdc): + if mcdc["settings"]["use_gyration_radius"]: + print("\n # k GyRad. k (avg) ") + print(" ==== ======= ====== ===================") + else: + print("\n # k k (avg) ") + print(" ==== ======= ===================") + sys.stdout.flush() + + +def print_batch_header(i, N): + print(f"\nBatch {i}/{N}") + sys.stdout.flush() + + +def print_time(tag, t, percent): + if t >= 24 * 60 * 60: + print(" %s | %.2f days (%.1f%%)" % (tag, t / 24 / 60 / 60), percent) + elif t >= 60 * 60: + print(" %s | %.2f hours (%.1f%%)" % (tag, t / 60 / 60, percent)) + elif t >= 60: + print(" %s | %.2f minutes (%.1f%%)" % (tag, t / 60, percent)) + else: + print(" %s | %.2f seconds (%.1f%%)" % (tag, t, percent)) + + +def print_runtime(mcdc): + total = mcdc["runtime_total"] + preparation = mcdc["runtime_preparation"] + simulation = mcdc["runtime_simulation"] + output = mcdc["runtime_output"] + print("\n Runtime report:") + print_time("Total ", total, 100) + print_time("Preparation", preparation, preparation / total * 100) + print_time("Simulation ", simulation, simulation / total * 100) + print_time("Output ", output, output / total * 100) + print("\n") + sys.stdout.flush() + + +def print_structure(struct): + dtype = struct.dtype + for name in dtype.names: + print(f"{name} = {struct[name]}") + + +# TODO: below is not evaulated yet during the refactor + + def print_msg(msg): if master: print(msg) @@ -26,114 +137,60 @@ def print_warning(msg): sys.stdout.flush() -def print_banner(mcdc): - size = MPI.COMM_WORLD.Get_size() - if master: - banner = ( - "\n" - + r" __ __ ____ __ ____ ____ " - + "\n" - + r" | \/ |/ ___|/ /_ _ \ / ___|" - + "\n" - + r" | |\/| | | /_ / | | | | " - + "\n" - + r" | | | | |___ / /| |_| | |___ " - + "\n" - + r" |_| |_|\____|// |____/ \____|" - + "\n" - + "\n" - ) - if nb.config.DISABLE_JIT: - banner += " Mode | Python\n" - else: - banner += " Mode | Numba\n" - if mcdc["technique"]["iQMC"]: - banner += " Algorithm | iQMC\n" - if mcdc["setting"]["mode_eigenvalue"]: - solver = "power iteration" - else: - solver = mcdc["technique"]["iqmc"]["fixed_source_solver"] - banner += " Solver | " + solver + "\n" - else: - banner += " Algorithm | History-based\n" - banner += " MPI Processes | %i\n" % size - banner += " OpenMP Threads | 1" - print(banner) - sys.stdout.flush() - - def print_progress(percent, mcdc): if master: sys.stdout.write("\r") - if not mcdc["setting"]["mode_eigenvalue"]: - if mcdc["setting"]["N_census"] == 1: + if not mcdc["settings"]["eigenvalue_mode"]: + if mcdc["settings"]["N_census"] == 1: sys.stdout.write( " [%-28s] %d%%" % ("=" * int(percent * 28), percent * 100.0) ) else: idx = mcdc["idx_census"] + 1 - N = len(mcdc["setting"]["census_time"]) + N = mcdc["settings"]["N_census"] sys.stdout.write( " Census %i/%i: [%-28s] %d%%" % (idx, N, "=" * int(percent * 28), percent * 100.0) ) else: - if mcdc["setting"]["gyration_radius"]: + if mcdc["settings"]["use_gyration_radius"]: sys.stdout.write( " [%-40s] %d%%" % ("=" * int(percent * 40), percent * 100.0) ) else: sys.stdout.write( - "[%-32s] %d%%" % ("=" * int(percent * 32), percent * 100.0) + " [%-32s] %d%%" % ("=" * int(percent * 32), percent * 100.0) ) sys.stdout.flush() -def print_progress_iqmc(mcdc): - # TODO: function was not working with numba when structured like the - # other print_progress functions - if master: - if mcdc["setting"]["progress_bar"]: - sys.stdout.write("\r") - itt = mcdc["technique"]["iqmc"]["iteration_count"] - res = mcdc["technique"]["iqmc"]["residual"] - print("\n*******************************") - print("Iteration %2d" % (itt)) - print("Residual %10.3E" % (res)) - print("*******************************\n") - sys.stdout.flush() - - def print_header_eigenvalue(mcdc): if master: - if mcdc["setting"]["gyration_radius"]: + if mcdc["settings"]["use_gyration_radius"]: print("\n # k GyRad. k (avg) ") print(" ==== ======= ====== ===================") - elif mcdc["technique"]["iQMC"] and mcdc["technique"]["iqmc"]["mode"] == "fixed": - print("\n # k Residual ") - print(" ==== ======= ===================") else: print("\n # k k (avg) ") print(" ==== ======= ===================") -def print_header_batch(mcdc): - idx_batch = mcdc["idx_batch"] +def print_header_batch(i, N): if master: - print("\nBatch %i/%i" % (idx_batch + 1, mcdc["setting"]["N_batch"])) + print(f"\nBatch {i+1}/{N}") + sys.stdout.flush() -def print_progress_eigenvalue(mcdc): +def print_progress_eigenvalue(mcdc, data): if master: idx_cycle = mcdc["idx_cycle"] k_eff = mcdc["k_eff"] k_avg = mcdc["k_avg_running"] k_sdv = mcdc["k_sdv_running"] - gr = mcdc["gyration_radius"][idx_cycle] - if mcdc["setting"]["progress_bar"]: + gr = mcdc_get.simulation.gyration_radius(idx_cycle, mcdc, data) + if mcdc["settings"]["use_progress_bar"]: sys.stdout.write("\r") sys.stdout.write("\033[K") - if mcdc["setting"]["gyration_radius"]: + if mcdc["settings"]["use_gyration_radius"]: if not mcdc["cycle_active"]: print(" %-4i %.5f %6.2f" % (idx_cycle + 1, k_eff, gr)) else: @@ -150,38 +207,6 @@ def print_progress_eigenvalue(mcdc): ) -def print_iqmc_eigenvalue_progress(mcdc): - if master: - if mcdc["setting"]["progress_bar"]: - sys.stdout.write("\r") - k_eff = mcdc["k_eff"] - itt = mcdc["technique"]["iqmc"]["iteration_count"] - res = mcdc["technique"]["iqmc"]["residual"] - print("\n %2d %2.5f %10.3E" % (itt, k_eff, res)) - sys.stdout.flush() - - -def print_iqmc_eigenvalue_exit_code(mcdc): - if master: - if mcdc["setting"]["progress_bar"]: - sys.stdout.write("\r") - maxit = mcdc["technique"]["iqmc"]["iterations_max"] - itt = mcdc["technique"]["iqmc"]["iteration_count"] - if itt >= maxit: - print("\n") - print("================================") - print("\n") - print( - " Convergence to tolerance not achieved: Maximum number of iterations." - ) - else: - print("\n") - print("================================") - print(" Successful convergence.") - print("\n") - sys.stdout.flush() - - def print_runtime(mcdc): total = mcdc["runtime_total"] preparation = mcdc["runtime_preparation"] diff --git a/mcdc/src/algorithm.py b/mcdc/src/algorithm.py deleted file mode 100644 index 6fddb8281..000000000 --- a/mcdc/src/algorithm.py +++ /dev/null @@ -1,37 +0,0 @@ -from numba import njit - - -@njit -def binary_search_with_length(val, grid, length): - """ - Binary search that returns the bin index of the value `val` given grid `grid` - Only search up to `length`-th element - - Some special cases: - val < min(grid) --> -1 - val > max(grid) --> size of bins - val = a grid point --> bin location whose upper bound is val - (-1 if val = min(grid)) - """ - left = 0 - if length == 0: - right = len(grid) - 1 - else: - right = length - 1 - mid = -1 - while left <= right: - mid = int((left + right) / 2) - if grid[mid] < val: - left = mid + 1 - else: - right = mid - 1 - return int(right) - - -@njit -def binary_search(val, grid): - """ - Binary search with full length of the given grid. - See binary_search_with _length - """ - return binary_search_with_length(val, grid, 0) diff --git a/mcdc/src/mesh/__init__.py b/mcdc/src/mesh/__init__.py deleted file mode 100644 index 607f85dca..000000000 --- a/mcdc/src/mesh/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from mcdc.src.mesh import structured, uniform diff --git a/mcdc/src/mesh/structured.py b/mcdc/src/mesh/structured.py deleted file mode 100644 index d7db06371..000000000 --- a/mcdc/src/mesh/structured.py +++ /dev/null @@ -1,157 +0,0 @@ -from numba import njit - -from mcdc.src.algorithm import binary_search_with_length -from mcdc.constant import COINCIDENCE_TOLERANCE, COINCIDENCE_TOLERANCE_TIME, INF - - -@njit -def get_indices(particle_container, mesh): - """ - Get mesh indices given the particle coordinate - """ - particle = particle_container[0] - - # Particle coordinate - x = particle["x"] - y = particle["y"] - z = particle["z"] - t = particle["t"] - ux = particle["ux"] - uy = particle["uy"] - uz = particle["uz"] - - # Mesh parameters - Nx = mesh["Nx"] - Ny = mesh["Ny"] - Nz = mesh["Nz"] - Nt = mesh["Nt"] - - # Check if particle is outside the mesh grid - outside = False - if ( - # Outside the mesh condition - x < mesh["x"][0] - COINCIDENCE_TOLERANCE - or x > mesh["x"][Nx] + COINCIDENCE_TOLERANCE - or y < mesh["y"][0] - COINCIDENCE_TOLERANCE - or y > mesh["y"][Ny] + COINCIDENCE_TOLERANCE - or z < mesh["z"][0] - COINCIDENCE_TOLERANCE - or z > mesh["z"][Nz] + COINCIDENCE_TOLERANCE - or t < mesh["t"][0] - COINCIDENCE_TOLERANCE_TIME - or t > mesh["t"][Nt] + COINCIDENCE_TOLERANCE_TIME - # At the outermost-grid but moving away - or (abs(x - mesh["x"][0]) < COINCIDENCE_TOLERANCE and ux < 0.0) - or (abs(x - mesh["x"][Nx]) < COINCIDENCE_TOLERANCE and ux > 0.0) - or (abs(y - mesh["y"][0]) < COINCIDENCE_TOLERANCE and uy < 0.0) - or (abs(y - mesh["y"][Ny]) < COINCIDENCE_TOLERANCE and uy > 0.0) - or (abs(z - mesh["z"][0]) < COINCIDENCE_TOLERANCE and uz < 0.0) - or (abs(z - mesh["z"][Nz]) < COINCIDENCE_TOLERANCE and uz > 0.0) - or (abs(t - mesh["t"][Nt]) < COINCIDENCE_TOLERANCE_TIME) - ): - outside = True - return -1, -1, -1, -1, outside - - ix = _grid_index(x, ux, mesh["x"], Nx + 1, COINCIDENCE_TOLERANCE) - iy = _grid_index(y, uy, mesh["y"], Ny + 1, COINCIDENCE_TOLERANCE) - iz = _grid_index(z, uz, mesh["z"], Nz + 1, COINCIDENCE_TOLERANCE) - it = _grid_index( - t, 1.0, mesh["t"], Nt + 1, COINCIDENCE_TOLERANCE_TIME - ) # Particle always moves forward in time - - return ix, iy, iz, it, outside - - -@njit -def get_crossing_distance(particle_arr, speed, mesh): - """ - Get distance for the particle, moving with the given speed, - to cross the nearest grid of the mesh - """ - particle = particle_arr[0] - - # Particle coordinate - x = particle["x"] - y = particle["y"] - z = particle["z"] - t = particle["t"] - ux = particle["ux"] - uy = particle["uy"] - uz = particle["uz"] - - # Mesh parameters - Nx = mesh["Nx"] - Ny = mesh["Ny"] - Nz = mesh["Nz"] - Nt = mesh["Nt"] - - # Check if particle is outside the mesh grid and moving away - outside = False - if ( - (t > mesh["t"][Nt] - COINCIDENCE_TOLERANCE_TIME) - or (x < mesh["x"][0] + COINCIDENCE_TOLERANCE and ux < 0.0) - or (x > mesh["x"][Nx] - COINCIDENCE_TOLERANCE and ux > 0.0) - or (y < mesh["y"][0] + COINCIDENCE_TOLERANCE and uy < 0.0) - or (y > mesh["y"][Ny] - COINCIDENCE_TOLERANCE and uy > 0.0) - or (z < mesh["z"][0] + COINCIDENCE_TOLERANCE and uz < 0.0) - or (z > mesh["z"][Nz] - COINCIDENCE_TOLERANCE and uz > 0.0) - ): - return INF - - d = INF - d = min(d, _grid_distance(x, ux, mesh["x"], Nx + 1, COINCIDENCE_TOLERANCE)) - d = min(d, _grid_distance(y, uy, mesh["y"], Ny + 1, COINCIDENCE_TOLERANCE)) - d = min(d, _grid_distance(z, uz, mesh["z"], Nz + 1, COINCIDENCE_TOLERANCE)) - d = min( - d, _grid_distance(t, 1.0 / speed, mesh["t"], Nt + 1, COINCIDENCE_TOLERANCE_TIME) - ) - return d - - -@njit -def _grid_index(value, direction, grid, length, tolerance): - """ - Get grid index given the value and the direction - - Direction is used to tiebreak when the value is at a grid point - (within tolerance). - Note: It assumes the value is inside the grid. - """ - idx = binary_search_with_length(value, grid, length) - - # Coinciding cases - if direction > 0.0: - if abs(grid[idx + 1] - value) < tolerance: - idx += 1 - else: - if abs(grid[idx] - value) < tolerance: - idx -= 1 - - return idx - - -@njit -def _grid_distance(value, direction, grid, length, tolerance): - """ - Get distance to nearest grid given a value and direction - - Direction is used to tiebreak when the value is at a grid point - (within tolerance). - Note: It assumes that a grid must be hit - """ - if direction == 0.0: - return INF - - idx = binary_search_with_length(value, grid, length) - - if direction > 0.0: - idx += 1 - - # Coinciding cases - if abs(grid[idx] - value) < tolerance: - if direction > 0.0: - idx += 1 - else: - idx -= 1 - - dist = (grid[idx] - value) / direction - - return dist diff --git a/mcdc/src/physics.py b/mcdc/src/physics.py deleted file mode 100644 index 22e0739fe..000000000 --- a/mcdc/src/physics.py +++ /dev/null @@ -1,31 +0,0 @@ -import math - -from numba import njit - -from mcdc.constant import SQRT_E_TO_SPEED - - -# ====================================================================================== -# Particle properties -# ====================================================================================== - - -@njit -def get_speed(particle_container, mcdc): - """ - Get particle speed - """ - particle = particle_container[0] - - # Multigroup - if mcdc["setting"]["mode_MG"]: - material_ID = particle["material_ID"] - g = particle["g"] - - material = mcdc["materials"][material_ID] - - return material["speed"][g] - - # Continuoues energy - else: - return math.sqrt(particle["E"]) * SQRT_E_TO_SPEED diff --git a/mcdc/src/surface/__init__.py b/mcdc/src/surface/__init__.py deleted file mode 100644 index 3972f14ea..000000000 --- a/mcdc/src/surface/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from mcdc.src.surface.common import * diff --git a/mcdc/tally.py b/mcdc/tally.py deleted file mode 100644 index 4cb6d9b9e..000000000 --- a/mcdc/tally.py +++ /dev/null @@ -1,314 +0,0 @@ -# Get input_deck -import mcdc.config as config -import mcdc.global_ as global_ - -import numpy as np -from numba import njit - -from mcdc.card import ( - MeshTallyCard, - SurfaceTallyCard, - CellTallyCard, - CSTallyCard, -) -from mcdc.constant import ( - INF, - PI, -) -from mcdc.input_ import check_support -import mcdc.type_ as type_ - - -def mesh_tally( - x=np.array([-INF, INF]), - y=np.array([-INF, INF]), - z=np.array([-INF, INF]), - t=np.array([-INF, INF]), - mu=np.array([-1.0, 1.0]), - azi=np.array([-PI, PI]), - g=np.array([-INF, INF]), - E=np.array([0.0, INF]), - scores=["flux"], -): - """ - Create a tally card to collect MC solutions. - - Parameters - ---------- - x : array_like[float], optional - x-coordinates that demarcate tally bins. - y : array_like[float], optional - y-coordinates that demarcate tally bins. - z : array_like[float], optional - z-coordinates that demarcate tally bins. - t : array_like[float], optional - Times that demarcate tally bins. - mu : array_like[float], optional - Angles that demarcate axial angular tally bins. - azi : array_like[float], optional - Angles that demarcate azimuthal angular tally bins. - g : array_like[float] or str, optional - Energy group halves that demarcate energy group tally bins. - String value "all" can be used to tally each individual group. - E : array_like[float], optional - Energies that demarcate energy tally bins. This overrides `g` in - continuous-energy mode. - scores : list of str {"flux", "total", "fission", "density"} - List of physical quantities to be scored. - - Returns - ------- - MeshTallyCard - The tally card. - """ - - # Make tally card - card = MeshTallyCard() - - # Set ID - card.ID = len(global_.input_deck.mesh_tallies) - - # Set mesh - card.x = x - card.y = y - card.z = z - - # Set other filters - card.t = t - card.mu = mu - card.azi = azi - - # Set energy group grid - if type(g) == type("string") and g == "all": - G = global_.input_deck.materials[0].G - card.g = np.linspace(0, G, G + 1) - 0.5 - else: - card.g = g - if global_.input_deck.setting["mode_CE"]: - card.g = E - - # Calculate total number bins - Nx = len(card.x) - 1 - Ny = len(card.y) - 1 - Nz = len(card.z) - 1 - Nt = len(card.t) - 1 - Nmu = len(card.mu) - 1 - N_azi = len(card.azi) - 1 - Ng = len(card.g) - 1 - card.N_bin = Nx * Ny * Nz * Nt * Nmu * N_azi * Ng - - # Scores - for s in scores: - score_checked = check_support( - "score type", - s, - [ - "flux", - "total", - "fission", - "density", - "net-current", - "mu-sq", - "time-moment-flux", - "space-moment-flux", - "time-moment-current", - "space-moment-current", - "time-moment-mu-sq", - "space-moment-mu-sq", - ], - ) - card.scores.append(score_checked) - - # Add to deck - global_.input_deck.mesh_tallies.append(card) - - return card - - -def surface_tally( - surface, - scores=["net-current"], -): - """ - Create a tally card to collect MC solutions. - - Parameters - ---------- - surface : SurfaceCard - Surface to which the tally is attached to - scores : list of str {"flux", "net-current"} - List of physical quantities to be scored. - - Returns - ------- - SurfaceTallyCard - The tally card. - """ - - # Make tally card - card = SurfaceTallyCard(surface.ID) - - # Set ID - card.ID = len(global_.input_deck.surface_tallies) - - # Set surface - card.surface_ID = surface.ID - surface.tally_IDs.append(card.ID) - surface.N_tally += 1 - - # Calculate total number bins - card.N_bin = 1 - - # Scores - for s in scores: - score_checked = check_support( - "score type", - s, - ["flux", "net-current"], - ) - card.scores.append(score_checked) - - # Add to deck - global_.input_deck.surface_tallies.append(card) - - return card - - -def cell_tally( - cell, - t=np.array([-INF, INF]), - g=np.array([-INF, INF]), - E=np.array([0.0, INF]), - scores=["flux"], -): - """ - Create a tally card to collect MC solutions. - - Parameters - ---------- - cell : CellCard - Cell to which the tally is attached to - t : array_like[float], optional - Times that demarcate tally bins. - g : array_like[float] or str, optional - Energy group halves that demarcate energy group tally bins. - String value "all" can be used to tally each individual group. - E : array_like[float], optional - Energies that demarcate energy tally bins. This overrides `g` in - continuous-energy mode. - scores : list of str {"flux", "net-current"} - List of physical quantities to be scored. - - Returns - ------- - CellTallyCard - The tally card. - """ - - # Make tally card - card = CellTallyCard(cell.ID) - - # Set ID - card.ID = len(global_.input_deck.cell_tallies) - - card.t = t - # Set energy group grid - if type(g) == type("string") and g == "all": - G = global_.input_deck.materials[0].G - card.g = np.linspace(0, G, G + 1) - 0.5 - else: - card.g = g - if global_.input_deck.setting["mode_CE"]: - card.g = E - - # Set cell - card.cell_ID = cell.ID - cell.tally_IDs.append(card.ID) - cell.N_tally += 1 - - # Calculate total number bins - Nt = len(card.t) - 1 - Ng = len(card.g) - 1 - card.N_bin = Nt * Ng - - # Scores - for s in scores: - score_checked = check_support( - "score type", - s, - ["flux", "net-current", "fission"], - ) - card.scores.append(score_checked) - - # Add to deck - global_.input_deck.cell_tallies.append(card) - - return card - - -def cs_tally( - N_cs_bins=10, - cs_bin_size=([1.0, 1.0]), - x=np.array([-INF, INF]), - y=np.array([-INF, INF]), - z=np.array([-INF, INF]), - t=np.array([-INF, INF]), - mu=np.array([-1.0, 1.0]), - azi=np.array([-PI, PI]), - g=np.array([-INF, INF]), - E=np.array([0.0, INF]), - scores=["flux"], -): - # Make tally card - card = CSTallyCard() - - # Set ID - card.ID = len(global_.input_deck.cs_tallies) - - # Set mesh - card.x = x - card.y = y - card.z = z - - # Set bin properties, convert bin size to problem units - card.N_cs_bins = N_cs_bins - card.cs_bin_size[0] = cs_bin_size[0] / (len(x) - 1) * (x[-1] - x[0]) - card.cs_bin_size[1] = cs_bin_size[1] / (len(y) - 1) * (y[-1] - y[0]) - - # Set other filters - card.t = t - card.mu = mu - card.azi = azi - - # Set energy group grid - if type(g) == type("string") and g == "all": - G = global_.input_deck.materials[0].G - card.g = np.linspace(0, G, G + 1) - 0.5 - else: - card.g = g - if global_.input_deck.setting["mode_CE"]: - card.g = E - - # Calculate total number bins - Nx = len(card.x) - 1 - Ny = len(card.y) - 1 - Nz = len(card.z) - 1 - Nt = len(card.t) - 1 - Nmu = len(card.mu) - 1 - N_azi = len(card.azi) - 1 - Ng = len(card.g) - 1 - card.N_bin = Nx * Ny * Nz * Nt * Nmu * N_azi * Ng - - # Scores - for s in scores: - score_checked = check_support( - "score type", - s, - ["flux", "total", "fission", "density"], - ) - card.scores.append(score_checked) - - # Add to deck - global_.input_deck.cs_tallies.append(card) - - return card diff --git a/mcdc/transport/.gitignore b/mcdc/transport/.gitignore new file mode 100644 index 000000000..b9792f1c3 --- /dev/null +++ b/mcdc/transport/.gitignore @@ -0,0 +1 @@ +literals.py diff --git a/mcdc/transport/data.py b/mcdc/transport/data.py new file mode 100644 index 000000000..51e8b9b3b --- /dev/null +++ b/mcdc/transport/data.py @@ -0,0 +1,51 @@ +from numba import njit + +#### + +import mcdc.mcdc_get as mcdc_get + +from mcdc.constant import ( + DATA_POLYNOMIAL, + DATA_TABLE, + INTERPOLATION_LINEAR, + INTERPOLATION_LOG, +) +from mcdc.transport.util import find_bin, linear_interpolation, log_interpolation + + +@njit +def evaluate_data(x, data_base, mcdc, data): + data_type = data_base["child_type"] + ID = data_base["child_ID"] + if data_type == DATA_TABLE: + table = mcdc["table_data"][ID] + return evaluate_table(x, table, data) + elif data_type == DATA_POLYNOMIAL: + polynomial = mcdc["polynomial_data"][ID] + return evaluate_polynomial(x, polynomial, data) + else: + return 0.0 + + +@njit +def evaluate_table(x, table, data): + grid = mcdc_get.table_data.x_all(table, data) + idx = find_bin(x, grid) + x1 = grid[idx] + x2 = grid[idx + 1] + y1 = mcdc_get.table_data.y(idx, table, data) + y2 = mcdc_get.table_data.y(idx + 1, table, data) + + if table["interpolation"] == INTERPOLATION_LINEAR: + return linear_interpolation(x, x1, x2, y1, y2) + elif table["interpolation"] == INTERPOLATION_LOG: + return log_interpolation(x, x1, x2, y1, y2) + + +@njit +def evaluate_polynomial(x, polynomial, data): + coeffs = mcdc_get.polynomial_data.coefficients_all(polynomial, data) + total = 0.0 + for i in range(len(coeffs)): + total += coeffs[i] * x**i + return total diff --git a/mcdc/transport/distribution.py b/mcdc/transport/distribution.py new file mode 100644 index 000000000..579680622 --- /dev/null +++ b/mcdc/transport/distribution.py @@ -0,0 +1,544 @@ +import math + +from numba import njit + +#### + +import mcdc.mcdc_get as mcdc_get +import mcdc.transport.rng as rng + +from mcdc.constant import ( + DISTRIBUTION_EVAPORATION, + DISTRIBUTION_KALBACH_MANN, + DISTRIBUTION_LEVEL_SCATTERING, + DISTRIBUTION_MAXWELLIAN, + DISTRIBUTION_MULTITABLE, + DISTRIBUTION_N_BODY, + DISTRIBUTION_TABULATED, + DISTRIBUTION_TABULATED_ENERGY_ANGLE, + PI, +) +from mcdc.transport.data import evaluate_table +from mcdc.transport.util import find_bin, linear_interpolation + + +# ====================================================================================== +# General distribution samplers +# ====================================================================================== + + +@njit +def sample_distribution(E, distribution, rng_state, mcdc, data, scale=False): + distribution_type = distribution["child_type"] + ID = distribution["child_ID"] + + if distribution_type == DISTRIBUTION_TABULATED: + table = mcdc["tabulated_distributions"][ID] + return sample_tabulated(table, rng_state, data) + + elif distribution_type == DISTRIBUTION_MULTITABLE: + multi_table = mcdc["multi_table_distributions"][ID] + return sample_multi_table(E, rng_state, multi_table, data, scale) + + elif distribution_type == DISTRIBUTION_LEVEL_SCATTERING: + level_scattering = mcdc["level_scattering_distributions"][ID] + return sample_level_scattering(E, level_scattering) + + elif distribution_type == DISTRIBUTION_EVAPORATION: + evaporation = mcdc["evaporation_distributions"][ID] + return sample_evaporation(E, rng_state, evaporation, mcdc, data) + + elif distribution_type == DISTRIBUTION_MAXWELLIAN: + maxwellian = mcdc["maxwellian_distributions"][ID] + return sample_maxwellian(E, rng_state, maxwellian, mcdc, data) + + # TODO: Should not get here + else: + return -1.0 + + +@njit +def sample_correlated_distribution(E, distribution, rng_state, mcdc, data, scale=False): + distribution_type = distribution["child_type"] + ID = distribution["child_ID"] + + if distribution_type == DISTRIBUTION_KALBACH_MANN: + kalbach_mann = mcdc["kalbach_mann_distributions"][ID] + return sample_kalbach_mann(E, rng_state, kalbach_mann, data) + + elif distribution_type == DISTRIBUTION_TABULATED_ENERGY_ANGLE: + table = mcdc["tabulated_energy_angle_distributions"][ID] + return sample_tabulated_energy_angle(E, rng_state, table, data) + + elif distribution_type == DISTRIBUTION_N_BODY: + nbody = mcdc["nbody_distributions"][ID] + E_out = sample_tabulated(nbody, rng_state, data) + mu = sample_isotropic_cosine(rng_state) + return E_out, mu + + # TODO: Should not get here + else: + return -1.0, -1.0 + + +# ====================================================================================== +# Distribution samplers +# ====================================================================================== + + +@njit +def sample_uniform(low, high, rng_state): + return low + rng.lcg(rng_state) * (high - low) + + +@njit +def sample_isotropic_cosine(rng_state): + return 2.0 * rng.lcg(rng_state) - 1.0 + + +@njit +def sample_isotropic_direction(rng_state): + # Sample polar cosine and azimuthal angle uniformly + mu = sample_isotropic_cosine(rng_state) + azi = 2.0 * PI * rng.lcg(rng_state) + + # Convert to Cartesian coordinates + c = (1.0 - mu**2) ** 0.5 + y = math.cos(azi) * c + z = math.sin(azi) * c + x = mu + return x, y, z + + +@njit +def sample_tabulated(table, rng_state, data): + xi = rng.lcg(rng_state) + idx = find_bin(xi, mcdc_get.tabulated_distribution.cdf_all(table, data)) + cdf_low = mcdc_get.tabulated_distribution.cdf(idx, table, data) + cdf_high = mcdc_get.tabulated_distribution.cdf(idx + 1, table, data) + value_low = mcdc_get.tabulated_distribution.value(idx, table, data) + value_high = mcdc_get.tabulated_distribution.value(idx + 1, table, data) + return linear_interpolation(xi, cdf_low, cdf_high, value_low, value_high) + + +@njit +def sample_pmf(pmf, rng_state, data): + xi = rng.lcg(rng_state) + idx = find_bin(xi, mcdc_get.pmf_distribution.cmf_all(pmf, data)) + return mcdc_get.pmf_distribution.value(idx, pmf, data) + + +@njit +def sample_white_direction(nx, ny, nz, rng_state): + # Sample polar cosine + mu = math.sqrt(rng.lcg(rng_state)) + + # Sample azimuthal direction + azi = 2.0 * PI * rng.lcg(rng_state) + cos_azi = math.cos(azi) + sin_azi = math.sin(azi) + Ac = (1.0 - mu**2) ** 0.5 + + if nz != 1.0: + B = (1.0 - nz**2) ** 0.5 + C = Ac / B + + x = nx * mu + (nx * nz * cos_azi - ny * sin_azi) * C + y = ny * mu + (ny * nz * cos_azi + nx * sin_azi) * C + z = nz * mu - cos_azi * Ac * B + + # If dir = 0i + 0j + k, interchange z and y in the formula + else: + B = (1.0 - ny**2) ** 0.5 + C = Ac / B + + x = nx * mu + (nx * ny * cos_azi - nz * sin_azi) * C + z = nz * mu + (nz * ny * cos_azi + nx * sin_azi) * C + y = ny * mu - cos_azi * Ac * B + return x, y, z + + +@njit +def sample_multi_table(E, rng_state, multi_table, data, scale=False): + grid = mcdc_get.multi_table_distribution.grid_all(multi_table, data) + + # Edge cases + if E < grid[0]: + idx = 0 + scale = False + elif E > grid[-1]: + idx = len(grid) - 1 + scale = False + else: + # Interpolation factor + idx = find_bin(E, grid) + E0 = grid[idx] + E1 = grid[idx + 1] + f = (E - E0) / (E1 - E0) + + # Min and max values for scaling + val_min = 0.0 + val_max = 1.0 + if scale: + # First table + start = int( + mcdc_get.multi_table_distribution.offset(idx, multi_table, data) + ) + end = int( + mcdc_get.multi_table_distribution.offset(idx + 1, multi_table, data) + ) + val0_min = mcdc_get.multi_table_distribution.value(start, multi_table, data) + val0_max = mcdc_get.multi_table_distribution.value( + end - 1, multi_table, data + ) + + # Second table + start = end + if idx + 2 == len(grid): + end = multi_table["value_length"] + else: + end = int( + mcdc_get.multi_table_distribution.offset(idx + 2, multi_table, data) + ) + val1_min = mcdc_get.multi_table_distribution.value(start, multi_table, data) + val1_max = mcdc_get.multi_table_distribution.value( + end - 1, multi_table, data + ) + + # Both + val_min = val0_min + f * (val1_min - val0_min) + val_max = val0_max + f * (val1_max - val0_max) + + # Sample which table to choose + if rng.lcg(rng_state) > f: + idx += 1 + + # Get the table range + start = int(mcdc_get.multi_table_distribution.offset(idx, multi_table, data)) + if idx + 1 == len(grid): + end = multi_table["value_length"] + else: + end = int(mcdc_get.multi_table_distribution.offset(idx + 1, multi_table, data)) + size = end - start + + # The CDF + cdf = mcdc_get.multi_table_distribution.cdf_chunk(start, size, multi_table, data) + + # Generate random numbers + xi = rng.lcg(rng_state) + + # Sample bin index + idx = find_bin(xi, cdf) + c = cdf[idx] + + # Get the other values + idx += start # Apply the offset as these are not chunk-extracted like the cdf + p0 = mcdc_get.multi_table_distribution.pdf(idx, multi_table, data) + p1 = mcdc_get.multi_table_distribution.pdf(idx + 1, multi_table, data) + val0 = mcdc_get.multi_table_distribution.value(idx, multi_table, data) + val1 = mcdc_get.multi_table_distribution.value(idx + 1, multi_table, data) + + m = (p1 - p0) / (val1 - val0) + if m == 0.0: + sample = val0 + (xi - c) / p0 + else: + sample = val0 + 1.0 / m * (math.sqrt(p0**2 + 2 * m * (xi - c)) - p0) + + if not scale: + return sample + + # Scale against the bounds + val_low = mcdc_get.multi_table_distribution.value(start, multi_table, data) + val_high = mcdc_get.multi_table_distribution.value(end - 1, multi_table, data) + return val_min + (sample - val_low) / (val_high - val_low) * (val_max - val_min) + + +@njit +def sample_maxwellian(E, rng_state, maxwellian, mcdc, data): + # Get nuclear temperature + table = mcdc["table_data"][maxwellian["nuclear_temperature_ID"]] + nuclear_temperature = evaluate_table(E, table, data) + restriction_energy = maxwellian["restriction_energy"] + + # Rejection sampling + while True: + xi1 = rng.lcg(rng_state) + xi2 = rng.lcg(rng_state) + xi3 = rng.lcg(rng_state) + cos = math.cos(0.5 * PI * xi3) + cos_square = cos * cos + sample = -nuclear_temperature * (math.log(xi1) + math.log(xi2) * cos_square) + + # Accept sample? + if 0.0 <= sample and sample <= E - restriction_energy: + break + + return sample + + +@njit +def sample_level_scattering(E, level_scattering): + C1 = level_scattering["C1"] + C2 = level_scattering["C2"] + return C2 * (E - C1) + + +@njit +def sample_evaporation(E, rng_state, evaporation, mcdc, data): + # Get nuclear temperature + table = mcdc["table_data"][evaporation["nuclear_temperature_ID"]] + nuclear_temperature = evaluate_table(E, table, data) + restriction_energy = evaporation["restriction_energy"] + + w = (E - restriction_energy) / nuclear_temperature + g = 1.0 - math.exp(-w) + + # Rejection sampling + while True: + xi1 = rng.lcg(rng_state) + xi2 = rng.lcg(rng_state) + sample = -nuclear_temperature * math.log((1.0 - g * xi1) * (1.0 - g * xi2)) + + # Accept sample? + if 0.0 <= sample and sample <= E - restriction_energy: + break + + return sample + + +@njit +def sample_kalbach_mann(E, rng_state, kalbach_mann, data): + grid = mcdc_get.kalbach_mann_distribution.energy_all(kalbach_mann, data) + + # Random numbers + xi1 = rng.lcg(rng_state) + xi2 = rng.lcg(rng_state) + xi3 = rng.lcg(rng_state) + xi4 = rng.lcg(rng_state) + + # Interpolation factor + idx = find_bin(E, grid) + E0 = grid[idx] + E1 = grid[idx + 1] + f = (E - E0) / (E1 - E0) + + # ================================================================================== + # Min and max energy values for scaling + # ================================================================================== + + # First table + start = int(mcdc_get.kalbach_mann_distribution.offset(idx, kalbach_mann, data)) + end = int(mcdc_get.kalbach_mann_distribution.offset(idx + 1, kalbach_mann, data)) + E0_min = mcdc_get.kalbach_mann_distribution.energy_out(start, kalbach_mann, data) + E0_max = mcdc_get.kalbach_mann_distribution.energy_out(end - 1, kalbach_mann, data) + + # Second table + start = end + if idx + 2 == len(grid): + end = kalbach_mann["energy_length"] + else: + end = int( + mcdc_get.kalbach_mann_distribution.offset(idx + 2, kalbach_mann, data) + ) + E1_min = mcdc_get.kalbach_mann_distribution.energy_out(start, kalbach_mann, data) + E1_max = mcdc_get.kalbach_mann_distribution.energy_out(end - 1, kalbach_mann, data) + + # The combination of the two tables + E_min = E0_min + f * (E1_min - E0_min) + E_max = E0_max + f * (E1_max - E0_max) + + # Sample which table to choose + if xi1 > f: + idx += 1 + + # Get the table range + start = int(mcdc_get.kalbach_mann_distribution.offset(idx, kalbach_mann, data)) + if idx + 1 == len(grid): + end = kalbach_mann["energy_length"] + else: + end = int( + mcdc_get.kalbach_mann_distribution.offset(idx + 1, kalbach_mann, data) + ) + size = end - start + + # The CDF + cdf = mcdc_get.kalbach_mann_distribution.cdf_chunk(start, size, kalbach_mann, data) + + # Sample bin index + idx = find_bin(xi2, cdf) + c = cdf[idx] + + # Get the other values + idx += start # Apply the offset as these are not chunk-extracted like the cdf + p0 = mcdc_get.kalbach_mann_distribution.pdf(idx, kalbach_mann, data) + p1 = mcdc_get.kalbach_mann_distribution.pdf(idx + 1, kalbach_mann, data) + E0 = mcdc_get.kalbach_mann_distribution.energy_out(idx, kalbach_mann, data) + E1 = mcdc_get.kalbach_mann_distribution.energy_out(idx + 1, kalbach_mann, data) + + # Calculate the outgoing energy (not-scaled) + m = (p1 - p0) / (E1 - E0) + if m == 0.0: + E_hat = E0 + (xi2 - c) / p0 + else: + E_hat = E0 + 1.0 / m * (math.sqrt(p0**2 + 2 * m * (xi2 - c)) - p0) + + # Scale against the bounds + E_low = mcdc_get.kalbach_mann_distribution.energy_out(start, kalbach_mann, data) + E_high = mcdc_get.kalbach_mann_distribution.energy_out(end - 1, kalbach_mann, data) + E_new = E_min + (E_hat - E_low) / (E_high - E_low) * (E_max - E_min) + + # Precompound factor and angular slope + R0 = mcdc_get.kalbach_mann_distribution.precompound_factor(idx, kalbach_mann, data) + R1 = mcdc_get.kalbach_mann_distribution.precompound_factor( + idx + 1, kalbach_mann, data + ) + A0 = mcdc_get.kalbach_mann_distribution.angular_slope(idx, kalbach_mann, data) + A1 = mcdc_get.kalbach_mann_distribution.angular_slope(idx + 1, kalbach_mann, data) + # + mE = (E_hat - E0) / (E1 - E0) + R = R0 + mE * (R1 - R0) + A = A0 + mE * (A1 - A0) + + # Calculate the angular coine + T = (2.0 * xi4 - 1.0) * math.sinh(A) + if xi3 > R: + mu = math.log(T + math.sqrt(T**2 + 1.0)) / A + else: + mu = math.log(xi4 * math.exp(A) + (1.0 - xi4) * math.exp(-A)) / A + + return E_new, mu + + +@njit +def sample_tabulated_energy_angle(E, rng_state, table, data): + grid = mcdc_get.tabulated_energy_angle_distribution.energy_all(table, data) + + # Random numbers + xi1 = rng.lcg(rng_state) + xi2 = rng.lcg(rng_state) + xi3 = rng.lcg(rng_state) + + # Interpolation factor + idx = find_bin(E, grid) + E0 = grid[idx] + E1 = grid[idx + 1] + f = (E - E0) / (E1 - E0) + + # ================================================================================== + # Min and max energy values for scaling + # ================================================================================== + + # First table + start = int(mcdc_get.tabulated_energy_angle_distribution.offset(idx, table, data)) + end = int(mcdc_get.tabulated_energy_angle_distribution.offset(idx + 1, table, data)) + E0_min = mcdc_get.tabulated_energy_angle_distribution.energy_out(start, table, data) + E0_max = mcdc_get.tabulated_energy_angle_distribution.energy_out( + end - 1, table, data + ) + + # Second table + start = end + if idx + 2 == len(grid): + end = table["energy_length"] + else: + end = int( + mcdc_get.tabulated_energy_angle_distribution.offset(idx + 2, table, data) + ) + E1_min = mcdc_get.tabulated_energy_angle_distribution.energy_out(start, table, data) + E1_max = mcdc_get.tabulated_energy_angle_distribution.energy_out( + end - 1, table, data + ) + + # The combination of the two tables + E_min = E0_min + f * (E1_min - E0_min) + E_max = E0_max + f * (E1_max - E0_max) + + # Sample which table to choose + if xi1 > f: + idx += 1 + + # Get the table range + start = int(mcdc_get.tabulated_energy_angle_distribution.offset(idx, table, data)) + if idx + 1 == len(grid): + end = table["energy_length"] + else: + end = int( + mcdc_get.tabulated_energy_angle_distribution.offset(idx + 1, table, data) + ) + size = end - start + + # The CDF + cdf = mcdc_get.tabulated_energy_angle_distribution.cdf_chunk( + start, size, table, data + ) + + # Sample bin index + idx = find_bin(xi2, cdf) + c = cdf[idx] + + # Get the other values + idx_local = ( + idx + start + ) # Apply the offset as these are not chunk-extracted like the cdf + p0 = mcdc_get.tabulated_energy_angle_distribution.pdf(idx_local, table, data) + p1 = mcdc_get.tabulated_energy_angle_distribution.pdf(idx_local + 1, table, data) + E0 = mcdc_get.tabulated_energy_angle_distribution.energy_out(idx_local, table, data) + E1 = mcdc_get.tabulated_energy_angle_distribution.energy_out( + idx_local + 1, table, data + ) + + # Calculate the outgoing energy (not-scaled) + m = (p1 - p0) / (E1 - E0) + if m == 0.0: + E_hat = E0 + (xi2 - c) / p0 + else: + E_hat = E0 + 1.0 / m * (math.sqrt(p0**2 + 2 * m * (xi2 - c)) - p0) + + # Scale against the bounds + E_low = mcdc_get.tabulated_energy_angle_distribution.energy_out(start, table, data) + E_high = mcdc_get.tabulated_energy_angle_distribution.energy_out( + end - 1, table, data + ) + E_new = E_min + (E_hat - E_low) / (E_high - E_low) * (E_max - E_min) + + # Determine angular table index + if xi2 - cdf[idx] > cdf[idx + 1] - xi2: + idx += 1 + + # Get the angular table range + start = int( + mcdc_get.tabulated_energy_angle_distribution.cosine_offset_(idx, table, data) + ) + if idx + 1 == len(grid): + end = table["cosine_length"] + else: + end = int( + mcdc_get.tabulated_energy_angle_distribution.cosine_offset_( + idx + 1, table, data + ) + ) + size = end - start + + # The CDF + cdf = mcdc_get.tabulated_energy_angle_distribution.cosine_cdf_chunk( + start, size, table, data + ) + + # Sample bin index + idx = find_bin(xi3, cdf) + c = cdf[idx] + + # Get the other values + idx += start # Apply the offset as these are not chunk-extracted like the cdf + p0 = mcdc_get.tabulated_energy_angle_distribution.cosine_pdf(idx, table, data) + p1 = mcdc_get.tabulated_energy_angle_distribution.cosine_pdf(idx + 1, table, data) + mu0 = mcdc_get.tabulated_energy_angle_distribution.cosine(idx, table, data) + mu1 = mcdc_get.tabulated_energy_angle_distribution.cosine(idx + 1, table, data) + + m = (p1 - p0) / (mu1 - mu0) + if m == 0.0: + mu = mu0 + (xi3 - c) / p0 + else: + mu = mu0 + 1.0 / m * (math.sqrt(p0**2 + 2 * m * (xi3 - c)) - p0) + + return E_new, mu diff --git a/mcdc/transport/geometry/__init__.py b/mcdc/transport/geometry/__init__.py new file mode 100644 index 000000000..6e206217b --- /dev/null +++ b/mcdc/transport/geometry/__init__.py @@ -0,0 +1,10 @@ +from .interface import ( + inspect_geometry, + locate_particle, + get_cell, + check_cell, + report_lost, + distance_to_nearest_surface, + surface_crossing, + check_coincidence, +) diff --git a/mcdc/src/geometry.py b/mcdc/transport/geometry/interface.py similarity index 77% rename from mcdc/src/geometry.py rename to mcdc/transport/geometry/interface.py index 80d371547..28090dfb2 100644 --- a/mcdc/src/geometry.py +++ b/mcdc/transport/geometry/interface.py @@ -1,15 +1,21 @@ import math +import numpy as np -from numba import njit, int64 +from numba import njit -import mcdc.adapt as adapt -import mcdc.src.mesh as mesh -import mcdc.src.physics as physics -import mcdc.src.surface as surface_ -import mcdc.type_ as type_ +#### -from mcdc.adapt import for_cpu, for_gpu +import mcdc.code_factory.code_factory as code_factory +import mcdc.code_factory.adapt as adapt +import mcdc.mcdc_get as mcdc_get +import mcdc.transport.literals as literals +import mcdc.transport.mesh as mesh +import mcdc.transport.physics as physics +import mcdc.transport.tally as tally_module + +from mcdc.code_factory.adapt import for_cpu, for_gpu from mcdc.constant import * +from mcdc.transport.geometry.surface import get_distance, check_sense, reflect # ====================================================================================== @@ -18,7 +24,7 @@ @njit -def inspect_geometry(particle_container, mcdc): +def inspect_geometry(particle_container, mcdc, data): """ Full geometry inspection of the particle: - Set particle top cell and material IDs (if not lost) @@ -37,7 +43,7 @@ def inspect_geometry(particle_container, mcdc): ux_global = particle["ux"] uy_global = particle["uy"] uz_global = particle["uz"] - speed = physics.get_speed(particle_container, mcdc) + speed = physics.particle_speed(particle_container, mcdc, data) # Default returns distance = INF @@ -45,7 +51,7 @@ def inspect_geometry(particle_container, mcdc): # Find top cell from root universe if unknown if particle["cell_ID"] == -1: - particle["cell_ID"] = get_cell(particle_container, UNIVERSE_ROOT, mcdc) + particle["cell_ID"] = get_cell(particle_container, UNIVERSE_ROOT, mcdc, data) # Particle is lost? if particle["cell_ID"] == -1: @@ -58,7 +64,7 @@ def inspect_geometry(particle_container, mcdc): while event != EVENT_LOST: # Distance to nearest surface d_surface, surface_ID = distance_to_nearest_surface( - particle_container, cell, mcdc + particle_container, cell, mcdc, data ) # Check if smaller @@ -121,13 +127,13 @@ def inspect_geometry(particle_container, mcdc): event += EVENT_LATTICE_CROSSING # Get universe - ix, iy, iz, it, outside = mesh.uniform.get_indices( - particle_container, lattice - ) - if outside: + ix, iy, iz = mesh.uniform.get_indices(particle_container, lattice) + if ix == -1 or iy == -1 or iz == -1: event = EVENT_LOST continue - universe_ID = lattice["universe_IDs"][ix, iy, iz] + universe_ID = int( + mcdc_get.lattice.universe_IDs(ix, iy, iz, lattice, data) + ) # Lattice-translate the particle particle["x"] -= lattice["x0"] + (ix + 0.5) * lattice["dx"] @@ -135,7 +141,7 @@ def inspect_geometry(particle_container, mcdc): particle["z"] -= lattice["z0"] + (iz + 0.5) * lattice["dz"] # Get inner cell - cell_ID = get_cell(particle_container, universe_ID, mcdc) + cell_ID = get_cell(particle_container, universe_ID, mcdc, data) if cell_ID > -1: cell = mcdc["cells"][cell_ID] else: @@ -152,7 +158,7 @@ def inspect_geometry(particle_container, mcdc): # Report lost particle if event == EVENT_LOST: - report_lost(particle_container) + report_lost(particle_container, mcdc) # Assign particle event particle["event"] = event @@ -161,7 +167,7 @@ def inspect_geometry(particle_container, mcdc): @njit -def locate_particle(particle_container, mcdc): +def locate_particle(particle_container, mcdc, data): """ Set particle cell and material IDs Return False if particle is lost @@ -185,7 +191,7 @@ def locate_particle(particle_container, mcdc): # Find top cell from root universe if unknown if particle["cell_ID"] == -1: - particle["cell_ID"] = get_cell(particle_container, UNIVERSE_ROOT, mcdc) + particle["cell_ID"] = get_cell(particle_container, UNIVERSE_ROOT, mcdc, data) # Particle is lost? if particle["cell_ID"] == -1: @@ -225,13 +231,13 @@ def locate_particle(particle_container, mcdc): lattice = mcdc["lattices"][cell["fill_ID"]] # Get universe - ix, iy, iz, it, outside = mesh.uniform.get_indices( - particle_container, lattice - ) - if outside: + ix, iy, iz = mesh.uniform.get_indices(particle_container, lattice) + if ix == -1 or iy == -1 or iz == -1: particle_is_lost = True continue - universe_ID = lattice["universe_IDs"][ix, iy, iz] + universe_ID = int( + mcdc_get.lattice.universe_IDs(ix, iy, iz, lattice, data) + ) # Lattice-translate the particle particle["x"] -= lattice["x0"] + (ix + 0.5) * lattice["dx"] @@ -239,7 +245,7 @@ def locate_particle(particle_container, mcdc): particle["z"] -= lattice["z0"] + (iz + 0.5) * lattice["dz"] # Get inner cell - cell_ID = get_cell(particle_container, universe_ID, mcdc) + cell_ID = get_cell(particle_container, universe_ID, mcdc, data) if cell_ID > -1: cell = mcdc["cells"][cell_ID] else: @@ -256,12 +262,12 @@ def locate_particle(particle_container, mcdc): # Report lost particle if particle_is_lost: - report_lost(particle_container) + report_lost(particle_container, mcdc) return not particle_is_lost -@nb.njit +@njit def _rotate_particle(particle_container, rotation): # Particle initial coordinate particle = particle_container[0] @@ -292,7 +298,7 @@ def _rotate_particle(particle_container, rotation): particle["uz"] = uz_rotated -@nb.njit +@njit def _rotation_matrix(rotation): phi = rotation[0] theta = rotation[1] @@ -323,7 +329,7 @@ def _rotation_matrix(rotation): @njit -def get_cell(particle_container, universe_ID, mcdc): +def get_cell(particle_container, universe_ID, mcdc, data): """ Find and return particle cell ID in the given universe Return -1 if particle is lost @@ -331,53 +337,43 @@ def get_cell(particle_container, universe_ID, mcdc): particle = particle_container[0] universe = mcdc["universes"][universe_ID] - # Access universe cell data - idx = universe["cell_data_idx"] - N_cell = universe["N_cell"] - # Check over all cells in the universe - idx_end = idx + N_cell - while idx < idx_end: - cell_ID = mcdc["universes_data_cell"][idx] + for i in range(universe["N_cell"]): + cell_ID = int(mcdc_get.universe.cell_IDs(i, universe, data)) cell = mcdc["cells"][cell_ID] - if check_cell(particle_container, cell, mcdc): - return cell["ID"] - idx += 1 + if check_cell(particle_container, cell, mcdc, data): + return cell_ID # Particle is not found return -1 @njit -def check_cell(particle_container, cell, mcdc): +def check_cell(particle_container, cell, mcdc, data): """ Check if the particle is inside the cell """ particle = particle_container[0] # Access RPN data - idx = cell["region_data_idx"] - N_token = cell["N_region"] - - # No region description + N_token = cell["region_RPN_tokens_length"] if N_token == 0: return True # Create local value array - value = adapt.local_array(type_.rpn_buffer_size(), type_.bool_) + value = np.zeros(literals.rpn_evaluation_buffer_size, np.bool_) N_value = 0 # Particle parameters - speed = physics.get_speed(particle_container, mcdc) + speed = physics.particle_speed(particle_container, mcdc, data) # March forward through RPN tokens - idx_end = idx + N_token - while idx < idx_end: - token = mcdc["cells_data_region"][idx] + for idx in range(N_token): + token = int(mcdc_get.cell.region_RPN_tokens(idx, cell, data)) if token >= 0: surface = mcdc["surfaces"][token] - value[N_value] = surface_.check_sense(particle_container, speed, surface) + value[N_value] = check_sense(particle_container, speed, surface, data) N_value += 1 elif token == BOOL_NOT: @@ -391,13 +387,11 @@ def check_cell(particle_container, cell, mcdc): value[N_value - 2] = value[N_value - 2] | value[N_value - 1] N_value -= 1 - idx += 1 - return value[0] @for_cpu() -def report_lost(particle_container): +def report_lost(particle_container, mcdc): """ Report lost particle and terminate it """ @@ -407,12 +401,16 @@ def report_lost(particle_container): y = particle["y"] z = particle["z"] t = particle["t"] + idx_batch = mcdc["idx_batch"] + idx_census = mcdc["idx_census"] + idx_work = mcdc["idx_work"] print("A particle is lost at (", x, y, z, t, ")") + print("\_(batch/census/work) indices: (", idx_batch, idx_census, idx_work, ")") particle["alive"] = False @for_gpu() -def report_lost(particle_container): +def report_lost(particle_container, mcdc): particle = particle_container[0] particle["alive"] = False @@ -424,34 +422,53 @@ def report_lost(particle_container): @njit -def distance_to_nearest_surface(particle_container, cell, mcdc): +def distance_to_nearest_surface(particle_container, cell, mcdc, data): """ Determine the nearest cell surface and the distance to it """ - particle = particle_container[0] distance = INF surface_ID = -1 # Particle parameters - speed = physics.get_speed(particle_container, mcdc) - - # Access cell surface data - idx = cell["surface_data_idx"] - N_surface = cell["N_surface"] + speed = physics.particle_speed(particle_container, mcdc, data) - # Iterate over all surfaces - idx_end = idx + N_surface - while idx < idx_end: - candidate_surface_ID = mcdc["cells_data_surface"][idx] + # Iterate over all surfaces and find the minimum distance + for i in range(cell["N_surface"]): + candidate_surface_ID = int(mcdc_get.cell.surface_IDs(i, cell, data)) surface = mcdc["surfaces"][candidate_surface_ID] - d = surface_.get_distance(particle_container, speed, surface) + d = get_distance(particle_container, speed, surface, data) if d < distance: distance = d surface_ID = surface["ID"] - idx += 1 + return distance, surface_ID +@njit +def surface_crossing(P_arr, prog, data): + P = P_arr[0] + mcdc = adapt.mcdc_global(prog) + + # Apply BC + surface = mcdc["surfaces"][P["surface_ID"]] + BC = surface["boundary_condition"] + if BC == BC_VACUUM: + P["alive"] = False + elif BC == BC_REFLECTIVE: + reflect(P_arr, surface) + + # Score tally + for i in range(surface["N_tally"]): + tally_ID = int(mcdc_get.surface.tally_IDs(i, surface, data)) + tally = mcdc["surface_tallies"][tally_ID] + tally_module.score.surface_tally(P_arr, surface, tally, mcdc, data) + + # Need to check new cell later? + if P["alive"] and not BC == BC_REFLECTIVE: + P["cell_ID"] = -1 + P["material_ID"] = -1 + + # ====================================================================================== # Miscellanies # ====================================================================================== diff --git a/mcdc/transport/geometry/surface/__init__.py b/mcdc/transport/geometry/surface/__init__.py new file mode 100644 index 000000000..5ef475f8e --- /dev/null +++ b/mcdc/transport/geometry/surface/__init__.py @@ -0,0 +1,7 @@ +from .interface import ( + check_sense, + evaluate, + get_normal_component, + reflect, + get_distance, +) diff --git a/mcdc/src/surface/cylinder_x.py b/mcdc/transport/geometry/surface/cylinder_x.py similarity index 100% rename from mcdc/src/surface/cylinder_x.py rename to mcdc/transport/geometry/surface/cylinder_x.py diff --git a/mcdc/src/surface/cylinder_y.py b/mcdc/transport/geometry/surface/cylinder_y.py similarity index 100% rename from mcdc/src/surface/cylinder_y.py rename to mcdc/transport/geometry/surface/cylinder_y.py diff --git a/mcdc/src/surface/cylinder_z.py b/mcdc/transport/geometry/surface/cylinder_z.py similarity index 100% rename from mcdc/src/surface/cylinder_z.py rename to mcdc/transport/geometry/surface/cylinder_z.py diff --git a/mcdc/src/surface/common.py b/mcdc/transport/geometry/surface/interface.py similarity index 71% rename from mcdc/src/surface/common.py rename to mcdc/transport/geometry/surface/interface.py index 3e62a0a7e..91d59b9de 100644 --- a/mcdc/src/surface/common.py +++ b/mcdc/transport/geometry/surface/interface.py @@ -3,25 +3,25 @@ f(x,y,z) = Axx + Byy + Czz + Dxy + Exz + Fyz + Gx + Hy + Iz + J """ -import math - from numba import njit -import mcdc.src.surface.plane_x as plane_x -import mcdc.src.surface.plane_y as plane_y -import mcdc.src.surface.plane_z as plane_z -import mcdc.src.surface.plane as plane -import mcdc.src.surface.cylinder_x as cylinder_x -import mcdc.src.surface.cylinder_y as cylinder_y -import mcdc.src.surface.cylinder_z as cylinder_z -import mcdc.src.surface.sphere as sphere -import mcdc.src.surface.quadric as quadric +#### + +import mcdc.mcdc_get as mcdc_get +import mcdc.transport.geometry.surface.plane_x as plane_x +import mcdc.transport.geometry.surface.plane_y as plane_y +import mcdc.transport.geometry.surface.plane_z as plane_z +import mcdc.transport.geometry.surface.plane as plane +import mcdc.transport.geometry.surface.cylinder_x as cylinder_x +import mcdc.transport.geometry.surface.cylinder_y as cylinder_y +import mcdc.transport.geometry.surface.cylinder_z as cylinder_z +import mcdc.transport.geometry.surface.sphere as sphere +import mcdc.transport.geometry.surface.quadric as quadric from mcdc.constant import ( COINCIDENCE_TOLERANCE, + COINCIDENCE_TOLERANCE_TIME, INF, - SURFACE_LINEAR, - SURFACE_QUADRIC, SURFACE_PLANE_X, SURFACE_PLANE_Y, SURFACE_PLANE_Z, @@ -30,13 +30,12 @@ SURFACE_CYLINDER_Y, SURFACE_CYLINDER_Z, SURFACE_SPHERE, - SURFACE_QUADRIC, ) -from mcdc.src.algorithm import binary_search_with_length +from mcdc.transport.util import find_bin @njit -def check_sense(particle_container, speed, surface): +def check_sense(particle_container, speed, surface, data): """ Check on which side of the surface the particle is - Return True if on positive side @@ -44,13 +43,13 @@ def check_sense(particle_container, speed, surface): Particle direction and speed are used to tiebreak coincidence. """ particle = particle_container[0] - result = evaluate(particle_container, surface) + result = evaluate(particle_container, surface, data) # Check if coincident on the surface if abs(result) < COINCIDENCE_TOLERANCE: # Determine sense based on the direction return ( - get_normal_component(particle_container, speed, surface) + get_normal_component(particle_container, speed, surface, data) > 0.0 # TODO: Do we need to include COINCIDENCE TOLERANCE here? ) @@ -58,7 +57,7 @@ def check_sense(particle_container, speed, surface): @njit -def evaluate(particle_container, surface): +def evaluate(particle_container, surface, data): """ Evaluate the surface equation wrt the particle coordinate """ @@ -68,26 +67,26 @@ def evaluate(particle_container, surface): x_original = particle["x"] y_original = particle["y"] z_original = particle["z"] - idx = _get_move_idx(particle["t"], surface) - _translate_particle_position(particle_container, surface, idx) + idx = _get_move_idx(particle["t"], surface, data) + _translate_particle_position(particle_container, surface, idx, data) - if surface["type"] & SURFACE_LINEAR: - if surface["type"] & SURFACE_PLANE_X: + if surface["linear"]: + if surface["type"] == SURFACE_PLANE_X: result = plane_x.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Y: + elif surface["type"] == SURFACE_PLANE_Y: result = plane_y.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Z: + elif surface["type"] == SURFACE_PLANE_Z: result = plane_z.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_PLANE: + elif surface["type"] == SURFACE_PLANE: result = plane.evaluate(particle_container, surface) else: - if surface["type"] & SURFACE_CYLINDER_X: + if surface["type"] == SURFACE_CYLINDER_X: result = cylinder_x.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Y: + elif surface["type"] == SURFACE_CYLINDER_Y: result = cylinder_y.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Z: + elif surface["type"] == SURFACE_CYLINDER_Z: result = cylinder_z.evaluate(particle_container, surface) - elif surface["type"] & SURFACE_SPHERE: + elif surface["type"] == SURFACE_SPHERE: result = sphere.evaluate(particle_container, surface) else: result = quadric.evaluate(particle_container, surface) @@ -102,7 +101,7 @@ def evaluate(particle_container, surface): @njit -def get_normal_component(particle_container, speed, surface): +def get_normal_component(particle_container, speed, surface, data): """ Get the surface outward-normal component of the particle This is the dot product of the particle and the surface outward-normal directions. @@ -117,27 +116,27 @@ def get_normal_component(particle_container, speed, surface): ux_original = particle["ux"] uy_original = particle["uy"] uz_original = particle["uz"] - idx = _get_move_idx(particle["t"], surface) - _translate_particle_position(particle_container, surface, idx) - _translate_particle_direction(particle_container, speed, surface, idx) + idx = _get_move_idx(particle["t"], surface, data) + _translate_particle_position(particle_container, surface, idx, data) + _translate_particle_direction(particle_container, speed, surface, idx, data) - if surface["type"] & SURFACE_LINEAR: - if surface["type"] & SURFACE_PLANE_X: + if surface["linear"]: + if surface["type"] == SURFACE_PLANE_X: result = plane_x.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Y: + elif surface["type"] == SURFACE_PLANE_Y: result = plane_y.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Z: + elif surface["type"] == SURFACE_PLANE_Z: result = plane_z.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_PLANE: + elif surface["type"] == SURFACE_PLANE: result = plane.get_normal_component(particle_container, surface) else: - if surface["type"] & SURFACE_CYLINDER_X: + if surface["type"] == SURFACE_CYLINDER_X: result = cylinder_x.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Y: + elif surface["type"] == SURFACE_CYLINDER_Y: result = cylinder_y.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Z: + elif surface["type"] == SURFACE_CYLINDER_Z: result = cylinder_z.get_normal_component(particle_container, surface) - elif surface["type"] & SURFACE_SPHERE: + elif surface["type"] == SURFACE_SPHERE: result = sphere.get_normal_component(particle_container, surface) else: result = quadric.get_normal_component(particle_container, surface) @@ -160,30 +159,30 @@ def reflect(particle_container, surface): Reflect the particle off the surface """ particle = particle_container[0] - if surface["type"] & SURFACE_LINEAR: - if surface["type"] & SURFACE_PLANE_X: + if surface["linear"]: + if surface["type"] == SURFACE_PLANE_X: return plane_x.reflect(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Y: + elif surface["type"] == SURFACE_PLANE_Y: return plane_y.reflect(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Z: + elif surface["type"] == SURFACE_PLANE_Z: return plane_z.reflect(particle_container, surface) - elif surface["type"] & SURFACE_PLANE: + elif surface["type"] == SURFACE_PLANE: return plane.reflect(particle_container, surface) else: - if surface["type"] & SURFACE_CYLINDER_X: + if surface["type"] == SURFACE_CYLINDER_X: return cylinder_x.reflect(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Y: + elif surface["type"] == SURFACE_CYLINDER_Y: return cylinder_y.reflect(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Z: + elif surface["type"] == SURFACE_CYLINDER_Z: return cylinder_z.reflect(particle_container, surface) - elif surface["type"] & SURFACE_SPHERE: + elif surface["type"] == SURFACE_SPHERE: return sphere.reflect(particle_container, surface) else: return quadric.reflect(particle_container, surface) @njit -def get_distance(particle_container, speed, surface): +def get_distance(particle_container, speed, surface, data): """ Get particle distance to surface @@ -191,7 +190,7 @@ def get_distance(particle_container, speed, surface): """ particle = particle_container[0] if surface["moving"]: - return _get_distance_moving(particle_container, speed, surface) + return _get_distance_moving(particle_container, speed, surface, data) else: return _get_distance_static(particle_container, surface) @@ -202,32 +201,32 @@ def _get_distance_static(particle_container, surface): Get particle distance to static surface """ particle = particle_container[0] - if surface["type"] & SURFACE_LINEAR: - if surface["type"] & SURFACE_PLANE_X: + if surface["linear"]: + if surface["type"] == SURFACE_PLANE_X: return plane_x.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Y: + elif surface["type"] == SURFACE_PLANE_Y: return plane_y.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_PLANE_Z: + elif surface["type"] == SURFACE_PLANE_Z: return plane_z.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_PLANE: # SHOULD BE REVIEWED + elif surface["type"] == SURFACE_PLANE: # SHOULD BE REVIEWED return plane.get_distance(particle_container, surface) else: return INF else: - if surface["type"] & SURFACE_CYLINDER_X: + if surface["type"] == SURFACE_CYLINDER_X: return cylinder_x.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Y: + elif surface["type"] == SURFACE_CYLINDER_Y: return cylinder_y.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_CYLINDER_Z: + elif surface["type"] == SURFACE_CYLINDER_Z: return cylinder_z.get_distance(particle_container, surface) - elif surface["type"] & SURFACE_SPHERE: + elif surface["type"] == SURFACE_SPHERE: return sphere.get_distance(particle_container, surface) else: return quadric.get_distance(particle_container, surface) @njit -def _get_distance_moving(particle_container, speed, surface): +def _get_distance_moving(particle_container, speed, surface, data): """ Get particle distance to moving surface """ @@ -242,7 +241,7 @@ def _get_distance_moving(particle_container, speed, surface): t_original = particle["t"] # Move interval index - idx = _get_move_idx(particle["t"], surface) + idx = _get_move_idx(particle["t"], surface, data) # Distance accumulator total_distance = 0.0 @@ -250,15 +249,15 @@ def _get_distance_moving(particle_container, speed, surface): # Evaluate the current and the subsequent intervals until intersecting while idx < surface["N_move"]: # Translate particle position and direction - _translate_particle_position(particle_container, surface, idx) - _translate_particle_direction(particle_container, speed, surface, idx) + _translate_particle_position(particle_container, surface, idx, data) + _translate_particle_direction(particle_container, speed, surface, idx, data) # Get distance distance = _get_distance_static(particle_container, surface) # Intersection within the interval? distance_time = distance / speed - dt = surface["move_time_grid"][idx + 1] - particle["t"] + dt = mcdc_get.surface.move_time_grid(idx + 1, surface, data) - particle["t"] if distance_time < dt: # Restore particle parameters particle["x"] = x_original @@ -282,7 +281,7 @@ def _get_distance_moving(particle_container, speed, surface): particle["ux"] = ux_original particle["uy"] = uy_original particle["uz"] = uz_original - particle["t"] = surface["move_time_grid"][idx + 1] + particle["t"] = mcdc_get.surface.move_time_grid(idx + 1, surface, data) # Check next interval idx += 1 @@ -306,13 +305,12 @@ def _get_distance_moving(particle_container, speed, surface): @njit -def _get_move_idx(t, surface): +def _get_move_idx(t, surface, data): """ Get moving interval index wrt the given time """ - N_move = surface["N_move"] - time_grid = surface["move_time_grid"] - idx = binary_search_with_length(t, time_grid, N_move) + time_grid = mcdc_get.surface.move_time_grid_all(surface, data) + idx = find_bin(t, time_grid, epsilon=COINCIDENCE_TOLERANCE_TIME, go_lower=False) # Coinciding cases if abs(time_grid[idx + 1] - t) < COINCIDENCE_TOLERANCE: @@ -322,16 +320,16 @@ def _get_move_idx(t, surface): @njit -def _translate_particle_position(particle_container, surface, idx): +def _translate_particle_position(particle_container, surface, idx, data): """ Translate particle position wrt the given surface moving interval index """ particle = particle_container[0] # Surface move translations, velocities, and time grid - trans_0 = surface["move_translations"][idx] - time_0 = surface["move_time_grid"][idx] - V = surface["move_velocities"][idx] + trans_0 = mcdc_get.surface.move_translations_vector(idx, surface, data) + time_0 = mcdc_get.surface.move_time_grid(idx, surface, data) + V = mcdc_get.surface.move_velocities_vector(idx, surface, data) # Translate the particle t_local = particle["t"] - time_0 @@ -341,14 +339,14 @@ def _translate_particle_position(particle_container, surface, idx): @njit -def _translate_particle_direction(particle_container, speed, surface, idx): +def _translate_particle_direction(particle_container, speed, surface, idx, data): """ Translate particle direction wrt the given surface moving interval index """ particle = particle_container[0] # Surface move translations, velocities, and time grid - V = surface["move_velocities"][idx] + V = mcdc_get.surface.move_velocities_vector(idx, surface, data) # Translate the particle particle["ux"] -= V[0] / speed diff --git a/mcdc/src/surface/plane.py b/mcdc/transport/geometry/surface/plane.py similarity index 100% rename from mcdc/src/surface/plane.py rename to mcdc/transport/geometry/surface/plane.py diff --git a/mcdc/src/surface/plane_x.py b/mcdc/transport/geometry/surface/plane_x.py similarity index 100% rename from mcdc/src/surface/plane_x.py rename to mcdc/transport/geometry/surface/plane_x.py diff --git a/mcdc/src/surface/plane_y.py b/mcdc/transport/geometry/surface/plane_y.py similarity index 100% rename from mcdc/src/surface/plane_y.py rename to mcdc/transport/geometry/surface/plane_y.py diff --git a/mcdc/src/surface/plane_z.py b/mcdc/transport/geometry/surface/plane_z.py similarity index 100% rename from mcdc/src/surface/plane_z.py rename to mcdc/transport/geometry/surface/plane_z.py diff --git a/mcdc/src/surface/quadric.py b/mcdc/transport/geometry/surface/quadric.py similarity index 100% rename from mcdc/src/surface/quadric.py rename to mcdc/transport/geometry/surface/quadric.py diff --git a/mcdc/src/surface/sphere.py b/mcdc/transport/geometry/surface/sphere.py similarity index 100% rename from mcdc/src/surface/sphere.py rename to mcdc/transport/geometry/surface/sphere.py diff --git a/mcdc/transport/kernel.py b/mcdc/transport/kernel.py new file mode 100644 index 000000000..0d8bbc5fa --- /dev/null +++ b/mcdc/transport/kernel.py @@ -0,0 +1,351 @@ +import mcdc.mcdc_get as mcdc_get + +import numpy as np + +from mpi4py import MPI +from numba import ( + njit, + objmode, +) + +#### + +import mcdc.transport.particle as particle_module + +import mcdc.transport.mpi as mpi +import mcdc.transport.technique as technique + +import mcdc.code_factory.adapt as adapt + +import mcdc.object_.numba_types as type_ + +from mcdc.code_factory.adapt import for_cpu, for_gpu +from mcdc.constant import * +from mcdc.print_ import print_error + +import cffi + +ffi = cffi.FFI() + + +# ============================================================================= +# Particle bank operations +# ============================================================================= + + +@njit +def get_bank_size(bank): + return bank["size"][0] + + +@njit +def set_bank_size(bank, value): + bank["size"][0] = value + + +@njit +def add_bank_size(bank, value): + return adapt.global_add(bank["size"], 0, value) + + +@for_cpu() +def full_bank_print(bank): + with objmode(): + print_error( + "Particle %s bank is full at count %d." % (bank["tag"], bank["size"]) + ) + + +@for_gpu() +def full_bank_print(bank): + pass + + +@njit +def add_full_particle(P_arr, bank): + P = P_arr[0] + + idx = add_bank_size(bank, 1) + + # Check if bank is full + if idx >= bank["particles"].shape[0]: + full_bank_print(bank) + + # Set particle + copy_particle(bank["particles"][idx : idx + 1], P_arr) + + +@njit +def add_particle(P_arr, bank): + P = P_arr[0] + + idx = add_bank_size(bank, 1) + + # Check if bank is full + if idx >= bank["particles"].shape[0]: + full_bank_print(bank) + + # Set particle + particle_module.copy(bank["particles"][idx : idx + 1], P_arr) + + +@njit +def get_particle(P_arr, bank, mcdc): + P = P_arr[0] + + idx = add_bank_size(bank, -1) - 1 + + # Check if bank is empty + if idx < 0: + return False + # with objmode(): + # print_error("Particle %s bank is empty." % bank["tag"]) + + # Set attribute + P_rec = bank["particles"][idx] + P["x"] = P_rec["x"] + P["y"] = P_rec["y"] + P["z"] = P_rec["z"] + P["t"] = P_rec["t"] + P["ux"] = P_rec["ux"] + P["uy"] = P_rec["uy"] + P["uz"] = P_rec["uz"] + P["g"] = P_rec["g"] + P["E"] = P_rec["E"] + P["w"] = P_rec["w"] + P["particle_type"] = P_rec["particle_type"] + P["rng_seed"] = P_rec["rng_seed"] + + # Set default IDs and event + P["alive"] = True + P["material_ID"] = -1 + P["cell_ID"] = -1 + P["surface_ID"] = -1 + P["event"] = -1 + return True + + +@njit +def check_future_bank(mcdc, data): + # Get the data needed + settings = mcdc["settings"] + bank_future = mcdc["bank_future"] + bank_census = mcdc["bank_census"] + next_census_time = mcdc_get.settings.census_time( + mcdc["idx_census"] + 1, settings, data + ) + + # Particle container + P_arr = np.zeros(1, type_.particle_data) + P = P_arr[0] + + # Loop over all particles in future bank + N = get_bank_size(bank_future) + for i in range(N): + # Get the next future particle index + idx = i - get_bank_size(bank_census) + particle_module.copy(P_arr, bank_future["particles"][idx : idx + 1]) + + # Promote the future particle to census bank + if P["t"] < next_census_time: + adapt.add_census(P_arr, mcdc) + add_bank_size(bank_future, -1) + + # Consolidate the emptied space in the future bank + j = get_bank_size(bank_future) + particle_module.copy( + bank_future["particles"][idx : idx + 1], + bank_future["particles"][j : j + 1], + ) + + +@njit +def manage_particle_banks(mcdc): + # Record time + if mcdc["mpi_master"]: + with objmode(time_start="float64"): + time_start = MPI.Wtime() + + # Reset source bank + set_bank_size(mcdc["bank_source"], 0) + + # Normalize weight + if mcdc["settings"]["eigenvalue_mode"]: + normalize_weight(mcdc["bank_census"], mcdc["settings"]["N_particle"]) + + # Population control + if mcdc["population_control"]["active"]: + technique.population_control(mcdc) + else: + # Swap census and source bank + size = get_bank_size(mcdc["bank_census"]) + set_bank_size(mcdc["bank_source"], size) + mcdc["bank_source"]["particles"][:size] = mcdc["bank_census"]["particles"][ + :size + ] + # TODO: Population control future bank? + + # MPI rebalance + bank_rebalance(mcdc) + + # Zero out census bank + set_bank_size(mcdc["bank_census"], 0) + + # Accumulate time + if mcdc["mpi_master"]: + with objmode(time_end="float64"): + time_end = MPI.Wtime() + mcdc["runtime_bank_management"] += time_end - time_start + + +@njit +def bank_scanning(bank, mcdc): + N_local = get_bank_size(bank) + + # Starting index + buff = np.zeros(1, dtype=np.int64) + with objmode(): + MPI.COMM_WORLD.Exscan(np.array([N_local]), buff, MPI.SUM) + idx_start = buff[0] + + # Global size + buff[0] += N_local + with objmode(): + MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) + N_global = buff[0] + + return idx_start, N_local, N_global + + +@njit +def bank_scanning_weight(bank, mcdc): + # Local weight CDF + N_local = get_bank_size(bank) + w_cdf = np.zeros(N_local + 1) + for i in range(N_local): + w_cdf[i + 1] = w_cdf[i] + bank["particles"][i]["w"] + W_local = w_cdf[-1] + + # Starting weight + buff = np.zeros(1, dtype=np.float64) + with objmode(): + MPI.COMM_WORLD.Exscan(np.array([W_local]), buff, MPI.SUM) + w_start = buff[0] + w_cdf += w_start + + # Global weight + buff[0] = w_cdf[-1] + with objmode(): + MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) + W_global = buff[0] + + return w_start, w_cdf, W_global + + +@njit +def normalize_weight(bank, norm): + # Get total weight + W = total_weight(bank) + + # Normalize weight + for i in range(get_bank_size(bank)): + bank["particles"][i]["w"] *= norm / W + + +@njit +def total_weight(bank): + # Local total weight + W_local = np.zeros(1) + for i in range(get_bank_size(bank)): + W_local[0] += bank["particles"][i]["w"] + + # MPI Allreduce + buff = np.zeros(1, np.float64) + with objmode(): + MPI.COMM_WORLD.Allreduce(W_local, buff, MPI.SUM) + return buff[0] + + +@njit +def bank_rebalance(mcdc): + # Scan the bank + idx_start, N_local, N = bank_scanning(mcdc["bank_source"], mcdc) + idx_end = idx_start + N_local + + # Abort if source bank is empty + if N == 0: + return + + mpi.distribute_work(N, mcdc) + + # Rebalance not needed if there is only one rank + if mcdc["mpi_size"] <= 1: + return + + # Some constants + work_start = mcdc["mpi_work_start"] + work_end = work_start + mcdc["mpi_work_size"] + left = mcdc["mpi_rank"] - 1 + right = mcdc["mpi_rank"] + 1 + + # Need more or less? + more_left = idx_start < work_start + less_left = idx_start > work_start + more_right = idx_end > work_end + less_right = idx_end < work_end + + # Offside? + offside_left = idx_end <= work_start + offside_right = idx_start >= work_end + + # MPI nearest-neighbor send/receive + buff = np.zeros( + mcdc["bank_source"]["particles"].shape[0], dtype=type_.particle_data + ) + + with objmode(size="int64"): + # Create MPI-supported numpy object + size = get_bank_size(mcdc["bank_source"]) + bank = np.array(mcdc["bank_source"]["particles"][:size]) + + # If offside, need to receive first + if offside_left: + # Receive from right + bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) + less_right = False + if offside_right: + # Receive from left + bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) + less_left = False + + # Send + if more_left: + n = work_start - idx_start + request_left = MPI.COMM_WORLD.isend(bank[:n], dest=left) + bank = bank[n:] + if more_right: + n = idx_end - work_end + request_right = MPI.COMM_WORLD.isend(bank[-n:], dest=right) + bank = bank[:-n] + + # Receive + if less_left: + bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) + if less_right: + bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) + + # Wait until sent massage is received + if more_left: + request_left.Wait() + if more_right: + request_right.Wait() + + # Set output buffer + size = bank.shape[0] + for i in range(size): + buff[i] = bank[i] + + # Set source bank from buffer + set_bank_size(mcdc["bank_source"], size) + for i in range(size): + mcdc["bank_source"]["particles"][i] = buff[i] diff --git a/mcdc/transport/mesh/__init__.py b/mcdc/transport/mesh/__init__.py new file mode 100644 index 000000000..c4836d342 --- /dev/null +++ b/mcdc/transport/mesh/__init__.py @@ -0,0 +1,8 @@ +import mcdc.transport.mesh.uniform as uniform +import mcdc.transport.mesh.structured as structured +from mcdc.transport.mesh.interface import ( + get_indices, + get_x, + get_y, + get_z, +) diff --git a/mcdc/transport/mesh/interface.py b/mcdc/transport/mesh/interface.py new file mode 100644 index 000000000..97cdc416b --- /dev/null +++ b/mcdc/transport/mesh/interface.py @@ -0,0 +1,63 @@ +from numba import njit + +from mcdc import mcdc_get +from mcdc.constant import MESH_STRUCTURED, MESH_UNIFORM +import mcdc.transport.mesh.structured as structured +import mcdc.transport.mesh.uniform as uniform + + +@njit +def get_indices(particle_container, mesh_base, mcdc, data): + mesh_type = mesh_base["child_type"] + mesh_ID = mesh_base["child_ID"] + + if mesh_type == MESH_UNIFORM: + mesh = mcdc["uniform_meshes"][mesh_ID] + return uniform.get_indices(particle_container, mesh) + elif mesh_type == MESH_STRUCTURED: + mesh = mcdc["structured_meshes"][mesh_ID] + return structured.get_indices(particle_container, mesh, data) + + return -1, -1, -1 + + +@njit +def get_x(index, mesh_base, mcdc, data): + mesh_type = mesh_base["child_type"] + mesh_ID = mesh_base["child_ID"] + + if mesh_type == MESH_UNIFORM: + mesh = mcdc["uniform_meshes"][mesh_ID] + return mesh["x0"] + mesh["dx"] * index + elif mesh_type == MESH_STRUCTURED: + mesh = mcdc["structured_meshes"][mesh_ID] + return mcdc_get.structured_mesh.x(index, mesh, data) + return 0.0 + + +@njit +def get_y(index, mesh_base, mcdc, data): + mesh_type = mesh_base["child_type"] + mesh_ID = mesh_base["child_ID"] + + if mesh_type == MESH_UNIFORM: + mesh = mcdc["uniform_meshes"][mesh_ID] + return mesh["y0"] + mesh["dy"] * index + elif mesh_type == MESH_STRUCTURED: + mesh = mcdc["structured_meshes"][mesh_ID] + return mcdc_get.structured_mesh.y(index, mesh, data) + return 0.0 + + +@njit +def get_z(index, mesh_base, mcdc, data): + mesh_type = mesh_base["child_type"] + mesh_ID = mesh_base["child_ID"] + + if mesh_type == MESH_UNIFORM: + mesh = mcdc["uniform_meshes"][mesh_ID] + return mesh["z0"] + mesh["dz"] * index + elif mesh_type == MESH_STRUCTURED: + mesh = mcdc["structured_meshes"][mesh_ID] + return mcdc_get.structured_mesh.z(index, mesh, data) + return 0.0 diff --git a/mcdc/transport/mesh/structured.py b/mcdc/transport/mesh/structured.py new file mode 100644 index 000000000..7ea778632 --- /dev/null +++ b/mcdc/transport/mesh/structured.py @@ -0,0 +1,99 @@ +from numba import njit + +#### + +import mcdc.mcdc_get as mcdc_get + +from mcdc.constant import COINCIDENCE_TOLERANCE, COINCIDENCE_TOLERANCE_TIME, INF +from mcdc.transport.util import find_bin + + +@njit +def get_indices(particle_container, mesh, data): + """ + Get mesh indices given the particle coordinate + """ + particle = particle_container[0] + + # Particle coordinate + x = particle["x"] + y = particle["y"] + z = particle["z"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + tolerance = COINCIDENCE_TOLERANCE + ix = find_bin(x, mcdc_get.structured_mesh.x_all(mesh, data), tolerance, ux < 0.0) + iy = find_bin(y, mcdc_get.structured_mesh.y_all(mesh, data), tolerance, uy < 0.0) + iz = find_bin(z, mcdc_get.structured_mesh.z_all(mesh, data), tolerance, uz < 0.0) + + return ix, iy, iz + + +@njit +def get_crossing_distance(particle_arr, speed, mesh): + """ + Get distance for the particle, moving with the given speed, + to cross the nearest grid of the mesh + """ + particle = particle_arr[0] + + # Particle coordinate + x = particle["x"] + y = particle["y"] + z = particle["z"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Mesh parameters + Nx = mesh["Nx"] + Ny = mesh["Ny"] + Nz = mesh["Nz"] + + # Check if particle is outside the mesh grid and moving away + if ( + (x < mesh["x"][0] + COINCIDENCE_TOLERANCE and ux < 0.0) + or (x > mesh["x"][Nx] - COINCIDENCE_TOLERANCE and ux > 0.0) + or (y < mesh["y"][0] + COINCIDENCE_TOLERANCE and uy < 0.0) + or (y > mesh["y"][Ny] - COINCIDENCE_TOLERANCE and uy > 0.0) + or (z < mesh["z"][0] + COINCIDENCE_TOLERANCE and uz < 0.0) + or (z > mesh["z"][Nz] - COINCIDENCE_TOLERANCE and uz > 0.0) + ): + return INF + + d = INF + d = min(d, _grid_distance(x, ux, mesh["x"], Nx + 1, COINCIDENCE_TOLERANCE)) + d = min(d, _grid_distance(y, uy, mesh["y"], Ny + 1, COINCIDENCE_TOLERANCE)) + d = min(d, _grid_distance(z, uz, mesh["z"], Nz + 1, COINCIDENCE_TOLERANCE)) + return d + + +@njit +def _grid_distance(value, direction, grid, length, tolerance): + """ + Get distance to nearest grid given a value and direction + + Direction is used to tiebreak when the value is at a grid point + (within tolerance). + Note: It assumes that a grid must be hit + """ + if direction == 0.0: + return INF + + idx = binary_search_with_length(value, grid, length) + + if direction > 0.0: + idx += 1 + + # Coinciding cases + if abs(grid[idx] - value) < tolerance: + if direction > 0.0: + idx += 1 + else: + idx -= 1 + + dist = (grid[idx] - value) / direction + + return dist diff --git a/mcdc/src/mesh/uniform.py b/mcdc/transport/mesh/uniform.py similarity index 71% rename from mcdc/src/mesh/uniform.py rename to mcdc/transport/mesh/uniform.py index c649ccddb..0384fabe6 100644 --- a/mcdc/src/mesh/uniform.py +++ b/mcdc/transport/mesh/uniform.py @@ -1,8 +1,8 @@ import math -from numba import int64, njit +from numba import njit -from mcdc.constant import COINCIDENCE_TOLERANCE, COINCIDENCE_TOLERANCE_TIME, INF +from mcdc.constant import COINCIDENCE_TOLERANCE, INF @njit @@ -16,7 +16,6 @@ def get_indices(particle_container, mesh): x = particle["x"] y = particle["y"] z = particle["z"] - t = particle["t"] ux = particle["ux"] uy = particle["uy"] uz = particle["uz"] @@ -25,52 +24,56 @@ def get_indices(particle_container, mesh): x0 = mesh["x0"] y0 = mesh["y0"] z0 = mesh["z0"] - t0 = mesh["t0"] dx = mesh["dx"] dy = mesh["dy"] dz = mesh["dz"] - dt = mesh["dt"] Nx = mesh["Nx"] Ny = mesh["Ny"] Nz = mesh["Nz"] - Nt = mesh["Nt"] x_last = x0 + Nx * dx y_last = y0 + Ny * dy z_last = z0 + Nz * dz - t_last = t0 + Nt * dt - # Check if particle is outside the mesh grid - outside = False + # x-axis if ( - # Outside the mesh condition + # Outside the mesh x < x0 - COINCIDENCE_TOLERANCE or x > x_last + COINCIDENCE_TOLERANCE - or y < y0 - COINCIDENCE_TOLERANCE - or y > y_last + COINCIDENCE_TOLERANCE - or z < z0 - COINCIDENCE_TOLERANCE - or z > z_last + COINCIDENCE_TOLERANCE - or t < t0 - COINCIDENCE_TOLERANCE_TIME - or t > t_last + COINCIDENCE_TOLERANCE_TIME # At the outermost-grid but moving away or (abs(x - x0) < COINCIDENCE_TOLERANCE and ux < 0.0) or (abs(x - x_last) < COINCIDENCE_TOLERANCE and ux > 0.0) + ): + ix = -1 + else: + ix = _grid_index(x, ux, x0, dx, COINCIDENCE_TOLERANCE) + + # y-axis + if ( + # Outside the mesh + y < y0 - COINCIDENCE_TOLERANCE + or y > y_last + COINCIDENCE_TOLERANCE + # At the outermost-grid but moving away or (abs(y - y0) < COINCIDENCE_TOLERANCE and uy < 0.0) or (abs(y - y_last) < COINCIDENCE_TOLERANCE and uy > 0.0) + ): + iy = -1 + else: + iy = _grid_index(y, uy, y0, dy, COINCIDENCE_TOLERANCE) + + # z-axis + if ( + # Outside the mesh + z < z0 - COINCIDENCE_TOLERANCE + or z > z_last + COINCIDENCE_TOLERANCE + # At the outermost-grid but moving away or (abs(z - z0) < COINCIDENCE_TOLERANCE and uz < 0.0) or (abs(z - z_last) < COINCIDENCE_TOLERANCE and uz > 0.0) - or (abs(t - t_last) < COINCIDENCE_TOLERANCE_TIME) ): - outside = True - return -1, -1, -1, -1, outside - - ix = _grid_index(x, ux, x0, dx, COINCIDENCE_TOLERANCE) - iy = _grid_index(y, uy, y0, dy, COINCIDENCE_TOLERANCE) - iz = _grid_index(z, uz, z0, dz, COINCIDENCE_TOLERANCE) - it = _grid_index( - t, 1.0, t0, dt, COINCIDENCE_TOLERANCE_TIME - ) # Particle always moves forward in time + iz = -1 + else: + iz = _grid_index(z, uz, z0, dz, COINCIDENCE_TOLERANCE) - return ix, iy, iz, it, outside + return ix, iy, iz @njit @@ -85,7 +88,6 @@ def get_crossing_distance(particle_container, speed, mesh): x = particle["x"] y = particle["y"] z = particle["z"] - t = particle["t"] ux = particle["ux"] uy = particle["uy"] uz = particle["uz"] @@ -94,25 +96,19 @@ def get_crossing_distance(particle_container, speed, mesh): x0 = mesh["x0"] y0 = mesh["y0"] z0 = mesh["z0"] - t0 = mesh["t0"] dx = mesh["dx"] dy = mesh["dy"] dz = mesh["dz"] - dt = mesh["dt"] Nx = mesh["Nx"] Ny = mesh["Ny"] Nz = mesh["Nz"] - Nt = mesh["Nt"] x_last = x0 + Nx * dx y_last = y0 + Ny * dy z_last = z0 + Nz * dz - t_last = t0 + Nt * dt # Check if particle is outside the mesh grid and moving away - outside = False if ( - (t > t_last - COINCIDENCE_TOLERANCE_TIME) - or (x < x0 + COINCIDENCE_TOLERANCE and ux < 0.0) + (x < x0 + COINCIDENCE_TOLERANCE and ux < 0.0) or (x > x_last - COINCIDENCE_TOLERANCE and ux > 0.0) or (y < y0 + COINCIDENCE_TOLERANCE and uy < 0.0) or (y > y_last - COINCIDENCE_TOLERANCE and uy > 0.0) @@ -125,7 +121,6 @@ def get_crossing_distance(particle_container, speed, mesh): d = min(d, _grid_distance(x, ux, x0, dx, COINCIDENCE_TOLERANCE)) d = min(d, _grid_distance(y, uy, y0, dy, COINCIDENCE_TOLERANCE)) d = min(d, _grid_distance(z, uz, z0, dz, COINCIDENCE_TOLERANCE)) - d = min(d, _grid_distance(t, 1.0 / speed, t0, dt, COINCIDENCE_TOLERANCE_TIME)) return d @@ -138,7 +133,7 @@ def _grid_index(value, direction, start, width, tolerance): (within tolerance). Note: It assumes the value is inside the grid. """ - idx = int64(math.floor((value + tolerance - start) / width)) + idx = int(math.floor((value + tolerance - start) / width)) # Coinciding cases if abs(start + width * idx - value) < tolerance: @@ -160,7 +155,7 @@ def _grid_distance(value, direction, start, width, tolerance): if direction == 0.0: return INF - idx = int64(math.floor((value + tolerance - start) / width)) + idx = int(math.floor((value + tolerance - start) / width)) # Coinciding cases if abs(start + width * idx - value) < tolerance: diff --git a/mcdc/transport/mpi.py b/mcdc/transport/mpi.py new file mode 100644 index 000000000..395957f67 --- /dev/null +++ b/mcdc/transport/mpi.py @@ -0,0 +1,33 @@ +import math + +from numba import njit + + +@njit +def distribute_work(N_work, mcdc): + size = mcdc["mpi_size"] + rank = mcdc["mpi_rank"] + + # Total number of work + work_size_total = N_work + + # Evenly distribute work + work_size = math.floor(N_work / size) + + # Starting index (based on even distribution) + work_start = work_size * rank + + # Count reminder + rem = N_work % size + + # Assign reminder and update starting index + if rank < rem: + work_size += 1 + work_start += rank + else: + work_start += rem + + # Store the workload specification + mcdc["mpi_work_start"] = work_start + mcdc["mpi_work_size"] = work_size + mcdc["mpi_work_size_total"] = work_size_total diff --git a/mcdc/transport/particle.py b/mcdc/transport/particle.py new file mode 100644 index 000000000..5a01b02b2 --- /dev/null +++ b/mcdc/transport/particle.py @@ -0,0 +1,51 @@ +from numba import njit + +#### + +import mcdc.transport.physics as physics +import mcdc.transport.rng as rng + + +@njit +def move(particle_container, distance, mcdc, data): + particle = particle_container[0] + ut = 1.0 / physics.particle_speed(particle_container, mcdc, data) + + particle["x"] += particle["ux"] * distance + particle["y"] += particle["uy"] * distance + particle["z"] += particle["uz"] * distance + particle["t"] += ut * distance + + +@njit +def copy(target_particle_container, source_particle_container): + target_particle = target_particle_container[0] + source_particle = source_particle_container[0] + + target_particle["x"] = source_particle["x"] + target_particle["y"] = source_particle["y"] + target_particle["z"] = source_particle["z"] + target_particle["t"] = source_particle["t"] + target_particle["ux"] = source_particle["ux"] + target_particle["uy"] = source_particle["uy"] + target_particle["uz"] = source_particle["uz"] + target_particle["g"] = source_particle["g"] + target_particle["E"] = source_particle["E"] + target_particle["w"] = source_particle["w"] + target_particle["particle_type"] = source_particle["particle_type"] + target_particle["rng_seed"] = source_particle["rng_seed"] + + +@njit +def copy_as_child(child_particle_container, parent_particle_container): + parent_particle = parent_particle_container[0] + child_particle = child_particle_container[0] + + copy(child_particle_container, parent_particle_container) + + # Set child RNG seed based of the parent + parent_seed = parent_particle["rng_seed"] + child_particle["rng_seed"] = rng.split_seed(parent_seed, rng.SEED_SPLIT_PARTICLE) + + # Evolve parent seed + rng.lcg(parent_particle_container) diff --git a/mcdc/transport/particle_bank.py b/mcdc/transport/particle_bank.py new file mode 100644 index 000000000..4d21300ba --- /dev/null +++ b/mcdc/transport/particle_bank.py @@ -0,0 +1,396 @@ +import mcdc.mcdc_get as mcdc_get + +import numpy as np + +from mpi4py import MPI +from numba import ( + njit, + objmode, +) + +#### + +import mcdc.code_factory.adapt as adapt +import mcdc.object_.numba_types as type_ +import mcdc.transport.mpi as mpi +import mcdc.transport.particle as particle_module +import mcdc.transport.technique as technique + +from mcdc.constant import * +from mcdc.print_ import print_error + + +# ============================================================================= +# Particle bank operations +# ============================================================================= + + +@njit +def get_bank_size(bank): + return bank["size"][0] + + +@njit +def set_bank_size(bank, value): + bank["size"][0] = value + + +@njit +def add_bank_size(bank, value): + return adapt.global_add(bank["size"], 0, value) + + +@njit +def add_particle(P_arr, bank): + P = P_arr[0] + + idx = add_bank_size(bank, 1) + + # Check if bank is full + if idx >= bank["particles"].shape[0]: + full_bank_print(bank) + + # Set particle + particle_module.copy(bank["particles"][idx : idx + 1], P_arr) + + +@njit +def get_particle(P_arr, bank, mcdc): + P = P_arr[0] + + idx = add_bank_size(bank, -1) - 1 + + # Check if bank is empty + if idx < 0: + return False + # with objmode(): + # print_error("Particle %s bank is empty." % bank["tag"]) + + # Set attribute + P_rec = bank["particles"][idx] + P["x"] = P_rec["x"] + P["y"] = P_rec["y"] + P["z"] = P_rec["z"] + P["t"] = P_rec["t"] + P["ux"] = P_rec["ux"] + P["uy"] = P_rec["uy"] + P["uz"] = P_rec["uz"] + P["g"] = P_rec["g"] + P["E"] = P_rec["E"] + P["w"] = P_rec["w"] + P["particle_type"] = P_rec["particle_type"] + P["rng_seed"] = P_rec["rng_seed"] + + # Set default IDs and event + P["alive"] = True + P["material_ID"] = -1 + P["cell_ID"] = -1 + P["surface_ID"] = -1 + P["event"] = -1 + return True + + +@njit +def check_future_bank(mcdc, data): + # Get the data needed + settings = mcdc["settings"] + bank_future = mcdc["bank_future"] + bank_census = mcdc["bank_census"] + next_census_time = mcdc_get.settings.census_time( + mcdc["idx_census"] + 1, settings, data + ) + + # Particle container + P_arr = np.zeros(1, type_.particle_data) + P = P_arr[0] + + # Loop over all particles in future bank + N = get_bank_size(bank_future) + for i in range(N): + # Get the next future particle index + idx = i - get_bank_size(bank_census) + particle_module.copy(P_arr, bank_future["particles"][idx : idx + 1]) + + # Promote the future particle to census bank + if P["t"] < next_census_time: + add_census(P_arr, mcdc) + add_bank_size(bank_future, -1) + + # Consolidate the emptied space in the future bank + j = get_bank_size(bank_future) + particle_module.copy( + bank_future["particles"][idx : idx + 1], + bank_future["particles"][j : j + 1], + ) + + +@njit +def manage_particle_banks(mcdc): + # Record time + if mcdc["mpi_master"]: + with objmode(time_start="float64"): + time_start = MPI.Wtime() + + # Reset source bank + set_bank_size(mcdc["bank_source"], 0) + + # Normalize weight + if mcdc["settings"]["eigenvalue_mode"]: + normalize_weight(mcdc["bank_census"], mcdc["settings"]["N_particle"]) + + # Population control + if mcdc["population_control"]["active"]: + technique.population_control(mcdc) + else: + # Swap census and source bank + source_bank = mcdc["bank_source"] + census_bank = mcdc["bank_census"] + + size = get_bank_size(census_bank) + if size >= source_bank["particles"].shape[0]: + full_bank_print(source_bank) + source_bank["particles"][:size] = census_bank["particles"][:size] + set_bank_size(source_bank, size) + # TODO: Population control future bank? + + # MPI rebalance + bank_rebalance(mcdc) + + # Zero out census bank + set_bank_size(mcdc["bank_census"], 0) + + # Accumulate time + if mcdc["mpi_master"]: + with objmode(time_end="float64"): + time_end = MPI.Wtime() + mcdc["runtime_bank_management"] += time_end - time_start + + +@njit +def bank_scanning(bank, mcdc): + N_local = get_bank_size(bank) + + # Starting index + buff = np.zeros(1, dtype=np.int64) + with objmode(): + MPI.COMM_WORLD.Exscan(np.array([N_local]), buff, MPI.SUM) + idx_start = buff[0] + + # Global size + buff[0] += N_local + with objmode(): + MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) + N_global = buff[0] + + return idx_start, N_local, N_global + + +@njit +def bank_scanning_weight(bank, mcdc): + # Local weight CDF + N_local = get_bank_size(bank) + w_cdf = np.zeros(N_local + 1) + for i in range(N_local): + w_cdf[i + 1] = w_cdf[i] + bank["particles"][i]["w"] + W_local = w_cdf[-1] + + # Starting weight + buff = np.zeros(1, dtype=np.float64) + with objmode(): + MPI.COMM_WORLD.Exscan(np.array([W_local]), buff, MPI.SUM) + w_start = buff[0] + w_cdf += w_start + + # Global weight + buff[0] = w_cdf[-1] + with objmode(): + MPI.COMM_WORLD.Bcast(buff, mcdc["mpi_size"] - 1) + W_global = buff[0] + + return w_start, w_cdf, W_global + + +@njit +def normalize_weight(bank, norm): + # Get total weight + W = total_weight(bank) + + # Normalize weight + for i in range(get_bank_size(bank)): + bank["particles"][i]["w"] *= norm / W + + +@njit +def total_weight(bank): + # Local total weight + W_local = np.zeros(1) + for i in range(get_bank_size(bank)): + W_local[0] += bank["particles"][i]["w"] + + # MPI Allreduce + buff = np.zeros(1, np.float64) + with objmode(): + MPI.COMM_WORLD.Allreduce(W_local, buff, MPI.SUM) + return buff[0] + + +@njit +def total_size(bank): + # Local total weight + local_size = np.ones(1, np.int64) * bank["size"] + + # MPI Allreduce + buff = np.zeros(1, np.int64) + with objmode(): + MPI.COMM_WORLD.Allreduce(local_size, buff, MPI.SUM) + return buff[0] + + +@njit +def bank_rebalance(mcdc): + # Scan the bank + idx_start, N_local, N = bank_scanning(mcdc["bank_source"], mcdc) + idx_end = idx_start + N_local + + # Abort if source bank is empty + if N == 0: + return + + mpi.distribute_work(N, mcdc) + + # Rebalance not needed if there is only one rank + if mcdc["mpi_size"] <= 1: + return + + # Some constants + work_start = mcdc["mpi_work_start"] + work_end = work_start + mcdc["mpi_work_size"] + left = mcdc["mpi_rank"] - 1 + right = mcdc["mpi_rank"] + 1 + + # Need more or less? + more_left = idx_start < work_start + less_left = idx_start > work_start + more_right = idx_end > work_end + less_right = idx_end < work_end + + # Offside? + offside_left = idx_end <= work_start and work_start != work_end + offside_right = idx_start >= work_end and work_start != work_end + + # MPI nearest-neighbor send/receive + buff = np.zeros( + mcdc["bank_source"]["particles"].shape[0], dtype=type_.particle_data + ) + + with objmode(size="int64"): + # Create MPI-supported numpy object + size = get_bank_size(mcdc["bank_source"]) + bank = np.array(mcdc["bank_source"]["particles"][:size]) + + # If offside, need to receive first + if offside_left: + # Receive from right + bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) + less_right = False + if offside_right: + # Receive from left + bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) + less_left = False + + # Send + if more_left: + n = work_start - idx_start + request_left = MPI.COMM_WORLD.isend(bank[:n], dest=left) + bank = bank[n:] + if more_right: + n = idx_end - work_end + request_right = MPI.COMM_WORLD.isend(bank[-n:], dest=right) + bank = bank[:-n] + + # Receive + if less_left: + bank = np.insert(bank, 0, MPI.COMM_WORLD.recv(source=left)) + if less_right: + bank = np.append(bank, MPI.COMM_WORLD.recv(source=right)) + + # Wait until sent massage is received + if more_left: + request_left.Wait() + if more_right: + request_right.Wait() + + # Set output buffer + size = bank.shape[0] + for i in range(size): + buff[i] = bank[i] + + # Set source bank from buffer + set_bank_size(mcdc["bank_source"], size) + for i in range(size): + mcdc["bank_source"]["particles"][i] = buff[i] + + +# ====================================================================================== +# Adaptive functions +# ====================================================================================== +# TODO: Need review + + +@adapt.for_cpu() +def full_bank_print(bank): + with objmode(): + print_error("Particle %s bank is full." % bank["tag"]) + + +@adapt.for_gpu() +def full_bank_print(bank): + pass + + +@adapt.for_cpu() +def add_active(P_arr, prog): + add_particle(P_arr, prog["bank_active"]) + + +@adapt.for_gpu() +def add_active(P_rec_arr, prog): + P_arr = local_array(1, type_.particle) + kernel.recordlike_to_particle(P_arr, P_rec_arr) + if SIMPLE_ASYNC: + step_async(prog, P_arr[0]) + else: + find_cell_async(prog, P_arr[0]) + + +@adapt.for_cpu() +def add_source(P_arr, prog): + add_particle(P_arr, prog["bank_source"]) + + +@adapt.for_gpu() +def add_source(P_arr, prog): + mcdc = mcdc_global(prog) + add_particle(P_arr, mcdc["bank_source"]) + + +@adapt.for_cpu() +def add_census(P_arr, prog): + add_particle(P_arr, prog["bank_census"]) + + +@adapt.for_gpu() +def add_census(P_arr, prog): + mcdc = mcdc_global(prog) + add_particle(P_arr, mcdc["bank_census"]) + + +@adapt.for_cpu() +def add_future(P_arr, prog): + add_particle(P_arr, prog["bank_future"]) + + +@adapt.for_gpu() +def add_future(P_arr, prog): + mcdc = mcdc_global(prog) + add_particle(P_arr, mcdc["bank_future"]) diff --git a/mcdc/transport/physics/__init__.py b/mcdc/transport/physics/__init__.py new file mode 100644 index 000000000..73dc04af2 --- /dev/null +++ b/mcdc/transport/physics/__init__.py @@ -0,0 +1,8 @@ +from .interface import ( + particle_speed, + macro_xs, + neutron_production_xs, + collision_distance, + collision, +) +import mcdc.transport.physics.neutron as neutron diff --git a/mcdc/transport/physics/interface.py b/mcdc/transport/physics/interface.py new file mode 100644 index 000000000..fd30f0f8f --- /dev/null +++ b/mcdc/transport/physics/interface.py @@ -0,0 +1,73 @@ +import math + +from numba import njit + +### + +import mcdc.transport.rng as rng +import mcdc.transport.physics.neutron as neutron + +from mcdc.constant import * + + +# ====================================================================================== +# Particle attributes +# ====================================================================================== + + +@njit +def particle_speed(particle_container, mcdc, data): + particle = particle_container[0] + if particle["particle_type"] == PARTICLE_NEUTRON: + return neutron.particle_speed(particle_container, mcdc, data) + return -1.0 + + +# ====================================================================================== +# Material properties +# ====================================================================================== + + +@njit +def macro_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + if particle["particle_type"] == PARTICLE_NEUTRON: + return neutron.macro_xs(reaction_type, particle_container, mcdc, data) + return -1.0 + + +@njit +def neutron_production_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + if particle["particle_type"] == PARTICLE_NEUTRON: + return neutron.neutron_production_xs( + reaction_type, particle_container, mcdc, data + ) + return -1.0 + + +# ====================================================================================== +# Collision +# ====================================================================================== + + +@njit +def collision_distance(particle_container, mcdc, data): + # Get total cross-section + SigmaT = macro_xs(REACTION_TOTAL, particle_container, mcdc, data) + + # Vacuum material? + if SigmaT == 0.0: + return INF + + # Sample collision distance + xi = rng.lcg(particle_container) + distance = -math.log(xi) / SigmaT + return distance + + +@njit +def collision(particle_container, prog, data): + particle = particle_container[0] + if particle["particle_type"] == PARTICLE_NEUTRON: + neutron.collision(particle_container, prog, data) diff --git a/mcdc/transport/physics/neutron/__init__.py b/mcdc/transport/physics/neutron/__init__.py new file mode 100644 index 000000000..d7357c337 --- /dev/null +++ b/mcdc/transport/physics/neutron/__init__.py @@ -0,0 +1,8 @@ +from .interface import ( + particle_speed, + macro_xs, + neutron_production_xs, + collision, +) +import mcdc.transport.physics.neutron.native as native +import mcdc.transport.physics.neutron.multigroup as multigroup diff --git a/mcdc/transport/physics/neutron/interface.py b/mcdc/transport/physics/neutron/interface.py new file mode 100644 index 000000000..a441cfd39 --- /dev/null +++ b/mcdc/transport/physics/neutron/interface.py @@ -0,0 +1,40 @@ +from numba import njit + +#### + +import mcdc.transport.physics.neutron.native as native + + +# ====================================================================================== +# Particle attributes +# ====================================================================================== + + +@njit +def particle_speed(particle_container, mcdc, data): + return native.particle_speed(particle_container) + + +# ====================================================================================== +# Material properties +# ====================================================================================== + + +@njit +def macro_xs(reaction_type, particle_container, mcdc, data): + return native.macro_xs(reaction_type, particle_container, mcdc, data) + + +@njit +def neutron_production_xs(reaction_type, particle_container, mcdc, data): + return native.neutron_production_xs(reaction_type, particle_container, mcdc, data) + + +# ====================================================================================== +# Collision +# ====================================================================================== + + +@njit +def collision(particle_container, prog, data): + native.collision(particle_container, prog, data) diff --git a/mcdc/transport/physics/neutron/multigroup.py b/mcdc/transport/physics/neutron/multigroup.py new file mode 100644 index 000000000..2c0764f1e --- /dev/null +++ b/mcdc/transport/physics/neutron/multigroup.py @@ -0,0 +1,354 @@ +import numpy as np +import math + +from numba import njit + +#### + +import mcdc.code_factory.adapt as adapt +import mcdc.mcdc_get as mcdc_get +import mcdc.object_.numba_types as type_ +import mcdc.transport.particle as particle_module +import mcdc.transport.particle_bank as particle_bank_module +import mcdc.transport.rng as rng + +from mcdc.constant import ( + PI, + REACTION_TOTAL, + REACTION_NEUTRON_CAPTURE, + REACTION_NEUTRON_ELASTIC_SCATTERING, + REACTION_NEUTRON_FISSION, + REACTION_NEUTRON_FISSION_DELAYED, + REACTION_NEUTRON_FISSION_PROMPT, +) +from mcdc.transport.physics.util import scatter_direction +from mcdc.transport.distribution import sample_isotropic_direction + + +# ====================================================================================== +# Particle attributes +# ====================================================================================== + + +@njit +def particle_speed(particle_container, mcdc, data): + particle = particle_container[0] + material = mcdc["multigroup_materials"][particle["material_ID"]] + return mcdc_get.multigroup_material.mgxs_speed(particle["g"], material, data) + + +# ====================================================================================== +# Material properties +# ====================================================================================== + + +@njit +def macro_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + material = mcdc["multigroup_materials"][particle["material_ID"]] + g = particle["g"] + + if reaction_type == REACTION_TOTAL: + return mcdc_get.multigroup_material.mgxs_total(g, material, data) + elif reaction_type == REACTION_NEUTRON_CAPTURE: + return mcdc_get.multigroup_material.mgxs_capture(g, material, data) + elif reaction_type == REACTION_NEUTRON_ELASTIC_SCATTERING: + return mcdc_get.multigroup_material.mgxs_scatter(g, material, data) + elif reaction_type == REACTION_NEUTRON_FISSION: + return mcdc_get.multigroup_material.mgxs_fission(g, material, data) + return 0.0 + + +@njit +def neutron_production_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + material = mcdc["multigroup_materials"][particle["material_ID"]] + + g = particle["g"] + if reaction_type == REACTION_TOTAL: + total = 0.0 + total += neutron_production_xs( + REACTION_NEUTRON_ELASTIC_SCATTERING, + particle_container, + mcdc, + data, + ) + total += neutron_production_xs( + REACTION_NEUTRON_FISSION, particle_container, mcdc, data + ) + return total + elif reaction_type == REACTION_NEUTRON_CAPTURE: + return 0.0 + elif reaction_type == REACTION_NEUTRON_ELASTIC_SCATTERING: + nu = mcdc_get.multigroup_material.mgxs_nu_s(g, material, data) + xs = mcdc_get.multigroup_material.mgxs_scatter(g, material, data) + return nu * xs + elif reaction_type == REACTION_NEUTRON_FISSION: + nu = mcdc_get.multigroup_material.mgxs_nu_f(g, material, data) + xs = mcdc_get.multigroup_material.mgxs_fission(g, material, data) + return nu * xs + elif reaction_type == REACTION_NEUTRON_FISSION_PROMPT: + nu = mcdc_get.multigroup_material.mgxs_nu_p(g, material, data) + xs = mcdc_get.multigroup_material.mgxs_fission(g, material, data) + return nu * xs + elif reaction_type == REACTION_NEUTRON_FISSION_DELAYED: + nu = mcdc_get.multigroup_material.mgxs_nu_d_total(g, material, data) + xs = mcdc_get.multigroup_material.mgxs_fission(g, material, data) + return nu * xs + + +# ====================================================================================== +# Collision +# ====================================================================================== + + +@njit +def collision(particle_container, prog, data): + particle = particle_container[0] + mcdc = adapt.mcdc_global(prog) + + # Get the reaction cross-sections + SigmaT = macro_xs(REACTION_TOTAL, particle_container, mcdc, data) + SigmaS = macro_xs( + REACTION_NEUTRON_ELASTIC_SCATTERING, particle_container, mcdc, data + ) + SigmaC = macro_xs(REACTION_NEUTRON_CAPTURE, particle_container, mcdc, data) + SigmaF = macro_xs(REACTION_NEUTRON_FISSION, particle_container, mcdc, data) + + # Implicit capture + if mcdc["implicit_capture"]["active"]: + particle["w"] *= (SigmaT - SigmaC) / SigmaT + SigmaT -= SigmaC + + # Sample reaction type and perform the reaction + xi = rng.lcg(particle_container) * SigmaT + total = SigmaS + if total > xi: + scattering(particle_container, prog, data) + else: + total += SigmaF + if total > xi: + fission(particle_container, prog, data) + else: + particle["alive"] = False + + +# ====================================================================================== +# Reactions +# ====================================================================================== + + +@njit +def scattering(particle_container, prog, data): + mcdc = adapt.mcdc_global(prog) + + # Particle attributes + particle = particle_container[0] + g = particle["g"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Material attributes + material = mcdc["multigroup_materials"][particle["material_ID"]] + G = material["G"] + + # Kill the current particle + particle["alive"] = False + + # Adjust production and product weights if weighted emission + weight_production = 1.0 + weight_product = particle["w"] + if mcdc["weighted_emission"]["active"]: + weight_target = mcdc["weighted_emission"]["weight_target"] + weight_production = particle["w"] / weight_target + weight_product = weight_target + + # Get number of secondaries + nu_s = mcdc_get.multigroup_material.mgxs_nu_s(g, material, data) + N = int(math.floor(weight_production * nu_s + rng.lcg(particle_container))) + + # Set up secondary partice container + particle_container_new = np.zeros(1, type_.particle_data) + particle_new = particle_container_new[0] + + # Create the secondaries + for n in range(N): + # Set default attributes + particle_module.copy_as_child(particle_container_new, particle_container) + + # Set weight + particle_new["w"] = weight_product + + # Sample scattering angle + mu0 = 2.0 * rng.lcg(particle_container_new) - 1.0 + + # Scatter direction + azi = 2.0 * PI * rng.lcg(particle_container_new) + ux_new, uy_new, uz_new = scatter_direction(ux, uy, uz, mu0, azi) + particle_new["ux"] = ux_new + particle_new["uy"] = uy_new + particle_new["uz"] = uz_new + + # Get outgoing spectrum + chi_s = mcdc_get.multigroup_material.mgxs_chi_s_vector(g, material, data) + + # Sample outgoing energy + xi = rng.lcg(particle_container_new) + total = 0.0 + for g_out in range(G): + total += chi_s[g_out] + if total > xi: + break + particle_new["g"] = g_out + + # Bank, but keep it if it is the last particle + if n == N - 1: + particle["alive"] = True + particle["ux"] = particle_new["ux"] + particle["uy"] = particle_new["uy"] + particle["uz"] = particle_new["uz"] + particle["g"] = particle_new["g"] + particle["E"] = particle_new["E"] + particle["w"] = particle_new["w"] + else: + particle_bank_module.add_active(particle_container_new, prog) + + +@njit +def fission(particle_container, prog, data): + mcdc = adapt.mcdc_global(prog) + settings = mcdc["settings"] + + # Particle properties + particle = particle_container[0] + g = particle["g"] + + # Material properties + material = mcdc["multigroup_materials"][particle["material_ID"]] + G = material["G"] + J = material["J"] + + # Kill the current particle + particle["alive"] = False + + # Adjust production and product weights if weighted emission + weight_production = 1.0 + weight_product = particle["w"] + if mcdc["weighted_emission"]["active"]: + weight_target = mcdc["weighted_emission"]["weight_target"] + weight_production = particle["w"] / weight_target + weight_product = weight_target + + # Fission yields + nu = mcdc_get.multigroup_material.mgxs_nu_f(g, material, data) + nu_p = mcdc_get.multigroup_material.mgxs_nu_p(g, material, data) + if J > 0: + nu_d = mcdc_get.multigroup_material.mgxs_nu_d_vector(g, material, data) + + # Get number of secondaries + N = int( + math.floor(weight_production * nu / mcdc["k_eff"] + rng.lcg(particle_container)) + ) + + # Set up secondary partice container + particle_container_new = np.zeros(1, type_.particle_data) + particle_new = particle_container_new[0] + + # Create the secondaries + for n in range(N): + # Set default attributes + particle_module.copy_as_child(particle_container_new, particle_container) + + # Set weight + particle_new["w"] = weight_product + + # Sample isotropic direction + ux_new, uy_new, uz_new = sample_isotropic_direction(particle_container_new) + particle_new["ux"] = ux_new + particle_new["uy"] = uy_new + particle_new["uz"] = uz_new + + # Prompt or delayed? + xi = rng.lcg(particle_container_new) * nu + total = nu_p + if xi < total: + prompt = True + spectrum = mcdc_get.multigroup_material.mgxs_chi_p_vector(g, material, data) + else: + prompt = False + + # Determine delayed group, decay constant, and spectrum + for j in range(J): + total += nu_d[j] + if xi < total: + spectrum = mcdc_get.multigroup_material.mgxs_chi_d_vector( + j, material, data + ) + decay = mcdc_get.multigroup_material.mgxs_decay_rate( + j, material, data + ) + break + + # Sample outgoing energy + xi = rng.lcg(particle_container_new) + tot = 0.0 + for g_out in range(G): + tot += spectrum[g_out] + if tot > xi: + break + particle_new["g"] = g_out + + # Sample emission time + if not prompt: + xi = rng.lcg(particle_container_new) + particle_new["t"] -= math.log(xi) / decay + + # Eigenvalue mode: bank right away + if settings["eigenvalue_mode"]: + particle_bank_module.add_census(particle_container_new, prog) + continue + # Below is only relevant for fixed-source problem + + # Skip if it's beyond time boundary + if particle_new["t"] > settings["time_boundary"]: + continue + + # Check if it hits current or next census times + hit_current_census = False + hit_future_census = False + idx_census = mcdc["idx_census"] + if settings["N_census"] > 1: + if particle_new["t"] > mcdc_get.settings.census_time( + idx_census, settings, data + ): + hit_current_census = True + if particle_new["t"] > mcdc_get.settings.census_time( + idx_census + 1, settings, data + ): + hit_future_census = True + + # Not hitting census --> add to active bank + if not hit_current_census: + # Keep it if it is the last particle + if n == N - 1: + particle["alive"] = True + particle["ux"] = particle_new["ux"] + particle["uy"] = particle_new["uy"] + particle["uz"] = particle_new["uz"] + particle["t"] = particle_new["t"] + particle["g"] = particle_new["g"] + particle["E"] = particle_new["E"] + particle["w"] = particle_new["w"] + else: + particle_bank_module.add_active(particle_container_new, prog) + + # Hit future census --> add to future bank + elif hit_future_census: + # Particle will participate in the future + particle_bank_module.add_future(particle_container_new, prog) + + # Hit current census --> add to census bank + else: + # Particle will participate after the current census is completed + particle_bank_module.add_census(particle_container_new, prog) diff --git a/mcdc/transport/physics/neutron/native.py b/mcdc/transport/physics/neutron/native.py new file mode 100644 index 000000000..093c2fdb0 --- /dev/null +++ b/mcdc/transport/physics/neutron/native.py @@ -0,0 +1,794 @@ +import math +import numpy as np + +from numba import njit + +#### + +import mcdc.code_factory.adapt as adapt +import mcdc.mcdc_get as mcdc_get +import mcdc.object_.numba_types as type_ +from mcdc.print_ import print_structure +import mcdc.transport.particle as particle_module +import mcdc.transport.particle_bank as particle_bank_module +import mcdc.transport.rng as rng + +from mcdc.constant import ( + ANGLE_DISTRIBUTED, + ANGLE_ENERGY_CORRELATED, + ANGLE_ISOTROPIC, + BOLTZMANN_K, + THERMAL_THRESHOLD_FACTOR, + LIGHT_SPEED, + NEUTRON_MASS, + PI, + PI_HALF, + PI_SQRT, + REACTION_NEUTRON_INELASTIC_SCATTERING, + REACTION_TOTAL, + REACTION_NEUTRON_CAPTURE, + REACTION_NEUTRON_ELASTIC_SCATTERING, + REACTION_NEUTRON_FISSION, + REFERENCE_FRAME_COM, +) +from mcdc.transport.data import evaluate_data +from mcdc.transport.distribution import ( + sample_correlated_distribution, + sample_distribution, + sample_isotropic_cosine, + sample_isotropic_direction, + sample_multi_table, +) +from mcdc.transport.physics.util import evaluate_xs_energy_grid, scatter_direction +from mcdc.transport.util import find_bin, linear_interpolation + + +# ====================================================================================== +# Particle attributes +# ====================================================================================== + + +@njit +def particle_speed(particle_container): + particle = particle_container[0] + E = particle["E"] + mass = NEUTRON_MASS + return LIGHT_SPEED * math.sqrt(E * (E + 2.0 * mass)) / (E + mass) + + +@njit +def particle_energy_from_speed(speed): + beta = speed / LIGHT_SPEED + gamma = 1.0 / math.sqrt(1.0 - beta * beta) + mass = NEUTRON_MASS + return mass * (gamma - 1.0) + + +# ====================================================================================== +# Material properties +# ====================================================================================== + + +@njit +def macro_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + material = mcdc["native_materials"][particle["material_ID"]] + E = particle["E"] + + total = 0.0 + + for i in range(material["N_nuclide"]): + nuclide_ID = int(mcdc_get.native_material.nuclide_IDs(i, material, data)) + nuclide = mcdc["nuclides"][nuclide_ID] + + nuclide_density = mcdc_get.native_material.nuclide_densities(i, material, data) + xs = total_micro_xs(reaction_type, E, nuclide, data) + + total += nuclide_density * xs + + return total + + +@njit +def total_micro_xs(reaction_type, E, nuclide, data): + idx, E0, E1 = evaluate_xs_energy_grid(E, nuclide, data) + if reaction_type == REACTION_TOTAL: + xs0 = mcdc_get.nuclide.total_xs(idx, nuclide, data) + xs1 = mcdc_get.nuclide.total_xs(idx + 1, nuclide, data) + elif reaction_type == REACTION_NEUTRON_ELASTIC_SCATTERING: + xs0 = mcdc_get.nuclide.elastic_xs(idx, nuclide, data) + xs1 = mcdc_get.nuclide.elastic_xs(idx + 1, nuclide, data) + elif reaction_type == REACTION_NEUTRON_CAPTURE: + xs0 = mcdc_get.nuclide.capture_xs(idx, nuclide, data) + xs1 = mcdc_get.nuclide.capture_xs(idx + 1, nuclide, data) + elif reaction_type == REACTION_NEUTRON_INELASTIC_SCATTERING: + xs0 = mcdc_get.nuclide.inelastic_xs(idx, nuclide, data) + xs1 = mcdc_get.nuclide.inelastic_xs(idx + 1, nuclide, data) + elif reaction_type == REACTION_NEUTRON_FISSION: + xs0 = mcdc_get.nuclide.fission_xs(idx, nuclide, data) + xs1 = mcdc_get.nuclide.fission_xs(idx + 1, nuclide, data) + return linear_interpolation(E, E0, E1, xs0, xs1) + + +@njit +def reaction_micro_xs(E, reaction_base, nuclide, data): + idx, E0, E1 = evaluate_xs_energy_grid(E, nuclide, data) + + # Apply offset + offset = reaction_base["xs_offset_"] + if idx < offset: + return 0.0 + else: + idx -= offset + + xs0 = mcdc_get.reaction.xs(idx, reaction_base, data) + xs1 = mcdc_get.reaction.xs(idx + 1, reaction_base, data) + return linear_interpolation(E, E0, E1, xs0, xs1) + + +@njit +def neutron_production_xs(reaction_type, particle_container, mcdc, data): + particle = particle_container[0] + material_base = mcdc["materials"][particle["material_ID"]] + material = mcdc["native_materials"][material_base["child_ID"]] + + if reaction_type == REACTION_TOTAL: + elastic_type = REACTION_NEUTRON_ELASTIC_SCATTERING + inelastic_type = REACTION_NEUTRON_INELASTIC_SCATTERING + fission_type = REACTION_NEUTRON_FISSION + elastic_xs = neutron_production_xs(elastic_type, particle_container, mcdc, data) + inelastic_xs = neutron_production_xs( + inelastic_type, particle_container, mcdc, data + ) + fission_xs = neutron_production_xs(fission_type, particle_container, mcdc, data) + return elastic_xs + inelastic_xs + fission_xs + + elif reaction_type == REACTION_NEUTRON_ELASTIC_SCATTERING: + return macro_xs(reaction_type, particle_container, mcdc, data) + + elif reaction_type == REACTION_NEUTRON_CAPTURE: + return 0.0 + + elif reaction_type == REACTION_NEUTRON_INELASTIC_SCATTERING: + total = 0.0 + for i in range(material["N_nuclide"]): + nuclide_ID = int(mcdc_get.native_material.nuclide_IDs(i, material, data)) + nuclide = mcdc["nuclides"][nuclide_ID] + + E = particle["E"] + nuclide_density = mcdc_get.native_material.nuclide_densities( + i, material, data + ) + + for j in range(nuclide["N_inelastic_scattering_reaction"]): + reaction_ID = int( + mcdc_get.nuclide.inelastic_scattering_reaction_IDs(j, nuclide, data) + ) + reaction_base = mcdc["reactions"][reaction_ID] + reaction = mcdc["neutron_inelastic_scattering_reactions"][ + reaction_base["child_ID"] + ] + + xs = reaction_micro_xs(E, reaction_base, nuclide, data) + nu = reaction["multiplicity"] + total += nuclide_density * nu * xs + + return total + + elif reaction_type == REACTION_NEUTRON_FISSION: + if not material_base["fissionable"]: + return 0.0 + + total = 0.0 + for i in range(material["N_nuclide"]): + nuclide_ID = int(mcdc_get.native_material.nuclide_IDs(i, material, data)) + nuclide = mcdc["nuclides"][nuclide_ID] + if not nuclide["fissionable"]: + continue + + E = particle["E"] + nuclide_density = mcdc_get.native_material.nuclide_densities( + i, material, data + ) + + for j in range(nuclide["N_fission_reaction"]): + reaction_ID = int( + mcdc_get.nuclide.fission_reaction_IDs(j, nuclide, data) + ) + reaction_base = mcdc["reactions"][reaction_ID] + reaction = mcdc["neutron_fission_reactions"][reaction_base["child_ID"]] + + xs = reaction_micro_xs(E, reaction_base, nuclide, data) + nu_p = fission_prompt_multiplicity(E, nuclide, mcdc, data) + nu_d = fission_delayed_multiplicity(E, nuclide, mcdc, data) + nu = nu_d + nu_p + total += nuclide_density * nu * xs + + return total + + else: + return -1.0 + + +# ====================================================================================== +# Collision +# ====================================================================================== + + +@njit +def collision(particle_container, prog, data): + mcdc = adapt.mcdc_global(prog) + + particle = particle_container[0] + material = mcdc["native_materials"][particle["material_ID"]] + + # Particle properties + E = particle["E"] + + # ================================================================================== + # Sample colliding nuclide + # ================================================================================== + + SigmaT = macro_xs(REACTION_TOTAL, particle_container, mcdc, data) + + # Implicit capture + if mcdc["implicit_capture"]["active"]: + SigmaC = macro_xs(REACTION_NEUTRON_CAPTURE, particle_container, mcdc, data) + particle["w"] *= (SigmaT - SigmaC) / SigmaT + SigmaT -= SigmaC + + xi = rng.lcg(particle_container) * SigmaT + total = 0.0 + for i in range(material["N_nuclide"]): + nuclide_ID = int(mcdc_get.native_material.nuclide_IDs(i, material, data)) + nuclide = mcdc["nuclides"][nuclide_ID] + + nuclide_density = mcdc_get.native_material.nuclide_densities(i, material, data) + sigmaT = total_micro_xs(REACTION_TOTAL, E, nuclide, data) + + if mcdc["implicit_capture"]["active"]: + sigmaC = total_micro_xs(REACTION_NEUTRON_CAPTURE, E, nuclide, data) + particle["w"] *= (sigmaT - sigmaC) / sigmaT + sigmaT -= sigmaC + + SigmaT_nuclide = nuclide_density * sigmaT + total += SigmaT_nuclide + + if total > xi: + break + + # ================================================================================== + # Sample and perform reaction + # ================================================================================== + + sigma_elastic = total_micro_xs( + REACTION_NEUTRON_ELASTIC_SCATTERING, E, nuclide, data + ) + sigma_inelastic = total_micro_xs( + REACTION_NEUTRON_INELASTIC_SCATTERING, E, nuclide, data + ) + sigma_fission = total_micro_xs(REACTION_NEUTRON_FISSION, E, nuclide, data) + + xi = rng.lcg(particle_container) * sigmaT + + # Elastic scattering + total = sigma_elastic + if xi < total: + total -= sigma_elastic + for i in range(nuclide["N_elastic_scattering_reaction"]): + reaction_ID = int( + mcdc_get.nuclide.elastic_scattering_reaction_IDs(i, nuclide, data) + ) + reaction = mcdc["neutron_elastic_scattering_reactions"][reaction_ID] + reaction_base_ID = reaction["parent_ID"] + reaction_base = mcdc["reactions"][reaction_base_ID] + total += reaction_micro_xs(E, reaction_base, nuclide, data) + if xi < total: + elastic_scattering(reaction, particle_container, nuclide, prog, data) + return + + # Capture + if not mcdc["implicit_capture"]["active"]: + sigma_capture = total_micro_xs(REACTION_NEUTRON_CAPTURE, E, nuclide, data) + total += sigma_capture + if xi < total: + particle["alive"] = False + return + + # Inelastic scattering + total += sigma_inelastic + if xi < total: + total -= sigma_inelastic + + for i in range(nuclide["N_inelastic_scattering_reaction"]): + reaction_ID = int( + mcdc_get.nuclide.inelastic_scattering_reaction_IDs(i, nuclide, data) + ) + reaction = mcdc["neutron_inelastic_scattering_reactions"][reaction_ID] + reaction_base_ID = reaction["parent_ID"] + reaction_base = mcdc["reactions"][reaction_base_ID] + xs = reaction_micro_xs(E, reaction_base, nuclide, data) + total += xs + if xi < total: + inelastic_scattering(reaction, particle_container, nuclide, prog, data) + return + + # Fission (arive here only if nuclide is fissionable) + total += sigma_fission + if xi < total: + total -= sigma_fission + for i in range(nuclide["N_fission_reaction"]): + reaction_ID = int(mcdc_get.nuclide.fission_reaction_IDs(i, nuclide, data)) + reaction = mcdc["neutron_fission_reactions"][reaction_ID] + reaction_base_ID = reaction["parent_ID"] + reaction_base = mcdc["reactions"][reaction_base_ID] + total += reaction_micro_xs(E, reaction_base, nuclide, data) + if xi < total: + fission(reaction, particle_container, nuclide, prog, data) + return + + +# ====================================================================================== +# Elastic scattering +# ====================================================================================== + + +@njit +def elastic_scattering(reaction, particle_container, nuclide, prog, data): + mcdc = adapt.mcdc_global(prog) + + # Particle attributes + particle = particle_container[0] + E = particle["E"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Sample nucleus thermal velocity + A = nuclide["atomic_weight_ratio"] + temperature = nuclide["temperature"] + if E > THERMAL_THRESHOLD_FACTOR * BOLTZMANN_K * temperature: + Vx = 0.0 + Vy = 0.0 + Vz = 0.0 + else: + Vx, Vy, Vz = sample_nucleus_velocity(A, particle_container) + + # ========================================================================= + # COM kinematics + # ========================================================================= + + # Particle speed + speed = particle_speed(particle_container) + + # Neutron velocity - LAB + vx = speed * ux + vy = speed * uy + vz = speed * uz + + # COM velocity + COM_x = (vx + A * Vx) / (1.0 + A) + COM_y = (vy + A * Vy) / (1.0 + A) + COM_z = (vz + A * Vz) / (1.0 + A) + + # Neutron velocity - COM + vx = vx - COM_x + vy = vy - COM_y + vz = vz - COM_z + + # Neutron speed - COM + speed = math.sqrt(vx * vx + vy * vy + vz * vz) + + # Neutron initial direction - COM + ux = vx / speed + uy = vy / speed + uz = vz / speed + + # Sample the scattering cosine from the multi-PDF distribution + multi_table = mcdc["multi_table_distributions"][reaction["mu_table_ID"]] + mu0 = sample_multi_table(E, particle_container, multi_table, data) + + # Scatter the direction in COM + azi = 2.0 * PI * rng.lcg(particle_container) + ux_new, uy_new, uz_new = scatter_direction(ux, uy, uz, mu0, azi) + + # Neutron final velocity - COM + vx = speed * ux_new + vy = speed * uy_new + vz = speed * uz_new + + # ========================================================================= + # COM to LAB + # ========================================================================= + + # Final velocity - LAB + vx = vx + COM_x + vy = vy + COM_y + vz = vz + COM_z + + # Final energy - LAB + speed = math.sqrt(vx * vx + vy * vy + vz * vz) + particle["E"] = particle_energy_from_speed(speed) + + # Final direction - LAB + particle["ux"] = vx / speed + particle["uy"] = vy / speed + particle["uz"] = vz / speed + + +@njit +def sample_nucleus_velocity(A, particle_container): + particle = particle_container[0] + + # Particle speed + speed = particle_speed(particle_container) + + # Maxwellian parameter + beta = math.sqrt(2.0659834e-11 * A) + # The constant above is + # (1.674927471e-27 kg) / (1.38064852e-19 cm^2 kg s^-2 K^-1) / (293.6 K)/2 + + # Sample nuclide speed candidate V_tilda and + # nuclide-neutron polar cosine candidate mu_tilda via + # rejection sampling + y = beta * speed + while True: + if rng.lcg(particle_container) < 2.0 / (2.0 + PI_SQRT * y): + x = math.sqrt( + -math.log(rng.lcg(particle_container) * rng.lcg(particle_container)) + ) + else: + cos_val = math.cos(PI_HALF * rng.lcg(particle_container)) + x = math.sqrt( + -math.log(rng.lcg(particle_container)) + - math.log(rng.lcg(particle_container)) * cos_val * cos_val + ) + V_tilda = x / beta + mu_tilda = 2.0 * rng.lcg(particle_container) - 1.0 + + # Accept candidate V_tilda and mu_tilda? + if rng.lcg(particle_container) > math.sqrt( + speed * speed + V_tilda * V_tilda - 2.0 * speed * V_tilda * mu_tilda + ) / (speed + V_tilda): + break + + # Set nuclide velocity - LAB + azi = 2.0 * PI * rng.lcg(particle_container) + ux, uy, uz = scatter_direction( + particle["ux"], particle["uy"], particle["uz"], mu_tilda, azi + ) + Vx = ux * V_tilda + Vy = uy * V_tilda + Vz = uz * V_tilda + + return Vx, Vy, Vz + + +# ====================================================================================== +# Inelastic scattering +# ====================================================================================== + + +@njit +def inelastic_scattering(reaction, particle_container, nuclide, prog, data): + mcdc = adapt.mcdc_global(prog) + + # Particle attributes + particle = particle_container[0] + E = particle["E"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Kill the current particle + particle["alive"] = False + + # Number of secondaries and spectra + N = reaction["multiplicity"] + N_spectrum = reaction["N_spectrum"] + use_all_spectrum = N == N_spectrum + + # Set up secondary partice container + particle_container_new = np.zeros(1, type_.particle_data) + particle_new = particle_container_new[0] + + # Create the secondaries + for n in range(N): + # Set default attributes + particle_module.copy_as_child(particle_container_new, particle_container) + + # ============================================================================== + # Sample angle (if not energy-correlated) + # ============================================================================== + + angle_type = reaction["angle_type"] + if angle_type == ANGLE_ENERGY_CORRELATED: + pass + elif angle_type == ANGLE_ISOTROPIC: + mu = sample_isotropic_cosine(particle_container_new) + elif angle_type == ANGLE_DISTRIBUTED: + distribution_base = mcdc["distributions"][reaction["mu_ID"]] + multi_table = mcdc["multi_table_distributions"][ + distribution_base["child_ID"] + ] + mu = sample_multi_table(E, particle_container_new, multi_table, data) + + # ============================================================================== + # Sample energy (also angle if correlated) + # ============================================================================== + + # Get energy spectrum + if use_all_spectrum: + ID = int( + mcdc_get.neutron_inelastic_scattering_reaction.energy_spectrum_IDs( + n, reaction, data + ) + ) + spectrum_base = mcdc["distributions"][ID] + else: + probability_grid = mcdc_get.neutron_inelastic_scattering_reaction.spectrum_probability_grid_all( + reaction, data + ) + probability_idx = find_bin(E, probability_grid) + xi = rng.lcg(particle_container_new) + total = 0.0 + for j in range(N_spectrum): + probability = ( + mcdc_get.neutron_inelastic_scattering_reaction.spectrum_probability( + probability_idx, j, reaction, data + ) + ) + total += probability + if xi < total: + ID = int( + mcdc_get.neutron_inelastic_scattering_reaction.energy_spectrum_IDs( + j, reaction, data + ) + ) + spectrum_base = mcdc["distributions"][ID] + break + + # Sample energy + if not angle_type == ANGLE_ENERGY_CORRELATED: + E_new = sample_distribution( + E, spectrum_base, particle_container_new, mcdc, data, scale=True + ) + else: + E_new, mu = sample_correlated_distribution( + E, spectrum_base, particle_container_new, mcdc, data, scale=True + ) + + # ============================================================================== + # Frame transformation + # ============================================================================== + + reaction_base = mcdc["reactions"][int(reaction["parent_ID"])] + reference_frame = reaction_base["reference_frame"] + if reference_frame == REFERENCE_FRAME_COM: + A = nuclide["atomic_weight_ratio"] + mu_COM = mu + E_COM = E_new + + E_new = ( + E_COM + (E + 2 * mu_COM * (A + 1) * math.sqrt(E * E_COM)) / (A + 1) ** 2 + ) + mu = mu_COM * math.sqrt(E_COM / E_new) + math.sqrt(E / E_new) / (A + 1) + + azi = 2.0 * PI * rng.lcg(particle_container_new) + ux_new, uy_new, uz_new = scatter_direction(ux, uy, uz, mu, azi) + + # Now the secondary angle and energy are finalized + particle_new["ux"] = ux_new + particle_new["uy"] = uy_new + particle_new["uz"] = uz_new + particle_new["E"] = E_new + + # ============================================================================== + # Bank the new particle + # ============================================================================== + + # Keep it if it is the last particle + if n == N - 1: + particle["alive"] = True + particle["ux"] = particle_new["ux"] + particle["uy"] = particle_new["uy"] + particle["uz"] = particle_new["uz"] + particle["E"] = particle_new["E"] + else: + particle_bank_module.add_active(particle_container_new, prog) + + +# ====================================================================================== +# Fission +# ====================================================================================== + + +@njit +def fission(reaction, particle_container, nuclide, prog, data): + mcdc = adapt.mcdc_global(prog) + settings = mcdc["settings"] + + # Particle properties + particle = particle_container[0] + E = particle["E"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Kill the current particle + particle["alive"] = False + + # Adjust production and product weights if weighted emission + weight_production = 1.0 + weight_product = particle["w"] + if mcdc["weighted_emission"]["active"]: + weight_target = mcdc["weighted_emission"]["weight_target"] + weight_production = particle["w"] / weight_target + weight_product = weight_target + + # Fission yields + N_delayed = nuclide["N_fission_delayed_precursor"] + nu_p = fission_prompt_multiplicity(E, nuclide, mcdc, data) + nu_d = fission_delayed_multiplicity(E, nuclide, mcdc, data) + nu = nu_p + nu_d + + # Get number of secondaries + N = int( + math.floor(weight_production * nu / mcdc["k_eff"] + rng.lcg(particle_container)) + ) + + # Set up secondary partice container + particle_container_new = np.zeros(1, type_.particle_data) + particle_new = particle_container_new[0] + + # Create the secondaries + for n in range(N): + # Set default attributes + particle_module.copy_as_child(particle_container_new, particle_container) + + # Set weight + particle_new["w"] = weight_product + + # Prompt or delayed? + prompt = True + delayed_group = -1 + xi = rng.lcg(particle_container_new) + total = nu_p + if xi > total: + prompt = False + # Determine delayed group + for j in range(N_delayed): + fraction = mcdc_get.nuclide.fission_delayed_fractions(j, nuclide, data) + total += fraction + if xi < total: + delayed_group = j + break + + # ============================================================================== + # Sample prompt neutron + # ============================================================================== + + if prompt: + # Sample angle (if not energy-correlated) + angle_type = reaction["angle_type"] + if angle_type == ANGLE_ENERGY_CORRELATED: + pass + elif angle_type == ANGLE_ISOTROPIC: + mu = sample_isotropic_cosine(particle_container_new) + elif angle_type == ANGLE_DISTRIBUTED: + distribution_base = mcdc["distributions"][reaction["mu_ID"]] + multi_table = mcdc["multi_table_distributions"][ + distribution_base["child_ID"] + ] + mu = sample_multi_table(E, particle_container_new, multi_table, data) + + # Sample energy (also angle if correlated) + spectrum_base = mcdc["distributions"][reaction["spectrum_ID"]] + if not angle_type == ANGLE_ENERGY_CORRELATED: + E_new = sample_distribution( + E, spectrum_base, particle_container_new, mcdc, data, scale=True + ) + else: + E_new, mu = sample_correlated_distribution( + E, spectrum_base, particle_container_new, mcdc, data, scale=True + ) + + # Frame transformation + reaction_base = mcdc["reactions"][int(reaction["parent_ID"])] + reference_frame = reaction_base["reference_frame"] + if reference_frame == REFERENCE_FRAME_COM: + A = nuclide["atomic_weight_ratio"] + mu_COM = mu + E_COM = E_new + + E_new = ( + E_COM + + (E + 2 * mu_COM * (A + 1) * math.sqrt(E * E_COM)) / (A + 1) ** 2 + ) + mu = mu_COM * math.sqrt(E_COM / E_new) + math.sqrt(E / E_new) / (A + 1) + + azi = 2.0 * PI * rng.lcg(particle_container_new) + ux_new, uy_new, uz_new = scatter_direction(ux, uy, uz, mu, azi) + + # Now the secondary angle and energy are finalized + particle_new["ux"] = ux_new + particle_new["uy"] = uy_new + particle_new["uz"] = uz_new + particle_new["E"] = E_new + + # ============================================================================== + # Sample delayed fission neutron + # ============================================================================== + + else: + # Sample isotropic angle + ux_new, uy_new, uz_new = sample_isotropic_direction(particle_container_new) + + # Sample emission time + decay_rate = mcdc_get.nuclide.fission_delayed_fractions( + delayed_group, nuclide, data + ) + if not prompt: + xi = rng.lcg(particle_container_new) + particle_new["t"] -= math.log(xi) / decay_rate + + # Eigenvalue mode: bank right away + if settings["eigenvalue_mode"]: + particle_bank_module.add_census(particle_container_new, prog) + continue + # Below is only relevant for fixed-source problem + + # Skip if it's beyond time boundary + if particle_new["t"] > settings["time_boundary"]: + continue + + # Check if it hits current or next census times + hit_current_census = False + hit_future_census = False + idx_census = mcdc["idx_census"] + if settings["N_census"] > 1: + if particle_new["t"] > mcdc_get.settings.census_time( + idx_census, settings, data + ): + hit_current_census = True + if particle_new["t"] > mcdc_get.settings.census_time( + idx_census + 1, settings, data + ): + hit_future_census = True + + # Not hitting census --> add to active bank + if not hit_current_census: + # Keep it if it is the last particle + if n == N - 1: + particle["alive"] = True + particle["ux"] = particle_new["ux"] + particle["uy"] = particle_new["uy"] + particle["uz"] = particle_new["uz"] + particle["t"] = particle_new["t"] + particle["g"] = particle_new["g"] + particle["E"] = particle_new["E"] + particle["w"] = particle_new["w"] + else: + particle_bank_module.add_active(particle_container_new, prog) + + # Hit future census --> add to future bank + elif hit_future_census: + # Particle will participate in the future + particle_bank_module.add_future(particle_container_new, prog) + + # Hit current census --> add to census bank + else: + # Particle will participate after the current census is completed + particle_bank_module.add_census(particle_container_new, prog) + + +@njit +def fission_prompt_multiplicity(E, nuclide, mcdc, data): + data_base = mcdc["data"][nuclide["fission_prompt_multiplicity_ID"]] + return evaluate_data(E, data_base, mcdc, data) + + +@njit +def fission_delayed_multiplicity(E, nuclide, mcdc, data): + data_base = mcdc["data"][nuclide["fission_delayed_multiplicity_ID"]] + return evaluate_data(E, data_base, mcdc, data) diff --git a/mcdc/transport/physics/util.py b/mcdc/transport/physics/util.py new file mode 100644 index 000000000..cc70e801f --- /dev/null +++ b/mcdc/transport/physics/util.py @@ -0,0 +1,44 @@ +import math + +from numba import njit + +#### + +import mcdc.mcdc_get as mcdc_get + +from mcdc.transport.util import find_bin + + +@njit +def evaluate_xs_energy_grid(e, nuclide, data): + energy_grid = mcdc_get.nuclide.xs_energy_grid_all(nuclide, data) + idx = find_bin(e, energy_grid) + e0 = energy_grid[idx] + e1 = energy_grid[idx + 1] + return idx, e0, e1 + + +@njit +def scatter_direction(ux, uy, uz, mu0, azi): + cos_azi = math.cos(azi) + sin_azi = math.sin(azi) + Ac = (1.0 - mu0**2) ** 0.5 + + if uz != 1.0: + B = (1.0 - uz**2) ** 0.5 + C = Ac / B + + ux_new = ux * mu0 + (ux * uz * cos_azi - uy * sin_azi) * C + uy_new = uy * mu0 + (uy * uz * cos_azi + ux * sin_azi) * C + uz_new = uz * mu0 - cos_azi * Ac * B + + # If dir = 0i + 0j + k, interchange z and y in the scattering formula + else: + B = (1.0 - uy**2) ** 0.5 + C = Ac / B + + ux_new = ux * mu0 + (ux * uy * cos_azi - uz * sin_azi) * C + uz_new = uz * mu0 + (uz * uy * cos_azi + ux * sin_azi) * C + uy_new = uy * mu0 - cos_azi * Ac * B + + return ux_new, uy_new, uz_new diff --git a/mcdc/transport/rng.py b/mcdc/transport/rng.py new file mode 100644 index 000000000..c9bcf6006 --- /dev/null +++ b/mcdc/transport/rng.py @@ -0,0 +1,87 @@ +import numba as nb +import numpy as np + +from numba import uint64, njit + + +# ====================================================================================== +# Random number generator +# LCG with hash seed-split +# ====================================================================================== + +# LCG parameters +RNG_G = nb.uint64(2806196910506780709) +RNG_C = nb.uint64(1) +RNG_MOD_MASK = nb.uint64(0x7FFFFFFFFFFFFFFF) +RNG_MOD = nb.uint64(0x8000000000000000) + +# Splitter seeds +SEED_SPLIT_CENSUS = nb.uint64(0x43454D654E54) +SEED_SPLIT_SOURCE = nb.uint64(0x43616D696C6C65) +SEED_SPLIT_SOURCE_PRECURSOR = nb.uint64(0x546F6464) +SEED_SPLIT_PARTICLE = nb.uint64(0) +SEED_SPLIT_UQ = nb.uint64(0x5368656261) + + +@njit +def wrapping_mul(a, b): + return a * b + + +@njit +def wrapping_add(a, b): + return a + b + + +def wrapping_mul_python(a, b): + a = uint64(a) + b = uint64(b) + with np.errstate(all="ignore"): + return a * b + + +def wrapping_add_python(a, b): + a = uint64(a) + b = uint64(b) + with np.errstate(all="ignore"): + return a + b + + +@njit +def split_seed(key, seed): + """ + murmur_hash64a + + If called from non-jitted function, may need to recast the argument key with numba.uint64 + """ + multiplier = uint64(0xC6A4A7935BD1E995) + length = uint64(8) + rotator = uint64(47) + key = uint64(key) + seed = uint64(seed) + + hash_value = uint64(seed) ^ wrapping_mul(length, multiplier) + + key = wrapping_mul(key, multiplier) + key ^= key >> rotator + key = wrapping_mul(key, multiplier) + hash_value ^= key + hash_value = wrapping_mul(hash_value, multiplier) + + hash_value ^= hash_value >> rotator + hash_value = wrapping_mul(hash_value, multiplier) + hash_value ^= hash_value >> rotator + return hash_value + + +@njit +def lcg_(seed): + seed = uint64(seed) + return wrapping_add(wrapping_mul(RNG_G, seed), RNG_C) & RNG_MOD_MASK + + +@njit +def lcg(state_container): + state = state_container[0] + state["rng_seed"] = lcg_(state["rng_seed"]) + return state["rng_seed"] / RNG_MOD diff --git a/mcdc/transport/simulation.py b/mcdc/transport/simulation.py new file mode 100644 index 000000000..9c4f2abe3 --- /dev/null +++ b/mcdc/transport/simulation.py @@ -0,0 +1,878 @@ +import numpy as np + +from mpi4py import MPI +from numba import njit, objmode, uint64 + +#### + +import mcdc.code_factory.adapt as adapt +import mcdc.config as config +import mcdc.mcdc_get as mcdc_get +import mcdc.object_.numba_types as type_ +import mcdc.output as output_module +import mcdc.transport.geometry as geometry +import mcdc.transport.mpi as mpi +import mcdc.transport.particle as particle_module +import mcdc.transport.particle_bank as particle_bank_module +import mcdc.transport.physics as physics +import mcdc.transport.rng as rng +import mcdc.transport.tally as tally_module +import mcdc.transport.technique as technique + +from mcdc.constant import * +from mcdc.print_ import ( + print_header_batch, + print_progress, + print_progress_eigenvalue, +) +from mcdc.transport.source import source_particle + +caching = config.caching + + +# ============================================================================= +# Functions for GPU Interop +# ============================================================================= + +# The symbols declared below will be overwritten to reference external code that +# manages GPU execution (if GPU execution is supported and selected) +alloc_state, free_state = [None] * 2 + +src_alloc_program, src_free_program = [None] * 2 +( + src_load_global, + src_load_constant, + src_store_global, + src_store_data, + src_store_pointer_data, +) = [None] * 5 +src_init_program, src_exec_program, src_complete, src_clear_flags = [None] * 4 + +pre_alloc_program, pre_free_program = [None] * 2 +pre_load_global, pre_load_data, pre_store_global, pre_store_data = [None] * 4 +pre_init_program, pre_exec_program, pre_complete, pre_clear_flags = [None] * 4 + + +# If GPU execution is supported and selected, the functions shown below will +# be redefined to overwrite the above symbols and perform initialization/ +# finalization of GPU state +@njit +def setup_gpu(mcdc, data_tally): + pass + + +@njit +def teardown_gpu(mcdc): + pass + + +# ====================================================================================== +# Fixed-source simulation +# ====================================================================================== + + +def fixed_source_simulation(mcdc_arr, data): + # Ensure `mcdc` exist for the lifetime of the program by intentionally leaking their memory + # adapt.leak(mcdc_arr) + mcdc = mcdc_arr[0] + + # Get some settings + settings = mcdc["settings"] + N_batch = settings["N_batch"] + N_particle = settings["N_particle"] + N_census = settings["N_census"] + use_census_based_tally = settings["use_census_based_tally"] + + # Loop over batches + for idx_batch in range(N_batch): + mcdc["idx_batch"] = idx_batch + seed_batch = rng.split_seed(uint64(idx_batch), settings["rng_seed"]) + + # Distribute work + mpi.distribute_work(N_particle, mcdc) + + # Print multi-batch header + if N_batch > 1: + with objmode(): + print_header_batch(idx_batch, N_batch) + + # Loop over time censuses + for idx_census in range(N_census): + mcdc["idx_census"] = idx_census + seed_census = rng.split_seed(uint64(seed_batch), rng.SEED_SPLIT_CENSUS) + + # Reset tally time filters if census-based tally is used + if use_census_based_tally: + tally_module.filter.set_census_based_time_grid(mcdc, data) + + # Check and accordingly promote future particles to censused particles + if particle_bank_module.get_bank_size(mcdc["bank_future"]) > 0: + particle_bank_module.check_future_bank(mcdc, data) + + # Loop over source particles + seed_source = rng.split_seed(uint64(seed_census), rng.SEED_SPLIT_SOURCE) + loop_source(uint64(seed_source), mcdc, data) + + # Manage particle banks: population control and work rebalance + particle_bank_module.manage_particle_banks(mcdc) + + # Time census-based tally closeout + if use_census_based_tally: + tally_module.closeout.reduce(mcdc, data) + tally_module.closeout.accumulate(mcdc, data) + if mcdc["mpi_master"]: + with objmode(): + output_module.generate_census_based_tally(mcdc, data) + tally_module.closeout.reset_sum_bins(mcdc, data) + + # Terminate census loop if all banks are empty + if ( + idx_census > 0 + and particle_bank_module.total_size(mcdc["bank_source"]) == 0 + and particle_bank_module.total_size(mcdc["bank_census"]) == 0 + and particle_bank_module.total_size(mcdc["bank_future"]) == 0 + ): + break + + # Multi-batch closeout + if N_batch > 1: + # Reset banks + particle_bank_module.set_bank_size(mcdc["bank_active"], 0) + particle_bank_module.set_bank_size(mcdc["bank_census"], 0) + particle_bank_module.set_bank_size(mcdc["bank_source"], 0) + particle_bank_module.set_bank_size(mcdc["bank_future"], 0) + + if not use_census_based_tally: + # Tally history closeout + tally_module.closeout.reduce(mcdc, data) + tally_module.closeout.accumulate(mcdc, data) + + # Tally closeout + if not use_census_based_tally: + tally_module.closeout.finalize(mcdc, data) + + +# ========================================================================= +# Eigenvalue simulation +# ========================================================================= + + +def eigenvalue_simulation(mcdc_arr, data): + # Ensure `mcdc` exist for the lifetime of the program + # by intentionally leaking their memory + # adapt.leak(mcdc_arr) + mcdc = mcdc_arr[0] + + # Get some settings + settings = mcdc["settings"] + N_inactive = settings["N_inactive"] + N_cycle = settings["N_cycle"] + N_particle = settings["N_particle"] + + # Distribute work + mpi.distribute_work(N_particle, mcdc) + + # Loop over power iteration cycles + for idx_cycle in range(N_cycle): + mcdc["idx_cycle"] = idx_cycle + seed_cycle = rng.split_seed(uint64(idx_cycle), settings["rng_seed"]) + + # Loop over source particles + loop_source(uint64(seed_cycle), mcdc, data) + + # Tally "history" closeout + tally_module.closeout.eigenvalue_cycle(mcdc, data) + if mcdc["cycle_active"]: + tally_module.closeout.reduce(mcdc, data) + tally_module.closeout.accumulate(mcdc, data) + + # Manage particle banks: population control and work rebalance + particle_bank_module.manage_particle_banks(mcdc) + + # Print progress + with objmode(): + print_progress_eigenvalue(mcdc, data) + + # Entering active cycle? + mcdc["idx_cycle"] += 1 + if mcdc["idx_cycle"] >= N_inactive: + mcdc["cycle_active"] = True + + # Tally closeout + tally_module.closeout.finalize(mcdc, data) + tally_module.closeout.eigenvalue_simulation(mcdc) + + +# ============================================================================= +# Source loop +# ============================================================================= + + +@njit +def loop_source(seed, mcdc, data): + # Progress bar indicator + N_prog = 0 + + # Loop over particle sources + work_start = mcdc["mpi_work_start"] + work_size = mcdc["mpi_work_size"] + + for idx_work in range(work_size): + mcdc["idx_work"] = work_start + idx_work + generate_source_particle(work_start, idx_work, seed, mcdc, data) + + # Run the source particle and its secondaries + exhaust_active_bank(mcdc, data) + + source_closeout(mcdc, idx_work, N_prog, data) + + +@njit +def generate_source_particle(work_start, idx_work, seed, prog, data): + """Get a source particle and put into one of the banks""" + mcdc = adapt.mcdc_global(prog) + settings = mcdc["settings"] + + particle_container = np.zeros(1, type_.particle_data) + particle = particle_container[0] + + # Get from fixed-source? + if particle_bank_module.get_bank_size(mcdc["bank_source"]) == 0: + # Sample source + seed_work = rng.split_seed(work_start + idx_work, seed) + source_particle(particle_container, seed_work, mcdc, data) + + # Get from source bank + else: + particle_container = mcdc["bank_source"]["particles"][idx_work : (idx_work + 1)] + particle = particle_container[0] + + # Skip if beyond time boundary + if particle["t"] > settings["time_boundary"]: + return + + # Check if it is beyond current or next census times + hit_census = False + hit_next_census = False + idx_census = mcdc["idx_census"] + + if idx_census < settings["N_census"] - 1: + if particle["t"] > mcdc_get.settings.census_time( + idx_census + 1, settings, data + ): + hit_census = True + hit_next_census = True + elif particle["t"] > mcdc_get.settings.census_time(idx_census, settings, data): + hit_census = True + + # Put into the right bank + if not hit_census: + particle_bank_module.add_active(particle_container, prog) + elif not hit_next_census: + # Particle will participate after the current census + particle_bank_module.add_census(particle_container, prog) + else: + # Particle will participate in the future + particle_bank_module.add_future(particle_container, prog) + + +@njit +def exhaust_active_bank(prog, data): + mcdc = adapt.mcdc_global(prog) + particle_container = np.zeros(1, type_.particle) + particle = particle_container[0] + + # Loop until active bank is exhausted + while particle_bank_module.get_bank_size(mcdc["bank_active"]) > 0: + # Get particle from active bank + particle_bank_module.get_particle(particle_container, mcdc["bank_active"], mcdc) + + prep_particle(particle_container, prog) + + # Particle loop + loop_particle(particle_container, mcdc, data) + + +@njit +def prep_particle(particle_container, prog): + particle = particle_container[0] + mcdc = adapt.mcdc_global(prog) + + +@njit +def source_closeout(prog, idx_work, N_prog, data): + mcdc = adapt.mcdc_global(prog) + + # Tally history closeout for one-batch fixed-source simulation + if not mcdc["settings"]["eigenvalue_mode"] and mcdc["settings"]["N_batch"] == 1: + if not mcdc["settings"]["use_census_based_tally"]: + tally_module.closeout.accumulate(mcdc, data) + + # Progress printout + percent = (idx_work + 1.0) / mcdc["mpi_work_size"] + if mcdc["settings"]["use_progress_bar"] and int(percent * 100.0) > N_prog: + N_prog += 1 + with objmode(): + print_progress(percent, mcdc) + + +@njit +def loop_source(seed, mcdc, data): + # Progress bar indicator + N_prog = 0 + + # Loop over particle sources + work_start = mcdc["mpi_work_start"] + work_size = mcdc["mpi_work_size"] + + for idx_work in range(work_size): + mcdc["idx_work"] = work_start + idx_work + generate_source_particle(work_start, idx_work, seed, mcdc, data) + + # Run the source particle and its secondaries + exhaust_active_bank(mcdc, data) + + source_closeout(mcdc, idx_work, N_prog, data) + + +def gpu_sources_spec(): + def make_work(prog: nb.uintp) -> nb.boolean: + mcdc = adapt.mcdc_global(prog) + + idx_work = adapt.global_add(mcdc["mpi_work_iter"], 0, 1) + + if idx_work >= mcdc["mpi_work_size"]: + return False + + generate_source_particle( + mcdc["mpi_work_start"], nb.uint64(idx_work), mcdc["source_seed"], prog + ) + return True + + def initialize(prog: nb.uintp): + pass + + def finalize(prog: nb.uintp): + pass + + base_fns = (initialize, finalize, make_work) + + shape = eval(f"{adapt.tally_shape_literal}") + + # Just do exec/eval + def step(prog: nb.uintp, P_input: adapt.particle_gpu): + mcdc = adapt.mcdc_global(prog) + data_ptr = adapt.mcdc_data(prog) + data = adapt.harm.array_from_ptr(data_ptr, shape, nb.float64) + P_arr = adapt.local_array(1, type_.particle) + P_arr[0] = P_input + P = P_arr[0] + if P["fresh"]: + prep_particle(P_arr, prog) + P["fresh"] = False + step_particle(P_arr, data, prog) + if P["alive"]: + adapt.step_async(prog, P) + + async_fns = [step] + return adapt.harm.RuntimeSpec("mcdc_source", adapt.state_spec, base_fns, async_fns) + + +BLOCK_COUNT = config.args.gpu_block_count + +ASYNC_EXECUTION = config.args.gpu_strat == "async" + + +@njit(cache=caching) +def gpu_loop_source(seed, data, mcdc): + + # Progress bar indicator + N_prog = 0 + + if mcdc["technique"]["domain_decomposition"]: + kernel.dd_check_in(mcdc) + + # ===================================================================== + # GPU Interop + # ===================================================================== + + # For async execution + iter_count = 655360000 + # For event-based execution + batch_size = 64 + + full_work_size = mcdc["mpi_work_size"] + if ASYNC_EXECUTION: + phase_size = 1000000000 + else: + phase_size = 1000000 + phase_count = (full_work_size + phase_size - 1) // phase_size + + for phase in range(phase_count): + + mcdc["mpi_work_iter"][0] = phase_size * phase + mcdc["mpi_work_size"] = min(phase_size * (phase + 1), full_work_size) + mcdc["source_seed"] = seed + + # Store the global state to the GPU + if config.gpu_state_storage == "separate": + adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], mcdc) + adapt.harm.memcpy_host_to_device(mcdc["gpu_meta"]["state_pointer"], data) + + # Execute the program, and continue to do so until it is done + if ASYNC_EXECUTION: + src_exec_program( + mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count + ) + while not src_complete(mcdc["gpu_meta"]["source_program_pointer"]): + kernel.dd_particle_send(mcdc) + src_exec_program( + mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, iter_count + ) + else: + src_exec_program( + mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size + ) + while not src_complete(mcdc["gpu_meta"]["source_program_pointer"]): + kernel.dd_particle_send(mcdc) + src_exec_program( + mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT, batch_size + ) + src_clear_flags(mcdc["gpu_meta"]["source_program_pointer"]) + # Recover the original program state + + if config.gpu_state_storage == "separate": + adapt.harm.memcpy_device_to_host(mcdc, mcdc["gpu_meta"]["state_pointer"]) + adapt.harm.memcpy_device_to_host(data, mcdc["gpu_meta"]["state_pointer"]) + + src_clear_flags(mcdc["gpu_meta"]["source_program_pointer"]) + + mcdc["mpi_work_size"] = full_work_size + + kernel.set_bank_size(mcdc["bank_active"], 0) + + # ===================================================================== + # Closeout (Moved out of the typical particle loop) + # ===================================================================== + + source_closeout(mcdc, 1, 1, data) + + if mcdc["technique"]["domain_decomposition"]: + source_dd_resolution(data, mcdc) + + +# ====================================================================================== +# Particle loop +# ====================================================================================== + + +@njit +def loop_particle(particle_container, prog, data): + particle = particle_container[0] + mcdc = adapt.mcdc_global(prog) + + while particle["alive"]: + step_particle(particle_container, prog, data) + + +@njit +def step_particle(particle_container, prog, data): + particle = particle_container[0] + mcdc = adapt.mcdc_global(prog) + + # Determine and move to event + move_to_event(particle_container, mcdc, data) + + # Execute events + if particle["event"] == EVENT_LOST: + return + + # Collision + if particle["event"] & EVENT_COLLISION: + physics.collision(particle_container, prog, data) + + # Surface and domain crossing + if particle["event"] & EVENT_SURFACE_CROSSING: + geometry.surface_crossing(particle_container, prog, data) + + # Census time crossing + if particle["event"] & EVENT_TIME_CENSUS: + particle_bank_module.add_census(particle_container, prog) + particle["alive"] = False + + # Time boundary crossing + if particle["event"] & EVENT_TIME_BOUNDARY: + particle["alive"] = False + + # Weight roulette + if particle["alive"]: + technique.weight_roulette(particle_container, prog) + + +@njit +def move_to_event(particle_container, mcdc, data): + settings = mcdc["settings"] + + # ================================================================================== + # Preparation (as needed) + # ================================================================================== + particle = particle_container[0] + + # Multigroup preparation + # In MG mode, particle speed is material-dependent. + if settings["multigroup_mode"]: + # If material is not identified yet, locate the particle + if particle["material_ID"] == -1: + if not geometry.locate_particle(particle_container, mcdc, data): + # Particle is lost + particle["event"] = EVENT_LOST + return + + # ================================================================================== + # Geometry inspection + # ================================================================================== + # - Set particle top cell and material IDs (if not lost) + # - Set surface ID (if surface hit) + # - Set particle boundary event (surface or lattice crossing, or lost) + # - Return distance to boundary (surface or lattice) + + d_boundary = geometry.inspect_geometry(particle_container, mcdc, data) + + # Particle is lost? + if particle["event"] == EVENT_LOST: + return + + # ================================================================================== + # Get distances to other events + # ================================================================================== + + # Distance to domain + speed = physics.particle_speed(particle_container, mcdc, data) + + # Distance to time boundary + d_time_boundary = speed * (settings["time_boundary"] - particle["t"]) + + # Distance to census time + idx = mcdc["idx_census"] + d_time_census = speed * ( + mcdc_get.settings.census_time(idx, settings, data) - particle["t"] + ) + + # Distance to next collision + d_collision = physics.collision_distance(particle_container, mcdc, data) + + # ================================================================================== + # Determine event(s) + # ================================================================================== + # TODO: Make a function to better maintain the repeating operation + + distance = d_boundary + + # Check distance to collision + if d_collision < distance - COINCIDENCE_TOLERANCE: + distance = d_collision + particle["event"] = EVENT_COLLISION + particle["surface_ID"] = -1 + elif geometry.check_coincidence(d_collision, distance): + particle["event"] += EVENT_COLLISION + + # Check distance to time census + if d_time_census < distance - COINCIDENCE_TOLERANCE: + distance = d_time_census + particle["event"] = EVENT_TIME_CENSUS + particle["surface_ID"] = -1 + elif geometry.check_coincidence(d_time_census, distance): + particle["event"] += EVENT_TIME_CENSUS + + # Check distance to time boundary (exclusive event) + if d_time_boundary < distance + COINCIDENCE_TOLERANCE: + distance = d_time_boundary + particle["event"] = EVENT_TIME_BOUNDARY + particle["surface_ID"] = -1 + + # ================================================================================== + # Move particle + # ================================================================================== + + # Score tracklength tallies + if mcdc["cycle_active"]: + # Cell tallies + cell = mcdc["cells"][particle["cell_ID"]] + for i in range(cell["N_tally"]): + tally_ID = int(mcdc_get.cell.tally_IDs(i, cell, data)) + tally = mcdc["cell_tallies"][tally_ID] + tally_module.score.tracklength_tally( + particle_container, distance, tally, mcdc, data + ) + + # Global tallies + for i in range(mcdc["N_global_tally"]): + tally = mcdc["global_tallies"][i] + tally_module.score.tracklength_tally( + particle_container, distance, tally, mcdc, data + ) + + # Mesh tallies + for i in range(mcdc["N_mesh_tally"]): + tally = mcdc["mesh_tallies"][i] + tally_module.score.mesh_tally( + particle_container, distance, tally, mcdc, data + ) + + if settings["eigenvalue_mode"]: + tally_module.score.eigenvalue_tally(particle_container, distance, mcdc, data) + + # Move particle + particle_module.move(particle_container, distance, mcdc, data) + + +# ====================================================================================== +# Unsorted [TODO] +# ====================================================================================== + + +def gpu_sources_spec(): + def make_work(prog: nb.uintp) -> nb.boolean: + mcdc = adapt.mcdc_global(prog) + + idx_work = adapt.global_add(mcdc["mpi_work_iter"], 0, 1) + + if idx_work >= mcdc["mpi_work_size"]: + return False + + generate_source_particle( + mcdc["mpi_work_start"], nb.uint64(idx_work), mcdc["source_seed"], prog + ) + return True + + def initialize(prog: nb.uintp): + pass + + def finalize(prog: nb.uintp): + pass + + base_fns = (initialize, finalize, make_work) + + def step(prog: nb.uintp, P_input: adapt.particle_gpu): + mcdc = adapt.mcdc_global(prog) + data = adapt.mcdc_data(prog) + particle_container = np.zeros(1, type_.particle) + particle_container[0] = P_input + particle = particle_container[0] + if particle["fresh"]: + prep_particle(particle_container, prog) + particle["fresh"] = False + step_particle(particle_container, data, prog) + if particle["alive"]: + adapt.step_async(prog, P) + + async_fns = [step] + return adapt.harm.RuntimeSpec("mcdc_source", adapt.state_spec, base_fns, async_fns) + + +BLOCK_COUNT = config.args.gpu_block_count + +ASYNC_EXECUTION = config.args.gpu_strat == "async" + + +@njit(cache=caching) +def gpu_loop_source(seed, data, mcdc): + + # Progress bar indicator + N_prog = 0 + + if mcdc["technique"]["domain_decomposition"]: + particle_bank_module.dd_check_in(mcdc) + + # ===================================================================== + # GPU Interop + # ===================================================================== + + # For async execution + iter_count = 655360000 + # For event-based execution + batch_size = 1 + + full_work_size = mcdc["mpi_work_size"] + if ASYNC_EXECUTION: + phase_size = 1000000000 + else: + phase_size = 1000000 + phase_count = (full_work_size + phase_size - 1) // phase_size + + for phase in range(phase_count): + + mcdc["mpi_work_iter"][0] = phase_size * phase + mcdc["mpi_work_size"] = min(phase_size * (phase + 1), full_work_size) + mcdc["source_seed"] = seed + + # Store the global state to the GPU + src_store_constant(mcdc["gpu_state_pointer"], mcdc) + src_store_data(mcdc["gpu_state_pointer"], data) + + # Execute the program, and continue to do so until it is done + if ASYNC_EXECUTION: + src_exec_program(mcdc["source_program_pointer"], BLOCK_COUNT, iter_count) + while not src_complete(mcdc["source_program_pointer"]): + particle_bank_module.dd_particle_send(mcdc) + src_exec_program( + mcdc["source_program_pointer"], BLOCK_COUNT, iter_count + ) + else: + src_exec_program(mcdc["source_program_pointer"], BLOCK_COUNT, batch_size) + while not src_complete(mcdc["source_program_pointer"]): + particle_bank_module.dd_particle_send(mcdc) + src_exec_program( + mcdc["source_program_pointer"], BLOCK_COUNT, batch_size + ) + + # Recover the original program state + src_load_constant(mcdc, mcdc["gpu_state_pointer"]) + src_load_data(data, mcdc["gpu_state_pointer"]) + src_clear_flags(mcdc["source_program_pointer"]) + + mcdc["mpi_work_size"] = full_work_size + + particle_bank_module.set_bank_size(mcdc["bank_active"], 0) + + # ===================================================================== + # Closeout (Moved out of the typical particle loop) + # ===================================================================== + + source_closeout(mcdc, 1, 1, data) + + if mcdc["technique"]["domain_decomposition"]: + source_dd_resolution(data, mcdc) + + +def build_gpu_progs(input_deck, args): + + STRAT = args.gpu_strat + + src_spec = gpu_sources_spec() + + adapt.harm.RuntimeSpec.bind_specs() + + rank = MPI.COMM_WORLD.Get_rank() + device_id = rank % args.gpu_share_stride + + if MPI.COMM_WORLD.Get_size() > 1: + MPI.COMM_WORLD.Barrier() + + adapt.harm.RuntimeSpec.load_specs() + + if STRAT == "async": + args.gpu_arena_size = args.gpu_arena_size // 32 + src_fns = src_spec.async_functions() + pre_fns = pre_spec.async_functions() + else: + src_fns = src_spec.event_functions() + pre_fns = pre_spec.event_functions() + + ARENA_SIZE = args.gpu_arena_size + BLOCK_COUNT = args.gpu_block_count + + global alloc_state, free_state + alloc_state = src_fns["alloc_state"] + free_state = src_fns["free_state"] + + global src_alloc_program, src_free_program + global src_load_global, src_store_global, src_load_data, src_store_data, src_store_pointer_data + global src_init_program, src_exec_program, src_complete, src_clear_flags + src_alloc_program = src_fns["alloc_program"] + src_free_program = src_fns["free_program"] + src_load_global = src_fns["load_state_device_global"] + src_store_global = src_fns["store_state_device_global"] + src_store_pointer_global = src_fns["store_pointer_state_device_global"] + src_load_data = src_fns["load_state_device_data"] + src_store_data = src_fns["store_state_device_data"] + src_store_pointer_data = src_fns["store_pointer_state_device_data"] + src_init_program = src_fns["init_program"] + src_exec_program = src_fns["exec_program"] + src_complete = src_fns["complete"] + src_clear_flags = src_fns["clear_flags"] + src_set_device = src_fns["set_device"] + + global pre_alloc_program, pre_free_program + global pre_load_global, pre_store_global, pre_load_data, pre_store_data + global pre_init_program, pre_exec_program, pre_complete, pre_clear_flags + pre_alloc_state = pre_fns["alloc_state"] + pre_free_state = pre_fns["free_state"] + pre_alloc_program = pre_fns["alloc_program"] + pre_free_program = pre_fns["free_program"] + pre_load_global = pre_fns["load_state_device_global"] + pre_store_global = pre_fns["store_state_device_global"] + pre_load_data = pre_fns["load_state_device_data"] + pre_store_data = pre_fns["store_state_device_data"] + pre_init_program = pre_fns["init_program"] + pre_exec_program = pre_fns["exec_program"] + pre_complete = pre_fns["complete"] + pre_clear_flags = pre_fns["clear_flags"] + + @njit + def real_setup_gpu(mcdc_array, data_tally): + mcdc = mcdc_array[0] + src_set_device(device_id) + arena_size = ARENA_SIZE + mcdc["gpu_meta"]["state_pointer"] = adapt.cast_voidptr_to_uintp(alloc_state()) + # src_store_global(mcdc["gpu_meta"]["state_pointer"], mcdc_array[0]) + if config.gpu_state_storage == "separate": + src_store_pointer_global( + mcdc["gpu_meta"]["state_pointer"], mcdc["gpu_meta"]["global_pointer"] + ) + src_store_pointer_data( + mcdc["gpu_meta"]["state_pointer"], mcdc["gpu_meta"]["tally_pointer"] + ) + else: + src_store_pointer_global(mcdc["gpu_meta"]["state_pointer"], mcdc_array) + src_store_pointer_data(mcdc["gpu_meta"]["state_pointer"], data_tally) + + mcdc["gpu_meta"]["source_program_pointer"] = adapt.cast_voidptr_to_uintp( + src_alloc_program(mcdc["gpu_meta"]["state_pointer"], ARENA_SIZE) + ) + src_init_program(mcdc["gpu_meta"]["source_program_pointer"], BLOCK_COUNT) + return + + @njit + def real_teardown_gpu(mcdc): + src_free_program( + adapt.cast_uintp_to_voidptr(mcdc["gpu_meta"]["source_program_pointer"]) + ) + free_state(adapt.cast_uintp_to_voidptr(mcdc["gpu_meta"]["state_pointer"])) + + global setup_gpu, teardown_gpu + setup_gpu = real_setup_gpu + teardown_gpu = real_teardown_gpu + + global loop_source + loop_source = gpu_loop_source + + +# ============================================================================= +# Functions for GPU Interop +# ============================================================================= + +# The symbols declared below will be overwritten to reference external code that +# manages GPU execution (if GPU execution is supported and selected) +alloc_state, free_state = [None] * 2 + +src_alloc_program, src_free_program = [None] * 2 +src_load_constant, src_load_constant, src_store_constant, src_store_data = [None] * 4 +src_init_program, src_exec_program, src_complete, src_clear_flags = [None] * 4 + +pre_alloc_program, pre_free_program = [None] * 2 +pre_load_constant, pre_load_data, pre_store_constant, pre_store_data = [None] * 4 +pre_init_program, pre_exec_program, pre_complete, pre_clear_flags = [None] * 4 + + +# If GPU execution is supported and selected, the functions shown below will +# be redefined to overwrite the above symbols and perform initialization/ +# finalization of GPU state +@njit +def setup_gpu(mcdc): + pass + + +@njit +def teardown_gpu(mcdc): + pass diff --git a/mcdc/transport/source.py b/mcdc/transport/source.py new file mode 100644 index 000000000..5d06be34c --- /dev/null +++ b/mcdc/transport/source.py @@ -0,0 +1,88 @@ +from numba import njit + +#### + +import mcdc.transport.rng as rng + +from mcdc.transport.distribution import ( + sample_uniform, + sample_tabulated, + sample_pmf, + sample_white_direction, + sample_isotropic_direction, +) + + +@njit +def source_particle(P_rec_arr, seed, mcdc, data): + P_rec = P_rec_arr[0] + P_rec["rng_seed"] = seed + + # Sample source + # TODO: use cdf and binary search instead + xi = rng.lcg(P_rec_arr) + tot = 0.0 + for source in mcdc["sources"]: + tot += source["probability"] + if tot >= xi: + break + + # Position + if source["point_source"]: + x = source["point"][0] + y = source["point"][1] + z = source["point"][2] + else: + x = sample_uniform(source["x"][0], source["x"][1], P_rec_arr) + y = sample_uniform(source["y"][0], source["y"][1], P_rec_arr) + z = sample_uniform(source["z"][0], source["z"][1], P_rec_arr) + + # Direction + if source["isotropic_direction"]: + ux, uy, uz = sample_isotropic_direction(P_rec_arr) + elif source["white_direction"]: + rx = source["direction"][0] + ry = source["direction"][1] + rz = source["direction"][2] + ux, uy, uz = sample_white_direction(rx, ry, rz, P_rec_arr) + elif source["mono_direction"]: + ux = source["direction"][0] + uy = source["direction"][1] + uz = source["direction"][2] + + # Energy + if mcdc["settings"]["multigroup_mode"]: + E = 0.0 + if source["mono_energetic"]: + g = source["energy_group"] + else: + ID = source["energy_group_pmf_ID"] + pmf = mcdc["pmf_distributions"][ID] + g = sample_pmf(pmf, P_rec_arr, data) + else: + g = 0 + if source["mono_energetic"]: + E = source["energy"] + else: + ID = source["energy_pdf_ID"] + table = mcdc["tabulated_distributions"][ID] + E = sample_tabulated(table, P_rec_arr, data) + + # Time + if source["discrete_time"]: + t = source["time"] + else: + t = sample_uniform(source["time_range"][0], source["time_range"][1], P_rec_arr) + + # Make and return particle + P_rec["x"] = x + P_rec["y"] = y + P_rec["z"] = z + P_rec["t"] = t + P_rec["ux"] = ux + P_rec["uy"] = uy + P_rec["uz"] = uz + P_rec["g"] = g + P_rec["E"] = E + P_rec["w"] = 1.0 + P_rec["particle_type"] = source["particle_type"] diff --git a/mcdc/transport/tally/__init__.py b/mcdc/transport/tally/__init__.py new file mode 100644 index 000000000..000e1cc2a --- /dev/null +++ b/mcdc/transport/tally/__init__.py @@ -0,0 +1,3 @@ +import mcdc.transport.tally.filter as filter +import mcdc.transport.tally.score as score +import mcdc.transport.tally.closeout as closeout diff --git a/mcdc/transport/tally/closeout.py b/mcdc/transport/tally/closeout.py new file mode 100644 index 000000000..21de2c84d --- /dev/null +++ b/mcdc/transport/tally/closeout.py @@ -0,0 +1,312 @@ +import math +import numpy as np + +from numba import literal_unroll, njit, objmode +from mpi4py import MPI + +#### + +import mcdc.mcdc_set as mcdc_set +import mcdc.transport.particle_bank as particle_bank_module + +from mcdc.constant import ( + GYRATION_RADIUS_ALL, + GYRATION_RADIUS_INFINITE_X, + GYRATION_RADIUS_INFINITE_Y, + GYRATION_RADIUS_INFINITE_Z, + GYRATION_RADIUS_ONLY_X, + GYRATION_RADIUS_ONLY_Y, + GYRATION_RADIUS_ONLY_Z, +) +from mcdc.print_ import print_structure + + +# ====================================================================================== +# Reduce tally bins +# ====================================================================================== + + +@njit +def reduce(mcdc, data): + for tally in mcdc["tallies"]: + _reduce(tally, mcdc, data) + + +@njit +def _reduce(tally, mcdc, data): + N = tally["bin_length"] + start = tally["bin_offset"] + end = start + N + + # Normalize + N_particle = mcdc["settings"]["N_particle"] + for i in range(N): + data[start + i] /= N_particle + + # MPI Reduce + buff = np.zeros(N) + with objmode(): + MPI.COMM_WORLD.Reduce(data[start:end], buff, MPI.SUM, 0) + data[start:end] = buff + + +# ====================================================================================== +# Accumulate tally bins +# ====================================================================================== + + +@njit +def accumulate(mcdc, data): + for tally in mcdc["tallies"]: + _accumulate(tally, data) + + +@njit +def _accumulate(tally, data): + N_bin = tally["bin_length"] + offset_bin = tally["bin_offset"] + offset_sum = tally["bin_sum_offset"] + offset_sum_square = tally["bin_sum_square_offset"] + + # Note: Three separate loops are employed to avoid cache miss due to potentially + # large N_bin + + # Sum of score + for i in range(N_bin): + score = data[offset_bin + i] + data[offset_sum + i] += score + + # Sum of score squared + for i in range(N_bin): + score = data[offset_bin + i] + data[offset_sum_square + i] += score * score + + # Reset score bin + for i in range(N_bin): + data[offset_bin + i] = 0.0 + + +# ====================================================================================== +# Finalize +# ====================================================================================== + + +@njit +def finalize(mcdc, data): + for tally in mcdc["tallies"]: + _finalize(tally, mcdc, data) + + +@njit +def _finalize(tally, mcdc, data): + N_history = mcdc["settings"]["N_particle"] + N_batch = mcdc["settings"]["N_batch"] + N_bin = tally["bin_length"] + sum_start = tally["bin_sum_offset"] + sum_sq_start = tally["bin_sum_square_offset"] + sum_end = sum_start + N_bin + sum_sq_end = sum_sq_start + N_bin + + if N_batch > 1: + N_history = N_batch + + elif mcdc["settings"]["eigenvalue_mode"]: + N_history = mcdc["settings"]["N_active"] + + else: + # MPI Reduce + buff = np.zeros(N_bin) + buff_sq = np.zeros(N_bin) + with objmode(): + MPI.COMM_WORLD.Reduce(data[sum_start:sum_end], buff, MPI.SUM, 0) + MPI.COMM_WORLD.Reduce(data[sum_sq_start:sum_sq_end], buff_sq, MPI.SUM, 0) + data[sum_start:sum_end] = buff + data[sum_sq_start:sum_sq_end] = buff_sq + + # Calculate and store statistics + # sum --> mean + # sum_sq --> standard deviation + N_bin = tally["bin_length"] + offset_sum = tally["bin_sum_offset"] + offset_sum_square = tally["bin_sum_square_offset"] + for i in range(N_bin): + data[offset_sum + i] = data[offset_sum + i] / N_history + radicand = ( + data[offset_sum_square + i] / N_history - np.square(data[offset_sum + i]) + ) / (N_history - 1) + + # Check for round-off error (TODO: Check why this is needed.) + if abs(radicand) < 1e-16: + data[offset_sum_square + i] = 0.0 + else: + data[offset_sum_square + i] = math.sqrt(radicand) + + +# ====================================================================================== +# Reset sum bins +# ====================================================================================== + + +@njit +def reset_sum_bins(mcdc, data): + for tally in mcdc["tallies"]: + _reset_sum_bins(tally, data) + + +@njit +def _reset_sum_bins(tally, data): + N_bin = tally["bin_length"] + offset_sum = tally["bin_sum_offset"] + offset_sum_square = tally["bin_sum_square_offset"] + + for i in range(N_bin): + data[offset_sum + i] = 0.0 + data[offset_sum_square + i] = 0.0 + + +# ====================================================================================== +# Eigenvalue +# ====================================================================================== + + +@njit +def eigenvalue_cycle(mcdc, data): + idx_cycle = mcdc["idx_cycle"] + N_particle = mcdc["settings"]["N_particle"] + + # MPI Allreduce + buff_nuSigmaF = np.zeros(1, np.float64) + buff_n = np.zeros(1, np.float64) + buff_nmax = np.zeros(1, np.float64) + buff_C = np.zeros(1, np.float64) + buff_Cmax = np.zeros(1, np.float64) + with objmode(): + MPI.COMM_WORLD.Allreduce( + np.array(mcdc["eigenvalue_tally_nuSigmaF"]), buff_nuSigmaF, MPI.SUM + ) + if mcdc["cycle_active"]: + MPI.COMM_WORLD.Allreduce( + np.array(mcdc["eigenvalue_tally_n"]), buff_n, MPI.SUM + ) + MPI.COMM_WORLD.Allreduce(np.array([mcdc["n_max"]]), buff_nmax, MPI.MAX) + MPI.COMM_WORLD.Allreduce( + np.array(mcdc["eigenvalue_tally_C"]), buff_C, MPI.SUM + ) + MPI.COMM_WORLD.Allreduce(np.array([mcdc["C_max"]]), buff_Cmax, MPI.MAX) + + # Update and store k_eff + mcdc["k_eff"] = buff_nuSigmaF[0] / N_particle + mcdc_set.simulation.k_cycle(idx_cycle, mcdc, data, value=mcdc["k_eff"]) + + # Normalize other eigenvalue/global tallies + tally_n = buff_n[0] / N_particle + tally_C = buff_C[0] / N_particle + + # Maximum densities + mcdc["n_max"] = buff_nmax[0] + mcdc["C_max"] = buff_Cmax[0] + + # Accumulate running average + if mcdc["cycle_active"]: + mcdc["k_avg"] += mcdc["k_eff"] + mcdc["k_sdv"] += mcdc["k_eff"] * mcdc["k_eff"] + mcdc["n_avg"] += tally_n + mcdc["n_sdv"] += tally_n * tally_n + mcdc["C_avg"] += tally_C + mcdc["C_sdv"] += tally_C * tally_C + + N = 1 + mcdc["idx_cycle"] - mcdc["settings"]["N_inactive"] + mcdc["k_avg_running"] = mcdc["k_avg"] / N + if N == 1: + mcdc["k_sdv_running"] = 0.0 + else: + mcdc["k_sdv_running"] = math.sqrt( + (mcdc["k_sdv"] / N - mcdc["k_avg_running"] ** 2) / (N - 1) + ) + + # Reset accumulators + mcdc["eigenvalue_tally_nuSigmaF"][0] = 0.0 + mcdc["eigenvalue_tally_n"][0] = 0.0 + mcdc["eigenvalue_tally_C"][0] = 0.0 + + # ===================================================================== + # Gyration radius + # ===================================================================== + + if mcdc["settings"]["use_gyration_radius"]: + # Center of mass + N_local = particle_bank_module.get_bank_size(mcdc["bank_census"]) + total_local = np.zeros(4, np.float64) # [x,y,z,W] + total = np.zeros(4, np.float64) + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + total_local[0] += P["x"] * P["w"] + total_local[1] += P["y"] * P["w"] + total_local[2] += P["z"] * P["w"] + total_local[3] += P["w"] + # MPI Allreduce + with objmode(): + MPI.COMM_WORLD.Allreduce(total_local, total, MPI.SUM) + # COM + W = total[3] + com_x = total[0] / W + com_y = total[1] / W + com_z = total[2] / W + + # Distance RMS + rms_local = np.zeros(1, np.float64) + rms = np.zeros(1, np.float64) + gr_type = mcdc["settings"]["gyration_radius_type"] + if gr_type == GYRATION_RADIUS_ALL: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ( + (P["x"] - com_x) ** 2 + + (P["y"] - com_y) ** 2 + + (P["z"] - com_z) ** 2 + ) * P["w"] + elif gr_type == GYRATION_RADIUS_INFINITE_X: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["y"] - com_y) ** 2 + (P["z"] - com_z) ** 2) * P["w"] + elif gr_type == GYRATION_RADIUS_INFINITE_Y: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["x"] - com_x) ** 2 + (P["z"] - com_z) ** 2) * P["w"] + elif gr_type == GYRATION_RADIUS_INFINITE_Z: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["x"] - com_x) ** 2 + (P["y"] - com_y) ** 2) * P["w"] + elif gr_type == GYRATION_RADIUS_ONLY_X: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["x"] - com_x) ** 2) * P["w"] + elif gr_type == GYRATION_RADIUS_ONLY_Y: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["y"] - com_y) ** 2) * P["w"] + elif gr_type == GYRATION_RADIUS_ONLY_Z: + for i in range(N_local): + P = mcdc["bank_census"]["particles"][i] + rms_local[0] += ((P["z"] - com_z) ** 2) * P["w"] + + # MPI Allreduce + with objmode(): + MPI.COMM_WORLD.Allreduce(rms_local, rms, MPI.SUM) + rms = math.sqrt(rms[0] / W) + + # Gyration radius + mcdc_set.simulation.gyration_radius(idx_cycle, mcdc, data, value=rms) + + +@njit +def eigenvalue_simulation(mcdc): + N = mcdc["settings"]["N_active"] + mcdc["n_avg"] /= N + mcdc["C_avg"] /= N + if N > 1: + mcdc["n_sdv"] = math.sqrt((mcdc["n_sdv"] / N - mcdc["n_avg"] ** 2) / (N - 1)) + mcdc["C_sdv"] = math.sqrt((mcdc["C_sdv"] / N - mcdc["C_avg"] ** 2) / (N - 1)) + else: + mcdc["n_sdv"] = 0.0 + mcdc["C_sdv"] = 0.0 diff --git a/mcdc/transport/tally/filter.py b/mcdc/transport/tally/filter.py new file mode 100644 index 000000000..22856ba1c --- /dev/null +++ b/mcdc/transport/tally/filter.py @@ -0,0 +1,112 @@ +import math + +from numba import literal_unroll, njit + +#### + +import mcdc.mcdc_get as mcdc_get +import mcdc.mcdc_set as mcdc_set + +from mcdc.constant import ( + COINCIDENCE_TOLERANCE_DIRECTION, + COINCIDENCE_TOLERANCE_ENERGY, + COINCIDENCE_TOLERANCE_TIME, +) +from mcdc.transport.util import find_bin + + +@njit +def get_filter_indices(particle_container, tally, data, MG_mode): + i_mu, i_azi, i_energy, i_time = 0, 0, 0, 0 + + if tally["filter_direction"]: + i_mu, i_azi = get_direction_index(particle_container, tally, data) + + if tally["filter_energy"]: + i_energy = get_energy_index(particle_container, tally, data, MG_mode) + + if tally["filter_time"]: + i_time = get_time_index(particle_container, tally, data) + + return i_mu, i_azi, i_energy, i_time + + +@njit +def get_direction_index(particle_container, tally, data): + particle = particle_container[0] + + # Particle properties + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + + # Polar reference + nx = tally["polar_reference"][0] + ny = tally["polar_reference"][1] + nz = tally["polar_reference"][2] + + # TODO: Rotate direction based on the polar reference + if nz != 1.0: + pass + + mu = uz + azi = math.acos(ux / math.sqrt(ux * ux + uy * uy)) + if uy < 0.0: + azi *= -1 + + tolerance = COINCIDENCE_TOLERANCE_DIRECTION + i_mu = find_bin(mu, mcdc_get.tally.mu_all(tally, data), tolerance) + i_azi = find_bin(azi, mcdc_get.tally.azi_all(tally, data), tolerance) + return i_mu, i_azi + + +@njit +def get_energy_index(particle_container, tally, data, multigroup_mode): + particle = particle_container[0] + + if multigroup_mode: + E = particle["g"] + else: + E = particle["E"] + + tolerance = COINCIDENCE_TOLERANCE_ENERGY + return find_bin(E, mcdc_get.tally.energy_all(tally, data), tolerance) + + +@njit +def get_time_index(particle_container, tally, data): + particle = particle_container[0] + + # Particle properties + time = particle["t"] + + tolerance = COINCIDENCE_TOLERANCE_TIME + return find_bin( + time, mcdc_get.tally.time_all(tally, data), tolerance, go_lower=False + ) + + +@njit +def set_census_based_time_grid(mcdc, data): + settings = mcdc["settings"] + tally_frequency = settings["census_tally_frequency"] + idx_census = mcdc["idx_census"] + + # Starting time + if idx_census == 0: + t_start = 0.0 + else: + t_start = mcdc_get.settings.census_time(idx_census - 1, settings, data) + + # Ending time + t_end = mcdc_get.settings.census_time(idx_census, settings, data) + + # Time grid width + dt = (t_end - t_start) / tally_frequency + + # Set the time grid to all tallies + for tally in mcdc["tallies"]: + mcdc_set.tally.time(0, tally, data, t_start) + for j in range(tally_frequency): + t_next = mcdc_get.tally.time(j, tally, data) + dt + mcdc_set.tally.time(j + 1, tally, data, t_next) diff --git a/mcdc/transport/tally/score.py b/mcdc/transport/tally/score.py new file mode 100644 index 000000000..9c4c081b2 --- /dev/null +++ b/mcdc/transport/tally/score.py @@ -0,0 +1,463 @@ +from numba import njit + +#### + +import mcdc.mcdc_get as mcdc_get +import mcdc.transport.mesh as mesh_module +import mcdc.transport.physics as physics + +from mcdc.code_factory import adapt +from mcdc.constant import ( + AXIS_T, + AXIS_X, + AXIS_Y, + AXIS_Z, + COINCIDENCE_TOLERANCE, + COINCIDENCE_TOLERANCE_TIME, + INF, + MESH_STRUCTURED, + MESH_UNIFORM, + MULTIPLIER_ENERGY, + REACTION_NEUTRON_CAPTURE, + REACTION_NEUTRON_FISSION, + REACTION_TOTAL, + SCORE_FLUX, + SCORE_DENSITY, + SCORE_COLLISION, + SCORE_CAPTURE, + SCORE_FISSION, + SCORE_NET_CURRENT, +) +from mcdc.transport.geometry.surface import get_normal_component +from mcdc.transport.tally.filter import get_filter_indices +from mcdc.print_ import print_structure + + +@njit +def make_scores(particle_container, flux, tally, idx_base, mcdc, data): + particle = particle_container[0] + speed = physics.particle_speed(particle_container, mcdc, data) + + multiplier = 1.0 + for i_multiplier in range(tally["multipliers_length"]): + multiplier_type = mcdc_get.tally.multipliers(i_multiplier, tally, data) + if multiplier_type == MULTIPLIER_ENERGY: + multiplier *= particle["E"] + + for i_score in range(tally["scores_length"]): + score_type = mcdc_get.tally.scores(i_score, tally, data) + score = 0.0 + if score_type == SCORE_FLUX: + score = flux + elif score_type == SCORE_DENSITY: + score = flux / speed + elif score_type == SCORE_COLLISION: + score = flux * physics.macro_xs( + REACTION_TOTAL, particle_container, mcdc, data + ) + elif score_type == SCORE_CAPTURE: + score = flux * physics.macro_xs( + REACTION_NEUTRON_CAPTURE, particle_container, mcdc, data + ) + elif score_type == SCORE_FISSION: + score = flux * physics.macro_xs( + REACTION_NEUTRON_FISSION, particle_container, mcdc, data + ) + elif score_type == SCORE_NET_CURRENT: + surface = mcdc["surfaces"][particle["surface_ID"]] + mu = get_normal_component(particle_container, speed, surface, data) + score = flux * mu + adapt.global_add(data, idx_base + i_score, score * multiplier) + + +@njit +def tracklength_tally(particle_container, distance, tally, mcdc, data): + particle = particle_container[0] + tally_base = mcdc["tallies"][tally["parent_ID"]] + + # Get filter indices + MG_mode = mcdc["settings"]["multigroup_mode"] + i_mu, i_azi, i_energy, i_time = get_filter_indices( + particle_container, tally_base, data, MG_mode + ) + + # No score if outside non-changing phase-space bins + if i_mu == -1 or i_azi == -1 or i_energy == -1: + return + + # Particle/track properties + ut = 1.0 / physics.particle_speed(particle_container, mcdc, data) + t = particle["t"] + t_final = t + ut * distance + + # No score if particle does not cross the time bins + t_min = mcdc_get.tally.time(0, tally_base, data) + t_max = mcdc_get.tally.time_last(tally_base, data) + if ( + t_final < t_min + COINCIDENCE_TOLERANCE_TIME + or t > t_max - COINCIDENCE_TOLERANCE_TIME + ): + return + + # Get the appropriate time index if needed + if t < t_min + COINCIDENCE_TOLERANCE_TIME: + i_time = 0 + + # Tally base index + idx_base = ( + tally_base["bin_offset"] + + i_mu * tally_base["stride_mu"] + + i_azi * tally_base["stride_azi"] + + i_energy * tally_base["stride_energy"] + + i_time * tally_base["stride_time"] + ) + + # Sweep through the distance + distance_swept = 0.0 + while distance_swept < distance - COINCIDENCE_TOLERANCE: + # The next time grid + t_next = mcdc_get.tally.time(i_time + 1, tally_base, data) + + # Get the distance to score in this segment + if t_final < t_next - COINCIDENCE_TOLERANCE_TIME: + distance_scored = distance - distance_swept + else: + distance_scored = (t_next - t) / ut + + # Score + flux = distance_scored * particle["w"] + make_scores(particle_container, flux, tally_base, idx_base, mcdc, data) + + # Accumulate distance swept + distance_swept += distance_scored + + # Increment the time + t += distance_scored * ut + + # Increment index + i_time += 1 + idx_base += tally_base["stride_time"] + + # Check if it is the last segment + # The rest of the distance is not scored + if i_time == tally_base["time_length"]: + return + + +@njit +def surface_tally(particle_container, surface, tally, mcdc, data): + particle = particle_container[0] + tally_base = mcdc["tallies"][tally["parent_ID"]] + + # Get filter indices + MG_mode = mcdc["settings"]["multigroup_mode"] + i_mu, i_azi, i_energy, i_time = get_filter_indices( + particle_container, tally_base, data, MG_mode + ) + + # No score if outside non-changing phase-space bins + if i_mu == -1 or i_azi == -1 or i_energy == -1 or i_time == -1: + return + + # Tally index + idx_base = ( + tally_base["bin_offset"] + + i_mu * tally_base["stride_mu"] + + i_azi * tally_base["stride_azi"] + + i_energy * tally_base["stride_energy"] + + i_time * tally_base["stride_time"] + ) + + # Flux + speed = physics.particle_speed(particle_container, mcdc, data) + mu = get_normal_component(particle_container, speed, surface, data) + flux = particle["w"] / abs(mu) + + # Score + make_scores(particle_container, flux, tally_base, idx_base, mcdc, data) + + +@njit +def mesh_tally(particle_container, distance, tally, mcdc, data): + particle = particle_container[0] + tally_base = mcdc["tallies"][tally["parent_ID"]] + + # Get filter indices + MG_mode = mcdc["settings"]["multigroup_mode"] + i_mu, i_azi, i_energy, i_time = get_filter_indices( + particle_container, tally_base, data, MG_mode + ) + + # No score if outside non-changing phase-space bins + if i_mu == -1 or i_azi == -1 or i_energy == -1: + return + + # Get the mesh + mesh = mcdc["meshes"][tally["mesh_ID"]] + + # Particle/track properties + x = particle["x"] + y = particle["y"] + z = particle["z"] + t = particle["t"] + ux = particle["ux"] + uy = particle["uy"] + uz = particle["uz"] + ut = 1.0 / physics.particle_speed(particle_container, mcdc, data) + x_final = x + ux * distance + y_final = y + uy * distance + z_final = z + uz * distance + t_final = t + ut * distance + + # No score if particle does not cross the time bins + t_min = mcdc_get.tally.time(0, tally_base, data) + t_max = mcdc_get.tally.time_last(tally_base, data) + if ( + t_final < t_min + COINCIDENCE_TOLERANCE_TIME + or t > t_max - COINCIDENCE_TOLERANCE_TIME + ): + return + + # Get the appropriate time index if needed + if t < t_min: + i_time = 0 + + # Get mesh bin indices + i_x, i_y, i_z = mesh_module.get_indices(particle_container, mesh, mcdc, data) + + # No score if particle does not cross the mesh bins + # Also get the appropriate index if needed + x_min = mesh_module.get_x(0, mesh, mcdc, data) + x_max = mesh_module.get_x(mesh["Nx"], mesh, mcdc, data) + if ux > 0.0: + if x_final < x_min + COINCIDENCE_TOLERANCE or x > x_max - COINCIDENCE_TOLERANCE: + return + if x < x_min + COINCIDENCE_TOLERANCE: + i_x = 0 + else: + if x < x_min + COINCIDENCE_TOLERANCE or x_final > x_max - COINCIDENCE_TOLERANCE: + return + if x > x_max - COINCIDENCE_TOLERANCE: + i_x = mesh["Nx"] + y_min = mesh_module.get_y(0, mesh, mcdc, data) + y_max = mesh_module.get_y(mesh["Ny"], mesh, mcdc, data) + if uy > 0.0: + if y_final < y_min + COINCIDENCE_TOLERANCE or y > y_max - COINCIDENCE_TOLERANCE: + return + if y < y_min + COINCIDENCE_TOLERANCE: + i_y = 0 + else: + if y < y_min + COINCIDENCE_TOLERANCE or y_final > y_max - COINCIDENCE_TOLERANCE: + return + if y > y_max - COINCIDENCE_TOLERANCE: + i_y = mesh["Ny"] + z_min = mesh_module.get_z(0, mesh, mcdc, data) + z_max = mesh_module.get_z(mesh["Nz"], mesh, mcdc, data) + if uz > 0.0: + if z_final < z_min + COINCIDENCE_TOLERANCE or z > z_max - COINCIDENCE_TOLERANCE: + return + if z < z_min + COINCIDENCE_TOLERANCE: + i_z = 0 + else: + if z < z_min + COINCIDENCE_TOLERANCE or z_final > z_max - COINCIDENCE_TOLERANCE: + return + if z > z_max - COINCIDENCE_TOLERANCE: + i_z = mesh["Nz"] + + # Tally base index + idx_base = ( + tally_base["bin_offset"] + + i_mu * tally_base["stride_mu"] + + i_azi * tally_base["stride_azi"] + + i_energy * tally_base["stride_energy"] + + i_time * tally_base["stride_time"] + + i_x * tally["stride_x"] + + i_y * tally["stride_y"] + + i_z * tally["stride_z"] + ) + + # Sweep through the distance + distance_swept = 0.0 + while distance_swept < distance - COINCIDENCE_TOLERANCE: + # ============================================================================== + # Find distances to the mesh grids + # ============================================================================== + + # x-direction + if ux == 0.0: + dx = INF + else: + if ux > 0.0: + x_next = mesh_module.get_x(i_x + 1, mesh, mcdc, data) + x_next = min(x_next, x_final) + else: + x_next = mesh_module.get_x(i_x, mesh, mcdc, data) + x_next = max(x_next, x_final) + dx = (x_next - x) / ux + + # y-direction + if uy == 0.0: + dy = INF + else: + if uy > 0.0: + y_next = mesh_module.get_y(i_y + 1, mesh, mcdc, data) + y_next = min(y_next, y_final) + else: + y_next = mesh_module.get_y(i_y, mesh, mcdc, data) + y_next = max(y_next, y_final) + dy = (y_next - y) / uy + + # z-direction + if uz == 0.0: + dz = INF + else: + if uz > 0.0: + z_next = mesh_module.get_z(i_z + 1, mesh, mcdc, data) + z_next = min(z_next, z_final) + else: + z_next = mesh_module.get_z(i_z, mesh, mcdc, data) + z_next = max(z_next, z_final) + dz = (z_next - z) / uz + + # t-direction + t_next = mcdc_get.tally.time(i_time + 1, tally_base, data) + dt = (min(t_next, t_final) - t) / ut + + # ============================================================================== + # Evaluate grid crossings + # ============================================================================== + + distance_scored = INF + axis_crossed = -1 + if dx <= distance_scored: + axis_crossed = AXIS_X + distance_scored = dx + if dy <= distance_scored: + axis_crossed = AXIS_Y + distance_scored = dy + if dz <= distance_scored: + axis_crossed = AXIS_Z + distance_scored = dz + if dt <= distance_scored: + axis_crossed = AXIS_T + distance_scored = dt + + # Score + flux = distance_scored * particle["w"] + make_scores(particle_container, flux, tally_base, idx_base, mcdc, data) + + # Accumulate distance swept + distance_swept += distance_scored + + # Move the 4D position + x += distance_scored * ux + y += distance_scored * uy + z += distance_scored * uz + t += distance_scored * ut + + # Increment index and check if out of bounds + if axis_crossed == AXIS_X: + if ux > 0.0: + i_x += 1 + if i_x == mesh["Nx"]: + break + idx_base += tally["stride_x"] + else: + i_x -= 1 + if i_x == -1: + break + idx_base -= tally["stride_x"] + elif axis_crossed == AXIS_Y: + if uy > 0.0: + i_y += 1 + if i_y == mesh["Ny"]: + break + idx_base += tally["stride_y"] + else: + i_y -= 1 + if i_y == -1: + break + idx_base -= tally["stride_y"] + elif axis_crossed == AXIS_Z: + if uz > 0.0: + i_z += 1 + if i_z == mesh["Nz"]: + break + idx_base += tally["stride_z"] + else: + i_z -= 1 + if i_z == -1: + break + idx_base -= tally["stride_z"] + elif axis_crossed == AXIS_T: + i_time += 1 + if i_time == tally_base["time_length"] - 1: + break + idx_base += tally_base["stride_time"] + + +# ============================================================================= +# Eigenvalue tally +# ============================================================================= + + +@njit +def eigenvalue_tally(particle_container, distance, mcdc, data): + particle = particle_container[0] + flux = distance * particle["w"] + + # Get nu-fission + nuSigmaF = physics.neutron_production_xs( + REACTION_NEUTRON_FISSION, particle_container, mcdc, data + ) + + # Fission production (needed even during inactive cycle) + adapt.global_add(mcdc["eigenvalue_tally_nuSigmaF"], 0, flux * nuSigmaF) + + # Done, if inactive + if not mcdc["cycle_active"]: + return + + # ================================================================================== + # Neutron density + # ================================================================================== + + v = physics.particle_speed(particle_container, mcdc, data) + n_density = flux / v + adapt.global_add(mcdc["eigenvalue_tally_n"], 0, n_density) + + # Maximum neutron density + if mcdc["n_max"] < n_density: + mcdc["n_max"] = n_density + + # ================================================================================== + # TODO: Delayed neutron precursor density + # ================================================================================== + return + # Get the decay-wighted multiplicity + total = 0.0 + if mcdc["settings"]["multigroup_mode"]: + g = particle["g"] + for j in range(J): + nu_d = mcdc_get.material.mgxs_nu_d(g, j, material, data) + decay = mcdc_get.material.mgxs_decay_rate(j, material, data) + total += nu_d / decay + else: + E = P["E"] + for i in range(material["N_nuclide"]): + ID_nuclide = material["nuclide_IDs"][i] + nuclide = mcdc["nuclides"][ID_nuclide] + if not nuclide["fissionable"]: + continue + for j in range(J): + nu_d = get_nu_group(NU_FISSION_DELAYED, nuclide, E, j) + decay = nuclide["ce_decay"][j] + total += nu_d / decay + + SigmaF = physics.macro_xs(REACTION_NEUTRON_FISSION, particle_container, mcdc, data) + C_density = flux * total * SigmaF / mcdc["k_eff"] + adapt.global_add(mcdc["eigenvalue_tally_C"], 0, C_density) + + # Maximum precursor density + if mcdc["C_max"] < C_density: + mcdc["C_max"] = C_density diff --git a/mcdc/transport/technique.py b/mcdc/transport/technique.py new file mode 100644 index 000000000..bbc6acfcd --- /dev/null +++ b/mcdc/transport/technique.py @@ -0,0 +1,84 @@ +import numpy as np +import math + +from numba import njit + +#### + +import mcdc.code_factory.adapt as adapt +import mcdc.object_.numba_types as type_ +import mcdc.transport.particle as particle_module +import mcdc.transport.particle_bank as particle_bank_module +import mcdc.transport.rng as rng + + +# ====================================================================================== +# Weight Roulette +# ====================================================================================== + + +@njit +def weight_roulette(particle_container, mcdc): + particle = particle_container[0] + if particle["w"] < mcdc["weight_roulette"]["weight_threshold"]: + w_target = mcdc["weight_roulette"]["weight_target"] + survival_probability = particle["w"] / w_target + if rng.lcg(particle_container) < survival_probability: + particle["w"] = w_target + else: + particle["alive"] = False + + +# ====================================================================================== +# Population Control +# ====================================================================================== + + +@njit +def population_control(mcdc): + """Uniform Splitting-Roulette technique""" + + bank_census = mcdc["bank_census"] + M = mcdc["settings"]["N_particle"] + bank_source = mcdc["bank_source"] + + # Scan the bank + idx_start, N_local, N = particle_bank_module.bank_scanning(bank_census, mcdc) + idx_end = idx_start + N_local + + # Abort if census bank is empty + if N == 0: + return + + # Weight scaling + ws = float(N) / float(M) + + # Splitting Number + sn = 1.0 / ws + + P_rec_arr = np.zeros(1, type_.particle_data) + P_rec = P_rec_arr[0] + + # Perform split-roulette to all particles in local bank + particle_bank_module.set_bank_size(bank_source, 0) + for idx in range(N_local): + # Weight of the surviving particles + w = bank_census["particles"][idx]["w"] + w_survive = w * ws + + # Determine number of guaranteed splits + N_split = math.floor(sn) + + # Survive the russian roulette? + xi = rng.lcg(bank_census["particles"][idx : idx + 1]) + if xi < sn - N_split: + N_split += 1 + + # Split the particle + for i in range(N_split): + particle_module.copy_as_child( + P_rec_arr, bank_census["particles"][idx : idx + 1] + ) + # Set weight + P_rec["w"] = w_survive + particle_bank_module.add_source(P_rec_arr, mcdc) diff --git a/mcdc/transport/util.py b/mcdc/transport/util.py new file mode 100644 index 000000000..51c27ec79 --- /dev/null +++ b/mcdc/transport/util.py @@ -0,0 +1,115 @@ +import math + +from numba import njit +from typing import Sequence + + +@njit +def find_bin( + value: float, grid: Sequence[float], epsilon: float = 0.0, go_lower: bool = True +) -> int: + """ + Return the bin index i for which grid[i] <= value < grid[i+1], with optional + epsilon tolerance and tie-breaking toward the lower/upper bin. + + Parameters + ---------- + value : float + Query point. + grid : Sequence[float] + Monotonically increasing bin edges of length N_grid = N_bin + 1. + epsilon : float, optional (default: 0.0) + Tolerance to treat values as being exactly on a grid edge if + |value - grid[k]| <= epsilon. + go_lower : bool, optional (default: True) + Tie-breaking rule when value is at/within epsilon of a grid edge: + - True -> tie to the lower/left bin + - False -> tie to the upper/right bin + + Edge behavior (with epsilon) + ---------------------------- + - Interior edges (grid[k], 0 bin k-1 + * go_lower=False -> bin k + - First edge (grid[0]): + * If inside or exactly at grid[0] within epsilon: + - go_lower=True -> -1 (treat as outside left) + - go_lower=False -> 0 (first bin) + - Last edge (grid[-1]): + * If exactly at/within epsilon: + - go_lower=True -> last bin (N_bin-1) + - go_lower=False -> -1 (outside right) + - Beyond first/last edge by more than epsilon: return -1. + + Notes + ----- + - With epsilon=0 and go_lower=True, this reduces to the standard + left-closed/right-open binning (grid[i] <= value < grid[i+1]). + - Scalar-only implementation (no NumPy required). + """ + n = len(grid) + + # Fast reject beyond tolerance band + if value < grid[0] - epsilon or value > grid[-1] + epsilon: + return -1 + + # Base binary search (strict left-closed / right-open, no epsilon) + low, high = 0, n - 1 # search over edge indices + if value < grid[0] or value >= grid[-1]: + base = -1 + else: + while high - low > 1: + mid = (low + high) // 2 + if value < grid[mid]: + high = mid + else: + low = mid + base = low # provisional bin: [grid[low], grid[low+1]) + + # Tie-breaking near edges (epsilon band) + if base == -1: + # Near first edge? + if abs(value - grid[0]) <= epsilon: + return -1 if go_lower else 0 + # Near last edge? + if abs(value - grid[-1]) <= epsilon: + return (n - 2) if go_lower else -1 + return -1 + + idx = base + + # Check left edge of this bin + if abs(value - grid[idx]) <= epsilon: + if idx == 0: + return -1 if go_lower else 0 + return (idx - 1) if go_lower else idx + + # Check right edge of this bin + right_edge = grid[idx + 1] + if abs(value - right_edge) <= epsilon: + if idx + 1 == n - 1: # last grid point + return (n - 2) if go_lower else -1 + return idx if go_lower else (idx + 1) + + # Strict interior + return idx + + +@njit +def linear_interpolation(x, x1, x2, y1, y2): + return y1 + (x - x1) * (y2 - y1) / (x2 - x1) + + +@njit +def log_interpolation(x, x1, x2, y1, y2): + # Convert to logs + lx1, lx2 = math.log(x1), math.log(x2) + ly1, ly2 = math.log(y1), math.log(y2) + + # Slope in log–log space + m = (ly2 - ly1) / (lx2 - lx1) + + # Interpolate log(y) + ly = ly1 + m * (math.log(x) - lx1) + + return math.exp(ly) diff --git a/mcdc/type_.py b/mcdc/type_.py deleted file mode 100644 index ad266b4d4..000000000 --- a/mcdc/type_.py +++ /dev/null @@ -1,1738 +0,0 @@ -import h5py -import math -import numpy as np -import os - -from mpi4py import MPI -from mpi4py.util.dtlib import from_numpy_dtype -from numba import njit - -from mcdc.print_ import print_error - -from mcdc.constant import WW_PREVIOUS - -# ============================================================================== -# Basic types -# ============================================================================== - -float64 = np.float64 -int64 = np.int64 -int32 = np.int32 -uint64 = np.uint64 -uint8 = np.uint8 -bool_ = np.bool_ -uintp = np.uintp -str_ = "U32" - - -# ============================================================================== -# MC/DC types -# ============================================================================== -""" -Some types are problem-dependent and defined in code_factory.py -""" - -particle = None -particle_record = None - -nuclide = None -material = None - -lattice = None - -source = None -setting = None -mesh_tally = None -surface_tally = None -cell_tally = None -cs_tally = None -technique = None - -gpu_meta = None - -global_ = None -global_size = None - -# ============================================================================== -# MC/DC Member Array Sizes -# ============================================================================== - - -def literalize(value): - jit_str = f"@njit\ndef impl():\n return {value}\n" - exec(jit_str, globals(), locals()) - return eval("impl") - - -def material_g_size(): - pass - - -def material_j_size(): - pass - - -def rpn_buffer_size(): - pass - - -def make_size_rpn(input_deck): - global rpn_buffer_size - size = max([np.sum(np.array(x._region_RPN) >= 0.0) for x in input_deck.cells]) - rpn_buffer_size = literalize(size) - - -# ============================================================================== -# Alignment Logic -# ============================================================================== -# While CPU execution can robustly handle all sorts of Numba types, GPU -# execution requires structs to follow some of the basic properties expected of -# C-style structs with standard layout: -# -# - Every primitive field is aligned by its size, and padding is inserted -# between fields to ensure alignment in arrays and nested data structures -# -# - Every field has a unique address -# -# If these rules are violated, memory accesses made in GPUs may encounter -# problems. For example, in cases where an access is not at an address aligned -# by their size, a segfault or similar fault will occur, or information will be -# lost. These issues were fixed by providing a function, align, which ensures the -# field lists fed to np.dtype fulfill these requirements. -# -# The align function does the following: -# -# - Tracks the cumulative offset of fields as they appear in the input list. -# -# - Inserts additional padding fields to ensure that primitive fields are -# aligned by their size -# -# - Re-sizes arrays to have at least one element in their array (this ensure -# they have a non-zero size, and hence cannot overlap base addresses with -# other fields. -# - - -def fixup_dims(dim_tuple): - return tuple([max(d, 1) for d in dim_tuple]) - - -def align(field_list): - result = [] - offset = 0 - pad_id = 0 - for field in field_list: - - if isinstance(field[1], list): - raise ValueError("Given type of subfield is a list, but should be a dtype.") - - if len(field) > 3: - print_error( - "Unexpected struct field specification. Specifications \ - usually only consist of 3 or fewer members" - ) - multiplier = 1 - if len(field) == 3: - field = (field[0], field[1], fixup_dims(field[2])) - for d in field[2]: - multiplier *= d - kind = np.dtype(field[1]) - size = kind.itemsize - - if kind.isbuiltin == 0: - alignment = 8 - elif kind.isbuiltin == 1: - alignment = size - else: - print_error("Unexpected field item type") - - size *= multiplier - - if offset % alignment != 0: - pad_size = alignment - (offset % alignment) - result.append((f"padding_{pad_id}", uint8, (pad_size,))) - pad_id += 1 - offset += pad_size - - result.append(field) - offset += size - - if offset % 8 != 0: - pad_size = 8 - (offset % 8) - result.append((f"padding_{pad_id}", uint8, (pad_size,))) - pad_id += 1 - - return result - - -def into_dtype(field_list): - result = np.dtype(align(field_list), align=True) - return result - - -# ============================================================================== -# Copy Logic -# ============================================================================== - - -type_roster = {} - - -def copy_fn_for(kind, name): - code = f"@njit\ndef copy_{name}(dst,src):\n" - for f_name, spec in kind.fields.items(): - f_dtype = spec[0] - if f_dtype in type_roster: - kind_name = type_roster[f_dtype]["name"] - code += f" copy_{kind_name}(dst['{f_name}'],src['{f_name}'])" - else: - code += f" dst['{f_name}'] = src['{f_name}']\n" - type_roster[kind] = {} - type_roster[kind]["name"] = name - exec(code) - return eval(f"copy_{name}") - - -# ============================================================================== -# Particle -# ============================================================================== - - -# Particle (in-flight) -def make_type_particle(input_deck): - global particle - - struct = [ - # Coordinate - ("x", float64), - ("y", float64), - ("z", float64), - ("t", float64), - # Spatial direction - ("ux", float64), - ("uy", float64), - ("uz", float64), - # Energy - ("g", uint64), - ("E", float64), - # Weight - ("w", float64), - # IDs - ("material_ID", int64), - ("cell_ID", int64), - ("surface_ID", int64), - # Misc. - ("alive", bool_), - ("fresh", bool_), - ("event", int64), - ("rng_seed", uint64), - ] - - # Get modes - iQMC = input_deck.technique["iQMC"] - - # ========================================================================= - # iQMC - # ========================================================================= - - # Default number of groups for iQMC - G = 1 - - # iQMC vector of weights - if iQMC: - G = input_deck.materials[0].G - iqmc_struct = into_dtype([("w", float64, (G,))]) - struct += [("iqmc", iqmc_struct)] - - # Save type - particle = into_dtype(struct) - - -# Particle record (in-bank) -def make_type_particle_record(input_deck): - global particle_record, particle_record_mpi - - struct = [ - ("x", float64), - ("y", float64), - ("z", float64), - ("t", float64), - ("ux", float64), - ("uy", float64), - ("uz", float64), - ("g", uint64), - ("E", float64), - ("w", float64), - ("rng_seed", uint64), - ] - - # Get modes - iQMC = input_deck.technique["iQMC"] - - # ========================================================================= - # iQMC - # ========================================================================= - - # Default number of groups for iQMC - G = 1 - - # iQMC vector of weights - if iQMC: - G = input_deck.materials[0].G - iqmc_struct = into_dtype([("w", float64, (G,))]) - struct += [("iqmc", iqmc_struct)] - - # Save type - particle_record = into_dtype(struct) - - particle_record_mpi = from_numpy_dtype(particle_record) - particle_record_mpi.Commit() - - -precursor = into_dtype( - [ - ("x", float64), - ("y", float64), - ("z", float64), - ("g", uint64), - ("n_g", uint64), - ("w", float64), - ] -) - - -# ============================================================================== -# Particle bank -# ============================================================================== - - -def full_particle_bank(max_size): - return into_dtype( - [ - ("particles", particle, (max_size,)), - ("size", int64, (1,)), - ("tag", str_), - ] - ) - - -def particle_bank(max_size): - return into_dtype( - [ - ("particles", particle_record, (max_size,)), - ("size", int64, (1,)), - ("tag", str_), - ] - ) - - -def precursor_bank(max_size): - return into_dtype( - [("precursors", precursor, (max_size,)), ("size", int64, (1,)), ("tag", str_)] - ) - - -# ============================================================================== -# Nuclide -# ============================================================================== - - -def make_type_nuclide(input_deck): - global nuclide - - # Get modes - mode_CE = input_deck.setting["mode_CE"] - mode_MG = input_deck.setting["mode_MG"] - - # Get CE sizes - if mode_CE: - # Zeros for MG sizes - G = 1 - J = 0 - - # Get maximum energy grid sizes for CE data - NE_xs = 0 - NE_nu_p = 0 - NE_nu_d = 0 - NE_chi_p = 0 - NE_chi_d1 = 0 - NE_chi_d2 = 0 - NE_chi_d3 = 0 - NE_chi_d4 = 0 - NE_chi_d5 = 0 - NE_chi_d6 = 0 - - dir_name = os.getenv("MCDC_XSLIB") - for nuc in input_deck.nuclides: - with h5py.File(dir_name + "/" + nuc.name + ".h5", "r") as f: - NE_xs = max(NE_xs, len(f["E_xs"][:])) - NE_nu_p = max(NE_nu_p, len(f["E_nu_p"][:])) - NE_nu_d = max(NE_nu_d, len(f["E_nu_d"][:])) - NE_chi_p = max(NE_chi_p, len(f["E_chi_p"][:])) - NE_chi_d1 = max(NE_chi_d1, len(f["E_chi_d1"][:])) - NE_chi_d2 = max(NE_chi_d2, len(f["E_chi_d2"][:])) - NE_chi_d3 = max(NE_chi_d3, len(f["E_chi_d3"][:])) - NE_chi_d4 = max(NE_chi_d4, len(f["E_chi_d4"][:])) - NE_chi_d5 = max(NE_chi_d5, len(f["E_chi_d5"][:])) - NE_chi_d6 = max(NE_chi_d6, len(f["E_chi_d6"][:])) - - # Get MG sizes - if mode_MG: - G = input_deck.materials[0].G - J = input_deck.materials[0].J - - # Zeros for CE sizes - NE_xs = 0 - NE_nu_p = 0 - NE_nu_d = 0 - NE_chi_p = 0 - NE_chi_d1 = 0 - NE_chi_d2 = 0 - NE_chi_d3 = 0 - NE_chi_d4 = 0 - NE_chi_d5 = 0 - NE_chi_d6 = 0 - - # General data - struct = [ - ("ID", int64), - ("fissionable", bool_), - ("uq", bool_), - ] - - # MG data - struct += [ - ("G", int64), - ("J", int64), - ("speed", float64, (G,)), - ("decay", float64, (J,)), - ("total", float64, (G,)), - ("capture", float64, (G,)), - ("scatter", float64, (G,)), - ("fission", float64, (G,)), - ("nu_s", float64, (G,)), - ("nu_f", float64, (G,)), - ("nu_p", float64, (G,)), - ("nu_d", float64, (G, J)), - ("chi_s", float64, (G, G)), - ("chi_p", float64, (G, G)), - ("chi_d", float64, (J, G)), - ] - - # CE data - struct += [ - ("A", float64), - ("NE_xs", int64), - ("NE_nu_p", int64), - ("NE_nu_d", int64), - ("NE_chi_p", int64), - ("NE_chi_d1", int64), - ("NE_chi_d2", int64), - ("NE_chi_d3", int64), - ("NE_chi_d4", int64), - ("NE_chi_d5", int64), - ("NE_chi_d6", int64), - ("E_xs", float64, (NE_xs,)), - ("E_nu_p", float64, (NE_nu_p,)), - ("E_nu_d", float64, (NE_nu_d,)), - ("E_chi_p", float64, (NE_chi_p,)), - ("E_chi_d1", float64, (NE_chi_d1,)), - ("E_chi_d2", float64, (NE_chi_d2,)), - ("E_chi_d3", float64, (NE_chi_d3,)), - ("E_chi_d4", float64, (NE_chi_d4,)), - ("E_chi_d5", float64, (NE_chi_d5,)), - ("E_chi_d6", float64, (NE_chi_d6,)), - ("ce_total", float64, (NE_xs,)), - ("ce_capture", float64, (NE_xs,)), - ("ce_scatter", float64, (NE_xs,)), - ("ce_fission", float64, (NE_xs,)), - ("ce_nu_p", float64, (NE_nu_p,)), - ("ce_nu_d", float64, (6, NE_nu_d)), - ("ce_chi_p", float64, (NE_chi_p,)), - ("ce_chi_d1", float64, (NE_chi_d1,)), - ("ce_chi_d2", float64, (NE_chi_d2,)), - ("ce_chi_d3", float64, (NE_chi_d3,)), - ("ce_chi_d4", float64, (NE_chi_d4,)), - ("ce_chi_d5", float64, (NE_chi_d5,)), - ("ce_chi_d6", float64, (NE_chi_d6,)), - ("ce_decay", float64, (6,)), - ] - - # Set the type - nuclide = into_dtype(struct) - - -# ============================================================================== -# Material -# ============================================================================== - - -def make_type_material(input_deck): - global material - - # Maximum number of nuclides per material - Nmax_nuclide = max([material.N_nuclide for material in input_deck.materials]) - - # Get modes - mode_CE = input_deck.setting["mode_CE"] - mode_MG = input_deck.setting["mode_MG"] - - # Get CE sizes - if mode_CE: - # Zeros for MG sizes - G = 1 - J = 0 - - # Get MG sizes - if mode_MG: - G = input_deck.materials[0].G - J = input_deck.materials[0].J - - G_adjusted = max(1, G) - J_adjusted = max(1, J) - - global material_g_size - global material_j_size - material_g_size = literalize(G_adjusted) - material_j_size = literalize(J_adjusted) - - # General data - struct = [ - ("ID", int64), - ("N_nuclide", int64), - ("nuclide_IDs", int64, (Nmax_nuclide,)), - ("nuclide_densities", float64, (Nmax_nuclide,)), - ("uq", bool_), - ] - - # MG data - struct += [ - ("G", int64), - ("J", int64), - ("speed", float64, (G,)), - ("total", float64, (G,)), - ("capture", float64, (G,)), - ("scatter", float64, (G,)), - ("fission", float64, (G,)), - ("nu_s", float64, (G,)), - ("nu_f", float64, (G,)), - ("nu_p", float64, (G,)), - ("nu_d", float64, (G, J)), - ("chi_s", float64, (G, G)), - ("chi_p", float64, (G, G)), - ] - - # Set the type - material = into_dtype(struct) - - -# ============================================================================== -# Surface -# ============================================================================== - - -def make_type_surface(input_deck): - global surface - - # Maximum number of tallies and movements - Nmax_tally = 0 - Nmax_move = 0 - for surface in input_deck.surfaces: - Nmax_tally = max(Nmax_tally, surface.N_tally) - Nmax_move = max(Nmax_move, surface.N_move) - - surface = into_dtype( - [ - ("ID", int64), - ("BC", int64), - ("A", float64), - ("B", float64), - ("C", float64), - ("D", float64), - ("E", float64), - ("F", float64), - ("G", float64), - ("H", float64), - ("I", float64), - ("J", float64), - ("type", int64), - ("nx", float64), - ("ny", float64), - ("nz", float64), - ("N_tally", int64), - ("tally_IDs", int64, (Nmax_tally,)), - ("moving", bool_), - ("N_move", int64), - ("move_time_grid", float64, (Nmax_move + 1,)), - ("move_translations", float64, (Nmax_move + 1, 3)), - ("move_velocities", float64, (Nmax_move, 3)), - ] - ) - - -# ============================================================================== -# Cell -# ============================================================================== - - -def make_type_cell(input_deck): - global cell - - # Maximum number tallies - Nmax_tally = 0 - for cell in input_deck.cells: - Nmax_tally = max(Nmax_tally, len(cell.tally_IDs)) - - cell = into_dtype( - [ - ("ID", int64), - # Surface IDs - ("N_surface", int64), - ("surface_data_idx", int64), - # Region RPN tokens - ("N_region", int64), - ("region_data_idx", int64), - # Fill status - ("fill_type", int64), - ("fill_ID", int64), - ("fill_translated", bool_), - ("fill_rotated", bool_), - # Cell tally - ("N_tally", int64), - ("tally_IDs", int64, (Nmax_tally,)), - # Local coordinate modifier - ("translation", float64, (3,)), - ("rotation", float64, (3,)), - ] - ) - - -# ============================================================================== -# Universe -# ============================================================================== - - -universe = into_dtype( - [ - ("ID", int64), - # Cell IDs - ("N_cell", int64), - ("cell_data_idx", int64), - ] -) - - -# ============================================================================== -# Lattice -# ============================================================================== - - -def make_type_lattice(input_deck): - global lattice - - # Max dimensional grids - Nmax_x = 0 - Nmax_y = 0 - Nmax_z = 0 - for card in input_deck.lattices: - Nmax_x = max(Nmax_x, card.Nx) - Nmax_y = max(Nmax_y, card.Ny) - Nmax_z = max(Nmax_z, card.Nz) - - lattice = into_dtype( - [ - ("x0", float64), - ("dx", float64), - ("Nx", int64), - ("y0", float64), - ("dy", float64), - ("Ny", int64), - ("z0", float64), - ("dz", float64), - ("Nz", int64), - ("t0", float64), - ("dt", float64), - ("Nt", int64), - ("universe_IDs", int64, (Nmax_x, Nmax_y, Nmax_z)), - ] - ) - - -# ============================================================================== -# Source -# ============================================================================== - - -def make_type_source(input_deck): - global source - - # Get modes - mode_CE = input_deck.setting["mode_CE"] - mode_MG = input_deck.setting["mode_MG"] - - # Get energy data size - if mode_CE: - G = 1 - # Maximum number of data point in energy pdf - Nmax_E = max([source.energy.shape[1] for source in input_deck.sources]) - if mode_MG: - G = input_deck.materials[0].G - Nmax_E = 2 - - # General data - struct = [ - ("ID", int64), - ("box", bool_), - ("isotropic", bool_), - ("white", bool_), - ("x", float64), - ("y", float64), - ("z", float64), - ("box_x", float64, (2,)), - ("box_y", float64, (2,)), - ("box_z", float64, (2,)), - ("ux", float64), - ("uy", float64), - ("uz", float64), - ("white_x", float64), - ("white_y", float64), - ("white_z", float64), - ("time", float64, (2,)), - ("prob", float64), - ] - - # MG data - struct += [ - ("group", float64, (G,)), - ] - - # CE data - struct += [ - ("energy", float64, (2, Nmax_E)), - ] - - source = into_dtype(struct) - - -# ============================================================================== -# Tallies -# ============================================================================== - - -def dd_meshtally(input_deck): - # find DD mesh index of subdomain - d_idx = input_deck.technique["dd_idx"] # subdomain index - d_Nx = input_deck.technique["dd_mesh"]["x"].size - 1 - d_Ny = input_deck.technique["dd_mesh"]["y"].size - 1 - d_Nz = input_deck.technique["dd_mesh"]["z"].size - 1 - zmesh_idx = d_idx // (d_Nx * d_Ny) - ymesh_idx = (d_idx % (d_Nx * d_Ny)) // d_Nx - xmesh_idx = d_idx % d_Nx - - # find spatial boundaries of subdomain - xn = input_deck.technique["dd_mesh"]["x"][xmesh_idx] - xp = input_deck.technique["dd_mesh"]["x"][xmesh_idx + 1] - yn = input_deck.technique["dd_mesh"]["y"][ymesh_idx] - yp = input_deck.technique["dd_mesh"]["y"][ymesh_idx + 1] - zn = input_deck.technique["dd_mesh"]["z"][zmesh_idx] - zp = input_deck.technique["dd_mesh"]["z"][zmesh_idx + 1] - - # Maximum numbers of mesh and filter grids and scores - Nx = 2 - Ny = 2 - Nz = 2 - for card in input_deck.mesh_tallies: - # find boundary indices in tally mesh - mesh_xn = int(np.where(card.x == xn)[0]) - mesh_xp = int(np.where(card.x == xp)[0]) + 1 - mesh_yn = int(np.where(card.y == yn)[0]) - mesh_yp = int(np.where(card.y == yp)[0]) + 1 - mesh_zn = int(np.where(card.z == zn)[0]) - mesh_zp = int(np.where(card.z == zp)[0]) + 1 - - # adjust Nmax numbers - new_x = card.x[mesh_xn:mesh_xp] - new_y = card.y[mesh_yn:mesh_yp] - new_z = card.z[mesh_zn:mesh_zp] - Nx = max(Nx, len(new_x)) - Ny = max(Ny, len(new_y)) - Nz = max(Nz, len(new_z)) - - # ensure all subdomains have equivalent tally sizes - # (this is necessary for domain decomp to function on GPUs) - Nx = MPI.COMM_WORLD.allreduce(Nx, MPI.MAX) - Ny = MPI.COMM_WORLD.allreduce(Ny, MPI.MAX) - Nz = MPI.COMM_WORLD.allreduce(Nz, MPI.MAX) - return Nx, Ny, Nz - - -def make_type_mesh_tally(input_deck): - global mesh_tally - struct = [] - - # Maximum numbers of mesh and filter grids and scores - Nmax_x = 2 - Nmax_y = 2 - Nmax_z = 2 - Nmax_t = 2 - Nmax_mu = 2 - Nmax_azi = 2 - Nmax_g = 2 - Nmax_score = 1 - for card in input_deck.mesh_tallies: - Nmax_x = max(Nmax_x, len(card.x)) - Nmax_y = max(Nmax_y, len(card.y)) - Nmax_z = max(Nmax_z, len(card.z)) - Nmax_t = max(Nmax_t, len(card.t)) - Nmax_mu = max(Nmax_mu, len(card.mu)) - Nmax_azi = max(Nmax_azi, len(card.azi)) - Nmax_g = max(Nmax_g, len(card.g)) - Nmax_score = max(Nmax_score, len(card.scores)) - - # reduce tally sizes for subdomains - if input_deck.technique["domain_decomposition"]: - Nmax_x, Nmax_y, Nmax_z = dd_meshtally(input_deck) - - # Set the filter - filter_ = into_dtype( - [ - ("x", float64, (Nmax_x,)), - ("y", float64, (Nmax_y,)), - ("z", float64, (Nmax_z,)), - ("t", float64, (Nmax_t,)), - ("mu", float64, (Nmax_mu,)), - ("azi", float64, (Nmax_azi,)), - ("g", float64, (Nmax_g,)), - ("Nx", int64), - ("Ny", int64), - ("Nz", int64), - ("Nt", int64), - ("Nmu", int64), - ("N_azi", int64), - ("Ng", int64), - ] - ) - struct += [("filter", filter_)] - - # Tally strides - stride = into_dtype( - [ - ("tally", int64), - ("sensitivity", int64), - ("mu", int64), - ("azi", int64), - ("g", int64), - ("t", int64), - ("x", int64), - ("y", int64), - ("z", int64), - ] - ) - struct += [("stride", stride)] - - # Total number of bins - struct += [("N_bin", int64)] - - # Scores - struct += [("N_score", int64), ("scores", int64, (Nmax_score,))] - - # Make tally structure - mesh_tally = into_dtype(struct) - - -def make_type_surface_tally(input_deck): - global surface_tally - struct = [] - - # Maximum number of grid for each mesh coordinate and filter - Nmax_t = 2 - Nmax_mu = 2 - Nmax_azi = 2 - Nmax_g = 2 - Nmax_score = 1 - - # IDK if this is right, but I changed this to input_deck.surface_tallies - for card in input_deck.surface_tallies: - Nmax_t = max(Nmax_t, len(card.t)) - Nmax_mu = max(Nmax_mu, len(card.mu)) - Nmax_azi = max(Nmax_azi, len(card.azi)) - Nmax_g = max(Nmax_g, len(card.g)) - Nmax_score = max(Nmax_score, len(card.scores)) - - # Set the filter - filter_ = into_dtype( - [ - ("surface_ID", int64), - ("t", float64, (Nmax_t,)), - ("mu", float64, (Nmax_mu,)), - ("azi", float64, (Nmax_azi,)), - ("g", float64, (Nmax_g,)), - ] - ) - struct = [("filter", filter_)] - - # Tally strides - stride = into_dtype( - [ - ("tally", int64), - ("sensitivity", int64), - ("mu", int64), - ("azi", int64), - ("g", int64), - ("t", int64), - ] - ) - struct += [("stride", stride)] - - # Total number of bins - struct += [("N_bin", int64)] - - # Scores - struct += [("N_score", int64), ("scores", int64, (Nmax_score,))] - - # Make tally structure - surface_tally = into_dtype(struct) - - -def make_type_cell_tally(input_deck): - global cell_tally - struct = [] - - # Maximum number of grid for each mesh coordinate and filter - Nmax_t = 2 - Nmax_mu = 2 - Nmax_azi = 2 - Nmax_g = 2 - Nmax_score = 1 - - for card in input_deck.cell_tallies: - Nmax_t = max(Nmax_t, len(card.t)) - Nmax_mu = max(Nmax_mu, len(card.mu)) - Nmax_azi = max(Nmax_azi, len(card.azi)) - Nmax_g = max(Nmax_g, len(card.g)) - Nmax_score = max(Nmax_score, len(card.scores)) - - # Set the filter - filter_ = into_dtype( - [ - ("cell_ID", int64), - ("t", float64, (Nmax_t,)), - ("mu", float64, (Nmax_mu,)), - ("azi", float64, (Nmax_azi,)), - ("g", float64, (Nmax_g,)), - ("Nt", int64), - ("Ng", int64), - ] - ) - struct = [("filter", filter_)] - - # Tally strides - stride = into_dtype( - [ - ("tally", int64), - ("sensitivity", int64), - ("mu", int64), - ("azi", int64), - ("g", int64), - ("t", int64), - ] - ) - struct += [("stride", stride)] - - # Total number of bins - struct += [("N_bin", int64)] - - # Scores - struct += [("N_score", int64), ("scores", int64, (Nmax_score,))] - - # Make tally structure - cell_tally = into_dtype(struct) - - -def make_type_cs_tally(input_deck): - global cs_tally - struct = [] - - # Maximum numbers of mesh and filter grids and scores - Nmax_x = 2 - Nmax_y = 2 - Nmax_z = 2 - Nmax_t = 2 - Nmax_mu = 2 - Nmax_azi = 2 - Nmax_g = 2 - Nmax_score = 1 - N_cs_centers = 1 - for card in input_deck.cs_tallies: - Nmax_x = max(Nmax_x, len(card.x)) - Nmax_y = max(Nmax_y, len(card.y)) - Nmax_z = max(Nmax_z, len(card.z)) - Nmax_t = max(Nmax_t, len(card.t)) - Nmax_mu = max(Nmax_mu, len(card.mu)) - Nmax_azi = max(Nmax_azi, len(card.azi)) - Nmax_g = max(Nmax_g, len(card.g)) - Nmax_score = max(Nmax_score, len(card.scores)) - N_cs_centers = card.N_cs_bins[0] - - # # reduce tally sizes for subdomains - # if input_deck.technique["domain_decomposition"]: - # Nmax_x, Nmax_y, Nmax_z = dd_meshtally(input_deck) - - # Set the filter - filter_ = into_dtype( - [ - ("N_cs_bins", int), - ("cs_bin_size", float64, (2,)), - ( - "cs_centers", - float64, - ( - 2, - N_cs_centers, - ), - ), - ("cs_S", float64, (N_cs_centers, (Nmax_x - 1) * (Nmax_y - 1))), - ("cs_reconstruction", float64, ((Nmax_y - 1), (Nmax_x - 1))), - ("x", float64, (Nmax_x,)), - ("y", float64, (Nmax_y,)), - ("z", float64, (Nmax_z,)), - ("t", float64, (Nmax_t,)), - ("mu", float64, (Nmax_mu,)), - ("azi", float64, (Nmax_azi,)), - ("g", float64, (Nmax_g,)), - ] - ) - - struct += [("filter", filter_)] - - # Tally strides - stride = into_dtype( - [ - ("tally", int64), - ("sensitivity", int64), - ("mu", int64), - ("azi", int64), - ("g", int64), - ("t", int64), - ("x", int64), - ("y", int64), - ("z", int64), - # ("N_cs_bins", int64), # TODO: get rid of this line? - ] - ) - struct += [("stride", stride)] - - # Total number of bins (will be used for the reconstruction) - # TODO: Might be able to get rid of this (just get N_bin from the mesh) - struct += [("N_bin", int64)] - - # Number of compressed sensing bins - # struct += [("N_cs_bins", int64)] - - # Scores - struct += [("N_score", int64), ("scores", int64, (Nmax_score,))] - - # Make tally structure - cs_tally = into_dtype(struct) - - -# ============================================================================== -# Setting -# ============================================================================== - - -def make_type_setting(deck): - global setting - - card = deck.setting - struct = [ - # Basic MC simulation parameters - ("N_particle", uint64), - ("N_batch", uint64), - ("rng_seed", uint64), - ("time_boundary", float64), - # Physics flags - ("mode_MG", bool_), - ("mode_CE", bool_), - # Misc. - ("progress_bar", bool_), - ("output_name", str_), - ("save_input_deck", bool_), - # Eigenvalue mode - ("mode_eigenvalue", bool_), - ("k_init", float64), - ("N_inactive", uint64), - ("N_active", uint64), - ("N_cycle", uint64), - ("save_particle", bool_), - ("gyration_radius", bool_), - ("gyration_radius_type", uint64), - # Time census - ("N_census", uint64), - ("census_time", float64, (card["N_census"],)), - ("census_based_tally", bool_), - ("census_tally_frequency", int64), - # Particle source file - ("source_file", bool_), - ("source_file_name", str_), - # Initial condition source file - ("IC_file", bool_), - ("IC_file_name", str_), - ("N_precursor", uint64), - ] - - # Finalize setting type - setting = into_dtype(struct) - - -# ============================================================================== -# Technique -# ============================================================================== - -iqmc_score_list = ( - "flux", - "effective-scattering", - "effective-fission", - "source-x", - "source-y", - "source-z", - "fission-power", - "fission-source", -) - - -def make_type_technique(input_deck): - global technique - - # Get sizes - N_particle = input_deck.setting["N_particle"] - - # Get modes - mode_MG = input_deck.setting["mode_MG"] - - # Get card - card = input_deck.technique - - # Number of groups - if mode_MG: - G = input_deck.materials[0].G - else: - G = 1 - - # Technique flags - struct = [ - ("weighted_emission", bool_), - ("implicit_capture", bool_), - ("population_control", bool_), - ("weight_window", bool_), - ("weight_roulette", bool_), - ("iQMC", bool_), - ("IC_generator", bool_), - ("branchless_collision", bool_), - ("domain_decomposition", bool_), - ("uq", bool_), - ] - - # ========================================================================= - # Population control - # ========================================================================= - - struct += [("pct", int64), ("pc_factor", float64)] - - # ========================================================================= - # domain decomp - # ========================================================================= - # Mesh - mesh, Nx, Ny, Nz, Nt, Nmu, N_azi, Ng = make_type_mesh(card["dd_mesh"]) - struct += [("dd_mesh", mesh)] - struct += [("dd_xlen", int64)] - struct += [("dd_ylen", int64)] - struct += [("dd_zlen", int64)] - struct += [("dd_xsum", int64)] - struct += [("dd_ysum", int64)] - struct += [("dd_zsum", int64)] - struct += [("dd_idx", int64)] - struct += [("dd_sent", int64)] - struct += [("dd_work_ratio", int64, (len(card["dd_work_ratio"]),))] - struct += [("dd_exchange_rate", int64)] - struct += [("dd_exchange_rate_padding", int64)] - struct += [("dd_xp_neigh", int64, (len(card["dd_xp_neigh"]),))] - struct += [("dd_xn_neigh", int64, (len(card["dd_xn_neigh"]),))] - struct += [("dd_yp_neigh", int64, (len(card["dd_yp_neigh"]),))] - struct += [("dd_yn_neigh", int64, (len(card["dd_yn_neigh"]),))] - struct += [("dd_zp_neigh", int64, (len(card["dd_zp_neigh"]),))] - struct += [("dd_zn_neigh", int64, (len(card["dd_zn_neigh"]),))] - - # ========================================================================= - # Weight window - # ========================================================================= - - # ========================================================================= - # Weight window - # ========================================================================= - ww_list = [] - - # Mesh - mesh, Nx, Ny, Nz, Nt, Nmu, N_azi, Ng = make_type_mesh(card["ww"]["mesh"]) - ww_list += [("mesh", mesh)] - ww_list += [("auto", int64)] - ww_list += [("width", float64)] - ww_list += [("epsilon", float64, (3,))] - ww_list += [("center", float64, (Nt, Nx, Ny, Nz))] - ww_list += [("save", bool_)] - ww_list += [("tally_idx", int64)] - if card["weight_window"]: - if card["ww"]["save"]: - if card["ww"]["auto"] == WW_PREVIOUS: - ww_list += [("phi_previous", float64, (Nt, Nx, Ny, Nz))] - struct += [("ww", into_dtype(ww_list))] - - # ========================================================================= - # Weight Roulette - # ========================================================================= - - # Constants - struct += [("wr_threshold", float64), ("wr_survive", float64)] - - # ========================================================================= - # Quasi Monte Carlo - # ========================================================================= - iqmc_list = [] - - # Mesh (for qmc source tallies) - if card["iQMC"]: - mesh, Nx, Ny, Nz, Nt, Nmu, N_azi = make_type_mesh_(card["iqmc"]["mesh"]) - Ng = G - N_dim = 6 # group, x, y, z, mu, phi - else: - Nx = Ny = Nz = Nt = Nmu = N_azi = N_particle = Ng = N_dim = 0 - - iqmc_list += [("mesh", mesh)] - - # make low-discprenecy sequence array - work_size = get_work_size(N_particle) - iqmc_list += [("samples", float64, (work_size, N_dim))] - # make global arrays - iqmc_list += [("fixed_source", float64, (Ng, Nt, Nx, Ny, Nz))] - iqmc_list += [("material_idx", int64, (Nt, Nx, Ny, Nz))] - iqmc_list += [("source", float64, (Ng, Nt, Nx, Ny, Nz))] - total_size = (Ng * Nt * Nx * Ny * Nz) * card["iqmc"]["krylov_vector_size"] - iqmc_list += [(("total_source"), float64, (total_size,))] - - # Make scores - scores_shapes = [ - ["flux", (Ng, Nt, Nx, Ny, Nz)], - ["effective-scattering", (Ng, Nt, Nx, Ny, Nz)], - ["effective-fission", (Ng, Nt, Nx, Ny, Nz)], - ["source-x", (Ng, Nt, Nx, Ny, Nz)], - ["source-y", (Ng, Nt, Nx, Ny, Nz)], - ["source-z", (Ng, Nt, Nx, Ny, Nz)], - ["fission-power", (Ng, Nt, Nx, Ny, Nz)], # SigmaF*phi - ["fission-source", (1,)], # nu*SigmaF*phi - ] - - if card["iQMC"]: - if setting["mode_eigenvalue"]: - card["iqmc"]["score_list"]["fission-source"] = True - - # Add score flags to structure - score_list = [] - for i in range(len(scores_shapes)): - name = scores_shapes[i][0] - score_list += [(name, bool_)] - score_list = into_dtype(score_list) - iqmc_list += [("score_list", score_list)] - - # Add scores to structure - scores_struct = [] - for i in range(len(scores_shapes)): - name = scores_shapes[i][0] - shape = scores_shapes[i][1] - if not card["iqmc"]["score_list"][name]: - shape = (0,) * len(shape) - scores_struct += [(name, make_type_score(shape))] - # TODO: make outter effective fission size zero if not eigenmode - # (causes problems with numba) - scores_struct += [("effective-fission-outter", float64, (Ng, Nt, Nx, Ny, Nz))] - scores = into_dtype(scores_struct) - iqmc_list += [("score", scores)] - - # Constants - iqmc_list += [ - ("tol", float64), - ("w_min", float64), - ("residual", float64), - ("iteration_count", int64), - ("iterations_max", int64), - ("krylov_restart", int64), - ("sweep_count", int64), - ("fixed_source_solver", str_), - ("sample_method", str_), - ("mode", str_), - ] - - struct += [("iqmc", into_dtype(iqmc_list))] - - # ========================================================================= - # IC generator - # ========================================================================= - - # Create bank types - # We need local banks to ensure reproducibility regardless of # of MPIs - # TODO: Having smaller bank buffer (~N_target/MPI_size) and even smaller - # local bank would be more efficient. - if card["IC_generator"]: - Nn = int(card["IC_N_neutron"] * 1.2) - Np = int(card["IC_N_precursor"] * 1.2) - Nn_local = Nn - Np_local = Np - else: - Nn = 0 - Np = 0 - Nn_local = 0 - Np_local = 0 - bank_neutron = particle_bank(Nn) - bank_neutron_local = particle_bank(Nn_local) - bank_precursor = precursor_bank(Np) - bank_precursor_local = precursor_bank(Np_local) - - # The parameters - struct += [ - ("IC_N_neutron", int64), - ("IC_N_precursor", int64), - ("IC_neutron_density", float64), - ("IC_neutron_density_max", float64), - ("IC_precursor_density", float64), - ("IC_precursor_density_max", float64), - ("IC_bank_neutron_local", bank_neutron_local), - ("IC_bank_precursor_local", bank_precursor_local), - ("IC_bank_neutron", bank_neutron), - ("IC_bank_precursor", bank_precursor), - ("IC_fission_score", float64, (1,)), - ("IC_fission", float64), - ] - - # ========================================================================= - # Variance Deconvolution - # ========================================================================= - - struct += [("uq_", uq)] - - # Finalize technique type - technique = into_dtype(struct) - - -# UQ -def make_type_uq(input_deck): - global uq, uq_nuc, uq_mat - - # def make_type_parameter(shape): - # return into_dtype( - # [ - # ("tag", str_), # nuclides, materials, surfaces, sources - # ("ID", int64), - # ("key", str_), - # ("mean", float64, shape), - # ("delta", float64, shape), - # ("distribution", str_), - # ("rng_seed", uint64), - # ] - # ) - - def make_type_parameter(G, J, decay=False): - # Fields are things that can have deltas - struct = [ - ("speed", float64, (G,)), - ("capture", float64, (G,)), - ("scatter", float64, (G, G)), - ("fission", float64, (G,)), - ("nu_s", float64, (G,)), - ("nu_p", float64, (G,)), - ("nu_d", float64, (G, J)), - ("chi_p", float64, (G, G)), - ] - struct += [("decay", float64, (J,)), ("chi_d", float64, (J, G))] - return into_dtype(struct) - - # Size numbers - G = input_deck.materials[0].G - J = input_deck.materials[0].J - - # UQ deck - uq_deck = input_deck.uq_deltas - - uq_nuc = make_type_parameter(G, J, True) - uq_mat = make_type_parameter(G, J) - - flags = into_dtype( - [ - ("speed", bool_), - ("decay", bool_), - ("total", bool_), - ("capture", bool_), - ("scatter", bool_), - ("fission", bool_), - ("nu_s", bool_), - ("nu_f", bool_), - ("nu_p", bool_), - ("nu_d", bool_), - ("chi_s", bool_), - ("chi_p", bool_), - ("chi_d", bool_), - ] - ) - info = into_dtype([("distribution", str_), ("ID", int64), ("rng_seed", uint64)]) - - container = into_dtype( - [("mean", uq_nuc), ("delta", uq_mat), ("flags", flags), ("info", info)] - ) - - N_nuclide = len(uq_deck["nuclides"]) - N_material = len(uq_deck["materials"]) - uq = into_dtype( - [("nuclides", container, (N_nuclide,)), ("materials", container, (N_material,))] - ) - - -def make_type_dd_turnstile_event(input_deck): - global dd_turnstile_event, dd_turnstile_event_mpi - dd_turnstile_event = into_dtype( - [ - ("busy_delta", int32), - ("send_delta", int32), - ] - ) - dd_turnstile_event_mpi = from_numpy_dtype(dd_turnstile_event) - dd_turnstile_event_mpi.Commit() - - -def make_type_domain_decomp(input_deck): - global domain_decomp - # Domain banks if needed - if input_deck.technique["domain_decomposition"]: - bank_size = input_deck.technique["dd_exchange_rate"] - bank_size += input_deck.technique["dd_exchange_rate_padding"] - bank_domain_xp = particle_bank(bank_size) - bank_domain_xn = particle_bank(bank_size) - bank_domain_yp = particle_bank(bank_size) - bank_domain_yn = particle_bank(bank_size) - bank_domain_zp = particle_bank(bank_size) - bank_domain_zn = particle_bank(bank_size) - else: - bank_domain_xp = particle_bank(0) - bank_domain_xn = particle_bank(0) - bank_domain_yp = particle_bank(0) - bank_domain_yn = particle_bank(0) - bank_domain_zp = particle_bank(0) - bank_domain_zn = particle_bank(0) - - domain_decomp = into_dtype( - [ - # Info tracked in all ranks - ("bank_xp", bank_domain_xp), - ("bank_xn", bank_domain_xn), - ("bank_yp", bank_domain_yp), - ("bank_yn", bank_domain_yn), - ("bank_zp", bank_domain_zp), - ("bank_zn", bank_domain_zn), - ("send_count", int64), # Number of particles sent - ("recv_count", int64), # Number of particles recv'd - ("rank_busy", bool_), # True if the rank currently has particles to process - ( - "work_done", - int64, - ), # Whether or not there is any outstanding work across any ranks - # Info tracked in "leader" rank zero - ( - "send_total", - int64, - ), # The total number of particles sent but not yet recv'd - ("busy_total", int64), # The total number of busy ranks - ] - ) - - -param_names = ["tag", "ID", "key", "mean", "delta", "distribution", "rng_seed"] - - -# ============================================================================== -# GPU Metadata -# ============================================================================== - - -def make_type_gpu_meta(): - global gpu_meta - - gpu_meta = into_dtype( - [ - ("state_pointer", uintp), - ("source_program_pointer", uintp), - ("precursor_program_pointer", uintp), - ("global_pointer", uintp), - ("tally_pointer", uintp), - ] - ) - - -# ============================================================================== -# Global -# ============================================================================== - - -def make_type_global(input_deck): - global global_, global_size - - # Get modes - mode_CE = input_deck.setting["mode_CE"] - mode_MG = input_deck.setting["mode_MG"] - - # Numbers of objects - N_nuclide = len(input_deck.nuclides) - N_material = len(input_deck.materials) - N_surface = len(input_deck.surfaces) - N_cell = len(input_deck.cells) - N_source = len(input_deck.sources) - N_universe = len(input_deck.universes) - N_lattice = len(input_deck.lattices) - N_mesh_tally = len(input_deck.mesh_tallies) - N_surface_tally = len(input_deck.surface_tallies) - N_cell_tally = len(input_deck.cell_tallies) - N_cs_tally = len(input_deck.cs_tallies) - - # Cell data sizes - N_cell_surface = sum([len(x.surface_IDs) for x in input_deck.cells]) - N_cell_region = sum([len(x._region_RPN) for x in input_deck.cells]) - - # Universe data sizes - N_universe_cell = sum([len(x.cell_IDs) for x in input_deck.universes]) - - # Simulation parameters - N_particle = input_deck.setting["N_particle"] - N_precursor = input_deck.setting["N_precursor"] - N_cycle = input_deck.setting["N_cycle"] - - # Particle bank buffers - bank_active_buff = input_deck.setting["bank_active_buff"] - bank_census_buff = input_deck.setting["bank_census_buff"] - bank_source_buff = input_deck.setting["bank_source_buff"] - bank_future_buff = input_deck.setting["bank_future_buff"] - - # Number of precursor groups - if mode_MG: - J = input_deck.materials[0].J - if mode_CE: - J = 6 - - # Number of work - N_work = math.ceil(N_particle / MPI.COMM_WORLD.Get_size()) - N_work_precursor = math.ceil(N_precursor / MPI.COMM_WORLD.Get_size()) - - # Particle bank types - bank_active = particle_bank(1 + bank_active_buff) - if input_deck.setting["mode_eigenvalue"] or input_deck.setting["N_census"] > 1: - bank_census = particle_bank(int((1 + bank_census_buff) * N_work)) - bank_source = particle_bank(int((1 + bank_source_buff) * N_work)) - bank_future = particle_bank(int((1 + bank_future_buff) * N_work)) - else: - bank_census = particle_bank(0) - bank_source = particle_bank(0) - bank_future = particle_bank(0) - bank_precursor = precursor_bank(0) - - # iQMC bank adjustment - if input_deck.technique["iQMC"]: - bank_source = particle_bank(N_work) - if input_deck.setting["mode_eigenvalue"]: - bank_census = particle_bank(0) - bank_future = particle_bank(0) - - # Source and IC files bank adjustments - if not input_deck.setting["mode_eigenvalue"]: - if input_deck.setting["source_file"]: - bank_source = particle_bank(N_work) - if input_deck.setting["IC_file"]: - bank_source = particle_bank(N_work) - bank_precursor = precursor_bank(N_precursor) - - if ( - input_deck.setting["source_file"] and not input_deck.setting["mode_eigenvalue"] - ) or input_deck.technique["iQMC"]: - bank_source = particle_bank(N_work) - - global_ = into_dtype( - [ - ("nuclides", nuclide, (N_nuclide,)), - ("materials", material, (N_material,)), - ("surfaces", surface, (N_surface,)), - # Cells - ("cells", cell, (N_cell,)), - ("cells_data_surface", int64, (N_cell_surface,)), - ("cells_data_region", int64, (N_cell_region,)), - # Universes - ("universes", universe, (N_universe,)), - ("universes_data_cell", int64, (N_universe_cell,)), - ("lattices", lattice, (N_lattice,)), - ("sources", source, (N_source,)), - ("mesh_tallies", mesh_tally, (N_mesh_tally,)), - ("surface_tallies", surface_tally, (N_surface_tally,)), - ("cell_tallies", cell_tally, (N_cell_tally,)), - ("cs_tallies", cs_tally, (N_cs_tally,)), - ("setting", setting), - ("technique", technique), - ("domain_decomp", domain_decomp), - ("bank_active", bank_active), - ("bank_census", bank_census), - ("bank_source", bank_source), - ("bank_future", bank_future), - ("bank_precursor", bank_precursor), - ("rng_seed_base", uint64), - ("rng_seed", uint64), - ("rng_stride", int64), - ("dd_idx", int64), - ("dd_N_local_source", int64), - ("dd_local_rank", int64), - ("k_eff", float64), - ("k_cycle", float64, (N_cycle,)), - ("k_avg", float64), - ("k_sdv", float64), - ("n_avg", float64), # Neutron density - ("n_sdv", float64), - ("n_max", float64), - ("C_avg", float64), # Precursor density - ("C_sdv", float64), - ("C_max", float64), - ("k_avg_running", float64), - ("k_sdv_running", float64), - ("gyration_radius", float64, (N_cycle,)), - ("idx_cycle", int64), - ("cycle_active", bool_), - ("eigenvalue_tally_nuSigmaF", float64, (1,)), - ("eigenvalue_tally_n", float64, (1,)), - ("eigenvalue_tally_C", float64, (1,)), - ("idx_census", int64), - ("idx_batch", int64), - ("mpi_size", int64), - ("mpi_rank", int64), - ("mpi_master", bool_), - ("mpi_work_start", int64), - ("mpi_work_size", int64), - ("mpi_work_size_total", int64), - ("mpi_work_start_precursor", int64), - ("mpi_work_size_precursor", int64), - ("mpi_work_size_total_precursor", int64), - ("runtime_total", float64), - ("runtime_preparation", float64), - ("runtime_simulation", float64), - ("runtime_output", float64), - ("runtime_bank_management", float64), - ("precursor_strength", float64), - ("mpi_work_iter", int64, (1,)), - ("gpu_meta", gpu_meta), - ("source_seed", uint64), - ] - ) - - # GLobal type - - global_size = global_.itemsize - - -# ============================================================================== -# Util -# ============================================================================== - - -def make_type_score(shape): - return into_dtype( - [ - ("bin", float64, shape), - ("mean", float64, shape), - ("sdev", float64, shape), - ] - ) - - -def get_work_size(N_particle): - size = MPI.COMM_WORLD.Get_size() - rank = MPI.COMM_WORLD.Get_rank() - # Evenly distribute work - work_size = math.floor(N_particle / size) - # Count reminder - rem = N_particle % size - # Assign reminder and update starting index - if rank < rem: - work_size += 1 - return work_size - - -def make_type_mesh(card): - Nx = len(card["x"]) - 1 - Ny = len(card["y"]) - 1 - Nz = len(card["z"]) - 1 - Nt = len(card["t"]) - 1 - Nmu = len(card["mu"]) - 1 - N_azi = len(card["azi"]) - 1 - Ng = len(card["g"]) - 1 - return ( - into_dtype( - [ - ("x", float64, (Nx + 1,)), - ("y", float64, (Ny + 1,)), - ("z", float64, (Nz + 1,)), - ("t", float64, (Nt + 1,)), - ("mu", float64, (Nmu + 1,)), - ("azi", float64, (N_azi + 1,)), - ("g", float64, (Ng + 1,)), - ("Nx", int64), - ("Ny", int64), - ("Nz", int64), - ("Nt", int64), - ("Nmu", int64), - ("N_azi", int64), - ("Ng", int64), - ] - ), - Nx, - Ny, - Nz, - Nt, - Nmu, - N_azi, - Ng, - ) - - -def make_type_mesh_(card): - Nx = len(card["x"]) - 1 - Ny = len(card["y"]) - 1 - Nz = len(card["z"]) - 1 - Nt = len(card["t"]) - 1 - Nmu = len(card["mu"]) - 1 - N_azi = len(card["azi"]) - 1 - return ( - into_dtype( - [ - ("x", float64, (Nx + 1,)), - ("y", float64, (Ny + 1,)), - ("z", float64, (Nz + 1,)), - ("t", float64, (Nt + 1,)), - ("mu", float64, (Nmu + 1,)), - ("azi", float64, (N_azi + 1,)), - ("Nx", int64), - ("Ny", int64), - ("Nz", int64), - ("Nt", int64), - ("Nmu", int64), - ("N_azi", int64), - ] - ), - Nx, - Ny, - Nz, - Nt, - Nmu, - N_azi, - ) - - -mesh_names = ["x", "y", "z", "t", "mu", "azi", "g"] diff --git a/mcdc/util.py b/mcdc/util.py new file mode 100644 index 000000000..445967f23 --- /dev/null +++ b/mcdc/util.py @@ -0,0 +1,26 @@ +def flatten(lst): + """ + Recursively flattens a nested list of arbitrary depth. + + Parameters + ---------- + lst : list + A (possibly nested) list, e.g. [1, [2, [3, 4]], 5]. + + Yields + ------ + element + Each non-list element contained in `lst`, in depth-first order. + + Examples + -------- + >>> list(flatten([1, [2, [3, 4]], 5])) + [1, 2, 3, 4, 5] + """ + for item in lst: + if isinstance(item, list): + # If the current item is a list, recursively flatten it + yield from flatten(item) + else: + # Otherwise, yield the item directly + yield item diff --git a/pyproject.toml b/pyproject.toml index 335257fda..3a96735ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,69 +5,87 @@ build-backend = "hatchling.build" [project] name = "mcdc" version = "0.12.0" + authors = [ - { name="Ilham Variansyah", email="variansi@oregonstate.edu" }, - { name="Sam Pasmann", email="spasmann@nd.edu" }, - { name="Joanna Morgan", email="morgajoa@oregonstate.edu" }, - { name="Kayla Clements", email="clemekay@oregonstate.edu" }, - { name="Braxton Cuneo", email="bcuneo@seattleu.edu" }, - { name="Caleb Shaw"}, - { name="Rohan Pankaj"}, - { name="Alexander Mote"}, - { name="Ethan Lame"}, - { name="Benjamin Whewell"}, - { name="Ryan G. McClarren"}, - { name="Todd S. Palmer"}, - { name="Lizhong Chen"}, - { name="Dmitriy Y. Anistratov"}, - { name="C. T. Kelley"}, - { name="Camille J. Palmer"}, - { name="Kyle E. Niemeyer"}, + { name = "Ilham Variansyah", email = "variansi@oregonstate.edu" }, + { name = "Sam Pasmann", email = "spasmann@nd.edu" }, + { name = "Joanna Morgan", email = "morgajoa@oregonstate.edu" }, + { name = "Kayla Clements", email = "clemekay@oregonstate.edu" }, + { name = "Braxton Cuneo", email = "bcuneo@seattleu.edu" }, + { name = "Caleb Shaw" }, + { name = "Rohan Pankaj" }, + { name = "Alexander Mote" }, + { name = "Ethan Lame" }, + { name = "Benjamin Whewell" }, + { name = "Ryan G. McClarren" }, + { name = "Todd S. Palmer" }, + { name = "Lizhong Chen" }, + { name = "Dmitriy Y. Anistratov" }, + { name = "C. T. Kelley" }, + { name = "Camille J. Palmer" }, + { name = "Kyle E. Niemeyer" }, ] maintainers = [ - { name="Ilham Variansyah", email = "variansi@oregonstate.edu"}, - { name="Braxton Cuneo", email="bcuneo@seattleu.edu" }, - { name="Kayla Clements", email = "clemekay@oregonstate.edu"}, - { name="Joanna Piper Morgan", email = "morgajoa@oregonstate.edu"}, - { name="Kyle E. Niemeyer", email = "kyle.niemeyer@oregonstate.edu"}, + { name = "Ilham Variansyah", email = "variansi@oregonstate.edu" }, + { name = "Braxton Cuneo", email = "bcuneo@seattleu.edu" }, + { name = "Kayla Clements", email = "clemekay@oregonstate.edu" }, + { name = "Joanna Piper Morgan", email = "morgajoa@oregonstate.edu" }, + { name = "Kyle E. Niemeyer", email = "kyle.niemeyer@oregonstate.edu" }, ] description = "MC/DC (Monte Carlo Dynamic Code): a performant, scalable, and machine-portable Python-based Monte Carlo neutron transport package" readme = "README.md" -requires-python = ">=3.9.1, <3.12" -license = {file = "LICENSE"} -keywords = ["Monte Carlo", "nuclear engineering", "neutron transport", "HPC", "GPU", "numba", "mpi4py"] +requires-python = ">=3.9.1,<3.12" +license = { file = "LICENSE" } + +keywords = [ + "Monte Carlo", + "nuclear engineering", + "neutron transport", + "HPC", + "GPU", + "numba", + "mpi4py", +] + classifiers = [ - "Programming Language :: Python :: 3", - 'License :: OSI Approved :: BSD License', - 'Intended Audience :: Science/Research', - 'Typing :: Typed', - 'Natural Language :: English', - 'Operating System :: Unix', - 'Operating System :: MacOS', + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Intended Audience :: Science/Research", + "Typing :: Typed", + "Natural Language :: English", + "Operating System :: Unix", + "Operating System :: MacOS", ] + dependencies = [ - "numba>=0.60.0", - "numpy", - "scipy", - "matplotlib", - "mpi4py>=3.1.4", - "pytest", - "h5py", - "colorama", - "black", - "sympy", - "pre-commit", - "cvxpy" + "numba>=0.60.0", + "numpy>=2.0.0", + "scipy", + "matplotlib", + "mpi4py>=3.1.4", + "h5py", + "colorama", + "sympy", + "cvxpy", ] -[project.optional-dependencies] - docs = ["sphinx==7.2.6", "furo", "sphinx_toolbox"] +[project.optional-dependencies] +docs = [ + "sphinx==7.2.6", + "furo", + "sphinx_toolbox", +] +dev = [ + "black", + "pre-commit", + "pytest", +] [project.urls] -Repository = "https://github.com/CEMeNT-PSAAP/MCDC" Homepage = "https://cement-psaap.github.io/" +Repository = "https://github.com/CEMeNT-PSAAP/MCDC" Documentation = "https://mcdc.readthedocs.io/en/latest/" Issues = "https://github.com/CEMeNT-PSAAP/MCDC/issues" diff --git a/test/regression/.gitignore b/test/regression/.gitignore new file mode 100644 index 000000000..9a22d1d35 --- /dev/null +++ b/test/regression/.gitignore @@ -0,0 +1 @@ +MCDC-regression_test_data diff --git a/test/regression/azurv1/answer.h5 b/test/regression/azurv1/answer.h5 index ba9df9918..86d02ff7d 100644 Binary files a/test/regression/azurv1/answer.h5 and b/test/regression/azurv1/answer.h5 differ diff --git a/test/regression/azurv1/input.py b/test/regression/azurv1/input.py index ea21c2507..7dd883ae8 100644 --- a/test/regression/azurv1/input.py +++ b/test/regression/azurv1/input.py @@ -1,16 +1,15 @@ import numpy as np -from pprint import pprint import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Infinite medium with isotropic plane surface at the center # Based on Ganapol LA-UR-01-1854 (AZURV1 benchmark) # Effective scattering ratio c = 1.1 # Set materials -m = mcdc.material( +m = mcdc.MaterialMG( capture=np.array([1.0 / 3.0]), scatter=np.array([[1.0 / 3.0]]), fission=np.array([1.0 / 3.0]), @@ -18,31 +17,35 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -mcdc.cell(+s1 & -s2, m) +mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic pulse at x=t=0 -mcdc.source(point=[0.0, 0.0, 0.0], isotropic=True, time=[1e-10, 1e-10]) +mcdc.Source( + position=[0.0, 0.0, 0.0], + isotropic=True, + energy_group=0, + time=0.0, +) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(-20.5, 20.5, 202), - t=np.linspace(0.0, 20.0, 21), -) +# Tallies +mesh = mcdc.MeshStructured(x=np.linspace(-20.5, 20.5, 202)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], time=np.linspace(0.0, 20.0, 21)) -# Setting -mcdc.setting(N_particle=100, N_batch=2) +# Settings +mcdc.settings.N_particle = 60 +mcdc.settings.N_batch = 2 # Run mcdc.run() diff --git a/test/regression/azurv1_census/answer.h5 b/test/regression/azurv1_census/answer.h5 index 2f5c6d752..8659f1fe7 100644 Binary files a/test/regression/azurv1_census/answer.h5 and b/test/regression/azurv1_census/answer.h5 differ diff --git a/test/regression/azurv1_census/input.py b/test/regression/azurv1_census/input.py index a9905cedd..edbf918da 100644 --- a/test/regression/azurv1_census/input.py +++ b/test/regression/azurv1_census/input.py @@ -1,16 +1,15 @@ import numpy as np -from pprint import pprint import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Infinite medium with isotropic plane surface at the center # Based on Ganapol LA-UR-01-1854 (AZURV1 benchmark) # Effective scattering ratio c = 1.1 # Set materials -m = mcdc.material( +m = mcdc.MaterialMG( capture=np.array([1.0 / 3.0]), scatter=np.array([[1.0 / 3.0]]), fission=np.array([1.0 / 3.0]), @@ -18,33 +17,41 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -mcdc.cell(+s1 & -s2, m) +mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic pulse at x=t=0 -mcdc.source(point=[0.0, 0.0, 0.0], isotropic=True, time=[1e-10, 1e-10]) +mcdc.Source( + position=[0.0, 0.0, 0.0], + isotropic=True, + energy_group=0, + time=0.0, +) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(-20.5, 20.5, 202), - t=np.linspace(0.0, 20.0, 21), -) +# Tallies +mesh = mcdc.MeshStructured(x=np.linspace(-20.5, 20.5, 202)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], time=np.linspace(0.0, 20.0, 21)) + +# Settings +mcdc.settings.N_particle = 50 +mcdc.settings.N_batch = 2 +mcdc.settings.census_bank_buffer_ratio = 5.0 +mcdc.settings.source_bank_buffer_ratio = 5.0 +mcdc.settings.set_time_census(np.linspace(0.0, 20.0, 21)[1:-1]) -# Setting -mcdc.setting(N_particle=50, census_bank_buff=5, source_bank_buff=5, N_batch=2) -mcdc.time_census(np.linspace(0.0, 20.0, 21)[1:-1]) -mcdc.population_control() +# Tecniques +mcdc.simulation.population_control() # Run mcdc.run() diff --git a/test/regression/azurv1_census_tally/answer.h5 b/test/regression/azurv1_census_tally/answer.h5 index eae59cd17..4a9a790fc 100644 Binary files a/test/regression/azurv1_census_tally/answer.h5 and b/test/regression/azurv1_census_tally/answer.h5 differ diff --git a/test/regression/azurv1_census_tally/input.py b/test/regression/azurv1_census_tally/input.py index 673cc4c41..1a3a1c649 100644 --- a/test/regression/azurv1_census_tally/input.py +++ b/test/regression/azurv1_census_tally/input.py @@ -1,16 +1,15 @@ import numpy as np -from pprint import pprint -import mcdc, mpi4py, h5py +import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Infinite medium with isotropic plane surface at the center # Based on Ganapol LA-UR-01-1854 (AZURV1 benchmark) # Effective scattering ratio c = 1.1 # Set materials -m = mcdc.material( +m = mcdc.MaterialMG( capture=np.array([1.0 / 3.0]), scatter=np.array([[1.0 / 3.0]]), fission=np.array([1.0 / 3.0]), @@ -18,34 +17,44 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -mcdc.cell(+s1 & -s2, m) +mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic pulse at x=t=0 -mcdc.source(point=[0.0, 0.0, 0.0], isotropic=True, time=[1e-10, 1e-10]) +mcdc.Source( + position=[0.0, 0.0, 0.0], + isotropic=True, + energy_group=0, + time=0.0, +) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(-20.5, 20.5, 202), - t=np.linspace(0.0, 20.0, 21), -) +# Tallies +mesh = mcdc.MeshStructured(x=np.linspace(-20.5, 20.5, 202)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], time=np.linspace(0.0, 20.0, 21)) -# Setting -mcdc.setting(N_particle=50, census_bank_buff=5, source_bank_buff=5, N_batch=2) -mcdc.time_census(np.linspace(0.0, 20.0, 5)[1:], tally_frequency=5) -mcdc.population_control() +# Settings +mcdc.settings.N_particle = 50 +mcdc.settings.N_batch = 2 +mcdc.settings.census_bank_buffer_ratio = 5.0 +mcdc.settings.source_bank_buffer_ratio = 5.0 +mcdc.settings.set_time_census(np.linspace(0.0, 20.0, 21)[1:], tally_frequency=5) + +# Tecniques +mcdc.simulation.population_control() # Run mcdc.run() + +# Post-processing mcdc.recombine_tallies() diff --git a/test/regression/azurv1_ww/answer.h5 b/test/regression/azurv1_ww/answer.h5 deleted file mode 100644 index fceb94299..000000000 Binary files a/test/regression/azurv1_ww/answer.h5 and /dev/null differ diff --git a/test/regression/azurv1_ww/input.py b/test/regression/azurv1_ww/input.py deleted file mode 100644 index d181df3fd..000000000 --- a/test/regression/azurv1_ww/input.py +++ /dev/null @@ -1,67 +0,0 @@ -import numpy as np - -import mcdc, mpi4py, h5py - -# ============================================================================= -# Set model -# ============================================================================= -# Infinite medium with isotropic plane surface at the center -# Based on Ganapol LA-UR-01-1854 (AZURV1 benchmark) -# Effective scattering ratio c = 1.1 -N_history = 50 -# Set materials -m = mcdc.material( - capture=np.array([1.0 / 3.0]), - scatter=np.array([[1.0 / 3.0]]), - fission=np.array([1.0 / 3.0]), - nu_p=np.array([2.3]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") - -# Set cells -mcdc.cell(+s1 & -s2, m) - -# ============================================================================= -# Set source -# ============================================================================= -# Isotropic pulse at x=t=0 - -mcdc.source(point=[0.0, 0.0, 0.0], isotropic=True, time=[1e-10, 1e-10]) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: cell-average, cell-edge, and time-edge scalar fluxes -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(-20.5, 20.5, 202), - t=np.linspace(0.0, 20.0, 21), -) - -# Setting -mcdc.setting( - N_particle=N_history, - active_bank_buff=1e4, - census_bank_buff=1e3, - source_bank_buff=1e3, - N_batch=5, -) -mcdc.time_census(np.linspace(0.0, 20.0, 21)[1:], tally_frequency=1) -""" -mcdc.weight_window( - x=np.linspace(-20.5, 20.5, 202), - method="previous", - modifications=[["min-center", 1e-3]], - width=2.5, - save_ww_data=True, -) -""" -mcdc.population_control() -# Run -mcdc.run() -# Combine the tally output into a single file -mcdc.recombine_tallies() diff --git a/test/regression/c5g7_2d_k_eigenvalue/answer.h5 b/test/regression/c5g7_2d_k_eigenvalue/answer.h5 index 09de0d66b..aa8809aad 100644 Binary files a/test/regression/c5g7_2d_k_eigenvalue/answer.h5 and b/test/regression/c5g7_2d_k_eigenvalue/answer.h5 differ diff --git a/test/regression/c5g7_2d_k_eigenvalue/input.py b/test/regression/c5g7_2d_k_eigenvalue/input.py index 7a54fa816..8240f53ee 100644 --- a/test/regression/c5g7_2d_k_eigenvalue/input.py +++ b/test/regression/c5g7_2d_k_eigenvalue/input.py @@ -13,7 +13,7 @@ # Materials def set_mat(mat): - return mcdc.material( + return mcdc.MaterialMG( capture=mat["capture"][:], scatter=mat["scatter"][:], fission=mat["fission"][:], @@ -21,19 +21,20 @@ def set_mat(mat): nu_d=mat["nu_d"][:], chi_p=mat["chi_p"][:], chi_d=mat["chi_d"][:], - speed=mat["speed"], - decay=mat["decay"], + speed=mat["speed"][:], + decay_rate=mat["decay"][:], ) -mat_uo2 = set_mat(lib["uo2"]) -mat_mox43 = set_mat(lib["mox43"]) -mat_mox7 = set_mat(lib["mox7"]) -mat_mox87 = set_mat(lib["mox87"]) -mat_gt = set_mat(lib["gt"]) -mat_fc = set_mat(lib["fc"]) -mat_cr = set_mat(lib["cr"]) -mat_mod = set_mat(lib["mod"]) +# Set the material +mat_uo2 = set_mat(lib["uo2"]) # Fuel: UO2 +mat_mox43 = set_mat(lib["mox43"]) # Fuel: MOX 4.3% +mat_mox7 = set_mat(lib["mox7"]) # Fuel: MOX 7.0% +mat_mox87 = set_mat(lib["mox87"]) # Fuel: MOX 8.7% +mat_gt = set_mat(lib["gt"]) # Guide tube +mat_fc = set_mat(lib["fc"]) # Fission chamber +mat_cr = set_mat(lib["cr"]) # Control rod +mat_mod = set_mat(lib["mod"]) # Moderator # ============================================================================= # Pin cells @@ -43,35 +44,35 @@ def set_mat(mat): radius = 0.54 # Surfaces -cy = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=radius) +cy = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=radius) # Cells -uo2 = mcdc.cell(-cy, mat_uo2) -mox4 = mcdc.cell(-cy, mat_mox43) -mox7 = mcdc.cell(-cy, mat_mox7) -mox8 = mcdc.cell(-cy, mat_mox87) -gt = mcdc.cell(-cy, mat_gt) -fc = mcdc.cell(-cy, mat_fc) -cr = mcdc.cell(-cy, mat_cr) -mod = mcdc.cell(+cy, mat_mod) -modi = mcdc.cell(-cy, mat_mod) # For all-water lattice +uo2 = mcdc.Cell(region=-cy, fill=mat_uo2) +mox4 = mcdc.Cell(region=-cy, fill=mat_mox43) +mox7 = mcdc.Cell(region=-cy, fill=mat_mox7) +mox8 = mcdc.Cell(region=-cy, fill=mat_mox87) +gt = mcdc.Cell(region=-cy, fill=mat_gt) +fc = mcdc.Cell(region=-cy, fill=mat_fc) +cr = mcdc.Cell(region=-cy, fill=mat_cr) +mod = mcdc.Cell(region=+cy, fill=mat_mod) +modi = mcdc.Cell(region=-cy, fill=mat_mod) # For all-water lattice # Universes -u = mcdc.universe([uo2, mod]) -l = mcdc.universe([mox4, mod]) -m = mcdc.universe([mox7, mod]) -n = mcdc.universe([mox8, mod]) -g = mcdc.universe([gt, mod]) -f = mcdc.universe([fc, mod]) -c = mcdc.universe([cr, mod]) -w = mcdc.universe([modi, mod]) +u = mcdc.Universe(cells=[uo2, mod]) +l = mcdc.Universe(cells=[mox4, mod]) +m = mcdc.Universe(cells=[mox7, mod]) +n = mcdc.Universe(cells=[mox8, mod]) +g = mcdc.Universe(cells=[gt, mod]) +f = mcdc.Universe(cells=[fc, mod]) +c = mcdc.Universe(cells=[cr, mod]) +w = mcdc.Universe(cells=[modi, mod]) # ============================================================================= # Assemblies # ============================================================================= # Lattices -lattice_uo2 = mcdc.lattice( +lattice_uo2 = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -95,7 +96,7 @@ def set_mat(mat): ], ) -lattice_mox = mcdc.lattice( +lattice_mox = mcdc.Lattice( x=[-pitch * 17 / 2, pitch, 17], y=[-pitch * 17 / 2, pitch, 17], universes=[ @@ -119,7 +120,7 @@ def set_mat(mat): ], ) -lattice_mod = mcdc.lattice( +lattice_mod = mcdc.Lattice( x=[-pitch * 17 / 2, pitch * 17, 1], y=[-pitch * 17 / 2, pitch * 17, 1], universes=[[w]], @@ -127,26 +128,26 @@ def set_mat(mat): # Assembly cells # Surfaces -x0 = mcdc.surface("plane-x", x=-pitch * 17 / 2) -x1 = mcdc.surface("plane-x", x=pitch * 17 / 2) -y0 = mcdc.surface("plane-y", y=-pitch * 17 / 2) -y1 = mcdc.surface("plane-y", y=pitch * 17 / 2) +x0 = mcdc.Surface.PlaneX(x=-pitch * 17 / 2) +x1 = mcdc.Surface.PlaneX(x=pitch * 17 / 2) +y0 = mcdc.Surface.PlaneY(y=-pitch * 17 / 2) +y1 = mcdc.Surface.PlaneY(y=pitch * 17 / 2) # Cells -assembly_uo2 = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_uo2) -assembly_mox = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mox) -assembly_mod = mcdc.cell(+x0 & -x1 & +y0 & -y1, lattice_mod) +assembly_uo2 = mcdc.Cell(region=+x0 & -x1 & +y0 & -y1, fill=lattice_uo2) +assembly_mox = mcdc.Cell(region=+x0 & -x1 & +y0 & -y1, fill=lattice_mox) +assembly_mod = mcdc.Cell(region=+x0 & -x1 & +y0 & -y1, fill=lattice_mod) # Set assemblies in their respective universes -u_ = mcdc.universe([assembly_uo2]) -m_ = mcdc.universe([assembly_mox]) -w_ = mcdc.universe([assembly_mod]) +u_ = mcdc.Universe(cells=[assembly_uo2]) +m_ = mcdc.Universe(cells=[assembly_mox]) +w_ = mcdc.Universe(cells=[assembly_mod]) # ============================================================================= # Root universe: core # ============================================================================= # Lattice -lattice_core = mcdc.lattice( +lattice_core = mcdc.Lattice( x=[-pitch * 17 * 3 / 2, pitch * 17, 3], y=[-pitch * 17 * 3 / 2, pitch * 17, 3], universes=[[u_, m_, w_], [m_, u_, w_], [w_, w_, w_]], @@ -154,44 +155,53 @@ def set_mat(mat): # Core cell # Surfaces -x0_ = mcdc.surface("plane-x", x=0.0, bc="reflective") -x1_ = mcdc.surface("plane-x", x=pitch * 17 * 3, bc="vacuum") -y0_ = mcdc.surface("plane-y", y=-pitch * 17 * 3, bc="vacuum") -y1_ = mcdc.surface("plane-y", y=0.0, bc="reflective") +x0_ = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +x1_ = mcdc.Surface.PlaneX(x=pitch * 17 * 3, boundary_condition="vacuum") +y0_ = mcdc.Surface.PlaneY(y=-pitch * 17 * 3, boundary_condition="vacuum") +y1_ = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") # Cell -core = mcdc.cell( - +x0_ & -x1_ & +y0_ & -y1_, - lattice_core, +core = mcdc.Cell( + region=+x0_ & -x1_ & +y0_ & -y1_, + fill=lattice_core, translation=[pitch * 17 * 3 / 2, -pitch * 17 * 3 / 2, 0.0], ) # Root universe -mcdc.universe([core], root=True) +mcdc.simulation.set_root_universe(cells=[core]) # ============================================================================= # Set source # ============================================================================= -# Uniform in energy -source = mcdc.source( - x=[0.0, pitch * 17 * 2], y=[-pitch * 17 * 2, 0.0], energy=np.ones(7) +mcdc.Source( + x=[0.0, pitch * 17 * 2], + y=[-pitch * 17 * 2, 0.0], + isotropic=True, + energy_group=6, ) # ============================================================================= -# Set tally and parameter, and then run mcdc +# Set tallies, settings, techniques, and run MC/DC # ============================================================================= -# Tally -mcdc.tally.mesh_tally( - scores=["flux"], +# Tallies +mesh = mcdc.MeshStructured( x=np.linspace(0.0, pitch * 17 * 3, 17 * 3 + 1), y=np.linspace(-pitch * 17 * 3, 0.0, 17 * 3 + 1), ) +mcdc.TallyMesh(mesh=mesh, scores=["flux"]) -# Setting -mcdc.setting(N_particle=2e1, census_bank_buff=3.0, source_bank_buff=2.0) -mcdc.eigenmode(N_inactive=1, N_active=2, gyration_radius="infinite-z") -mcdc.population_control() +# Settings +mcdc.settings.N_particle = 20 +mcdc.settings.census_bank_buffer_ratio = 4.0 +mcdc.settings.source_bank_buffer_ratio = 3.0 +mcdc.settings.set_eigenmode(N_inactive=1, N_active=2, gyration_radius="infinite-z") + +# Techniques +mcdc.simulation.population_control() # Run +mcdc.settings.set_eigenmode(N_inactive=1, N_active=2, gyration_radius="infinite-z") + + mcdc.run() diff --git a/test/regression/cooper2/answer.h5 b/test/regression/cooper2/answer.h5 index 40d65d44f..58bfc6f35 100644 Binary files a/test/regression/cooper2/answer.h5 and b/test/regression/cooper2/answer.h5 differ diff --git a/test/regression/cooper2/input.py b/test/regression/cooper2/input.py index f1ed491db..965c9e2fc 100644 --- a/test/regression/cooper2/input.py +++ b/test/regression/cooper2/input.py @@ -11,45 +11,53 @@ # Set materials SigmaT = 5.0 c = 0.8 -m_barrier = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) +m_barrier = mcdc.MaterialMG( + capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]]) +) SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) +m_room = mcdc.MaterialMG(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) # Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=2.0) -sy3 = mcdc.surface("plane-y", y=4.0, bc="vacuum") +sx1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +sx2 = mcdc.Surface.PlaneX(x=2.0) +sx3 = mcdc.Surface.PlaneX(x=2.4) +sx4 = mcdc.Surface.PlaneX(x=4.0, boundary_condition="vacuum") +sy1 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") +sy2 = mcdc.Surface.PlaneY(y=2.0) +sy3 = mcdc.Surface.PlaneY(y=4.0, boundary_condition="vacuum") # Set cells -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2, m_room) -mcdc.cell(+sx1 & -sx4 & +sy2 & -sy3, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy2, m_room) -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_barrier) +mcdc.Cell(region=+sx1 & -sx2 & +sy1 & -sy2, fill=m_room) +mcdc.Cell(region=+sx1 & -sx4 & +sy2 & -sy3, fill=m_room) +mcdc.Cell(region=+sx3 & -sx4 & +sy1 & -sy2, fill=m_room) +mcdc.Cell(region=+sx2 & -sx3 & +sy1 & -sy2, fill=m_barrier) # ============================================================================= # Set source # ============================================================================= -# Uniform isotropic source throughout the domain -mcdc.source(x=[0.0, 1.0], y=[0.0, 1.0], isotropic=True) +mcdc.Source( + x=[0.0, 1.0], + y=[0.0, 1.0], + isotropic=True, + energy_group=0, + time=0.0, +) # ============================================================================= -# Set tally, setting, and run mcdc +# Set tallies, settings, techniques, and run MC/DC # ============================================================================= -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 4.0, 40), - y=np.linspace(0.0, 4.0, 40), -) +# Tallies +mesh = mcdc.MeshUniform(x=(0.0, 0.1, 40), y=(0.0, 0.1, 40)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"]) + +# Settings +mcdc.settings.N_particle = 50 +mcdc.settings.N_batch = 2 -# Setting -mcdc.setting(N_particle=50, N_batch=2) -mcdc.implicit_capture() +# Techniques +mcdc.simulation.implicit_capture() # Run mcdc.run() diff --git a/test/regression/fuel_array_packaged/answer.h5 b/test/regression/fuel_array_packaged/answer.h5 new file mode 100644 index 000000000..2776c24a0 Binary files /dev/null and b/test/regression/fuel_array_packaged/answer.h5 differ diff --git a/test/regression/fuel_array_packaged/input.py b/test/regression/fuel_array_packaged/input.py new file mode 100644 index 000000000..c8b433320 --- /dev/null +++ b/test/regression/fuel_array_packaged/input.py @@ -0,0 +1,109 @@ +import numpy as np +import mcdc + + +# ====================================================================================== +# Materials +# ====================================================================================== + +fuel = mcdc.MaterialMG( + capture=np.array([0.45]), + fission=np.array([0.55]), + nu_p=np.array([2.5]), +) + +cover = mcdc.MaterialMG( + capture=np.array([0.05]), + scatter=np.array([[0.95]]), +) + +water = mcdc.MaterialMG( + capture=np.array([0.02]), + scatter=np.array([[0.08]]), +) + +# ====================================================================================== +# The assembly +# ====================================================================================== + +# Surfaces +cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0) +cylinder_x = mcdc.Surface.CylinderX(center=[0.0, 0.0], radius=1.0) + +top_z = mcdc.Surface.PlaneZ(z=2.5) +bot_z = mcdc.Surface.PlaneZ(z=-2.5) +top_x = mcdc.Surface.PlaneX(x=2.5) +bot_x = mcdc.Surface.PlaneX(x=-2.5) + +sphere = mcdc.Surface.Sphere(center=[0.0, 0.0, 0.0], radius=3.0) + +# Cells +pellet_z = -cylinder_z & +bot_z & -top_z +pellet_x = -cylinder_x & +bot_x & -top_x +shooting_star = pellet_z | pellet_x +fuel_shooting_star = mcdc.Cell(region=shooting_star, fill=fuel) +cover_sphere = mcdc.Cell(region=-sphere & ~shooting_star, fill=cover) +water_tank = mcdc.Cell(region=+sphere, fill=water) + +# ====================================================================================== +# Copy the assembly via universe cells +# ====================================================================================== + +# Set the universe +assembly = mcdc.Universe(cells=[fuel_shooting_star, cover_sphere, water_tank]) + +# Set container cell surfaces +min_x = mcdc.Surface.PlaneX(x=-10.0, boundary_condition="vacuum") +mid_x = mcdc.Surface.PlaneX(x=0.0) +max_x = mcdc.Surface.PlaneX(x=10.0, boundary_condition="vacuum") +min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum") +max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum") +min_z = mcdc.Surface.PlaneZ(z=-5.0, boundary_condition="vacuum") +max_z = mcdc.Surface.PlaneZ(z=5.0, boundary_condition="vacuum") + +# Make copies via universe cells +container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x +container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x +assembly_left = mcdc.Cell(region=container_left, fill=assembly, translation=[-5, 0, 0]) +assembly_right = mcdc.Cell( + region=container_right, fill=assembly, translation=[+5, 0, 0], rotation=[0, 10, 0] +) + +# Root universe +mcdc.simulation.set_root_universe(cells=[assembly_left, assembly_right]) + +# ====================================================================================== +# Set source +# ====================================================================================== + +mcdc.Source(x=[-0.1, 0.1], isotropic=True, energy_group=0) + +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== + +# Tallies +mesh = mcdc.MeshStructured( + x=np.linspace(-10, 10, 201), + z=np.linspace(-5, 5, 101), +) +mcdc.TallyMesh(mesh=mesh, scores=["fission"]) + +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 + +# Run (or visualize) +visualize = False +if not visualize: + mcdc.run() +else: + colors = { + fuel: "red", + cover: "gray", + water: "blue", + } + mcdc.visualize( + "xz", y=0.0, x=[-11.0, 11.0], z=[-6, 6], pixels=(400, 400), colors=colors + ) diff --git a/test/regression/shooting_stars/process.py b/test/regression/fuel_array_packaged/process.py similarity index 100% rename from test/regression/shooting_stars/process.py rename to test/regression/fuel_array_packaged/process.py diff --git a/test/regression/inf_shem361/answer.h5 b/test/regression/inf_shem361/answer.h5 index deb406273..f45b44bbb 100644 Binary files a/test/regression/inf_shem361/answer.h5 and b/test/regression/inf_shem361/answer.h5 differ diff --git a/test/regression/inf_shem361/input.py b/test/regression/inf_shem361/input.py index 950071f93..f9ebf364a 100644 --- a/test/regression/inf_shem361/input.py +++ b/test/regression/inf_shem361/input.py @@ -1,12 +1,10 @@ import numpy as np -import sys - import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # The infinite homogenous medium is modeled with reflecting slab # Load material data @@ -23,7 +21,7 @@ lamd = data["lamd"] # Set material -m = mcdc.material( +m = mcdc.MaterialMG( capture=SigmaC, scatter=SigmaS, fission=SigmaF, @@ -34,29 +32,31 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -c = mcdc.cell(+s1 & -s2, m) +c = mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= -# Set initial source -# ============================================================================= +# ====================================================================================== +# Set source +# ====================================================================================== -energy = np.zeros(G) -energy[-1] = 1.0 -source = mcdc.source(energy=energy) +mcdc.Source( + position=(0.0, 0.0, 0.0), isotropic=True, energy_group=np.array([[360], [1.0]]) +) -# ============================================================================= -# Set problem and tally, and then run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Tally -mcdc.tally.mesh_tally(scores=["flux"], g="all") +# Tallies +mcdc.TallyGlobal(scores=["flux"], energy="all_groups") -# Setting -mcdc.setting(N_particle=40, active_bank_buff=1000, N_batch=2) +# Swttings +mcdc.settings.N_particle = 25 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 # Run mcdc.run() diff --git a/test/regression/inf_shem361_cell_tally/SHEM-361.npz b/test/regression/inf_shem361_cell_tally/SHEM-361.npz deleted file mode 100644 index 6ba2c1f4b..000000000 Binary files a/test/regression/inf_shem361_cell_tally/SHEM-361.npz and /dev/null differ diff --git a/test/regression/inf_shem361_cell_tally/answer.h5 b/test/regression/inf_shem361_cell_tally/answer.h5 deleted file mode 100644 index 4365497cb..000000000 Binary files a/test/regression/inf_shem361_cell_tally/answer.h5 and /dev/null differ diff --git a/test/regression/inf_shem361_cell_tally/input.py b/test/regression/inf_shem361_cell_tally/input.py deleted file mode 100644 index 4403d504a..000000000 --- a/test/regression/inf_shem361_cell_tally/input.py +++ /dev/null @@ -1,65 +0,0 @@ -import numpy as np -import sys - -import mcdc - -# This regression test adds time census and time/energy binned cell tallies to the inf_shem361 test - -# ============================================================================= -# Set model -# ============================================================================= -# The infinite homogenous medium is modeled with reflecting slab - -# Load material data -with np.load("SHEM-361.npz") as data: - SigmaC = data["SigmaC"] * 5 # /cm - SigmaS = data["SigmaS"] - SigmaF = data["SigmaF"] - nu_p = data["nu_p"] - nu_d = data["nu_d"] - chi_p = data["chi_p"] - chi_d = data["chi_d"] - G = data["G"] - speed = data["v"] - lamd = data["lamd"] - -# Set material -m = mcdc.material( - capture=SigmaC, - scatter=SigmaS, - fission=SigmaF, - nu_p=nu_p, - chi_p=chi_p, - nu_d=nu_d, - chi_d=chi_d, -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") - -# Set cells -c = mcdc.cell(+s1 & -s2, m) - -# ============================================================================= -# Set initial source -# ============================================================================= - -energy = np.zeros(G) -energy[-1] = 1.0 -source = mcdc.source(energy=energy) - -# ============================================================================= -# Set problem and tally, and then run mcdc -# ============================================================================= - -# Tally -# mcdc.tally.mesh_tally(scores=["flux"], g="all") -mcdc.tally.cell_tally(c, scores=["flux"], g="all", t=np.linspace(0.0, 20.0, 21)[1:-1]) - -# Setting -mcdc.setting(N_particle=1e2, active_bank_buff=1000, N_batch=2) -mcdc.time_census(np.linspace(0.0, 20.0, 21)[1:-1]) - -# Run -mcdc.run() diff --git a/test/regression/inf_shem361_k_eigenvalue/answer.h5 b/test/regression/inf_shem361_k_eigenvalue/answer.h5 index a25ac8aeb..787616696 100644 Binary files a/test/regression/inf_shem361_k_eigenvalue/answer.h5 and b/test/regression/inf_shem361_k_eigenvalue/answer.h5 differ diff --git a/test/regression/inf_shem361_k_eigenvalue/input.py b/test/regression/inf_shem361_k_eigenvalue/input.py index 219a31703..2f4a65c82 100644 --- a/test/regression/inf_shem361_k_eigenvalue/input.py +++ b/test/regression/inf_shem361_k_eigenvalue/input.py @@ -19,7 +19,7 @@ G = data["G"] # Set material -m = mcdc.material( +m = mcdc.MaterialMG( capture=SigmaC, scatter=SigmaS, fission=SigmaF, @@ -30,32 +30,35 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -c = mcdc.cell(+s1 & -s2, m) +c = mcdc.Cell(region=+s1 & -s2, fill=m) # ============================================================================= # Set initial source # ============================================================================= -source = mcdc.source(energy=np.ones(G)) # Arbitrary +mcdc.Source( + position=(0.0, 0.0, 0.0), isotropic=True, energy_group=np.array([[360], [1.0]]) +) # ============================================================================= -# Set problem and tally, and then run mcdc +# Set tallies, settings, techniques, and run MC/DC # ============================================================================= -# Tally -mcdc.tally.mesh_tally( - scores=["flux"], - g="all", -) +# Tallies +mcdc.TallyGlobal(scores=["flux"], energy="all_groups") + +# Settings +mcdc.settings.N_particle = 70 +mcdc.settings.source_bank_buffer_ratio = 2.0 +mcdc.settings.census_bank_buffer_ratio = 3.0 +mcdc.settings.set_eigenmode(N_inactive=1, N_active=2) -# Setting -mcdc.setting(N_particle=1e2, source_bank_buff=2.0) -mcdc.eigenmode(N_inactive=1, N_active=2) -mcdc.population_control() +# Techniques +mcdc.simulation.population_control() # Run mcdc.run() diff --git a/test/regression/inf_shem361_td/answer.h5 b/test/regression/inf_shem361_td/answer.h5 index a990c320f..abf3f94fd 100644 Binary files a/test/regression/inf_shem361_td/answer.h5 and b/test/regression/inf_shem361_td/answer.h5 differ diff --git a/test/regression/inf_shem361_td/input.py b/test/regression/inf_shem361_td/input.py index 4fa25fe44..b21ea9571 100644 --- a/test/regression/inf_shem361_td/input.py +++ b/test/regression/inf_shem361_td/input.py @@ -1,17 +1,15 @@ import numpy as np -import sys - import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # The infinite homogenous medium is modeled with reflecting slab # Load material data with np.load("SHEM-361.npz") as data: - SigmaC = data["SigmaC"] * 1.5 # /cm + SigmaC = data["SigmaC"] * 2.5 # /cm SigmaS = data["SigmaS"] SigmaF = data["SigmaF"] nu_p = data["nu_p"] @@ -23,7 +21,7 @@ lamd = data["lamd"] # Set material -m = mcdc.material( +m = mcdc.MaterialMG( capture=SigmaC, scatter=SigmaS, fission=SigmaF, @@ -31,36 +29,40 @@ chi_p=chi_p, nu_d=nu_d, chi_d=chi_d, - decay=lamd, + decay_rate=lamd, speed=speed, ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -c = mcdc.cell(+s1 & -s2, m) +c = mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= -# Set initial source -# ============================================================================= +# ====================================================================================== +# Set source +# ====================================================================================== -energy = np.zeros(G) -energy[-1] = 1.0 -source = mcdc.source(energy=energy) +mcdc.Source( + position=(0.0, 0.0, 0.0), isotropic=True, energy_group=np.array([[360], [1.0]]) +) -# ============================================================================= -# Set problem and tally, and then run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Tally -mcdc.tally.mesh_tally( - scores=["flux"], t=np.insert(np.logspace(-8, 1, 100), 0, 0.0), g="all" +# Tallies +mcdc.TallyGlobal( + scores=["flux"], + time=np.insert(np.logspace(-8, 1, 100), 0, 0.0), + energy="all_groups", ) -# Setting -mcdc.setting(N_particle=50, active_bank_buff=1000, N_batch=2) +# Swttings +mcdc.settings.N_particle = 50 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 # Run mcdc.run() diff --git a/test/regression/inf_shem361_td_census/answer.h5 b/test/regression/inf_shem361_td_census/answer.h5 index e215ba90e..a0046043c 100644 Binary files a/test/regression/inf_shem361_td_census/answer.h5 and b/test/regression/inf_shem361_td_census/answer.h5 differ diff --git a/test/regression/inf_shem361_td_census/input.py b/test/regression/inf_shem361_td_census/input.py index 0c0a03aad..e08129a54 100644 --- a/test/regression/inf_shem361_td_census/input.py +++ b/test/regression/inf_shem361_td_census/input.py @@ -1,17 +1,15 @@ import numpy as np -import sys - import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # The infinite homogenous medium is modeled with reflecting slab # Load material data with np.load("SHEM-361.npz") as data: - SigmaC = data["SigmaC"] * 1.5 # /cm + SigmaC = data["SigmaC"] * 3.0 # /cm SigmaS = data["SigmaS"] SigmaF = data["SigmaF"] nu_p = data["nu_p"] @@ -23,7 +21,7 @@ lamd = data["lamd"] # Set material -m = mcdc.material( +m = mcdc.MaterialMG( capture=SigmaC, scatter=SigmaS, fission=SigmaF, @@ -31,45 +29,46 @@ chi_p=chi_p, nu_d=nu_d, chi_d=chi_d, - decay=lamd, + decay_rate=lamd, speed=speed, ) # Set surfaces -s1 = mcdc.surface("plane-x", x=-1e10, bc="reflective") -s2 = mcdc.surface("plane-x", x=1e10, bc="reflective") +s1 = mcdc.Surface.PlaneX(x=-1e10, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneX(x=1e10, boundary_condition="reflective") # Set cells -c = mcdc.cell(+s1 & -s2, m) +c = mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= -# Set initial source -# ============================================================================= +# ====================================================================================== +# Set source +# ====================================================================================== -energy = np.zeros(G) -energy[-1] = 1.0 -source = mcdc.source(energy=energy) +mcdc.Source( + position=(0.0, 0.0, 0.0), isotropic=True, energy_group=np.array([[360], [1.0]]) +) -# ============================================================================= -# Set problem and tally, and then run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== -# Tally -mcdc.tally.mesh_tally( - scores=["flux"], t=np.insert(np.logspace(-8, 1, 100), 0, 0.0), g="all" +# Tallies +mcdc.TallyGlobal( + scores=["flux"], + time=np.insert(np.logspace(-8, 1, 100), 0, 0.0), + energy="all_groups", ) -# Setting -mcdc.setting( - N_particle=30, - active_bank_buff=1000, - census_bank_buff=5, - source_bank_buff=5, - rng_seed=7, - N_batch=2, -) -mcdc.time_census(np.logspace(-5, 1, 6)) -mcdc.population_control() +# Settings +mcdc.settings.N_particle = 40 +mcdc.settings.N_batch = 2 +mcdc.settings.set_time_census(np.logspace(-5, 1, 6)) +mcdc.settings.active_bank_buffer = 1000 +mcdc.settings.census_bank_buffer_ratio = 5.0 +mcdc.settings.source_bank_buffer_ratio = 5.0 + +# Techniques +mcdc.simulation.population_control() # Run mcdc.run() diff --git a/test/regression/iqmc_cooper2/answer.h5 b/test/regression/iqmc_cooper2/answer.h5 deleted file mode 100644 index 335e754b4..000000000 Binary files a/test/regression/iqmc_cooper2/answer.h5 and /dev/null differ diff --git a/test/regression/iqmc_cooper2/input.py b/test/regression/iqmc_cooper2/input.py deleted file mode 100644 index 1307c02e3..000000000 --- a/test/regression/iqmc_cooper2/input.py +++ /dev/null @@ -1,65 +0,0 @@ -import numpy as np -import mcdc - - -# ============================================================================= -# Set model -# ============================================================================= -# A shielding problem based on Problem 2 of [Coper NSE 2001] -# https://ans.tandfonline.com/action/showCitFormats?doi=10.13182/NSE00-34 - -# Set materials -SigmaT = 5.0 -c = 0.8 -m_barrier = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) -SigmaT = 1.0 -m_room = mcdc.material(capture=np.array([SigmaT]), scatter=np.array([[SigmaT * c]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=2.0) -sx3 = mcdc.surface("plane-x", x=2.4) -sx4 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=2.0) -sy3 = mcdc.surface("plane-y", y=4.0, bc="vacuum") - -# Set cells -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2, m_room) -mcdc.cell(+sx1 & -sx4 & +sy2 & -sy3, m_room) -mcdc.cell(+sx3 & -sx4 & +sy1 & -sy2, m_room) -mcdc.cell(+sx2 & -sx3 & +sy1 & -sy2, m_barrier) - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 20 -Nx = Ny = 40 -maxit = 2 -tol = 1e-3 -x = np.linspace(0, 4, num=Nx + 1) -y = np.linspace(0, 4, num=Ny + 1) - -# fixed source in lower left corner -fixed_source = np.zeros((Nx, Ny)) -fixed_source[0 : int(0.25 * Nx), 0 : int(0.25 * Nx)] = 1 - -phi0 = np.ones((Nx, Ny)) - -mcdc.iQMC( - x=x, - y=y, - fixed_source=fixed_source, - phi0=phi0, - maxit=maxit, - tol=tol, - scores=["source-x", "source-y"], -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= -# Setting -mcdc.setting(N_particle=N) -# Run -mcdc.run() diff --git a/test/regression/iqmc_kornreich_pi/answer.h5 b/test/regression/iqmc_kornreich_pi/answer.h5 deleted file mode 100644 index f02243851..000000000 Binary files a/test/regression/iqmc_kornreich_pi/answer.h5 and /dev/null differ diff --git a/test/regression/iqmc_kornreich_pi/input.py b/test/regression/iqmc_kornreich_pi/input.py deleted file mode 100644 index 2dcefca30..000000000 --- a/test/regression/iqmc_kornreich_pi/input.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -import h5py -import mcdc - - -# ========================================================================= -# Set model -# ========================================================================= -# Based on Kornreich, ANE 2004, 31, 1477-1494, -# DOI: 10.1016/j.anucene.2004.03.012 - -# Set materials -m1 = mcdc.material( - capture=np.array([0.0]), - scatter=np.array([[0.9]]), - fission=np.array([0.1]), - nu_p=np.array([6.0]), -) -m2 = mcdc.material( - capture=np.array([0.68]), - scatter=np.array([[0.2]]), - fission=np.array([0.12]), - nu_p=np.array([2.5]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=1.5) -s3 = mcdc.surface("plane-x", x=2.5, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) - -# ========================================================================= -# iQMC Parameters -# ========================================================================= -N = 50 -maxit = 5 -tol = 1e-3 -x = np.arange(0.0, 2.6, 0.1) -Nx = len(x) - 1 -fixed_source = np.zeros(Nx) -phi0 = np.ones((Nx)) - -# ========================================================================= -# Set tally, setting, and run mcdc -# ========================================================================= - -mcdc.iQMC( - x=x, - fixed_source=fixed_source, - phi0=phi0, - maxit=maxit, - tol=tol, - scores=["source-x"], -) -# Setting -mcdc.setting(N_particle=N) -mcdc.eigenmode() - -# Run -mcdc.run() diff --git a/test/regression/iqmc_reed/answer.h5 b/test/regression/iqmc_reed/answer.h5 deleted file mode 100644 index 0d8ff09f3..000000000 Binary files a/test/regression/iqmc_reed/answer.h5 and /dev/null differ diff --git a/test/regression/iqmc_reed/input.py b/test/regression/iqmc_reed/input.py deleted file mode 100644 index 879a64d35..000000000 --- a/test/regression/iqmc_reed/input.py +++ /dev/null @@ -1,72 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different materials -# Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 - -# Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=-8.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=-5.0) -s3 = mcdc.surface("plane-x", x=-3.0) -s4 = mcdc.surface("plane-x", x=-2.0) -s5 = mcdc.surface("plane-x", x=2.0) -s6 = mcdc.surface("plane-x", x=3.0) -s7 = mcdc.surface("plane-x", x=5.0) -s8 = mcdc.surface("plane-x", x=8.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m4) -mcdc.cell(+s2 & -s3, m3) -mcdc.cell(+s3 & -s4, m2) -mcdc.cell(+s4 & -s5, m1) -mcdc.cell(+s5 & -s6, m2) -mcdc.cell(+s6 & -s7, m3) -mcdc.cell(+s7 & -s8, m4) - - -# ============================================================================= -# iQMC Parameters -# ============================================================================= -N = 20 -Nx = 16 -maxit = 10 -tol = 1e-3 -x = np.linspace(-8, 8, num=Nx + 1) -solver = "gmres" - -fixed_source = np.zeros(Nx) -fixed_source[int(0.375 * Nx) : int(0.625 * Nx)] = 50.0 -fixed_source[int(0.125 * Nx) : int(0.1875 * Nx)] = 1.0 -fixed_source[int(0.8125 * Nx) : int(0.875 * Nx)] = 1.0 - -phi0 = np.ones((Nx)) - -mcdc.iQMC( - x=x, - fixed_source=fixed_source, - phi0=phi0, - maxit=maxit, - tol=tol, - fixed_source_solver=solver, - scores=["source-x"], -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Setting -mcdc.setting(N_particle=N) - -# Run -mcdc.run() diff --git a/test/regression/iqmc_sood_pi/answer.h5 b/test/regression/iqmc_sood_pi/answer.h5 deleted file mode 100644 index 5b613351d..000000000 Binary files a/test/regression/iqmc_sood_pi/answer.h5 and /dev/null differ diff --git a/test/regression/iqmc_sood_pi/input.py b/test/regression/iqmc_sood_pi/input.py deleted file mode 100644 index 6b257f47b..000000000 --- a/test/regression/iqmc_sood_pi/input.py +++ /dev/null @@ -1,55 +0,0 @@ -import numpy as np -import h5py -import mcdc - - -# ========================================================================= -# Set model -# ========================================================================= -# Based on Sood, PNE, Volume 42, Issue 1, 2003, Pages 55-106 2003, -# "Analytical Benchmark Test Set For Criticality Code Verification" - -# 2G-U Slab data -m1 = mcdc.material( - capture=np.array([0.01344, 0.00384]), - scatter=np.array([[0.26304, 0.0720], [0.00000, 0.078240]]), - fission=np.array([0.06912, 0.06192]), - nu_p=np.array([2.5, 2.7]), - chi_p=np.array([[0.425, 0.425], [0.575, 0.575]]), -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=6.01275, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) - -# ========================================================================= -# iQMC Parameters -# ========================================================================= -Nx = 5 -N = 10 -maxit = 5 -tol = 1e-3 -x = np.linspace(0.0, 6.01275, num=Nx + 1) -fixed_source = np.zeros(Nx) -phi0 = np.ones((Nx)) - -# ========================================================================= -# Set tally, setting, and run mcdc -# ========================================================================= - -mcdc.iQMC( - x=x, - phi0=phi0, - fixed_source=fixed_source, - maxit=maxit, - tol=tol, -) -# Setting -mcdc.setting(N_particle=N) -mcdc.eigenmode() - -# Run -mcdc.run() diff --git a/test/regression/kobayashi3-TD-new/input.py b/test/regression/kobayashi3-TD-new/input.py deleted file mode 100644 index 468b5ec93..000000000 --- a/test/regression/kobayashi3-TD-new/input.py +++ /dev/null @@ -1,75 +0,0 @@ -import numpy as np -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Based on Kobayashi dog-leg benchmark problem -# (PNE 2001, https://doi.org/10.1016/S0149-1970(01)00007-5) - -# Set materials -m = mcdc.material(capture=np.array([0.05]), scatter=np.array([[0.05]])) -m_void = mcdc.material(capture=np.array([5e-5]), scatter=np.array([[5e-5]])) - -# Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=10.0) -sx3 = mcdc.surface("plane-x", x=30.0) -sx4 = mcdc.surface("plane-x", x=40.0) -sx5 = mcdc.surface("plane-x", x=60.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=10.0) -sy3 = mcdc.surface("plane-y", y=50.0) -sy4 = mcdc.surface("plane-y", y=60.0) -sy5 = mcdc.surface("plane-y", y=100.0, bc="vacuum") -sz1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -sz2 = mcdc.surface("plane-z", z=10.0) -sz3 = mcdc.surface("plane-z", z=30.0) -sz4 = mcdc.surface("plane-z", z=40.0) -sz5 = mcdc.surface("plane-z", z=60.0, bc="vacuum") - -# Set cells -# Source -mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2, m) -# Voids -channel_1 = +sx1 & -sx2 & +sy2 & -sy3 & +sz1 & -sz2 -channel_2 = +sx1 & -sx3 & +sy3 & -sy4 & +sz1 & -sz2 -channel_3 = +sx3 & -sx4 & +sy3 & -sy4 & +sz1 & -sz3 -channel_4 = +sx3 & -sx4 & +sy3 & -sy5 & +sz3 & -sz4 -void_channel = channel_1 | channel_2 | channel_3 | channel_4 -mcdc.cell(void_channel, m_void) -# Shield -box = +sx1 & -sx5 & +sy1 & -sy5 & +sz1 & -sz5 -mcdc.cell(box & ~void_channel, m) - -# ============================================================================= -# Set source -# ============================================================================= -# The source pulses in t=[0,5] - -mcdc.source( - x=[0.0, 10.0], y=[0.0, 10.0], z=[0.0, 10.0], time=[0.0, 50.0], isotropic=True -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -time_grid = np.linspace(0.0, 200.0, 21) -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 60.0, 61), - y=np.linspace(0.0, 100.0, 101), - t=time_grid, -) -mcdc.tally.mesh_tally( - scores=["density"], - t=time_grid, -) - -# Setting -mcdc.setting(N_particle=80, N_batch=2) -mcdc.implicit_capture() - -# Run -mcdc.run() diff --git a/test/regression/kobayashi3-TD/answer.h5 b/test/regression/kobayashi3-TD/answer.h5 index 9fffe66ff..977a34eda 100644 Binary files a/test/regression/kobayashi3-TD/answer.h5 and b/test/regression/kobayashi3-TD/answer.h5 differ diff --git a/test/regression/kobayashi3-TD/input.py b/test/regression/kobayashi3-TD/input.py index ee2eba85b..32f85c0e3 100644 --- a/test/regression/kobayashi3-TD/input.py +++ b/test/regression/kobayashi3-TD/input.py @@ -1,74 +1,80 @@ import numpy as np import mcdc -# ============================================================================= + +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Based on Kobayashi dog-leg benchmark problem # (PNE 2001, https://doi.org/10.1016/S0149-1970(01)00007-5) # Set materials -m = mcdc.material(capture=np.array([0.05]), scatter=np.array([[0.05]])) -m_void = mcdc.material(capture=np.array([5e-5]), scatter=np.array([[5e-5]])) +m = mcdc.MaterialMG(capture=np.array([0.05]), scatter=np.array([[0.05]])) +m_void = mcdc.MaterialMG(capture=np.array([5e-5]), scatter=np.array([[5e-5]])) # Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=10.0) -sx3 = mcdc.surface("plane-x", x=30.0) -sx4 = mcdc.surface("plane-x", x=40.0) -sx5 = mcdc.surface("plane-x", x=60.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=10.0) -sy3 = mcdc.surface("plane-y", y=50.0) -sy4 = mcdc.surface("plane-y", y=60.0) -sy5 = mcdc.surface("plane-y", y=100.0, bc="vacuum") -sz1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -sz2 = mcdc.surface("plane-z", z=10.0) -sz3 = mcdc.surface("plane-z", z=30.0) -sz4 = mcdc.surface("plane-z", z=40.0) -sz5 = mcdc.surface("plane-z", z=60.0, bc="vacuum") +sx1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="reflective") +sx2 = mcdc.Surface.PlaneX(x=10.0) +sx3 = mcdc.Surface.PlaneX(x=30.0) +sx4 = mcdc.Surface.PlaneX(x=40.0) +sx5 = mcdc.Surface.PlaneX(x=60.0, boundary_condition="vacuum") +sy1 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="reflective") +sy2 = mcdc.Surface.PlaneY(y=10.0) +sy3 = mcdc.Surface.PlaneY(y=50.0) +sy4 = mcdc.Surface.PlaneY(y=60.0) +sy5 = mcdc.Surface.PlaneY(y=100.0, boundary_condition="vacuum") +sz1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="reflective") +sz2 = mcdc.Surface.PlaneZ(z=10.0) +sz3 = mcdc.Surface.PlaneZ(z=30.0) +sz4 = mcdc.Surface.PlaneZ(z=40.0) +sz5 = mcdc.Surface.PlaneZ(z=60.0, boundary_condition="vacuum") # Set cells # Source -source_cell = mcdc.cell(+sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2, m) +source_cell = mcdc.Cell(region=+sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2, fill=m) # Voids channel_1 = +sx1 & -sx2 & +sy2 & -sy3 & +sz1 & -sz2 channel_2 = +sx1 & -sx3 & +sy3 & -sy4 & +sz1 & -sz2 channel_3 = +sx3 & -sx4 & +sy3 & -sy4 & +sz1 & -sz3 channel_4 = +sx3 & -sx4 & +sy3 & -sy5 & +sz3 & -sz4 void_channel = channel_1 | channel_2 | channel_3 | channel_4 -void_cell = mcdc.cell(void_channel, m_void) +void_cell = mcdc.Cell(region=void_channel, fill=m_void) # Shield box = +sx1 & -sx5 & +sy1 & -sy5 & +sz1 & -sz5 -shield_cell = mcdc.cell(box & ~void_channel, m) +shield_cell = mcdc.Cell(region=box & ~void_channel, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # The source pulses in t=[0,5] -mcdc.source( - x=[0.0, 10.0], y=[0.0, 10.0], z=[0.0, 10.0], time=[0.0, 50.0], isotropic=True +mcdc.Source( + x=[0.0, 10.0], + y=[0.0, 10.0], + z=[0.0, 10.0], + isotropic=True, + energy_group=0, + time=[0.0, 50.0], ) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== -# Tally: z-integrated flux (X-Y section view) -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 60.0, 31), - y=np.linspace(0.0, 100.0, 51), - t=np.linspace(0.0, 200.0, 21), -) +# Tallies +time_grid = np.linspace(0.0, 200.0, 21) +mcdc.TallyCell(cell=source_cell, scores=["flux"], time=time_grid) +mcdc.TallyCell(cell=void_cell, scores=["flux"], time=time_grid) +mcdc.TallyCell(cell=shield_cell, scores=["flux"], time=time_grid) +mesh = mcdc.MeshUniform(x=(0.0, 1.0, 60), y=(0.0, 1.0, 100)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"], time=time_grid) +mcdc.TallyGlobal(scores=["density"], time=time_grid) -mcdc.tally.cell_tally(source_cell, scores=["flux"]) -mcdc.tally.cell_tally(void_cell, scores=["flux"]) -mcdc.tally.cell_tally(shield_cell, scores=["flux"]) +# Settings +mcdc.settings.N_particle = 25 -# Setting -mcdc.setting(N_particle=80, N_batch=2) +# Techniques +mcdc.simulation.implicit_capture() # Run mcdc.run() diff --git a/test/regression/kornreich/answer.h5 b/test/regression/kornreich/answer.h5 index 40a8eb29f..135432d5e 100644 Binary files a/test/regression/kornreich/answer.h5 and b/test/regression/kornreich/answer.h5 differ diff --git a/test/regression/kornreich/input.py b/test/regression/kornreich/input.py index 8bbbab84b..f7ddbce3c 100644 --- a/test/regression/kornreich/input.py +++ b/test/regression/kornreich/input.py @@ -1,23 +1,21 @@ import numpy as np -import h5py - import mcdc -# ========================================================================= +# ====================================================================================== # Set model -# ========================================================================= +# ====================================================================================== # Based on Kornreich, ANE 2004, 31, 1477-1494, # DOI: 10.1016/j.anucene.2004.03.012 # Set materials -m1 = mcdc.material( +m1 = mcdc.MaterialMG( capture=np.array([0.0]), scatter=np.array([[0.9]]), fission=np.array([0.1]), nu_p=np.array([6.0]), ) -m2 = mcdc.material( +m2 = mcdc.MaterialMG( capture=np.array([0.68]), scatter=np.array([[0.2]]), fission=np.array([0.12]), @@ -25,58 +23,59 @@ ) # Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=1.5) -s3 = mcdc.surface("plane-x", x=2.5, bc="vacuum") +s1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="vacuum") +s2 = mcdc.Surface.PlaneX(x=1.5) +s3 = mcdc.Surface.PlaneX(x=2.5, boundary_condition="vacuum") # Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) +mcdc.Cell(region=+s1 & -s2, fill=m1) +mcdc.Cell(region=+s2 & -s3, fill=m2) -# ========================================================================= +# ====================================================================================== # Set source -# ========================================================================= +# ====================================================================================== -mcdc.source(x=[0.0, 2.5], isotropic=True) +mcdc.Source(x=[0.0, 2.5], isotropic=True, energy_group=0) -# ========================================================================= -# Set tally, setting, and run mcdc -# ========================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Tally -x = np.array( - [ - 0.0, - 0.15, - 0.3, - 0.45, - 0.6, - 0.75, - 0.9, - 1.05, - 1.2, - 1.35, - 1.5, - 1.6, - 1.7, - 1.8, - 1.9, - 2, - 2.1, - 2.2, - 2.3, - 2.4, - 2.5, - ] +# Tallies +mesh = mcdc.MeshStructured( + x=np.array( + [ + 0.0, + 0.15, + 0.3, + 0.45, + 0.6, + 0.75, + 0.9, + 1.05, + 1.2, + 1.35, + 1.5, + 1.6, + 1.7, + 1.8, + 1.9, + 2, + 2.1, + 2.2, + 2.3, + 2.4, + 2.5, + ] + ) ) -scores = ["flux"] -mcdc.tally.mesh_tally(scores=scores, x=x) +mcdc.TallyMesh(mesh=mesh, scores=["flux"]) -# Setting -mcdc.setting( - N_particle=100, progress_bar=False, census_bank_buff=2.0, source_bank_buff=2.0 -) -mcdc.eigenmode(N_inactive=1, N_active=2, gyration_radius="only-x") +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.census_bank_buffer_ratio = 3.0 +mcdc.settings.source_bank_buffer_ratio = 3.0 +mcdc.settings.set_eigenmode(N_inactive=1, N_active=2, gyration_radius="only-x") # Run mcdc.run() diff --git a/test/regression/moving_pellet/answer.h5 b/test/regression/moving_pellet/answer.h5 index 324c1426a..9e275fea4 100644 Binary files a/test/regression/moving_pellet/answer.h5 and b/test/regression/moving_pellet/answer.h5 differ diff --git a/test/regression/moving_pellet/input.py b/test/regression/moving_pellet/input.py index 0c454aeb8..b56e38203 100644 --- a/test/regression/moving_pellet/input.py +++ b/test/regression/moving_pellet/input.py @@ -3,90 +3,94 @@ import mcdc -# ============================================================================= -# Materials -# ============================================================================= +# ====================================================================================== +# Set model +# ====================================================================================== # Set materials -fuel = mcdc.material( +fuel = mcdc.MaterialMG( capture=np.array([0.5]), - fission=np.array([0.5]), - nu_p=np.array([2.5]), + fission=np.array([0.25]), + nu_p=np.array([1.5]), speed=np.array([200000.0]), ) - -air = mcdc.material( +air = mcdc.MaterialMG( capture=np.array([0.002]), scatter=np.array([[0.008]]), speed=np.array([200000.0]), ) -# ============================================================================= -# Set an assembly -# ============================================================================= - -# Surfaces -cylinder_z = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=1.0) -top_z = mcdc.surface("plane-z", z=9.0) -bot_z = mcdc.surface("plane-z", z=6.0) +# Set surfaces +cylinder_z = mcdc.Surface.CylinderZ(center=[0.0, 0.0], radius=1.0) +top_z = mcdc.Surface.PlaneZ(z=9.0) +bot_z = mcdc.Surface.PlaneZ(z=6.0) -# Move +# Move surfaces cylinder_z.move([[-0.5, 0.0, 0.0], [1.0, 0.0, 0.0], [-2.0, 0.0, 0.0]], [2.0, 5.0, 1.0]) top_z.move([[0.0, 0.0, -2.0], [0.0, 0.0, 4.0], [0.0, 0.0, -10.0]], [5.0, 2.0, 1.0]) bot_z.move([[0.0, 0.0, -2.0], [0.0, 0.0, 4.0], [0.0, 0.0, -10.0]], [5.0, 2.0, 1.0]) # Set container cell surfaces -min_x = mcdc.surface("plane-x", x=-5.0, bc="vacuum") -max_x = mcdc.surface("plane-x", x=5.0, bc="vacuum") -min_y = mcdc.surface("plane-y", y=-5.0, bc="vacuum") -max_y = mcdc.surface("plane-y", y=5.0, bc="vacuum") -min_z = mcdc.surface("plane-z", z=-10.0, bc="vacuum") -max_z = mcdc.surface("plane-z", z=10.0, bc="vacuum") +min_x = mcdc.Surface.PlaneX(x=-5.0, boundary_condition="vacuum") +max_x = mcdc.Surface.PlaneX(x=5.0, boundary_condition="vacuum") +min_y = mcdc.Surface.PlaneY(y=-5.0, boundary_condition="vacuum") +max_y = mcdc.Surface.PlaneY(y=5.0, boundary_condition="vacuum") +min_z = mcdc.Surface.PlaneZ(z=-10.0, boundary_condition="vacuum") +max_z = mcdc.Surface.PlaneZ(z=10.0, boundary_condition="vacuum") # Make cells fuel_pellet_region = +bot_z & -top_z & -cylinder_z -mcdc.cell(fuel_pellet_region, fuel) -mcdc.cell( - ~fuel_pellet_region & +min_x & -max_x & +min_y & -max_y & +min_z & -max_z, air +mcdc.Cell(region=fuel_pellet_region, fill=fuel) +mcdc.Cell( + region=~fuel_pellet_region & +min_x & -max_x & +min_y & -max_y & +min_z & -max_z, + fill=air, ) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source(x=[2.0, 3.0], y=[-0.5, 0.5], z=[-0.5, 0.5], time=[0.0, 9.0]) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: cell-average and cell-edge angular fluxes and currents -mcdc.tally.mesh_tally( - x=np.linspace(-5, 5, 201), - z=np.linspace(-10, 10, 201), - t=np.linspace(0, 9, 46), - scores=["fission"], +# ====================================================================================== + +mcdc.Source( + x=[2.0, 3.0], + y=[-0.5, 0.5], + z=[-0.5, 0.5], + isotropic=True, + energy_group=0, + time=[0.0, 9.0], ) -# Setting -mcdc.setting(N_particle=5, active_bank_buff=1000, N_batch=2) +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Run -mcdc.run() -""" -colors = { - fuel: "red", - air: "blue", -} -mcdc.visualize( - "xz", - y=0.0, - x=[-5.0, 5.0], - z=[-10, 10], - pixel=(100, 100), - colors=colors, - time=np.linspace(0.0, 9.0, 19), - save_as="figure", +# Tallies +mesh = mcdc.MeshStructured( + x=np.linspace(-5, 5, 101), + z=np.linspace(-10, 10, 101), ) -""" +mcdc.TallyMesh(mesh=mesh, scores=["fission"], time=np.linspace(0, 9, 46)) + +# Settings +mcdc.settings.N_particle = 50 +mcdc.settings.N_batch = 2 +mcdc.settings.active_bank_buffer = 1000 + +# Run (or visualize) +visualize = False +if not visualize: + mcdc.run() +else: + colors = { + fuel: "red", + air: "blue", + } + mcdc.visualize( + "xz", + y=0.0, + x=[-5.0, 5.0], + z=[-10, 10], + pixels=(100, 100), + colors=colors, + time=np.linspace(0.0, 9.0, 19), + save_as="figure", + ) diff --git a/test/regression/pincell-k_eigenvalue/answer.h5 b/test/regression/pincell-k_eigenvalue/answer.h5 new file mode 100644 index 000000000..871ecb0ab Binary files /dev/null and b/test/regression/pincell-k_eigenvalue/answer.h5 differ diff --git a/test/regression/pincell-k_eigenvalue/input.py b/test/regression/pincell-k_eigenvalue/input.py new file mode 100644 index 000000000..893705fa1 --- /dev/null +++ b/test/regression/pincell-k_eigenvalue/input.py @@ -0,0 +1,53 @@ +import mcdc +import numpy as np +import os + +os.environ["MCDC_LIB"] = "../MCDC-regression_test_data/" + +# Material +fuel = mcdc.Material( + nuclide_composition={ + "U235": 0.0001654509603995036, + "U238": 0.022801089905717036, + "O16": 0.04593308173223308, + } +) +moderator = mcdc.Material( + nuclide_composition={ + "H1": 0.05129627050184732, + "O16": 0.024622209840886707, + "B10": 4.103701640147785e-05, + } +) + +# Geometry +cylinder = mcdc.Surface.CylinderZ(radius=0.45720) +pitch = 1.25984 +x0 = mcdc.Surface.PlaneX(x=-pitch / 2, boundary_condition="reflective") +x1 = mcdc.Surface.PlaneX(x=pitch / 2, boundary_condition="reflective") +y0 = mcdc.Surface.PlaneY(y=-pitch / 2, boundary_condition="reflective") +y1 = mcdc.Surface.PlaneY(y=pitch / 2, boundary_condition="reflective") +# +mcdc.Cell(-cylinder, fill=fuel) +mcdc.Cell(+x0 & -x1 & +y0 & -y1 & +cylinder, fill=moderator) + +# Source +mcdc.Source(position=[0.0, 0.0, 0.0], isotropic=True, time=0.0, energy=14.1e6) + +# Setting +mcdc.settings.N_particle = 30 +mcdc.settings.time_boundary = 1.0 +mcdc.settings.active_bank_buffer = 1000 +mcdc.settings.census_bank_buffer_ratio = 3.0 +mcdc.settings.source_bank_buffer_ratio = 3.0 +mcdc.settings.set_eigenmode(N_inactive=1, N_active=2) + +# Tally +t_grid = np.insert(np.logspace(-9, -4, 200), 0, 0.0) +e_min, e_max = 1e-5, 20.0e6 +groups = 500 +energies = np.logspace(np.log10(e_min), np.log10(e_max), groups + 1) + +mcdc.TallyGlobal(scores=["flux"], time=t_grid, energy=energies) + +mcdc.run() diff --git a/test/regression/kobayashi3-TD-new/answer.h5 b/test/regression/pincell/answer.h5 similarity index 60% rename from test/regression/kobayashi3-TD-new/answer.h5 rename to test/regression/pincell/answer.h5 index e3d625467..e51ca8171 100644 Binary files a/test/regression/kobayashi3-TD-new/answer.h5 and b/test/regression/pincell/answer.h5 differ diff --git a/test/regression/pincell/input.py b/test/regression/pincell/input.py new file mode 100644 index 000000000..db6897a82 --- /dev/null +++ b/test/regression/pincell/input.py @@ -0,0 +1,51 @@ +import mcdc +import numpy as np +import os + +os.environ["MCDC_LIB"] = "../MCDC-regression_test_data/" + +# Material +fuel = mcdc.Material( + nuclide_composition={ + "U235": 0.0001654509603995036, + "U238": 0.022801089905717036, + "O16": 0.04593308173223308, + } +) +moderator = mcdc.Material( + nuclide_composition={ + "H1": 0.05129627050184732, + "O16": 0.024622209840886707, + "B10": 4.103701640147785e-05, + } +) + +# Geometry +cylinder = mcdc.Surface.CylinderZ(radius=0.45720) +pitch = 1.25984 +x0 = mcdc.Surface.PlaneX(x=-pitch / 2, boundary_condition="reflective") +x1 = mcdc.Surface.PlaneX(x=pitch / 2, boundary_condition="reflective") +y0 = mcdc.Surface.PlaneY(y=-pitch / 2, boundary_condition="reflective") +y1 = mcdc.Surface.PlaneY(y=pitch / 2, boundary_condition="reflective") +# +mcdc.Cell(-cylinder, fill=fuel) +mcdc.Cell(+x0 & -x1 & +y0 & -y1 & +cylinder, fill=moderator) + +# Source +mcdc.Source(position=[0.0, 0.0, 0.0], isotropic=True, time=0.0, energy=14.1e6) + +# Setting +mcdc.settings.N_particle = 20 +mcdc.settings.N_batch = 2 +mcdc.settings.time_boundary = 1.0 +mcdc.settings.active_bank_buffer = 1000 + +# Tally +t_grid = np.insert(np.logspace(-9, -4, 200), 0, 0.0) +e_min, e_max = 1e-5, 20.0e6 +groups = 500 +energies = np.logspace(np.log10(e_min), np.log10(e_max), groups + 1) + +mcdc.TallyGlobal(scores=["flux"], time=t_grid, energy=energies) + +mcdc.run() diff --git a/test/regression/revise_canon.py b/test/regression/revise_canon.py deleted file mode 100644 index 756593225..000000000 --- a/test/regression/revise_canon.py +++ /dev/null @@ -1,9 +0,0 @@ -import os - - -for item in os.listdir(): - if os.path.isdir(item): - print(item) - os.chdir(item) - os.system("mv output.h5 answer.h5") - os.chdir(r"..") diff --git a/test/regression/run.py b/test/regression/run.py index 70a4a3932..d9a32c388 100644 --- a/test/regression/run.py +++ b/test/regression/run.py @@ -10,6 +10,7 @@ parser.add_argument("--srun", type=int, default=0) parser.add_argument("--name", type=str, default="ALL") parser.add_argument("--skip", type=str, default="NONE") +parser.add_argument("--include_native_physics", default=False, action="store_true") args, unargs = parser.parse_known_args() # Parse @@ -19,12 +20,15 @@ srun = args.srun name = args.name skip = args.skip +include_native_physics = args.include_native_physics + +non_test_files = ["__pycache__", "MCDC-regression_test_data", "tmp"] # Get test names if name == "ALL": names = [] for item in os.listdir(): - if os.path.isdir(item): + if os.path.isdir(item) and item not in non_test_files: names.append(item) else: names = [item for item in os.listdir() if fnmatch.fnmatch(item, name)] @@ -37,9 +41,13 @@ print(Fore.YELLOW + "Note: Skipping %s" % name + Style.RESET_ALL) names.remove(name) -# Skip cache if any -if "__pycache__" in names: - names.remove("__pycache__") +# Remove native physics if not incuded +native_physics_tests = ["pincell", "pincell-k_eigenvalue"] +if not include_native_physics: + for name in native_physics_tests: + print(Fore.YELLOW + "Note: Skipping %s" % name + Style.RESET_ALL) + if name in names: + names.remove(name) # Skip domain decomp tests unless there are 4 MPI processes temp = names.copy() @@ -174,7 +182,14 @@ all_pass = False error_msgs[-1].append( "Differences in %s" - % (name + "/" + result + "\n" + "{}".format(a - b)) + % ( + name + + "/" + + result + + "\n" + + "{}\n".format(a - b) + + "Max difference: {}".format(np.max(np.abs(a - b))) + ) ) print(Fore.RED + " {}: Failed".format(name) + Style.RESET_ALL) diff --git a/test/regression/shooting_stars/answer.h5 b/test/regression/shooting_stars/answer.h5 deleted file mode 100644 index 8ce4bd78d..000000000 Binary files a/test/regression/shooting_stars/answer.h5 and /dev/null differ diff --git a/test/regression/shooting_stars/input.py b/test/regression/shooting_stars/input.py deleted file mode 100644 index e13b37c6e..000000000 --- a/test/regression/shooting_stars/input.py +++ /dev/null @@ -1,105 +0,0 @@ -import numpy as np - -import mcdc - - -# ============================================================================= -# Materials -# ============================================================================= - -# Set materials -fuel = mcdc.material( - capture=np.array([0.45]), - fission=np.array([0.55]), - nu_p=np.array([2.5]), -) - -cover = mcdc.material( - capture=np.array([0.05]), - scatter=np.array([[0.95]]), -) - -water = mcdc.material( - capture=np.array([0.02]), - scatter=np.array([[0.08]]), -) - -# ============================================================================= -# Set an assembly -# ============================================================================= - -# Surfaces -cylinder_z = mcdc.surface("cylinder-z", center=[0.0, 0.0], radius=1.0) -cylinder_x = mcdc.surface("cylinder-x", center=[0.0, 0.0], radius=1.0) - -top_z = mcdc.surface("plane-z", z=2.5) -bot_z = mcdc.surface("plane-z", z=-2.5) -top_x = mcdc.surface("plane-x", x=2.5) -bot_x = mcdc.surface("plane-x", x=-2.5) - -sphere = mcdc.surface("sphere", center=[0.0, 0.0, 0.0], radius=3.0) - -# Cells -pellet_z = -cylinder_z & +bot_z & -top_z -pellet_x = -cylinder_x & +bot_x & -top_x -shooting_star = pellet_z | pellet_x -fuel_shooting_star = mcdc.cell(shooting_star, fuel) -cover_sphere = mcdc.cell(-sphere & ~shooting_star, cover) -water_tank = mcdc.cell(+sphere, water) - -# ============================================================================= -# Copy the assembly via universe cells -# ============================================================================= - -# Set the universe -assembly = mcdc.universe([fuel_shooting_star, cover_sphere, water_tank]) - -# Set container cell surfaces -min_x = mcdc.surface("plane-x", x=-10.0, bc="vacuum") -mid_x = mcdc.surface("plane-x", x=0.0) -max_x = mcdc.surface("plane-x", x=10.0, bc="vacuum") -min_y = mcdc.surface("plane-y", y=-5.0, bc="vacuum") -max_y = mcdc.surface("plane-y", y=5.0, bc="vacuum") -min_z = mcdc.surface("plane-z", z=-5.0, bc="vacuum") -max_z = mcdc.surface("plane-z", z=5.0, bc="vacuum") - -# Make copies via universe cells -container_left = +min_y & -max_y & +min_z & -max_z & +min_x & -mid_x -container_right = +min_y & -max_y & +min_z & -max_z & +mid_x & -max_x -assembly_left = mcdc.cell(container_left, assembly, (-5, 0, 0)) -assembly_right = mcdc.cell(container_right, assembly, (+5, 0, 0), (0, 10, 0)) - -# Root universe -mcdc.universe([assembly_left, assembly_right], root=True) - -# ============================================================================= -# Set source -# ============================================================================= -# Uniform isotropic source throughout the domain - -mcdc.source() - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally: cell-average and cell-edge angular fluxes and currents -mcdc.tally.mesh_tally( - x=np.linspace(-10, 10, 201), - z=np.linspace(-5, 5, 101), - scores=["fission"], -) - -# Setting -mcdc.setting(N_particle=100, active_bank_buff=1000, N_batch=2) - -# Run -mcdc.run() -""" -colors = { - fuel: 'red', - cover: 'gray', - water: 'blue', -} -mcdc.visualize('xz', y=0.0, x=[-11., 11.], z=[-6, 6], pixel=(400, 400), colors=colors) -""" diff --git a/test/regression/slab_absorbium/answer.h5 b/test/regression/slab_absorbium/answer.h5 index b9a51ad02..1a582886a 100644 Binary files a/test/regression/slab_absorbium/answer.h5 and b/test/regression/slab_absorbium/answer.h5 differ diff --git a/test/regression/slab_absorbium/input.py b/test/regression/slab_absorbium/input.py index 7b6545670..bf2037501 100644 --- a/test/regression/slab_absorbium/input.py +++ b/test/regression/slab_absorbium/input.py @@ -1,50 +1,49 @@ import numpy as np -import sys - import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Three slab layers with different purely-absorbing materials # Set materials -m1 = mcdc.material(capture=np.array([1.0])) -m2 = mcdc.material(capture=np.array([1.5])) -m3 = mcdc.material(capture=np.array([2.0])) +m1 = mcdc.MaterialMG(capture=np.array([1.0])) +m2 = mcdc.MaterialMG(capture=np.array([1.5])) +m3 = mcdc.MaterialMG(capture=np.array([2.0])) # Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="vacuum") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=4.0) -s4 = mcdc.surface("plane-z", z=6.0, bc="vacuum") +s1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="vacuum") +s2 = mcdc.Surface.PlaneZ(z=2.0) +s3 = mcdc.Surface.PlaneZ(z=4.0) +s4 = mcdc.Surface.PlaneZ(z=6.0, boundary_condition="vacuum") # Set cells -mcdc.cell(+s1 & -s2, m2) -mcdc.cell(+s2 & -s3, m3) -mcdc.cell(+s3 & -s4, m1) +mcdc.Cell(region=+s1 & -s2, fill=m2) +mcdc.Cell(region=+s2 & -s3, fill=m3) +mcdc.Cell(region=+s3 & -s4, fill=m1) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Uniform isotropic source throughout the domain -mcdc.source(z=[0.0, 6.0], isotropic=True) +mcdc.Source(z=[0.0, 6.0], isotropic=True, energy_group=0) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run mcdc +# ====================================================================================== -# Tally: cell-average and cell-edge angular fluxes and currents -mcdc.tally.mesh_tally( - z=np.linspace(0.0, 6.0, 61), - mu=np.linspace(-1.0, 1.0, 32 + 1), - scores=["flux", "total"], +# Tallies +mcdc.TallySurface(surface=s4, scores=["net-current"]) +mesh = mcdc.MeshStructured(z=np.linspace(0.0, 6.0, 61)) +mcdc.TallyMesh( + mesh=mesh, mu=np.linspace(-1.0, 1.0, 32 + 1), scores=["flux", "collision"] ) -# Setting -mcdc.setting(N_particle=100, N_batch=2) +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 # Run mcdc.run() diff --git a/test/regression/slab_ce/answer.h5 b/test/regression/slab_ce/answer.h5 deleted file mode 100644 index 1fc34e33b..000000000 Binary files a/test/regression/slab_ce/answer.h5 and /dev/null differ diff --git a/test/regression/slab_ce/input.py b/test/regression/slab_ce/input.py deleted file mode 100644 index 4fd0da8b3..000000000 --- a/test/regression/slab_ce/input.py +++ /dev/null @@ -1,77 +0,0 @@ -import numpy as np -import os, h5py -from mpi4py import MPI - -import mcdc - - -# Set the XS library directory -os.environ["MCDC_XSLIB"] = os.getcwd() - -# Create the dummy nuclide (only master, rank 0) -if MPI.COMM_WORLD.Get_rank() == 0: - with h5py.File("dummy_nuclide.h5", "w") as f: - f["A"] = 1.0 - - f["E_xs"] = np.array([0.0, 1.0 - 1e-6, 1.0 + 1e-6, 2e7]) - f["capture"] = np.array([0.01344, 0.01344, 0.00384, 0.00384]) - f["fission"] = np.array([0.06912, 0.06912, 0.00619, 0.00619]) - f["scatter"] = np.array([0.26304, 0.26304, 0.15024, 0.15024]) - - f["E_nu_p"] = np.array([0.0, 1.0 - 1e-6, 1.0 + 1e-6, 2e7]) - f["nu_p"] = np.array([2.5, 2.5, 2.7, 2.7]) - - f["E_chi_p"] = np.array([0.0, 1e5, 2e7]) - f["chi_p"] = np.array([0.0, 0.0, 1.0]) - - f["decay_rate"] = np.zeros(6) - - f["E_nu_d"] = np.array([0.0, 2e7]) - f["nu_d"] = np.zeros((6, 2)) - - f["E_chi_d1"] = np.zeros(0) - f["E_chi_d2"] = np.zeros(0) - f["E_chi_d3"] = np.zeros(0) - f["E_chi_d4"] = np.zeros(0) - f["E_chi_d5"] = np.zeros(0) - f["E_chi_d6"] = np.zeros(0) - f["chi_d1"] = np.zeros(0) - f["chi_d2"] = np.zeros(0) - f["chi_d3"] = np.zeros(0) - f["chi_d4"] = np.zeros(0) - f["chi_d5"] = np.zeros(0) - f["chi_d6"] = np.zeros(0) -MPI.COMM_WORLD.Barrier() - -# Create the material -dummy_material = mcdc.material( - [ - ["dummy_nuclide", 1.0], - ] -) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -s2 = mcdc.surface("plane-x", x=2.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, dummy_material) - -# ============================================================================= -# Set source -# ============================================================================= - -mcdc.source( - x=[0.95, 1.05], - energy=np.array([[0.9, 1.1], [1.0, 1.0]]), -) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], x=np.linspace(0.0, 2.0, 21), E=np.array([0.0, 1.0, 20e6]) -) -mcdc.setting(N_particle=1e3, N_batch=2) -mcdc.run() diff --git a/test/regression/slab_isobeam_td/answer.h5 b/test/regression/slab_isobeam_td/answer.h5 index fad4eaef4..e71988518 100644 Binary files a/test/regression/slab_isobeam_td/answer.h5 and b/test/regression/slab_isobeam_td/answer.h5 differ diff --git a/test/regression/slab_isobeam_td/input.py b/test/regression/slab_isobeam_td/input.py index 9ff2867e7..a39fd27f3 100644 --- a/test/regression/slab_isobeam_td/input.py +++ b/test/regression/slab_isobeam_td/input.py @@ -3,41 +3,48 @@ import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Finite homogeneous pure-absorbing slab # Set materials -m = mcdc.material(capture=np.array([1.0])) +m = mcdc.MaterialMG(capture=np.array([1.0])) # Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=5.0, bc="vacuum") +s1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="vacuum") +s2 = mcdc.Surface.PlaneX(x=5.0, boundary_condition="vacuum") # Set cells -mcdc.cell(+s1 & -s2, m) +mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic beam from left-end -mcdc.source(point=[1e-10, 0.0, 0.0], time=[0.0, 5.0], white_direction=[1.0, 0.0, 0.0]) +mcdc.Source( + position=(0.0, 0.0, 0.0), + white_direction=(1.0, 0.0, 0.0), + energy_group=0, + time=[0.0, 5.0], +) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Tally -mcdc.tally.mesh_tally( +# Tallies +mesh = mcdc.MeshUniform(x=(0.0, 0.1, 50)) +mcdc.TallyMesh( + mesh=mesh, scores=["flux"], - x=np.linspace(0.0, 5.0, 51), - t=np.linspace(0.0, 5.0, 51), + time=np.linspace(0.0, 5.0, 51), ) -# Setting -mcdc.setting(N_particle=100, N_batch=2) +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 # Run mcdc.run() diff --git a/test/regression/slab_isobeam_td_census/answer.h5 b/test/regression/slab_isobeam_td_census/answer.h5 index 0fe977f01..ab5b51c43 100644 Binary files a/test/regression/slab_isobeam_td_census/answer.h5 and b/test/regression/slab_isobeam_td_census/answer.h5 differ diff --git a/test/regression/slab_isobeam_td_census/input.py b/test/regression/slab_isobeam_td_census/input.py index d253ef976..e3157d742 100644 --- a/test/regression/slab_isobeam_td_census/input.py +++ b/test/regression/slab_isobeam_td_census/input.py @@ -3,43 +3,53 @@ import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Finite homogeneous pure-absorbing slab # Set materials -m = mcdc.material(capture=np.array([1.0])) +m = mcdc.MaterialMG(capture=np.array([1.0])) # Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=5.0, bc="vacuum") +s1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="vacuum") +s2 = mcdc.Surface.PlaneX(x=5.0, boundary_condition="vacuum") # Set cells -mcdc.cell(+s1 & -s2, m) +mcdc.Cell(region=+s1 & -s2, fill=m) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic beam from left-end -mcdc.source(point=[1e-10, 0.0, 0.0], time=[0.0, 5.0], white_direction=[1.0, 0.0, 0.0]) +mcdc.Source( + position=(1e-10, 0.0, 0.0), + white_direction=(1.0, 0.0, 0.0), + energy_group=0, + time=[0.0, 5.0], +) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, techniques, and run MC/DC +# ====================================================================================== -# Tally -mcdc.tally.mesh_tally( +# Tallies +mesh = mcdc.MeshUniform(x=(0.0, 0.1, 50)) +mcdc.TallyMesh( + mesh=mesh, scores=["flux"], - x=np.linspace(0.0, 5.0, 51), - t=np.linspace(0.0, 5.0, 51), + time=np.linspace(0.0, 5.0, 51), ) -# Setting -mcdc.setting(N_particle=100, source_bank_buff=5, N_batch=2) -mcdc.time_census(np.linspace(0.0, 5.0, 6)[1:]) -mcdc.population_control() +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 +mcdc.settings.source_bank_buffer_ratio = 5.0 +mcdc.settings.set_time_census(np.linspace(0.0, 5.0, 6)[1:]) + +# Techniques +mcdc.simulation.population_control() # Run mcdc.run() diff --git a/test/regression/slab_reed/answer.h5 b/test/regression/slab_reed/answer.h5 index 059c84126..ea18c4a8d 100644 Binary files a/test/regression/slab_reed/answer.h5 and b/test/regression/slab_reed/answer.h5 differ diff --git a/test/regression/slab_reed/input.py b/test/regression/slab_reed/input.py index caf2336df..35e1b1fac 100644 --- a/test/regression/slab_reed/input.py +++ b/test/regression/slab_reed/input.py @@ -1,52 +1,53 @@ import numpy as np - import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Three slab layers with different materials # Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 # Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) +m1 = mcdc.MaterialMG(capture=np.array([50.0])) +m2 = mcdc.MaterialMG(capture=np.array([5.0])) +m3 = mcdc.MaterialMG(capture=np.array([0.0])) # Vacuum +m4 = mcdc.MaterialMG(capture=np.array([0.1]), scatter=np.array([[0.9]])) # Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=3.0) -s4 = mcdc.surface("plane-z", z=5.0) -s5 = mcdc.surface("plane-z", z=8.0, bc="vacuum") +s1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="reflective") +s2 = mcdc.Surface.PlaneZ(z=2.0) +s3 = mcdc.Surface.PlaneZ(z=3.0) +s4 = mcdc.Surface.PlaneZ(z=5.0) +s5 = mcdc.Surface.PlaneZ(z=8.0, boundary_condition="vacuum") # Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) -mcdc.cell(+s3 & -s4, m3) -mcdc.cell(+s4 & -s5, m4) +mcdc.Cell(region=+s1 & -s2, fill=m1) +mcdc.Cell(region=+s2 & -s3, fill=m2) +mcdc.Cell(region=+s3 & -s4, fill=m3) +mcdc.Cell(region=+s4 & -s5, fill=m4) -# ============================================================================= +# ====================================================================================== # Set source -# ============================================================================= +# ====================================================================================== # Isotropic source in the absorbing medium -mcdc.source(z=[0.0, 2.0], isotropic=True, prob=50.0) +mcdc.Source(z=[0.0, 2.0], isotropic=True, energy_group=0, probability=50.0) # Isotropic source in the first half of the outermost medium, # with 1/100 strength -mcdc.source(z=[5.0, 6.0], isotropic=True, prob=0.5) +mcdc.Source(z=[5.0, 6.0], isotropic=True, energy_group=0, probability=0.5) -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= +# ====================================================================================== +# Set tallies, settings, and run MC/DC +# ====================================================================================== -# Setting -mcdc.setting(N_particle=5000, N_batch=2) +# Tallies +mesh = mcdc.MeshStructured(z=np.linspace(0.0, 8.0, 81)) +mcdc.TallyMesh(mesh=mesh, scores=["flux"]) -# Tally -mcdc.tally.mesh_tally(scores=["flux"], z=np.linspace(0.0, 8.0, 81)) +# Settings +mcdc.settings.N_particle = 4000 +mcdc.settings.N_batch = 2 # Run mcdc.run() diff --git a/test/regression/slab_reed_dd/answer.h5 b/test/regression/slab_reed_dd/answer.h5 deleted file mode 100644 index 059c84126..000000000 Binary files a/test/regression/slab_reed_dd/answer.h5 and /dev/null differ diff --git a/test/regression/slab_reed_dd/input.py b/test/regression/slab_reed_dd/input.py deleted file mode 100644 index 5abb7c23f..000000000 --- a/test/regression/slab_reed_dd/input.py +++ /dev/null @@ -1,52 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different materials -# Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 - -# Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=3.0) -s4 = mcdc.surface("plane-z", z=5.0) -s5 = mcdc.surface("plane-z", z=8.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) -mcdc.cell(+s3 & -s4, m3) -mcdc.cell(+s4 & -s5, m4) - -# ============================================================================= -# Set source -# ============================================================================= - -# Isotropic source in the absorbing medium -mcdc.source(z=[0.0, 2.0], isotropic=True, prob=50.0) - -# Isotropic source in the first half of the outermost medium, -# with 1/100 strength -mcdc.source(z=[5.0, 6.0], isotropic=True, prob=0.5) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally(scores=["flux"], z=np.linspace(0.0, 8.0, 81)) - -# Setting -mcdc.setting(N_particle=5000, N_batch=2) -dd_z = np.array([0.0, 2.0, 3.0, 5.0, 8.0]) -mcdc.domain_decomposition(z=dd_z) -# Run -mcdc.run() diff --git a/test/regression/slab_reed_dd_3d/answer.h5 b/test/regression/slab_reed_dd_3d/answer.h5 deleted file mode 100644 index d033d7ddd..000000000 Binary files a/test/regression/slab_reed_dd_3d/answer.h5 and /dev/null differ diff --git a/test/regression/slab_reed_dd_3d/input.py b/test/regression/slab_reed_dd_3d/input.py deleted file mode 100644 index b0f7d8580..000000000 --- a/test/regression/slab_reed_dd_3d/input.py +++ /dev/null @@ -1,86 +0,0 @@ -import numpy as np - -import mcdc - -# ============================================================================= -# Set model -# ============================================================================= -# Three slab layers with different materials -# Based on William H. Reed, NSE (1971), 46:2, 309-314, DOI: 10.13182/NSE46-309 - -# Set materials -m1 = mcdc.material(capture=np.array([50.0])) -m2 = mcdc.material(capture=np.array([5.0])) -m3 = mcdc.material(capture=np.array([0.0])) # Vacuum -m4 = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-z", z=0.0, bc="reflective") -s2 = mcdc.surface("plane-z", z=2.0) -s3 = mcdc.surface("plane-z", z=3.0) -s4 = mcdc.surface("plane-z", z=5.0) -s5 = mcdc.surface("plane-z", z=8.0, bc="vacuum") -sx1 = mcdc.surface("plane-x", x=0.0, bc="reflective") -sx2 = mcdc.surface("plane-x", x=8.0, bc="vacuum") -sx3 = mcdc.surface("plane-x", x=4.0) -sy1 = mcdc.surface("plane-y", y=0.0, bc="reflective") -sy2 = mcdc.surface("plane-y", y=8.0, bc="vacuum") -sy3 = mcdc.surface("plane-y", y=4.0) - -# Set cells -mcdc.cell(+s1 & -s2 & +sx1 & -sx3 & +sy1 & -sy3, m1) -mcdc.cell(+s2 & -s3 & +sx1 & -sx3 & +sy1 & -sy3, m2) -mcdc.cell(+s3 & -s4 & +sx1 & -sx3 & +sy1 & -sy3, m3) -mcdc.cell(+s4 & -s5 & +sx1 & -sx3 & +sy1 & -sy3, m4) - -mcdc.cell(+s1 & -s2 & +sx3 & -sx2 & +sy1 & -sy3, m1) -mcdc.cell(+s2 & -s3 & +sx3 & -sx2 & +sy1 & -sy3, m2) -mcdc.cell(+s3 & -s4 & +sx3 & -sx2 & +sy1 & -sy3, m3) -mcdc.cell(+s4 & -s5 & +sx3 & -sx2 & +sy1 & -sy3, m4) - -mcdc.cell(+s1 & -s2 & +sx1 & -sx3 & +sy3 & -sy2, m1) -mcdc.cell(+s2 & -s3 & +sx1 & -sx3 & +sy3 & -sy2, m2) -mcdc.cell(+s3 & -s4 & +sx1 & -sx3 & +sy3 & -sy2, m3) -mcdc.cell(+s4 & -s5 & +sx1 & -sx3 & +sy3 & -sy2, m4) - -mcdc.cell(+s1 & -s2 & +sx3 & -sx2 & +sy3 & -sy2, m1) -mcdc.cell(+s2 & -s3 & +sx3 & -sx2 & +sy3 & -sy2, m2) -mcdc.cell(+s3 & -s4 & +sx3 & -sx2 & +sy3 & -sy2, m3) -mcdc.cell(+s4 & -s5 & +sx3 & -sx2 & +sy3 & -sy2, m4) - -# ============================================================================= -# Set source -# ============================================================================= - -# Isotropic source in the absorbing medium -mcdc.source(x=[0.0, 4.0], y=[0.0, 4.0], z=[0.0, 2.0], isotropic=True, prob=50.0) -mcdc.source(x=[4.0, 8.0], y=[0.0, 4.0], z=[0.0, 2.0], isotropic=True, prob=50.0) -mcdc.source(x=[0.0, 4.0], y=[4.0, 8.0], z=[0.0, 2.0], isotropic=True, prob=50.0) -mcdc.source(x=[4.0, 8.0], y=[4.0, 8.0], z=[0.0, 2.0], isotropic=True, prob=50.0) - -# Isotropic source in the first half of the outermost medium, -# with 1/100 strength -mcdc.source(x=[0.0, 4.0], y=[0.0, 4.0], z=[5.0, 6.0], isotropic=True, prob=0.5) -mcdc.source(x=[4.0, 8.0], y=[0.0, 4.0], z=[5.0, 6.0], isotropic=True, prob=0.5) -mcdc.source(x=[0.0, 4.0], y=[4.0, 8.0], z=[5.0, 6.0], isotropic=True, prob=0.5) -mcdc.source(x=[4.0, 8.0], y=[4.0, 8.0], z=[5.0, 6.0], isotropic=True, prob=0.5) - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 8.0, 9), - y=np.linspace(0.0, 8.0, 9), - z=np.linspace(0.0, 8.0, 9), -) - -# Setting -mcdc.setting(N_particle=5000, N_batch=2) -dd_x = np.array([0.0, 4.0, 8.0]) -dd_y = np.array([0.0, 4.0, 8.0]) -dd_z = np.array([0.0, 2.0, 3.0, 5.0, 8.0]) -mcdc.domain_decomposition(x=dd_x, y=dd_y, z=dd_z) -# Run -mcdc.run() diff --git a/test/regression/source_file/answer.h5 b/test/regression/source_file/answer.h5 deleted file mode 100644 index 96a5a8c45..000000000 Binary files a/test/regression/source_file/answer.h5 and /dev/null differ diff --git a/test/regression/source_file/input.py b/test/regression/source_file/input.py deleted file mode 100644 index 626fc0aaa..000000000 --- a/test/regression/source_file/input.py +++ /dev/null @@ -1,62 +0,0 @@ -import numpy as np -from mpi4py import MPI - -import mcdc - -# ============================================================================= -# Set source particles and create the source particle file -# (only master, rank 0) -# ============================================================================= - -if MPI.COMM_WORLD.Get_rank() == 0: - rng = np.random.default_rng(seed=7) - - N = 500 - bank = mcdc.make_particle_bank(N) - - for i in range(N): - particle = bank[i] - particle["x"] = rng.random() * 5.0 - particle["y"] = rng.random() - particle["z"] = rng.random() - particle["t"] = rng.random() * 5.0 - particle["ux"] = 1.0 # All going right - particle["uy"] = 0.0 - particle["uz"] = 0.0 - particle["E"] = 1e6 # Arbitrary - - mcdc.save_particle_bank(bank, "source_particles") -MPI.COMM_WORLD.Barrier() - - -# ============================================================================= -# Set model -# ============================================================================= - -# Set materials -m = mcdc.material(capture=np.array([0.1]), scatter=np.array([[0.9]])) - -# Set surfaces -s1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=5.0, bc="vacuum") - -# Set cells -mcdc.cell(+s1 & -s2, m) - - -# ============================================================================= -# Set tally, setting, and run mcdc -# ============================================================================= - -# Tally -mcdc.tally.mesh_tally( - scores=["flux"], - x=np.linspace(0.0, 5.0, 51), - t=np.linspace(0.0, 5.0, 51), -) - -# Setting -mcdc.setting(source_file="source_particles.h5") - -# Run -mcdc.run() diff --git a/test/regression/sphere_in_cube/answer.h5 b/test/regression/sphere_in_cube/answer.h5 index c382aad8a..cac9813ec 100644 Binary files a/test/regression/sphere_in_cube/answer.h5 and b/test/regression/sphere_in_cube/answer.h5 differ diff --git a/test/regression/sphere_in_cube/input.py b/test/regression/sphere_in_cube/input.py index 1769446eb..10b76f2fd 100644 --- a/test/regression/sphere_in_cube/input.py +++ b/test/regression/sphere_in_cube/input.py @@ -1,57 +1,64 @@ import numpy as np import mcdc -# ============================================================================= +# ====================================================================================== # Set model -# ============================================================================= +# ====================================================================================== # Homogeneous pure-fission sphere inside a pure-scattering cube # Set materials -pure_f = mcdc.material(fission=np.array([1.0]), nu_p=np.array([1.2])) -pure_s = mcdc.material(scatter=np.array([[1.0]])) +pure_f = mcdc.MaterialMG(fission=np.array([1.0]), nu_p=np.array([1.2])) +pure_s = mcdc.MaterialMG(scatter=np.array([[1.0]])) # Set surfaces -sx1 = mcdc.surface("plane-x", x=0.0, bc="vacuum") -sx2 = mcdc.surface("plane-x", x=4.0, bc="vacuum") -sy1 = mcdc.surface("plane-y", y=0.0, bc="vacuum") -sy2 = mcdc.surface("plane-y", y=4.0, bc="vacuum") -sz1 = mcdc.surface("plane-z", z=0.0, bc="vacuum") -sz2 = mcdc.surface("plane-z", z=4.0, bc="vacuum") -sphere = mcdc.surface("sphere", center=[2.0, 2.0, 2.0], radius=1.5) +sx1 = mcdc.Surface.PlaneX(x=0.0, boundary_condition="vacuum") +sx2 = mcdc.Surface.PlaneX(x=4.0, boundary_condition="vacuum") +sy1 = mcdc.Surface.PlaneY(y=0.0, boundary_condition="vacuum") +sy2 = mcdc.Surface.PlaneY(y=4.0, boundary_condition="vacuum") +sz1 = mcdc.Surface.PlaneZ(z=0.0, boundary_condition="vacuum") +sz2 = mcdc.Surface.PlaneZ(z=4.0, boundary_condition="vacuum") +sphere = mcdc.Surface.Sphere(center=[2.0, 2.0, 2.0], radius=1.5) inside_sphere = -sphere inside_box = +sx1 & -sx2 & +sy1 & -sy2 & +sz1 & -sz2 # Set cells # Source -mcdc.cell(inside_box & ~inside_sphere, pure_s) +mcdc.Cell(region=inside_box & ~inside_sphere, fill=pure_s) # Sphere -sphere_cell = mcdc.cell(inside_sphere, pure_f) +sphere_cell = mcdc.Cell(region=inside_sphere, fill=pure_f) # ============================================================================= # Set source # ============================================================================= -# The source pulses in t=[0,5] -mcdc.source(x=[0.0, 4.0], y=[0.0, 4.0], z=[0.0, 4.0], time=[0.0, 50.0], isotropic=True) +mcdc.Source( + x=[0.0, 4.0], + y=[0.0, 4.0], + z=[0.0, 4.0], + isotropic=True, + energy_group=0, + time=[0.0, 50.0], +) # ============================================================================= -# Set tally, setting, and run mcdc +# Set tallies, settings, techniques, and run MC/DC # ============================================================================= -mcdc.tally.mesh_tally( + +# Tallies +mesh = mcdc.MeshUniform(x=(0.0, 4.0, 1), y=(0.0, 4.0, 1), z=(0.0, 4.0, 1)) +mcdc.TallyMesh( + mesh=mesh, scores=["fission"], - x=np.linspace(0.0, 4.0, 2), - y=np.linspace(0.0, 4.0, 2), - z=np.linspace(0.0, 4.0, 2), - # t=np.linspace(0.0, 200.0, 2), ) +mcdc.TallyCell(cell=sphere_cell, scores=["fission"]) +# Settings +mcdc.settings.N_particle = 100 +mcdc.settings.N_batch = 2 -mcdc.tally.cell_tally(sphere_cell, scores=["fission"]) - -# Setting -mcdc.setting(N_particle=100, N_batch=2) -mcdc.implicit_capture() +# Techniques +mcdc.simulation.implicit_capture() # Run mcdc.run() diff --git a/test/regression/variance_deconv/answer.h5 b/test/regression/variance_deconv/answer.h5 deleted file mode 100644 index 587cfaa76..000000000 Binary files a/test/regression/variance_deconv/answer.h5 and /dev/null differ diff --git a/test/regression/variance_deconv/input.py b/test/regression/variance_deconv/input.py deleted file mode 100644 index efa7122f3..000000000 --- a/test/regression/variance_deconv/input.py +++ /dev/null @@ -1,34 +0,0 @@ -import numpy as np -import h5py - -import mcdc - - -# ============================================================================= -# Set model and run -# ============================================================================= - -m1 = mcdc.material(capture=np.array([0.90])) -m2 = mcdc.material(capture=np.array([0.15])) -m3 = mcdc.material(capture=np.array([0.60])) - -s1 = mcdc.surface("plane-x", x=-1.0, bc="vacuum") -s2 = mcdc.surface("plane-x", x=2.0) -s3 = mcdc.surface("plane-x", x=5.0) -s4 = mcdc.surface("plane-x", x=6.0, bc="vacuum") - -mcdc.cell(+s1 & -s2, m1) -mcdc.cell(+s2 & -s3, m2) -mcdc.cell(+s3 & -s4, m3) - -mcdc.source(point=[0.0, 0.0, 0.0], direction=[1.0, 0.0, 0.0]) - -mcdc.tally.surface_tally(s4, scores=["net-current"]) - -mcdc.setting(N_particle=1e1, N_batch=1e1, progress_bar=False) - -mcdc.uq(material=m1, distribution="uniform", capture=np.array([0.7])) -mcdc.uq(material=m2, distribution="uniform", capture=np.array([0.12])) -mcdc.uq(material=m3, distribution="uniform", capture=np.array([0.5])) - -mcdc.run() diff --git a/test/unit/src/mesh/test_structured.py b/test/unit/src/mesh/test_structured.py deleted file mode 100644 index 93225666b..000000000 --- a/test/unit/src/mesh/test_structured.py +++ /dev/null @@ -1,445 +0,0 @@ -import numpy as np - -from mcdc.constant import ( - COINCIDENCE_TOLERANCE, - COINCIDENCE_TOLERANCE_TIME, - INF, -) - -from mcdc.src.mesh.structured import ( - get_indices, - get_crossing_distance, - _grid_index, - _grid_distance, -) - - -def particle(x, y, z, t, ux, uy, uz): - return [{"x": x, "y": y, "z": z, "t": t, "ux": ux, "uy": uy, "uz": uz}] - - -grid = np.array([-6.0, -3.0, -1.0, 0.0, 1.0, 3.0, 6.0]) -Nbin = len(grid) - 1 - -mesh = {} -mesh["x"] = grid -mesh["y"] = grid -mesh["z"] = grid -mesh["t"] = grid -mesh["Nx"] = Nbin -mesh["Ny"] = Nbin -mesh["Nz"] = Nbin -mesh["Nt"] = Nbin - -tiny = COINCIDENCE_TOLERANCE * 0.8 -tiny_time = COINCIDENCE_TOLERANCE_TIME * 0.8 - - -def test_get_indices(): - # Inside bin - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 4.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 5 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 4.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 5 and not outside - - # Outside - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 10.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 10.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - - # At internal grid - ix, iy, iz, it, outside = get_indices( - particle(-3.0, -1.0, 1.0, 3.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == 1 and iy == 2 and iz == 4 and it == 5 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-3.0, -1.0, 1.0, 3.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 3 and it == 5 and not outside - - # At left-most grid - ix, iy, iz, it, outside = get_indices( - particle(-6.0, -6.0, -6.0, 0.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - - # At right-most grid - ix, iy, iz, it, outside = get_indices( - particle(6.0, 6.0, 6.0, 0.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - - # At internal grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(-3.0 + tiny, -1.0 + tiny, 1.0 + tiny, 3.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 1 and iy == 2 and iz == 4 and it == 5 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-3.0 - tiny, -1.0 - tiny, 1.0 - tiny, 3.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 1 and iy == 2 and iz == 4 and it == 5 and not outside - ix, iy, iz, it, outside = get_indices( - particle( - -3.0 + tiny, -1.0 + tiny, 1.0 + tiny, 3.0 + tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == 0 and iy == 1 and iz == 3 and it == 5 and not outside - ix, iy, iz, it, outside = get_indices( - particle( - -3.0 - tiny, -1.0 - tiny, 1.0 - tiny, 3.0 - tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == 0 and iy == 1 and iz == 3 and it == 5 and not outside - - # At left-most grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(-6.0 + tiny, -6.0 + tiny, -6.0 + tiny, 0.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-6.0 - tiny, -6.0 - tiny, -6.0 - tiny, 0.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle( - -6.0 + tiny, -6.0 + tiny, -6.0 + tiny, 0.0 + tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle( - -6.0 - tiny, -6.0 - tiny, -6.0 - tiny, 0.0 - tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - - # At right-most grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(6.0 + tiny, 6.0 + tiny, 6.0 + tiny, 0.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 - tiny, 6.0 - tiny, 6.0 - tiny, 0.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 + tiny, 6.0 + tiny, 6.0 + tiny, 0.0 + tiny_time, -1.0, -1.0, -1.0), - mesh, - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 - tiny, 6.0 - tiny, 6.0 - tiny, 0.0 - tiny_time, -1.0, -1.0, -1.0), - mesh, - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - - -def test_get_corssing_distance(): - # Inside bin - distance = get_crossing_distance( - particle(-3.2, -3.3, -3.4, -3.5, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.2 / 0.4) - distance = get_crossing_distance( - particle(-3.2, -3.3, -5.9, -3.5, 0.4, 0.4, -0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.1 / 0.4) - - # Outside, moving away - distance = get_crossing_distance( - particle(8.2, -3.3, -3.4, -3.5, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, INF) - - # Outside, moving closer - distance = get_crossing_distance( - particle(-6.1, -3.3, -3.4, -3.5, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.1 / 0.4) - - # At internal grid - distance = get_crossing_distance( - particle(-3.0, -3.0, -3.0, -3.0, 0.4, 0.3, 0.2), 1.0, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-3.0, -3.0, -3.0, -3.0, -0.4, -0.3, -0.2), -1.0, mesh - ) - assert np.isclose(distance, 3.0) - - # At left-most grid, going right - distance = get_crossing_distance( - particle(-6.0, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - - # At left-most grid, going left - distance = get_crossing_distance( - particle(-6.0, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going right - distance = get_crossing_distance( - particle(6.0, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going left - distance = get_crossing_distance( - particle(6.0, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - - # At internal grid (within tolerance) - distance = get_crossing_distance( - particle(-3.0 + tiny, -3.0, -3.0, -3.0, 1.0, 0.3, 0.2), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-3.0 - tiny, -3.0, -3.0, -3.0, 1.0, 0.3, 0.2), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-3.0 + tiny, -3.0, -3.0, -3.0, -1.0, -0.3, -0.2), -1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - distance = get_crossing_distance( - particle(-3.0 - tiny, -3.0, -3.0, -3.0, -1.0, -0.3, -0.2), -1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - - # At left-most grid, going right (within tolerance) - distance = get_crossing_distance( - particle(-6.0 + tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - distance = get_crossing_distance( - particle(-6.0 - tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - - # At left-most grid, going left (within tolerance) - distance = get_crossing_distance( - particle(-6.0 + tiny, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - distance = get_crossing_distance( - particle(-6.0 - tiny, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going right (within tolerance) - distance = get_crossing_distance( - particle(6.0 + tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - distance = get_crossing_distance( - particle(6.0 - tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going left (within tolerance) - distance = get_crossing_distance( - particle(6.0 + tiny, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - distance = get_crossing_distance( - particle(6.0 - tiny, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 3.0) - - -def test__grid_index(): - # Inside bin, going right - assert np.isclose(_grid_index(-3.2, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0) - assert np.isclose(_grid_index(3.2, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5) - - # Inside bin, going left - assert np.isclose(_grid_index(-3.2, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0) - assert np.isclose(_grid_index(3.2, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5) - - # At internal grid, going right - assert np.isclose(_grid_index(3.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5) - assert np.isclose(_grid_index(-3.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 1) - - # At internal grid, going left - assert np.isclose(_grid_index(3.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 4) - assert np.isclose(_grid_index(-3.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0) - - # At left-most grid, going right - assert np.isclose(_grid_index(-6.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0) - - # At right-most grid, going left - assert np.isclose(_grid_index(6.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5) - - # At internal grid (within tolerance), going right - assert np.isclose( - _grid_index(3.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5 - ) - assert np.isclose( - _grid_index(3.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5 - ) - assert np.isclose( - _grid_index(-3.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 1 - ) - assert np.isclose( - _grid_index(-3.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 1 - ) - - # At internal grid (within tolerance), going left - assert np.isclose( - _grid_index(3.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 4 - ) - assert np.isclose( - _grid_index(3.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 4 - ) - assert np.isclose( - _grid_index(-3.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0 - ) - assert np.isclose( - _grid_index(-3.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0 - ) - - # At left-most grid (within tolerance), going right - assert np.isclose( - _grid_index(-6.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0 - ) - assert np.isclose( - _grid_index(-6.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0 - ) - - # At right-most grid (within tolerance), going left - assert np.isclose( - _grid_index(6.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5 - ) - assert np.isclose( - _grid_index(6.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 5 - ) - - -def test__grid_distance(): - # Inside bin, going right - assert np.isclose( - _grid_distance(-3.2, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0.2 / 0.4 - ) - assert np.isclose( - _grid_distance(3.2, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.8 / 0.4 - ) - - # Inside bin, going left - assert np.isclose( - _grid_distance(-3.2, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.8 / 0.4 - ) - assert np.isclose( - _grid_distance(3.2, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 0.2 / 0.4 - ) - - # Outside, moving closer - assert np.isclose( - _grid_distance(8.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.0 / 0.4 - ) - assert np.isclose( - _grid_distance(-8.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.0 / 0.4 - ) - - # At internal grid, going right - assert np.isclose( - _grid_distance(3.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 3.0 / 0.4 - ) - assert np.isclose( - _grid_distance(-3.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.0 / 0.4 - ) - - # At internal grid, going left - assert np.isclose( - _grid_distance(3.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 2.0 / 0.4 - ) - assert np.isclose( - _grid_distance(-3.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 3.0 / 0.4 - ) - - # At left-most grid, going right - assert np.isclose( - _grid_distance(-6.0, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 3.0 / 0.4 - ) - - # At right-most grid, going left - assert np.isclose( - _grid_distance(6.0, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), 3.0 / 0.4 - ) - - # At internal grid (within tolerance), going right - assert np.isclose( - _grid_distance(3.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - assert np.isclose( - _grid_distance(3.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-3.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-3.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At internal grid (within tolerance), going left - assert np.isclose( - _grid_distance(3.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(3.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-3.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-3.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - - # At left-most grid (within tolerance), going right - assert np.isclose( - _grid_distance(-6.0 + tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-6.0 - tiny, 0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - - # At right-most grid (within tolerance), going left - assert np.isclose( - _grid_distance(6.0 + tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) - assert np.isclose( - _grid_distance(6.0 - tiny, -0.4, grid, Nbin + 1, COINCIDENCE_TOLERANCE), - 3.0 / 0.4, - ) diff --git a/test/unit/src/mesh/test_uniform.py b/test/unit/src/mesh/test_uniform.py deleted file mode 100644 index ebb51351e..000000000 --- a/test/unit/src/mesh/test_uniform.py +++ /dev/null @@ -1,488 +0,0 @@ -import numpy as np - -from mcdc.constant import ( - COINCIDENCE_TOLERANCE, - COINCIDENCE_TOLERANCE_TIME, - INF, -) - -from mcdc.src.mesh.uniform import ( - get_indices, - get_crossing_distance, - _grid_index, - _grid_distance, -) - - -def particle(x, y, z, t, ux, uy, uz): - return [{"x": x, "y": y, "z": z, "t": t, "ux": ux, "uy": uy, "uz": uz}] - - -grid = np.array([-6.0, -3.0, -1.0, 0.0, 1.0, 3.0, 6.0]) - -mesh = {} -mesh["x0"] = -6.0 -mesh["y0"] = -6.0 -mesh["z0"] = -6.0 -mesh["t0"] = -6.0 -mesh["dx"] = 2.0 -mesh["dy"] = 2.0 -mesh["dz"] = 2.0 -mesh["dt"] = 2.0 -mesh["Nx"] = 6 -mesh["Ny"] = 6 -mesh["Nz"] = 6 -mesh["Nt"] = 6 - -tiny = COINCIDENCE_TOLERANCE * 0.8 -tiny_time = COINCIDENCE_TOLERANCE_TIME * 0.8 - - -def test_get_indices(): - # Inside bin - ix, iy, iz, it, outside = get_indices( - particle(-5.2, -3.2, -1.2, 1.2, 1.0, 1.0, 1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-5.2, -3.2, -1.2, 1.2, -1.0, -1.0, -1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 3 and not outside - - # Outside - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 10.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(-5.0, -2.0, -0.5, 10.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - - # At internal grid - ix, iy, iz, it, outside = get_indices( - particle(-4.0, -2.0, 0.0, 2.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == 1 and iy == 2 and iz == 3 and it == 4 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-4.0, -2.0, 0.0, 2.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 4 and not outside - - # At left-most grid - ix, iy, iz, it, outside = get_indices( - particle(-6.0, -6.0, -6.0, 0.0, 1.0, 1.0, 1.0), mesh - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - - # At right-most grid - ix, iy, iz, it, outside = get_indices( - particle(6.0, 6.0, 6.0, 0.0, -1.0, -1.0, -1.0), mesh - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - - # At internal grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(-4.0 + tiny, -2.0 + tiny, 0.0 + tiny, 2.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 1 and iy == 2 and iz == 3 and it == 4 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-4.0 - tiny, -2.0 - tiny, 0.0 - tiny, 2.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 1 and iy == 2 and iz == 3 and it == 4 and not outside - - ix, iy, iz, it, outside = get_indices( - particle( - -4.0 + tiny, -2.0 + tiny, 0.0 + tiny, 2.0 + tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 4 and not outside - ix, iy, iz, it, outside = get_indices( - particle( - -4.0 - tiny, -2.0 - tiny, 0.0 - tiny, 2.0 - tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == 0 and iy == 1 and iz == 2 and it == 4 and not outside - - # At left-most grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(-6.0 + tiny, -6.0 + tiny, -6.0 + tiny, 0.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle(-6.0 - tiny, -6.0 - tiny, -6.0 - tiny, 0.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == 0 and iy == 0 and iz == 0 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle( - -6.0 + tiny, -6.0 + tiny, -6.0 + tiny, 0.0 + tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle( - -6.0 - tiny, -6.0 - tiny, -6.0 - tiny, 0.0 - tiny_time, -1.0, -1.0, -1.0 - ), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - - # At right-most grid (within tolerance) - ix, iy, iz, it, outside = get_indices( - particle(6.0 + tiny, 6.0 + tiny, 6.0 + tiny, 0.0 + tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 - tiny, 6.0 - tiny, 6.0 - tiny, 0.0 - tiny_time, 1.0, 1.0, 1.0), - mesh, - ) - assert ix == -1 and iy == -1 and iz == -1 and it == -1 and outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 + tiny, 6.0 + tiny, 6.0 + tiny, 0.0 + tiny_time, -1.0, -1.0, -1.0), - mesh, - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - ix, iy, iz, it, outside = get_indices( - particle(6.0 - tiny, 6.0 - tiny, 6.0 - tiny, 0.0 - tiny_time, -1.0, -1.0, -1.0), - mesh, - ) - assert ix == 5 and iy == 5 and iz == 5 and it == 3 and not outside - - --6, -4, -2, 0, 2, 4, 6 - - -def test_get_corssing_distance(): - # Inside bin - distance = get_crossing_distance( - particle(-4.2, -3.2, -1.2, 1.2, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.2 / 0.4) - distance = get_crossing_distance( - particle(-4.2, -3.2, 0.1, 1.2, 0.4, 0.4, -0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.1 / 0.4) - - # Outside, moving away - distance = get_crossing_distance( - particle(8.2, -3.3, -3.4, -3.5, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, INF) - - # Outside, moving closer - distance = get_crossing_distance( - particle(-6.1, -3.3, -3.4, -3.5, 0.4, 0.4, 0.4), 1.0 / 0.4, mesh - ) - assert np.isclose(distance, 0.1 / 0.4) - - # At internal grid - distance = get_crossing_distance( - particle(-4.0, -4.0, -4.0, -4.0, 0.4, 0.3, 0.2), 1.0, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-4.0, -4.0, -4.0, -4.0, -0.4, -0.3, -0.2), -1.0, mesh - ) - assert np.isclose(distance, 2.0) - - # At left-most grid, going right - distance = get_crossing_distance( - particle(-6.0, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - - # At left-most grid, going left - distance = get_crossing_distance( - particle(-6.0, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going right - distance = get_crossing_distance( - particle(6.0, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going left - distance = get_crossing_distance( - particle(6.0, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - - # At internal grid (within tolerance) - distance = get_crossing_distance( - particle(-4.0 + tiny, -4.0, -4.0, -4.0, 1.0, 0.3, 0.2), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-4.0 - tiny, -4.0, -4.0, -4.0, 1.0, 0.3, 0.2), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-4.0 + tiny, -3.0, -3.0, -3.0, -1.0, -0.3, -0.2), -1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-4.0 - tiny, -3.0, -3.0, -3.0, -1.0, -0.3, -0.2), -1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - - # At left-most grid, going right (within tolerance) - distance = get_crossing_distance( - particle(-6.0 + tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(-6.0 - tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - - # At left-most grid, going left (within tolerance) - distance = get_crossing_distance( - particle(-6.0 + tiny, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - distance = get_crossing_distance( - particle(-6.0 - tiny, -3.0, -3.0, -3.0, -0.1, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going right (within tolerance) - distance = get_crossing_distance( - particle(6.0 + tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - distance = get_crossing_distance( - particle(6.0 - tiny, -3.0, -3.0, -3.0, 1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, INF) - - # At right-most grid, going left (within tolerance) - distance = get_crossing_distance( - particle(6.0 + tiny, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - distance = get_crossing_distance( - particle(6.0 - tiny, -3.0, -3.0, -3.0, -1.0, 0.1, 0.1), 1.0 / 0.1, mesh - ) - assert np.isclose(distance, 2.0) - - -def test__grid_index(): - # Inside bin, going right - assert np.isclose( - _grid_index(-3.2, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 1 - ) - assert np.isclose( - _grid_index(3.2, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 4 - ) - - # Inside bin, going left - assert np.isclose( - _grid_index(-3.2, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 1 - ) - assert np.isclose( - _grid_index(3.2, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 4 - ) - - # At internal grid, going right - assert np.isclose( - _grid_index(2.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 4 - ) - assert np.isclose( - _grid_index(-2.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 2 - ) - - # At internal grid, going left - assert np.isclose( - _grid_index(2.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 3 - ) - assert np.isclose( - _grid_index(-2.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 1 - ) - - # At left-most grid, going right - assert np.isclose( - _grid_index(-6.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 0 - ) - - # At right-most grid, going left - assert np.isclose( - _grid_index(6.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 5 - ) - - # At internal grid (within tolerance), going right - assert np.isclose( - _grid_index(2.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 4 - ) - assert np.isclose( - _grid_index(2.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 4 - ) - assert np.isclose( - _grid_index(-2.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 2 - ) - assert np.isclose( - _grid_index(-2.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 2 - ) - - # At internal grid (within tolerance), going left - assert np.isclose( - _grid_index(2.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 3 - ) - assert np.isclose( - _grid_index(2.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 3 - ) - assert np.isclose( - _grid_index(-2.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 1 - ) - assert np.isclose( - _grid_index(-2.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 1 - ) - - # At left-most grid (within tolerance), going right - assert np.isclose( - _grid_index(-6.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 0 - ) - assert np.isclose( - _grid_index(-6.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 0 - ) - - # At right-most grid (within tolerance), going left - assert np.isclose( - _grid_index(6.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 5 - ) - assert np.isclose( - _grid_index(6.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), 5 - ) - - -def test__grid_distance(): - # Inside bin, going right - assert np.isclose( - _grid_distance(-3.2, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 1.2 / 0.4, - ) - assert np.isclose( - _grid_distance(3.2, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 0.8 / 0.4, - ) - - # Inside bin, going left - assert np.isclose( - _grid_distance(-3.2, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 0.8 / 0.4, - ) - assert np.isclose( - _grid_distance(3.2, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 1.2 / 0.4, - ) - - # Outside, moving closer - assert np.isclose( - _grid_distance(8.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-8.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At internal grid, going right - assert np.isclose( - _grid_distance(2.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-2.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At internal grid, going left - assert np.isclose( - _grid_distance(2.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-2.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At left-most grid, going right - assert np.isclose( - _grid_distance(-6.0, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At right-most grid, going left - assert np.isclose( - _grid_distance(6.0, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At internal grid (within tolerance), going right - assert np.isclose( - _grid_distance(2.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(2.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-2.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-2.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At internal grid (within tolerance), going left - assert np.isclose( - _grid_distance(2.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(2.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance( - -2.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE - ), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance( - -2.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE - ), - 2.0 / 0.4, - ) - - # At left-most grid (within tolerance), going right - assert np.isclose( - _grid_distance(-6.0 + tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(-6.0 - tiny, 0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - - # At right-most grid (within tolerance), going left - assert np.isclose( - _grid_distance(6.0 + tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) - assert np.isclose( - _grid_distance(6.0 - tiny, -0.4, mesh["x0"], mesh["dx"], COINCIDENCE_TOLERANCE), - 2.0 / 0.4, - ) diff --git a/test/unit/src/surface/test_common.py b/test/unit/src/surface/test_common.py deleted file mode 100644 index e4d69aa83..000000000 --- a/test/unit/src/surface/test_common.py +++ /dev/null @@ -1,129 +0,0 @@ -import numpy as np - -from mcdc.constant import INF -from mcdc.src.surface.common import ( - _get_move_idx, - _translate_particle_position, - _translate_particle_direction, -) - - -def particle(x, y, z, t, ux, uy, uz): - return {"x": x, "y": y, "z": z, "t": t, "ux": ux, "uy": uy, "uz": uz} - - -time_grid = np.array((0.0, 1.0, 3.0, 6.0, 10.0, INF)) -N_move = len(time_grid) - 1 -move_translations = np.zeros((N_move + 1, 3)) -move_velocities = np.zeros((N_move, 3)) - -for i in range(N_move - 1): - move_translations[i + 1][0] = 1.0 * (i + 1) - move_translations[i + 1][1] = 2.0 * (i + 1) - move_translations[i + 1][2] = 3.0 * (i + 1) - move_velocities[i] = (move_translations[i + 1] - move_translations[i]) / ( - time_grid[i + 1] - time_grid[i] - ) -move_translations[-1] = move_translations[-2] - -surface = { - "N_move": N_move, - "move_translations": move_translations, - "move_velocities": move_velocities, - "move_time_grid": time_grid, -} - - -def test_get_move_idx(): - # In bin - result = _get_move_idx(0.4, surface) - assert np.isclose(result, 0) - result = _get_move_idx(5.4, surface) - assert np.isclose(result, 2) - result = _get_move_idx(15.0, surface) - assert np.isclose(result, 4) - - # At grid - result = _get_move_idx(0.0, surface) - assert np.isclose(result, 0) - result = _get_move_idx(1.0, surface) - assert np.isclose(result, 1) - result = _get_move_idx(3.0, surface) - assert np.isclose(result, 2) - result = _get_move_idx(6.0, surface) - assert np.isclose(result, 3) - result = _get_move_idx(10.0, surface) - assert np.isclose(result, 4) - - -def test_translate_particle_position(): - u = (1.0 / 3.0) ** 0.5 - - # At grid - t = 6.0 - P = particle(5.0, 3.0, 8.0, t, u, -u, u) - idx = _get_move_idx(t, surface) - _translate_particle_position([P], surface, idx) - x = 5.0 - move_translations[3][0] - y = 3.0 - move_translations[3][1] - z = 8.0 - move_translations[3][2] - assert np.isclose(P["x"], x) - assert np.isclose(P["y"], y) - assert np.isclose(P["z"], z) - assert np.isclose(P["t"], t) - assert np.isclose(P["ux"], u) - assert np.isclose(P["uy"], -u) - assert np.isclose(P["uz"], u) - - # In bin - t = 6.5 - P = particle(5.0, 3.0, 8.0, t, u, -u, u) - idx = _get_move_idx(t, surface) - _translate_particle_position([P], surface, idx) - x = 5.0 - move_translations[3][0] - move_velocities[3][0] * (t - time_grid[3]) - y = 3.0 - move_translations[3][1] - move_velocities[3][1] * (t - time_grid[3]) - z = 8.0 - move_translations[3][2] - move_velocities[3][2] * (t - time_grid[3]) - assert np.isclose(P["x"], x) - assert np.isclose(P["y"], y) - assert np.isclose(P["z"], z) - assert np.isclose(P["t"], t) - assert np.isclose(P["ux"], u) - assert np.isclose(P["uy"], -u) - assert np.isclose(P["uz"], u) - - -def test_translate_particle_direction(): - speed = 2.0 - u = (1.0 / 3.0) ** 0.5 - - # At grid - t = 6.0 - P = particle(5.0, 3.0, 8.0, t, u, -u, u) - idx = _get_move_idx(t, surface) - _translate_particle_direction([P], speed, surface, idx) - ux = u - move_velocities[3][0] / speed - uy = -u - move_velocities[3][1] / speed - uz = u - move_velocities[3][2] / speed - assert np.isclose(P["x"], 5.0) - assert np.isclose(P["y"], 3.0) - assert np.isclose(P["z"], 8.0) - assert np.isclose(P["t"], 6.0) - assert np.isclose(P["ux"], ux) - assert np.isclose(P["uy"], uy) - assert np.isclose(P["uz"], uz) - - # At grid - t = 6.5 - P = particle(5.0, 3.0, 8.0, t, u, -u, u) - idx = _get_move_idx(t, surface) - _translate_particle_direction([P], speed, surface, idx) - ux = u - move_velocities[3][0] / speed - uy = -u - move_velocities[3][1] / speed - uz = u - move_velocities[3][2] / speed - assert np.isclose(P["x"], 5.0) - assert np.isclose(P["y"], 3.0) - assert np.isclose(P["z"], 8.0) - assert np.isclose(P["t"], 6.5) - assert np.isclose(P["ux"], ux) - assert np.isclose(P["uy"], uy) - assert np.isclose(P["uz"], uz) diff --git a/test/unit/src/surface/test_plane_z.py b/test/unit/src/surface/test_plane_z.py deleted file mode 100644 index d4b45cbe8..000000000 --- a/test/unit/src/surface/test_plane_z.py +++ /dev/null @@ -1,1026 +0,0 @@ -import numpy as np - -from mcdc.constant import ( - COINCIDENCE_TOLERANCE, - INF, - SURFACE_LINEAR, - SURFACE_PLANE_Z, -) - -import mcdc.src.surface.common as common - -from mcdc.src.surface.plane_z import ( - evaluate, - reflect, - get_normal_component, - get_distance, -) - - -def particle_container(z, uz, t=0.0): - u_ = np.sqrt(0.5 * (1.0 - uz**2)) - return [{"x": -12.0, "y": 24.0, "z": z, "t": t, "ux": u_, "uy": -u_, "uz": uz}] - - -def surface(z): - return {"type": SURFACE_LINEAR + SURFACE_PLANE_Z, "J": -z, "moving": False} - - -tiny = COINCIDENCE_TOLERANCE * 0.8 - - -# ===================================================================================== -# Basics -# ===================================================================================== - - -def test_evaluate(): - # Positive side - result = evaluate(particle_container(3.0, -0.4), surface(1.0)) - assert np.isclose(result, 2.0) - # Negative side - result = evaluate(particle_container(5.0, 0.2), surface(9.0)) - assert np.isclose(result, -4.0) - - -def test_reflect(): - # From positive direction - P = particle_container(3.0, 0.2) - reflect(P, surface(123.0)) - assert np.isclose(P[0]["uz"], -0.2) - # From negative direction - P = particle_container(4.0, -0.1) - reflect(P, surface(-23.0)) - assert np.isclose(P[0]["uz"], 0.1) - - -def test_get_normal_component(): - # Positive direction - result = get_normal_component(particle_container(3.0, 0.4), surface(1.0)) - assert np.isclose(result, 0.4) - # Negative direction - result = get_normal_component(particle_container(5.0, -0.2), surface(9.0)) - assert np.isclose(result, -0.2) - - -def test_get_distance(): - # Positive side, moving closer - result = get_distance(particle_container(3.0, -0.4), surface(1.0)) - assert np.isclose(result, 5.0) - # Positive side, moving away - result = get_distance(particle_container(4.0, 0.3), surface(1.0)) - assert np.isclose(result, INF) - - # Negative side, moving closer - result = get_distance(particle_container(-3.0, 0.4), surface(1.0)) - assert np.isclose(result, 10.0) - # Negative side, moving away - result = get_distance(particle_container(-4.0, -0.3), surface(1.0)) - assert np.isclose(result, INF) - - # Positive side, parallel - result = get_distance(particle_container(4.0, 0.0), surface(1.0)) - assert np.isclose(result, INF) - # Positive side, parallel - result = get_distance(particle_container(-4.0, 0.0), surface(1.0)) - assert np.isclose(result, INF) - - # At surface on the positive side, moving away - result = get_distance(particle_container(1.0 + tiny, 0.4), surface(1.0)) - assert np.isclose(result, INF) - # At surface on the positive side, moving closer - result = get_distance(particle_container(1.0 + tiny, -0.4), surface(1.0)) - assert np.isclose(result, INF) - - # At surface on the negative side, moving away - result = get_distance(particle_container(1.0 - tiny, -0.4), surface(1.0)) - assert np.isclose(result, INF) - # At surface on the negative side, moving closer - result = get_distance(particle_container(1.0 - tiny, 0.4), surface(1.0)) - assert np.isclose(result, INF) - - -# ===================================================================================== -# Integrated -# ===================================================================================== - -Z = 10.0 -time_grid = np.array([0.0, 5.0, 10.0, 15.0, INF]) -N_move = len(time_grid) - 1 -velocities = np.zeros((N_move, 3)) -velocities[0, 2] = -1.0 -velocities[1, 2] = 2.0 -velocities[2, 2] = -3.0 -translations = np.zeros((N_move + 1, 3)) -for i in range(N_move): - translations[i + 1] = translations[i] + velocities[i] * ( - time_grid[i + 1] - time_grid[i] - ) - -moving_surface = { - "type": SURFACE_LINEAR + SURFACE_PLANE_Z, - "J": -Z, - "moving": True, - "N_move": N_move, - "move_time_grid": time_grid, - "move_translations": translations, - "move_velocities": velocities, -} - - -def test_common_reflect(): - # Copied from test_reflect - - # From positive direction - P = particle_container(3.0, 0.2) - common.reflect(P, surface(123.0)) - assert np.isclose(P[0]["uz"], -0.2) - # From negative direction - P = particle_container(4.0, -0.1) - common.reflect(P, surface(-23.0)) - assert np.isclose(P[0]["uz"], 0.1) - - -def test_common_evaluate(): - # ================================================================================= - # Static - # ================================================================================= - # Copied from test_evaluate - - # Positive side - result = common.evaluate(particle_container(3.0, -0.4), surface(1.0)) - assert np.isclose(result, 2.0) - # Negative side - result = common.evaluate(particle_container(5.0, 0.2), surface(9.0)) - assert np.isclose(result, -4.0) - - # ================================================================================= - # Moving - # ================================================================================= - - # First bin, positive side - result = common.evaluate(particle_container(10.0, -0.4, 3.0), moving_surface) - assert np.isclose(result, 3.0) - # First bin, negative side - result = common.evaluate(particle_container(1.0, 0.2, 3.0), moving_surface) - assert np.isclose(result, -6.0) - - # First bin, at grid, positive side - result = common.evaluate(particle_container(10.0, -0.4, 5.0), moving_surface) - assert np.isclose(result, 5.0) - # First bin, at grid, negative side - result = common.evaluate(particle_container(1.0, 0.2, 5.0), moving_surface) - assert np.isclose(result, -4.0) - - # Middle bin, positive side - result = common.evaluate(particle_container(10.0, -0.4, 12.0), moving_surface) - assert np.isclose(result, 1.0) - # Middle bin, negative side - result = common.evaluate(particle_container(1.0, 0.2, 12.0), moving_surface) - assert np.isclose(result, -8.0) - - # Middle bin, at grid, positive side - result = common.evaluate(particle_container(10.0, -0.4, 15.0), moving_surface) - assert np.isclose(result, 10.0) - # Middle bin, at grid, negative side - result = common.evaluate(particle_container(-5.0, 0.2, 15.0), moving_surface) - assert np.isclose(result, -5.0) - - # Last bin, positive side - result = common.evaluate(particle_container(10.0, -0.4, 17.0), moving_surface) - assert np.isclose(result, 10.0) - # Last bin, negative side - result = common.evaluate(particle_container(-5.0, 0.2, 18.0), moving_surface) - assert np.isclose(result, -5.0) - - -def test_common_get_normal_component(): - # ================================================================================= - # Static - # ================================================================================= - # Copied from test_get_normal_component - - # Positive direction - result = common.get_normal_component( - particle_container(3.0, 0.4), 1.0, surface(1.0) - ) - assert np.isclose(result, 0.4) - # Negative direction - result = common.get_normal_component( - particle_container(5.0, -0.2), 1.0, surface(9.0) - ) - assert np.isclose(result, -0.2) - - # ================================================================================= - # Moving - # ================================================================================= - - # First move bin, same direction, faster - result = common.get_normal_component( - particle_container(3.0, -0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, -0.2 / 3.0) - # First move bin, same direction, slower - result = common.get_normal_component( - particle_container(3.0, -0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, 0.2 / 2.0) - # First move bin, same direction, same speed - result = common.get_normal_component( - particle_container(3.0, -0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, 0.0) - - # First move bin, opposite direction, faster - result = common.get_normal_component( - particle_container(3.0, 0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, 2.2 / 3.0) - # First move bin, opposite direction, slower - result = common.get_normal_component( - particle_container(3.0, 0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, 1.8 / 2.0) - # First move bin, opposite direction, same speed - result = common.get_normal_component( - particle_container(3.0, 0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, 2.0 * 0.4) - - # First move bin, at grid, same direction, faster - result = common.get_normal_component( - particle_container(3.0, 0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, 0.4 / 6.0) - # First move bin, at grid, same direction, slower - result = common.get_normal_component( - particle_container(3.0, 0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, -1.2 / 2.0) - # First move bin, at grid, same direction, same speed - result = common.get_normal_component( - particle_container(3.0, 0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, 0.0) - - # First move bin, at grid, opposite direction, faster - result = common.get_normal_component( - particle_container(3.0, -0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, -4.4 / 6.0) - # First move bin, at grid, opposite direction, slower - result = common.get_normal_component( - particle_container(3.0, -0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, -2.8 / 2.0) - # First move bin, at grid, opposite direction, same speed - result = common.get_normal_component( - particle_container(3.0, -0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, -4.0 / 5.0) - - # Middle move bin, same direction, faster - result = common.get_normal_component( - particle_container(3.0, 0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, 0.4 / 6.0) - # Middle move bin, same direction, slower - result = common.get_normal_component( - particle_container(3.0, 0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, -1.2 / 2.0) - # Middle move bin, same direction, same speed - result = common.get_normal_component( - particle_container(3.0, 0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, 0.0) - - # Middle move bin, opposite direction, faster - result = common.get_normal_component( - particle_container(3.0, -0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, -4.4 / 6.0) - # Middle move bin, opposite direction, slower - result = common.get_normal_component( - particle_container(3.0, -0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, -2.8 / 2.0) - # Middle move bin, opposite direction, same speed - result = common.get_normal_component( - particle_container(3.0, -0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, -4.0 / 5.0) - - # Middle move bin, at grid, same direction, faster - result = common.get_normal_component( - particle_container(3.0, -0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, -0.2 / 8.0) - # Middle move bin, at grid, same direction, slower - result = common.get_normal_component( - particle_container(3.0, -0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, 2.2 / 2.0) - # Middle move bin, at grid, same direction, same speed - result = common.get_normal_component( - particle_container(3.0, -0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, 0.0) - - # Middle move bin, at grid, opposite direction, faster - result = common.get_normal_component( - particle_container(3.0, 0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, 6.2 / 8.0) - # Middle move bin, at grid, opposite direction, slower - result = common.get_normal_component( - particle_container(3.0, 0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, 3.8 / 2.0) - # Middle move bin, at grid, opposite direction, same speed - result = common.get_normal_component( - particle_container(3.0, 0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, 6.0 / 7.5) - - # Last move bin, positive direction - result = common.get_normal_component( - particle_container(3.0, 0.4, 38.5), 6.0, moving_surface - ) - assert np.isclose(result, 0.4) - # Last move bin, negative direction - result = common.get_normal_component( - particle_container(3.0, -0.4, 38.5), 6.0, moving_surface - ) - assert np.isclose(result, -0.4) - - -def test_check_sense(): - # ================================================================================= - # Static - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(3.0, -0.4), 1.0, surface(1.0)) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.2), 1.0, surface(9.0)) - assert np.isclose(result, False) - - # At surface, positive side, positive direction - result = common.check_sense(particle_container(1.0 + tiny, 0.4), 1.0, surface(1.0)) - assert np.isclose(result, True) - # At surface, positive side, negative direction - result = common.check_sense(particle_container(1.0 + tiny, -0.4), 1.0, surface(1.0)) - assert np.isclose(result, False) - # At surface, negative side, positive direction - result = common.check_sense(particle_container(9.0 - tiny, 0.2), 1.0, surface(9.0)) - assert np.isclose(result, True) - # At surface, negative side, negative direction - result = common.check_sense(particle_container(9.0 - tiny, -0.2), 1.0, surface(9.0)) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, same direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 2.5), 3.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 2.5), 3.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, -0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, -0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, same direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 2.5), 2.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 2.5), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, -0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, -0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: first move bin, same direction, same speed - # At surface, this is undefined, but we choose to return false - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 2.5), 2.5, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 2.5), 2.5, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, -0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, -0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, opposite direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 2.5), 3.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 2.5), 3.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, 0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, 0.4, 2.5), 3.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: first move bin, opposite direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 2.5), 2.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 2.5), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, 0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, 0.4, 2.5), 2.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: first move bin, opposite direction, same speed - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 2.5), 2.5, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 2.5), 2.5, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(7.5 + tiny, 0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(7.5 - tiny, 0.4, 2.5), 2.5, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: first move bin, at grid, same direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 5.0), 6.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 5.0), 6.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, 0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, 0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: first move bin, at grid, same direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 5.0), 2.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 5.0), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, 0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, 0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, at grid, same direction, same speed - # At surface, this is undefined, but we choose to return false - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, 0.4, 5.0), 5.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 5.0), 5.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, 0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, 0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, at grid, opposite direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 5.0), 6.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, -0.4, 5.0), 6.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, -0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, -0.4, 5.0), 6.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, at grid, opposite direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 5.0), 2.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, -0.4, 5.0), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, -0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, -0.4, 5.0), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: first move bin, at grid, opposite direction, same speed - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(8.0, -0.4, 5.0), 5.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, -0.4, 5.0), 5.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(5.0 + tiny, -0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(5.0 - tiny, -0.4, 5.0), 5.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, same direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(14.0, 0.4, 8.5), 6.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 8.5), 6.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, 0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, 0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: middle move bin, same direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(14.0, 0.4, 8.5), 2.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 8.5), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, 0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, 0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, same direction, same speed - # At surface, this is undefined, but we choose to return false - # ================================================================================= - - # Positive side - result = common.check_sense(particle_container(14.0, 0.4, 8.5), 5.0, moving_surface) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, 0.4, 8.5), 5.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, 0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, 0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, opposite direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(14.0, -0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 8.5), 6.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, -0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, -0.4, 8.5), 6.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, opposite direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(14.0, -0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 8.5), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, -0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, -0.4, 8.5), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, opposite direction, same speed - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(14.0, -0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(5.0, -0.4, 8.5), 5.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(12.0 + tiny, -0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(12.0 - tiny, -0.4, 8.5), 5.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, at grid, same direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, -0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense( - particle_container(3.0, -0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, -0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, -0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, at grid, same direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, -0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense( - particle_container(3.0, -0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, -0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, -0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: middle move bin, at grid, same direction, same speed - # At surface, this is undefined, but we choose to return false - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, -0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense( - particle_container(13.0, -0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, -0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, False) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, -0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, False) - - # ================================================================================= - # Moving: middle move bin, at grid, opposite direction, faster - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, 0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 10.0), 8.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, 0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, 0.4, 10.0), 8.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: middle move bin, at grid, opposite direction, slower - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, 0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 10.0), 2.0, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, 0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, 0.4, 10.0), 2.0, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: middle move bin, at grid, opposite direction, same speed - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(18.0, 0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense(particle_container(3.0, 0.4, 10.0), 7.5, moving_surface) - assert np.isclose(result, False) - - # At surface, positive side - result = common.check_sense( - particle_container(15.0 + tiny, 0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side - result = common.check_sense( - particle_container(15.0 - tiny, 0.4, 10.0), 7.5, moving_surface - ) - assert np.isclose(result, True) - - # ================================================================================= - # Moving: last move bin - # ================================================================================= - - # Positive side - result = common.check_sense( - particle_container(14.0, -0.4, 18.5), 8.0, moving_surface - ) - assert np.isclose(result, True) - # Negative side - result = common.check_sense( - particle_container(-5.0, 0.4, 18.5), 2.0, moving_surface - ) - assert np.isclose(result, False) - - # At surface, positive side, positive direction - result = common.check_sense( - particle_container(tiny, 0.4, 18.5), 6.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, positive side, negative firection - result = common.check_sense( - particle_container(tiny, -0.4, 18.5), 6.0, moving_surface - ) - assert np.isclose(result, False) - - # At surface, negative side, positive direction - result = common.check_sense( - particle_container(-tiny, 0.4, 18.5), 6.0, moving_surface - ) - assert np.isclose(result, True) - # At surface, negative side, negative direction - result = common.check_sense( - particle_container(-tiny, -0.4, 18.5), 6.0, moving_surface - ) - assert np.isclose(result, False) - - -def test_common_get_distance(): - # ================================================================================= - # Static - # ================================================================================= - # Copied from test_get_distance - - # Positive side, moving closer - result = common.get_distance(particle_container(3.0, -0.4), 1.0, surface(1.0)) - assert np.isclose(result, 5.0) - # Positive side, moving away - result = common.get_distance(particle_container(4.0, 0.3), 1.0, surface(1.0)) - assert np.isclose(result, INF) - - # Negative side, moving closer - result = common.get_distance(particle_container(-3.0, 0.4), 1.0, surface(1.0)) - assert np.isclose(result, 10.0) - # Negative side, moving away - result = common.get_distance(particle_container(-4.0, -0.3), 1.0, surface(1.0)) - assert np.isclose(result, INF) - - # Positive side, parallel - result = common.get_distance(particle_container(4.0, 0.0), 1.0, surface(1.0)) - assert np.isclose(result, INF) - # Positive side, parallel - result = common.get_distance(particle_container(-4.0, 0.0), 1.0, surface(1.0)) - assert np.isclose(result, INF) - - # At surface on the positive side, moving away - result = common.get_distance(particle_container(1.0 + tiny, 0.4), 1.0, surface(1.0)) - assert np.isclose(result, INF) - # At surface on the positive side, moving closer - result = common.get_distance( - particle_container(1.0 + tiny, -0.4), 1.0, surface(1.0) - ) - assert np.isclose(result, INF) - - # At surface on the negative side, moving away - result = common.get_distance( - particle_container(1.0 - tiny, -0.4), 1.0, surface(1.0) - ) - assert np.isclose(result, INF) - # At surface on the negative side, moving closer - result = common.get_distance(particle_container(1.0 - tiny, 0.4), 1.0, surface(1.0)) - assert np.isclose(result, INF) - - # ================================================================================= - # Moving - # ================================================================================= - - # TODO diff --git a/test/unit/test_input_.py b/test/unit/test_input_.py deleted file mode 100644 index b7c8660e1..000000000 --- a/test/unit/test_input_.py +++ /dev/null @@ -1,280 +0,0 @@ -import mcdc -import mcdc.type_ -import numpy as np - - -# ====================================================================================== -# Nuclide -# ====================================================================================== - - -def test_nuclide_basic(): - """Create a nuclide with complete definition.""" - mcdc.reset() - - n1 = mcdc.nuclide( - capture=np.array([1.0, 2.0, 3.0, 4.0]), - fission=np.array([1.0, 2.0, 3.0, 4.0]), - scatter=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - nu_s=np.array([1.0, 2.0, 3.0, 4.0]), - nu_p=np.array([1.0, 2.0, 3.0, 4.0]), - nu_d=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - chi_p=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - chi_d=np.array( - [ - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - ] - ), - speed=np.array([1.0, 2.0, 3.0, 4.0]), - decay=np.array([1.0, 2.0, 3.0]), - ) - - assert n1.tag == "Nuclide" - assert n1.ID == 0 - assert n1.G == 4 - assert n1.J == 3 - assert (n1.speed == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (n1.decay == np.array([1.0, 2.0, 3.0])).all() - assert (n1.capture == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (n1.scatter == np.array([4.0, 8.0, 12.0, 16.0])).all() - assert (n1.fission == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (n1.total == np.array([6.0, 12.0, 18.0, 24.0])).all() - assert (n1.nu_s == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (n1.nu_p == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert ( - n1.nu_d - == np.array( - [ - [1.0, 1.0, 1.0], - [2.0, 2.0, 2.0], - [3.0, 3.0, 3.0], - [4.0, 4.0, 4.0], - ] - ) - ).all() - assert (n1.nu_f == np.array([4.0, 8.0, 12.0, 16.0])).all() - assert (n1.chi_s == np.ones([4, 4]) * 0.25).all() - assert (n1.chi_p == np.ones([4, 4]) * 0.25).all() - assert (n1.chi_d == np.ones([3, 4]) * 0.25).all() - - -def test_nuclide_default(): - """Create nuclides with incomplete definitions.""" - mcdc.reset() - - n1 = mcdc.nuclide(capture=np.ones(5)) - n2 = mcdc.nuclide(scatter=np.ones((5, 5))) - n3 = mcdc.nuclide(fission=np.ones(5), nu_p=np.ones(5), chi_p=np.ones((5, 5))) - - # Checks - assert n1.tag == "Nuclide" - assert n1.ID == 0 - assert n1.G == 5 - assert n1.J == 0 - assert (n1.speed == np.ones(5)).all() - assert (n1.decay == np.zeros(0)).all() - assert (n1.capture == np.ones(5)).all() - assert (n1.scatter == np.zeros(5)).all() - assert (n1.fission == np.zeros(5)).all() - assert (n1.nu_s == np.ones(5)).all() - assert (n1.nu_p == np.zeros(5)).all() - assert (n1.nu_f == np.zeros(5)).all() - assert (n1.nu_d == np.zeros((5, 0))).all() - assert (n1.chi_s == np.zeros((5, 5))).all() - assert (n1.chi_p == np.zeros((5, 5))).all() - assert (n1.chi_d == np.zeros((0, 5))).all() - - assert (n2.capture == np.zeros(5)).all() - assert (n2.scatter == np.ones(5) * 5.0).all() - assert (n2.fission == np.zeros(5)).all() - assert (n1.nu_s == np.ones(5)).all() - assert (n2.nu_p == np.zeros(5)).all() - assert (n2.nu_f == np.zeros(5)).all() - assert (n2.nu_d == np.zeros((5, 0))).all() - assert (n2.chi_s == np.ones((5, 5)) * 0.2).all() - assert (n2.chi_p == np.zeros((5, 5))).all() - assert (n2.chi_d == np.zeros((0, 5))).all() - - assert (n3.capture == np.zeros(5)).all() - assert (n3.scatter == np.zeros(5)).all() - assert (n3.fission == np.ones(5)).all() - assert (n1.nu_s == np.ones(5)).all() - assert (n3.nu_p == np.ones(5)).all() - assert (n3.nu_f == np.ones(5)).all() - assert (n3.nu_d == np.zeros((5, 0))).all() - assert (n3.chi_s == np.zeros((5, 5))).all() - assert (n3.chi_p == np.ones((5, 5)) * 0.2).all() - assert (n3.chi_d == np.zeros((0, 5))).all() - - -# ====================================================================================== -# Material -# ====================================================================================== - - -def test_material_single(): - # Start fresh - mcdc.reset() - - # Create a single-nuclide material - m1 = mcdc.material( - capture=np.array([1.0, 2.0, 3.0, 4.0]), - fission=np.array([1.0, 2.0, 3.0, 4.0]), - scatter=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - nu_s=np.array([1.0, 2.0, 3.0, 4.0]), - nu_p=np.array([1.0, 2.0, 3.0, 4.0]), - nu_d=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - chi_p=np.array( - [ - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - [1.0, 2.0, 3.0, 4.0], - ] - ), - chi_d=np.array( - [ - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - [1.0, 2.0, 3.0], - ] - ), - speed=np.array([1.0, 2.0, 3.0, 4.0]), - decay=np.array([1.0, 2.0, 3.0]), - ) - - # Checks - assert m1.tag == "Material" - assert m1.ID == 0 - assert m1.N_nuclide == 1 - assert (m1.nuclide_IDs == np.array([0])).all() - assert (m1.nuclide_densities == np.array([1.0])).all() - assert m1.G == 4 - assert m1.J == 3 - assert (m1.speed == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (m1.capture == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (m1.scatter == np.array([4.0, 8.0, 12.0, 16.0])).all() - assert (m1.fission == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (m1.total == np.array([6.0, 12.0, 18.0, 24.0])).all() - assert (m1.nu_s == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert (m1.nu_p == np.array([1.0, 2.0, 3.0, 4.0])).all() - assert ( - m1.nu_d - == np.array( - [ - [1.0, 1.0, 1.0], - [2.0, 2.0, 2.0], - [3.0, 3.0, 3.0], - [4.0, 4.0, 4.0], - ] - ) - ).all() - assert (m1.nu_f == np.array([4.0, 8.0, 12.0, 16.0])).all() - assert (m1.chi_s == np.ones([4, 4]) * 0.25).all() - assert (m1.chi_p == np.ones([4, 4]) * 0.25).all() - - # Check if the nuclide was registered - n2 = mcdc.nuclide(capture=np.ones(5)) - assert n2.ID == 1 - - -def test_material_multi(): - # Start fresh - mcdc.reset() - - # Create a multi-nuclide material - n1 = mcdc.nuclide(capture=np.ones(5), speed=np.ones(5) * 1) - n2 = mcdc.nuclide(scatter=np.ones((5, 5)), speed=np.ones(5) * 2) - n3 = mcdc.nuclide( - fission=np.ones(5), nu_p=np.ones(5), chi_p=np.ones((5, 5)), speed=np.ones(5) * 3 - ) - m1 = mcdc.material(nuclides=[(n1, 1.0), (n2, 2.0), (n3, 3.0)]) - - # Checks - assert m1.tag == "Material" - assert m1.ID == 0 - assert m1.N_nuclide == 3 - assert (m1.nuclide_IDs == np.array([0, 1, 2])).all() - assert (m1.nuclide_densities == np.array([1.0, 2.0, 3.0])).all() - assert m1.G == 5 - assert m1.J == 0 - assert (m1.total == np.ones(5) * 14).all() - assert (m1.speed == np.ones(5) * 30 / 14).all() - - -# ====================================================================================== -# Surface -# ====================================================================================== - - -def test_surface_input_lower(): - type_ = "pLaNe x" - result = mcdc.surface(type_, bc="RefLeCtiVe", x=0.0) - assert result.boundary_type == "reflective" - assert result.A == 0.0 - assert result.B == 0.0 - assert result.C == 0.0 - assert result.D == 0.0 - assert result.E == 0.0 - assert result.F == 0.0 - assert result.G == 1.0 - assert result.H == 0.0 - assert result.I == 0.0 - assert (result.J == np.array([[-0.0, 0.0]])).all() - assert result.linear - - -# ====================================================================================== -# Reset -# ====================================================================================== - - -def test_reset(): - # Start fresh - mcdc.reset() - - # ID reset - n = mcdc.nuclide(capture=np.ones(5)) - assert n.ID == 0 - - mcdc.reset() - - n1 = mcdc.nuclide(capture=np.ones(5)) - assert n1.ID == 0 diff --git a/test/unit/test_kernel.py b/test/unit/test_kernel.py deleted file mode 100644 index 5801059d8..000000000 --- a/test/unit/test_kernel.py +++ /dev/null @@ -1,134 +0,0 @@ -import numpy as np -import mcdc as MCDC -from mcdc.iqmc.iqmc_loop import AxV -from mcdc.kernel import rng -import mcdc.global_ as mcdc_ - -input_deck = mcdc_.input_deck - - -def iqmc_dummy_mcdc_variable(): - """ - This function returns the global "mcdc" container. Inputs are - taken from the kornreich eigenvalue problem. - - """ - # Set materials - m1 = MCDC.material( - capture=np.array([0.0]), - scatter=np.array([[0.9]]), - fission=np.array([0.1]), - nu_p=np.array([6.0]), - ) - m2 = MCDC.material( - capture=np.array([0.68]), - scatter=np.array([[0.2]]), - fission=np.array([0.12]), - nu_p=np.array([2.5]), - ) - - # Set surfaces - s1 = MCDC.surface("plane-x", x=0.0, bc="vacuum") - s2 = MCDC.surface("plane-x", x=1.5) - s3 = MCDC.surface("plane-x", x=2.5, bc="vacuum") - - # Set cells - MCDC.cell(+s1 & -s2, m1) - MCDC.cell(+s2 & -s3, m2) - - # ============================================================================= - # iQMC Parameters - # ============================================================================= - N = 100 - maxit = 10 - tol = 1e-3 - x = np.arange(0.0, 2.6, 0.1) - Nx = len(x) - 1 - fixed_source = np.zeros(Nx) - phi0 = np.ones((Nx)) - - # ============================================================================= - # Set tally, setting, and run mcdc - # ============================================================================= - - MCDC.iQMC( - x=x, - fixed_source=fixed_source, - phi0=phi0, - maxit=maxit, - tol=tol, - ) - # Setting - MCDC.setting(N_particle=N) - MCDC.eigenmode() - return MCDC.prepare() - - -def test_rn_basic(): - """ - Basic test routine for random number generator. - Get the first 5 random numbers, skip a few, get 5 more and compare to - reference data from [1] - - Seed numbers for index 1-5, 123456-123460 - - [1] F. B. Brown, “Random number generation with arbitrary strides”, - Trans. Am. Nucl. Soc, 71, 202 (1994) - - """ - MCDC.reset() - - ref_data = np.array( - ( - 1, - 2806196910506780710, - 6924308458965941631, - 7093833571386932060, - 4133560638274335821, - ) - ) - - data_arr, mcdc_arr = iqmc_dummy_mcdc_variable() - data = data_arr[0] - mcdc = mcdc_arr[0] - - # run through the first five seeds (1-5) - for i in range(5): - assert mcdc["setting"]["rng_seed"] == ref_data[i] - rng([mcdc["setting"]]) - - -def test_AxV_linearity(): - """ - AxV is the linear operator used for GMRES in iQMC. - - Linear operators must satisfy conditions of additivity and multiplicity - defined as: - - Additivity: f(x+y) = f(x) + f(y) - - Multiplicity: f(cx) = cf(x) - - We can test both properties with: - - f(a*x + b*y) = a*f(x) + b*f(y) - """ - MCDC.reset() - - data_arr, mcdc_arr = iqmc_dummy_mcdc_variable() - data = data_arr[0] - mcdc = mcdc_arr[0] - - size = mcdc["technique"]["iqmc"]["total_source"].size - np.random.seed(123456) - a = np.random.random() - b = np.random.random() - x = np.random.random((size,)) - y = np.random.random((size,)) - rhs = np.zeros((size,)) - - print(mcdc) - F1 = AxV((a * x + b * y), rhs, mcdc) - F2 = a * AxV(x, rhs, mcdc) + b * AxV(y, rhs, mcdc) - assert np.allclose(F1, F2, rtol=1e-10) - - -# if __name__ == "__main__": -# test_AxV_linearity() diff --git a/test/unit/test_type_.py b/test/unit/test_type_.py deleted file mode 100644 index 33baa4864..000000000 --- a/test/unit/test_type_.py +++ /dev/null @@ -1,282 +0,0 @@ -import numpy as np - -from mcdc.type_ import nuclide -from mcdc.input_ import nuclide - - -def generate_test_nuclear_data(n_neutron_groups, n_dnp_groups): - # Set random seed - np.random.seed(90053) - - # Generate nuclear data - capture = np.random.rand(n_neutron_groups) - scatter = np.random.rand(n_neutron_groups, n_neutron_groups) - fission = np.random.rand(n_neutron_groups) - nu_s = np.random.rand(n_neutron_groups) - nu_p = np.random.rand(n_neutron_groups) - nu_d = np.random.rand(n_dnp_groups, n_neutron_groups) - chi_p = np.random.rand(n_neutron_groups, n_neutron_groups) - chi_d = np.random.rand(n_neutron_groups, n_dnp_groups) - speed = np.random.rand(n_neutron_groups) - decay = np.random.rand(n_dnp_groups) - - return [capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay] - - -def verify_card_quantities_with_input_quantities( - mat, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay -): - # Verify pass-through quantities are correct - assert np.allclose(mat.capture, capture) - assert np.allclose(mat.fission, fission) - assert np.allclose(mat.nu_p, nu_p) - assert np.allclose(mat.nu_s, nu_s) - assert np.allclose(mat.speed, speed) - assert np.allclose(mat.decay, decay) - - # Verify modified and/or calculated quantities are correct - n_neutron_groups = len(capture) - n_dnp_groups = len(decay) - total_scatter = np.sum(scatter, 0) - total = capture + total_scatter + fission - nu_f = nu_p + np.sum(np.transpose(nu_d), 1) - normalized_chi_s = scatter * np.divide(1.0, np.sum(scatter, 0)) - normalized_chi_p = chi_p * np.divide(1.0, np.sum(chi_p, 0)) - normalized_chi_d = chi_d * np.divide(1.0, np.sum(chi_d, 0)) - assert mat.G == n_neutron_groups - assert mat.J == n_dnp_groups - assert np.allclose(mat.scatter, total_scatter) - assert np.allclose(mat.total, total) - assert np.allclose(mat.nu_d, np.transpose(nu_d)) - assert np.allclose(mat.nu_f, nu_f) - assert np.allclose(mat.chi_s, np.transpose(normalized_chi_s)) - assert np.allclose(mat.chi_p, np.transpose(normalized_chi_p)) - assert np.allclose(mat.chi_d, np.transpose(normalized_chi_d)) - - -def test_single_neutron_energy_and_zero_dnp_group_nuclide(): - n_neutron_groups = 1 - n_dnp_groups = 0 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) - - -def test_single_neutron_energy_and_single_dnp_group_nuclide(): - n_neutron_groups = 1 - n_dnp_groups = 1 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) - - -def test_multiple_neutron_energy_and_zero_dnp_group_nuclide(): - n_neutron_groups = 7 - n_dnp_groups = 0 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) - - -def test_multiple_neutron_energy_and_single_dnp_group_nuclide(): - n_neutron_groups = 7 - n_dnp_groups = 1 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) - - -def test_single_neutron_energy_and_multiple_dnp_group_nuclide(): - n_neutron_groups = 1 - n_dnp_groups = 6 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) - - -def test_multiple_neutron_energy_and_multiple_dnp_group_nuclide(): - n_neutron_groups = 7 - n_dnp_groups = 6 - - # Generate data for one energy group and one DNP group - [ - capture, - scatter, - fission, - nu_s, - nu_p, - nu_d, - chi_p, - chi_d, - speed, - decay, - ] = generate_test_nuclear_data(n_neutron_groups, n_dnp_groups) - - # Initialize nuclide with single energy and DNP group - m = nuclide( - capture=capture, - scatter=scatter, - fission=fission, - nu_p=nu_p, - nu_d=nu_d, - chi_p=chi_p, - chi_d=chi_d, - nu_s=nu_s, - speed=speed, - decay=decay, - ) - - # Verify input processing - verify_card_quantities_with_input_quantities( - m, capture, scatter, fission, nu_s, nu_p, nu_d, chi_p, chi_d, speed, decay - ) diff --git a/test/unit/transport/util/test_find_bin.py b/test/unit/transport/util/test_find_bin.py new file mode 100644 index 000000000..f864a5e48 --- /dev/null +++ b/test/unit/transport/util/test_find_bin.py @@ -0,0 +1,62 @@ +import numpy as np +import pytest + +#### + +from mcdc.transport.util import find_bin + + +@pytest.fixture +def grid(): + return np.array([0.0, 1.0, 2.0, 5.0, 10.0]) + + +@pytest.fixture +def eps(): + return 1e-5 + + +def test_inside_bins(grid): + assert find_bin(0.5, grid) == 0 + assert find_bin(1.5, grid) == 1 + assert find_bin(4.9, grid) == 2 + assert find_bin(9.9, grid) == 3 + + +def test_exact_interior_edges(grid): + assert find_bin(1.0, grid, 0.0, True) == 0 + assert find_bin(1.0, grid, 0.0, False) == 1 + assert find_bin(5.0, grid, 0.0, True) == 2 + assert find_bin(5.0, grid, 0.0, False) == 3 + + +def test_first_edge(grid): + assert find_bin(0.0, grid, 0.0, True) == -1 + assert find_bin(0.0, grid, 0.0, False) == 0 + + +def test_last_edge(grid): + assert find_bin(10.0, grid, 0.0, True) == 3 + assert find_bin(10.0, grid, 0.0, False) == -1 + + +def test_near_interior_edges_with_epsilon(grid, eps): + assert find_bin(1.0 - 1e-6, grid, eps, True) == 0 + assert find_bin(1.0 - 1e-6, grid, eps, False) == 1 + assert find_bin(1.0 + 1e-6, grid, eps, True) == 0 + assert find_bin(1.0 + 1e-6, grid, eps, False) == 1 + + +def test_near_first_edge_with_epsilon(grid, eps): + assert find_bin(0.0 + 1e-6, grid, eps, True) == -1 + assert find_bin(0.0 + 1e-6, grid, eps, False) == 0 + + +def test_near_last_edge_with_epsilon(grid, eps): + assert find_bin(10.0 - 1e-6, grid, eps, True) == 3 + assert find_bin(10.0 - 1e-6, grid, eps, False) == -1 + + +def test_out_of_range(grid): + assert find_bin(-1.0, grid) == -1 + assert find_bin(11.0, grid) == -1 diff --git a/test/unit/transport/util/test_linear_interpolation.py b/test/unit/transport/util/test_linear_interpolation.py new file mode 100644 index 000000000..f517c7068 --- /dev/null +++ b/test/unit/transport/util/test_linear_interpolation.py @@ -0,0 +1,42 @@ +from mcdc.transport.util import linear_interpolation + + +def test_exact_endpoints(): + assert linear_interpolation(0, 0, 10, 0, 100) == 0 + assert linear_interpolation(10, 0, 10, 0, 100) == 100 + + +def test_midpoint(): + assert linear_interpolation(5, 0, 10, 0, 100) == 50 + assert linear_interpolation(2.5, 0, 10, 0, 100) == 25 + + +def test_negative_slopes(): + assert linear_interpolation(5, 0, 10, 100, 0) == 50 + assert linear_interpolation(2, 0, 4, 4, 0) == 2 + + +def test_non_uniform_interval(): + # Interval [2, 4] mapped to [10, 30] + assert linear_interpolation(3, 2, 4, 10, 30) == 20 + + +def test_floats(): + result = linear_interpolation(0.5, 0, 1, 0.0, 1.0) + assert abs(result - 0.5) < 1e-12 + + +def test_extrapolation(): + # x before x1 + assert linear_interpolation(-5, 0, 10, 0, 100) == -50 + # x beyond x2 + assert linear_interpolation(20, 0, 10, 0, 100) == 200 + + +def test_x1_equals_x2_raises_zero_division(): + try: + linear_interpolation(1, 2, 2, 0, 10) + except ZeroDivisionError: + assert True + else: + assert False, "Expected ZeroDivisionError when x1 == x2" diff --git a/tools/data_library_generator/generate.py b/tools/data_library_generator/generate.py new file mode 100644 index 000000000..3e595a817 --- /dev/null +++ b/tools/data_library_generator/generate.py @@ -0,0 +1,459 @@ +import ACEtk +import argparse +import h5py +import numpy as np +import os + +from tqdm import tqdm + +#### + +import util +from util import print_error, print_note + +parser = argparse.ArgumentParser(description="MC/DC data generator") +parser.add_argument("--rewrite", dest="rewrite", action="store_true", default=False) +parser.add_argument("--verbose", dest="verbose", action="store_true", default=False) +args, unargs = parser.parse_known_args() +rewrite = args.rewrite +verbose = args.verbose + +# Directories +output_dir = os.getenv("MCDC_LIB") +ace_dir = os.getenv("MCDC_ACELIB") + +if output_dir is None: + print_error("Environment variable $MCDC_LIB is not set") +if ace_dir is None: + print_error("Environment variable $MCDC_ACELIB is not set") + +# Create output directory if needed +os.makedirs(output_dir, exist_ok=True) +print(f"\nACE directory: {ace_dir}") +print(f"Output directory: {output_dir}\n") + +# Select the files +if rewrite: + target_files = os.listdir(ace_dir) +else: + target_files = [] + for file_name in os.listdir(ace_dir): + # File header + with open(f"{ace_dir}/{file_name}", "r") as f: + header = ACEtk.Header.from_string(f.readline()) + + # Decode ACE name to MC/DC name + Z, A, S, T = util.decode_ace_name(header.zaid) + symbol = util.Z_TO_SYMBOL[Z] + nuclide_name = f"{symbol}{A}" if S == 0 else f"{symbol}{A}m{S}" + mcdc_name = f"{nuclide_name}-{T}K.h5" + + if not os.path.exists(f"{output_dir}/{mcdc_name}"): + target_files.append(file_name) + +# Loop over all files +pbar = tqdm( + target_files, + disable=verbose, + bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt}{postfix}", +) +for ace_name in pbar: + # File header + with open(f"{ace_dir}/{ace_name}", "r") as f: + header = ACEtk.Header.from_string(f.readline()) + + # Decode ACE name to MC/DC name + Z, A, S, T = util.decode_ace_name(header.zaid) + symbol = util.Z_TO_SYMBOL[Z] + nuclide_name = f"{symbol}{A}" if S == 0 else f"{symbol}{A}m{S}" + mcdc_name = f"{nuclide_name}-{T}K.h5" + + if not rewrite and os.path.exists(f"{output_dir}/{mcdc_name}"): + continue + + # Create MC/DC file + if verbose: + print("\n" + "=" * 80 + "\n") + print(f"Create {mcdc_name} from {ace_name}\n") + pbar.set_postfix_str(f"{mcdc_name[:-3]} from {ace_name}") + file = h5py.File(f"{output_dir}/{mcdc_name}", "w") + + # ================================================================================== + # Basic properties + # ================================================================================== + + # Load ACE tables + ace_table = ACEtk.ContinuousEnergyTable.from_file(f"{ace_dir}/{ace_name}") + + # ACE data source description + header = ace_table.header + file.attrs["source_title"] = header.title + file.attrs["source_version"] = header.version + file.attrs["source_date"] = header.date + if "comments" in dir(header): + file.attrs["source_comments"] = header.comments + + # Name and excitation level + file.create_dataset("nuclide_name", data=nuclide_name) + file.create_dataset("excitation_level", data=S) + + # Temperature + temperature = file.create_dataset("temperature", data=T) + temperature.attrs["unit"] = "K" + + # Atomic weight ratio + atomic_weight_ratio = ace_table.atomic_weight_ratio + file.create_dataset("atomic_weight_ratio", data=atomic_weight_ratio) + + # Fissionable? + fissionable = ace_table.fission_multiplicity_block is not None + file.create_dataset("fissionable", data=fissionable) + + # ================================================================================== + # Reaction groups + # ================================================================================== + # Elastic scattering: MT=2 + # Capture: Reactions with zero multiplicity + # Fission: MT=18 or MT=(19, 20, 21, and 38) if given + # Inelastic: Non-fission reactions with non-zero multiplicity + # Ignored: MT=(1, 3, 4, 10) and MT>117 + + reactions = file.create_group("neutron_reactions") + + # ACE blocks + nu_block = ace_table.frame_and_multiplicity_block + rx_block = ace_table.reaction_number_block + N_reaction = nu_block.number_reactions + + if nu_block.number_reactions != rx_block.number_reactions: + print_error("Non-equal reaction number in reaction and multiplicity blocks") + + # The groups + elastic_group = reactions.create_group("elastic_scattering") + capture_group = reactions.create_group("capture") + inelastic_group = reactions.create_group("inelastic_scattering") + fission_group = reactions.create_group("fission") + + # MT groups + elastic_MTs = [2] + capture_MTs = [] + inelastic_MTs = [] + fission_MTs = [] + + # Redundant MTs + fission_chance_MTs = [19, 20, 21, 38] + redundant_MTs = [1, 3, 4, 10] + + # Set fission MTs + total_fission_given = rx_block.has_MT(18) + if total_fission_given: + fission_MTs = [18] + # The component should not be given + for MT in fission_chance_MTs: + if rx_block.has_MT(MT): + print_error("Both total fission and its components are given") + else: + for MT in fission_chance_MTs: + if rx_block.has_MT(MT): + fission_MTs.append(MT) + + # Capture and inelastic MTs + for i in range(N_reaction): + idx = i + 1 + MT = rx_block.MT(idx) + + if MT in redundant_MTs + elastic_MTs + fission_MTs or MT > 117: + continue + + nu = nu_block.multiplicity(idx) + + if type(nu) != int: + print_error(f"Non-integer multiplicity for inelastic scattering") + + if nu == 0: + capture_MTs.append(MT) + elif nu > 0: + inelastic_MTs.append(MT) + else: + print_error(f"Negative multiplicity for MT-{MT:03}") + + # Create MTs + for rx_group, rx_MTs in [ + (elastic_group, elastic_MTs), + (capture_group, capture_MTs), + (inelastic_group, inelastic_MTs), + (fission_group, fission_MTs), + ]: + for MT in rx_MTs: + MT_group = rx_group.create_group(f"MT-{MT:03}") + MT_group.attrs["MT"] = MT + + # Report MT groups + if verbose: + print(f" Reaction group MTs") + print(f" - Elastic scattering MTs: {elastic_MTs}") + print(f" - Capture MTs: {capture_MTs}") + print(f" - Inelastic scattering MTs: {inelastic_MTs}") + if fissionable: + print(f" - Fission MT: {fission_MTs}") + + # Delete empty groups + if not fissionable: + del file["neutron_reactions/fission"] + if len(inelastic_MTs) == 0: + del file["neutron_reactions/inelastic_scattering"] + + # ================================================================================== + # Cross-sections + # ================================================================================== + + xs0_block = ace_table.principal_cross_section_block + xs_block = ace_table.cross_section_block + + xs_energy = xs0_block.energies + xs_elastic = xs0_block.elastic + cross_sections = xs_block.cross_sections + offsets = xs_block.energy_index + + # Energy grid + xs_energy = np.array(xs_energy) + dataset = reactions.create_dataset("xs_energy_grid", data=xs_energy) + dataset.attrs["unit"] = "MeV" + + # Elastic scattering + xs = elastic_group.create_dataset("MT-002/xs", data=xs_elastic) + xs.attrs["offset"] = 0 + xs.attrs["unit"] = "barns" + + # Capture, inelastic scattering, and fission + for MTs, group in [ + (capture_MTs, capture_group), + (inelastic_MTs, inelastic_group), + (fission_MTs, fission_group), + ]: + for MT in MTs: + idx = rx_block.index(MT) + xs = group.create_dataset(f"MT-{MT:03}/xs", data=cross_sections(idx)) + xs.attrs["offset"] = offsets(idx) - 1 + xs.attrs["unit"] = "barns" + + # ================================================================================== + # Reference frames and inelastic scattering multiplicities + # ================================================================================== + # Elastic is always in COM frame (per ACE standard) + + # Elastic scattering reference frame + for MT in elastic_MTs: + elastic_group.create_dataset(f"MT-{MT:03}/reference_frame", data="COM") + + # Reference frames of the others + for MTs, group in [ + (capture_MTs, capture_group), + (inelastic_MTs, inelastic_group), + (fission_MTs, fission_group), + ]: + for MT in MTs: + idx = rx_block.index(MT) + reference_frame = nu_block.reference_frame(idx) + if reference_frame == ACEtk.ReferenceFrame.Laboratory: + reference_frame = "LAB" + elif reference_frame == ACEtk.ReferenceFrame.CentreOfMass: + reference_frame = "COM" + else: + print_error(f"Unknown reaction reference frame type for MT-{MT:03}") + group.create_dataset(f"MT-{MT:03}/reference_frame", data=reference_frame) + + # Inelastic multiplicity + for MT in inelastic_MTs: + idx = rx_block.index(MT) + nu = nu_block.multiplicity(idx) + inelastic_group.create_dataset(f"MT-{MT:03}/multiplicity", data=nu) + + # ================================================================================== + # Angular distributions + # ================================================================================== + + angle_block = ace_table.angular_distribution_block + + # Elastic scattering + angle_group = elastic_group.create_group("MT-002/angular_cosine_distribution") + data = angle_block.angular_distribution_data(0) + for subdata in data.distributions: + if not isinstance(subdata, ACEtk.continuous.TabulatedAngularDistribution): + print_error("Unsupported elastic scattering angular distribution") + util.load_cosine_distribution(data, angle_group) + + # Inelastic scattering and fission + for MTs, group in [ + (inelastic_MTs, inelastic_group), + (fission_MTs, fission_group), + ]: + for MT in MTs: + idx = rx_block.index(MT) + angle_group = group.create_group(f"MT-{MT:03}/angular_cosine_distribution") + data = angle_block.angular_distribution_data(idx) + util.load_cosine_distribution(data, angle_group) + + # ================================================================================== + # Energy distributions + # ================================================================================== + + energy_block = ace_table.energy_distribution_block + + for MTs, group in [ + (inelastic_MTs, inelastic_group), + (fission_MTs, fission_group), + ]: + for MT in MTs: + idx = rx_block.index(MT) + data = energy_block.energy_distribution_data(idx) + + if not isinstance(data, ACEtk.continuous.MultiDistributionData): + # Probabilities + dataset = group.create_dataset( + f"MT-{MT:03}/spectrum_probability_grid", data=np.array([0.0, 30.0]) + ) + dataset.attrs["unit"] = "MeV" + dataset = group.create_dataset( + f"MT-{MT:03}/spectrum_probability", data=np.array([[1.0]]) + ) + + # The distributions + energy_group = group.create_group(f"MT-{MT:03}/energy_spectrum-1") + util.load_energy_distribution(data, energy_group) + + else: + N_dist = data.number_distributions + + # ====================================================================== + # Probabilities + # ====================================================================== + + # Constant probability + if all( + np.array( + [x.number_interpolation_regions for x in data.probabilities] + ) + == 0 + ): + probability_grid = np.array([0.0, 30.0]) + probability = np.zeros((1, N_dist)) + for i in range(N_dist): + probability[0, i] = max(data.probability(i + 1).probabilities) + + # Histogram probability + elif all( + np.array( + [x.number_interpolation_regions for x in data.probabilities] + ) + == 1 + ) and all(np.array([x.interpolants for x in data.probabilities]) == 1): + probability_grid = np.array(data.probability(1).energies) + probability = np.zeros((len(probability_grid) - 1, N_dist)) + for i in range(N_dist): + if not all( + probability_grid + == np.array(data.probability(i + 1).energies) + ): + print_error("Unsupported multi-distribution energy spetrum") + probability[:, i] = np.array( + data.probability(i + 1).probabilities[:-1] + ) + + else: + print_error("Unsupported multi-distribution energy spetrum") + + dataset = group.create_dataset( + f"MT-{MT:03}/spectrum_probability_grid", data=probability_grid + ) + dataset.attrs["unit"] = "MeV" + dataset = group.create_dataset( + f"MT-{MT:03}/spectrum_probability", data=probability + ) + + # ====================================================================== + # The disributions + # ====================================================================== + + for i in range(N_dist): + energy_group = group.create_group( + f"MT-{MT:03}/energy_spectrum-{i+1}" + ) + distribution = data.distribution(i + 1) + util.load_energy_distribution(distribution, energy_group) + + # Fissionable zone below + if not fissionable: + continue + + # ================================================================================== + # Fission multiplicities and delayed neutron precursor fractions and decay rates + # ================================================================================== + + prompt_block = ace_table.fission_multiplicity_block + delayed_block = ace_table.delayed_fission_multiplicity_block + dnp_block = ace_table.delayed_neutron_precursor_block + + # Prompt multiplicity + data = prompt_block.multiplicity + h5_group = fission_group.create_group("prompt_multiplicity") + util.load_fission_multiplicity(data, h5_group) + + # Delayed multiplicity + if delayed_block is not None: + data = delayed_block.multiplicity + h5_group = fission_group.create_group("delayed_multiplicity") + util.load_fission_multiplicity(data, h5_group) + + # Delayed neutron precursor fractions and decay rates + if dnp_block is not None: + N_DNP = dnp_block.number_delayed_precursors + fractions = np.zeros(N_DNP) + decay_rates = np.zeros(N_DNP) + + for i in range(N_DNP): + idx = 1 + 1 + data = dnp_block.precursor_group_data(idx) + + if ( + not data.number_interpolation_regions == 0 + or not len(data.probabilities[:]) == 2 + or not data.probabilities[0] == data.probabilities[1] + ): + print_error("Non-constant delayed neutron precursor fraction") + + fractions[i] = data.probabilities[0] + decay_rates[i] = data.decay_constant + + precursors = fission_group.create_group("delayed_neutron_precursors") + precursors.create_dataset("fractions", data=fractions) + decay_rates = precursors.create_dataset("decay_rates", data=decay_rates) + decay_rates.attrs["unit"] = "/s" + + # ================================================================================== + # Delayed fission spectra + # ================================================================================== + + delayed_spectrum_block = ace_table.delayed_neutron_energy_distribution_block + if dnp_block is not None: + N_DNP = dnp_block.number_delayed_precursors + + for i in range(N_DNP): + idx = 1 + 1 + data = delayed_spectrum_block.energy_distribution_data(idx) + + if not isinstance(data, ACEtk.continuous.OutgoingEnergyDistributionData): + print_error(f"Unsupported delayed fission neutron spectrum: {data}") + + energy_group = fission_group.create_group( + f"delayed_neutron_precursors/energy_spectrum-{i+1}" + ) + util.load_energy_distribution(data, energy_group) + + # ================================================================================== + # Finalize + # ================================================================================== + + file.close() + +print("") diff --git a/tools/data_library_generator/util.py b/tools/data_library_generator/util.py new file mode 100644 index 000000000..eca313517 --- /dev/null +++ b/tools/data_library_generator/util.py @@ -0,0 +1,459 @@ +import ACEtk +import h5py +import numpy as np + + +def print_error(message): + print(f"\n [ERROR]: {message}\n") + exit() + + +def print_note(message): + print(f"\n [NOTE]: {message}\n") + + +def decode_interpolation(code): + if code not in INTERPOLATION_MAP.keys(): + print_error(f"Unsupported interpolation law: {code}") + return INTERPOLATION_MAP[code] + + +def decode_ace_name(name: str): + """ + Decode an ACE file name into atomic number Z, mass number A, excitation state S, + following the rule: + ZAID = 1000*Z + A, (ground state), + ZAID = 1000*Z + A + 300 + 100*S, (excited, S >= 1), + and temperature T. + Returns (Z, A, S, T) + """ + zaid, extension = name.split(".") + + zaid = int(zaid) + Z = zaid // 1000 + remainder = zaid % 1000 + + if remainder < 300: + # ground state + A = remainder + S = 0 + else: + # excited state + offset = remainder - 300 + S = offset // 100 + A = offset % 100 + + T = ACE_TEMPERATURE_LIB81[extension] + + return Z, A, S, T + + +def get_zaid(nuclide_name): + nuclide_name = nuclide_name.strip().capitalize() + + # Find where the letters end and digits begin + symbol = "" + mass = 0 + for i, ch in enumerate(nuclide_name): + if ch.isdigit(): + symbol = nuclide_name[:i] + mass = int(nuclide_name[i:]) + break + else: + raise ValueError(f"No mass number found in '{nuclide_name}'") + + if symbol not in Z_MAP.keys(): + raise ValueError(f"Unknown element symbol '{symbol}'") + + Z = Z_MAP[symbol] + A = mass + return Z, A + + +def get_ace_name(Z, A, T, S=None): + ID = Z * 1000 + A + if S is not None: + ID += 300 + S * 100 + extension = ACE_EXTENSION_LIB81[T] + return f"{ID}{extension}" + + +def load_fission_multiplicity(data, h5_group: h5py.Group): + # Polynomial + if data.type == 1: + h5_group.attrs["type"] = "polynomial" + + C = np.array(data.coefficients) + dataset = h5_group.create_dataset("coefficient", data=C) + dataset.attrs["unit-base"] = "MeV" + + # Tabulated + elif data.type == 2: + h5_group.attrs["type"] = "tabulated" + + if not data.interpolation_data.is_linear_linear: + print(f"[ERROR] Non linear-linear tabulated multiplicity is not supported") + exit() + + energy = np.array(data.energies) + + h5_group.create_dataset("value", data=data.multiplicities) + dataset = h5_group.create_dataset("energy", data=energy) + dataset.attrs["unit"] = "MeV" + + ## Yield - Unsupported + else: + print(f"[ERROR] Unsupported multiplicity type: {data.type}") + exit() + + +def load_cosine_distribution(data, h5_group: h5py.Group): + if isinstance(data, ACEtk.continuous.FullyIsotropicDistribution): + h5_group.attrs["type"] = "isotropic" + + elif isinstance(data, ACEtk.continuous.DistributionGivenElsewhere): + h5_group.attrs["type"] = "energy-correlated" + + else: + h5_group.attrs["type"] = "tabulated" + + # Check distribution support: all tabulated + NE = data.number_incident_energies + for i in range(NE): + idx = i + 1 + if data.distribution_type(idx) != ACEtk.AngularDistributionType.Tabulated: + print_error("Angular distribution is not all-tabulated") + + # Incident energy + energy = np.array(data.incident_energies) + energy = h5_group.create_dataset("energy", data=energy) + energy.attrs["unit"] = "MeV" + + # Tabulated disstributions + interpolation = np.zeros(NE, dtype=int) + offset = np.zeros(NE, dtype=int) + cosine = [] + pdf = [] + for i, distribution in enumerate(data.distributions): + interpolation[i] = distribution.interpolation + offset[i] = len(cosine) + cosine.extend(distribution.cosines) + pdf.extend(distribution.pdf) + cosine = np.array(cosine) + pdf = np.array(pdf) + h5_group.create_dataset("offset", data=offset) + h5_group.create_dataset("value", data=cosine) + h5_group.create_dataset("pdf", data=pdf) + + if not all(interpolation == 2): + print_error("Angular distribution is not linearly-iterpolable") + + +def load_energy_distribution(data, h5_group: h5py.Group): + if isinstance(data, ACEtk.continuous.LevelScatteringDistribution): + h5_group.attrs["type"] = "level-scattering" + + C1 = np.array(data.C1) + C1 = h5_group.create_dataset("C1", data=C1) + C1.attrs["unit"] = "MeV" + + h5_group.create_dataset("C2", data=data.C2) + + elif isinstance(data, ACEtk.continuous.EvaporationSpectrum): + h5_group.attrs["type"] = "evaporation" + + if not data.interpolation_data.is_linear_linear: + print_error( + "Evaporation distribution temperature is not linearly interpolable" + ) + + energy = np.array(data.energies) + temperature = np.array(data.temperatures) + restriction_energy = np.array(data.restriction_energy) + + dataset = h5_group.create_dataset("temperature_energy_grid", data=energy) + dataset.attrs["unit"] = "MeV" + dataset = h5_group.create_dataset("temperature", data=temperature) + dataset.attrs["unit"] = "MeV" + dataset = h5_group.create_dataset("restriction_energy", data=restriction_energy) + dataset.attrs["unit"] = "MeV" + + elif isinstance(data, ACEtk.continuous.SimpleMaxwellianFissionSpectrum): + h5_group.attrs["type"] = "maxwellian" + + if all(np.array(data.interpolation_data.interpolants) == 2): + interpolation = "linear" + elif all(np.array(data.interpolation_data.interpolants) == 5): + interpolation = "log" + else: + print_error( + "Unsupported temperature interpolation law in Maxwellian distribution" + ) + + energy = np.array(data.energies) + temperature = np.array(data.temperatures) + restriction_energy = np.array(data.restriction_energy) + + h5_group.create_dataset("temperature_interpolation", data=interpolation) + dataset = h5_group.create_dataset("temperature_energy_grid", data=energy) + dataset.attrs["unit"] = "MeV" + dataset = h5_group.create_dataset("temperature", data=temperature) + dataset.attrs["unit"] = "MeV" + dataset = h5_group.create_dataset("restriction_energy", data=restriction_energy) + dataset.attrs["unit"] = "MeV" + + elif isinstance(data, ACEtk.continuous.OutgoingEnergyDistributionData): + h5_group.attrs["type"] = "tabulated" + + if not data.interpolation_data.is_linear_linear: + print_error( + "Non-linearly-interpolated energy distribution is not supported" + ) + + # Incident energy + energy = np.array(data.incident_energies) + energy = h5_group.create_dataset("energy", data=energy) + energy.attrs["unit"] = "MeV" + + # Tabulated disstributions + NE = data.number_incident_energies + offset = np.zeros(NE, dtype=int) + energy_out = [] + pdf = [] + for i in range(NE): + distribution = data.distribution(i + 1) + offset[i] = len(energy_out) + energy_out.extend(distribution.outgoing_energies) + pdf.extend(distribution.pdf) + + energy_out = np.array(energy_out) + pdf = np.array(pdf) + + h5_group.create_dataset("offset", data=offset) + dataset = h5_group.create_dataset("value", data=energy_out) + dataset.attrs["unit"] = ["MeV"] + h5_group.create_dataset("pdf", data=pdf) + + elif isinstance(data, ACEtk.continuous.KalbachMannDistributionData): + h5_group.attrs["type"] = "kalbach-mann" + + if not data.interpolation_data.is_linear_linear: + print_error("Non-linearly-interpolated kalbach-mann is not supported") + + # Check distribution support: all kalbach-mann + NE = data.number_incident_energies + + # Incident energy + energy = np.array(data.incident_energies) + energy = h5_group.create_dataset("energy", data=energy) + energy.attrs["unit"] = "MeV" + + # Tabulated distributions + offset = np.zeros(NE, dtype=int) + energy_out = [] + pdf = [] + precompound_factor = [] + angular_slope = [] + for i, distribution in enumerate(data.distributions): + offset[i] = len(pdf) + energy_out.extend(distribution.outgoing_energies) + pdf.extend(distribution.pdf) + precompound_factor.extend(distribution.precompound_fraction_values) + angular_slope.extend(distribution.angular_distribution_slope_values) + + energy_out = np.array(energy_out) + pdf = np.array(pdf) + precompound_factor = np.array(precompound_factor) + angular_slope = np.array(angular_slope) + + h5_group.create_dataset("offset", data=offset) + dataset = h5_group.create_dataset("energy_out", data=energy_out) + dataset.attrs["unit"] = "MeV" + h5_group.create_dataset("pdf", data=pdf) + h5_group.create_dataset("precompound_factor", data=precompound_factor) + h5_group.create_dataset("angular_slope", data=angular_slope) + + elif isinstance(data, ACEtk.continuous.EnergyAngleDistributionData): + h5_group.attrs["type"] = "energy-angle-tabulated" + + if not data.interpolation_data.is_linear_linear: + print_error( + "Non-linearly-interpolated correlated-energy-angle is not supported" + ) + + # Check distribution support: all kalbach-mann + NE = data.number_incident_energies + + # Incident energy + energy = np.array(data.incident_energies) + dataset = h5_group.create_dataset("energy", data=energy) + dataset.attrs["unit"] = "MeV" + + # Tabulated distributions + offset = np.zeros(NE, dtype=int) + energy_out = [] + pdf = [] + cosine_offset = [] + cosine = [] + cosine_pdf = [] + for i, distribution in enumerate(data.distributions): + offset[i] = len(pdf) + energy_out.extend(distribution.outgoing_energies) + pdf.extend(distribution.pdf) + + for inner_distribution in distribution.distributions: + cosine_offset.append(len(cosine_pdf)) + cosine.extend(inner_distribution.cosines) + cosine_pdf.extend(inner_distribution.pdf) + + energy_out = np.array(energy_out) + pdf = np.array(pdf) + cosine_offset = np.array(cosine_offset) + cosine = np.array(cosine) + cosine_pdf = np.array(cosine_pdf) + + h5_group.create_dataset("offset", data=offset) + dataset = h5_group.create_dataset("energy_out", data=energy_out) + dataset.attrs["unit"] = "MeV" + h5_group.create_dataset("pdf", data=pdf) + h5_group.create_dataset("cosine_offset", data=cosine_offset) + h5_group.create_dataset("cosine", data=cosine) + h5_group.create_dataset("cosine_pdf", data=cosine_pdf) + + elif isinstance(data, ACEtk.continuous.NBodyPhaseSpaceDistribution): + h5_group.attrs["type"] = "N-body" + + if data.interpolation != 2: + print_error("Non-linearly-interpolable N-body energy distribution") + + dataset = h5_group.create_dataset("value", data=data.values) + dataset.attrs["unit"] = "MeV" + h5_group.create_dataset("pdf", data=data.pdf) + + else: + print_error(f"Unsupported energy distribution: {data}") + + +# ====================================================================================== +# Constants +# ====================================================================================== + +INTERPOLATION_MAP = {2: "linear-linear"} + +ACE_TEMPERATURE_LIB81 = { + "10c": 293.6, + "11c": 600.0, + "12c": 900.0, + "13c": 1200.0, + "14c": 2500.0, + "15c": 0.1, + "16c": 233.15, + "17c": 273.15, +} + +TEMPERATURE_TO_ACELIB81 = {value: key for key, value in ACE_TEMPERATURE_LIB81.items()} + +SYMBOL_TO_Z = { + "H": 1, + "He": 2, + "Li": 3, + "Be": 4, + "B": 5, + "C": 6, + "N": 7, + "O": 8, + "F": 9, + "Ne": 10, + "Na": 11, + "Mg": 12, + "Al": 13, + "Si": 14, + "P": 15, + "S": 16, + "Cl": 17, + "Ar": 18, + "K": 19, + "Ca": 20, + "Sc": 21, + "Ti": 22, + "V": 23, + "Cr": 24, + "Mn": 25, + "Fe": 26, + "Co": 27, + "Ni": 28, + "Cu": 29, + "Zn": 30, + "Ga": 31, + "Ge": 32, + "As": 33, + "Se": 34, + "Br": 35, + "Kr": 36, + "Rb": 37, + "Sr": 38, + "Y": 39, + "Zr": 40, + "Nb": 41, + "Mo": 42, + "Tc": 43, + "Ru": 44, + "Rh": 45, + "Pd": 46, + "Ag": 47, + "Cd": 48, + "In": 49, + "Sn": 50, + "Sb": 51, + "Te": 52, + "I": 53, + "Xe": 54, + "Cs": 55, + "Ba": 56, + "La": 57, + "Ce": 58, + "Pr": 59, + "Nd": 60, + "Pm": 61, + "Sm": 62, + "Eu": 63, + "Gd": 64, + "Tb": 65, + "Dy": 66, + "Ho": 67, + "Er": 68, + "Tm": 69, + "Yb": 70, + "Lu": 71, + "Hf": 72, + "Ta": 73, + "W": 74, + "Re": 75, + "Os": 76, + "Ir": 77, + "Pt": 78, + "Au": 79, + "Hg": 80, + "Tl": 81, + "Pb": 82, + "Bi": 83, + "Po": 84, + "At": 85, + "Rn": 86, + "Fr": 87, + "Ra": 88, + "Ac": 89, + "Th": 90, + "Pa": 91, + "U": 92, + "Np": 93, + "Pu": 94, + "Am": 95, + "Cm": 96, + "Bk": 97, + "Cf": 98, + "Es": 99, + "Fm": 100, +} + +Z_TO_SYMBOL = {value: key for key, value in SYMBOL_TO_Z.items()}