PLaSK library

Loading...
Searching...
No Matches
edge.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#ifndef PLASK__GEOMETRY_EDGE_H
15#define PLASK__GEOMETRY_EDGE_H
16
17#include "../material/db.hpp"
18#include "primitives.hpp"
19
20#include "../log/log.hpp"
21
22 namespace plask {
23
24 namespace edge {
25
29 struct PLASK_API Strategy {
30
32 enum Type {
33 DEFAULT,
34 SIMPLE,
35 EXTEND,
36 PERIODIC,
37 MIRROR
38 };
39
40 virtual ~Strategy() {}
41
43 virtual Type type() const = 0;
44
52 virtual void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const = 0;
53
61 virtual void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const = 0;
62
70 virtual bool canMoveOutsideBoundingBox() const;
71
72 /*
73 * Check if this strategy can coexists on opposite side with oppositeStrategy.
74 */
75 /*virtual bool canCoexistsWith(const Strategy& oppositeStrategy) const {
76 return true;
77 }*/
78
79 /*void ensureCanCoexists(const Strategy& oppositeStrategy) const {
80 if (!canCoexistsWith(oppositeStrategy) || !oppositeStrategy.canCoexistsWith(*this))
81 throw Exception("edges \"{0}\" and \"{1}\" can't be used on opposite sides.", this->str(), oppositeStrategy.str());
82 }*/
83
88 virtual Strategy* clone() const = 0;
89
94 virtual std::string str() const = 0;
95
104 static Strategy* fromStr(const std::string& str, const MaterialsDB& materialsDB = MaterialsDB::getDefault());
105
114 static std::unique_ptr<Strategy> fromStrUnique(const std::string& str, const MaterialsDB& materialsDB = MaterialsDB::getDefault()) {
115 return std::unique_ptr<Strategy>(fromStr(str, materialsDB));
116 }
117};
118
124 struct PLASK_API UniversalStrategy: public Strategy {
125 UniversalStrategy* clone() const override = 0;
126};
127
131 struct PLASK_API Null: public UniversalStrategy {
132 Type type() const override { return DEFAULT; }
133 void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
134 void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
135 Null* clone() const override;
136 std::string str() const override;
137};
138
142 struct PLASK_API SimpleMaterial: public UniversalStrategy {
143
147 shared_ptr<Material> material;
148
153 SimpleMaterial(const shared_ptr<Material>& material): material(material) {}
154
155 Type type() const override { return SIMPLE; }
156
157 void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
158 void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
159
160 SimpleMaterial* clone() const override;
161
162 std::string str() const override;
163
164};
165
169 struct PLASK_API Extend: public UniversalStrategy {
170
171 Type type() const override { return EXTEND; }
172
173 void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
174 void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
175
176 Extend* clone() const override;
177
178 std::string str() const override;
179
180};
181
185 struct PLASK_API Periodic: public Strategy {
186
187 Type type() const override { return PERIODIC; }
188
189 void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
190 void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
191
192 Periodic* clone() const override;
193
194 std::string str() const override;
195
196 /*virtual bool canCoexistsWith(const Strategy& oppositeStrategy) const {
197 return oppositeStrategy.type() == Strategy::PERIODIC;
198 }*/
199};
200
201 struct PLASK_API Mirror: public Strategy {
202
203 Type type() const override { return MIRROR; }
204
205 void applyLo(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
206 void applyHi(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material, const Strategy* opposite) const override;
207
208 bool canMoveOutsideBoundingBox() const override;
209
210 Mirror* clone() const override;
211
212 std::string str() const override;
213
214};
215
223 template <int direction, typename StrategyType = Strategy>
224 class PLASK_API StrategyHolder {
225
226 StrategyType* strategy;
227
228 public:
229 StrategyHolder(const StrategyType& strategy = Null()): strategy(strategy.clone()) {}
230
231 template <int adirection>
232 StrategyHolder(const StrategyHolder<adirection, StrategyType>& strategyHolder): strategy(strategyHolder.strategy->clone()) {}
233
234 ~StrategyHolder() { delete strategy; }
235
236 const StrategyType& getStrategy() const { return *strategy; }
237
238 void setStrategy(const StrategyType& strategy) {
239 if (this->strategy == &strategy) return; //self-assignment protect
240 delete this->strategy;
241 this->strategy = strategy.clone();
242 }
243
244 std::string str() const { return strategy->str(); }
245
246 StrategyHolder<direction, StrategyType>& operator=(const StrategyType& strategy) { setStrategy(strategy); return *this; }
247
248 template <int adirection>
249 StrategyHolder<direction, StrategyType>& operator=(const StrategyHolder<adirection, StrategyType>& strategyHolder) {
250 setStrategy(strategyHolder.getStrategy());
251 return *this;
252 }
253
254 /*inline void apply(double bbox_lo, double bbox_hi, double& p, shared_ptr<Material>& result_material) const {
255 strategy->apply(bbox_lo, bbox_hi, p, result_material);
256 }*/
257
258 template <int dims>
259 inline void applyLo(const typename Primitive<dims>::Box& bbox, Vec<dims, double>& p, shared_ptr<Material>& result_material, const Strategy* opposite) const {
260 strategy->applyLo(bbox.lower[direction], bbox.upper[direction], p[direction], result_material, opposite);
261 }
262
263 template <int dims>
264 inline void applyHi(const typename Primitive<dims>::Box& bbox, Vec<dims, double>& p, shared_ptr<Material>& result_material, const Strategy* opposite) const {
265 strategy->applyHi(bbox.lower[direction], bbox.upper[direction], p[direction], result_material, opposite);
266 }
267
268 template <int dims>
269 inline void applyIfLo(const typename Primitive<dims>::Box& bbox, Vec<dims, double>& p, shared_ptr<Material>& result_material, const Strategy* opposite) const {
270 if (p[direction] < bbox.lower[direction])
271 applyLo(bbox, p, result_material, opposite);
272 }
273
274 template <int dims>
275 inline void applyIfHi(const typename Primitive<dims>::Box& bbox, Vec<dims, double>& p, shared_ptr<Material>& result_material, const Strategy* opposite) const {
276 if (p[direction] > bbox.upper[direction])
277 applyHi(bbox, p, result_material, opposite);
278 }
279
280};
281
287 template <int direction, typename StrategyType = Strategy>
288 class PLASK_API StrategyPairHolder {
290 StrategyHolder<direction, StrategyType> strategy_lo, strategy_hi;
291
293 bool reverseCallingOrder;
294
295 void setOrder(const StrategyType& strategy_lo, const StrategyType& strategy_hi) {
296 if ((strategy_lo.type() == Strategy::PERIODIC || strategy_hi.type() == Strategy::PERIODIC) &&
297 strategy_lo.type() != Strategy::MIRROR && strategy_hi.type() != Strategy::MIRROR &&
298 strategy_lo.type() != strategy_hi.type()
299 ) writelog(LOG_WARNING, "Periodic and non-periodic edges used on opposite sides of one direction.");
300 // strategy_lo.ensureCanCoexists(strategy_hi);
301 if (strategy_hi.canMoveOutsideBoundingBox()) {
302 if (strategy_lo.canMoveOutsideBoundingBox())
303 throw Exception("edges on both sides can move point outside bounding box.");
304 reverseCallingOrder = true;
305 } else
306 reverseCallingOrder = false;
307 }
308
309 public:
310
311 StrategyPairHolder(): reverseCallingOrder(false) {}
312
313 void setStrategies(const StrategyType& strategy_lo, const StrategyType& strategy_hi) {
314 setOrder(strategy_lo, strategy_hi);
315 this->strategy_lo = strategy_lo;
316 this->strategy_hi = strategy_hi;
317 }
318
319 void setBoth(const StrategyType& s) { setStrategies(s, s); }
320
321 void setLo(const StrategyType& strategy_lo) {
322 setOrder(strategy_lo, getHi());
323 this->strategy_lo = strategy_lo;
324 }
325
326 const StrategyType& getLo() const {
327 return strategy_lo.getStrategy();
328 }
329
330 void setHi(const StrategyType& strategy_hi) {
331 setOrder(getLo(), strategy_hi);
332 this->strategy_hi = strategy_hi;
333 }
334
335 const StrategyType& getHi() const {
336 return strategy_hi.getStrategy();
337 }
338
344 void set(bool setNewHi, const StrategyType& strategy) {
345 if (setNewHi) setHi(strategy); else setLo(strategy);
346 }
347
353 const StrategyType& get(bool _getHi) const {
354 return _getHi ? getHi() : getLo();
355 }
356
357 template <int dims>
358 inline void apply(const typename Primitive<dims>::Box& bbox, Vec<dims, double>& p, shared_ptr<Material>& result_material) const {
359 if (reverseCallingOrder) {
360 strategy_hi.applyIfHi(bbox, p, result_material, &strategy_lo.getStrategy());
361 if (result_material) return;
362 strategy_lo.applyIfLo(bbox, p, result_material, &strategy_hi.getStrategy());
363 } else {
364 strategy_lo.applyIfLo(bbox, p, result_material, &strategy_hi.getStrategy());
365 if (result_material) return;
366 strategy_hi.applyIfHi(bbox, p, result_material, &strategy_lo.getStrategy());
367 }
368 }
369
370 bool isSymmetric() const { return strategy_lo.type() == Strategy::MIRROR || strategy_hi.type() == Strategy::MIRROR; }
371
372 bool isPeriodic() const { return strategy_lo.type() == Strategy::PERIODIC && strategy_hi.type() == Strategy::PERIODIC; }
373};
374
375} // namespace edge
376
377} // namespace plask
378
379#endif // PLASK__GEOMETRY_EDGE_H