52 dcomplex ff, fb, bf,
bb;
54 MatrixZ(dcomplex t1, dcomplex t2, dcomplex t3, dcomplex t4) : ff(t1), fb(t2), bf(t3), bb(t4) {}
67 FieldR(dcomplex j, dcomplex h) : J(j), H(h) {}
83 dcomplex JJ, JH, HJ,
HH;
84 MatrixR(dcomplex jj, dcomplex jh, dcomplex hj, dcomplex hh) : JJ(jj), JH(jh), HJ(hj), HH(hh) {}
91 return MatrixR(c * JJ, c * JH, c * HJ, c * HH);
115 result /= (JJ * HH - JH * HJ);
138 std::vector<FieldR, aligned_allocator<FieldR>>
rfields;
139 std::vector<double, aligned_allocator<double>>
rweights;
144 : solver(solver), m(m), have_fields(false), rfields(solver->rsize), rweights(solver->rsize), power(1.) {}
150 double Jr, Ji, Hr, Hi;
152 size_t ir = solver->mesh->axis[0]->findIndex(r);
154 if (ir >= solver->veffs.size()) ir = solver->veffs.size() - 1;
155 dcomplex x = r * solver->k0 * sqrt(solver->nng[ir] * (solver->veffs[ir] - solver->freqv(lam)));
156 if (
real(x) < 0.) x = -x;
157 if (imag(x) >
SMALL) x = -x;
158 if (ir == solver->rsize - 1) {
161 zbesj(x.real(), x.imag(), m, 1, 1, &Jr, &Ji, nz, ierr);
162 if (ierr != 0)
throw ComputationError(solver->getId(),
"could not compute J({0}, {1}) @ r = {2}um", m,
str(x), r);
167 zbesh(x.real(), x.imag(), m, 1, MH, 1, &Hr, &Hi, nz, ierr);
168 if (ierr != 0)
throw ComputationError(solver->getId(),
"could not compute H({0}, {1}) @ r = {2}um", m,
str(x), r);
170 return rfields[ir].J * dcomplex(Jr, Ji) + rfields[ir].H * dcomplex(Hr, Hi);
174 double loss()
const {
return imag(4e7 *
PI / lam); }
178 dcomplex
freqv(dcomplex lam) {
return 2. - 4e3 *
PI / lam / k0; }
181 dcomplex
lambda(dcomplex freq) {
return 2e3 *
PI / (k0 * (1. - freq / 2.)); }
194 std::vector<std::vector<dcomplex, aligned_allocator<dcomplex>>>
nrCache;
197 std::vector<std::vector<dcomplex, aligned_allocator<dcomplex>>>
ngCache;
206 std::vector<dcomplex, aligned_allocator<dcomplex>>
veffs;
209 std::vector<dcomplex, aligned_allocator<dcomplex>>
nng;
235 if (!mesh) setSimpleMesh();
236 if (stripe < 0 || std::size_t(stripe) >= mesh->axis[0]->size())
throw BadInput(getId(),
"wrong stripe number specified");
243 if (rstripe == -1 || !mesh)
return NAN;
244 return mesh->axis[0]->at(rstripe);
252 if (!mesh) setSimpleMesh();
253 if (r < 0)
throw BadInput(getId(),
"radial position cannot be negative");
254 rstripe = int(std::lower_bound(mesh->axis[0]->begin() + 1, mesh->axis[0]->end(), r) - mesh->axis[0]->begin() - 1);
270 if (r < 0)
throw BadInput(getId(),
"radial position cannot be negative");
271 size_t ir = mesh->axis[0]->findIndex(r);
273 if (ir >= veffs.size()) ir = veffs.size() - 1;
274 return sqrt(nng[ir] * veffs[ir]);
283 if (r < 0)
throw BadInput(getId(),
"radial position cannot be negative");
284 size_t ir = mesh->axis[0]->findIndex(r);
286 if (ir >= veffs.size()) ir = veffs.size() - 1;
287 return sqrt(nng[ir]);
341 std::string
getClassName()
const override {
return "optical.EffectiveFrequencyCyl"; }
344 return "Calculate optical modes and optical field distribution using the effective index method "
345 "in Cartesian two-dimensional space.";
358 for (
auto& mode : modes) mode.have_fields =
false;
379 meshxy->setTran(meshx);
401 size_t findMode(dcomplex lambda,
int m = 0);
416 std::vector<size_t> findModes(plask::dcomplex lambda1 = 0.,
417 plask::dcomplex lambda2 = 0.,
419 size_t resteps = 256,
421 dcomplex eps = dcomplex(1
e-6, 1
e-9));
429 if (rstripe < 0)
throw BadInput(getId(),
"this works only for the weighted approach");
430 if (vlam == 0. &&
isnan(k0.real()))
throw BadInput(getId(),
"no reference wavelength `lam0` specified");
431 dcomplex v = freqv(vlambda);
432 return this->detS1(v, nrCache[rstripe], ngCache[rstripe]);
441 if (
isnan(k0.real()))
throw BadInput(getId(),
"no reference wavelength `lam0` specified");
444 dcomplex det = detS(lambda, mode);
455 size_t setMode(dcomplex clambda,
int m = 0);
465 inline size_t setMode(
double lambda,
double loss,
int m = 0) {
466 return setMode(dcomplex(lambda, -lambda * lambda / (4e7 *
PI) * loss), m);
476 double getTotalAbsorption(Mode& mode);
482 double getTotalAbsorption(
size_t num);
488 double getGainIntegral(Mode& mode);
494 double getGainIntegral(
size_t num);
510 void onInitialize()
override;
513 void onInvalidate()
override;
527 dcomplex detS1(
const dcomplex& v,
530 std::vector<FieldZ>* saveto =
nullptr);
533 void computeStripeNNg(
size_t stripe,
bool save_integrals =
false);
538 double integrateBessel(
Mode& mode);
541 void computeBessel(
size_t i, dcomplex v,
const Mode& mode, dcomplex* J1, dcomplex* H1, dcomplex* J2, dcomplex* H2);
544 dcomplex detS(
const plask::dcomplex& lam,
Mode& mode,
bool save =
false);
551 bool all_the_same =
true;
552 while (all_the_same) {
553 dcomplex same_nr = nrCache[stripe].front();
554 dcomplex same_ng = ngCache[stripe].front();
555 for (
auto nr = nrCache[stripe].begin(), ng = ngCache[stripe].begin(); nr != nrCache[stripe].end(); ++nr, ++ng)
556 if (*nr != same_nr || *ng != same_ng) {
557 all_the_same =
false;
560 if (all_the_same) ++stripe;
571 for (
size_t i = 0; i != modes.size(); ++i)
572 if (modes[i] == mode)
return i;
573 modes.push_back(mode);
574 outWavelength.fireChanged();
575 outLoss.fireChanged();
576 outLightMagnitude.fireChanged();
577 outLightE.fireChanged();
578 return modes.size() - 1;
582 size_t nmodes()
const {
return modes.size(); }
589 if (
n >= modes.size())
throw NoValue(ModeWavelength::NAME);
590 return real(modes[
n].lam);
598 if (
n >= modes.size())
throw NoValue(ModeLoss::NAME);
599 return imag(4e7 *
PI / modes[
n].lam);
602 template <
typename T>
struct FieldDataBase;
603 template <
typename T>
struct FieldDataInefficient;
604 template <
typename T>
struct FieldDataEfficient;
609 const shared_ptr<
const MeshD<2>>& dst_mesh,
619 const shared_ptr<
const MeshD<2>>& dst_mesh,