32 auto geometry =
SOLVER->getGeometry();
39 back = geometry->getChild()->getBoundingBox().lower[0];
40 front = geometry->getChild()->getBoundingBox().upper[0];
41 left = geometry->getChild()->getBoundingBox().lower[1];
42 right = geometry->getChild()->getBoundingBox().upper[1];
49 throw BadInput(
solver->
getId(),
"longitudinal symmetry not allowed for asymmetric structure");
51 throw BadInput(
solver->
getId(),
"transverse symmetry not allowed for asymmetric structure");
60 throw BadInput(
SOLVER->getId(),
"longitudinally symmetric geometry must have one of its sides at symmetry axis");
70 throw BadInput(
SOLVER->getId(),
"transversely symmetric geometry must have one of its sides at symmetry axis");
75 if (
SOLVER->getLongSize() == 0)
77 "Flat structure in longitudinal direction (size_long = 0) allowed only for periodic geometry");
83 if (
SOLVER->getTranSize() == 0)
85 "Flat structure in transverse direction (size_tran = 0) allowed only for periodic geometry");
112 size_t nNa = 4 *
SOLVER->getLongSize() + 1;
133 size_t nNa = 4 *
SOLVER->getTranSize() + 1;
143 :
" symmetric in longitudinal direction");
164 SOLVER->writelog(
LOG_DETAIL,
"Adding side PMLs (total structure dimensions: {0}um x {1}um)",
Ll,
Lt);
178 for (
size_t i = 0; i !=
nNl; ++i) {
179 for (
size_t j =
refl * i, end =
refl * (i + 1); j != end; ++j) {
183 s = 1. + (
SOLVER->pml_long.factor - 1.) * pow(h,
SOLVER->pml_long.order);
184 }
else if (j >
pif) {
186 s = 1. + (
SOLVER->pml_long.factor - 1.) * pow(h,
SOLVER->pml_long.order);
194 .execute(
reinterpret_cast<dcomplex*
>(
mag_long.data()));
199 for (std::size_t i = 0; i !=
nNl; ++i) {
218 for (
size_t i = 0; i !=
nNt; ++i) {
219 for (
size_t j =
reft * i, end =
reft * (i + 1); j != end; ++j) {
223 s = 1. + (
SOLVER->pml_tran.factor - 1.) * pow(h,
SOLVER->pml_tran.order);
224 }
else if (j >
pir) {
226 s = 1. + (
SOLVER->pml_tran.factor - 1.) * pow(h,
SOLVER->pml_tran.order);
234 .execute(
reinterpret_cast<dcomplex*
>(
mag_tran.data()));
239 for (std::size_t i = 0; i !=
nNt; ++i) {
295 auto geometry =
SOLVER->getGeometry();
304#if defined(OPENMP_FOUND)
305 SOLVER->writelog(
LOG_DETAIL,
"Getting refractive indices for layer {}/{} (sampled at {}x{} points) in thread {}", layer,
312 if (
isnan(lam))
throw BadInput(
SOLVER->getId(),
"no wavelength given: specify 'lam' or 'lam0'");
315 for (
size_t i = 0; i !=
solver->
stack.size(); ++i) {
323 SOLVER->writelog(
LOG_DEBUG,
"Layer {:d} takes some materials parameters from inEpsilon", layer);
335 std::fill_n(
reinterpret_cast<char*
>(
coeffs.data()),
nN *
sizeof(
Coeff), 0);
385 for (
size_t t =
tbegin, j = 0; t !=
tend; ++t) {
386 for (
size_t l =
lbegin; l !=
lend; ++l, ++j) {
387 std::set<std::string> roles;
394 for (
size_t k = 0,
v =
mesh->index(l, t, 0); k !=
mesh->vert()->size(); ++
v, ++k) {
397 throw BadInput(
solver->
getId(),
"complex permittivity tensor got from inEpsilon is NaN at {}",
399 double w = (k == 0 || k ==
mesh->vert()->size() - 1)
408 double T = 0.,
W = 0., C = 0.;
409 for (
size_t k = 0,
v =
mesh->index(l, t, 0); k !=
mesh->vert()->size(); ++
v, ++k) {
411 double w = (k == 0 || k ==
mesh->vert()->size() - 1)
424 lock = material->lock();
425 cell[j] = material->Eps(lam, T, C);
428 "complex permittivity tensor (Eps) for {} is NaN at lam={}nm, T={}K n={}/cm3",
429 material->name(), lam, T, C);
432 if (roles.find(
"QW") != roles.end() || roles.find(
"QD") != roles.end() ||
433 roles.find(
"gain") != roles.end()) {
436 for (
size_t k = 0,
v =
mesh->index(l, t, 0); k !=
mesh->vert()->size(); ++
v, ++k) {
438 double w = (k == 0 || k ==
mesh->vert()->size() - 1)
446 double n00 = sqrt(
cell[j].c00).real(), n11 = sqrt(
cell[j].c11).real(),
447 n22 = sqrt(
cell[j].c22).real();
448 cell[j].c00 = dcomplex(n00 * n00 -
ni.c00 *
ni.c00, 2 * n00 *
ni.c00);
449 cell[j].c11 = dcomplex(n11 * n11 -
ni.c00 *
ni.c00, 2 * n11 *
ni.c00);
451 cell[j].c01.imag(0.);
452 cell[j].c02.imag(0.);
453 cell[j].c10.imag(0.);
454 cell[j].c12.imag(0.);
455 cell[j].c20.imag(0.);
456 cell[j].c21.imag(0.);
466 s = 1. + (
SOLVER->pml_long.factor - 1.) * pow(h,
SOLVER->pml_long.order);
467 }
else if (l >
pif) {
469 s = 1. + (
SOLVER->pml_long.factor - 1.) * pow(h,
SOLVER->pml_long.order);
471 cell[j].c00 *= 1. / s;
479 s = 1. + (
SOLVER->pml_tran.factor - 1.) * pow(h,
SOLVER->pml_tran.order);
480 }
else if (t >
pir) {
482 s = 1. + (
SOLVER->pml_tran.factor - 1.) * pow(h,
SOLVER->pml_tran.order);
485 cell[j].c11 *= 1. / s;
500 for (
size_t t =
tbegin, j = 0; t !=
tend; ++t) {
501 for (
size_t l =
lbegin; l !=
lend; ++l, ++j) {
508 double a = abs(
norm);
514 for (
size_t t =
tbegin, j = 0; t !=
tend; ++t) {
515 for (
size_t l =
lbegin; l !=
lend; ++l, ++j) {
524 eps = commutator(P, ieps.
inv()) + commutator(
P1,
eps);
530 throw BadInput(
solver->
getId(),
"complex permittivity tensor (Eps) must be Hermitian for this solver");
541 double vmax = 0., vmin = std::numeric_limits<double>::max();
543 for (
size_t i = 0,
nM =
nMl *
nMt; i <
nM; ++i, ++
v) {
544 if (*
v > vmax) vmax = *
v;
545 if (*
v < vmin) vmin = *
v;
547 if (vmax != vmin)
normlim *= 0.1 * (vmax - vmin);
588 double a = abs(
norm);
612 for (
size_t i = 1; i !=
nN; ++i) {
624 std::fill_n(
reinterpret_cast<dcomplex*
>(
coeffs.data() + 1), 6 * (
coeffs.size() - 1), 0.);
640 for (
size_t i = 0; i !=
nN; ++i) {
661 for (std::size_t
it = 0;
it !=
nNt; ++
it) {
664 for (std::size_t
il = 0;
il !=
nNl; ++
il) {
708 std::vector<Gradient::Vertex>
vertices;
711 for (
int t = 0; t <
nNt; ++t) {
712 for (
int l = 0; l <
nNl; ++l, ++i) {
717 for (
int t = 0; t <
nNt; ++t) {
718 for (
int l = 0; l <
nNl; ++l, ++i) {
744 double c2 =
grad.
c2.real();
748 double cs = sqrt(c2 - c2 * c2);
749 if (
grad.cs.real() >= 0)
780 if (
SOLVER->grad_smooth) {
785 for (std::size_t
it = 0;
it !=
nNt; ++
it) {
788 for (std::size_t
il = 0;
il !=
nNl; ++
il) {
1218 double vpos = level->vpos();
1227 for (
size_t t = 0, end = nl *
nt; t != end; t += nl) field[nl - 1 + t] =
Vec<3, dcomplex>(0., 0., 0.);
1248 if (!(
it == 0 &&
dxt) && !(
il == 0 &&
dyl)) {
1249 field[
iez].vert() = 0.;
1256 field[
iez].vert() +=
1262 field[
iez].vert() /=
k0;
1274 if (!(
it == 0 &&
dxt) && !(
il == 0 &&
dyl)) {
1275 field[
ihz].vert() = 0.;
1285 field[
ihz].vert() /=
k0;
1296 dcomplex
ikx =
I * kx,
iky =
I * ky;
1299 double ftx = 1.,
fty = 1.;
1316 double flx = 1.,
fly = 1.;
1336 for (
size_t ip = 0;
ip != dest_mesh->size(); ++
ip) {
1337 auto p = dest_mesh->at(
ip);
1347 fft_x.
execute(&(field.data()->lon()), 1);
1348 fft_y.
execute(&(field.data()->tran()), 1);
1349 fft_z.
execute(&(field.data()->vert()), 1);
1354 for (
size_t l = 0,
off = nl *
Nt; l !=
Nl; ++l) field[
off + l] = field[l];
1360 for (
size_t t = 0, end = nl *
nt; t != end; t += nl) field[
Nl + t] = field[t];
1381 double x = std::fmod(dest_mesh->at(i)[0],
Ll);
1387 double x = std::fmod(dest_mesh->at(i)[0],
Ll);
1393 dcomplex
ikx =
I * kx;
1399 double y = std::fmod(dest_mesh->at(i)[1],
Lt);
1405 double y = std::fmod(dest_mesh->at(i)[1],
Lt);
1411 dcomplex
iky =
I * ky;
1417 fft_z.
execute(
reinterpret_cast<dcomplex*
>(field.data()));
1418 for (
size_t l = 0,
off = nl *
Nt; l !=
Nl; ++l) field[
off + l] = field[l];
1419 for (
size_t t = 0, end = nl *
nt; t != end; t += nl) field[
Nl + t] = field[t];
1428 dcomplex
ikx =
I * kx,
iky =
I * ky;
1453 std::fill_n(Te.
data(), nr *
nc, 0.);
1454 std::fill_n(Te1.
data(), nr *
nc, 0.);
1459 for (std::size_t i = 0; i <
n; i++) {
1463 dcomplex
a =
RE(2 * i, 2 * i),
b =
RE(2 * i, 2 * i + 1), c =
RE(2 * i + 1, 2 * i), d =
RE(2 * i + 1, 2 * i + 1);
1465 Te1(2 * i, 2 * i) = Te1(2 * i + 1, 2 * i + 1) = Te(2 * i, 2 * i) = Te(2 * i + 1, 2 * i + 1) = 1.;
1466 Te1(2 * i, 2 * i + 1) = Te1(2 * i + 1, 2 * i) = Te(2 * i, 2 * i + 1) = Te(2 * i + 1, 2 * i) = 0.;
1468 dcomplex s = sqrt(
a * d -
b * c);
1472 s = 1. / sqrt(
a *
a +
b *
b);
1475 s = 1. / sqrt(c * c + d * d);
1478 Te1(2 * i, 2 * i) =
a;
1479 Te1(2 * i, 2 * i + 1) =
b;
1480 Te1(2 * i + 1, 2 * i) = c;
1481 Te1(2 * i + 1, 2 * i + 1) = d;
1483 s = 1. / (
a * d -
b * c);
1484 Te(2 * i, 2 * i) = s * d;
1485 Te(2 * i, 2 * i + 1) = -s *
b;
1486 Te(2 * i + 1, 2 * i) = -s * c;
1487 Te(2 * i + 1, 2 * i + 1) = s *
a;
1619 double z = level->vpos();
1621 const int which =
int(what);
1630 return LazyData<double>(dest_mesh->size(), [
this,
lay, which, dest_mesh](
size_t i) ->
double {
1632 const int nt = symmetric_tran() ? int(nNt) - 1 : int(nNt / 2), nl = symmetric_long() ? int(nNl) - 1 : int(nNl / 2);
1633 double Lt = right - left;
1634 if (symmetric_tran()) Lt *= 2;
1635 double Ll = front - back;
1636 if (symmetric_long()) Ll *= 2;
1638 for (int kt = -nt; kt <= nt; ++kt) {
1639 size_t t = (kt >= 0) ? kt : (symmetric_tran()) ? -kt : kt + nNt;
1640 const double phast = kt * (dest_mesh->at(i).c1 - left) / Lt;
1641 for (int kl = -nl; kl <= nl; ++kl) {
1642 size_t l = (kl >= 0) ? kl : (symmetric_long()) ? -kl : kl + nNl;
1643 res += (*(reinterpret_cast<dcomplex*>(gradients[lay].data() + nNl * t + l) + which) *
1644 exp(2 * PI * I * (kl * (dest_mesh->at(i).c0 - back) / Ll + phast)))
1648 if (which && (dest_mesh->at(i).c0 < 0) != (dest_mesh->at(i).c1 < 0))
res = -
res;
1652 size_t nl = symmetric_long() ? nNl : nNl + 1,
nt = symmetric_tran() ? nNt : nNt + 1;
1656 for (
size_t t = 0; t != nNt; ++t) {
1657 size_t op = nl * t,
oc = nNl * t;
1658 for (
size_t l = 0; l != nNl; ++l) {
1659 work[
op + l] = *(
reinterpret_cast<dcomplex*
>((gradients[
lay].data() +
oc + l)) + which);
1663 : (which ? FFT::SYMMETRY_ODD_1 : FFT::SYMMETRY_EVEN_1);
1664 FFT::Backward2D(1, nNl, nNt, symmetric_long() ?
dct_symmetry : FFT::SYMMETRY_NONE,
1665 symmetric_tran() ?
dct_symmetry : FFT::SYMMETRY_NONE, nl)
1668 auto dst =
grads.begin();
1669 for (
const dcomplex& val :
work) *(dst++) = val.
real();
1672 if (symmetric_long()) {
1674 double dx = 0.5 * (front - back) /
double(nl);
1677 lcmesh->reset(0., front, nl);
1680 lcmesh->reset(back, front, nl);
1681 for (
size_t t = 0, end = nl *
nt, dist = nl - 1; t !=
end; t +=
nl)
grads[dist + t] =
grads[t];
1683 if (symmetric_tran()) {
1692 for (
size_t l = 0, last = nl * (
nt - 1); l !=
nl; ++l)
grads[last + l] =
grads[l];
1701 src_mesh,
grads, dest_mesh, interp,
1702 InterpolationFlags(
SOLVER->getGeometry(), symmetric_long() ? sym : InterpolationFlags::
Symmetry::NO,
1703 symmetric_tran() ?
sym : InterpolationFlags::
Symmetry::NO, InterpolationFlags::
Symmetry::POSITIVE));