PLaSK library
Loading...
Searching...
No Matches
diffusion2d.cpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include "diffusion2d.hpp"
15
16#define DEFAULT_MESH_SPACING 0.005 // µm
17
18namespace plask { namespace electrical { namespace diffusion {
19
20constexpr double inv_hc = 1.0e-13 / (phys::c * phys::h_J);
21using phys::Z0;
22
23template <typename Geometry2DType>
26 loopno(0),
27 maxerr(0.05),
28 outCarriersConcentration(this, &Diffusion2DSolver<Geometry2DType>::getConcentration) {
29 inTemperature = 300.;
30}
31
32template <typename Geometry2DType> void Diffusion2DSolver<Geometry2DType>::loadConfiguration(XMLReader& source, Manager& manager) {
33 while (source.requireTagOrEnd()) parseConfiguration(source, manager);
34}
35
36template <typename Geometry2DType> void Diffusion2DSolver<Geometry2DType>::parseConfiguration(XMLReader& source, Manager& manager) {
37 std::string param = source.getNodeName();
38
39 if (param == "loop") {
40 maxerr = source.getAttribute<double>("maxerr", maxerr);
41 source.requireTagEnd();
42 }
43
44 else if (param == "mesh") {
45 auto name = source.getAttribute("ref");
46 if (!name)
47 name.reset(source.requireTextInCurrentTag());
48 else
49 source.requireTagEnd();
50 auto found = manager.meshes.find(*name);
51 if (found != manager.meshes.end()) {
52 if (shared_ptr<RectangularMesh<2>> mesh = dynamic_pointer_cast<RectangularMesh<2>>(found->second)) {
53 this->setMesh(mesh);
54 } else if (shared_ptr<MeshGeneratorD<2>> generator = dynamic_pointer_cast<MeshGeneratorD<2>>(found->second)) {
55 this->setMesh(generator);
56 } else if (shared_ptr<MeshD<1>> mesh = dynamic_pointer_cast<MeshD<1>>(found->second)) {
57 this->setMesh(mesh);
58 } else if (shared_ptr<MeshGeneratorD<1>> generator = dynamic_pointer_cast<MeshGeneratorD<1>>(found->second)) {
59 this->setMesh(generator);
60 }
61 }
62 }
63
64 else if (param == "config") {
65 this->writelog(LOG_WARNING, "Tag <config> is not used in this solver. Update your file!");
66 source.ignoreAllAttributes();
67 source.requireTagEnd();
68 }
69
70 else if (!this->parseFemConfiguration(source, manager)) {
71 this->parseStandardConfiguration(source, manager);
72 }
73}
74
75template <typename Geometry2DType> Diffusion2DSolver<Geometry2DType>::~Diffusion2DSolver() {}
76
77template <typename Geometry2DType> void Diffusion2DSolver<Geometry2DType>::setupActiveRegion2Ds() {
78 if (!this->geometry || !this->mesh) return;
79
80 auto points = this->mesh->getElementMesh();
81
82 std::vector<typename ActiveRegion2D::Region> regions;
83
84 for (size_t r = 0; r < points->vert()->size(); ++r) {
85 size_t prev = 0;
86 shared_ptr<Material> material;
87 for (size_t c = 0; c < points->tran()->size(); ++c) { // In the (possible) active region
88 auto point = points->at(c, r);
89 size_t num = isActive(point);
90
91 if (num) { // here we are inside the active region
92 if (regions.size() >= num && regions[num - 1].warn) {
93 if (!material)
94 material = this->geometry->getMaterial(points->at(c, r));
95 else if (*material != *this->geometry->getMaterial(points->at(c, r))) {
96 writelog(LOG_WARNING, "Active region {} is laterally non-uniform", num - 1);
97 regions[num - 1].warn = false;
98 }
99 }
100 regions.resize(max(regions.size(), num));
101 auto& reg = regions[num - 1];
102 if (prev != num) { // this region starts in the current row
103 if (reg.top < r) {
104 throw Exception("{0}: Active region {1} is disjoint", this->getId(), num - 1);
105 }
106 if (reg.bottom >= r)
107 reg.bottom = r; // first row
108 else if (reg.rowr <= c)
109 throw Exception("{0}: Active region {1} is disjoint", this->getId(), num - 1);
110 reg.top = r + 1;
111 reg.rowl = c;
112 if (reg.left > reg.rowl) reg.left = reg.rowl;
113 }
114 }
115 if (prev && prev != num) { // previous region ended
116 auto& reg = regions[prev - 1];
117 if (reg.bottom < r && reg.rowl >= c) throw Exception("{0}: Active region {1} is disjoint", this->getId(), prev - 1);
118 reg.rowr = c;
119 if (reg.right < reg.rowr) reg.right = reg.rowr;
120 }
121 prev = num;
122 }
123 if (prev) // junction reached the edge
124 regions[prev - 1].rowr = regions[prev - 1].right = points->tran()->size();
125 }
126
127 active.clear();
128 size_t act = 0;
129 for (auto& reg : regions) {
130 if (reg.bottom == std::numeric_limits<size_t>::max()) {
131 ++act;
132 continue;
133 }
134 // Detect quantum wells in the active region
135 std::vector<double> QWz;
136 std::vector<std::pair<size_t, size_t>> QWbt;
137 double QWheight = 0.;
138 std::vector<bool> isQW;
139 isQW.reserve(reg.top - reg.bottom);
140 for (size_t c = reg.left; c < reg.right; ++c) {
141 shared_ptr<Material> material;
142 for (size_t r = reg.bottom, j = 0; r < reg.top; ++r, ++j) {
143 auto point = points->at(c, r);
144 auto tags = this->geometry->getRolesAt(point);
145 bool QW = tags.find("QW") != tags.end() || tags.find("QD") != tags.end() || tags.find("carriers") != tags.end();
146 if (c == reg.left) {
147 isQW.push_back(QW);
148 if (QW) {
149 if (QWbt.empty() || QWbt.back().second != r)
150 QWbt.emplace_back(r, r + 1);
151 else
152 QWbt.back().second = r + 1;
153 QWz.push_back(point.c1);
154 QWheight += this->mesh->vert()->at(r + 1) - this->mesh->vert()->at(r);
155 }
156 } else if (isQW[j] != QW) {
157 throw Exception("{}: Quantum wells in active region {} are not identical", this->getId(), act);
158 }
159 if (QW) {
160 if (!material)
161 material = this->geometry->getMaterial(point);
162 else if (*material != *this->geometry->getMaterial(point)) {
163 throw Exception("{}: Quantum wells in active region {} are not identical", this->getId(), act);
164 }
165 }
166 }
167 }
168 if (QWz.empty()) {
169 throw Exception("{}: Active region {} does not contain quantum wells", this->getId(), act);
170 }
171 active.emplace(
172 std::piecewise_construct, std::forward_as_tuple(act),
173 std::forward_as_tuple(this, reg.left, reg.right, reg.bottom, reg.top, QWheight, std::move(QWz), std::move(QWbt)));
174 this->writelog(LOG_DETAIL, "Total QWs thickness in active region {}: {}nm", act, 1e3 * QWheight);
175 ++act;
176 }
177}
178
179template <typename Geometry2DType> void Diffusion2DSolver<Geometry2DType>::onInitialize() {
180 if (!this->geometry) throw NoGeometryException(this->getId());
181 if (!this->mesh) {
182 auto mesh1 = makeGeometryGrid(this->geometry);
183 this->mesh = make_shared<RectangularMesh<2>>(refineAxis(mesh1->tran(), DEFAULT_MESH_SPACING), mesh1->vert());
184 writelog(LOG_DETAIL, "{}: Setting up default mesh [{}]", this->getId(), this->mesh->tran()->size());
185 }
186 setupActiveRegion2Ds();
187 loopno = 0;
188}
189
190template <typename Geometry2DType> void Diffusion2DSolver<Geometry2DType>::onInvalidate() { active.clear(); }
191
192// clang-format off
193template <>
195 const double, const double L, const double L2, const double L3, const double L4, const double L5, const double L6,
196 const double A, const double B, const double C, const double D,
197 const double* U, const double* J,
198 double& K00, double& K01, double& K02, double& K03, double& K11,
199 double& K12, double& K13, double& K22, double& K23, double& K33,
200 double& F0, double& F1, double& F2, double& F3)
201{
202 K00 += (1.0/180180.0)*(216216*D + L2*(66924*A + 13871*B*L*U[1] - 6149*B*L*U[3] + 110682*B*U[0] + 23166*B*U[2] + 2520*C*L2*U[1]*U[1] - 2331*C*L2*U[1]*U[3] + 804*C*L2*U[3]*U[3] + 33012*C*L*U[0]*U[1] - 12033*C*L*U[0]*U[3] + 8601*C*L*U[1]*U[2] - 6414*C*L*U[2]*U[3] + 144396*C*U[0]*U[0] + 43254*C*U[0]*U[2] + 13122*C*U[2]*U[2]))/L;
203 K01 += (11.0/210.0)*A*L2 + (4.0/315.0)*B*L3*U[1] - 1.0/140.0*B*L3*U[3] + (97.0/1260.0)*B*L2*U[0] + (1.0/36.0)*B*L2*U[2] + (7.0/2860.0)*C*L4*U[1]*U[1] - 23.0/8580.0*C*L4*U[1]*U[3] + (25.0/24024.0)*C*L4*U[3]*U[3] + (4.0/143.0)*C*L3*U[0]*U[1] - 37.0/2860.0*C*L3*U[0]*U[3] + (152.0/15015.0)*C*L3*U[1]*U[2] - 17.0/2002.0*C*L3*U[2]*U[3] + (131.0/1430.0)*C*L2*U[0]*U[0] + (2867.0/60060.0)*C*L2*U[0]*U[2] + (1069.0/60060.0)*C*L2*U[2]*U[2] + (1.0/10.0)*D;
204 K02 += (1.0/180180.0)*(-216216*D + L2*(23166*A + 5005*B*L*U[1] - 5005*B*L*U[3] + 23166*B*U[0] + 23166*B*U[2] + 912*C*L2*U[1]*U[1] - 1530*C*L2*U[1]*U[3] + 912*C*L2*U[3]*U[3] + 8601*C*L*U[0]*U[1] - 6414*C*L*U[0]*U[3] + 6414*C*L*U[1]*U[2] - 8601*C*L*U[2]*U[3] + 21627*C*U[0]*U[0] + 26244*C*U[0]*U[2] + 21627*C*U[2]*U[2]))/L;
205 K03 += -13.0/420.0*A*L2 - 1.0/140.0*B*L3*U[1] + (2.0/315.0)*B*L3*U[3] - 43.0/1260.0*B*L2*U[0] - 1.0/36.0*B*L2*U[2] - 23.0/17160.0*C*L4*U[1]*U[1] + (25.0/12012.0)*C*L4*U[1]*U[3] - 9.0/8008.0*C*L4*U[3]*U[3] - 37.0/2860.0*C*L3*U[0]*U[1] + (134.0/15015.0)*C*L3*U[0]*U[3] - 17.0/2002.0*C*L3*U[1]*U[2] + (152.0/15015.0)*C*L3*U[2]*U[3] - 191.0/5720.0*C*L2*U[0]*U[0] - 1069.0/30030.0*C*L2*U[0]*U[2] - 2867.0/120120.0*C*L2*U[2]*U[2] + (1.0/10.0)*D;
206 K11 += (1.0/180180.0)*L*(1716*A*L2 + 429*B*L3*U[1] - 286*B*L3*U[3] + 2288*B*L2*U[0] + 1144*B*L2*U[2] + 84*C*L4*U[1]*U[1] - 105*C*L4*U[1]*U[3] + 45*C*L4*U[3]*U[3] + 882*C*L3*U[0]*U[1] - 483*C*L3*U[0]*U[3] + 405*C*L3*U[1]*U[2] - 375*C*L3*U[2]*U[3] + 2520*C*L2*U[0]*U[0] + 1824*C*L2*U[0]*U[2] + 804*C*L2*U[2]*U[2] + 24024*D);
207 K12 += (13.0/420.0)*A*L2 + (2.0/315.0)*B*L3*U[1] - 1.0/140.0*B*L3*U[3] + (1.0/36.0)*B*L2*U[0] + (43.0/1260.0)*B*L2*U[2] + (9.0/8008.0)*C*L4*U[1]*U[1] - 25.0/12012.0*C*L4*U[1]*U[3] + (23.0/17160.0)*C*L4*U[3]*U[3] + (152.0/15015.0)*C*L3*U[0]*U[1] - 17.0/2002.0*C*L3*U[0]*U[3] + (134.0/15015.0)*C*L3*U[1]*U[2] - 37.0/2860.0*C*L3*U[2]*U[3] + (2867.0/120120.0)*C*L2*U[0]*U[0] + (1069.0/30030.0)*C*L2*U[0]*U[2] + (191.0/5720.0)*C*L2*U[2]*U[2] - 1.0/10.0*D;
208 K13 += (1.0/360360.0)*L*(-2574*A*L2 - 572*B*L3*U[1] + 572*B*L3*U[3] - 2574*B*L2*U[0] - 2574*B*L2*U[2] - 105*C*L4*U[1]*U[1] + 180*C*L4*U[1]*U[3] - 105*C*L4*U[3]*U[3] - 966*C*L3*U[0]*U[1] + 750*C*L3*U[0]*U[3] - 750*C*L3*U[1]*U[2] + 966*C*L3*U[2]*U[3] - 2331*C*L2*U[0]*U[0] - 3060*C*L2*U[0]*U[2] - 2331*C*L2*U[2]*U[2] - 12012*D);
209 K22 += (1.0/180180.0)*(216216*D + L2*(66924*A + 6149*B*L*U[1] - 13871*B*L*U[3] + 23166*B*U[0] + 110682*B*U[2] + 804*C*L2*U[1]*U[1] - 2331*C*L2*U[1]*U[3] + 2520*C*L2*U[3]*U[3] + 6414*C*L*U[0]*U[1] - 8601*C*L*U[0]*U[3] + 12033*C*L*U[1]*U[2] - 33012*C*L*U[2]*U[3] + 13122*C*U[0]*U[0] + 43254*C*U[0]*U[2] + 144396*C*U[2]*U[2]))/L;
210 K23 += -11.0/210.0*A*L2 - 1.0/140.0*B*L3*U[1] + (4.0/315.0)*B*L3*U[3] - 1.0/36.0*B*L2*U[0] - 97.0/1260.0*B*L2*U[2] - 25.0/24024.0*C*L4*U[1]*U[1] + (23.0/8580.0)*C*L4*U[1]*U[3] - 7.0/2860.0*C*L4*U[3]*U[3] - 17.0/2002.0*C*L3*U[0]*U[1] + (152.0/15015.0)*C*L3*U[0]*U[3] - 37.0/2860.0*C*L3*U[1]*U[2] + (4.0/143.0)*C*L3*U[2]*U[3] - 1069.0/60060.0*C*L2*U[0]*U[0] - 2867.0/60060.0*C*L2*U[0]*U[2] - 131.0/1430.0*C*L2*U[2]*U[2] - 1.0/10.0*D;
211 K33 += (1.0/180180.0)*L*(1716*A*L2 + 286*B*L3*U[1] - 429*B*L3*U[3] + 1144*B*L2*U[0] + 2288*B*L2*U[2] + 45*C*L4*U[1]*U[1] - 105*C*L4*U[1]*U[3] + 84*C*L4*U[3]*U[3] + 375*C*L3*U[0]*U[1] - 405*C*L3*U[0]*U[3] + 483*C*L3*U[1]*U[2] - 882*C*L3*U[2]*U[3] + 804*C*L2*U[0]*U[0] + 1824*C*L2*U[0]*U[2] + 2520*C*L2*U[2]*U[2] + 24024*D);
212 F0 += (1.0/180180.0)*L*(1144*B*L2*U[1]*U[1] - 1287*B*L2*U[1]*U[3] + 572*B*L2*U[3]*U[3] + 13871*B*L*U[0]*U[1] - 6149*B*L*U[0]*U[3] + 5005*B*L*U[1]*U[2] - 5005*B*L*U[2]*U[3] + 55341*B*U[0]*U[0] + 23166*B*U[0]*U[2] + 11583*B*U[2]*U[2] + 294*C*L3*U[1]*U[1]*U[1] - 483*C*L3*U[1]*U[1]*U[3] + 375*C*L3*U[1]*U[3]*U[3] - 135*C*L3*U[3]*U[3]*U[3] + 5040*C*L2*U[0]*U[1]*U[1] - 4662*C*L2*U[0]*U[1]*U[3] + 1608*C*L2*U[0]*U[3]*U[3] + 1824*C*L2*U[1]*U[1]*U[2] - 3060*C*L2*U[1]*U[2]*U[3] + 1824*C*L2*U[2]*U[3]*U[3] + 33012*C*L*U[0]*U[0]*U[1] - 12033*C*L*U[0]*U[0]*U[3] + 17202*C*L*U[0]*U[1]*U[2] - 12828*C*L*U[0]*U[2]*U[3] + 6414*C*L*U[1]*U[2]*U[2] - 8601*C*L*U[2]*U[2]*U[3] + 96264*C*U[0]*U[0]*U[0] + 43254*C*U[0]*U[0]*U[2] + 26244*C*U[0]*U[2]*U[2] + 14418*C*U[2]*U[2]*U[2] + 63063*J[0] + 27027*J[1]);
213 F1 += (1.0/360360.0)*L2*(429*B*L2*U[1]*U[1] - 572*B*L2*U[1]*U[3] + 286*B*L2*U[3]*U[3] + 4576*B*L*U[0]*U[1] - 2574*B*L*U[0]*U[3] + 2288*B*L*U[1]*U[2] - 2574*B*L*U[2]*U[3] + 13871*B*U[0]*U[0] + 10010*B*U[0]*U[2] + 6149*B*U[2]*U[2] + 112*C*L3*U[1]*U[1]*U[1] - 210*C*L3*U[1]*U[1]*U[3] + 180*C*L3*U[1]*U[3]*U[3] - 70*C*L3*U[3]*U[3]*U[3] + 1764*C*L2*U[0]*U[1]*U[1] - 1932*C*L2*U[0]*U[1]*U[3] + 750*C*L2*U[0]*U[3]*U[3] + 810*C*L2*U[1]*U[1]*U[2] - 1500*C*L2*U[1]*U[2]*U[3] + 966*C*L2*U[2]*U[3]*U[3] + 10080*C*L*U[0]*U[0]*U[1] - 4662*C*L*U[0]*U[0]*U[3] + 7296*C*L*U[0]*U[1]*U[2] - 6120*C*L*U[0]*U[2]*U[3] + 3216*C*L*U[1]*U[2]*U[2] - 4662*C*L*U[2]*U[2]*U[3] + 22008*C*U[0]*U[0]*U[0] + 17202*C*U[0]*U[0]*U[2] + 12828*C*U[0]*U[2]*U[2] + 8022*C*U[2]*U[2]*U[2] + 18018*J[0] + 12012*J[1]);
214 F2 += (1.0/180180.0)*L*(572*B*L2*U[1]*U[1] - 1287*B*L2*U[1]*U[3] + 1144*B*L2*U[3]*U[3] + 5005*B*L*U[0]*U[1] - 5005*B*L*U[0]*U[3] + 6149*B*L*U[1]*U[2] - 13871*B*L*U[2]*U[3] + 11583*B*U[0]*U[0] + 23166*B*U[0]*U[2] + 55341*B*U[2]*U[2] + 135*C*L3*U[1]*U[1]*U[1] - 375*C*L3*U[1]*U[1]*U[3] + 483*C*L3*U[1]*U[3]*U[3] - 294*C*L3*U[3]*U[3]*U[3] + 1824*C*L2*U[0]*U[1]*U[1] - 3060*C*L2*U[0]*U[1]*U[3] + 1824*C*L2*U[0]*U[3]*U[3] + 1608*C*L2*U[1]*U[1]*U[2] - 4662*C*L2*U[1]*U[2]*U[3] + 5040*C*L2*U[2]*U[3]*U[3] + 8601*C*L*U[0]*U[0]*U[1] - 6414*C*L*U[0]*U[0]*U[3] + 12828*C*L*U[0]*U[1]*U[2] - 17202*C*L*U[0]*U[2]*U[3] + 12033*C*L*U[1]*U[2]*U[2] - 33012*C*L*U[2]*U[2]*U[3] + 14418*C*U[0]*U[0]*U[0] + 26244*C*U[0]*U[0]*U[2] + 43254*C*U[0]*U[2]*U[2] + 96264*C*U[2]*U[2]*U[2] + 27027*J[0] + 63063*J[1]);
215 F3 += (1.0/360360.0)*L2*(-286*B*L2*U[1]*U[1] + 572*B*L2*U[1]*U[3] - 429*B*L2*U[3]*U[3] - 2574*B*L*U[0]*U[1] + 2288*B*L*U[0]*U[3] - 2574*B*L*U[1]*U[2] + 4576*B*L*U[2]*U[3] - 6149*B*U[0]*U[0] - 10010*B*U[0]*U[2] - 13871*B*U[2]*U[2] - 70*C*L3*U[1]*U[1]*U[1] + 180*C*L3*U[1]*U[1]*U[3] - 210*C*L3*U[1]*U[3]*U[3] + 112*C*L3*U[3]*U[3]*U[3] - 966*C*L2*U[0]*U[1]*U[1] + 1500*C*L2*U[0]*U[1]*U[3] - 810*C*L2*U[0]*U[3]*U[3] - 750*C*L2*U[1]*U[1]*U[2] + 1932*C*L2*U[1]*U[2]*U[3] - 1764*C*L2*U[2]*U[3]*U[3] - 4662*C*L*U[0]*U[0]*U[1] + 3216*C*L*U[0]*U[0]*U[3] - 6120*C*L*U[0]*U[1]*U[2] + 7296*C*L*U[0]*U[2]*U[3] - 4662*C*L*U[1]*U[2]*U[2] + 10080*C*L*U[2]*U[2]*U[3] - 8022*C*U[0]*U[0]*U[0] - 12828*C*U[0]*U[0]*U[2] - 17202*C*U[0]*U[2]*U[2] - 22008*C*U[2]*U[2]*U[2] - 12012*J[0] - 18018*J[1]);
216}
217
218template <>
220 const double R, const double L, const double L2, const double L3, const double L4, const double L5, const double L6,
221 const double A, const double B, const double C, const double D,
222 const double* U, const double* J,
223 double& K00, double& K01, double& K02, double& K03, double& K11,
224 double& K12, double& K13, double& K22, double& K23, double& K33,
225 double& F0, double& F1, double& F2, double& F3)
226{
227 K00 += (1.0/360360.0)*(432432*D*R + L*(30888*A*L2 + 133848*A*L*R + 7540*B*L3*U[1] - 4758*B*L3*U[3] + 27742*B*L2*R*U[1] - 12298*B*L2*R*U[3] + 42822*B*L2*U[0] + 18954*B*L2*U[2] + 221364*B*L*R*U[0] + 46332*B*L*R*U[2] + 1458*C*L4*U[1]*U[1] - 1746*C*L4*U[1]*U[3] + 735*C*L4*U[3]*U[3] + 5040*C*L3*R*U[1]*U[1] - 4662*C*L3*R*U[1]*U[3] + 1608*C*L3*R*U[3]*U[3] + 15912*C*L3*U[0]*U[1] - 8154*C*L3*U[0]*U[3] + 6708*C*L3*U[1]*U[2] - 6120*C*L3*U[2]*U[3] + 66024*C*L2*R*U[0]*U[1] - 24066*C*L2*R*U[0]*U[3] + 17202*C*L2*R*U[1]*U[2] - 12828*C*L2*R*U[2]*U[3] + 48924*C*L2*U[0]*U[0] + 30618*C*L2*U[0]*U[2] + 13122*C*L2*U[2]*U[2] + 288792*C*L*R*U[0]*U[0] + 86508*C*L*R*U[0]*U[2] + 26244*C*L*R*U[2]*U[2] + 216216*D))/L;
228 K01 += (1.0/60.0)*A*L3 + (11.0/210.0)*A*L2*R + (19.0/4620.0)*B*L4*U[1] - 1.0/330.0*B*L4*U[3] + (4.0/315.0)*B*L3*R*U[1] - 1.0/140.0*B*L3*R*U[3] + (29.0/1386.0)*B*L3*U[0] + (43.0/3465.0)*B*L3*U[2] + (97.0/1260.0)*B*L2*R*U[0] + (1.0/36.0)*B*L2*R*U[2] + (4.0/5005.0)*C*L5*U[1]*U[1] - 1.0/924.0*C*L5*U[1]*U[3] + (1.0/2002.0)*C*L5*U[3]*U[3] + (7.0/2860.0)*C*L4*R*U[1]*U[1] - 23.0/8580.0*C*L4*R*U[1]*U[3] + (25.0/24024.0)*C*L4*R*U[3]*U[3] + (81.0/10010.0)*C*L4*U[0]*U[1] - 97.0/20020.0*C*L4*U[0]*U[3] + (17.0/4004.0)*C*L4*U[1]*U[2] - 17.0/4004.0*C*L4*U[2]*U[3] + (4.0/143.0)*C*L3*R*U[0]*U[1] - 37.0/2860.0*C*L3*R*U[0]*U[3] + (152.0/15015.0)*C*L3*R*U[1]*U[2] - 17.0/2002.0*C*L3*R*U[2]*U[3] + (17.0/770.0)*C*L3*U[0]*U[0] + (43.0/2310.0)*C*L3*U[0]*U[2] + (43.0/4620.0)*C*L3*U[2]*U[2] + (131.0/1430.0)*C*L2*R*U[0]*U[0] + (2867.0/60060.0)*C*L2*R*U[0]*U[2] + (1069.0/60060.0)*C*L2*R*U[2]*U[2] + (1.0/10.0)*D*L + (1.0/10.0)*D*R;
229 K02 += (1.0/360360.0)*(-432432*D*R + L*(23166*A*L2 + 46332*A*L*R + 4472*B*L3*U[1] - 5538*B*L3*U[3] + 10010*B*L2*R*U[1] - 10010*B*L2*R*U[3] + 18954*B*L2*U[0] + 27378*B*L2*U[2] + 46332*B*L*R*U[0] + 46332*B*L*R*U[2] + 765*C*L4*U[1]*U[1] - 1530*C*L4*U[1]*U[3] + 1059*C*L4*U[3]*U[3] + 1824*C*L3*R*U[1]*U[1] - 3060*C*L3*R*U[1]*U[3] + 1824*C*L3*R*U[3]*U[3] + 6708*C*L3*U[0]*U[1] - 6120*C*L3*U[0]*U[3] + 6708*C*L3*U[1]*U[2] - 10494*C*L3*U[2]*U[3] + 17202*C*L2*R*U[0]*U[1] - 12828*C*L2*R*U[0]*U[3] + 12828*C*L2*R*U[1]*U[2] - 17202*C*L2*R*U[2]*U[3] + 15309*C*L2*U[0]*U[0] + 26244*C*L2*U[0]*U[2] + 27945*C*L2*U[2]*U[2] + 43254*C*L*R*U[0]*U[0] + 52488*C*L*R*U[0]*U[2] + 43254*C*L*R*U[2]*U[2] - 216216*D))/L;
230 K03 += -1.0/70.0*A*L3 - 13.0/420.0*A*L2*R - 1.0/330.0*B*L4*U[1] + (23.0/6930.0)*B*L4*U[3] - 1.0/140.0*B*L3*R*U[1] + (2.0/315.0)*B*L3*R*U[3] - 61.0/4620.0*B*L3*U[0] - 71.0/4620.0*B*L3*U[2] - 43.0/1260.0*B*L2*R*U[0] - 1.0/36.0*B*L2*R*U[2] - 1.0/1848.0*C*L5*U[1]*U[1] + (1.0/1001.0)*C*L5*U[1]*U[3] - 5.0/8008.0*C*L5*U[3]*U[3] - 23.0/17160.0*C*L4*R*U[1]*U[1] + (25.0/12012.0)*C*L4*R*U[1]*U[3] - 9.0/8008.0*C*L4*R*U[3]*U[3] - 97.0/20020.0*C*L4*U[0]*U[1] + (7.0/1716.0)*C*L4*U[0]*U[3] - 17.0/4004.0*C*L4*U[1]*U[2] + (353.0/60060.0)*C*L4*U[2]*U[3] - 37.0/2860.0*C*L3*R*U[0]*U[1] + (134.0/15015.0)*C*L3*R*U[0]*U[3] - 17.0/2002.0*C*L3*R*U[1]*U[2] + (152.0/15015.0)*C*L3*R*U[2]*U[3] - 453.0/40040.0*C*L3*U[0]*U[0] - 17.0/1001.0*C*L3*U[0]*U[2] - 53.0/3640.0*C*L3*U[2]*U[2] - 191.0/5720.0*C*L2*R*U[0]*U[0] - 1069.0/30030.0*C*L2*R*U[0]*U[2] - 2867.0/120120.0*C*L2*R*U[2]*U[2] + (1.0/10.0)*D*R;
231 K11 += (1.0/360360.0)*L*(1287*A*L3 + 3432*A*L2*R + 312*B*L4*U[1] - 260*B*L4*U[3] + 858*B*L3*R*U[1] - 572*B*L3*R*U[3] + 1482*B*L3*U[0] + 1092*B*L3*U[2] + 4576*B*L2*R*U[0] + 2288*B*L2*R*U[2] + 60*C*L5*U[1]*U[1] - 90*C*L5*U[1]*U[3] + 45*C*L5*U[3]*U[3] + 168*C*L4*R*U[1]*U[1] - 210*C*L4*R*U[1]*U[3] + 90*C*L4*R*U[3]*U[3] + 576*C*L4*U[0]*U[1] - 390*C*L4*U[0]*U[3] + 360*C*L4*U[1]*U[2] - 390*C*L4*U[2]*U[3] + 1764*C*L3*R*U[0]*U[1] - 966*C*L3*R*U[0]*U[3] + 810*C*L3*R*U[1]*U[2] - 750*C*L3*R*U[2]*U[3] + 1458*C*L3*U[0]*U[0] + 1530*C*L3*U[0]*U[2] + 873*C*L3*U[2]*U[2] + 5040*C*L2*R*U[0]*U[0] + 3648*C*L2*R*U[0]*U[2] + 1608*C*L2*R*U[2]*U[2] + 12012*D*L + 48048*D*R);
232 K12 += (1.0/60.0)*A*L3 + (13.0/420.0)*A*L2*R + (1.0/330.0)*B*L4*U[1] - 19.0/4620.0*B*L4*U[3] + (2.0/315.0)*B*L3*R*U[1] - 1.0/140.0*B*L3*R*U[3] + (43.0/3465.0)*B*L3*U[0] + (29.0/1386.0)*B*L3*U[2] + (1.0/36.0)*B*L2*R*U[0] + (43.0/1260.0)*B*L2*R*U[2] + (1.0/2002.0)*C*L5*U[1]*U[1] - 1.0/924.0*C*L5*U[1]*U[3] + (4.0/5005.0)*C*L5*U[3]*U[3] + (9.0/8008.0)*C*L4*R*U[1]*U[1] - 25.0/12012.0*C*L4*R*U[1]*U[3] + (23.0/17160.0)*C*L4*R*U[3]*U[3] + (17.0/4004.0)*C*L4*U[0]*U[1] - 17.0/4004.0*C*L4*U[0]*U[3] + (97.0/20020.0)*C*L4*U[1]*U[2] - 81.0/10010.0*C*L4*U[2]*U[3] + (152.0/15015.0)*C*L3*R*U[0]*U[1] - 17.0/2002.0*C*L3*R*U[0]*U[3] + (134.0/15015.0)*C*L3*R*U[1]*U[2] - 37.0/2860.0*C*L3*R*U[2]*U[3] + (43.0/4620.0)*C*L3*U[0]*U[0] + (43.0/2310.0)*C*L3*U[0]*U[2] + (17.0/770.0)*C*L3*U[2]*U[2] + (2867.0/120120.0)*C*L2*R*U[0]*U[0] + (1069.0/30030.0)*C*L2*R*U[0]*U[2] + (191.0/5720.0)*C*L2*R*U[2]*U[2] - 1.0/10.0*D*L - 1.0/10.0*D*R;
233 K13 += (1.0/360360.0)*L*(-1287*A*L3 - 2574*A*L2*R - 260*B*L4*U[1] + 312*B*L4*U[3] - 572*B*L3*R*U[1] + 572*B*L3*R*U[3] - 1092*B*L3*U[0] - 1482*B*L3*U[2] - 2574*B*L2*R*U[0] - 2574*B*L2*R*U[2] - 45*C*L5*U[1]*U[1] + 90*C*L5*U[1]*U[3] - 60*C*L5*U[3]*U[3] - 105*C*L4*R*U[1]*U[1] + 180*C*L4*R*U[1]*U[3] - 105*C*L4*R*U[3]*U[3] - 390*C*L4*U[0]*U[1] + 360*C*L4*U[0]*U[3] - 390*C*L4*U[1]*U[2] + 576*C*L4*U[2]*U[3] - 966*C*L3*R*U[0]*U[1] + 750*C*L3*R*U[0]*U[3] - 750*C*L3*R*U[1]*U[2] + 966*C*L3*R*U[2]*U[3] - 873*C*L3*U[0]*U[0] - 1530*C*L3*U[0]*U[2] - 1458*C*L3*U[2]*U[2] - 2331*C*L2*R*U[0]*U[0] - 3060*C*L2*R*U[0]*U[2] - 2331*C*L2*R*U[2]*U[2] - 6006*D*L - 12012*D*R);
234 K22 += (1.0/360360.0)*(432432*D*R + L*(102960*A*L2 + 133848*A*L*R + 7540*B*L3*U[1] - 20202*B*L3*U[3] + 12298*B*L2*R*U[1] - 27742*B*L2*R*U[3] + 27378*B*L2*U[0] + 178542*B*L2*U[2] + 46332*B*L*R*U[0] + 221364*B*L*R*U[2] + 873*C*L4*U[1]*U[1] - 2916*C*L4*U[1]*U[3] + 3582*C*L4*U[3]*U[3] + 1608*C*L3*R*U[1]*U[1] - 4662*C*L3*R*U[1]*U[3] + 5040*C*L3*R*U[3]*U[3] + 6708*C*L3*U[0]*U[1] - 10494*C*L3*U[0]*U[3] + 15912*C*L3*U[1]*U[2] - 50112*C*L3*U[2]*U[3] + 12828*C*L2*R*U[0]*U[1] - 17202*C*L2*R*U[0]*U[3] + 24066*C*L2*R*U[1]*U[2] - 66024*C*L2*R*U[2]*U[3] + 13122*C*L2*U[0]*U[0] + 55890*C*L2*U[0]*U[2] + 239868*C*L2*U[2]*U[2] + 26244*C*L*R*U[0]*U[0] + 86508*C*L*R*U[0]*U[2] + 288792*C*L*R*U[2]*U[2] + 216216*D))/L;
235 K23 += -1.0/28.0*A*L3 - 11.0/210.0*A*L2*R - 19.0/4620.0*B*L4*U[1] + (17.0/1980.0)*B*L4*U[3] - 1.0/140.0*B*L3*R*U[1] + (4.0/315.0)*B*L3*R*U[3] - 71.0/4620.0*B*L3*U[0] - 37.0/660.0*B*L3*U[2] - 1.0/36.0*B*L2*R*U[0] - 97.0/1260.0*B*L2*R*U[2] - 1.0/1848.0*C*L5*U[1]*U[1] + (8.0/5005.0)*C*L5*U[1]*U[3] - 3.0/1820.0*C*L5*U[3]*U[3] - 25.0/24024.0*C*L4*R*U[1]*U[1] + (23.0/8580.0)*C*L4*R*U[1]*U[3] - 7.0/2860.0*C*L4*R*U[3]*U[3] - 17.0/4004.0*C*L4*U[0]*U[1] + (353.0/60060.0)*C*L4*U[0]*U[3] - 81.0/10010.0*C*L4*U[1]*U[2] + (199.0/10010.0)*C*L4*U[2]*U[3] - 17.0/2002.0*C*L3*R*U[0]*U[1] + (152.0/15015.0)*C*L3*R*U[0]*U[3] - 37.0/2860.0*C*L3*R*U[1]*U[2] + (4.0/143.0)*C*L3*R*U[2]*U[3] - 17.0/2002.0*C*L3*U[0]*U[0] - 53.0/1820.0*C*L3*U[0]*U[2] - 348.0/5005.0*C*L3*U[2]*U[2] - 1069.0/60060.0*C*L2*R*U[0]*U[0] - 2867.0/60060.0*C*L2*R*U[0]*U[2] - 131.0/1430.0*C*L2*R*U[2]*U[2] - 1.0/10.0*D*R;
236 K33 += (1.0/360360.0)*L*(2145*A*L3 + 3432*A*L2*R + 312*B*L4*U[1] - 546*B*L4*U[3] + 572*B*L3*R*U[1] - 858*B*L3*R*U[3] + 1196*B*L3*U[0] + 3094*B*L3*U[2] + 2288*B*L2*R*U[0] + 4576*B*L2*R*U[2] + 45*C*L5*U[1]*U[1] - 120*C*L5*U[1]*U[3] + 108*C*L5*U[3]*U[3] + 90*C*L4*R*U[1]*U[1] - 210*C*L4*R*U[1]*U[3] + 168*C*L4*R*U[3]*U[3] + 360*C*L4*U[0]*U[1] - 450*C*L4*U[0]*U[3] + 576*C*L4*U[1]*U[2] - 1188*C*L4*U[2]*U[3] + 750*C*L3*R*U[0]*U[1] - 810*C*L3*R*U[0]*U[3] + 966*C*L3*R*U[1]*U[2] - 1764*C*L3*R*U[2]*U[3] + 735*C*L3*U[0]*U[0] + 2118*C*L3*U[0]*U[2] + 3582*C*L3*U[2]*U[2] + 1608*C*L2*R*U[0]*U[0] + 3648*C*L2*R*U[0]*U[2] + 5040*C*L2*R*U[2]*U[2] + 36036*D*L + 48048*D*R);
237 F0 += (1.0/360360.0)*L*(741*B*L3*U[1]*U[1] - 1092*B*L3*U[1]*U[3] + 598*B*L3*U[3]*U[3] + 2288*B*L2*R*U[1]*U[1] - 2574*B*L2*R*U[1]*U[3] + 1144*B*L2*R*U[3]*U[3] + 7540*B*L2*U[0]*U[1] - 4758*B*L2*U[0]*U[3] + 4472*B*L2*U[1]*U[2] - 5538*B*L2*U[2]*U[3] + 27742*B*L*R*U[0]*U[1] - 12298*B*L*R*U[0]*U[3] + 10010*B*L*R*U[1]*U[2] - 10010*B*L*R*U[2]*U[3] + 21411*B*L*U[0]*U[0] + 18954*B*L*U[0]*U[2] + 13689*B*L*U[2]*U[2] + 110682*B*R*U[0]*U[0] + 46332*B*R*U[0]*U[2] + 23166*B*R*U[2]*U[2] + 192*C*L4*U[1]*U[1]*U[1] - 390*C*L4*U[1]*U[1]*U[3] + 360*C*L4*U[1]*U[3]*U[3] - 150*C*L4*U[3]*U[3]*U[3] + 588*C*L3*R*U[1]*U[1]*U[1] - 966*C*L3*R*U[1]*U[1]*U[3] + 750*C*L3*R*U[1]*U[3]*U[3] - 270*C*L3*R*U[3]*U[3]*U[3] + 2916*C*L3*U[0]*U[1]*U[1] - 3492*C*L3*U[0]*U[1]*U[3] + 1470*C*L3*U[0]*U[3]*U[3] + 1530*C*L3*U[1]*U[1]*U[2] - 3060*C*L3*U[1]*U[2]*U[3] + 2118*C*L3*U[2]*U[3]*U[3] + 10080*C*L2*R*U[0]*U[1]*U[1] - 9324*C*L2*R*U[0]*U[1]*U[3] + 3216*C*L2*R*U[0]*U[3]*U[3] + 3648*C*L2*R*U[1]*U[1]*U[2] - 6120*C*L2*R*U[1]*U[2]*U[3] + 3648*C*L2*R*U[2]*U[3]*U[3] + 15912*C*L2*U[0]*U[0]*U[1] - 8154*C*L2*U[0]*U[0]*U[3] + 13416*C*L2*U[0]*U[1]*U[2] - 12240*C*L2*U[0]*U[2]*U[3] + 6708*C*L2*U[1]*U[2]*U[2] - 10494*C*L2*U[2]*U[2]*U[3] + 66024*C*L*R*U[0]*U[0]*U[1] - 24066*C*L*R*U[0]*U[0]*U[3] + 34404*C*L*R*U[0]*U[1]*U[2] - 25656*C*L*R*U[0]*U[2]*U[3] + 12828*C*L*R*U[1]*U[2]*U[2] - 17202*C*L*R*U[2]*U[2]*U[3] + 32616*C*L*U[0]*U[0]*U[0] + 30618*C*L*U[0]*U[0]*U[2] + 26244*C*L*U[0]*U[2]*U[2] + 18630*C*L*U[2]*U[2]*U[2] + 192528*C*R*U[0]*U[0]*U[0] + 86508*C*R*U[0]*U[0]*U[2] + 52488*C*R*U[0]*U[2]*U[2] + 28836*C*R*U[2]*U[2]*U[2] + 30030*L*J[0] + 24024*L*J[1] + 126126*R*J[0] + 54054*R*J[1]);
238 F1 += (1.0/360360.0)*L2*(156*B*L3*U[1]*U[1] - 260*B*L3*U[1]*U[3] + 156*B*L3*U[3]*U[3] + 429*B*L2*R*U[1]*U[1] - 572*B*L2*R*U[1]*U[3] + 286*B*L2*R*U[3]*U[3] + 1482*B*L2*U[0]*U[1] - 1092*B*L2*U[0]*U[3] + 1092*B*L2*U[1]*U[2] - 1482*B*L2*U[2]*U[3] + 4576*B*L*R*U[0]*U[1] - 2574*B*L*R*U[0]*U[3] + 2288*B*L*R*U[1]*U[2] - 2574*B*L*R*U[2]*U[3] + 3770*B*L*U[0]*U[0] + 4472*B*L*U[0]*U[2] + 3770*B*L*U[2]*U[2] + 13871*B*R*U[0]*U[0] + 10010*B*R*U[0]*U[2] + 6149*B*R*U[2]*U[2] + 40*C*L4*U[1]*U[1]*U[1] - 90*C*L4*U[1]*U[1]*U[3] + 90*C*L4*U[1]*U[3]*U[3] - 40*C*L4*U[3]*U[3]*U[3] + 112*C*L3*R*U[1]*U[1]*U[1] - 210*C*L3*R*U[1]*U[1]*U[3] + 180*C*L3*R*U[1]*U[3]*U[3] - 70*C*L3*R*U[3]*U[3]*U[3] + 576*C*L3*U[0]*U[1]*U[1] - 780*C*L3*U[0]*U[1]*U[3] + 360*C*L3*U[0]*U[3]*U[3] + 360*C*L3*U[1]*U[1]*U[2] - 780*C*L3*U[1]*U[2]*U[3] + 576*C*L3*U[2]*U[3]*U[3] + 1764*C*L2*R*U[0]*U[1]*U[1] - 1932*C*L2*R*U[0]*U[1]*U[3] + 750*C*L2*R*U[0]*U[3]*U[3] + 810*C*L2*R*U[1]*U[1]*U[2] - 1500*C*L2*R*U[1]*U[2]*U[3] + 966*C*L2*R*U[2]*U[3]*U[3] + 2916*C*L2*U[0]*U[0]*U[1] - 1746*C*L2*U[0]*U[0]*U[3] + 3060*C*L2*U[0]*U[1]*U[2] - 3060*C*L2*U[0]*U[2]*U[3] + 1746*C*L2*U[1]*U[2]*U[2] - 2916*C*L2*U[2]*U[2]*U[3] + 10080*C*L*R*U[0]*U[0]*U[1] - 4662*C*L*R*U[0]*U[0]*U[3] + 7296*C*L*R*U[0]*U[1]*U[2] - 6120*C*L*R*U[0]*U[2]*U[3] + 3216*C*L*R*U[1]*U[2]*U[2] - 4662*C*L*R*U[2]*U[2]*U[3] + 5304*C*L*U[0]*U[0]*U[0] + 6708*C*L*U[0]*U[0]*U[2] + 6708*C*L*U[0]*U[2]*U[2] + 5304*C*L*U[2]*U[2]*U[2] + 22008*C*R*U[0]*U[0]*U[0] + 17202*C*R*U[0]*U[0]*U[2] + 12828*C*R*U[0]*U[2]*U[2] + 8022*C*R*U[2]*U[2]*U[2] + 6006*L*J[0] + 6006*L*J[1] + 18018*R*J[0] + 12012*R*J[1]);
239 F2 += (1.0/360360.0)*L*(546*B*L3*U[1]*U[1] - 1482*B*L3*U[1]*U[3] + 1547*B*L3*U[3]*U[3] + 1144*B*L2*R*U[1]*U[1] - 2574*B*L2*R*U[1]*U[3] + 2288*B*L2*R*U[3]*U[3] + 4472*B*L2*U[0]*U[1] - 5538*B*L2*U[0]*U[3] + 7540*B*L2*U[1]*U[2] - 20202*B*L2*U[2]*U[3] + 10010*B*L*R*U[0]*U[1] - 10010*B*L*R*U[0]*U[3] + 12298*B*L*R*U[1]*U[2] - 27742*B*L*R*U[2]*U[3] + 9477*B*L*U[0]*U[0] + 27378*B*L*U[0]*U[2] + 89271*B*L*U[2]*U[2] + 23166*B*R*U[0]*U[0] + 46332*B*R*U[0]*U[2] + 110682*B*R*U[2]*U[2] + 120*C*L4*U[1]*U[1]*U[1] - 390*C*L4*U[1]*U[1]*U[3] + 576*C*L4*U[1]*U[3]*U[3] - 396*C*L4*U[3]*U[3]*U[3] + 270*C*L3*R*U[1]*U[1]*U[1] - 750*C*L3*R*U[1]*U[1]*U[3] + 966*C*L3*R*U[1]*U[3]*U[3] - 588*C*L3*R*U[3]*U[3]*U[3] + 1530*C*L3*U[0]*U[1]*U[1] - 3060*C*L3*U[0]*U[1]*U[3] + 2118*C*L3*U[0]*U[3]*U[3] + 1746*C*L3*U[1]*U[1]*U[2] - 5832*C*L3*U[1]*U[2]*U[3] + 7164*C*L3*U[2]*U[3]*U[3] + 3648*C*L2*R*U[0]*U[1]*U[1] - 6120*C*L2*R*U[0]*U[1]*U[3] + 3648*C*L2*R*U[0]*U[3]*U[3] + 3216*C*L2*R*U[1]*U[1]*U[2] - 9324*C*L2*R*U[1]*U[2]*U[3] + 10080*C*L2*R*U[2]*U[3]*U[3] + 6708*C*L2*U[0]*U[0]*U[1] - 6120*C*L2*U[0]*U[0]*U[3] + 13416*C*L2*U[0]*U[1]*U[2] - 20988*C*L2*U[0]*U[2]*U[3] + 15912*C*L2*U[1]*U[2]*U[2] - 50112*C*L2*U[2]*U[2]*U[3] + 17202*C*L*R*U[0]*U[0]*U[1] - 12828*C*L*R*U[0]*U[0]*U[3] + 25656*C*L*R*U[0]*U[1]*U[2] - 34404*C*L*R*U[0]*U[2]*U[3] + 24066*C*L*R*U[1]*U[2]*U[2] - 66024*C*L*R*U[2]*U[2]*U[3] + 10206*C*L*U[0]*U[0]*U[0] + 26244*C*L*U[0]*U[0]*U[2] + 55890*C*L*U[0]*U[2]*U[2] + 159912*C*L*U[2]*U[2]*U[2] + 28836*C*R*U[0]*U[0]*U[0] + 52488*C*R*U[0]*U[0]*U[2] + 86508*C*R*U[0]*U[2]*U[2] + 192528*C*R*U[2]*U[2]*U[2] + 30030*L*J[0] + 96096*L*J[1] + 54054*R*J[0] + 126126*R*J[1]);
240 F3 += (1.0/360360.0)*L2*(-130*B*L3*U[1]*U[1] + 312*B*L3*U[1]*U[3] - 273*B*L3*U[3]*U[3] - 286*B*L2*R*U[1]*U[1] + 572*B*L2*R*U[1]*U[3] - 429*B*L2*R*U[3]*U[3] - 1092*B*L2*U[0]*U[1] + 1196*B*L2*U[0]*U[3] - 1482*B*L2*U[1]*U[2] + 3094*B*L2*U[2]*U[3] - 2574*B*L*R*U[0]*U[1] + 2288*B*L*R*U[0]*U[3] - 2574*B*L*R*U[1]*U[2] + 4576*B*L*R*U[2]*U[3] - 2379*B*L*U[0]*U[0] - 5538*B*L*U[0]*U[2] - 10101*B*L*U[2]*U[2] - 6149*B*R*U[0]*U[0] - 10010*B*R*U[0]*U[2] - 13871*B*R*U[2]*U[2] - 30*C*L4*U[1]*U[1]*U[1] + 90*C*L4*U[1]*U[1]*U[3] - 120*C*L4*U[1]*U[3]*U[3] + 72*C*L4*U[3]*U[3]*U[3] - 70*C*L3*R*U[1]*U[1]*U[1] + 180*C*L3*R*U[1]*U[1]*U[3] - 210*C*L3*R*U[1]*U[3]*U[3] + 112*C*L3*R*U[3]*U[3]*U[3] - 390*C*L3*U[0]*U[1]*U[1] + 720*C*L3*U[0]*U[1]*U[3] - 450*C*L3*U[0]*U[3]*U[3] - 390*C*L3*U[1]*U[1]*U[2] + 1152*C*L3*U[1]*U[2]*U[3] - 1188*C*L3*U[2]*U[3]*U[3] - 966*C*L2*R*U[0]*U[1]*U[1] + 1500*C*L2*R*U[0]*U[1]*U[3] - 810*C*L2*R*U[0]*U[3]*U[3] - 750*C*L2*R*U[1]*U[1]*U[2] + 1932*C*L2*R*U[1]*U[2]*U[3] - 1764*C*L2*R*U[2]*U[3]*U[3] - 1746*C*L2*U[0]*U[0]*U[1] + 1470*C*L2*U[0]*U[0]*U[3] - 3060*C*L2*U[0]*U[1]*U[2] + 4236*C*L2*U[0]*U[2]*U[3] - 2916*C*L2*U[1]*U[2]*U[2] + 7164*C*L2*U[2]*U[2]*U[3] - 4662*C*L*R*U[0]*U[0]*U[1] + 3216*C*L*R*U[0]*U[0]*U[3] - 6120*C*L*R*U[0]*U[1]*U[2] + 7296*C*L*R*U[0]*U[2]*U[3] - 4662*C*L*R*U[1]*U[2]*U[2] + 10080*C*L*R*U[2]*U[2]*U[3] - 2718*C*L*U[0]*U[0]*U[0] - 6120*C*L*U[0]*U[0]*U[2] - 10494*C*L*U[0]*U[2]*U[2] - 16704*C*L*U[2]*U[2]*U[2] - 8022*C*R*U[0]*U[0]*U[0] - 12828*C*R*U[0]*U[0]*U[2] - 17202*C*R*U[0]*U[2]*U[2] - 22008*C*R*U[2]*U[2]*U[2] - 6006*L*J[0] - 12012*L*J[1] - 12012*R*J[0] - 18018*R*J[1]);
241}
242
243template <>
245 const double, const double L, const double L2, const double L3,
246 const double* P, const double* g, const double* dg, const double ug,
247 double& K00, double& K01, double& K02, double& K03, double& K11,
248 double& K12, double& K13, double& K22, double& K23, double& K33, double& F0,
249 double& F1, double& F2, double& F3)
250{
251 K00 += (1.0/35.0)*L*(10*P[0]*dg[0] + 10*P[1]*dg[1] + 3*P[2]*dg[0] + 3*P[3]*dg[1]);
252 K01 += L2*((1.0/28.0)*P[0]*dg[0] + (1.0/28.0)*P[1]*dg[1] + (1.0/60.0)*P[2]*dg[0] + (1.0/60.0)*P[3]*dg[1]);
253 K02 += (9.0/140.0)*L*(P[0]*dg[0] + P[1]*dg[1] + P[2]*dg[0] + P[3]*dg[1]);
254 K03 += L2*(-1.0/60.0*P[0]*dg[0] - 1.0/60.0*P[1]*dg[1] - 1.0/70.0*P[2]*dg[0] - 1.0/70.0*P[3]*dg[1]);
255 K11 += L3*((1.0/168.0)*P[0]*dg[0] + (1.0/168.0)*P[1]*dg[1] + (1.0/280.0)*P[2]*dg[0] + (1.0/280.0)*P[3]*dg[1]);
256 K12 += L2*((1.0/70.0)*P[0]*dg[0] + (1.0/70.0)*P[1]*dg[1] + (1.0/60.0)*P[2]*dg[0] + (1.0/60.0)*P[3]*dg[1]);
257 K13 += (1.0/280.0)*L3*(-P[0]*dg[0] - P[1]*dg[1] - P[2]*dg[0] - P[3]*dg[1]);
258 K22 += (1.0/35.0)*L*(3*P[0]*dg[0] + 3*P[1]*dg[1] + 10*P[2]*dg[0] + 10*P[3]*dg[1]);
259 K23 += L2*(-1.0/60.0*P[0]*dg[0] - 1.0/60.0*P[1]*dg[1] - 1.0/28.0*P[2]*dg[0] - 1.0/28.0*P[3]*dg[1]);
260 K33 += L3*((1.0/280.0)*P[0]*dg[0] + (1.0/280.0)*P[1]*dg[1] + (1.0/168.0)*P[2]*dg[0] + (1.0/168.0)*P[3]*dg[1]);
261 F0 += (1.0/20.0)*L*(7*ug*P[0]*dg[0] + 7*ug*P[1]*dg[1] + 3*ug*P[2]*dg[0] + 3*ug*P[3]*dg[1] - 7*P[0]*g[0] - 7*P[1]*g[1] - 3*P[2]*g[0] - 3*P[3]*g[1]);
262 F1 += L2*((1.0/20.0)*ug*P[0]*dg[0] + (1.0/20.0)*ug*P[1]*dg[1] + (1.0/30.0)*ug*P[2]*dg[0] + (1.0/30.0)*ug*P[3]*dg[1] - 1.0/20.0*P[0]*g[0] - 1.0/20.0*P[1]*g[1] - 1.0/30.0*P[2]*g[0] - 1.0/30.0*P[3]*g[1]);
263 F2 += (1.0/20.0)*L*(3*ug*P[0]*dg[0] + 3*ug*P[1]*dg[1] + 7*ug*P[2]*dg[0] + 7*ug*P[3]*dg[1] - 3*P[0]*g[0] - 3*P[1]*g[1] - 7*P[2]*g[0] - 7*P[3]*g[1]);
264 F3 += L2*(-1.0/30.0*ug*P[0]*dg[0] - 1.0/30.0*ug*P[1]*dg[1] - 1.0/20.0*ug*P[2]*dg[0] - 1.0/20.0*ug*P[3]*dg[1] + (1.0/30.0)*P[0]*g[0] + (1.0/30.0)*P[1]*g[1] + (1.0/20.0)*P[2]*g[0] + (1.0/20.0)*P[3]*g[1]);
265}
266
267template <>
269 const double R, const double L, const double L2, const double L3,
270 const double* P, const double* g, const double* dg, const double ug,
271 double& K00, double& K01, double& K02, double& K03, double& K11,
272 double& K12, double& K13, double& K22, double& K23, double& K33, double& F0,
273 double& F1, double& F2, double& F3)
274{
275 K00 += (1.0/630.0)*L*(35*L*P[0]*dg[0] + 35*L*P[1]*dg[1] + 19*L*P[2]*dg[0] + 19*L*P[3]*dg[1] + 180*R*P[0]*dg[0] + 180*R*P[1]*dg[1] + 54*R*P[2]*dg[0] + 54*R*P[3]*dg[1]);
276 K01 += (1.0/2520.0)*L2*(25*L*P[0]*dg[0] + 25*L*P[1]*dg[1] + 17*L*P[2]*dg[0] + 17*L*P[3]*dg[1] + 90*R*P[0]*dg[0] + 90*R*P[1]*dg[1] + 42*R*P[2]*dg[0] + 42*R*P[3]*dg[1]);
277 K02 += (1.0/1260.0)*L*(35*L*P[0]*dg[0] + 35*L*P[1]*dg[1] + 46*L*P[2]*dg[0] + 46*L*P[3]*dg[1] + 81*R*P[0]*dg[0] + 81*R*P[1]*dg[1] + 81*R*P[2]*dg[0] + 81*R*P[3]*dg[1]);
278 K03 += (1.0/2520.0)*L2*(-17*L*P[0]*dg[0] - 17*L*P[1]*dg[1] - 19*L*P[2]*dg[0] - 19*L*P[3]*dg[1] - 42*R*P[0]*dg[0] - 42*R*P[1]*dg[1] - 36*R*P[2]*dg[0] - 36*R*P[3]*dg[1]);
279 K11 += L3*((1.0/504.0)*L*P[0]*dg[0] + (1.0/504.0)*L*P[1]*dg[1] + (1.0/630.0)*L*P[2]*dg[0] + (1.0/630.0)*L*P[3]*dg[1] + (1.0/168.0)*R*P[0]*dg[0] + (1.0/168.0)*R*P[1]*dg[1] + (1.0/280.0)*R*P[2]*dg[0] + (1.0/280.0)*R*P[3]*dg[1]);
280 K12 += (1.0/2520.0)*L2*(17*L*P[0]*dg[0] + 17*L*P[1]*dg[1] + 25*L*P[2]*dg[0] + 25*L*P[3]*dg[1] + 36*R*P[0]*dg[0] + 36*R*P[1]*dg[1] + 42*R*P[2]*dg[0] + 42*R*P[3]*dg[1]);
281 K13 += L3*(-1.0/630.0*L*P[0]*dg[0] - 1.0/630.0*L*P[1]*dg[1] - 1.0/504.0*L*P[2]*dg[0] - 1.0/504.0*L*P[3]*dg[1] - 1.0/280.0*R*P[0]*dg[0] - 1.0/280.0*R*P[1]*dg[1] - 1.0/280.0*R*P[2]*dg[0] - 1.0/280.0*R*P[3]*dg[1]);
282 K22 += (1.0/630.0)*L*(35*L*P[0]*dg[0] + 35*L*P[1]*dg[1] + 145*L*P[2]*dg[0] + 145*L*P[3]*dg[1] + 54*R*P[0]*dg[0] + 54*R*P[1]*dg[1] + 180*R*P[2]*dg[0] + 180*R*P[3]*dg[1]);
283 K23 += (1.0/2520.0)*L2*(-25*L*P[0]*dg[0] - 25*L*P[1]*dg[1] - 65*L*P[2]*dg[0] - 65*L*P[3]*dg[1] - 42*R*P[0]*dg[0] - 42*R*P[1]*dg[1] - 90*R*P[2]*dg[0] - 90*R*P[3]*dg[1]);
284 K33 += L3*((1.0/504.0)*L*P[0]*dg[0] + (1.0/504.0)*L*P[1]*dg[1] + (1.0/252.0)*L*P[2]*dg[0] + (1.0/252.0)*L*P[3]*dg[1] + (1.0/280.0)*R*P[0]*dg[0] + (1.0/280.0)*R*P[1]*dg[1] + (1.0/168.0)*R*P[2]*dg[0] + (1.0/168.0)*R*P[3]*dg[1]);
285 F0 += (1.0/60.0)*L*(5*L*ug*P[0]*dg[0] + 5*L*ug*P[1]*dg[1] + 4*L*ug*P[2]*dg[0] + 4*L*ug*P[3]*dg[1] - 5*L*P[0]*g[0] - 5*L*P[1]*g[1] - 4*L*P[2]*g[0] - 4*L*P[3]*g[1] + 21*R*ug*P[0]*dg[0] + 21*R*ug*P[1]*dg[1] + 9*R*ug*P[2]*dg[0] + 9*R*ug*P[3]*dg[1] - 21*R*P[0]*g[0] - 21*R*P[1]*g[1] - 9*R*P[2]*g[0] - 9*R*P[3]*g[1]);
286 F1 += (1.0/60.0)*L2*(L*ug*P[0]*dg[0] + L*ug*P[1]*dg[1] + L*ug*P[2]*dg[0] + L*ug*P[3]*dg[1] - L*P[0]*g[0] - L*P[1]*g[1] - L*P[2]*g[0] - L*P[3]*g[1] + 3*R*ug*P[0]*dg[0] + 3*R*ug*P[1]*dg[1] + 2*R*ug*P[2]*dg[0] + 2*R*ug*P[3]*dg[1] - 3*R*P[0]*g[0] - 3*R*P[1]*g[1] - 2*R*P[2]*g[0] - 2*R*P[3]*g[1]);
287 F2 += (1.0/60.0)*L*(5*L*ug*P[0]*dg[0] + 5*L*ug*P[1]*dg[1] + 16*L*ug*P[2]*dg[0] + 16*L*ug*P[3]*dg[1] - 5*L*P[0]*g[0] - 5*L*P[1]*g[1] - 16*L*P[2]*g[0] - 16*L*P[3]*g[1] + 9*R*ug*P[0]*dg[0] + 9*R*ug*P[1]*dg[1] + 21*R*ug*P[2]*dg[0] + 21*R*ug*P[3]*dg[1] - 9*R*P[0]*g[0] - 9*R*P[1]*g[1] - 21*R*P[2]*g[0] - 21*R*P[3]*g[1]);
288 F3 += (1.0/60.0)*L2*(-L*ug*P[0]*dg[0] - L*ug*P[1]*dg[1] - 2*L*ug*P[2]*dg[0] - 2*L*ug*P[3]*dg[1] + L*P[0]*g[0] + L*P[1]*g[1] + 2*L*P[2]*g[0] + 2*L*P[3]*g[1] - 2*R*ug*P[0]*dg[0] - 2*R*ug*P[1]*dg[1] - 3*R*ug*P[2]*dg[0] - 3*R*ug*P[3]*dg[1] + 2*R*P[0]*g[0] + 2*R*P[1]*g[1] + 3*R*P[2]*g[0] + 3*R*P[3]*g[1]);
289}
290// clang-format on
291
292template <>
293template <typename T>
294inline T Diffusion2DSolver<Geometry2DCartesian>::integrateLinear(const double R, const double L, const T* P) {
295 T res = 0.5 * (P[0] + P[1]) * L;
296 if (this->geometry->getExtrusion()->getLength()) res *= this->geometry->getExtrusion()->getLength();
297 return res;
298}
299
300template <>
301template <typename T>
302inline T Diffusion2DSolver<Geometry2DCylindrical>::integrateLinear(const double R, const double L, const T* P) {
303 return (PI / 3.) * L * (L * (P[0] + 2 * P[1]) + 3 * R * (P[0] + P[1]));
304}
305
306template <typename Geometry2DType> double Diffusion2DSolver<Geometry2DType>::compute(unsigned loops, bool shb, size_t act) {
307 this->initCalculation();
308
309 auto found = this->active.find(act);
310 if (found == this->active.end()) throw Exception("{}: Active region {} does not exist", this->getId(), act);
311 auto& active = found->second;
312
313 double z = active.vert();
314
315 auto mesh = active.mesh();
316 size_t nn = mesh->size();
317 size_t N = 2 * nn, ne = nn - 1;
318 assert(active.mesh1->size() == nn);
319 assert(active.emesh1->size() == ne);
320
321 size_t nmodes = 0;
322
323 if (!active.U) active.U.reset(N, 0.);
324
325 DataVector<double> A(ne), B(ne), C(ne), D(ne);
326
327 auto temperature = active.verticallyAverage(inTemperature, active.emesh2, InterpolationMethod::INTERPOLATION_SPLINE);
328 for (size_t i = 0; i != ne; ++i) {
329 auto material = this->geometry->getMaterial(active.emesh1->at(i));
330 double T = temperature[i];
331 A[i] = material->A(T);
332 B[i] = material->B(T);
333 C[i] = material->C(T);
334 D[i] = 1e8 * material->D(T); // cm²/s -> µm²/s
335 }
336
337 DataVector<double> J(nn);
338 double js = 1e7 / (phys::qe * active.QWheight);
339 size_t i = 0;
340 for (auto j : inCurrentDensity(active.mesh1, InterpolationMethod::INTERPOLATION_SPLINE)) {
341 J[i] = abs(js * j.c1);
342 ++i;
343 }
344
345 std::vector<DataVector<Tensor2<double>>> Ps;
346 std::vector<DataVector<double>> nrs;
347
348 this->writelog(LOG_INFO, "Running diffusion calculations");
349
350 if (shb) {
351 nmodes = inWavelength.size();
352
353 if (inLightE.size() != nmodes)
354 throw BadInput(this->getId(), "number of modes in inWavelength ({}) and inLightE ({}) differ", inWavelength.size(),
355 inLightE.size());
356
357 active.modesP.assign(inWavelength.size(), 0.);
358
359 Ps.reserve(nmodes);
360 nrs.reserve(nmodes);
361 for (size_t i = 0; i != nmodes; ++i) {
362 Ps.emplace_back(nn);
363 nrs.emplace_back(ne);
364 }
365
366 for (size_t i = 0; i != ne; ++i) {
367 auto material = this->geometry->getMaterial(active.emesh1->at(i));
368 for (size_t n = 0; n != nmodes; ++n) nrs[n][i] = material->Nr(real(inWavelength(n)), temperature[i]).real();
369 }
370
371 for (size_t n = 0; n != nmodes; ++n) {
372 double wavelength = real(inWavelength(n));
373 writelog(LOG_DEBUG, "Mode {} wavelength: {} nm", n, wavelength);
374 auto P = active.verticallyAverage(inLightE, active.mesh2);
375 for (size_t i = 0; i != nn; ++i) {
376 Ps[n][i].c00 = (0.5 / Z0) * real(P[i].c0 * conj(P[i].c0) + P[i].c1 * conj(P[i].c1));
377 Ps[n][i].c11 = (0.5 / Z0) * real(P[i].c2 * conj(P[i].c2));
378 }
379 }
380 }
381
382 unsigned loop = 0;
383
384 std::unique_ptr<FemMatrix> K;
385
386 toterr = 0.;
387
390
391 switch (this->algorithm) {
392 case ALGORITHM_CHOLESKY: K.reset(new DpbMatrix(this, N, 3)); break;
393 case ALGORITHM_GAUSS: K.reset(new DgbMatrix(this, N, 3)); break;
394 case ALGORITHM_ITERATIVE: K.reset(new SparseBandMatrix(this, N, {0, 1, 2, 3})); break;
395 }
396
397 while (true) {
398 // Set stiffness matrix and load vector
399 this->writelog(LOG_DETAIL, "Setting up matrix system ({})", K->describe());
400 K->clear();
401 F.fill(0.);
402 for (size_t ie = 0; ie < ne; ++ie) {
403 double x0 = mesh->at(ie), x1 = mesh->at(ie + 1);
404 size_t i = 2 * ie;
405 // clang-format off
406 const double L = x1 - x0;
407 const double L2 = L * L;
408 const double L3 = L2 * L;
409 const double L4 = L2 * L2, L5 = L3 * L2, L6 = L3 * L3;
410 setLocalMatrix(x0, L, L2, L3, L4, L5, L6, A[ie], B[ie], C[ie], D[ie], active.U.data() + i, J.data() + ie,
411 (*K)(i,i), (*K)(i,i+1), (*K)(i,i+2), (*K)(i,i+3), (*K)(i+1,i+1),
412 (*K)(i+1,i+2), (*K)(i+1,i+3), (*K)(i+2,i+2), (*K)(i+2,i+3), (*K)(i+3,i+3),
413 F[i], F[i+1], F[i+2], F[i+3]);
414 // clang-format on
415 }
416
417 write_debug("{}: Iteration {}", this->getId(), loop);
418
419 // Add SHB
420 if (shb) {
421 std::fill(active.modesP.begin(), active.modesP.end(), 0.);
422 for (size_t n = 0; n != nmodes; ++n) {
423 double wavelength = real(inWavelength(n));
424 double factor = inv_hc * wavelength;
425 auto gain = inGain(active.emesh1, wavelength, InterpolationMethod::INTERPOLATION_SPLINE);
426 auto dgdn = inGain(Gain::DGDN, active.emesh1, wavelength, InterpolationMethod::INTERPOLATION_SPLINE);
427 const Tensor2<double>* Pdata = Ps[n].data();
428 for (size_t ie = 0; ie < ne; ++ie) {
429 double x0 = mesh->at(ie), x1 = mesh->at(ie + 1);
430 size_t i = 2 * ie;
431 const double L = x1 - x0;
432 // clang-format off
433 const double L2 = L * L;
434 const double L3 = L2 * L;
435 Tensor2<double> g = nrs[n][ie] * gain[ie];
437 Tensor2<double> p = integrateLinear(x0, L, Pdata + ie);
438 active.modesP[n] += p.c00 * g.c00 + p.c11 * g.c11;
439 g *= factor;
440 dg *= factor;
441 double ug = 0.5 * (active.U[i] + active.U[i+2] + 0.25 * L * (active.U[i+1] - active.U[i+3]));
442 addLocalBurningMatrix(x0, L, L2, L3, reinterpret_cast<const double*>(Pdata + ie), &g.c00, &dg.c00, ug,
443 (*K)(i,i), (*K)(i,i+1), (*K)(i,i+2), (*K)(i,i+3), (*K)(i+1,i+1),
444 (*K)(i+1,i+2), (*K)(i+1,i+3), (*K)(i+2,i+2), (*K)(i+2,i+3), (*K)(i+3,i+3),
445 F[i], F[i+1], F[i+2], F[i+3]);
446 // clang-format ons
447 }
448 active.modesP[n] *= 1e-13 * active.QWheight;
449 // 10⁻¹³ from µm to cm conversion and conversion to mW (r dr), (...) — photon energy
450 writelog(LOG_DEBUG, "{}: Mode {} burned power: {} mW", this->getId(), n, active.modesP[n]);
451 }
452 }
453
454 // Set derivatives to 0 at the edges
455 K->setBC(F, 1, 0.);
456 K->setBC(F, K->rank - 1, 0.);
457
458#ifndef NDEBUG
459 double* kend = K->data + K->size;
460 for (double* pk = K->data; pk != kend; ++pk) {
461 if (isnan(*pk) || isinf(*pk))
462 throw ComputationError(this->getId(), "error in stiffness matrix at position {0} ({1})", pk - K->data,
463 isnan(*pk) ? "nan" : "inf");
464 }
465 for (auto f = F.begin(); f != F.end(); ++f) {
466 if (isnan(*f) || isinf(*f))
467 throw ComputationError(this->getId(), "error in load vector at position {0} ({1})", f - F.begin(),
468 isnan(*f) ? "nan" : "inf");
469 }
470#endif
471
472 // Compute current error
473 for (auto f = F.begin(), r = resid.begin(); f != F.end(); ++f, ++r) *r = -*f;
474 K->addmult(active.U, resid);
475
476 double err = 0.;
477 for (auto r = resid.begin(); r != resid.end(); ++r) err += *r * *r;
478 double denorm = 0.;
479 for (auto f = F.begin(); f != F.end(); ++f) denorm += *f * *f;
480 err = 100. * sqrt(err / denorm);
481
482 // Do next calculation step
483 if (loop != 0) this->writelog(LOG_RESULT, "Loop {:d}({:d}) @ active region {}: error = {:g}%", loop, loopno, act, err);
484 ++loopno;
485 ++loop;
486 if (err < maxerr || ((loops != 0 && loop >= loops))) break;
487
488 // TODO add linear mixing with the previous solution
489 K->solve(F, active.U);
490 }
491
492 outCarriersConcentration.fireChanged();
493
494 return toterr;
495}
496
497template <typename Geometry2DType>
499 if (mode >= inLightE.size()) throw BadInput(this->getId(), "mode index out of range");
500 double res = 0.;
501 for (const auto& iactive: this->active) {
502 const auto& active = iactive.second;
503 if (mode >= active.modesP.size()) throw Exception("{}: SHB not computed for active region {}", this->getId(), iactive.first);
504 res += active.modesP[mode];
505 }
506 return res;
507}
508
509template <typename Geometry2DType>
511 double res = 0.;
512 for (size_t i = 0; i != inLightE.size(); ++i) res += get_burning_integral_for_mode(i);
513 return res;
514}
515
516
517template <typename Geometry2DType>
519 shared_ptr<const plask::MeshD<2>> dest_mesh,
520 InterpolationMethod interp)
521 : solver(solver), destination_mesh(dest_mesh), interpolationFlags(InterpolationFlags(solver->geometry)) {
522 concentrations.reserve(solver->active.size());
523
525 for (const auto& iactive : solver->active) {
526 const auto& active = iactive.second;
527 auto src_mesh = active.mesh();
528 if (!active.U) throw NoValue("carriers concentration");
529 assert(src_mesh->size() == active.U.size() / 2);
530 concentrations.emplace_back(LazyData<double>(dest_mesh->size(), [this, active, src_mesh](size_t i) -> double {
531 double x = interpolationFlags.wrap(0, destination_mesh->at(i).c0);
532 assert(src_mesh->at(0) <= x && x <= src_mesh->at(src_mesh->size() - 1));
533 size_t idx = src_mesh->findIndex(x);
534 if (idx == 0) return active.U[0];
535 const double x0 = src_mesh->at(idx - 1);
536 const double L = src_mesh->at(idx) - x0;
537 x -= x0;
538 double L2 = L * L;
539 double L3 = L2 * L;
540 double x2 = x * x;
541 double x3 = x2 * x;
542 idx *= 2;
543 // U[idx - 2] <- U[idx - 1].value
544 // U[idx] <- U[idx].value
545 // U[idx - 1] <- U[idx - 1].derivative
546 // U[idx + 1] <- U[idx].derivative
547 return (1 - 3 * x2 / L2 + 2 * x3 / L3) * active.U[idx - 2] + (3 * x2 / L2 - 2 * x3 / L3) * active.U[idx] +
548 (x - 2 * x2 / L + x3 / L2) * active.U[idx - 1] + (-x2 / L + x3 / L2) * active.U[idx + 1];
549 }));
550 }
551
552 } else {
553 for (const auto& iactive : solver->active) {
554 const auto& active = iactive.second;
555 if (!active.U) throw NoValue("carriers concentration");
558 DataVector<double> conc(active.U.size() / 2);
560 for (auto u = active.U.begin(); u < active.U.end(); u += 2, ++c) *c = *u;
561 concentrations.emplace_back(interpolate(mesh, conc, dest_mesh, interp, interpolationFlags));
562 }
563 }
564}
565
566template <typename Geometry2DType> double Diffusion2DSolver<Geometry2DType>::ConcentrationDataImpl::at(size_t i) const {
567 auto point = interpolationFlags.wrap(destination_mesh->at(i));
568 bool found = false;
569 size_t an;
570 for (const auto& iactive : solver->active) {
571 const auto& active = iactive.second;
572 if (solver->mesh->vert()->at(active.bottom) <= point.c1 && point.c1 <= solver->mesh->vert()->at(active.top)) {
573 // Make sure we have concentration only in the quantum wells
574 // TODO maybe more optimal approach would be reasonable?
575 if (solver->mesh->tran()->at(active.left) <= point.c0 && point.c0 <= solver->mesh->tran()->at(active.right))
576 for (auto qw : active.QWs)
577 if (qw.first <= point.c1 && point.c1 < qw.second) {
578 found = true;
579 an = iactive.first;
580 break;
581 }
582 break;
583 }
584 }
585 if (!found) return 0.;
586 return concentrations[an][i];
587}
588
589template <typename Geometry2DType>
591 shared_ptr<const plask::MeshD<2>> dest_mesh,
592 InterpolationMethod interpolation) const {
594 return LazyData<double>(dest_mesh->size(), NAN);
595 }
596 return LazyData<double>(new Diffusion2DSolver<Geometry2DType>::ConcentrationDataImpl(this, dest_mesh, interpolation));
597}
598
599template <> std::string Diffusion2DSolver<Geometry2DCartesian>::getClassName() const { return "electrical.Diffusion2D"; }
600template <> std::string Diffusion2DSolver<Geometry2DCylindrical>::getClassName() const { return "electrical.DiffusionCyl"; }
601
604
605}}} // namespace plask::electrical::diffusion