Skip to content

Commit 52f8618

Browse files
authored
Merge pull request #2439 from paulromano/cyl-sph-mesh-coincident-bugfix
Fix bug in cylindrical and spherical meshes when grid boundary is coincident with cell boundary
2 parents 2630dbf + 5b7fb42 commit 52f8618

File tree

2 files changed

+108
-5
lines changed

2 files changed

+108
-5
lines changed

src/mesh.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,8 @@ void StructuredMesh::raytrace_mesh(
500500
}
501501

502502
// translate start and end positions,
503-
// this needs to come after the get_indices call because it does its own translation
503+
// this needs to come after the get_indices call because it does its own
504+
// translation
504505
local_coords(r0);
505506
local_coords(r1);
506507

@@ -1075,15 +1076,16 @@ double CylindricalMesh::find_r_crossing(
10751076
const double inv_denominator = 1.0 / denominator;
10761077

10771078
const double p = (u.x * r.x + u.y * r.y) * inv_denominator;
1078-
double D = p * p + (r0 * r0 - r.x * r.x - r.y * r.y) * inv_denominator;
1079+
double c = r.x * r.x + r.y * r.y - r0 * r0;
1080+
double D = p * p - c * inv_denominator;
10791081

10801082
if (D < 0.0)
10811083
return INFTY;
10821084

10831085
D = std::sqrt(D);
10841086

10851087
// the solution -p - D is always smaller as -p + D : Check this one first
1086-
if (-p - D > l)
1088+
if (-p - D > l && std::abs(c) > 1e-10)
10871089
return -p - D;
10881090
if (-p + D > l)
10891091
return -p + D;
@@ -1303,12 +1305,13 @@ double SphericalMesh::find_r_crossing(
13031305
// |r+s*u| = |r| + 2*s*r*u + s^2 (|u|==1 !)
13041306
const double r0 = grid_[0][shell];
13051307
const double p = r.dot(u);
1306-
double D = p * p - r.dot(r) + r0 * r0;
1308+
double c = r.dot(r) - r0 * r0;
1309+
double D = p * p - c;
13071310

13081311
if (D >= 0.0) {
13091312
D = std::sqrt(D);
13101313
// the solution -p - D is always smaller as -p + D : Check this one first
1311-
if (-p - D > l)
1314+
if (-p - D > l && std::abs(c) > 1e-10)
13121315
return -p - D;
13131316
if (-p + D > l)
13141317
return -p + D;

tests/unit_tests/test_filter_mesh.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import math
22

33
import numpy as np
4+
import pytest
45
from uncertainties import unumpy
56

67
import openmc
@@ -112,6 +113,105 @@ def test_cylindrical_mesh_estimators(run_in_tmpdir):
112113
std_dev = unumpy.std_devs(delta)
113114
assert np.all(diff < 3*std_dev)
114115

116+
117+
@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5])
118+
def test_cylindrical_mesh_coincident(scale, run_in_tmpdir):
119+
"""Test for cylindrical mesh boundary being coincident with a cell boundary"""
120+
121+
fuel = openmc.Material()
122+
fuel.add_nuclide('U235', 1.)
123+
fuel.set_density('g/cm3', 4.5)
124+
125+
zcyl = openmc.ZCylinder(r=1.25*scale)
126+
box = openmc.rectangular_prism(4*scale, 4*scale, boundary_type='reflective')
127+
cell1 = openmc.Cell(fill=fuel, region=-zcyl)
128+
cell2 = openmc.Cell(fill=None, region=+zcyl & box)
129+
model = openmc.Model()
130+
model.geometry = openmc.Geometry([cell1, cell2])
131+
132+
model.settings.particles = 100
133+
model.settings.batches = 10
134+
model.settings.inactive = 0
135+
136+
cyl_mesh = openmc.CylindricalMesh()
137+
cyl_mesh.r_grid = [0., 1.25*scale]
138+
cyl_mesh.phi_grid = [0., 2*math.pi]
139+
cyl_mesh.z_grid = [-1e10, 1e10]
140+
cyl_mesh_filter = openmc.MeshFilter(cyl_mesh)
141+
cell_filter = openmc.CellFilter([cell1])
142+
143+
tally1 = openmc.Tally()
144+
tally1.filters = [cyl_mesh_filter]
145+
tally1.scores = ['flux']
146+
tally2 = openmc.Tally()
147+
tally2.filters = [cell_filter]
148+
tally2.scores = ['flux']
149+
model.tallies = openmc.Tallies([tally1, tally2])
150+
151+
# Run OpenMC
152+
sp_filename = model.run()
153+
154+
# Get flux for each of the two tallies
155+
with openmc.StatePoint(sp_filename) as sp:
156+
t1 = sp.tallies[tally1.id]
157+
t2 = sp.tallies[tally2.id]
158+
mean1 = t1.mean.ravel()[0]
159+
mean2 = t2.mean.ravel()[0]
160+
161+
# The two tallies should be exactly the same
162+
assert mean1 == pytest.approx(mean2)
163+
164+
165+
@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5])
166+
def test_spherical_mesh_coincident(scale, run_in_tmpdir):
167+
"""Test for spherical mesh boundary being coincident with a cell boundary"""
168+
169+
fuel = openmc.Material()
170+
fuel.add_nuclide('U235', 1.)
171+
fuel.set_density('g/cm3', 4.5)
172+
173+
sph = openmc.Sphere(r=1.25*scale)
174+
rcc = openmc.model.RectangularParallelepiped(
175+
-2*scale, 2*scale, -2*scale, 2*scale, -2*scale, 2*scale,
176+
boundary_type='reflective')
177+
cell1 = openmc.Cell(fill=fuel, region=-sph)
178+
cell2 = openmc.Cell(fill=None, region=+sph & -rcc)
179+
model = openmc.Model()
180+
model.geometry = openmc.Geometry([cell1, cell2])
181+
182+
model.settings.particles = 100
183+
model.settings.batches = 10
184+
model.settings.inactive = 0
185+
186+
sph_mesh = openmc.SphericalMesh()
187+
sph_mesh.r_grid = [0., 1.25*scale]
188+
sph_mesh.phi_grid = [0., 2*math.pi]
189+
sph_mesh.theta_grid = [0., math.pi]
190+
sph_mesh_filter = openmc.MeshFilter(sph_mesh)
191+
cell_filter = openmc.CellFilter([cell1])
192+
193+
tally1 = openmc.Tally()
194+
tally1.filters = [sph_mesh_filter]
195+
tally1.scores = ['flux']
196+
tally2 = openmc.Tally()
197+
tally2.filters = [cell_filter]
198+
tally2.scores = ['flux']
199+
model.tallies = openmc.Tallies([tally1, tally2])
200+
201+
# Run OpenMC
202+
sp_filename = model.run()
203+
204+
# Get flux for each of the two tallies
205+
with openmc.StatePoint(sp_filename) as sp:
206+
t1 = sp.tallies[tally1.id]
207+
t2 = sp.tallies[tally2.id]
208+
mean1 = t1.mean.ravel()[0]
209+
mean2 = t2.mean.ravel()[0]
210+
211+
# The two tallies should be exactly the same
212+
assert mean1 == pytest.approx(mean2)
213+
214+
115215
def test_get_reshaped_data(run_in_tmpdir):
116216
"""Test that expanding MeshFilter dimensions works as expected"""
117217

0 commit comments

Comments
 (0)