272 if (py::len(
args) != 1)
273 throw TypeError(
u8"get_determinant() takes exactly one non-keyword argument ({0} given)", py::len(
args));
288 plask::optional<dcomplex> wavelength, k0;
292 py::stl_input_iterator<std::string> begin(
kwargs), end;
293 for (
auto i = begin; i != end; ++i) {
296 if (what)
throw TypeError(
u8"only one key may be an array");
297 what = WHAT_WAVELENGTH; array =
kwargs[*i];
299 wavelength.reset(py::extract<dcomplex>(
kwargs[*i]));
300 }
else if (*i ==
"k0") {
302 if (what)
throw TypeError(
u8"only one key may be an array");
303 what = WHAT_K0; array =
kwargs[*i];
305 k0.reset(dcomplex(py::extract<dcomplex>(
kwargs[*i])));
306 }
else if (*i ==
"klong" || *i ==
"kl" || *i ==
"k"+axes->getNameForLong()) {
310 if (expansion->symmetric_long())
311 throw Exception(
"{0}: Cannot get determinant for longitudinal wavevector array with longitudinal symmetry",
313 if (what)
throw TypeError(
u8"only one key may be an array");
314 what = WHAT_KLONG; array =
kwargs[*i];
316 klong = py::extract<dcomplex>(
kwargs[*i]);
317 if (expansion->symmetric_long() && klong != 0.)
318 throw Exception(
"{0}: Longitudinal wavevector must be 0 with longitudinal symmetry", self->
getId());
320 }
else if (*i ==
"ktran" || *i ==
"kt" || *i ==
"k"+axes->getNameForTran()) {
324 if (expansion->symmetric_tran())
325 throw Exception(
"{0}: Cannot get determinant for transverse wavevector array with transverse symmetry",
327 if (what)
throw TypeError(
u8"only one key may be an array");
328 what = WHAT_KTRAN; array =
kwargs[*i];
330 ktran = py::extract<dcomplex>(
kwargs[*i]);
331 if (expansion->symmetric_tran() && ktran != 0.)
332 throw Exception(
"{0}: Transverse wavevector must be 0 with transverse symmetry", self->
getId());
335 throw TypeError(
u8"get_determinant() got unexpected keyword argument '{0}'", *i);
338 self->Solver::initCalculation();
341 if (k0)
throw BadInput(self->
getId(),
u8"'lam' and 'k0' are mutually exclusive");
342 expansion->setK0(2
e3*
PI / (*wavelength));
344 expansion->setK0(*k0);
346 expansion->setK0(self->
getK0());
348 expansion->setKlong(klong);
349 expansion->setKtran(ktran);
350 expansion->setLam0(self->
getLam0());
357 case WHAT_WAVELENGTH:
360 array,
"Fourier3D.get_determinant",
"lam"
365 array,
"Fourier3D.get_determinant",
"k0"
370 array,
"Fourier3D.get_determinant",
"klong"
375 array,
"Fourier3D.get_determinant",
"ktran"
521 u8"Optical Solver using Fourier expansion in 3D.\n\n"
522 u8"It calculates optical modes and optical field distribution using Fourier modal method\n"
523 u8"and reflection transfer in three-dimensional Cartesian space.")
525 solver.add_property(
"size",
528 py::default_call_policies(),
529 boost::mpl::vector3<void, FourierSolver3D&, py::object>()),
530 u8"Orthogonal expansion sizes in longitudinal and transverse directions.");
531 solver.add_property(
"refine",
534 py::default_call_policies(),
535 boost::mpl::vector3<void, FourierSolver3D&, py::object>()),
536 u8"Number of refinement points for refractive index averaging in longitudinal and transverse directions.");
537 solver.add_property(
"pmls",
540 py::default_call_policies(),
541 boost::mpl::vector3<void, FourierSolver3D&, py::object>()),
542 u8"Longitudinal and transverse edge Perfectly Matched Layers boundary conditions.\n\n"
544 solver.add_property(
"symmetry",
547 u8"Longitudinal and transverse mode symmetries.\n");
548 solver.add_property(
"dct", &__Class__::getDCT, &__Class__::setDCT,
"Type of discrete cosine transform for symmetric expansion.");
549 solver.add_property(
"rule", &__Class__::getRule, &__Class__::setRule,
550 "Permittivity inversion rule.\n\n"
551 "Can be 'direct', 'inverse', 'combined', or 'old'. The new 'combined' rule is\n"
552 "supposed to provide the best convergence. 'old' is available for consistency\n"
553 "with old results.\n");
554 solver.add_property(
"grad_smooth", &__Class__::getGradSmooth, &__Class__::setGradSmooth,
555 "Smoothing parameter for material boundaries gradients (needed for the new expansion rule).");
556 solver.add_provider(
"outGradients", &__Class__::outGradients,
"Gradients are important if the new factorization rule is used.");
558 u8"Wavelength of the light (nm).\n\n"
559 u8"Use this property only if you are looking for anything else than\n"
560 u8"the wavelength, e.g. the effective index of lateral wavevector.\n");
562 u8"Alias for :attr:`lam`");
564 u8"Normalized frequency of the light (1/µm).\n\n"
565 u8"Use this property only if you are looking for anything else than\n"
566 u8"the wavelength,e.g. the effective index of lateral wavevector.\n");
568 u8"Longitudinal propagation constant of the light (1/µm).\n\n"
569 u8"Use this property only if you are looking for anything else than\n"
570 u8"the longitudinal component of the propagation vector and the effective index.\n");
572 u8"Transverse propagation constant of the light (1/µm).\n\n"
573 u8"Use this property only if you are looking for anything else than\n"
574 u8"the transverse component of the propagation vector.\n");
575 RW_FIELD(emission,
u8"Direction of the useful light emission.\n\n"
576 u8"Necessary for the over-threshold model to correctly compute the output power.\n"
577 u8"Currently the fields are normalized only if this parameter is set to\n"
578 u8"``top`` or ``bottom``. Otherwise, it is ``undefined`` (default) and the fields\n"
579 u8"are not normalized.");
581 u8"Compute discontinuity matrix determinant.\n\n"
582 u8"Arguments can be given through keywords only.\n\n"
584 u8" lam (complex): Wavelength (nm).\n"
585 u8" k0 (complex): Normalized frequency (1/µm).\n"
586 u8" klong (complex): Longitudinal wavevector (1/µm).\n"
587 u8" ktran (complex): Transverse wavevector (1/µm).\n");
589 u8"Compute the mode near the specified effective index.\n\n"
590 u8"Only one of the following arguments can be given through a keyword.\n"
591 u8"It is the starting point for search of the specified parameter.\n\n"
593 u8" lam (complex): Wavelength (nm).\n"
594 u8" k0 (complex): Normalized frequency (1/µm).\n"
595 u8" klong (complex): Longitudinal wavevector (1/µm).\n"
596 u8" ktran (complex): Transverse wavevector (1/µm).\n");
597 solver.def(
"set_mode", py::raw_function(FourierSolver3D_setMode),
598 u8"Set the mode for specified parameters.\n\n"
599 u8"This method should be used if you have found a mode manually and want to insert\n"
600 u8"it into the solver in order to determine the fields. Calling this will raise an\n"
601 u8"exception if the determinant for the specified parameters is too large.\n\n"
602 u8"Arguments can be given through keywords only.\n\n"
604 u8" lam (complex): Wavelength (nm).\n"
605 u8" k0 (complex): Normalized frequency (1/µm).\n"
606 u8" klong (complex): Longitudinal wavevector (1/µm).\n"
607 u8" ktran (complex): Transverse wavevector (1/µm).\n");
609 (py::arg(
"lam"),
"side",
"polarization"));
611 (py::arg(
"lam"),
"side",
"index"));
613 (py::arg(
"lam"),
"side",
"coffs"),
614 u8"Compute reflection coefficient on planar incidence [%].\n\n"
616 u8" lam (float or array of floats): Incident light wavelength (nm).\n"
617 u8" side (`top` or `bottom`): Side of the structure where the incident light is\n"
619 u8" polarization: Specification of the incident light polarization.\n"
620 u8" It should be a string of the form 'E\\ *#*\\ ', where *#* is the axis\n"
621 u8" name of the non-vanishing electric field component.\n"
622 u8" idx: Eigenmode number.\n"
623 u8" coeffs: expansion coefficients of the incident vector.\n");
625 (py::arg(
"lam"),
"side",
"polarization"));
627 (py::arg(
"lam"),
"side",
"index"));
629 (py::arg(
"lam"),
"side",
"coffs"),
630 u8"Compute transmission coefficient on planar incidence [%].\n\n"
632 u8" lam (float or array of floats): Incident light wavelength (nm).\n"
633 u8" side (`top` or `bottom`): Side of the structure where the incident light is\n"
635 u8" polarization: Specification of the incident light polarization.\n"
636 u8" It should be a string of the form 'E\\ *#*\\ ', where *#* is the axis name\n"
637 u8" of the non-vanishing electric field component.\n"
638 u8" idx: Eigenmode number.\n"
639 u8" coeffs: expansion coefficients of the incident vector.\n");
643 u8"Access to the reflected field.\n\n"
645 u8" side (`top` or `bottom`): Side of the structure where the incident light is\n"
647 u8" polarization: Specification of the incident light polarization.\n"
648 u8" It should be a string of the form 'E\\ *#*\\ ', where *#* is the axis name\n"
649 u8" of the non-vanishing electric field component.\n"
650 u8" idx: Eigenmode number.\n"
651 u8" coeffs: expansion coefficients of the incident vector.\n\n"
652 u8":rtype: Fourier3D.Scattering\n"
654 solver.def(
"get_raw_E", FourierSolver3D_getFieldVectorE, (py::arg(
"num"),
"level"),
655 u8"Get Fourier expansion coefficients for the electric field.\n\n"
656 u8"This is a low-level function returning $E_l$ and/or $E_t$ Fourier\n"
657 u8"expansion coefficients. Please refer to the detailed solver description for their\n"
658 u8"interpretation.\n\n"
660 u8" num (int): Computed mode number.\n"
661 u8" level (float): Vertical level at which the coefficients are computed.\n\n"
662 u8":rtype: numpy.ndarray\n"
664 solver.def(
"get_raw_H", FourierSolver3D_getFieldVectorH, (py::arg(
"num"),
"level"),
665 u8"Get Fourier expansion coefficients for the magnetic field.\n\n"
666 u8"This is a low-level function returning $H_l$ and/or $H_t$ Fourier\n"
667 u8"expansion coefficients. Please refer to the detailed solver description for their\n"
668 u8"interpretation.\n\n"
670 u8" num (int): Computed mode number.\n"
671 u8" level (float): Vertical level at which the coefficients are computed.\n\n"
672 u8":rtype: numpy.ndarray\n"
675 u8"Get eignemodes for a layer at specified level.\n\n"
676 u8"This is a low-level function to access diagonalized eigenmodes for a specific\n"
677 u8"layer. Please refer to the detailed solver description for the interpretation\n"
678 u8"of the returned values.\n\n"
680 u8" level (float): Vertical level at which the coefficients are computed.\n\n"
681 u8":rtype: :class:`~optical.modal.Fourier3D.Eigenmodes`\n",
682 py::with_custodian_and_ward_postcall<0,1>()
685 solver.def(
"gaussian", &FourierSolver3D_incidentGaussian, (py::arg(
"side"),
"polarization",
"sigma", py::arg(
"center")=py::make_tuple(0., 0.)),
686 u8"Create coefficients vector with Gaussian profile.\n\n"
687 u8"This method is intended to use for :py:meth:`scattering` method.\n\n"
689 u8" side (`top` or `bottom`): Side of the structure where the incident light is\n"
691 u8" polarization: Specification of the incident light polarization.\n"
692 u8" It should be a string of the form 'E\\ *#*\\ ', where *#* is the axis name\n"
693 u8" of the non-vanishing electric field component.\n"
694 u8" sigma (float or tuple): Gaussian standard deviation in longitudinal and\n"
695 u8" transverse directions [µm, µm].\n"
696 u8" center (tuple): Position of the beam center [µm, µm].\n\n"
698 u8" >>> scattered = fourier.scattering('top', \n"
699 u8" ... fourier.gaussian('top', 'Ex', 0.2))\n"
701 solver.def(
"scattering_gaussian", &FourierSolver3D_scatteringGaussian, (py::arg(
"side"),
"polarization",
"sigma", py::arg(
"center")=py::make_tuple(0., 0.)),
702 u8"Helper function to Access reflected fields for access incidence.\n\n"
703 u8"This method is equivalent to calling:\n\n"
704 u8" >>> fourier.scattering(side,\n"
705 u8" ... fourier.gaussian(side, polarization, sigma, center))\n\n"
707 u8" side (`top` or `bottom`): Side of the structure where the incident light is\n"
709 u8" polarization: Specification of the incident light polarization.\n"
710 u8" It should be a string of the form 'E\\ *#*\\ ', where *#* is the axis name\n"
711 u8" of the non-vanishing electric field component.\n"
712 u8" sigma (float): Gaussian standard deviation (µm).\n"
713 u8" center (float): Position of the beam center (µm).\n\n"
716 py::scope
scope = solver;
720 py::class_<FourierSolver3D::Mode>(
"Mode",
u8"Detailed information about the mode.", py::no_init)