15#include <plask/python.hpp>
16#include <plask/common/fem/python.hpp>
21#include "../electr2d.hpp"
22#include "../electr3d.hpp"
25static py::object outPotential(
const py::object& self) {
26 throw TypeError(
u8"{}: 'outPotential' is reserved for drift-diffusion model; use 'outVoltage' instead",
27 std::string(py::extract<std::string>(self.attr(
"id"))));
44 if (attr.substr(0, 4) ==
"beta")
return py::object(
getBeta(boost::lexical_cast<size_t>(attr.substr(4))));
45 if (attr.substr(0, 2) ==
"js")
return py::object(
getJs(boost::lexical_cast<size_t>(attr.substr(2))));
46 }
catch (boost::bad_lexical_cast&) {
51 static void __setattr__(
const py::object&
oself,
const std::string& attr,
const py::object& value) {
54 if (attr.substr(0, 4) ==
"beta") {
55 self.
setBeta(boost::lexical_cast<size_t>(attr.substr(4)), value);
58 if (attr.substr(0, 2) ==
"js") {
59 self.
setJs(boost::lexical_cast<size_t>(attr.substr(2)), value);
62 }
catch (boost::bad_lexical_cast&) {
64 oself.attr(
"__class__").attr(
"__base__").attr(
"__setattr__")(
oself, attr, value);
72 void setBeta(
size_t n,
const py::object& value) {
73 py::extract<double> val(value);
77 if (this->beta_function.size() <=
n) this->beta_function.resize(
n + 1);
81 throw TypeError(
"{}: beta{} must be a float or a callable", this->getId(),
n);
90 void setJs(
size_t n,
const py::object& value) {
91 py::extract<double> val(value);
95 if (this->js_function.size() <=
n) this->js_function.resize(
n + 1);
99 throw TypeError(
"{}: js{} must be a float or a callable", this->getId(),
n);
113template <
typename GeometryT>
114struct PythonCondSolver :
public std::conditional<std::is_same<GeometryT, Geometry3D>::value,
115 ElectricalFem3DSolver,
116 ElectricalFem2DSolver<GeometryT>>::type {
117 typedef typename std::conditional<std::is_same<GeometryT, Geometry3D>::value,
135 if (this->cond_function.size() <=
n) this->cond_function.resize(
n + 1);
139 throw TypeError(
"{}: cond{} must be a a callable", this->getId(),
n);
145 if (attr.substr(0, 4) ==
"cond")
return py::object(
getCond(boost::lexical_cast<size_t>(attr.substr(4))));
146 }
catch (boost::bad_lexical_cast&) {
151 static void __setattr__(
const py::object&
oself,
const std::string& attr,
const py::object& value) {
155 if (attr.substr(0, 4) ==
"cond") {
156 self.
setCond(boost::lexical_cast<size_t>(attr.substr(4)), value);
159 }
catch (boost::bad_lexical_cast&) {
162 oself.attr(
"__class__").attr(
"__base__").attr(
"__setattr__")(
oself, attr, value);
173 throw IndexError(
"no conductivity for active region {}",
n);
177 return py::extract<Tensor2<double>>(cond);
195template <
typename __Class__>
198 format(
u8"{0}(name=\"\")\n\n"
199 u8"Finite element thermal solver for {1} geometry.",
202 py::init<std::string>(py::arg(
"name") =
""));
203 METHOD(compute, compute,
u8"Run electrical calculations", py::arg(
"loops") = 0);
204 METHOD(get_total_current, getTotalCurrent,
u8"Get total current flowing through active region (mA)", py::arg(
"nact") = 0);
211 BOUNDARY_CONDITIONS(voltage_boundary,
u8"Boundary conditions of the first kind (constant potential)");
212 RW_FIELD(maxerr,
u8"Limit for the potential updates");
213 RW_FIELD(convergence,
u8"Convergence method.\n\nIf stable, covergence is slown down to ensure stability.");
214 RW_PROPERTY(pcond, getCondPcontact, setCondPcontact,
u8"Conductivity of the p-contact");
215 RW_PROPERTY(ncond, getCondNcontact, setCondNcontact,
u8"Conductivity of the n-contact");
217 u8"Default effective conductivity of the active region.\n\n"
218 u8"Effective junction conductivity will be computed starting from this value.\n"
219 u8"Note that the actual junction conductivity after convergence can be obtained\n"
220 u8"with :attr:`outConductivity`.");
221 solver.attr(
"pnjcond") = solver.attr(
"start_cond");
222 solver.add_property(
"outPotential", outPotential,
u8"Not available in this solver. Use :attr:`outVoltage` instead.");
224 u8"Get the energy stored in the electrostatic field in the analyzed structure.\n\n"
226 u8" Total electrostatic energy [J].\n");
228 u8"Get the structure capacitance.\n\n"
230 u8" Total capacitance [pF].\n\n"
232 u8" This method can only be used it there are exactly two boundary conditions\n"
233 u8" specifying the voltage. Otherwise use :meth:`get_electrostatic_energy` to\n"
234 u8" obtain the stored energy $W$ and compute the capacitance as:\n"
235 u8" $C = 2 \\, W / U^2$, where $U$ is the applied voltage.\n");
237 u8"Get the total heat produced by the current flowing in the structure.\n\n"
239 u8" Total produced heat (mW).\n");
245template <
typename GeoT>
inline static void register_shockley_solver(
const char* name,
const char*
geoname) {
248 solver.add_property(
"beta", &__Class__::getBeta0, &__Class__::setBeta0,
249 u8"Junction coefficient (1/V).\n\n"
250 u8"In case, there is more than one junction you may set $\\\\beta$ parameter for any\n"
251 u8"of them by using ``beta#`` property, where # is the junction number (specified\n"
252 u8"by a role ``junction#`` or ``active#``).\n\n"
253 u8"``beta`` is an alias for ``beta0``.\n");
254 solver.add_property(
"js", &__Class__::getJs0, &__Class__::setJs0,
255 u8"Reverse bias current density (A/m\\ :sup:`2`\\ ).\n\n"
256 u8"In case, there is more than one junction you may set $j_s$ parameter for any\n"
257 u8"of them by using ``js#`` property, where # is the junction number (specified\n"
258 u8"by a role ``junction#`` or ``active#``).\n\n"
259 u8"``js`` is an alias for ``js0``.\n");
260 solver.def(
"__getattr__", &__Class__::__getattr__);
261 solver.def(
"__setattr__", &__Class__::__setattr__);
264template <
typename GeoT>
inline static void register_cond_solver(
const char* name,
const char*
geoname) {
267 solver.add_property(
"cond", &__Class__::getCond0, &__Class__::setCond0,
268 u8"Junction conductivity function [S/m].\n\n"
269 u8"This function should take junction voltage (V), current density (kA/cm²)\n"
270 u8"and temperature (K) as arguments and return a conductivity [S/m]. In case,\n"
271 u8"there is more than one junction you may set such function for any of them\n"
272 u8"by using ``cond#`` property, where # is the junction number (specified by\n"
273 u8"a role ``junction#`` or ``active#``).\n\n"
275 u8" >>> def cond(U, j, T):\n"
276 u8" ... return 1e-3 * j**2 + 1e-4 * T**2\n"
277 u8" >>> solver.cond = cond\n\n"
278 u8"``cond`` is an alias for ``cond0``.\n");
279 solver.def(
"__getattr__", &__Class__::__getattr__);
280 solver.def(
"__setattr__", &__Class__::__setattr__);