PLaSK library

Loading...
Searching...
No Matches
ferminew.hpp
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 */
18#ifndef PLASK__SOLVER_GAIN_FermiNew_H
19#define PLASK__SOLVER_GAIN_FermiNew_H
20
21#include <plask/plask.hpp>
22#include "wzmocnienie/kublybr.h"
23
24 namespace plask { namespace solvers { namespace FermiNew {
25
26 template <typename GeometryT, typename T> struct DataBase;
27 template <typename GeometryT> struct GainData;
28 template <typename GeometryT> struct DgDnData;
29 template <typename GeometryT> struct LuminescenceData;
30
31 template <typename GeometryT> struct GainSpectrum;
32 template <typename GeometryT> struct LuminescenceSpectrum;
33
34 struct Levels {
35 double Eg;
36 std::unique_ptr<kubly::struktura> bandsEc, bandsEvhh, bandsEvlh;
37 std::unique_ptr<kubly::struktura> modbandsEc, modbandsEvhh, modbandsEvlh;
38 plask::shared_ptr<kubly::obszar_aktywny> activeRegion;
39 operator bool() const { return bool(bandsEc) || bool(bandsEvhh) || bool(bandsEvlh); }
40};
41
45 template <typename GeometryType> struct PLASK_SOLVER_API FermiNewGainSolver : public SolverWithMesh<GeometryType, MeshAxis> {
49 struct ActiveRegionData {
50 shared_ptr<StackContainer<2>> layers;
51 Vec<2> origin;
52 std::set<int> QWs;
53
54 // LUKASZ
55 std::vector<double> lens;
56
57 // shared_ptr<Material> materialQW; ///< Quantum well material
58 // shared_ptr<Material> materialBarrier; ///< Barrier material
59 double qwlen;
60 double qwtotallen;
61 double totallen;
62
63 ActiveRegionData(Vec<2> origin) : layers(plask::make_shared<StackContainer<2>>()), origin(origin) {}
64
66 size_t size() const { return layers->getChildrenCount(); }
67
69 shared_ptr<Material> getLayerMaterial(size_t n) const {
70 auto block = static_cast<Block<2>*>(static_cast<Translation<2>*>(layers->getChildNo(n).get())->getChild().get());
71 if (auto m = block->singleMaterial()) return m;
72 throw plask::Exception("FermiNewGainSolver requires solid layers.");
73 }
74
76 Box2D getLayerBox(size_t n) const {
77 return static_cast<GeometryObjectD<2>*>(layers->getChildNo(n).get())->getBoundingBox() + origin;
78 }
79
81 bool isQW(size_t n) const { return static_cast<Translation<2>*>(layers->getChildNo(n).get())->getChild()->hasRole("QW"); }
82
84 Box2D getBoundingBox() const { return layers->getBoundingBox() + origin; }
85
87 bool contains(const Vec<2>& point) const { return getBoundingBox().contains(point); }
88
90 bool inQW(const Vec<2>& point) const {
91 if (!contains(point)) return false;
92 assert(layers->getChildForHeight(point.c1 - origin.c1));
93 return layers->getChildForHeight(point.c1 - origin.c1)->getChild()->hasRole("QW");
94 }
95
100 void summarize(const FermiNewGainSolver<GeometryType>* solver) {
101 totallen =
102 1e4 * (layers->getBoundingBox().height() -
103 static_pointer_cast<GeometryObjectD<GeometryType::DIM>>(layers->getChildNo(0))->getBoundingBox().height() -
104 static_pointer_cast<GeometryObjectD<GeometryType::DIM>>(layers->getChildNo(layers->getChildrenCount() - 1))
105 ->getBoundingBox()
106 .height()); // 1e4: µm -> Å
107 size_t qwn = 0;
108 qwtotallen = 0.;
109 bool lastbarrier = true;
110 for (const auto& layer : layers->children) {
111 auto block = static_cast<Block<2>*>(static_cast<Translation<2>*>(layer.get())->getChild().get());
112 auto material = block->singleMaterial();
113 if (!material) throw plask::Exception("FermiNewGainSolver requires solid layers.");
114 if (static_cast<Translation<2>*>(layer.get())->getChild()->hasRole("QW")) {
115 /*if (!materialQW)
116 materialQW = material;
117 else if (*material != *materialQW)
118 throw Exception("{0}: Multiple quantum well materials in active region.", solver->getId());*/
119 auto bbox = static_cast<GeometryObjectD<2>*>(layer.get())->getBoundingBox();
120 qwtotallen += bbox.upper[1] - bbox.lower[1];
121 if (lastbarrier)
122 ++qwn;
123 else
124 solver->writelog(LOG_WARNING, "Considering two adjacent quantum wells as one");
125 lastbarrier = false;
126 } else // if (static_cast<Translation<2>*>(layer.get())->getChild()->hasRole("barrier")) //
127 // TODO 4.09.2014
128 {
129 /*if (!materialBarrier)
130 materialBarrier = material;
131 else if (!is_zero(material->Me(300).c00 - materialBarrier->Me(300).c00) ||
132 !is_zero(material->Me(300).c11 - materialBarrier->Me(300).c11) ||
133 !is_zero(material->Mhh(300).c00 - materialBarrier->Mhh(300).c00) ||
134 !is_zero(material->Mhh(300).c11 - materialBarrier->Mhh(300).c11) ||
135 !is_zero(material->Mlh(300).c00 - materialBarrier->Mlh(300).c00) ||
136 !is_zero(material->Mlh(300).c11 - materialBarrier->Mlh(300).c11) ||
137 !is_zero(material->CB(300) - materialBarrier->CB(300)) ||
138 !is_zero(material->VB(300) - materialBarrier->VB(300)))
139 throw Exception("{0}: Multiple barrier materials around active region.", solver->getId());*/
140 lastbarrier = true;
141 } // TODO something must be added here because of spacers placed next to external barriers
142 }
143 qwtotallen *= 1e4; // µm -> Å
144 qwlen = qwtotallen / qwn;
145 }
146 };
147
151 struct ActiveRegionInfo : public ActiveRegionData {
152 boost::optional<ActiveRegionData> mod;
153
154 ActiveRegionInfo(Vec<2> origin) : ActiveRegionData(origin) {}
155
156 ActiveRegionInfo(const ActiveRegionData& src) : ActiveRegionData(src) {}
157
158 ActiveRegionInfo(ActiveRegionData&& src) : ActiveRegionData(std::move(src)) {}
159 };
160
161 shared_ptr<GeometryType> geometry_mod;
162
163 shared_ptr<Material> substrateMaterial;
164 bool explicitSubstrate = false;
165
167 std::vector<ActiveRegionInfo> regions;
168
170 ReceiverFor<Temperature, GeometryType> inTemperature;
171
173 ReceiverFor<CarriersConcentration, GeometryType> inCarriersConcentration;
174
176 typename ProviderFor<Gain, GeometryType>::Delegate outGain;
177
179 typename ProviderFor<Luminescence, GeometryType>::Delegate outLuminescence;
180
181 FermiNewGainSolver(const std::string& name = "");
182
183 virtual ~FermiNewGainSolver();
184
185 virtual std::string getClassName() const;
186
187 virtual void loadConfiguration(plask::XMLReader& reader, plask::Manager& manager);
188
190 shared_ptr<GeometryType> getModGeometry() const { return geometry_mod; }
191
196 void setModGeometry(const shared_ptr<GeometryType>& geometry) {
197 if (geometry == this->geometry_mod) return;
198 writelog(LOG_INFO, "Attaching modified geometry to solver");
199 disconnectModGeometry();
200 this->geometry_mod = geometry;
201 if (this->geometry_mod)
202 this->geometry_mod->changedConnectMethod(this, &FermiNewGainSolver<GeometryType>::onModGeometryChange);
203 onModGeometryChange(Geometry::Event(geometry.get(), 0));
204 }
205
206 void disconnectModGeometry() {
207 if (this->geometry_mod)
208 this->geometry_mod->changedDisconnectMethod(this, &FermiNewGainSolver<GeometryType>::onModGeometryChange);
209 }
210
211 friend struct DataBase<GeometryType, Tensor2<double>>;
212 friend struct DataBase<GeometryType, double>;
213 friend struct GainData<GeometryType>;
214 friend struct DgDnData<GeometryType>;
215 friend struct LuminescenceData<GeometryType>;
216
217 std::vector<Levels> region_levels;
218
219 friend struct GainSpectrum<GeometryType>;
220 friend struct LuminescenceSpectrum<GeometryType>;
221 friend class wzmocnienie;
222
223 double condQWshift;
224 double valeQWshift;
225 double QWwidthMod;
226 double roughness;
227 double lifetime;
228 double matrixElem;
229 double differenceQuotient;
230 double Tref;
231
232 void findEnergyLevels(Levels& levels, const ActiveRegionInfo& region, double T);
233
234 void buildStructure(double T,
235 const ActiveRegionData& region,
236 std::unique_ptr<kubly::struktura>& bandsEc,
237 std::unique_ptr<kubly::struktura>& bandsEvhh,
238 std::unique_ptr<kubly::struktura>& bandsEvlh);
239 kubly::struktura* buildEc(double T, const ActiveRegionData& region);
240 kubly::struktura* buildEvhh(double T, const ActiveRegionData& region);
241 kubly::struktura* buildEvlh(double T, const ActiveRegionData& region);
242
243 void showEnergyLevels(std::string str, const std::unique_ptr<kubly::struktura>& structure, double nQW);
244
245 kubly::wzmocnienie getGainModule(double wavelength, double T, double n, const ActiveRegionInfo& region, const Levels& levels);
246
247 void prepareLevels(kubly::wzmocnienie& gmodule, const ActiveRegionInfo& region) {}
248
250 virtual void onInitialize();
251
253 virtual void onInvalidate();
254
256 void onModGeometryChange(const Geometry::Event&) { this->invalidate(); }
257
259 void onInputChange(ReceiverBase&, ReceiverBase::ChangeReason) {
260 outGain.fireChanged(); // the input changed, so we inform the world that everybody should get the new gain
261 outLuminescence.fireChanged(); // the input changed, so we inform the world that everybody should get the new luminescence
262 }
263
267 std::list<ActiveRegionData> detectActiveRegions(const shared_ptr<GeometryType>& geometry);
268
273 void prepareActiveRegionsInfo();
274
282 const LazyData<Tensor2<double>> getGain(Gain::EnumType what,
283 const shared_ptr<const MeshD<2>>& dst_mesh,
284 double wavelength,
285 InterpolationMethod interp = INTERPOLATION_DEFAULT);
286
287 const LazyData<Tensor2<double>> getLuminescence(const shared_ptr<const MeshD<2>>& dst_mesh,
288 double wavelength,
289 InterpolationMethod interp = INTERPOLATION_DEFAULT);
290
291 bool strains;
292 bool adjust_widths;
293 bool build_struct_once;
294
295 public:
296 bool getStrains() const { return strains; }
297 void setStrains(bool value) {
298 if (strains != value) {
299 strains = value;
300 if (build_struct_once) this->invalidate();
301 }
302 }
303
305 shared_ptr<Material> getSubstrate() const { return substrateMaterial; }
307 void setSubstrate(shared_ptr<Material> material) {
308 bool invalid = substrateMaterial != material;
309 substrateMaterial = material;
310 explicitSubstrate = bool(material);
311 if (invalid) this->invalidate();
312 }
313
314 bool getAdjustWidths() const { return adjust_widths; }
315 void setAdjustWidths(bool value) {
316 if (adjust_widths != value) {
317 adjust_widths = value;
318 this->invalidate();
319 }
320 }
321
322 bool getBuildStructOnce() const { return build_struct_once; }
323 void setBuildStructOnce(bool value) {
324 if (build_struct_once != value) {
325 build_struct_once = value;
326 this->invalidate();
327 }
328 }
329
330 double getRoughness() const { return roughness; }
331 void setRoughness(double value) {
332 if (roughness != value) {
333 roughness = value;
334 if (build_struct_once) this->invalidate();
335 }
336 }
337
338 double getLifeTime() const { return lifetime; }
339 void setLifeTime(double value) {
340 if (lifetime != value) {
341 lifetime = value;
342 // if (build_struct_once) this->invalidate();
343 }
344 }
345
346 double getMatrixElem() const { return matrixElem; }
347 void setMatrixElem(double value) {
348 if (matrixElem != value) {
349 matrixElem = value;
350 if (build_struct_once) this->invalidate();
351 }
352 }
353
354 double getCondQWShift() const { return condQWshift; }
355 void setCondQWShift(double value) {
356 if (condQWshift != value) {
357 condQWshift = value;
358 if (build_struct_once) this->invalidate();
359 }
360 }
361
362 double getValeQWShift() const { return valeQWshift; }
363 void setValeQWShift(double value) {
364 if (valeQWshift != value) {
365 valeQWshift = value;
366 if (build_struct_once) this->invalidate();
367 }
368 }
369
370 double getTref() const { return Tref; }
371 void setTref(double value) {
372 if (Tref != value) {
373 Tref = value;
374 if (build_struct_once) this->invalidate();
375 }
376 }
377
381 GainSpectrum<GeometryType> getGainSpectrum(const Vec<2>& point);
382
386 LuminescenceSpectrum<GeometryType> getLuminescenceSpectrum(const Vec<2>& point);
387};
388
392 template <typename GeometryT> struct PLASK_SOLVER_API GainSpectrum {
393 FermiNewGainSolver<GeometryT>* solver;
394 Vec<2> point;
395
397 size_t reg;
398
399 double T;
400 double n;
401 unique_ptr<Levels> levels;
402 std::unique_ptr<kubly::wzmocnienie> gMod;
403
404 GainSpectrum(FermiNewGainSolver<GeometryT>* solver, const Vec<2> point);
405
406 GainSpectrum(const GainSpectrum& orig) : solver(orig.solver), point(orig.point), reg(orig.reg), T(orig.T), n(orig.n) {}
407
408 GainSpectrum(GainSpectrum&& orig) = default;
409
410 void onTChange(ReceiverBase&, ReceiverBase::ChangeReason) {
411 T = solver->inTemperature(plask::make_shared<const OnePointMesh<2>>(point))[0];
412 }
413
414 void onNChange(ReceiverBase&, ReceiverBase::ChangeReason) {
415 n = solver->inCarriersConcentration(plask::make_shared<const OnePointMesh<2>>(point))[0];
416 }
417
418 ~GainSpectrum() {
419 solver->inTemperature.changedDisconnectMethod(this, &GainSpectrum::onTChange);
420 solver->inCarriersConcentration.changedDisconnectMethod(this, &GainSpectrum::onNChange);
421 }
422
428 Tensor2<double> getGain(double wavelength);
429};
430
434 template <typename GeometryT> struct PLASK_SOLVER_API LuminescenceSpectrum {
435 FermiNewGainSolver<GeometryT>* solver;
436 Vec<2> point;
437
439 size_t reg;
440
441 double T;
442 double n;
443 unique_ptr<Levels> levels;
444 std::unique_ptr<kubly::wzmocnienie> gMod;
445
446 LuminescenceSpectrum(FermiNewGainSolver<GeometryT>* solver, const Vec<2> point);
447
448 LuminescenceSpectrum(const LuminescenceSpectrum& orig)
449 : solver(orig.solver), point(orig.point), reg(orig.reg), T(orig.T), n(orig.n) {}
450
451 LuminescenceSpectrum(LuminescenceSpectrum&& orig) = default;
452
453 void onTChange(ReceiverBase&, ReceiverBase::ChangeReason) {
454 T = solver->inTemperature(plask::make_shared<const OnePointMesh<2>>(point))[0];
455 }
456
457 void onNChange(ReceiverBase&, ReceiverBase::ChangeReason) {
458 n = solver->inCarriersConcentration(plask::make_shared<const OnePointMesh<2>>(point))[0];
459 }
460
461 ~LuminescenceSpectrum() {
462 solver->inTemperature.changedDisconnectMethod(this, &LuminescenceSpectrum::onTChange);
463 solver->inCarriersConcentration.changedDisconnectMethod(this, &LuminescenceSpectrum::onNChange);
464 }
465
471 Tensor2<double> getLuminescence(double wavelength);
472};
473
474}}} // namespace plask::solvers::FermiNew
475
476#endif