PLaSK library

Loading...
Searching...
No Matches
material.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 "material.hpp"
15
16#include <boost/lexical_cast.hpp>
17#include "../log/log.hpp"
18#include "../utils/stl.hpp"
19#include "../utils/string.hpp"
20#include "db.hpp"
21
22#include <cmath>
23#include <set>
24
25 namespace plask {
26
27// inline std::pair<std::string, int> el_g(const std::string& g, int p) { return std::pair<std::string, int>(g, p); }
28
29 int elementGroup(const std::string& objectName) {
30 static const std::map<std::string, int> elementGroups = {{"Be", 2}, {"Mg", 2}, {"Ca", 2}, {"Sr", 2}, {"Ba", 2}, {"B", 3},
31 {"Al", 3}, {"Ga", 3}, {"In", 3}, {"Tl", 3}, {"C", 4}, {"Si", 4},
32 {"Ge", 4}, {"Sn", 4}, {"Pb", 4}, {"N", 5}, {"P", 5}, {"As", 5},
33 {"Sb", 5}, {"Bi", 5}, {"O", 6}, {"S", 6}, {"Se", 6}, {"Te", 6}};
34 return map_find(elementGroups, objectName, 0);
35}
36
37 template <typename NameValuePairIter>
38 inline void fillGroupMaterialCompositionAmounts(NameValuePairIter begin, NameValuePairIter end, int group_nr) {
39 static const char* const ROMANS[] = {"I", "II", "III", "IV", "V", "VI", "VII"};
40 assert(0 < group_nr && group_nr < 8);
41 auto no_info = end;
42 double sum = 0.0;
43 unsigned n = 0;
44 for (auto i = begin; i != end; ++i) {
45 if (std::isnan(i->second)) {
46 if (no_info != end)
47 throw plask::MaterialParseException("incomplete material composition for group {0} elements", ROMANS[group_nr - 1]);
48 else
49 no_info = i;
50 } else {
51 sum += i->second;
52 ++n;
53 }
54 }
55 if (n > 0 && sum - 1.0 > SMALL * std::max(n, unsigned(1)))
56 throw plask::MaterialParseException("total material composition for group {0} elements exceeds 1", ROMANS[group_nr - 1]);
57 if (no_info != end) {
58 no_info->second = 1.0 - sum;
59 } else {
60 if (!is_zero(sum - 1.0, SMALL * std::max(n, unsigned(1))))
61 throw plask::MaterialParseException("total material composition for group {0} elements ({1}) differs from 1",
62 ROMANS[group_nr - 1], sum);
63 }
64}
65
66 Material::StringBuilder& Material::StringBuilder::operator()(const std::string& objectName, double ammount) {
67 str << objectName;
68 str << '(';
69 str << ammount;
70 str << ')';
71 return *this;
72}
73
74std::string Material::StringBuilder::dopant(const std::string& dopant, double dopantConcentration) {
75 str << ':';
76 str << dopant;
77 str << '=';
78 str << dopantConcentration;
79 return str.str();
80}
81
82 void Material::Parameters::parse(const std::string& full_material_str, bool allow_dopant_without_amount) {
83 std::string dope;
84 std::tie(name, dope) = splitString2(full_material_str, ':');
85 std::tie(name, label) = splitString2(name, '_');
86 if (!dope.empty())
87 Material::parseDopant(dope, dopant, doping, allow_dopant_without_amount, full_material_str.c_str());
88 else
89 this->clearDoping();
90 if (isSimpleMaterialName(name))
91 composition.clear();
92 else
93 composition = Material::parseComposition(name, full_material_str);
94}
95
96std::string Material::Parameters::str() const {
97 std::string result;
98 if (isAlloy()) {
99 std::map<int, std::vector<std::pair<std::string, double>>> by_group;
100 for (auto c : composition) {
101 int group = elementGroup(c.first);
102 if (group == 0) throw plask::MaterialParseException("wrong element name \"{0}\"", c.first);
103 by_group[group].push_back(c);
104 }
105 for (auto g : by_group) {
106 fillGroupMaterialCompositionAmounts(g.second.begin(), g.second.end(), g.first);
107 if (g.second.begin() != g.second.end()) {
108 auto last = g.second.end() - 1;
109 for (auto el = g.second.begin(); el != last; ++el) result += format("{}({})", el->first, el->second);
110 result += last->first;
111 }
112 }
113 } else {
114 result = name;
115 }
116 if (label != "") result += "_" + label;
117 if (dopant != "") result += ":" + dopant + "=" + plask::str(doping);
118 return result;
119}
120
121 Material::Composition Material::Parameters::completeComposition() const { return Material::completeComposition(composition); }
122
123 void Material::Parameters::setDoping(const std::string& dopant, double doping) {
124 this->dopant = dopant;
125 this->doping = doping;
126}
127
128std::string Material::str() const { return name(); }
129
130 bool Material::isAlloy() const { return !isSimpleMaterialName(str()); }
131
132 Material::Composition Material::composition() const { return Composition(); }
133
134 double Material::doping() const { return 0; }
135
136 double Material::A(double /*T*/) const { throwNotImplemented("A(double T)"); }
137
138 double Material::absp(double /*lam*/, double /*T*/) const { return 0.; }
139
140 double Material::B(double /*T*/) const { throwNotImplemented("B(double T)"); }
141
142 double Material::C(double /*T*/) const { throwNotImplemented("C(double T)"); }
143
144 double Material::CB(double T, double e, char point) const {
145 if (e == 0.)
146 return VB(T, 0., point) + Eg(T, 0., point);
147 else
148 return max(VB(T, e, point, 'H'), VB(T, e, point, 'L')) + Eg(T, e, point);
149}
150
151 double Material::chi(double /*T*/, double /*e*/, char /*point*/) const {
152 throwNotImplemented("chi(double T, double e, char point)");
153}
154
155 Tensor2<double> Material::cond(double /*T*/) const { throwNotImplemented("cond(double T)"); }
156
157 Material::ConductivityType Material::condtype() const { return CONDUCTIVITY_UNDETERMINED; }
158
159 double Material::D(double T) const {
160 // Use Einstein relation here
161 double mu;
162 try {
163 mu = mob(T).c00;
164 } catch (plask::NotImplemented&) {
165 throwNotImplemented("D(double T)");
166 }
167 return mu * T * 8.6173423e-5; // D = µ kB T / e
168}
169
170 double Material::dens(double /*T*/) const { throwNotImplemented("dens(double T)"); }
171
172 double Material::Dso(double /*T*/, double /*e*/) const { throwNotImplemented("Dso(double T, double e)"); }
173
174 double Material::EactA(double /*T*/) const { throwNotImplemented("EactA(double T)"); }
175 double Material::EactD(double /*T*/) const { throwNotImplemented("EactD(double T)"); }
176
177 double Material::Eg(double /*T*/, double /*e*/, char /*point*/) const { throwNotImplemented("Eg(double T, double e, char point)"); }
178
179 double Material::eps(double /*T*/) const { throwNotImplemented("eps(double T)"); }
180
181 double Material::lattC(double /*T*/, char /*x*/) const { throwNotImplemented("lattC(double T, char x)"); }
182
183 Tensor2<double> Material::Me(double /*T*/, double /*e*/, char /*point*/) const {
184 throwNotImplemented("Me(double T, double e, char point)");
185}
186 Tensor2<double> Material::Mh(double /*T*/, double /*e*/) const { throwNotImplemented("Mh(double T, double e)"); }
187 Tensor2<double> Material::Mhh(double /*T*/, double /*e*/) const { throwNotImplemented("Mhh(double T, double e)"); }
188 Tensor2<double> Material::Mlh(double /*T*/, double /*e*/) const { throwNotImplemented("Mlh(double T, double e)"); }
189
190 double Material::y1() const { throwNotImplemented("y1()"); }
191 double Material::y2() const { throwNotImplemented("y2()"); }
192 double Material::y3() const { throwNotImplemented("y3()"); }
193
194 double Material::ac(double /*T*/) const { throwNotImplemented("ac(double T)"); }
195 double Material::av(double /*T*/) const { throwNotImplemented("av(double T)"); }
196 double Material::b(double /*T*/) const { throwNotImplemented("b(double T)"); }
197 double Material::d(double /*T*/) const { throwNotImplemented("d(double T)"); }
198 double Material::c11(double /*T*/) const { throwNotImplemented("c11(double T)"); }
199 double Material::c12(double /*T*/) const { throwNotImplemented("c12(double T)"); }
200 double Material::c44(double /*T*/) const { throwNotImplemented("c44(double T)"); }
201
202 Tensor2<double> Material::mob(double /*T*/) const { throwNotImplemented("mob(double T)"); }
203
204 double Material::Mso(double /*T*/, double /*e*/) const { throwNotImplemented("Mso(double T, double e)"); }
205
206 double Material::Nf(double /*T*/) const { throwNotImplemented("Nf(double T)"); }
207
208 double Material::Ni(double /*T*/) const { throwNotImplemented("Ni(double T)"); }
209
210 double Material::nr(double /*lam*/, double /*T*/, double /*n*/) const { throwNotImplemented("nr(double lam, double T, double n)"); }
211
212dcomplex Material::Nr(double lam, double T, double n) const {
213 return dcomplex(nr(lam, T, n), -7.95774715459e-09 * absp(lam, T) * lam);
214}
215
216 Tensor3<dcomplex> Material::Eps(double lam, double T, double n) const {
217 dcomplex nr = Nr(lam, T, n);
218 return nr * nr;
219}
220
221 bool Material::operator==(const Material& other) const { return typeid(*this) == typeid(other) && this->isEqual(other); }
222
223 double Material::cp(double /*T*/) const { throwNotImplemented("cp(double T)"); }
224
225 Tensor2<double> Material::thermk(double /*T*/, double /*h*/) const { throwNotImplemented("thermk(double T, double h)"); }
226
227 double Material::VB(double /*T*/, double /*e*/, char /*point*/, char /*hole*/) const {
228 throwNotImplemented("VB(double T, double e, char point, char hole)");
229}
230
231 Tensor2<double> Material::mobe(double /*T*/) const { throwNotImplemented("mobe(double T)"); }
232
233 Tensor2<double> Material::mobh(double /*T*/) const { throwNotImplemented("mobh(double T)"); }
234
235 double Material::taue(double /*T*/) const { throwNotImplemented("taue(double T)"); }
236
237 double Material::tauh(double /*T*/) const { throwNotImplemented("tauh(double T)"); }
238
239 double Material::Ce(double /*T*/) const { throwNotImplemented("Ce(double T)"); }
240
241 double Material::Ch(double /*T*/) const { throwNotImplemented("Ch(double T)"); }
242
243 double Material::e13(double /*T*/) const { throwNotImplemented("e13(double T)"); }
244
245 double Material::e15(double /*T*/) const { throwNotImplemented("e15(double T)"); }
246
247 double Material::e33(double /*T*/) const { throwNotImplemented("e33(double T)"); }
248
249 double Material::c13(double /*T*/) const { throwNotImplemented("c13(double T)"); }
250
251 double Material::c33(double /*T*/) const { throwNotImplemented("c33(double T)"); }
252
253 double Material::Psp(double /*T*/) const { throwNotImplemented("Psp(double T)"); }
254
255 double Material::Na() const { throwNotImplemented("Na()"); }
256
257 double Material::Nd() const { throwNotImplemented("Nd()"); }
258
259[[noreturn]] void Material::throwNotImplemented(const std::string& method_name) const {
260 throw MaterialMethodNotImplemented(name(), method_name);
261}
262
263 Material::Composition Material::completeComposition(const Composition& composition) {
264 std::map<int, std::vector<std::pair<std::string, double>>> by_group;
265 for (auto c : composition) {
266 int group = elementGroup(c.first);
267 if (group == 0) throw plask::MaterialParseException("wrong object name \"{0}\"", c.first);
268 by_group[group].push_back(c);
269 }
270 Material::Composition result;
271 for (auto g : by_group) {
272 fillGroupMaterialCompositionAmounts(g.second.begin(), g.second.end(), g.first);
273 result.insert(g.second.begin(), g.second.end());
274 }
275 return result;
276}
277
278 Material::Composition Material::minimalComposition(const Composition& composition) {
279 std::map<int, std::vector<std::pair<std::string, double>>> by_group;
280 for (auto c : composition) {
281 int group = elementGroup(c.first);
282 if (group == 0) throw plask::MaterialParseException("wrong object name \"{0}\"", c.first);
283 by_group[group].push_back(c);
284 }
285 Material::Composition result;
286 for (auto g : by_group) {
287 fillGroupMaterialCompositionAmounts(g.second.begin(), g.second.end(), g.first);
288 if (g.second.begin() != g.second.end()) (g.second.end() - 1)->second = NAN;
289 result.insert(g.second.begin(), g.second.end());
290 }
291 return result;
292}
293
294 const char* getObjectEnd(const char* begin, const char* end) {
295 if (!('A' <= *begin && *begin <= 'Z')) return begin;
296 do {
297 ++begin;
298 } while (begin != end && 'a' <= *begin && *begin <= 'z');
299 return begin;
300}
301
302 const char* getAmountEnd(const char* begin, const char* end) {
303 if (*begin != '(') return begin;
304 do {
305 ++begin;
306 } while (begin != end && *begin != ')');
307 return begin;
308}
309
310 double toDouble(const std::string& s, const char* fullname) {
311 try {
312 return boost::lexical_cast<double>(s);
313 } catch (std::exception&) {
314 throw MaterialParseException("cannot parse '{}' as number in '{}'", s, fullname);
315 }
316}
317
318std::pair<std::string, double> Material::firstCompositionObject(const char*& begin, const char* end, const char* fullname) {
319 std::pair<std::string, double> result;
320 const char* comp_end = getObjectEnd(begin, end);
321 if (comp_end == begin)
322 throw MaterialParseException("expected element but found character: '{0:c}' in '{1:s}'", *begin, fullname);
323 result.first = std::string(begin, comp_end);
324 const char* amount_end = getAmountEnd(comp_end, end);
325 if (amount_end == comp_end) { // no amount info for this object
326 result.second = std::numeric_limits<double>::quiet_NaN();
327 begin = amount_end;
328 } else {
329 if (amount_end == end)
330 throw MaterialParseException("unexpected end of input while reading element amount. Couldn't find ')' in '{}'",
331 fullname);
332 result.second = toDouble(std::string(comp_end + 1, amount_end), fullname);
333 begin = amount_end + 1; // skip also ')', begin now points to 1 character after ')'
334 }
335 return result;
336}
337
338 Material::Composition Material::parseComposition(const char* begin, const char* end, const char* fullname) {
339 if (fullname == nullptr) fullname = begin; // for exceptions only
340 Material::Composition result;
341 std::set<int> groups;
342 int prev_g = -1;
343 while (begin != end) {
344 auto c = firstCompositionObject(begin, end, fullname);
345 int g = elementGroup(c.first);
346 if (g != prev_g) {
347 if (!groups.insert(g).second) throw MaterialParseException("incorrect elements order in '{}'", fullname);
348 prev_g = g;
349 }
350 result.insert(c);
351 }
352 return result;
353}
354
355 Material::Composition Material::parseComposition(const std::string& str, const std::string& fullname) {
356 const char* c = str.data();
357 if (fullname.empty())
358 return parseComposition(c, c + str.size(), c);
359 else
360 return parseComposition(c, c + str.size(), fullname.c_str());
361}
362
363 void Material::parseDopant(const char* begin,
364 const char* end,
365 std::string& dopant_elem_name,
366 double& doping,
367 bool allow_dopant_without_amount,
368 const char* fullname) {
369 const char* name_end = getObjectEnd(begin, end);
370 if (name_end == begin) throw MaterialParseException("no dopant name in '{}'", fullname);
371 dopant_elem_name.assign(begin, name_end);
372 if (name_end == end) {
373 if (!allow_dopant_without_amount)
374 throw MaterialParseException("unexpected end of input while reading doping concentration in '{}'", fullname);
375 // there might be some reason to specify material with dopant but undoped (can be caught in material constructor)
376 doping = NAN;
377 return;
378 }
379 if (*name_end == '=') {
380 if (name_end + 1 == end)
381 throw MaterialParseException("unexpected end of input while reading doping concentration in '{}'", fullname);
382 doping = toDouble(std::string(name_end + 1, end), fullname);
383 return;
384 }
385 throw MaterialParseException("expected '=' but found '{}' instead in '{}'", *name_end, fullname);
386}
387
388 void Material::parseDopant(const std::string& dopant,
389 std::string& dopant_elem_name,
390 double& doping,
391 bool allow_dopant_without_amount,
392 const std::string& fullname) {
393 const char* c = dopant.data();
394 parseDopant(c, c + dopant.size(), dopant_elem_name, doping, allow_dopant_without_amount, fullname.c_str());
395}
396
397std::vector<std::string> Material::parseObjectsNames(const char* begin, const char* end) {
398 const char* full_name = begin; // store for error msg. only
399 std::vector<std::string> elemenNames;
400 do {
401 const char* new_begin = getObjectEnd(begin, end);
402 if (new_begin == begin) throw MaterialParseException("ill-formatted name \"{0}\"", std::string(full_name, end));
403 elemenNames.push_back(std::string(begin, new_begin));
404 begin = new_begin;
405 } while (begin != end);
406 return elemenNames;
407}
408
409std::vector<std::string> Material::parseObjectsNames(const std::string& allNames) {
410 const char* c = allNames.c_str();
411 return parseObjectsNames(c, c + allNames.size());
412}
413
414std::string Material::dopant() const {
415 std::string::size_type p = this->name().rfind(':');
416 return p == std::string::npos ? "" : this->name().substr(p + 1);
417}
418
419std::string Material::nameWithoutDopant() const { return this->name().substr(0, this->name().rfind(':')); }
420
421//------------ Different material kinds -------------------------
422
423std::string Semiconductor::name() const { return NAME; }
424 Material::Kind Semiconductor::kind() const { return Material::SEMICONDUCTOR; }
425 static MaterialsDB::Register<Semiconductor> materialDB_register_Semiconductor;
426
427std::string Metal::name() const { return NAME; }
428 Material::Kind Metal::kind() const { return Material::METAL; }
429 static MaterialsDB::Register<Metal> materialDB_register_Metal;
430
431std::string Oxide::name() const { return NAME; }
432 Material::Kind Oxide::kind() const { return Material::OXIDE; }
433 static MaterialsDB::Register<Metal> materialDB_register_Oxide;
434
435std::string Dielectric::name() const { return NAME; }
436 Material::Kind Dielectric::kind() const { return Material::DIELECTRIC; }
437 static MaterialsDB::Register<Dielectric> materialDB_register_Dielectric;
438
439std::string LiquidCrystal::name() const { return NAME; }
440 Material::Kind LiquidCrystal::kind() const { return Material::LIQUID_CRYSTAL; }
441 static MaterialsDB::Register<LiquidCrystal> materialDB_register_LiquidCrystal;
442
443//------------ Metals -------------------------
444
445 double Metal::eps(double /*T*/) const { return 1.; }
446
447// -------------- Material with base ---------------------
448
449 Material::Kind MaterialWithBase::kind() const { return base->kind(); }
450
451 double MaterialWithBase::lattC(double T, char x) const { return base->lattC(T, x); }
452 double MaterialWithBase::Eg(double T, double e, char point) const { return base->Eg(T, e, point); }
453 double MaterialWithBase::CB(double T, double e, char point) const { return base->CB(T, e, point); }
454 double MaterialWithBase::VB(double T, double e, char point, char hole) const { return base->VB(T, e, point, 'H'); }
455 double MaterialWithBase::Dso(double T, double e) const { return base->Dso(T, e); }
456 double MaterialWithBase::Mso(double T, double e) const { return base->Mso(T, e); }
457 Tensor2<double> MaterialWithBase::Me(double T, double e, char point) const { return base->Me(T, e, point); }
458 Tensor2<double> MaterialWithBase::Mhh(double T, double e) const { return base->Mhh(T, e); }
459 Tensor2<double> MaterialWithBase::Mlh(double T, double e) const { return base->Mlh(T, e); }
460 Tensor2<double> MaterialWithBase::Mh(double T, double e) const { return base->Mh(T, e); }
461 double MaterialWithBase::ac(double T) const { return base->ac(T); }
462 double MaterialWithBase::av(double T) const { return base->av(T); }
463 double MaterialWithBase::b(double T) const { return base->b(T); }
464 double MaterialWithBase::d(double T) const { return base->d(T); }
465 double MaterialWithBase::c11(double T) const { return base->c11(T); }
466 double MaterialWithBase::c12(double T) const { return base->c12(T); }
467 double MaterialWithBase::c44(double T) const { return base->c44(T); }
468 double MaterialWithBase::eps(double T) const { return base->eps(T); }
469 double MaterialWithBase::chi(double T, double e, char point) const { return base->chi(T, e, point); }
470 double MaterialWithBase::Na() const { return base->Na(); }
471 double MaterialWithBase::Nd() const { return base->Nd(); }
472 double MaterialWithBase::Ni(double T) const { return base->Ni(T); }
473 double MaterialWithBase::Nf(double T) const { return base->Nf(T); }
474 double MaterialWithBase::EactD(double T) const { return base->EactD(T); }
475 double MaterialWithBase::EactA(double T) const { return base->EactA(T); }
476 Tensor2<double> MaterialWithBase::mob(double T) const { return base->mob(T); }
477 Tensor2<double> MaterialWithBase::cond(double T) const { return base->cond(T); }
478 double MaterialWithBase::A(double T) const { return base->A(T); }
479 double MaterialWithBase::B(double T) const { return base->B(T); }
480 double MaterialWithBase::C(double T) const { return base->C(T); }
481 double MaterialWithBase::D(double T) const {
482 try {
483 return mob(T).c00 * T * 8.6173423e-5;
484 } catch (NotImplemented&) {
485 return base->D(T);
486 }
487}
488 Tensor2<double> MaterialWithBase::thermk(double T, double t) const { return base->thermk(T, t); }
489 double MaterialWithBase::dens(double T) const { return base->dens(T); }
490 double MaterialWithBase::cp(double T) const { return base->cp(T); }
491 double MaterialWithBase::nr(double lam, double T, double n) const { return base->nr(lam, T, n); }
492 double MaterialWithBase::absp(double lam, double T) const { return base->absp(lam, T); }
493dcomplex MaterialWithBase::Nr(double lam, double T, double n) const {
494 try {
495 return nr(lam, T, n) - 7.95774715459e-09 * absp(lam, T) * lam;
496 } catch (NotImplemented&) {
497 return base->Nr(lam, T, n);
498 }
499}
500 Tensor3<dcomplex> MaterialWithBase::Eps(double lam, double T, double n) const {
501 try {
502 dcomplex nr = Nr(lam, T, n);
503 return Tensor3<dcomplex>(nr * nr);
504 } catch (NotImplemented&) {
505 return base->Eps(lam, T, n);
506 }
507}
508 Tensor2<double> MaterialWithBase::mobe(double T) const { return base->mobe(T); }
509 Tensor2<double> MaterialWithBase::mobh(double T) const { return base->mobh(T); }
510 double MaterialWithBase::taue(double T) const { return base->taue(T); }
511 double MaterialWithBase::tauh(double T) const { return base->tauh(T); }
512 double MaterialWithBase::Ce(double T) const { return base->Ce(T); }
513 double MaterialWithBase::Ch(double T) const { return base->Ch(T); }
514 double MaterialWithBase::e13(double T) const { return base->e13(T); }
515 double MaterialWithBase::e15(double T) const { return base->e15(T); }
516 double MaterialWithBase::e33(double T) const { return base->e33(T); }
517 double MaterialWithBase::c13(double T) const { return base->c13(T); }
518 double MaterialWithBase::c33(double T) const { return base->c33(T); }
519 double MaterialWithBase::Psp(double T) const { return base->Psp(T); }
520 double MaterialWithBase::y1() const { return base->y1(); }
521 double MaterialWithBase::y2() const { return base->y2(); }
522 double MaterialWithBase::y3() const { return base->y3(); }
523
524} // namespace plask