PLaSK library

Loading...
Searching...
No Matches
db.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 "db.hpp"
15#include "mixed.hpp"
16#include "const_material.hpp"
17
18#include "../utils/string.hpp"
19#include "../utils/dynlib/manager.hpp"
20#include "../log/log.hpp"
21
22#include <boost/filesystem.hpp>
23
24 namespace plask {
25
26 void checkCompositionSimilarity(const Material::Composition& material1composition, const Material::Composition& material2composition) {
27 for (auto& p1: material1composition) {
28 auto p2 = material2composition.find(p1.first);
29 if (p2 == material2composition.end())
30 throw MaterialParseException("materials compositions are different: {0} if missing from one of the materials", p1.first);
31 if (std::isnan(p1.second) != std::isnan(p2->second))
32 throw MaterialParseException("amounts must be defined for the same elements, which is not true in case of '{0}' element", p1.first);
33 }
34}
35
36/*const MaterialsDB *MaterialsDB::getFromSource(const MaterialsDB &materialsDB) {
37 const MaterialsDB::Source* src = materialsDB.target<const MaterialsDB::Source>();
38 return src ? &src->materialsDB : nullptr;
39}*/
40
41 MaterialsDB::MixedCompositionOnlyFactory::MixedCompositionOnlyFactory(shared_ptr<const MaterialConstructor> constructor, const Material::Composition& material1composition, const Material::Composition& material2composition, double shape)
42 : MaterialsDB::MixedCompositionFactory::MixedCompositionFactory(constructor), material1composition(material1composition), material2composition(material2composition), shape(shape) {
43 //check if compositions are fine and similar:
44 checkCompositionSimilarity(material1composition, material2composition);
45 checkCompositionSimilarity(material2composition, material1composition);
46 Material::completeComposition(material1composition);
47 Material::completeComposition(material2composition);
48}
49
50 Material::Composition plask::MaterialsDB::MixedCompositionOnlyFactory::mixedComposition(double m1_weight) const {
51 Material::Composition result = material1composition;
52 for (auto& p1: result) {
53 if (!std::isnan(p1.second)) {
54 auto p2 = material2composition.find(p1.first);
55 p1.second = p1.second * pow(m1_weight, shape) + p2->second * (1.0 - pow(m1_weight, shape));
56 }
57 }
58 return result;
59}
60
61// if part_value is not empty append separator and part_value to name
62std::string& appendPart(std::string& name, const std::string& part_value, char separator) {
63 if (!part_value.empty()) {
64 name += separator;
65 name += part_value;
66 }
67 return name;
68}
69
70// Append to name dopant, if it is not empty, return name
71std::string& appendDopant(std::string& name, const std::string& dopant_name) {
72 return appendPart(name, dopant_name, ':');
73}
74
75std::string& appendLabel(std::string& name, const std::string& label) {
76 return appendPart(name, label, '_');
77}
78
79std::string& appendLabelDopant(std::string& name, const std::string& label, const std::string& dopant_name) {
80 return appendDopant(appendLabel(name, label), dopant_name);
81}
82
83std::string alloyDbKey(const Material::Composition &composition, const std::string& label, const std::string& dopant_name) {
84 std::string db_key;
85 for (auto c: composition) db_key += c.first;
86 return appendLabelDopant(db_key, label, dopant_name);
87}
88
89std::string alloyDbKey(std::vector<std::string> elNames, const std::string& label, const std::string& dopant_name) {
90 std::string db_key;
91 std::sort(elNames.begin(), elNames.end());
92 for (std::string& c: elNames) db_key += c;
93 return appendLabelDopant(db_key, label, dopant_name);
94}
95
96std::string alloyDbKey(const std::string& name, const std::string& label, const std::string& dopant_name) {
97 return alloyDbKey(Material::parseObjectsNames(name), label, dopant_name);
98}
99
100std::string alloyDbKey(const std::string& fullAlloyName) {
101 auto fullname_dopant = splitString2(fullAlloyName, ':');
102 auto name_label = splitString2(fullname_dopant.first, '_');
103 return alloyDbKey(name_label.first, name_label.second, fullname_dopant.second);
104}
105
106std::string dbKey(const Material::Parameters& parameters) {
107 std::string res;
108 if (!parameters.isAlloy())
109 res = parameters.name;
110 else
111 for (auto c: parameters.composition) res += c.first;
112 return appendLabelDopant(res, parameters.label, parameters.dopant);
113}
114
115
116 MaterialsDB& MaterialsDB::getDefault() {
117 static MaterialsDB defaultDb;
118 return defaultDb;
119}
120
121 static void loadLibrary(const std::string& file_name) {
122 static std::map<void*, MaterialsDB> libraryCache;
123 void* key;
124 {
125 MaterialsDB::TemporaryClearDefault temporary;
126 key = DynamicLibraries::defaultLoad(file_name, DynamicLibrary::DONT_CLOSE).getHandle();
127 if (libraryCache.find(key) == libraryCache.end()) libraryCache[key] = MaterialsDB::getDefault();
128 }
129 MaterialsDB::getDefault().update(libraryCache[key]);
130}
131
132 void MaterialsDB::loadToDefault(const std::string &fileName_mainpart) {
133 loadLibrary(boost::filesystem::absolute(fileName_mainpart + DynamicLibrary::DEFAULT_EXTENSION, boost::filesystem::current_path()).string<std::string>());
134}
135
136 void MaterialsDB::loadAllToDefault(const std::string& dir) {
137 if (boost::filesystem::exists(dir) && boost::filesystem::is_directory(dir)) {
138 boost::filesystem::directory_iterator iter(dir);
139 boost::filesystem::directory_iterator end;
140 while (iter != end) {
141 boost::filesystem::path p = iter->path();
142 if (boost::filesystem::is_regular_file(p) && p.extension() == DynamicLibrary::DEFAULT_EXTENSION)
143 loadLibrary(p.string());
144 ++iter;
145 }
146 } else {
147 writelog(LOG_WARNING, "MaterialsDB: '{0}' does not exist or is not a directory. Cannot load default materials", dir);
148 }
149}
150
151 void MaterialsDB::ensureCompositionIsNotEmpty(const Material::Composition &composition) {
152 if (composition.empty()) throw MaterialParseException("unknown material composition");
153}
154
155 MaterialsDB::ProxyMaterialConstructor::ProxyMaterialConstructor():
156 MaterialsDB::MaterialConstructor(""), material(new GenericMaterial)
157{}
158
159 MaterialsDB::ProxyMaterialConstructor::ProxyMaterialConstructor(const std::string& name, const MaterialsDB& db):
160 MaterialsDB::MaterialConstructor(name)
161{
162 if (name.empty()) {
163 material = plask::make_shared<GenericMaterial>();
164 } else {
165 try {
166 material = db.get(name);
167 } catch (plask::MaterialParseException&) {
168 Material::Parameters p(name, true);
169 constructor = db.getConstructor(p, true);
170 composition = p.composition;
171 doping = p.doping;
172 }
173 }
174 assert(material || constructor);
175}
176
177 MaterialsDB::ProxyMaterialConstructor::ProxyMaterialConstructor(const shared_ptr<Material>& material):
178 MaterialsDB::MaterialConstructor(material->name()), material(material)
179{}
180
181 shared_ptr<Material> MaterialsDB::ProxyMaterialConstructor::operator()(const Material::Composition& comp, double dop) const {
182 if (material) {
183 return material;
184 }
185 if (!isnan(doping)) dop = doping;
186 if (composition.empty()) {
187 return (*constructor)(comp, dop);
188 } else {
189 return (*constructor)(composition, dop);
190 }
191}
192
193 bool MaterialsDB::ProxyMaterialConstructor::isAlloy() const {
194 if (material || !composition.empty() || !constructor) return false;
195 return constructor->isAlloy();
196}
197
198
199 shared_ptr<const MaterialsDB::MaterialConstructor> MaterialsDB::getConstructor(const std::string& db_Key, const Material::Composition& composition, bool allow_alloy_without_composition) const {
200 auto it = constructors.find(db_Key);
201 if (it == constructors.end()) {
202 if (composition.empty()) {
203 // check if material is alloy, but user forgot to provide composition:
204 std::string alloy_DbKey;
205 try { alloy_DbKey = alloyDbKey(db_Key); } catch (std::exception&) {}
206 auto c = constructors.find(alloy_DbKey);
207 if (c != constructors.end()) { //material is alloy
208 if (allow_alloy_without_composition)
209 return c->second;
210 else
211 throw MaterialParseException(format("material composition required for {0}", db_Key));
212 } else
213 throw NoSuchMaterial(db_Key);
214 }
215 // throw NoSuchMaterial(composition, dopant_name);
216 throw NoSuchMaterial(db_Key + " (alloy)");
217 }
218 return it->second;
219}
220
221 shared_ptr<Material> MaterialsDB::get(const std::string& db_Key, const Material::Composition& composition, double doping) const {
222 return (*getConstructor(db_Key, composition))(composition, doping);
223}
224
225 shared_ptr<const MaterialsDB::MaterialConstructor> MaterialsDB::getConstructor(const Material::Composition& composition, const std::string& label, const std::string& dopant_name) const {
226 return getConstructor(alloyDbKey(composition, label, dopant_name), composition);
227}
228
229 shared_ptr<const MaterialsDB::MaterialConstructor> MaterialsDB::getConstructor(const Material::Parameters &material, bool allow_alloy_without_composition) const
230{
231 return getConstructor(dbKey(material), material.composition, allow_alloy_without_composition);
232}
233
234 shared_ptr<Material> MaterialsDB::get(const Material::Composition &composition, const std::string& label, const std::string& dopant_name, double doping) const {
235 return get(alloyDbKey(composition, label, dopant_name), composition, doping);
236}
237
238/*shared_ptr<Material> MaterialsDB::get(const std::string& parsed_name_with_dopant, const std::vector<double>& composition, double doping) const {
239 std::string name, dopant;
240 std::tie(name, dopant) = splitString2(parsed_name_with_dopant, ':');
241 if (composition.empty())
242 return get(parsed_name_with_dopant, Material::Composition(), dopant, doping);
243 std::vector<std::string> objects = Material::parseObjectsNames(name);
244 if (composition.size() > objects.size())
245 throw plask::Exception("too long material composition vector (longer than number of objects in '{0}')", parsed_name_with_dopant);
246 Material::Composition comp;
247 for (std::size_t i = 0; i < composition.size(); ++i) comp[objects[i]] = composition[i];
248 for (std::size_t i = composition.size(); i < objects.size(); ++i) comp[objects[i]] = std::numeric_limits<double>::quiet_NaN();
249 return get(Material::completeComposition(comp), dopant, doping);
250}*/
251
252 shared_ptr<Material> MaterialsDB::get(const std::string& name_with_dopant, double doping) const {
253 Material::Parameters p(name_with_dopant, true);
254 if (p.hasDopantName()) {
255 p.doping = doping;
256 }
257 return get(p);
258}
259
260 shared_ptr<const MaterialsDB::MaterialConstructor> MaterialsDB::getConstructor(const std::string& name_without_composition) const {
261 auto it = constructors.find(name_without_composition); // try get as simple
262 if (it != constructors.end()) return it->second;
263 it = constructors.find(alloyDbKey(name_without_composition)); // try get as alloy
264 if (it != constructors.end()) return it->second;
265 throw NoSuchMaterial(name_without_composition);
266}
267
268 shared_ptr<Material> MaterialsDB::get(const Material::Parameters &m) const {
269 return (*getConstructor(m))(m.composition, m.doping);
270}
271
272 shared_ptr< Material > MaterialsDB::get(const std::string& full_name) const {
273 if (full_name.size() != 0 && full_name.find('[') != std::string::npos && full_name[full_name.size()-1] == ']')
274 return plask::make_shared<ConstMaterial>(full_name);
275 else
276 return get(Material::Parameters(full_name));
277}
278
279 shared_ptr<MaterialsDB::MixedCompositionFactory> MaterialsDB::getFactory(const std::string& material1_fullname, const std::string& material2_fullname, double shape) const {
280 Material::Parameters m1(material1_fullname), m2(material2_fullname);
281 if (m1.dopant != m2.dopant)
282 throw MaterialParseException("cannot mix materials with different doping: '{0}' and '{1}'", material1_fullname, material2_fullname);
283 if ((m1.label != m2.label) || (m1.isAlloy() != m2.isAlloy()))
284 throw MaterialParseException("cannot mix different materials: '{0}' and '{1}'", material1_fullname, material2_fullname);
285
286 if (!m1.isAlloy()) { // simple material, without parsing composition, still dopants can be mixed
287 if (m1.name != m2.name)
288 throw MaterialParseException("cannot mix different materials: '{0}' and '{1}'", material1_fullname, material2_fullname);
289
290 if (!m1.hasDoping()) //??
291 throw MaterialParseException("{0}: only alloy or doped materials with different doping concentrations can be mixed", material1_fullname);
292
293 return shared_ptr<MaterialsDB::MixedCompositionFactory>(
294 new MixedDopantFactory(getConstructor(m1), m1.doping, m2.doping, shape)
295 );
296 }
297
298 //alloy materials:
299 if (m1.hasDoping()) //both dopped
300 return shared_ptr<MaterialsDB::MixedCompositionFactory>(
301 new MixedCompositionAndDopantFactory(getConstructor(m1),
302 m1.composition, m2.composition,
303 m1.doping, m2.doping, shape)
304 );
305
306 //both undopped
307 return shared_ptr<MaterialsDB::MixedCompositionFactory>(
308 new MixedCompositionOnlyFactory(getConstructor(m1), m1.composition, m2.composition, shape)
309 );
310}
311
312/*void MaterialsDB::addSimple(const MaterialConstructor* constructor) {
313 constructors[constructor->materialName] = shared_ptr<const MaterialConstructor>(constructor);
314}*/
315
316 void MaterialsDB::addSimple(shared_ptr<MaterialConstructor> constructor) {
317 constructors[constructor->materialName] = constructor;
318}
319
320/*void MaterialsDB::addAlloy(const MaterialConstructor* constructor) {
321 constructors[dbKey(constructor->materialName)] = shared_ptr<const MaterialConstructor>(constructor);
322}*/
323
324 void MaterialsDB::addAlloy(shared_ptr<MaterialConstructor> constructor) {
325 constructors[alloyDbKey(constructor->materialName)] = constructor;
326}
327
328 void MaterialsDB::remove(const std::string& name) {
329 auto it = constructors.find(name); // try get as simple
330 if (it != constructors.end()) {
331 constructors.erase(it);
332 return;
333 }
334 it = constructors.find(alloyDbKey(name)); // try get as alloy
335 if (it != constructors.end()) {
336 constructors.erase(it);
337 return;
338 }
339 throw NoSuchMaterial(name);
340}
341
342
343 bool MaterialsDB::isAlloy(const std::string &material_name) const { return getConstructor(material_name)->isAlloy(); }
344
345} // namespace plask