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