18#include <plask/python.hpp> 
   19#include <plask/python/util/ufunc.hpp> 
   27#define ROOTDIGGER_ATTRS_DOC                             \ 
   28    u8".. rubric:: Attributes:\n\n"                      \ 
   29    u8".. autosummary::\n\n"                             \ 
   30    u8"   ~optical.effective.RootParams.alpha\n"         \ 
   31    u8"   ~optical.effective.RootParams.lambd\n"         \ 
   32    u8"   ~optical.effective.RootParams.initial_range\n" \ 
   33    u8"   ~optical.effective.RootParams.maxiter\n"       \ 
   34    u8"   ~optical.effective.RootParams.maxstep\n"       \ 
   35    u8"   ~optical.effective.RootParams.method\n"        \ 
   36    u8"   ~optical.effective.RootParams.tolf_max\n"      \ 
   37    u8"   ~optical.effective.RootParams.tolf_min\n"      \ 
   38    u8"   ~optical.effective.RootParams.tolx\n\n"        \ 
   39    u8"   ~optical.effective.RootParams.stairs\n\n"      \ 
   40    u8":rtype: RootParams\n" 
 
   42#define SEARCH_ARGS_DOC                                                                   \ 
   43    u8"    start (complex): Start of the search range (0 means automatic).\n"             \ 
   44    u8"    end (complex): End of the search range (0 means automatic).\n"                 \ 
   45    u8"    resteps (integer): Number of steps on the real axis during the search.\n"      \ 
   46    u8"    imsteps (integer): Number of steps on the imaginary axis during the search.\n" \ 
   47    u8"    eps (complex): required precision of the search.\n" 
 
   53        default: 
return py::object();
 
   63        std::string 
sym = py::extract<std::string>(symmetry);
 
   64        if (sym == 
"0" || sym == 
"none") {
 
   66        } 
else if (sym == 
"positive" || sym == 
"pos" || sym == 
"symmeric" || sym == 
"+" || sym == 
"+1") {
 
   68        } 
else if (sym == 
"negative" || sym == 
"neg" || sym == 
"anti-symmeric" || sym == 
"antisymmeric" || sym == 
"-" ||
 
   72        throw py::error_already_set();
 
   73    } 
catch (py::error_already_set&) {
 
   76            int sym = py::extract<int>(symmetry);
 
   79            } 
else if (sym == +1) {
 
   81            } 
else if (sym == -1) {
 
   84            throw py::error_already_set();
 
   85        } 
