79 detected_QW = detectQuantumWells();
83 z = getZQWCoordinate();
86 for (
const auto&
box : detected_QW) {
87 if (
box.left() < left) left =
box.left();
88 if (
box.right() > left) right =
box.right();
90 size_t num =
static_cast<size_t>(std::round((right - left) * 100)) + 1;
94 mesh2->setAxis0(this->mesh);
96 if (current_mesh().size() % 2 == 0)
97 current_mesh().reset(current_mesh().first(), current_mesh().last(), current_mesh().size() + 1);
99 n_present.reset(current_mesh().size(), 0.0);
115 initial_computation = type == COMPUTATION_INITIAL || (this->initCalculation() && do_initial);
116 threshold_computation = type == COMPUTATION_THRESHOLD;
117 overthreshold_computation = type == COMPUTATION_OVERTHRESHOLD;
119 this->
writelog(
LOG_INFO,
"Computing lateral carriers diffusion using {0} FEM method",
120 fem_method == FEM_LINEAR ?
"linear" :
"parabolic");
122 T_on_the_mesh = inTemperature(mesh2, interpolation_method);
124 inCurrentDensity(mesh2, interpolation_method);
127 bool convergence =
true;
129 auto& current_mesh = this->current_mesh();
134 throw ComputationError(this->getId(),
"maximum number of mesh refinements ({0}) reached", max_mesh_changes);
135 size_t new_size = 2 * current_mesh.size() - 1;
141 current_mesh.reset(current_mesh.first(), current_mesh.last(),
new_size);
143 inTemperature(mesh2, interpolation_method);
145 inCurrentDensity(mesh2, interpolation_method);
147 n_present.reset(current_mesh.size(), 0.0);
150 for (
size_t i = 0; i !=
nm; ++i) {
151 n_present[2*i] =
old_n[i];
152 n_present[2*i+1] = 0.5 * (
old_n[i] +
old_n[i+1]);
156 if (initial_computation) {
158 convergence = MatrixFEM();
159 if (convergence) initial_computation =
false;
161 if (threshold_computation) {
163 convergence = MatrixFEM();
164 if (convergence) threshold_computation =
false;
166 if (overthreshold_computation) {
170 convergence = MatrixFEM();
171 if (convergence) overthreshold_computation =
false;
173 }
while (initial_computation || threshold_computation || overthreshold_computation);
175 this->
writelog(
LOG_DETAIL,
"Converged after {0} mesh refinements and {1} computational loops", mesh_changes, iterations);
200 if (fem_method == FEM_LINEAR)
202 else if (fem_method == FEM_PARABOLIC)
203 A_matrix.reset(3 * current_mesh().size(), 0.0);
205 B_vector.reset(current_mesh().size(), 0.0);
207 n_previous = n_present.copy();
209 if (initial_computation) {
212 for (std::size_t i = 0; i < current_mesh().size(); i++) {
213 T = T_on_the_mesh[i];
215 A = this->QW_material->A(T);
216 B = this->QW_material->B(T);
217 C = this->QW_material->C(T);
219 double RS = rightSide(i);
221 pow((sqrt(27 * C * C *
RS *
RS + (4 * B * B * B - 18 * A * B * C) *
RS + 4 * A * A * A * C - A * A * B * B) /
222 (2 * pow(3.0, 3. / 2.) * C * C) +
223 (-27 * C * C *
RS + 9 * A * B * C - 2 * B * B * B) / (54 * C * C * C)),
225 (3 * A * C - B * B) / pow(9 * C * C *
226 (sqrt(27 * C * C *
RS *
RS + (4 * B * B * B - 18 * A * B * C) *
RS +
227 4 * A * A * A * C - A * A * B * B) /
228 (2 * pow(3.0, 3. / 2.) * C * C) +
229 (-27 * C * C *
RS + 9 * A * B * C - 2 * B * B * B) / (54 * C * C * C)),
249 const char uplo =
'U';
256 if (overthreshold_computation) {
258 if (inWavelength.size() != inLightE.size())
259 throw BadInput(this->getId(),
"number of modes in inWavelength ({}) and inLightE ({}) differ",
260 inWavelength.size(), inLightE.size());
266 modesP.assign(inWavelength.size(), 0.);
269 if (current_mesh().size() > 1) D = current_mesh()[1] - current_mesh()[0];
271 for (
size_t n = 0;
n != inWavelength.size(); ++
n) {
272 double wavelength =
real(inWavelength(
n));
277 mesh_Li->setAxis0(current_mesh_ptr());
285 for (
auto n : n_present) {
289 auto g = inGain(mesh2, wavelength, interpolation_method);
291 auto dgdn = inGain(
Gain::DGDN, mesh2, wavelength, interpolation_method);
293 auto factor =
inv_hc * wavelength * 1
e-4;
294 for (
size_t i = 0; i != mesh2->size(); ++i) {
295 auto common = factor * this->QW_material->nr(wavelength, T_on_the_mesh[i]) *
Li[i];
301 modesP[
n] +=
pm * D * jacobian(current_mesh()[i]);
310 if (fem_method == FEM_LINEAR) {
315 }
else if (fem_method == FEM_PARABOLIC) {
333 abs(this->QW_material->A(300.0) * minor_concentration +
334 this->QW_material->B(300.0) * minor_concentration * minor_concentration +
335 this->QW_material->C(300.0) * minor_concentration * minor_concentration * minor_concentration);
343 if (fem_method == FEM_LINEAR) {
345 for (std::size_t i = 0; i < current_mesh().size(); i++) {
353 }
else if (fem_method == FEM_PARABOLIC) {
360 for (std::size_t i = 0; std::ptrdiff_t(i) < (std::ptrdiff_t(current_mesh().size()) - 1) / 2; i++) {
361 L = leftSide(2 * i + 1);
362 R = rightSide(2 * i + 1);
387 if (overthreshold_computation)
388 writelog(
LOG_DEBUG,
"Integral of overthreshold loses: {0} mW, qw_width: {1} cm", burning_integral(),
393 }
while (!
_convergence && (iterations < max_iterations));
395 outCarriersConcentration.fireChanged();
404 double r1 = 0.0,
r2 = 0.0;
414 if (fem_method == FEM_LINEAR)
419 auto& current_mesh = this->current_mesh();
420 for (
int i = 0; i <
int(current_mesh.size()) - 1; i++)
422 r1 = current_mesh[i] * 1
e-4;
423 r2 = current_mesh[i+1] * 1
e-4;
425 j1 = abs(j_on_the_mesh[i][1] * 1
e+3);
426 j2 = abs(j_on_the_mesh[i+1][1] * 1
e+3);
448 }
else if (fem_method == FEM_PARABOLIC) {
453 auto& current_mesh = this->current_mesh();
454 for (
int i = 0; i < (
int(current_mesh.size()) - 1) / 2; i++)
456 r1 = current_mesh[2*i] * 1
e-4;
457 r3 = current_mesh[2*i+2] * 1
e-4;
459 K = this->
K(2 * i + 1);
460 F = this->
F(2 * i + 1);
461 E = this->
E(2 * i + 1);
499 double r1 = 0.0,
r2 = 0.0;
509 if (fem_method == FEM_LINEAR)
514 auto& current_mesh = this->current_mesh();
515 for (
int i = 0; i <
int(current_mesh.size()) - 1; i++)
517 r1 = current_mesh[i] * 1
e-4;
518 r2 = current_mesh[i+1] * 1
e-4;
520 j1 = abs(j_on_the_mesh[i][1] * 1
e+3);
521 j2 = abs(j_on_the_mesh[i+1][1] * 1
e+3);
534 (
F / 3 * (2 *
r1 +
r2) +
537 (
F / 3 * (
r1 + 2 *
r2) +
548 }
else if (fem_method == FEM_PARABOLIC)
554 auto& current_mesh = this->current_mesh();
555 for (
int i = 0; i < (
int(current_mesh.size()) - 1) / 2; i++)
557 r1 = current_mesh[2*i] * 1
e-4;
558 r3 = current_mesh[2*i+2] * 1
e-4;
560 K = this->
K(2 * i + 1);
561 F = this->
F(2 * i + 1);
562 E = this->
E(2 * i + 1);
761 std::vector<Box2D> results;
764 double left = 0., right = 0.;
767 for (std::size_t r = 0; r < points->axis[1]->size(); ++r) {
770 for (std::size_t c = 0; c < points->axis[0]->size(); ++c) {
771 auto point = points->at(c, r);
775 for (
const std::string&
tag :
tags)
776 if (
tag.substr(0, 6) ==
"active") {
780 if (
QW && !active)
throw Exception(
"{0}: All marked quantum wells must belong to marked active region.", this->
getId());
784 if (left !=
grid->axis[0]->at(c))
785 throw Exception(
"{0}: Left edge of quantum wells not vertically aligned.", this->
getId());
787 throw Exception(
"{0}: Quantum wells of multiple materials not supported.", this->
getId());
791 left =
grid->axis[0]->at(c);
797 throw Exception(
"{0}: Right edge of quantum wells not vertically aligned.", this->
getId());
798 right =
grid->axis[0]->at(c);
799 results.push_back(
Box2D(left,
grid->axis[1]->at(r), right,
grid->axis[1]->at(r + 1)));
809 if (
foundQW && right !=
grid->axis[0]->at(points->axis[0]->size()))
810 throw Exception(
"{0}: Right edge of quantum wells not vertically aligned.", this->
getId());
811 right =
grid->axis[0]->at(points->axis[0]->size());
812 results.push_back(
Box2D(left,
grid->axis[1]->at(r), right,
grid->axis[1]->at(r + 1)));