PLaSK library

Loading...
Searching...
No Matches
rectilinear3d.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 "rectilinear3d.hpp"
15
16#include "regular1d.hpp"
17#include "ordered1d.hpp"
18
19 namespace plask {
20
21#define RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(first, second, third) \
22 static std::size_t index_##first##second##third(const RectilinearMesh3D* mesh, std::size_t index0, std::size_t index1, std::size_t index2) { \
23 return index##third + mesh->axis[third]->size() * (index##second + mesh->axis[second]->size() * index##first); \
24 } \
25 static std::size_t index##first##_##first##second##third(const RectilinearMesh3D* mesh, std::size_t mesh_index) { \
26 return mesh_index / mesh->axis[third]->size() / mesh->axis[second]->size(); \
27 } \
28 static std::size_t index##second##_##first##second##third(const RectilinearMesh3D* mesh, std::size_t mesh_index) { \
29 return (mesh_index / mesh->axis[third]->size()) % mesh->axis[second]->size(); \
30 } \
31 static std::size_t index##third##_##first##second##third(const RectilinearMesh3D* mesh, std::size_t mesh_index) { \
32 return mesh_index % mesh->axis[third]->size(); \
33 }
34
35 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(0,1,2)
36 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(0,2,1)
37 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(1,0,2)
38 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(1,2,0)
39 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(2,0,1)
40 RECTILINEAR_MESH_3D_DECLARE_ITERATION_ORDER(2,1,0)
41
42
43 void RectilinearMesh3D::setIterationOrder(IterationOrder iterationOrder) {
44# define RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(o1,o2,o3) \
45 case ORDER_##o1##o2##o3: \
46 index_f = index_##o1##o2##o3; index0_f = index0_##o1##o2##o3; \
47 index1_f = index1_##o1##o2##o3; index2_f = index2_##o1##o2##o3; \
48 major_axis = &axis[o1]; medium_axis = &axis[o2]; minor_axis = &axis[o3]; \
49 break;
50 switch (iterationOrder) {
51 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(0,1,2)
52 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(0,2,1)
53 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(1,0,2)
54 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(1,2,0)
55 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(2,0,1)
56 RECTILINEAR_MESH_3D_CASE_ITERATION_ORDER(2,1,0)
57 default:
58 index_f = index_210; index0_f = index0_210; index1_f = index1_210; index2_f = index2_210;
59 major_axis = &axis[2]; medium_axis = &axis[1]; minor_axis = &axis[0];
60 }
61 fireChanged();
62}
63
64
65 typename RectilinearMesh3D::IterationOrder RectilinearMesh3D::getIterationOrder() const {
66 return this->index_f == decltype(this->index_f)(index_012) ? ORDER_012 :
67 this->index_f == decltype(this->index_f)(index_021) ? ORDER_021 :
68 this->index_f == decltype(this->index_f)(index_102) ? ORDER_102 :
69 this->index_f == decltype(this->index_f)(index_120) ? ORDER_120 :
70 this->index_f == decltype(this->index_f)(index_201) ? ORDER_201 :
71 ORDER_210;
72}
73
74 void RectilinearMesh3D::setOptimalIterationOrder() {
75# define RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(first, second, third) \
76 if (this->axis[third]->size() <= this->axis[second]->size() && this->axis[second]->size() <= this->axis[first]->size()) { \
77 setIterationOrder(ORDER_##first##second##third); return; \
78 }
79 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(0,1,2)
80 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(0,2,1)
81 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(1,0,2)
82 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(1,2,0)
83 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(2,0,1)
84 RECTILINEAR_MESH_3D_DETERMINE_ITERATION_ORDER(2,1,0)
85}
86
87 void RectilinearMesh3D::onAxisChanged(Mesh::Event &e) {
88 assert(!e.isDelete());
89 fireChanged(e.flags());
90}
91
92 RectilinearMesh3D::RectilinearMesh3D(IterationOrder iterationOrder)
93 : axis{plask::make_shared<OrderedAxis>(), plask::make_shared<OrderedAxis>(), plask::make_shared<OrderedAxis>()} {
94 setIterationOrder(iterationOrder);
95 setChangeSignal(this->axis[0]);
96 setChangeSignal(this->axis[1]);
97 setChangeSignal(this->axis[2]);
98}
99
100 RectilinearMesh3D::RectilinearMesh3D(shared_ptr<MeshAxis> mesh0, shared_ptr<MeshAxis> mesh1, shared_ptr<MeshAxis> mesh2, IterationOrder iterationOrder)
101 : axis{std::move(mesh0), std::move(mesh1), std::move(mesh2)}
102{
103 setIterationOrder(iterationOrder);
104 setChangeSignal(this->axis[0]);
105 setChangeSignal(this->axis[1]);
106 setChangeSignal(this->axis[2]);
107}
108
109 void RectilinearMesh3D::reset(shared_ptr<MeshAxis> axis0, shared_ptr<MeshAxis> axis1, shared_ptr<MeshAxis> axis2, RectilinearMesh3D::IterationOrder iterationOrder) {
110 setAxis(0, std::move(axis0), false);
111 setAxis(1, std::move(axis1), false);
112 setAxis(2, std::move(axis2), false);
113 setIterationOrder(iterationOrder);
114}
115
116 RectilinearMesh3D::RectilinearMesh3D(const RectilinearMesh3D &src, bool clone_axes)
117: RectangularMeshBase3D(src),
118 axis{clone_axes ? src.axis[0]->clone() : src.axis[0],
119 clone_axes ? src.axis[1]->clone() : src.axis[1],
120 clone_axes ? src.axis[2]->clone() : src.axis[2]}
121{
122 setIterationOrder(src.getIterationOrder());
123 setChangeSignal(this->axis[0]);
124 setChangeSignal(this->axis[1]);
125 setChangeSignal(this->axis[2]);
126}
127
128 void RectilinearMesh3D::reset(const RectilinearMesh3D &src, bool clone_axes)
129{
130 if (clone_axes)
131 reset(src.axis[0]->clone(), src.axis[1]->clone(), src.axis[2]->clone(), src.getIterationOrder());
132 else
133 reset(src.axis[0], src.axis[1], src.axis[2], src.getIterationOrder());
134}
135
136 RectilinearMesh3D::~RectilinearMesh3D() {
137 unsetChangeSignal(this->axis[0]);
138 unsetChangeSignal(this->axis[1]);
139 unsetChangeSignal(this->axis[2]);
140}
141
142 void RectilinearMesh3D::setAxis(std::size_t axis_nr, shared_ptr<MeshAxis> new_val, bool fireResized) {
143 assert(axis_nr < 3);
144 if (axis[axis_nr] == new_val) return;
145 unsetChangeSignal(axis[axis_nr]);
146 const_cast<shared_ptr<MeshAxis>&>(axis[axis_nr]) = new_val;
147 setChangeSignal(axis[axis_nr]);
148 if (fireResized) this->fireResized();
149}
150
151 BoundaryNodeSet RectilinearMesh3D::createIndex0BoundaryAtLine(std::size_t line_nr_axis0) const {
152 if (this->isChangeSlower(1, 2))
153 return new BoundaryNodeSetImpl<1, 2>(*this, line_nr_axis0);
154 else
155 return new BoundaryNodeSetImpl<2, 1>(*this, line_nr_axis0);
156}
157
158 BoundaryNodeSet RectilinearMesh3D::createBackBoundary() const {
159 return createIndex0BoundaryAtLine(0);
160}
161
162 BoundaryNodeSet RectilinearMesh3D::createFrontBoundary() const {
163 return createIndex0BoundaryAtLine(axis[0]->size()-1);
164}
165
166 BoundaryNodeSet RectilinearMesh3D::createIndex1BoundaryAtLine(std::size_t line_nr_axis1) const {
167 if (this->isChangeSlower(0, 2))
168 return new BoundaryNodeSetImpl<0, 2>(*this, line_nr_axis1);
169 else
170 return new BoundaryNodeSetImpl<2, 0>(*this, line_nr_axis1);
171}
172
173 BoundaryNodeSet RectilinearMesh3D::createLeftBoundary() const {
174 return createIndex1BoundaryAtLine(0);
175}
176
177 BoundaryNodeSet RectilinearMesh3D::createRightBoundary() const {
178 return createIndex1BoundaryAtLine(axis[1]->size()-1);
179}
180
181 BoundaryNodeSet RectilinearMesh3D::createIndex2BoundaryAtLine(std::size_t line_nr_axis2) const {
182 if (this->isChangeSlower(0, 1))
183 return new BoundaryNodeSetImpl<0, 1>(*this, line_nr_axis2);
184 else
185 return new BoundaryNodeSetImpl<1, 0>(*this, line_nr_axis2);
186}
187
188 BoundaryNodeSet RectilinearMesh3D::createBottomBoundary() const {
189 return createIndex2BoundaryAtLine(0);
190}
191
192 BoundaryNodeSet RectilinearMesh3D::createTopBoundary() const {
193 return createIndex2BoundaryAtLine(axis[2]->size()-1);
194}
195
196 BoundaryNodeSet RectilinearMesh3D::createIndex0BoundaryAtLine(std::size_t line_nr_axis0, std::size_t index1Begin, std::size_t index1End, std::size_t index2Begin, std::size_t index2End) const {
197 if (index1Begin >= index1End || index2Begin >= index2End)
198 return new EmptyBoundaryImpl();
199 if (isChangeSlower(1, 2))
200 return new BoundaryNodeSetRangeImpl<1, 2>(*this, line_nr_axis0, index1Begin, index2Begin, index1End, index2End);
201 else
202 return new BoundaryNodeSetRangeImpl<2, 1>(*this, line_nr_axis0, index1Begin, index2Begin, index2End, index1End);
203}
204
205 BoundaryNodeSet RectilinearMesh3D::createBackOfBoundary(const Box3D &box) const {
206 std::size_t line, begInd1, endInd1, begInd2, endInd2;
207 if (details::getLineLo(line, *axis[0], box.lower.c0, box.upper.c0) &&
208 details::getIndexesInBounds(begInd1, endInd1, *axis[1], box.lower.c1, box.upper.c1) &&
209 details::getIndexesInBounds(begInd2, endInd2, *axis[2], box.lower.c2, box.upper.c2))
210 return createIndex0BoundaryAtLine(line, begInd1, endInd1, begInd2, endInd2);
211 else
212 return new EmptyBoundaryImpl();
213}
214
215 BoundaryNodeSet RectilinearMesh3D::createFrontOfBoundary(const Box3D &box) const {
216 std::size_t line, begInd1, endInd1, begInd2, endInd2;
217 if (details::getLineHi(line, *axis[0], box.lower.c0, box.upper.c0) &&
218 details::getIndexesInBounds(begInd1, endInd1, *axis[1], box.lower.c1, box.upper.c1) &&
219 details::getIndexesInBounds(begInd2, endInd2, *axis[2], box.lower.c2, box.upper.c2))
220 return createIndex0BoundaryAtLine(line, begInd1, endInd1, begInd2, endInd2);
221 else
222 return new EmptyBoundaryImpl();
223}
224
225 BoundaryNodeSet RectilinearMesh3D::createIndex1BoundaryAtLine(std::size_t line_nr_axis1, std::size_t index0Begin, std::size_t index0End, std::size_t index2Begin, std::size_t index2End) const
226{
227 if (index0Begin >= index0End || index2Begin >= index2End)
228 return new EmptyBoundaryImpl();
229 if (isChangeSlower(0, 2))
230 return new BoundaryNodeSetRangeImpl<0, 2>(*this, index0Begin, line_nr_axis1, index2Begin, index0End, index2End);
231 else
232 return new BoundaryNodeSetRangeImpl<2, 0>(*this, index0Begin, line_nr_axis1, index2Begin, index2End, index0End);
233}
234
235 BoundaryNodeSet RectilinearMesh3D::createLeftOfBoundary(const Box3D &box) const {
236 std::size_t line, begInd0, endInd0, begInd2, endInd2;
237 if (details::getLineLo(line, *axis[1], box.lower.c1, box.upper.c1) &&
238 details::getIndexesInBounds(begInd0, endInd0, *axis[0], box.lower.c0, box.upper.c0) &&
239 details::getIndexesInBounds(begInd2, endInd2, *axis[2], box.lower.c2, box.upper.c2))
240 return createIndex1BoundaryAtLine(line, begInd0, endInd0, begInd2, endInd2);
241 else
242 return new EmptyBoundaryImpl();
243}
244
245 BoundaryNodeSet RectilinearMesh3D::createRightOfBoundary(const Box3D &box) const {
246 std::size_t line, begInd0, endInd0, begInd2, endInd2;
247 if (details::getLineHi(line, *axis[1], box.lower.c1, box.upper.c1) &&
248 details::getIndexesInBounds(begInd0, endInd0, *axis[0], box.lower.c0, box.upper.c0) &&
249 details::getIndexesInBounds(begInd2, endInd2, *axis[2], box.lower.c2, box.upper.c2))
250 return createIndex1BoundaryAtLine(line, begInd0, endInd0, begInd2, endInd2);
251 else
252 return new EmptyBoundaryImpl();
253}
254
255 BoundaryNodeSet RectilinearMesh3D::createIndex2BoundaryAtLine(std::size_t line_nr_axis2, std::size_t index0Begin, std::size_t index0End, std::size_t index1Begin, std::size_t index1End) const
256{
257 if (index0Begin >= index0End || index1Begin >= index1End)
258 return new EmptyBoundaryImpl();
259 if (isChangeSlower(0, 1))
260 return new BoundaryNodeSetRangeImpl<0, 1>(*this, index0Begin, index1Begin, line_nr_axis2, index0End, index1End);
261 else
262 return new BoundaryNodeSetRangeImpl<1, 0>(*this, index0Begin, index1Begin, line_nr_axis2, index1End, index0End);
263}
264
265 BoundaryNodeSet RectilinearMesh3D::createBottomOfBoundary(const Box3D &box) const {
266 std::size_t line, begInd0, endInd0, begInd1, endInd1;
267 if (details::getLineLo(line, *axis[2], box.lower.c2, box.upper.c2) &&
268 details::getIndexesInBounds(begInd0, endInd0, *axis[0], box.lower.c0, box.upper.c0) &&
269 details::getIndexesInBounds(begInd1, endInd1, *axis[1], box.lower.c1, box.upper.c1))
270 return createIndex2BoundaryAtLine(line, begInd0, endInd0, begInd1, endInd1);
271 else
272 return new EmptyBoundaryImpl();
273}
274
275 BoundaryNodeSet RectilinearMesh3D::createTopOfBoundary(const Box3D &box) const {
276 std::size_t line, begInd0, endInd0, begInd1, endInd1;
277 if (details::getLineHi(line, *axis[2], box.lower.c2, box.upper.c2) &&
278 details::getIndexesInBounds(begInd0, endInd0, *axis[0], box.lower.c0, box.upper.c0) &&
279 details::getIndexesInBounds(begInd1, endInd1, *axis[1], box.lower.c1, box.upper.c1))
280 return createIndex2BoundaryAtLine(line, begInd0, endInd0, begInd1, endInd1);
281 else
282 return new EmptyBoundaryImpl();
283}
284
285} // namespace plask