catch (py::error_already_set&) {
 
   91static std::string EffectiveIndex2D_getPolarization(
const EffectiveIndex2D& self) {
 
   95static void EffectiveIndex2D_setPolarization(
EffectiveIndex2D& self, std::string polarization) {
 
   96    if (polarization == 
"TE" || polarization == 
"s") {
 
  100    if (polarization == 
"TM" || polarization == 
"p") {
 
  106static py::object EffectiveIndex2D_getDeterminant(
EffectiveIndex2D& self, py::object val) {
 
  114static py::object EffectiveFrequencyCyl_getDeterminant(
EffectiveFrequencyCyl& self, py::object val, 
int m) {
 
  116                           "EffectiveFrequencyCyl.get_determinant", 
"lam");
 
  118static py::object EffectiveFrequencyCyl_getVertDeterminant(
EffectiveFrequencyCyl& self, py::object val) {
 
  120                           "EffectiveFrequencyCyl.get_vert_determinant", 
"lam");
 
  128    if (!self.
mirrors) 
return py::object();
 
 
  137            double v = py::extract<double>(value);
 
  138            self.
mirrors.reset(std::make_pair(
v, 
v));
 
  139        } 
catch (py::error_already_set&) {
 
  142                if (py::len(value) != 2) 
throw py::error_already_set();
 
  144                    std::make_pair<double, double>(
double(py::extract<double>(value[0])), 
double(py::extract<double>(value[1]))));
 
  145            } 
catch (py::error_already_set&) {
 
  146                throw ValueError(
u8"none, float, or tuple of two floats required");
 
 
  152static size_t EffectiveIndex2D_findMode(
EffectiveIndex2D& self, py::object neff, py::object symmetry) {
 
  153    return self.
findMode(py::extract<dcomplex>(neff), parseSymmetry(symmetry));
 
  166static size_t EffectiveIndex2D_setMode(
EffectiveIndex2D& self, py::object neff, py::object symmetry) {
 
  167    return self.
setMode(py::extract<dcomplex>(neff), parseSymmetry(symmetry));
 
  175        default: sym = 
"none";
 
  177    return format(
u8"<neff: {:.3f}{:+.3g}j, symmetry: {}, power: {:.2g}mW>", 
real(self.
neff), 
imag(self.
neff), sym, self.
power);
 
 
  184        default: sym = 
"None";
 
  186    return format(
u8"EffectiveIndex2D.Mode(neff={0}, symmetry={1}, power={2})", 
str(self.
neff), sym, self.
power);
 
 
  190    return self.
findMode(py::extract<dcomplex>(lam), m);
 
  195template <
typename SolverT> 
static void Optical_setMesh(
SolverT& self, py::object 
omesh) {
 
  198        self.setHorizontalMesh(mesh);
 
  199    } 
catch (py::error_already_set&) {
 
  204        } 
catch (py::error_already_set&) {
 
  206            plask::python::detail::ExportedSolverDefaultDefs<SolverT>::Solver_setMesh(self, 
omesh);
 
  214    return py::object(r);
 
 
  225    return format(
u8"<m: {:d}, lam: ({:.3f}{:+.3g}j)nm, power: {:.2g}mW>", self.
m, 
real(self.
lam), 
imag(self.
lam), self.
power);
 
 
  228    return format(
u8"EffectiveFrequencyCyl.Mode(m={0}, lam={1}, power={2})", self.
m, 
str(self.
lam), self.
power);
 
 
  231template <
typename Solver> 
static double Mode_total_absorption(
typename Solver::Mode& self) {
 
  232    return self.solver->getTotalAbsorption(self);
 
  237template <
typename Solver> 
static py::object getDeltaNeff(
Solver& self, py::object pos) {
 
  238    return UFUNC<dcomplex, double>([&](
double p) { 
return self.getDeltaNeff(p); }, 
pos, 
"EffectiveIndex2D.get_delta_neff", 
"pos");
 
  256              u8"Calculate optical modes and optical field distribution using the effective index\n" 
  257              u8"method in two-dimensional Cartesian space.\n")
 
  259                            u8"Mesh provided to the solver.");
 
  260        solver.add_property(
"polarization", &EffectiveIndex2D_getPolarization, &EffectiveIndex2D_setPolarization,
 
  261                            u8"Polarization of the searched modes.");
 
  263                 u8"Configuration of the root searching algorithm for horizontal component of the\n" 
  266                 u8"Configuration of the root searching algorithm for vertical component of the mode\n" 
  273               u8"Find the effective indices in the vertical direction within the specified range\n" 
  274               u8"using global method.\n\n" 
  278               u8"    list of floats: List of the found effective indices in the vertical\n" 
  280               arg(
"start") = 0., arg(
"end") = 0., arg(
"resteps") = 256, arg(
"imsteps") = 64, arg(
"eps") = dcomplex(1
e-6, 1
e-9));
 
  281        solver.def(
"find_mode", &EffectiveIndex2D_findMode,
 
  282                   u8"Compute the mode near the specified effective index.\n\n" 
  284                   u8"    neff (complex): Starting point of the root search.\n" 
  285                   u8"    symmetry ('+' or '-'): Symmetry of the mode to search. If this parameter\n" 
  286                   u8"                           is not specified, the default symmetry is used:\n" 
  287                   u8"                           positive mode symmetry fir symmetrical geometries\n" 
  288                   u8"                           and no symmetry for asymmetrical geometries.\n\n" 
  290                   u8"    integer: Index in the :attr:`modes` list of the found mode.\n",
 
  291                   (arg(
"neff"), arg(
"symmetry") = py::object()));
 
  293                   u8"Find the modes within the specified range using global method.\n\n" 
  297                   u8"    list of integers: List of the indices in the :attr:`modes` list of the found\n" 
  299                   (arg(
"start") = 0., arg(
"end") = 0., arg(
"symmetry") = py::object(), arg(
"resteps") = 256, arg(
"imsteps") = 64,
 
  300                    arg(
"eps") = dcomplex(1
e-6, 1
e-9)));
 
  301        solver.def(
"set_mode", EffectiveIndex2D_setMode,
 
  302                   u8"Set the current mode the specified effective index.\n\n" 
  304                   u8"    neff (complex): Mode effective index.\n" 
  305                   u8"    symmetry ('+' or '-'): Symmetry of the mode to search.\n",
 
  306                   "neff", arg(
"symmetry") = py::object());
 
  309                   u8"Get total energy absorbed by from a mode in unit time.\n\n" 
  311                   u8"    num (int): number of the mode.\n\n" 
  313                   u8"    Total absorbed energy (mW).\n",
 
  315        RW_PROPERTY(
vat, getStripeX, setStripeX, 
u8"Horizontal position of the main stripe (with dominant mode).");
 
  316        RW_FIELD(vneff, 
u8"Effective index in the vertical direction.");
 
  318                   u8"Return effective index part for lateral propagation at specified horizontal\n" 
  321                   u8"    pos (float or array of floats): Horizontal position to get the effective\n" 
  324                            u8"Mirror reflectivities. If None then they are automatically estimated from the" 
  325                            u8"Fresnel equations.\n");
 
  327                   u8"Get vertical modal determinant for debugging purposes.\n\n" 
  329                   u8"    neff (complex of numeric array of complex): Vertical effective index value\n" 
  330                   u8"    to compute the determinant at.\n\n" 
  332                   u8"    complex or list of complex: Determinant at the vertical effective index\n" 
  333                   u8"    *neff* or an array matching its size.",
 
  335        solver.def(
"get_determinant", &EffectiveIndex2D_getDeterminant,
 
  336                   u8"Get modal determinant.\n\n" 
  338                   u8"    neff (complex or array of complex): effective index value\n" 
  339                   u8"    to compute the determinant at.\n\n" 
  341                   u8"    complex or list of complex: Determinant at the effective index *neff* or\n" 
  342                   u8"    an array matching its size.",
 
  344        RW_PROPERTY(wavelength, getWavelength, setWavelength, 
"Current wavelength.");
 
  347        RECEIVER(inCarriersConcentration, 
"");
 
  354            "Alias for :attr:`outLightE`.");
 
  358                 u8"List of the computed modes.\n\n" 
  359                 u8".. rubric:: Item Attributes\n\n" 
  360                 u8".. autosummary::\n\n" 
  361                 u8"   ~optical.effective.EffectiveIndex2D.Mode.neff\n" 
  362                 u8"   ~optical.effective.EffectiveIndex2D.Mode.symmetry\n" 
  363                 u8"   ~optical.effective.EffectiveIndex2D.Mode.power\n" 
  364                 u8"   ~optical.effective.EffectiveIndex2D.Mode.total_absorption\n\n" 
  365                 u8":rtype: optical.effecticve.EffectiveIndex2D.Mode\n");
 
  367        py::scope 
scope = solver;
 
  372        py::class_<EffectiveIndex2D::Mode>(
"Mode", 
u8"Detailed information about the mode.", py::no_init)
 
  374            .add_property(
"symmetry", &EffectiveIndex2D_getSymmetry, 
u8"Mode symmetry ('positive', 'negative', or None).")
 
  378                          u8"Cumulated absorption for the mode (mW).\n\n" 
  379                          u8"This property combines gain in active region and absorption in the whole\n" 
  389              u8"Calculate optical modes and optical field distribution using the effective\n" 
  390              u8"frequency method in two-dimensional cylindrical space.\n")
 
  392                            "Mesh provided to the solver.");
 
  393        RW_FIELD(k0, 
u8"Reference normalized frequency.");
 
  394        RW_FIELD(vlam, 
u8"'Vertical wavelength' used as a helper for searching vertical modes.");
 
  396                            u8"Reference wavelength.");
 
  398                 u8"Configuration of the root searching algorithm for horizontal component of the\n" 
  401                 u8"Configuration of the root searching algorithm for vertical component of the mode\n" 
  406        RW_PROPERTY(emission, getEmission, setEmission, 
u8"Emission direction.");
 
  408                             u8"Radial determinant mode.\n\n" 
  409                             u8"This parameter determines the method used to compute radial determinant.\n" 
  410                             u8"If it is set to 'transfer', 2x2 transfer matrix is used to ensure field\n" 
  411                             u8"continuity at the interfaces. For the 'full' value, one single matrix is\n" 
  412                             u8"constructed for all the interfaces and its determinant is returned.");
 
  416        solver.def(
"find_mode", &EffectiveFrequencyCyl_findMode,
 
  417                   u8"Compute the mode near the specified wavelength.\n\n" 
  419                   u8"    lam (complex): Initial wavelength to for root finging algorithm.\n" 
  420                   u8"    m (int): Angular mode number (O for LP0x, 1 for LP1x, etc.).\n\n" 
  422                   u8"    integer: Index in the :attr:`modes` list of the found mode.\n",
 
  423                   (arg(
"lam"), arg(
"m") = 0));
 
  425               u8"Find the modes within the specified range using global method.\n\n" 
  427               u8"    m (int): Angular mode number (O for LP0x, 1 for LP1x, etc.).\n\n" SEARCH_ARGS_DOC 
  430               u8"    list of integers: List of the indices in the :attr:`modes` list of the found\n" 
  432               arg(
"start") = 0., arg(
"end") = 0., arg(
"m") = 0, arg(
"resteps") = 256, arg(
"imsteps") = 64,
 
  433               arg(
"eps") = dcomplex(1
e-6, 1
e-9));
 
  434        solver.def(
"get_vert_determinant", &EffectiveFrequencyCyl_getVertDeterminant,
 
  435                   u8"Get vertical modal determinant for debugging purposes.\n\n" 
  437                   u8"    vlam (complex of numeric array of complex): Vertical wavelength value\n" 
  438                   u8"    to compute the determinant at.\n\n" 
  440                   u8"    complex or list of complex: Determinant at the vertical wavelength *vlam* or\n" 
  441                   u8"    an array matching its size.\n",
 
  443        solver.def(
"get_determinant", &EffectiveFrequencyCyl_getDeterminant,
 
  444                   u8"Get modal determinant.\n\n" 
  446                   u8"    lam (complex of numeric array of complex): wavelength to compute the\n" 
  447                   u8"                                               determinant at.\n" 
  448                   u8"    m (int): Angular mode number (O for LP0x, 1 for LP1x, etc.).\n\n",
 
  450                   u8"    complex or list of complex: Determinant at the effective index *neff* or\n" 
  451                   u8"    an array matching its size.\n",
 
  452                   (py::arg(
"lam"), py::arg(
"m") = 0));
 
  454                   (py::arg(
"lam"), py::arg(
"m") = 0));
 
  456                   u8"Set the current mode the specified wavelength.\n\n" 
  458                   u8"    lam (float of complex): Mode wavelength.\n" 
  459                   u8"    loss (float): Mode losses. Allowed only if *lam* is a float.\n" 
  460                   u8"    m (int): Angular mode number (O for LP0x, 1 for LP1x, etc.).\n",
 
  461                   (py::arg(
"lam"), 
"loss", py::arg(
"m") = 0));
 
  464                   u8"Get total energy absorbed from a mode in unit time.\n\n" 
  466                   u8"    num (int): number of the mode.\n\n" 
  468                   u8"    Total absorbed energy (mW).\n",
 
  471                   u8"Get total energy generated in the gain region to a mode in unit time.\n\n" 
  473                   u8"    num (int): number of the mode.\n\n" 
  475                   u8"    Total generated energy (mW).\n",
 
  479        RECEIVER(inCarriersConcentration, 
"");
 
  484        solver.def_readonly(
"outElectricField",
 
  487                            u8"Alias for :attr:`outLightE`.");
 
  491                 u8"List of the computed modes.\n\n" 
  492                 u8".. rubric:: Item Attributes\n\n" 
  493                 u8".. autosummary::\n\n" 
  494                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.m\n" 
  495                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.lam\n" 
  496                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.wavelength\n" 
  497                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.power\n" 
  498                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.total_absorption\n" 
  499                 u8"   ~optical.effective.EffectiveFrequencyCyl.Mode.gain_integral\n\n" 
  500                 u8":rtype: optical.effective.EffectiveFrquencyCyl.Mode\n");
 
  502                            u8"Radial position of at which the vertical part of the field is calculated.\n\n" 
  503                            u8"Should be a float number or ``None`` to compute effective frequencies for all\n" 
  506                   u8"Return effective index part for lateral propagation at specified radial\n" 
  509                   u8"    pos (float or array of floats): Radial position to get the effective index.\n");
 
  510        solver.def(
"get_nng", &EffectiveFrequencyCyl_getNNg, py::arg(
"pos"),
 
  511                   u8"Return average index at specified radial position.\n\n" 
  513                   u8"    pos (float or array of floats): Radial position to get the effective index.\n");
 
  515        py::scope 
scope = solver;
 
  520        py::class_<EffectiveFrequencyCyl::Mode>(
"Mode", 
u8"Detailed information about the mode.", py::no_init)
 
  523                          u8"Alias for :attr:`~optical.effective.EffectiveFrequencyCyl.Mode.wavelength`.")
 
  528                          u8"Cumulated absorption for the mode (mW).\n\n" 
  529                          u8"This property combines gain in active region and absorption in the whole\n" 
  531            .add_property(
"gain_integral", &Mode_gain_integral, 
u8"Total gain for the mode (mW).")
 
  545    py::class_<RootDigger::Params, boost::noncopyable>(
"RootParams", 
u8"Configuration of the root finding algorithm.", py::no_init)
 
  553                       u8"Parameter ensuring sufficient decrease of determinant in each step\n(Broyden method only).")