PLaSK library
Loading...
Searching...
No Matches
manager.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 <fstream>
15#include <boost/algorithm/string.hpp>
16
17#include "manager.hpp"
18
19#include "utils/stl.hpp"
20#include "geometry/reader.hpp"
21#include "filters/factory.hpp"
22
24
25#include "utils/system.hpp"
26
27namespace plask {
28
29Manager::SetAxisNames::SetAxisNames(GeometryReader& reader): SetAxisNames(reader.manager, reader.source) {}
30
31void Manager::ExternalSourcesFromFile::operator()(Manager &manager, const std::string &url, const std::string &section) {
32 boost::filesystem::path url_path(url);
33 if (url_path.is_relative()) {
34 if (originalFileName.empty())
35 throw Exception("error while reading section \"{0}\": relative path name \"{1}\" is not supported.", section, url);
36 url_path = originalFileName;
37 url_path.remove_filename();
38 url_path /= url;
39 }
40 if (hasCircularRef(url_path, section))
41 throw Exception("error while reading section \"{0}\": circular reference was detected.", section);
42 XMLReader reader(url_path.string().c_str());
44}
45
47 : manager(manager), old(manager.axisNames) {
48 manager.axisNames = names;
49}
50
52 : manager(manager), old(manager.axisNames) {
54 if (axis) manager.axisNames = &AxisNames::axisNamesRegister.get(*axis);
55}
56
57bool Manager::tryLoadFromExternal(XMLReader& reader, const Manager::LoadFunCallbackT& load_from) {
59 if (!from_attr) return false;
60 load_from(*this, *from_attr, reader.getNodeName());
61 return true;
62
63 /*std::string section_to_load = reader.getNodeName();
64 std::pair< XMLReader, std::unique_ptr<LoadFunCallbackT> > new_loader = load_from.get(*from_attr);
65 load(new_loader.first, materialsDB, *new_loader.second, [&](const std::string& section_name) -> bool { return section_name == section_to_load; });
66 return true;*/
67}
68
71 if (result_it == pathHints.end()) return nullptr;
72 return &result_it->second;
73}
74
75const PathHints *Manager::getPathHints(const std::string &path_hints_name) const {
77 if (result_it == pathHints.end()) return nullptr;
78 return &result_it->second;
79}
80
83 if (result_it == pathHints.end()) throw NoSuchPath(path_hints_name);
84 return result_it->second;
85}
86
87const PathHints& Manager::requirePathHints(const std::string& path_hints_name) const {
89 if (result_it == pathHints.end()) throw NoSuchPath(path_hints_name);
90 return result_it->second;
91}
92
94 auto result_it = geometrics.find(name);
95 if (result_it == geometrics.end()) return shared_ptr<GeometryObject>();
96 // auto result = result_it->second.lock();
97 // if (!result) const_cast<Manager*>(this)->geometrics.erase(name);
98 // return result;
99 return result_it->second;
100 /*auto result_it = geometrics.find(name);
101 return result_it != geometrics.end() ? result_it->second.lock() : shared_ptr<GeometryObject>();*/
102}
103
109
110shared_ptr<Geometry> Manager::getGeometry(const std::string& name) const {
111 auto result_it = geometrics.find(name);
113}
114
115shared_ptr<MeshBase> Manager::getMesh(const std::string& name) const {
116 auto result_it = meshes.find(name);
117 return result_it == meshes.end() ? shared_ptr<Mesh>() : result_it->second;
118}
119
121 writelog(LOG_ERROR, "Loading defines from C++ not implemented. Ignoring XML section <defines>.");
122 reader.gotoEndOfCurrentTag();
123}
124
125void Manager::loadFromReader(XMLReader &reader, const LoadFunCallbackT& load_from_cb) {
126 load(reader, load_from_cb);
127}
128
129void Manager::loadFromStream(std::unique_ptr<std::istream>&& input, const LoadFunCallbackT& load_from_cb) {
130 XMLReader reader(std::move(input));
132}
133
134void Manager::loadFromXMLString(const std::string &input_XML_str, const LoadFunCallbackT& load_from_cb) {
135 loadFromStream(std::unique_ptr<std::istream>(new std::istringstream(input_XML_str)), load_from_cb);
136}
137
138void Manager::loadFromFile(const std::string &fileName) {
139 XMLReader reader(fileName.c_str());
141}
142
143void Manager::loadFromFILE(FILE* file, const LoadFunCallbackT& load_from_cb) {
144 XMLReader reader(file);
146}
147
148
150 if (greader.source.getNodeType() != XMLReader::NODE_ELEMENT || greader.source.getNodeName() != std::string("geometry"))
151 throw XMLUnexpectedElementException(greader.source, "<geometry>");
153 while(greader.source.requireTagOrEnd())
154 roots.push_back(greader.readGeometry());
155}
156
157
159 std::string name = reader.requireAttribute("name");
160 try {
161 if (name != "") MaterialsDB::loadToDefault(name);
162 } catch (Exception& err) {
163 throwErrorIfNotDraft(XMLException(reader, err.what()));
164 }
165 reader.requireTagEnd();
166}
167
168
170{
171 writelog(LOG_ERROR, "Loading XML material from C++ not implemented (ignoring material {})", reader.getAttribute<std::string>("name", "unknown"));
172 reader.gotoEndOfCurrentTag();
173}
174
176{
177 while (reader.requireTagOrEnd()) {
178 if (reader.getNodeName() == "material")
179 loadMaterial(reader);
180 else if (reader.getNodeName() == "library")
181 loadMaterialLib(reader);
182 else
183 throw XMLUnexpectedElementException(reader, "<material>");
184 }
185}
186
188{
189 if (reader.getNodeType() != XMLReader::NODE_ELEMENT || reader.getNodeName() != std::string("grids"))
190 throw XMLUnexpectedElementException(reader, "<grids>");
191 while(reader.requireTagOrEnd()) {
192 if (reader.getNodeName() == "mesh") {
193 std::string type = reader.requireAttribute("type");
194 std::string name = reader.requireAttribute("name");
195 std::replace(name.begin(), name.end(), '-', '_');
196 BadId::throwIfBad("mesh", name);
197 if (meshes.find(name) != meshes.end())
198 throw NamesConflictException("mesh or mesh generator", name);
200 if (reader.getNodeType() != XMLReader::NODE_ELEMENT_END || reader.getNodeName() != "mesh")
201 throw Exception("internal error in {0} mesh reader, after return reader does not point to end of mesh tag.", type);
202 meshes[name] = mesh;
203 } else if (reader.getNodeName() == "generator") {
204 std::string type = reader.requireAttribute("type");
205 std::string method = reader.requireAttribute("method");
206 std::string name = reader.requireAttribute("name");
207 std::replace(name.begin(), name.end(), '-', '_');
208 BadId::throwIfBad("generator", name);
209 std::string key = type + "." + method;
210 if (meshes.find(name) != meshes.end())
211 throw NamesConflictException("mesh or mesh generator", name);
213 if (reader.getNodeType() != XMLReader::NODE_ELEMENT_END || reader.getNodeName() != "generator")
214 throw Exception("internal error in {0} (method: {1}) mesh generator reader, after return reader does not point to end of generator tag.", type, method);
215 meshes[name] = generator;
216 } else
217 throw XMLUnexpectedElementException(reader, "<mesh...>, <generator...>, or </grids>");
218 }
219}
220
221shared_ptr<Solver> Manager::loadSolver(const std::string &, const std::string &, const std::string &, const std::string& name) {
222 auto found = solvers.find(name);
223 if (found == solvers.end())
224 throw Exception("in C++ solvers ('{0}' in this case) must be created and added to Manager::solvers manually before reading XML.", name);
225 solvers.erase(found); // this is necessary so we don't have name conflicts — the solver will be added back to the map by loadSolvers
226 return found->second;
227}
228
230 if (reader.getNodeType() != XMLReader::NODE_ELEMENT || reader.getNodeName() != std::string("solvers"))
231 throw XMLUnexpectedElementException(reader, "<solvers>");
232 while (reader.requireTagOrEnd()) {
233 std::string name = reader.requireAttribute("name");
234 std::replace(name.begin(), name.end(), '-', '_');
235 BadId::throwIfBad("solver", name);
236 if (shared_ptr<Solver> filter = FiltersFactory::getDefault().get(reader, *this)) {
237 if (!this->solvers.insert(std::make_pair(name, filter)).second)
238 throw NamesConflictException("solver", name);
239 continue;
240 }
242 const std::string solver_name = reader.requireAttribute("solver");
243 std::string category = reader.getNodeName();
244 if (!lib) {
245 if (category != "local") {
246 auto libs = global_solver_names[category];
247 if (libs.empty()) { // read lib index from file
248 boost::filesystem::directory_iterator iter(plaskSolversPath(category));
249 boost::filesystem::directory_iterator end;
250 while (iter != end) {
251 boost::filesystem::path p = iter->path();
252 std::string current_solver;
253 if (boost::filesystem::is_regular_file(p) && p.extension().string() == ".yml") {
254 // Look for lib in yaml file
255 std::ifstream yaml(p.string());
256 std::string line;
257 while (std::getline(yaml, line)) {
258 if (line.substr(0, 9) == "- solver:") {
259 current_solver = line.substr(9);
260 boost::trim(current_solver);
261 }
262 else if (current_solver != "" && line.substr(0, 6) == " lib:") {
263 std::string lib = line.substr(6);
264 boost::trim(lib);
266 }
267 }
268 }
269 ++iter;
270 }
271 }
272 lib.reset(libs[solver_name]);
273 }
274 }
275 if (!lib || lib->empty())
276 throw XMLException(reader, format("cannot determine library for {0}.{1} solver", category, solver_name));
277 shared_ptr<Solver> solver = loadSolver(category, *lib, solver_name, name);
278 solver->loadConfiguration(reader, *this);
279 if (!this->solvers.insert(std::make_pair(name, solver)).second)
280 throw NamesConflictException("solver", name);
281 }
282 assert(reader.getNodeName() == "solvers");
283}
284
286{
287 writelog(LOG_ERROR, "Loading interconnects only possible from Python interface. Ignoring XML section <connects>.");
288 reader.gotoEndOfCurrentTag();
289}
290
292{
293 if (reader.getNodeType() != XMLReader::NODE_ELEMENT || reader.getNodeName() != "script")
294 throw XMLUnexpectedElementException(reader, "<script>");
295 scriptline = reader.getLineNr();
296 std::string scr = reader.requireTextInCurrentTag();
297 size_t start;
298 for (start = 0; scr[start] != '\n' && start < scr.length(); ++start) {
299 if (!std::isspace(scr[start]))
300 throw XMLException(format("XML line {}", scriptline), "script must begin from new line after <script>", scriptline);
301 }
302 if (start != scr.length()) script = scr.substr(start+1);
303}
304
305
306/*static inline MaterialsDB& getMaterialsDBfromSource(const Manager::MaterialsDB& materialsDB) {
307 const GeometryReader::MaterialsDBSource* src = materialsDB.target<const GeometryReader::MaterialsDBSource>();
308 return src ? const_cast<MaterialsDB&>(src->materialsDB) : MaterialsDB::getDefault();
309}*/
310
312 const LoadFunCallbackT& load_from,
313 const std::function<bool(const std::string& section_name)>& section_filter)
314{
315 errors.clear();
316 try {
318 reader.removeAlienNamespaceAttr(); // remove possible schema declaration
319 auto logattr = reader.getAttribute("loglevel");
320 if (logattr && !forcedLoglevel) {
321 try {
322 maxLoglevel = LogLevel(boost::lexical_cast<unsigned>(*logattr));
323 } catch (boost::bad_lexical_cast&) {
324 maxLoglevel = reader.enumAttribute<LogLevel>("loglevel")
325 .value("critical-error", LOG_CRITICAL_ERROR)
326 .value("critical", LOG_CRITICAL_ERROR)
327 .value("error", LOG_ERROR)
328 .value("error-detail", LOG_ERROR_DETAIL)
329 .value("warning", LOG_WARNING)
330 .value("important", LOG_IMPORTANT)
331 .value("info", LOG_INFO)
332 .value("result", LOG_RESULT)
333 .value("data", LOG_DATA)
334 .value("detail", LOG_DETAIL)
335 .value("debug", LOG_DEBUG)
336 .get(maxLoglevel);
337 }
338 }
339
340 size_t next = 0;
341
342 if (!reader.requireTagOrEnd()) return;
343
344 if (reader.getNodeName() == TAG_NAME_DEFINES) {
345 next = 1;
347 if (!tryLoadFromExternal(reader, load_from)) loadDefines(reader);
348 } else
349 reader.gotoEndOfCurrentTag();
350 if (!reader.requireTagOrEnd()) return;
351 }
352
353 if (reader.getNodeName() == TAG_NAME_MATERIALS) {
354 next = 2;
356 if (!tryLoadFromExternal(reader, load_from)) loadMaterials(reader);
357 } else
358 reader.gotoEndOfCurrentTag();
359 if (!reader.requireTagOrEnd()) return;
360 }
361
362 if (reader.getNodeName() == TAG_NAME_GEOMETRY) {
363 next = 3;
365 if (!tryLoadFromExternal(reader, load_from)) {
366 GeometryReader greader(*this, reader);
368 }
369 } else
370 reader.gotoEndOfCurrentTag();
371 if (!reader.requireTagOrEnd()) return;
372 }
373
374 if (reader.getNodeName() == TAG_NAME_GRIDS) {
375 next = 4;
377 if (!tryLoadFromExternal(reader, load_from)) loadGrids(reader);
378 } else
379 reader.gotoEndOfCurrentTag();
380 if (!reader.requireTagOrEnd()) return;
381 }
382
383 if (reader.getNodeName() == TAG_NAME_SOLVERS) {
384 next = 5;
386 if (!tryLoadFromExternal(reader, load_from)) loadSolvers(reader);
387 } else
388 reader.gotoEndOfCurrentTag();
389 if (!reader.requireTagOrEnd()) return;
390 }
391
392 if (reader.getNodeName() == TAG_NAME_CONNECTS) {
393 next = 6;
395 if (!tryLoadFromExternal(reader, load_from)) loadConnects(reader);
396 } else
397 reader.gotoEndOfCurrentTag();
398 if (!reader.requireTagOrEnd()) return;
399 }
400
401 if (reader.getNodeName() == TAG_NAME_SCRIPT) {
402 next = 7;
404 if (!tryLoadFromExternal(reader, load_from)) loadScript(reader);
405 } else
406 reader.gotoEndOfCurrentTag();
407 if (!reader.requireTagOrEnd()) return;
408 }
409
412 std::string msg;
413 for (; next != 7; ++next) {
414 msg += "<"; msg += tags[next]; msg += ">, ";
415 }
416 if (msg != "") msg += "or ";
417 msg += "</plask>";
418
419 throw XMLUnexpectedElementException(reader, msg);
420
421 } catch (const XMLException&) {
422 throw;
423 } catch (const std::exception& err) {
424 throw XMLException(reader, err.what());
425 // } catch (...) {
426 // throw XMLException(reader, "unrecognized exception");
427 }
428}
429
430/*
431Validate positions:
432
433Notatki:
4341. obiekt istotny w geometrii to obiekt mający nazwę, taki że na ścieżce od korzenia (geometrii) do tego obiektu nie ma innego obiektu mającego nazwe
435 mozna je znaleźć przechodząc drzew w głąb aż do napotkania obiektu mającego nazwę (wtedy przestajemy schodzić w głąb)
4362. geometrie są porównywane parami, każda para zwiera:
437 geometrie tych samych typów, takie że jedna nie jest zawarta w drugiej
4383. sprawdzane są tylko obiekty należące do sumy zbiorów obiektów istotnych obu geometrii
439 (uwaga: obiekt który nie jest istotny w geometrii nadal może być w niej obiektem nazwanym)
4404. ustalane i porównywane są pozycje każdego takiego obiektu w obu geometriach i:
441 - jeśli obiekt nie występuje w jednej z geometrii ostrzeżenie NIE jest drukowane
442 - jeśli zbiory pozycji w geometriach są równej wielkości i nie są takie same ostrzeżenie JEST drukowane
443 - jeśli zbiory pozycji w geometriach mają elementy wspólne ostrzeżenie NIE jest drukowane
444 - w pozostałych przypadkach ostrzeżenie JEST drukowane
445*/
446
448
449 typedef std::map<const GeometryObject*, const char*> GeomToName;
450
451 // always sorted
452 typedef std::vector<const GeometryObject*> Set;
453
455
456 std::map<const Geometry*, Set> cache;
457
458 PositionValidator(GeomToName& geom_to_name): geom_to_name(geom_to_name) {}
459
460 Set& get(const Geometry* geometry) {
461 auto it = cache.find(geometry);
462 if (it != cache.end())
463 return it->second;
464 Set& res = cache[geometry];
465 fill(geometry->getObject3D().get(), res);
466 std::sort(res.begin(), res.end());
467 return res;
468 }
469
470 void fill(const GeometryObject* obj, Set& s) {
471 if (!obj) return;
472 if (geom_to_name.count(obj))
473 s.push_back(obj);
474 else {
475 std::size_t c = obj->getRealChildrenCount();
476 for (std::size_t i = 0; i < c; ++i)
477 fill(obj->getRealChildNo(i).get(), s);
478 }
479 }
480
486 // TODO what with NaNs in vectors?
487 template <typename VectorType>
488 bool compare_vec(std::vector<VectorType> v1, std::vector<VectorType> v2) {
489 if (v1.empty() || v2.empty()) return true;
490 std::sort(v1.begin(), v1.end());
491 std::sort(v2.begin(), v2.end());
492 if (v1.size() == v2.size()) {
493 return std::equal(v1.begin(), v1.end(), v2.begin(),
494 [](const VectorType& x1, const VectorType& x2) { return isnan(x1) || isnan(x2) || x1.equals(x2, 1.1e-4); });
495 } // different sizes:
496 auto v2_last_match_it = v2.begin(); // != v2.end() since v2 is not empty
497 for (VectorType point: v1) {
498 while (true) {
499 if (point.equals(*v2_last_match_it, 1.1e-4)) return true; // common point
500 if (point < *v2_last_match_it) break; // point is not included in v2, we are going to check next point from v1
501 ++v2_last_match_it;
502 if (v2_last_match_it == v2.end()) return false; // no common points found so far
503 }
504 }
505 return false;
506 }
507
513 template <typename GeomType>
514 Set compare_d(const GeomType* geom1, const GeomType* geom2) {
515 auto c1 = geom1->getChildUnsafe();
516 auto c2 = geom2->getChildUnsafe();
517 if (!c1 || !c2) return {}; //one geom. is empty
518 if (geom1->hasInSubtree(*c2) || geom2->hasInSubtree(*c1)) return {};
519 Set obj_to_check;
520 {
521 Set og1 = get(geom1);
522 Set og2 = get(geom2);
523 std::set_union(og1.begin(), og1.end(), og2.begin(), og2.end(), std::back_inserter(obj_to_check));
524 }
525 Set result;
526 for (auto o: obj_to_check)
527 if (!compare_vec(geom1->getObjectPositions(*o), geom2->getObjectPositions(*o))) {
528 // found problem, for obj geom_to_name[o]
529 result.push_back(o);
530 }
531 return result;
532 }
533
534 Set compare(const Geometry* g1, const Geometry* g2) {
535 if (const GeometryD<2>* g1_2d = dynamic_cast<const GeometryD<2>*>(g1))
536 return compare_d(g1_2d, static_cast<const GeometryD<2>*>(g2));
537 if (const GeometryD<3>* g1_3d = dynamic_cast<const GeometryD<3>*>(g1))
538 return compare_d(g1_3d, static_cast<const GeometryD<3>*>(g2));
539 return {};
540 }
541};
542
544 const std::function<void(const Geometry*, const Geometry*, std::vector<const GeometryObject*>&&, const std::map<const GeometryObject*, const char*>&)>& callback
545 ) const
546{
547 // split geometries by types, we will compare each pairs of geometries of the same type:
548 typedef std::map<std::type_index, std::set<const Geometry*> > GeomToType;
550 for (auto& geom: roots)
551 geometries_by_type[std::type_index(typeid(*geom))].insert(geom.get());
552 if (std::find_if(geometries_by_type.begin(), geometries_by_type.end(), [] (GeomToType::value_type& v) { return v.second.size() > 1; }) == geometries_by_type.end())
553 return; // no 2 geometries of the same type
554
556 for (auto& i: geometrics)
557 geom_to_name[i.second.get()] = i.first.c_str();
558 PositionValidator important_obj(geom_to_name);
559
560 for (auto& geom_set: geometries_by_type)
561 for (auto it = geom_set.second.begin(); it != geom_set.second.end(); ++it) {
562 auto it2 = it;
563 ++it2;
564 for (; it2 != geom_set.second.end(); ++it2) {
566 if (!objs.empty())
567 callback(*it, *it2, std::move(objs), geom_to_name);
568 }
569 }
570}
571
572static std::string geomName(const Manager& m, const Geometry* g, const std::map<const GeometryObject*, const char*>& names) {
573 auto it = names.find(g);
574 if (it != names.end()) {
575 std::string r = "'";
576 r += it->second;
577 r += '\'';
578 return r;
579 } else {
580 std::string r = "[";
581 r += boost::lexical_cast<std::string>(m.getRootIndex(g));
582 r += ']';
583 return r;
584 }
585}
586
588 if (this->draft) return;
590 [this] (const Geometry* g1, const Geometry* g2, std::vector<const GeometryObject*>&& objs, const std::map<const GeometryObject*, const char*>& names) {
591 bool single = objs.size() < 2;
592 std::string ons;
593 for (auto o: objs) {
594 ons += " '"; ons += names.find(o)->second; ons += '\'';
595 }
596 writelog(plask::LOG_WARNING, "Object{}{} ha{} different position in geometry {} and {}",
597 single?"":"s", ons, single?"s":"ve", geomName(*this, g1, names), geomName(*this, g2, names));
598 });
599}
600
601std::size_t Manager::getRootIndex(const Geometry *geom) const {
602 for (std::size_t result = 0; result < roots.size(); ++result)
603 if (roots[result].get() == geom) return result;
604 return roots.size();
605}
606
607} // namespace plask