PLaSK library
Loading...
Searching...
No Matches
generator_rectangular.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 <plask/log/log.hpp>
15#include <plask/manager.hpp>
16
18
19namespace plask {
20
21template <int dim>
24 double split) {
25 std::set<double> pts = geometry->getPointsAlong(dir);
26 std::vector<double> ptsv;
27 if (split == 0) {
28 ptsv.reserve(pts.size());
29 for (double p : pts) ptsv.push_back(p);
30 } else {
31 ptsv.reserve(2 * pts.size());
32 for (double p : pts) {
33 std::vector<double>::reverse_iterator it;
34 for (it = ptsv.rbegin(); it != ptsv.rend() && *it > p - split; ++it);
35 ptsv.insert(it.base(), p - split);
36 ptsv.push_back(p + split);
37 }
38 }
40}
41
42shared_ptr<OrderedAxis> makeGeometryGrid1D(const shared_ptr<GeometryObjectD<2>>& geometry, double split) {
43 return makeGeometryAxis(geometry, Primitive<3>::DIRECTION_TRAN, split);
44}
45
47 auto mesh = makeGeometryGrid1D(geometry, split ? OrderedAxis::MIN_DISTANCE : 0.);
48 writelog(LOG_DETAIL, "mesh.Rectangular1D.SimpleGenerator: Generating new mesh ({0})", mesh->size());
49 return mesh;
50}
51
52shared_ptr<RectangularMesh<2>> makeGeometryGrid(const shared_ptr<GeometryObjectD<2>>& geometry, double split) {
57 mesh->setOptimalIterationOrder();
58 return mesh;
59}
60
63 writelog(LOG_DETAIL, "mesh.Rectangular2D.SimpleGenerator: Generating new mesh ({0}x{1})", mesh->axis[0]->size(),
64 mesh->axis[1]->size());
65 return mesh;
66}
67
69 return plask::make_shared<RectangularMesh<2>>(horizontal_generator->get<MeshAxis>(geometry),
70 makeGeometryGrid(geometry)->axis[1]);
71}
72
73shared_ptr<RectangularMesh<3>> makeGeometryGrid(const shared_ptr<GeometryObjectD<3>>& geometry, double split) {
78 mesh->setOptimalIterationOrder();
79 return mesh;
80}
81
83 auto mesh = makeGeometryGrid(geometry, split ? OrderedAxis::MIN_DISTANCE : 0.);
84 writelog(LOG_DETAIL, "mesh.Rectangular3D.SimpleGenerator: Generating new mesh ({0}x{1}x{2})", mesh->axis[0]->size(),
85 mesh->axis[1]->size(), mesh->axis[2]->size());
86 return mesh;
87}
88
89shared_ptr<OrderedAxis> refineAxis(const shared_ptr<MeshAxis>& axis, double spacing) {
90 if (spacing == 0. || isinf(spacing) || isnan(spacing)) return make_shared<OrderedAxis>(*axis);
91 size_t total = 1;
92 for (size_t i = 1; i < axis->size(); ++i) {
93 total += size_t(max(round((axis->at(i) - axis->at(i - 1)) / spacing), 1.));
94 }
95 std::vector<double> points;
96 points.reserve(total);
97 for (size_t i = 1; i < axis->size(); ++i) {
98 const double offset = axis->at(i - 1);
99 const double range = axis->at(i) - offset;
100 const double steps = std::max(round(range / spacing), 1.);
101 const double step = range / steps;
102 for (size_t j = 0, n = std::size_t(steps); j < n; ++j) {
103 points.push_back(offset + double(j) * step);
104 }
105 }
106 points.push_back(axis->at(axis->size() - 1));
107 assert(points.size() == total);
108 return shared_ptr<OrderedAxis>(new OrderedAxis(std::move(points)));
109}
110
112 auto mesh = refineAxis(makeGeometryGrid1D(geometry, split ? OrderedAxis::MIN_DISTANCE : 0.), spacing);
113 writelog(LOG_DETAIL, "mesh.Rectangular1D.RegularGenerator: Generating new mesh ({0})", mesh->size());
114 return mesh;
115}
116
118 auto mesh1 = makeGeometryGrid(geometry, split ? OrderedAxis::MIN_DISTANCE : 0.);
119 auto mesh = make_shared<RectangularMesh<2>>(refineAxis(mesh1->axis[0], spacing0), refineAxis(mesh1->axis[1], spacing1));
120 writelog(LOG_DETAIL, "mesh.Rectangular2D.RegularGenerator: Generating new mesh ({0}x{1})", mesh->axis[0]->size(),
121 mesh->axis[1]->size());
122 return mesh;
123}
124
126 auto mesh1 = makeGeometryGrid(geometry, split ? OrderedAxis::MIN_DISTANCE : 0.);
127 auto mesh = make_shared<RectangularMesh<3>>(refineAxis(mesh1->axis[0], spacing0), refineAxis(mesh1->axis[1], spacing1),
128 refineAxis(mesh1->axis[2], spacing2));
129 writelog(LOG_DETAIL, "mesh.Rectangular3D.RegularGenerator: Generating new mesh ({0}x{1}x{2})", mesh->axis[0]->size(),
130 mesh->axis[1]->size(), mesh->axis[2]->size());
131 return mesh;
132}
133
134template <int dim> std::pair<double, double> RectangularMeshRefinedGenerator<dim>::getMinMax(const shared_ptr<OrderedAxis>& axis) {
135 double min = INFINITY, max = 0;
136 for (size_t i = 1; i != axis->size(); ++i) {
137 double L = axis->at(i) - axis->at(i - 1);
138 if (L < min) min = L;
139 if (L > max) max = L;
140 }
141 return std::pair<double, double>(min, max);
142}
143
145 double max = 0;
146 double newpoint;
147 for (size_t i = 1; i != axis->size(); ++i) {
148 double L = axis->at(i) - axis->at(i - 1);
149 if (L > max) {
150 max = L;
151 newpoint = 0.5 * (axis->at(i - 1) + axis->at(i));
152 }
153 }
155 axis->addPoint(newpoint);
156}
157
158template <int dim>
160 const shared_ptr<GeometryObjectD<DIM>>& geometry,
161 size_t dir) {
162 assert(bool(axis));
164
165 double geometry_lower = geometry->getBoundingBox().lower[dir], geometry_upper = geometry->getBoundingBox().upper[dir];
166
167 // Add refinement points
168 for (auto ref : this->refinements[dir]) {
169 auto object = ref.first.first.lock();
170 if (!object) {
171 writelog(LOG_WARNING, "{}: Refinement defined for object not existing any more", name());
172 } else {
173 auto path = ref.first.second;
174 auto boxes = geometry->getObjectBoundingBoxes(*object, path);
175 auto origins = geometry->getObjectPositions(*object, path);
176 if (boxes.size() == 0) writelog(LOG_WARNING, "DivideGenerator: Refinement defined for object absent from the geometry");
177 auto box = boxes.begin();
178 auto origin = origins.begin();
179 for (; box != boxes.end(); ++box, ++origin) {
180 for (auto x : ref.second) {
181 double zero = (*origin)[dir];
182 double lower = box->lower[dir] - zero;
183 double upper = box->upper[dir] - zero;
184 double x0 = x + zero;
185 if (geometry_lower <= x0 && x0 <= geometry_upper) axis->addPoint(x0);
186 }
187 }
188 }
189 }
190
191 // Have specialization make further axis processing
192 return processAxis(axis, geometry, dir);
193}
194
195template <>
198 getAxis(mesh, geometry, 0);
199 writelog(LOG_DETAIL, "mesh.Rectilinear1D::{}: Generating new mesh ({:d})", name(), mesh->size());
200 return mesh;
201}
202
203template <>
205 auto mesh = makeGeometryGrid(geometry);
207 getAxis(axis0, geometry, 0);
208 getAxis(axis1, geometry, 1);
209
210 auto minmax0 = getMinMax(axis0), minmax1 = getMinMax(axis1);
211 double asp0 = minmax0.second / minmax1.first, asp1 = minmax1.second / minmax0.first;
212 double limit = (1 + SMALL) * aspect;
213 while (aspect != 0. && (asp0 > limit || asp1 > limit)) {
214 if (asp0 > aspect) divideLargestSegment(axis0);
215 if (asp1 > aspect) divideLargestSegment(axis1);
216 minmax0 = getMinMax(axis0);
217 minmax1 = getMinMax(axis1);
218 asp0 = minmax0.second / minmax1.first;
219 asp1 = minmax1.second / minmax0.first;
220 }
221
222 mesh->setOptimalIterationOrder();
223 writelog(LOG_DETAIL, "mesh.Rectangular2D::{}: Generating new mesh ({:d}x{:d}, max. aspect {:.0f}:1)", name(),
224 mesh->axis[0]->size(), mesh->axis[1]->size(), max(asp0, asp1));
225 return mesh;
226}
227
228template <>
230 auto mesh = makeGeometryGrid(geometry);
233 getAxis(axis0, geometry, 0);
234 getAxis(axis1, geometry, 1);
235 getAxis(axis2, geometry, 2);
236
237 auto minmax0 = getMinMax(axis0), minmax1 = getMinMax(axis1), minmax2 = getMinMax(axis2);
238 double asp0 = minmax0.second / min(minmax1.first, minmax2.first), asp1 = minmax1.second / min(minmax0.first, minmax2.first),
239 asp2 = minmax2.second / min(minmax0.first, minmax1.first);
240 double limit = (1 + SMALL) * aspect;
241 while (aspect != 0. && (asp0 > limit || asp1 > limit || asp2 > limit)) {
242 if (asp0 > aspect) divideLargestSegment(axis0);
243 if (asp1 > aspect) divideLargestSegment(axis1);
244 if (asp2 > aspect) divideLargestSegment(axis2);
245 minmax0 = getMinMax(axis0);
246 minmax1 = getMinMax(axis1);
247 minmax2 = getMinMax(axis2);
248 asp0 = minmax0.second / min(minmax1.first, minmax2.first);
249 asp1 = minmax1.second / min(minmax0.first, minmax2.first);
250 asp2 = minmax2.second / min(minmax0.first, minmax1.first);
251 }
252
253 mesh->setOptimalIterationOrder();
254 writelog(LOG_DETAIL, "mesh.Rectangular3D::{}: Generating new mesh ({:d}x{:d}x{:d}, max. aspect {:.0f}:1)", name(),
255 mesh->axis[0]->size(), mesh->axis[1]->size(), mesh->axis[2]->size(), max(asp0, max(asp1, asp2)));
256 return mesh;
257}
258
259template <int dim>
261 const shared_ptr<GeometryObjectD<DIM>>& /*geometry*/,
262 size_t dir) {
263 assert(bool(axis));
265 (void)warning_off; // don't warn about unused variable warning_off
266
267 if (pre_divisions[dir] == 0) pre_divisions[dir] = 1;
268 if (post_divisions[dir] == 0) post_divisions[dir] = 1;
269
270 OrderedAxis& result = *axis.get();
271
272 // Pre-divide each object
273 double x = *result.begin();
274 std::vector<double> points;
275 points.reserve((pre_divisions[dir] - 1) * (result.size() - 1));
276 for (auto i = result.begin() + 1; i != result.end(); ++i) {
277 double w = *i - x;
278 for (size_t j = 1; j != pre_divisions[dir]; ++j) points.push_back(x + w * double(j) / double(pre_divisions[dir]));
279 x = *i;
280 }
281 result.addOrderedPoints(points.begin(), points.end());
282
283 // Now ensure, that the grids do not change to quickly
284 if (result.size() > 2 && getGradual(dir)) {
285 size_t end = result.size() - 2;
286 double w_prev = INFINITY, w = result[1] - result[0], w_next = result[2] - result[1];
287 for (size_t i = 0; i <= end;) {
288 bool goon = true;
289 if (w > 2.001 * w_prev) { // .0001 is for border case w == 2*w_prev, to avoid division even in presence of
290 // numerical error
291 if (result.addPoint(0.5 * (result[i] + result[i + 1]))) {
292 ++end;
293 w = w_next = result[i + 1] - result[i];
294 goon = false;
295 }
296 } else if (w > 2.001 * w_next) {
297 if (result.addPoint(0.5 * (result[i] + result[i + 1]))) {
298 ++end;
299 w_next = result[i + 1] - result[i];
300 if (i) {
301 --i;
302 w = w_prev;
303 w_prev = (i == 0) ? INFINITY : result[i] - result[i - 1];
304 } else
305 w = w_next;
306 goon = false;
307 }
308 }
309 if (goon) {
310 ++i;
311 w_prev = w;
312 w = w_next;
313 w_next = (i < end) ? result[i + 2] - result[i + 1] : INFINITY;
314 }
315 }
316 }
317
318 // Finally divide each object in post- division
319 x = *result.begin();
320 points.clear();
321 points.reserve((post_divisions[dir] - 1) * (result.size() - 1));
322 for (auto i = result.begin() + 1; i != result.end(); ++i) {
323 double w = *i - x;
324 for (size_t j = 1; j != post_divisions[dir]; ++j) points.push_back(x + w * double(j) / double(post_divisions[dir]));
325 x = *i;
326 }
327
328 result.addOrderedPoints(points.begin(), points.end());
329
330 return axis;
331}
332
333template <> RectangularMeshSmoothGenerator<1>::RectangularMeshSmoothGenerator() : finestep{0.005}, maxstep{INFINITY}, factor{1.2} {}
334
335template <>
337 : finestep{0.005, 0.005}, maxstep{INFINITY, INFINITY}, factor{1.2, 1.2} {}
338
339template <>
341 : finestep{0.005, 0.005, 0.005}, maxstep{INFINITY, INFINITY, INFINITY}, factor{1.2, 1.2, 1.2} {}
342
343template <int dim>
345 const shared_ptr<GeometryObjectD<DIM>>& /*geometry*/,
346 size_t dir) {
348
349 // Next divide each object
350 double x = *axis->begin();
351 std::vector<double> points; // points.reserve(...);
352 for (auto i = axis->begin() + 1; i != axis->end(); ++i) {
353 double width = *i - x;
354 if (width + OrderedAxis::MIN_DISTANCE <= finestep[dir]) continue;
355 if (factor[dir] == 1.) {
356 double m = ceil(width / finestep[dir]);
357 double d = width / m;
358 for (size_t i = 1, n = size_t(m); i < n; ++i) points.push_back(x + double(i) * d);
359 continue;
360 }
361 double logf = log(factor[dir]);
362 double maxm = floor(log(maxstep[dir] / finestep[dir]) / logf + OrderedAxis::MIN_DISTANCE);
363 double m = ceil(log(0.5 * (width - OrderedAxis::MIN_DISTANCE) / finestep[dir] * (factor[dir] - 1.) + 1.) / logf) -
364 1.; // number of points in one half
365 size_t lin = 0;
366 if (m > maxm) {
367 m = maxm;
368 lin = 1;
369 }
370 size_t n = size_t(m);
371 double end = finestep[dir] * (pow(factor[dir], m) - 1.) / (factor[dir] - 1.);
372 double last = finestep[dir] * pow(factor[dir], m);
373 if (lin) {
374 lin = size_t(ceil((width - 2. * end) / last));
375 } else if (width - 2. * end <= last) {
376 lin = 1;
377 } else {
378 lin = 2;
379 }
380 double s = finestep[dir] * 0.5 * width / (end + 0.5 * double(lin) * last);
381 double dx = 0.;
382 for (size_t i = 0; i < n; ++i) {
383 dx += s;
384 s *= factor[dir];
385 points.push_back(x + dx);
386 }
387 for (size_t i = 0; i < lin; ++i) {
388 dx += s;
389 points.push_back(x + dx);
390 }
391 for (size_t i = 1; i < n; ++i) {
392 s /= factor[dir];
393 dx += s;
394 points.push_back(x + dx);
395 }
396 x = *i;
397 }
398 axis->addOrderedPoints(points.begin(), points.end());
399
400 return axis;
401}
402
403template <int dim>
404inline double getObjectSize(const weak_ptr<GeometryObject>& object, unsigned direction) {
405 auto obj = object.lock();
406 if (!obj) return 0.;
408 if (obj2) return obj2->getBoundingBox().size()[unsigned(direction)];
409 throw std::runtime_error("Expected 2D geometry object");
410}
411
412template <>
413inline double getObjectSize<3>(const weak_ptr<GeometryObject>& object, unsigned direction) {
414 auto obj = object.lock();
415 if (!obj) return 0.;
417 if (obj3) return obj3->getBoundingBox().size()[unsigned(direction)];
419 if (!obj2) throw std::runtime_error("Expected 2D or 3D geometry object");
420 if (direction == 0)
421 throw std::runtime_error("Cannot get size along longitudinal direction of 2D geometry object");
422 return obj2->getBoundingBox().size()[unsigned(direction) - 1];
423}
424
425template <int dim> void RectangularMeshRefinedGenerator<dim>::fromXML(XMLReader& reader, Manager& manager) {
426 if (reader.getNodeName() == "refinements") {
427 while (reader.requireTagOrEnd()) {
428 if (reader.getNodeName() != "axis0" &&
429 (dim == 1 || (reader.getNodeName() != "axis1" && (dim == 2 || reader.getNodeName() != "axis2")))) {
430 if (dim == 1) throw XMLUnexpectedElementException(reader, "<axis0>");
431 if (dim == 2) throw XMLUnexpectedElementException(reader, "<axis0> or <axis1>");
432 if (dim == 3) throw XMLUnexpectedElementException(reader, "<axis0>, <axis1>, or <axis2>");
433 }
435 auto direction =
436 (reader.getNodeName() == "axis0") ? typename Primitive<RectangularMeshRefinedGenerator<dim>::DIM>::Direction(0)
437 : (reader.getNodeName() == "axis1") ? typename Primitive<RectangularMeshRefinedGenerator<dim>::DIM>::Direction(1)
440 weak_ptr<GeometryObject> object = manager.requireGeometryObject<GeometryObject>(reader.requireAttribute("object"));
441 if (!object.lock()) {
442 if (manager.draft) {
443 writelog(LOG_WARNING, "XML line {:d}: geometry object '{}' does not exist", reader.getLineNr(),
444 reader.requireAttribute("object"));
445 reader.ignoreAllAttributes();
446 reader.requireTagEnd();
447 continue;
448 } else
449 throw XMLException(reader, format("geometry object '{}' does not exist", reader.requireAttribute("object")));
450 }
451 PathHints path;
452 if (auto pathattr = reader.getAttribute("path")) path = manager.requirePathHints(*pathattr);
453 if (auto by = reader.getAttribute<unsigned>("by")) {
454 double objsize = getObjectSize<dim>(object, unsigned(direction));
455 for (unsigned i = 1; i < *by; ++i) {
456 double pos = objsize * i / *by;
457 addRefinement(direction, object, path, pos);
458 }
459 } else if (auto every = reader.getAttribute<double>("every")) {
460 double objsize = getObjectSize<dim>(object, unsigned(direction));
461 size_t n = int(max(round(objsize / *every), 1.));
462 double step = objsize / n;
463 for (
464 struct {
465 size_t i;
466 double pos;
467 } loop = {1, step};
468 loop.i < n; ++loop.i, loop.pos += step)
469 addRefinement(direction, object, path, loop.pos);
470 } else if (auto pos = reader.getAttribute<double>("at")) {
471 addRefinement(direction, object, path, *pos);
472 } else
473 throw XMLNoAttrException(reader, "at', 'every', or 'by");
474 reader.requireTagEnd();
475 }
476 } else if (reader.getNodeName() == "warnings") {
477 writelog(LOG_WARNING, "XML {:d}: <warnings> tag is deprecated", reader.getLineNr());
478 reader.ignoreAllAttributes();
479 reader.requireTagEnd();
480 } else
481 throw XMLUnexpectedElementException(reader, "proper generator configuration tag");
482}
483
487
488template <typename GeneratorT> static shared_ptr<MeshGenerator> readTrivialGenerator(XMLReader& reader, Manager&) {
489 bool split = false;
490 while (reader.requireTagOrEnd()) {
491 if (reader.getNodeName() == "boundaries") {
492 split = reader.getAttribute<bool>("split", split);
493 reader.requireTagEnd();
494 } else
495 throw XMLUnexpectedElementException(reader, "<boundaries>");
496 }
497 return plask::make_shared<GeneratorT>(split);
498}
499
500static RegisterMeshGeneratorReader ordered_simplegenerator_reader("ordered.simple",
502static RegisterMeshGeneratorReader rectangular2d_simplegenerator_reader("rectangular2d.simple",
504static RegisterMeshGeneratorReader rectangular3d_simplegenerator_reader("rectangular3d.simple",
506
507static shared_ptr<MeshGenerator> readRegularGenerator1(XMLReader& reader, Manager&) {
508 double spacing = INFINITY;
509 bool split = false;
510 while (reader.requireTagOrEnd()) {
511 if (reader.getNodeName() == "spacing") {
512 spacing = reader.getAttribute<double>("every", spacing);
513 reader.requireTagEnd();
514 } else if (reader.getNodeName() == "boundaries") {
515 split = reader.getAttribute<bool>("split", split);
516 reader.requireTagEnd();
517 } else
518 throw XMLUnexpectedElementException(reader, "<spacing>, <boundaries>");
519 }
521}
522
523static shared_ptr<MeshGenerator> readRegularGenerator2(XMLReader& reader, Manager&) {
524 double spacing0 = INFINITY, spacing1 = INFINITY;
525 bool split = false;
526 while (reader.requireTagOrEnd()) {
527 if (reader.getNodeName() == "spacing") {
528 if (reader.hasAttribute("every")) {
529 if (reader.hasAttribute("every0")) throw XMLConflictingAttributesException(reader, "every", "every0");
530 if (reader.hasAttribute("every1")) throw XMLConflictingAttributesException(reader, "every", "every1");
531 spacing0 = spacing1 = reader.requireAttribute<double>("every");
532 } else {
533 spacing0 = reader.getAttribute<double>("every0", spacing0);
534 spacing1 = reader.getAttribute<double>("every1", spacing1);
535 }
536 reader.requireTagEnd();
537 } else if (reader.getNodeName() == "boundaries") {
538 split = reader.getAttribute<bool>("split", split);
539 reader.requireTagEnd();
540 } else
541 throw XMLUnexpectedElementException(reader, "<spacing>, <boundaries>");
542 }
543 return plask::make_shared<RectangularMesh2DRegularGenerator>(spacing0, spacing1, split);
544}
545
546static shared_ptr<MeshGenerator> readRegularGenerator3(XMLReader& reader, Manager&) {
547 double spacing0 = INFINITY, spacing1 = INFINITY, spacing2 = INFINITY;
548 bool split = false;
549 while (reader.requireTagOrEnd()) {
550 if (reader.getNodeName() == "spacing") {
551 if (reader.hasAttribute("every")) {
552 if (reader.hasAttribute("every0")) throw XMLConflictingAttributesException(reader, "every", "every0");
553 if (reader.hasAttribute("every1")) throw XMLConflictingAttributesException(reader, "every", "every1");
554 if (reader.hasAttribute("every2")) throw XMLConflictingAttributesException(reader, "every", "every2");
555 spacing0 = spacing1 = reader.requireAttribute<double>("every");
556 } else {
557 spacing0 = reader.getAttribute<double>("every0", spacing0);
558 spacing1 = reader.getAttribute<double>("every1", spacing1);
559 spacing2 = reader.getAttribute<double>("every2", spacing2);
560 }
561 reader.requireTagEnd();
562 } else if (reader.getNodeName() == "boundaries") {
563 split = reader.getAttribute<bool>("split", split);
564 reader.requireTagEnd();
565 } else
566 throw XMLUnexpectedElementException(reader, "<spacing>, <boundaries>");
567 }
568 return plask::make_shared<RectangularMesh3DRegularGenerator>(spacing0, spacing1, spacing2, split);
569}
570
571static RegisterMeshGeneratorReader ordered_regulargenerator_reader("ordered.regular", readRegularGenerator1);
572static RegisterMeshGeneratorReader rectangular2d_regulargenerator_reader("rectangular2d.regular", readRegularGenerator2);
573static RegisterMeshGeneratorReader rectangular3d_regulargenerator_reader("rectangular3d.regular", readRegularGenerator3);
574
577
578 std::set<std::string> read;
579 while (reader.requireTagOrEnd()) {
580 if (read.find(reader.getNodeName()) != read.end())
581 throw XMLDuplicatedElementException(std::string("<generator>"), reader.getNodeName());
582 read.insert(reader.getNodeName());
583 if (reader.getNodeName() == "prediv") {
584 plask::optional<size_t> into = reader.getAttribute<size_t>("by");
585 if (into) {
586 if (reader.hasAttribute("by0")) throw XMLConflictingAttributesException(reader, "by", "by0");
587 if (reader.hasAttribute("by1")) throw XMLConflictingAttributesException(reader, "by", "by1");
588 if (reader.hasAttribute("by2")) throw XMLConflictingAttributesException(reader, "by", "by2");
589 for (int i = 0; i < dim; ++i) result->pre_divisions[i] = *into;
590 } else {
591 for (int i = 0; i < dim; ++i) result->pre_divisions[i] = reader.getAttribute<size_t>(format("by{0}", i), 1);
592 }
593 reader.requireTagEnd();
594 } else if (reader.getNodeName() == "postdiv") {
595 plask::optional<size_t> into = reader.getAttribute<size_t>("by");
596 if (into) {
597 if (reader.hasAttribute("by0")) throw XMLConflictingAttributesException(reader, "by", "by0");
598 if (reader.hasAttribute("by1")) throw XMLConflictingAttributesException(reader, "by", "by1");
599 if (reader.hasAttribute("by2")) throw XMLConflictingAttributesException(reader, "by", "by2");
600 for (int i = 0; i < dim; ++i) result->post_divisions[i] = *into;
601 } else {
602 for (int i = 0; i < dim; ++i) result->post_divisions[i] = reader.getAttribute<size_t>(format("by{0}", i), 1);
603 }
604 reader.requireTagEnd();
605 } else if (reader.getNodeName() == "options") {
606 plask::optional<bool> gradual = reader.getAttribute<bool>("gradual");
607 if (gradual) {
608 if (reader.hasAttribute("gradual0")) throw XMLConflictingAttributesException(reader, "gradual", "gradual0");
609 if (reader.hasAttribute("gradual1")) throw XMLConflictingAttributesException(reader, "gradual", "gradual1");
610 if (reader.hasAttribute("gradual2")) throw XMLConflictingAttributesException(reader, "gradual", "gradual2");
611 result->gradual = (*gradual) ? 7 : 0;
612 } else {
613 for (int i = 0; i < dim; ++i) {
614 result->setGradual(i, reader.getAttribute<bool>(format("gradual{0}", i), true));
615 }
616 }
617 result->setAspect(reader.getAttribute<double>("aspect", result->getAspect()));
618 reader.requireTagEnd();
619 } else
620 result->fromXML(reader, manager);
621 }
622 return result;
623}
624
628
629static RegisterMeshGeneratorReader ordered_dividinggenerator_reader("ordered.divide", readRectangularDivideGenerator<1>);
630static RegisterMeshGeneratorReader rectangular2d_dividinggenerator_reader("rectangular2d.divide",
632static RegisterMeshGeneratorReader rectangular3d_dividinggenerator_reader("rectangular3d.divide",
634
637
638 std::set<std::string> read;
639 while (reader.requireTagOrEnd()) {
640 if (read.find(reader.getNodeName()) != read.end())
641 throw XMLDuplicatedElementException(std::string("<generator>"), reader.getNodeName());
642 read.insert(reader.getNodeName());
643 if (reader.getNodeName() == "steps") {
644 plask::optional<double> small_op =
645 reader.getAttribute<double>("small"); // don't use small since some windows headers: #define small char
646 if (small_op) {
647 if (reader.hasAttribute("small0")) throw XMLConflictingAttributesException(reader, "small", "small0");
648 if (reader.hasAttribute("small1")) throw XMLConflictingAttributesException(reader, "small", "small1");
649 if (reader.hasAttribute("small2")) throw XMLConflictingAttributesException(reader, "small", "small2");
650 for (int i = 0; i < dim; ++i) result->finestep[i] = *small_op;
651 } else
652 for (int i = 0; i < dim; ++i)
653 result->finestep[i] = reader.getAttribute<double>(format("small{:d}", i), result->finestep[i]);
654 plask::optional<double> large = reader.getAttribute<double>("large");
655 if (large) {
656 if (reader.hasAttribute("large0")) throw XMLConflictingAttributesException(reader, "large", "large0");
657 if (reader.hasAttribute("large1")) throw XMLConflictingAttributesException(reader, "large", "large1");
658 if (reader.hasAttribute("large2")) throw XMLConflictingAttributesException(reader, "large", "large2");
659 for (int i = 0; i < dim; ++i) result->maxstep[i] = *large;
660 } else
661 for (int i = 0; i < dim; ++i)
662 result->maxstep[i] = reader.getAttribute<double>(format("large{:d}", i), result->maxstep[i]);
663 plask::optional<double> factor = reader.getAttribute<double>("factor");
664 if (factor) {
665 if (reader.hasAttribute("factor0")) throw XMLConflictingAttributesException(reader, "factor", "factor0");
666 if (reader.hasAttribute("factor1")) throw XMLConflictingAttributesException(reader, "factor", "factor1");
667 if (reader.hasAttribute("factor2")) throw XMLConflictingAttributesException(reader, "factor", "factor2");
668 for (int i = 0; i < dim; ++i) result->factor[i] = *factor;
669 } else
670 for (int i = 0; i < dim; ++i)
671 result->factor[i] = reader.getAttribute<double>(format("factor{:d}", i), result->factor[i]);
672 reader.requireTagEnd();
673 } else if (reader.getNodeName() == "options") {
674 result->setAspect(reader.getAttribute<double>("aspect", result->getAspect()));
675 reader.requireTagEnd();
676 } else
677 result->fromXML(reader, manager);
678 }
679 return result;
680}
681
682static RegisterMeshGeneratorReader ordered_smoothgenerator_reader("ordered.smooth", readRectangularSmoothGenerator<1>);
683static RegisterMeshGeneratorReader rectangular2d_smoothgenerator_reader("rectangular2d.smooth", readRectangularSmoothGenerator<2>);
684static RegisterMeshGeneratorReader rectangular3d_smoothgenerator_reader("rectangular3d.smooth", readRectangularSmoothGenerator<3>);
685
689
692 double split);
693
696 double split);
697
698} // namespace plask