PLaSK library

Loading...
Searching...
No Matches
manager.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 */
14#include "solver.hpp"
15
16#ifndef PLASK__GEOMETRY_MANAGER_H
17#define PLASK__GEOMETRY_MANAGER_H
18
24#include <string>
25#include <map>
26#include <set>
27#include <deque>
28#include <boost/filesystem.hpp>
29
30#include "utils/xml/reader.hpp"
31
32#include "math.hpp"
33#include "mesh/mesh.hpp"
34#include "material/db.hpp"
35#include "geometry/path.hpp"
36#include "geometry/space.hpp"
37
38 namespace plask {
39
40 class Solver;
41
42 class GeometryReader;
43
51 struct PLASK_API Manager {
52
53 template <typename T>
54 struct Map: std::map<std::string, T> {
55 typename std::map<std::string, T>::iterator find(const std::string& key) {
56 std::string name = key;
57 std::replace(name.begin(), name.end(), '-', '_');
58 return std::map<std::string, T>::find(name);
59 }
60
61 typename std::map<std::string, T>::const_iterator find(const std::string& key) const {
62 std::string name = key;
63 std::replace(name.begin(), name.end(), '-', '_');
64 return std::map<std::string, T>::find(name);
65 }
66 };
67
69 static void disallowExternalSources(Manager& PLASK_UNUSED(manager), const std::string& url, const std::string& section) {
70 throw Exception("can't load section \"{0}\" from \"{1}\". Loading from external sources is not supported or disallowed.", section, url); }
71
73 struct PLASK_API ExternalSourcesFromFile {
74
76 boost::filesystem::path originalFileName;
77
79 std::string currentSection;
80
82 ExternalSourcesFromFile* prev;
83
84 bool hasCircularRef(boost::filesystem::path& fileName, const std::string& section) {
85 if (!currentSection.empty() || currentSection != section) return false;
86 if (fileName == originalFileName) return true;
87 return prev != 0 && prev->hasCircularRef(fileName, section);
88 }
89
94 ExternalSourcesFromFile(): prev(nullptr) {}
95
102 ExternalSourcesFromFile(const boost::filesystem::path& originalFileName,
103 const std::string& currentSection = std::string(),
104 ExternalSourcesFromFile* prev = nullptr)
105 : originalFileName(originalFileName), currentSection(currentSection), prev(prev) {}
106
107 void operator()(Manager& manager, const std::string& url, const std::string& section);
108
109 };
110
111 private:
112
114 std::map<std::string, std::map<std::string, std::string>> global_solver_names;
115
117 static bool acceptAllSections(const std::string&) { return true; }
118
119 /*struct LoadFunCallbackT {
120 std::pair< XMLReader, std::unique_ptr<LoadFunCallbackT> > get(const std::string& url) const {
121 throw Exception("can't load section from \"{0}\". Loading from external sources is not supported or disallowed.", url);
122 }
123 };*/
124
126 typedef std::function<void(Manager&, const std::string&, const std::string&)> LoadFunCallbackT;
127
135 bool tryLoadFromExternal(XMLReader& reader, const LoadFunCallbackT& load_from);
136
137 protected:
138
145 virtual shared_ptr<Solver> loadSolver(const std::string& category, const std::string& lib, const std::string& solver_name, const std::string& name);
146
147
152 void loadMaterialLib(XMLReader& reader);
153
158 virtual void loadMaterial(XMLReader& reader);
159
160 public:
161
162 static constexpr const char* TAG_NAME_ROOT = "plask";
163 static constexpr const char* TAG_NAME_DEFINES = "defines";
164 static constexpr const char* TAG_NAME_MATERIALS = "materials";
165 static constexpr const char* TAG_NAME_GEOMETRY = "geometry";
166 static constexpr const char* TAG_NAME_GRIDS = "grids";
167 static constexpr const char* TAG_NAME_SOLVERS = "solvers";
168 static constexpr const char* TAG_NAME_CONNECTS = "connects";
169 static constexpr const char* TAG_NAME_SCRIPT = "script";
170
171 static constexpr const char* XML_AXES_ATTR = "axes";
172
174 Map<PathHints> pathHints;
175
177 std::vector<shared_ptr<Geometry>> roots;
178
180 Map<shared_ptr<GeometryObject>> geometrics;
181
183 Map<shared_ptr<MeshBase>> meshes;
184
186 Map<shared_ptr<Solver>> solvers;
187
189 //TODO? move to special modules reader class to have more local scope?
190 Map<boost::any> boundaries;
191
193 std::string script;
194
196 unsigned scriptline;
197
199 const AxisNames* axisNames;
200
202 bool draft;
203
205 std::deque<std::pair<int,std::string>> errors;
206
212 void pushError(const std::string& mesg, int line=-1) {
213 errors.push_back(std::make_pair(line, mesg));
214 }
215
221 void pushError(const std::runtime_error& error, int line=-1) {
222 pushError(error.what(), line);
223 }
224
230 void pushError(const XMLException& error, int line=-1) {
231 if (line == -1) line = error.line;
232 pushError(error.what(), line);
233 }
234
240 template <typename ErrorType>
241 void throwErrorIfNotDraft(ErrorType error, int line=-1) {
242 if (!draft) throw error;
243 else pushError(error, line);
244 }
245
251 std::string getAxisName(std::size_t axis_index) { return axisNames->operator [](axis_index); }
252
257 std::string getAxisLongName() { return getAxisName(axis::lon_index); }
258
263 std::string getAxisTranName() { return getAxisName(axis::tran_index); }
264
269 std::string getAxisVertName() { return getAxisName(axis::up_index); }
270
275 class PLASK_API SetAxisNames {
276 Manager& manager;
277 const AxisNames* old;
278
279 public:
280
286 SetAxisNames(Manager& manager, const AxisNames* names);
287
295 SetAxisNames(Manager& manager, XMLReader& source);
296
301 SetAxisNames(GeometryReader& reader);
302
304 ~SetAxisNames() { manager.axisNames = old; }
305 };
306
307 explicit Manager(bool draft = false): scriptline(0), axisNames(&AxisNames::axisNamesRegister.get("long, tran, vert")), draft(draft) {}
308
309 virtual ~Manager() {}
310
316 PathHints* getPathHints(const std::string& path_hints_name);
317
323 const PathHints* getPathHints(const std::string& path_hints_name) const;
324
331 PathHints& requirePathHints(const std::string& path_hints_name);
332
339 const PathHints& requirePathHints(const std::string& path_hints_name) const;
340
346 shared_ptr<GeometryObject> getGeometryObject(const std::string& name) const;
347
354 template <typename RequiredObjectType>
355 shared_ptr<RequiredObjectType> getGeometryObject(const std::string& name) const;
356
363 shared_ptr<GeometryObject> requireGeometryObject(const std::string& name);
364
373 template <typename RequiredObjectType>
374 shared_ptr<RequiredObjectType> requireGeometryObject(const std::string& name);
375
381 shared_ptr<Geometry> getGeometry(const std::string& name) const;
382
388 shared_ptr<MeshBase> getMesh(const std::string& name) const;
389
395 template <typename RequiredCalcSpaceType>
396 shared_ptr<RequiredCalcSpaceType> getGeometry(const std::string& name) const;
397
403 template <typename RequiredCalcSpaceType>
404 shared_ptr<RequiredCalcSpaceType> requireGeometry(const std::string& name) const {
405 auto geometry = getGeometry<RequiredCalcSpaceType>(name);
406 if (!geometry) throw NoSuchGeometry(name);
407 return geometry;
408 }
409
414 virtual void loadDefines(XMLReader& reader);
415
420 virtual void loadGeometry(GeometryReader& reader);
421
426 virtual void loadMaterials(XMLReader& reader);
427
432 virtual void loadGrids(XMLReader& reader);
433
438 virtual void loadSolvers(XMLReader& reader);
439
444 virtual void loadConnects(XMLReader& reader);
445
451 virtual void loadScript(XMLReader& reader);
452
459 void loadFromReader(XMLReader& XMLreader, const LoadFunCallbackT& load_from_cb = &disallowExternalSources);
460
467 void loadFromStream(std::unique_ptr<std::istream>&& input, const LoadFunCallbackT& load_from_cb = &disallowExternalSources);
468
475 void loadFromXMLString(const std::string &input_XML_str, const LoadFunCallbackT& load_from_cb = &disallowExternalSources);
476
477 /*
478 * Read all objects up to end of XML tag and call functor(object) for each object which was read.
479 * @param source
480 * @param functor
481 * @tparam FunctorType unary functor which can take RequiredObjectType& as argument
482 * @tparam RequiredObjectType required type of object
483 */
484 /*template <typename FunctorType, typename RequiredObjectType = GeometryObject>
485 void readAllObjects(XMLReader& source, FunctorType functor);*/
486
491 void loadFromFile(const std::string& fileName);
492
499 void loadFromFILE(FILE* file, const LoadFunCallbackT& load_from_cb = &disallowExternalSources);
500
501 private:
508 template <typename Boundary>
509 Boundary getBoundaryByName(XMLReader& reader, const std::string& name) {
510 auto p = this->boundaries.find(name);
511 if (p == this->boundaries.end())
512 throw XMLException(reader, format("can't find boundary (place) with given name \"{0}\".", name));
513 return boost::any_cast<Boundary>(p->second);
514 }
515
521 void storeBoundary(const std::string& name, boost::any&& boundary) {
522 if (!this->boundaries.insert(std::make_pair(name, std::move(boundary))).second)
523 throw NamesConflictException("place (boundary)", name);
524 }
525
526 public:
531 template <typename Boundary>
532 Boundary readBoundary(XMLReader& reader);
533
559 //TODO moves to modules reader (with names map)
560 //@param geometry (optional) geometry used by solver which reads boundary conditions
561 template <typename Boundary, typename ConditionT>
562 void readBoundaryConditions(XMLReader& reader, BoundaryConditions<Boundary, ConditionT>& dest/*, shared_ptr<Geometry> geometry = shared_ptr<Geometry>()*/);
563
571 void load(XMLReader& XMLreader,
572 const LoadFunCallbackT& load_from_cb = &disallowExternalSources,
573 const std::function<bool(const std::string& section_name)>& section_filter = &acceptAllSections);
574
582 void loadSection(XMLReader& XMLreader, const std::string& section_to_load,
583 const LoadFunCallbackT& load_from_cb = &disallowExternalSources) {
584 load(XMLreader, load_from_cb, [&](const std::string& section_name) -> bool { return section_name == section_to_load; });
585 }
586
596 void validatePositions(const std::function<void(const Geometry*, const Geometry*, std::vector<const GeometryObject*>&&, const std::map<const GeometryObject*, const char*>&)>& callback) const;
597
604 void validatePositions() const;
605
611 std::size_t getRootIndex(const Geometry* geom) const;
612};
613
614// Specialization for most types
615 template <typename RequiredObjectType>
616 shared_ptr<RequiredObjectType> Manager::getGeometryObject(const std::string& name) const {
617 return dynamic_pointer_cast<RequiredObjectType>(getGeometryObject(name));
618}
619
620// Specialization for GeometryObject which doesn't require dynamic_cast
621 template <>
622 inline shared_ptr<GeometryObject> Manager::getGeometryObject<GeometryObject>(const std::string& name) const {
623 return getGeometryObject(name);
624}
625
626// Specialization for most types
627 template <typename RequiredObjectType>
628 inline shared_ptr<RequiredObjectType> Manager::requireGeometryObject(const std::string& name) {
629 shared_ptr<RequiredObjectType> result = dynamic_pointer_cast<RequiredObjectType>(requireGeometryObject(name));
630 if (!result) throwErrorIfNotDraft(UnexpectedGeometryObjectTypeException());
631 return result;
632}
633
634// Specialization for GeometryObject which doesn't require dynamic_cast
635 template <>
636 inline shared_ptr<GeometryObject> Manager::requireGeometryObject<GeometryObject>(const std::string& name) {
637 return requireGeometryObject(name);
638}
639
640//specialization for most types
641 template <typename RequiredCalcSpaceType>
642 inline shared_ptr<RequiredCalcSpaceType> Manager::getGeometry(const std::string& name) const {
643 return dynamic_pointer_cast<RequiredCalcSpaceType>(getGeometry(name));
644}
645
646// Specialization for Geometry which doesn't require dynamic_cast
647 template <>
648 inline shared_ptr<Geometry> Manager::getGeometry<Geometry>(const std::string& name) const {
649 return getGeometry(name);
650}
651
661 template <typename ConditionT>
662 inline ConditionT parseBoundaryValue(const XMLReader& tag_with_value) {
663 return tag_with_value.requireAttribute<ConditionT>("value");
664}
665
666 template <typename Boundary>
667 Boundary Manager::readBoundary(XMLReader& reader) {
668 Boundary boundary;
669 std::string op_name = reader.getTagName();
670 plask::optional<std::string> placename = reader.getAttribute("name");
671 if (op_name == "union") {
672 reader.requireTag(); Boundary A = this->readBoundary<Boundary>(reader);
673 reader.requireTag(); Boundary B = this->readBoundary<Boundary>(reader);
674 reader.requireTagEnd();
675 boundary = A + B;
676 } else
677 if (op_name == "intersection") {
678 reader.requireTag(); Boundary A = this->readBoundary<Boundary>(reader);
679 reader.requireTag(); Boundary B = this->readBoundary<Boundary>(reader);
680 reader.requireTagEnd();
681 boundary = A * B;
682 } else
683 if (op_name == "difference") {
684 reader.requireTag(); Boundary A = this->readBoundary<Boundary>(reader);
685 reader.requireTag(); Boundary B = this->readBoundary<Boundary>(reader);
686 reader.requireTagEnd();
687 boundary = A - B;
688 } else
689 if (op_name == "place") {
690 reader.ensureNodeTypeIs(XMLReader::NODE_ELEMENT, "place");
691 plask::optional<std::string> refname = reader.getAttribute("ref");
692 boundary = refname ? this->getBoundaryByName<Boundary>(reader, *refname)
693 : parseBoundary<Boundary>(reader, *this);
694 } else
695 reader.throwUnexpectedElementException("place, union, intersection, or difference tag");
696 if (boundary.isNull()) throwErrorIfNotDraft(XMLException(reader, "Can't parse boundary place from XML."));
697 if (placename) {
698 std::replace(placename->begin(), placename->end(), '-', '_');
699 this->storeBoundary(*placename, boundary);
700 }
701 return boundary;
702}
703
704 template <typename Boundary, typename ConditionT>
705 inline void Manager::readBoundaryConditions(XMLReader& reader, BoundaryConditions<Boundary, ConditionT>& dest) {
706 while (reader.requireTagOrEnd("condition")) {
707 Boundary boundary;
708 plask::optional<std::string> place = reader.getAttribute("place");
709 plask::optional<std::string> placename = reader.getAttribute("placename");
710 ConditionT value;
711 try {
712 value = parseBoundaryValue<ConditionT>(reader);
713 } catch (std::runtime_error err) {
714 throwErrorIfNotDraft(err);
715 }
716 if (place) {
717 boundary = parseBoundary<Boundary>(*place, *this);
718 if (boundary.isNull()) throwErrorIfNotDraft(XMLException(reader, format("Can't parse boundary place from string \"{0}\".", *place)));
719 } else {
720 place = reader.getAttribute("placeref");
721 if (place)
722 boundary = this->getBoundaryByName<Boundary>(reader, *place);
723 else {
724 reader.requireTag();
725 boundary = this->readBoundary<Boundary>(reader);
726 //placename.reset(); // accept "placename" or only "name" in place tag?
727 }
728 }
729 /*if (!value) { // value still not known, must be read from tag <value>...</value>
730 reader.requireTag("value");
731 *value = reader.requireText<ConditionT>();
732 reader.requireTagEnd();
733 }*/ //now we read only from XML tags
734 if (placename) this->storeBoundary(*placename, boundary);
735 dest.add(std::move(boundary), std::move(value));
736 reader.requireTagEnd(); // </condition>
737 }
738}
739
740
741} // namespace plask
742
743#endif // PLASK__GEOMETRY_MANAGER_H