Skip to content

Commit c043604

Browse files
oskooistevengj
andauthored
Fix bug for 3D simulation using 1D cell and single-precision floating point (#3157)
* fix bug for 3D simulation using 1D cell and single-precision floating point * approximately compare phase to +/- 1 * Apply suggestion from @stevengj * Update boundaries.cpp: rm redundant thephase --------- Co-authored-by: Steven G. Johnson <stevenj@alum.mit.edu> Co-authored-by: Steven G. Johnson <stevenj@mit.edu>
1 parent 72a530b commit c043604

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

src/boundaries.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,21 @@ bool fields_chunk::needs_W_notowned(component c) {
350350
return false;
351351
}
352352

353+
/* approximate comparisons of phases to 1 or -1. exp(ix) * exp(-ix) is not exactly 1
354+
due to roundoff errors, but we want to treat it equal for the purpose of determining
355+
the boundary conditions, because we have optimized b.c.'s for phase +1 and -1, and
356+
roundoff errors on the order of 1e-13 are not significant relative to the truncation
357+
errors in meep anyway. (the alternative would be to accumulate symmetry phases more
358+
accurately by adding exponents rather than multiplying). */
359+
static bool phase_isclose(std::complex<double> thephase, double realphase) {
360+
return fabs(thephase.imag()) < 1e-13 && fabs(thephase.real() - realphase) < 1e-13;
361+
}
362+
static connect_phase connect_phase_from_phase(std::complex<double> thephase) {
363+
return phase_isclose(thephase, 1.0) ? CONNECT_COPY
364+
: phase_isclose(thephase, -1.0) ? CONNECT_NEGATE
365+
: CONNECT_PHASE;
366+
}
367+
353368
void fields::connect_the_chunks() {
354369
/* For some of the chunks, H==B, and we definitely don't need to
355370
send B between two such chunks. We'll still send B when
@@ -405,9 +420,7 @@ void fields::connect_the_chunks() {
405420
if ((chunks[i]->is_mine() || chunks[j]->is_mine()) && chunks[j]->gv.owns(here) &&
406421
!(is_B(corig) && is_B(c) && B_redundant[5 * i + corig - Bx] &&
407422
B_redundant[5 * j + c - Bx])) {
408-
const connect_phase ip = thephase == 1.0
409-
? CONNECT_COPY
410-
: (thephase == -1.0 ? CONNECT_NEGATE : CONNECT_PHASE);
423+
const connect_phase ip = connect_phase_from_phase(thephase);
411424
comm_sizes[{type(c), ip, pair_j_to_i}] += num_reals_per_voxel;
412425

413426
if (needs_W_notowned[corig]) {
@@ -468,9 +481,8 @@ void fields::connect_the_chunks() {
468481
IVEC_LOOP_ILOC(vi, here);
469482
component c = corig;
470483
// We're looking at a border element...
471-
std::complex<double> thephase_double;
472-
if (locate_component_point(&c, &here, &thephase_double) && !on_metal_boundary(here)) {
473-
std::complex<realnum> thephase(thephase_double.real(), thephase_double.imag());
484+
std::complex<double> thephase;
485+
if (locate_component_point(&c, &here, &thephase) && !on_metal_boundary(here)) {
474486
for (int j = 0; j < num_chunks; j++) {
475487
const std::pair<int, int> pair_j_to_i{j, i};
476488
const bool i_is_mine = chunks[i]->is_mine();
@@ -494,10 +506,7 @@ void fields::connect_the_chunks() {
494506
if (chunks[j]->gv.owns(here) &&
495507
!(is_B(corig) && is_B(c) && B_redundant[5 * i + corig - Bx] &&
496508
B_redundant[5 * j + c - Bx])) {
497-
const connect_phase ip =
498-
thephase == static_cast<realnum>(1.0)
499-
? CONNECT_COPY
500-
: (thephase == static_cast<realnum>(-1.0) ? CONNECT_NEGATE : CONNECT_PHASE);
509+
const connect_phase ip = connect_phase_from_phase(thephase);
501510
const ptrdiff_t m = chunks[j]->gv.index(c, here);
502511

503512
{

tests/three_d.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,32 @@ int test_pml_splitting(double eps(const vec &), int splitting) {
223223
return 1;
224224
}
225225

226+
// Test that a 3D simulation with a 1D cell (zero size in X and Y)
227+
// and Bloch-periodic boundaries does not crash. This exercises the
228+
// boundary connection logic where the connect_phase classification
229+
// must be consistent between the counting pass and the connection
230+
// setup pass, regardless of the realnum precision. (See issue #2916.)
231+
int test_1d_cell_bloch() {
232+
double a = 52.0;
233+
double pml_um = 1.0;
234+
double air_um = 10.0;
235+
double size_z = pml_um + air_um + pml_um;
236+
237+
grid_volume gv = vol3d(0, 0, size_z, a);
238+
gv.center_origin();
239+
structure s(gv, one, pml(pml_um));
240+
241+
master_printf("Testing 1D cell with Bloch boundaries...\n");
242+
fields f(&s);
243+
f.use_bloch(vec(-0.2, -0.2, 0.0));
244+
f.add_point_source(Ex, 1.0, 0.1, 0.0, 4.0, vec(0, 0, 0));
245+
246+
while (f.time() < 5.0)
247+
f.step();
248+
249+
return 1;
250+
}
251+
226252
int main(int argc, char **argv) {
227253
initialize mpi(argc, argv);
228254
verbosity = 0;
@@ -239,5 +265,7 @@ int main(int argc, char **argv) {
239265
for (int s = 2; s < 4; s++)
240266
if (!test_pml_splitting(one, s)) meep::abort("error in test_pml_splitting vacuum\n");
241267

268+
if (!test_1d_cell_bloch()) meep::abort("error in test_1d_cell_bloch\n");
269+
242270
return 0;
243271
}

0 commit comments

Comments
 (0)