ViennaSHE 1.3.0
Free open-source semiconductor device simulator using spherical harmonics expansions techniques.
generate_device.hpp
Go to the documentation of this file.
1#ifndef VIENNASHE_UTIL_GENERATE_DEVICE_HPP
2#define VIENNASHE_UTIL_GENERATE_DEVICE_HPP
3
4/* ============================================================================
5 Copyright (c) 2011-2022, Institute for Microelectronics,
6 Institute for Analysis and Scientific Computing,
7 TU Wien.
8
9 -----------------
10 ViennaSHE - The Vienna Spherical Harmonics Expansion Boltzmann Solver
11 -----------------
12
13 http://viennashe.sourceforge.net/
14
15 License: MIT (X11), see file LICENSE in the base directory
16=============================================================================== */
17
18// std
19#include <iostream>
20#include <sstream>
21#include <string>
22#include <stdexcept>
23#include <vector>
24
25// viennagrid
26#include "viennagrid/mesh/mesh.hpp"
27#include "viennagrid/mesh/element_creation.hpp"
28#include "viennagrid/topology/line.hpp"
29#include "viennagrid/topology/quadrilateral.hpp"
30
31// viennashe
32#include "viennashe/log/log.hpp"
34
35
40namespace viennashe
41{
42 namespace util
43 {
44
45
48 {
49 public:
51 {
52 public:
54 : start_x_(0.0),
55 start_y_(0.0),
56 len_x_(0.0),
57 len_y_(0.0),
58 points_x_(1),
59 points_y_(1) {}
60
61 segment_description(double start_x, double len_x, unsigned long points_x)
62 : start_x_(start_x),
63 start_y_(0.0),
64 len_x_(len_x),
65 len_y_(0.0),
66 points_x_(points_x),
67 points_y_(1) {}
68
69 segment_description(double start_x, double start_y, double len_x, double len_y, unsigned long points_x, unsigned long points_y)
70 : start_x_(start_x),
71 start_y_(start_y),
72 len_x_(len_x),
73 len_y_(len_y),
74 points_x_(points_x),
75 points_y_(points_y) {}
76
77 double get_start_x() const { return start_x_; }
78 double get_start_y() const { return start_y_; }
79
80 double get_length_x() const { return len_x_; }
81 double get_length_y() const { return len_y_; }
82
83 unsigned long get_points_x() const { return points_x_; }
84 unsigned long get_points_y() const { return points_y_; }
85
86 private:
87 double start_x_;
88 double start_y_;
89
90 double len_x_;
91 double len_y_;
92
93 unsigned long points_x_;
94 unsigned long points_y_;
95 };
96
98
99 void clear() { segment_descs_.clear(); }
100
101 void add_segment(double start_x, double start_y, double len_x, double len_y, unsigned long points_x, unsigned long points_y)
102 {
103 segment_descs_.push_back(segment_description(start_x, start_y, len_x, len_y, points_x, points_y));
104 }
105
106 void add_segment(double start_x, double len_x, unsigned long points_x,
107 double start_y, double len_y, unsigned long points_y)
108 {
109 segment_descs_.push_back(segment_description(start_x, start_y, len_x, len_y, points_x, points_y));
110 }
111
112 void add_segment(double start_x, double len_x, unsigned long points_x)
113 {
114 add_segment(start_x, 0.0, len_x, 0.0, points_x, 1);
115 }
116
117 std::size_t size() const { return segment_descs_.size(); }
118 segment_description const & at(std::size_t i) const { return segment_descs_.at(i); }
119
120 private:
121 std::vector<segment_description> segment_descs_;
122 };
123
124 namespace detail
125 {
126 //
127 // 1d generation
128 //
129
136 template <typename MeshT, typename SegmentationT>
137 void generate_device_impl(MeshT & mesh,
138 SegmentationT & segmentation,
139 device_generation_config const & conf,
140 viennagrid::simplex_tag<1>
141 )
142 {
143 typedef typename viennagrid::result_of::point<MeshT>::type PointType;
144 typedef typename viennagrid::result_of::vertex<MeshT>::type VertexType;
145 typedef typename viennagrid::result_of::cell<MeshT>::type CellType;
146
147 typedef typename viennagrid::result_of::cell_tag<MeshT>::type CellTag;
148
149 typedef typename viennagrid::result_of::handle<MeshT, viennagrid::vertex_tag>::type VertexHandleType;
150
151 typedef typename device_generation_config::segment_description SegmentDescriptionType;
152
153
154 //
155 // Prepare vertices at segment boundaries (note that this is O(N^2) with respect to the number of segments N. Not expected to hurt in practice, though...):
156 //
157 std::vector<PointType> segment_boundary_points;
158
159 std::size_t total_points = 1;
160 for (std::size_t i=0; i<conf.size(); ++i)
161 {
162 SegmentDescriptionType const & seg_desc = conf.at(i);
163
164 assert(seg_desc.get_points_x() > 1 && bool("Logic error: Not enough points in x-direction provided for segment"));
165 assert(seg_desc.get_points_y() == 1 && bool("Logic error: Provided two-dimensional grid description for one-dimensional mesh"));
166 assert(seg_desc.get_length_x() > 0.0 && bool("Logic error: x-coordinate is degenerate in device generation."));
167
168 double distance_tolerance = 1e-10 * seg_desc.get_length_x();
169
170 PointType p0(seg_desc.get_start_x());
171 PointType p1(seg_desc.get_start_x() + seg_desc.get_length_x());
172
173 bool insert_p0 = true;
174 bool insert_p1 = true;
175
176 for (std::size_t j=0; j<segment_boundary_points.size(); ++j)
177 {
178 if (viennagrid::norm_2(p0 - segment_boundary_points[j]) < distance_tolerance )
179 insert_p0 = false;
180 if (viennagrid::norm_2(p1 - segment_boundary_points[j]) < distance_tolerance )
181 insert_p1 = false;
182 }
183
184 if (insert_p0)
185 segment_boundary_points.push_back(p0);
186 if (insert_p1)
187 segment_boundary_points.push_back(p1);
188
189 total_points += seg_desc.get_points_x() - 1;
190 }
191
192 //
193 // Set up the vertices:
194 //
195 log::info<log_generate_device>() << "* generate_device(): Setting up vertices..." << std::endl;
196
197 std::vector<int> segment_boundary_ids(segment_boundary_points.size(), -1);
198
199 std::vector< std::vector<int> > segment_vertex_ids(conf.size()); // store the global vertex ID for each segment to save lookups later on.
200
201 int vertex_counter = 0;
202
203 // iterate over all segments and insert points if not already inserted in mesh. Store vertex ID for each segment.
204 for (std::size_t i=0; i<conf.size(); ++i)
205 {
206 SegmentDescriptionType const & seg_desc = conf.at(i);
207
208 segment_vertex_ids[i].resize(seg_desc.get_points_x());
209
210 double distance_tolerance = 1e-10 * seg_desc.get_length_x();
211
212 // Add get_points_x() points in the segment to the mesh if they haven't been added yet (check segment boundaries)
213 for (std::size_t j = 0; j<seg_desc.get_points_x(); ++j)
214 {
215 PointType candidate_point(seg_desc.get_start_x() + seg_desc.get_length_x() * static_cast<double>(j) / (static_cast<double>(seg_desc.get_points_x()) - 1.0));
216
217 // check segment_boundary points, since they might be in the mesh already:
218 if (j == 0 || j == seg_desc.get_points_x() - 1)
219 {
220 // find matching segment boundary point:
221 bool found = false;
222 for (std::size_t k=0; k<segment_boundary_points.size(); ++k)
223 {
224 if (viennagrid::norm_2(candidate_point - segment_boundary_points[k]) < distance_tolerance )
225 {
226 if (segment_boundary_ids[k] == -1) // point hasn't been added yet, so add now:
227 {
228 viennagrid::make_vertex_with_id(mesh, typename VertexType::id_type(vertex_counter), candidate_point);
229 segment_boundary_ids[k] = vertex_counter++;
230 }
231 segment_vertex_ids[i][j] = segment_boundary_ids[k];
232 found = true;
233 break;
234 }
235 }
236 assert(found && bool("Logic error: Could not find matching boundary point"));
237 (void)found; //silence unused variable warning in release mode
238 }
239 else
240 {
241 viennagrid::make_vertex_with_id(mesh, typename VertexType::id_type(vertex_counter), candidate_point);
242 segment_vertex_ids[i][j] = vertex_counter++;
243 }
244 }
245 }
246
247
248 //
249 // Set up cells:
250 //
251 log::info<log_generate_device>() << "* generate_device(): Setting up cells..." << std::endl;
252 viennagrid::static_array<VertexHandleType, viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num> cell_vertex_handles;
253 int cell_id = 0;
254 for (std::size_t i=0; i<conf.size(); ++i)
255 {
256 SegmentDescriptionType const & seg_desc = conf.at(i);
257
258 for (std::size_t j = 0; j<seg_desc.get_points_x() - 1; ++j)
259 {
260 cell_vertex_handles[0] = viennagrid::vertices(mesh).handle_at(static_cast<std::size_t>(segment_vertex_ids[i][j]));
261 cell_vertex_handles[1] = viennagrid::vertices(mesh).handle_at(static_cast<std::size_t>(segment_vertex_ids[i][j+1]));
262
263 viennagrid::make_element_with_id<CellType>(segmentation[static_cast<int>(i)],
264 cell_vertex_handles.begin(),
265 cell_vertex_handles.end(),
266 typename CellType::id_type(cell_id++));
267 }
268 }
269
270 log::info<log_generate_device>() << "* generate_device(): DONE" << std::endl;
271 }
272
275 template <typename MeshType>
276 void generate_device_impl(MeshType & mesh,
277 device_generation_config const & conf,
278 viennagrid::hypercube_tag<1>
279 )
280 {
281 generate_device_impl(mesh, conf, viennagrid::simplex_tag<1>());
282 }
283
284
285 //
286 // 2d generation
287 //
288
295 template <typename MeshT, typename SegmentationT>
296 void generate_device_impl(MeshT & mesh,
297 SegmentationT & segmentation,
298 device_generation_config const & conf,
299 viennagrid::quadrilateral_tag
300 )
301 {
302 typedef typename viennagrid::result_of::point<MeshT>::type PointType;
303 typedef typename viennagrid::result_of::vertex<MeshT>::type VertexType;
304 typedef typename viennagrid::result_of::cell<MeshT>::type CellType;
305
306 typedef typename viennagrid::result_of::cell_tag<MeshT>::type CellTag;
307
308 typedef typename viennagrid::result_of::handle<MeshT, viennagrid::vertex_tag>::type VertexHandleType;
309
310 typedef typename device_generation_config::segment_description SegmentDescriptionType;
311
312
313 //
314 // Prepare vertices at segment boundaries (note that this is O(N^2) with respect to the number of segments N. Not expected to hurt in practice, though...):
315 //
316 std::vector<PointType> segment_boundary_points;
317
318 for (std::size_t seg_idx=0; seg_idx<conf.size(); ++seg_idx)
319 {
320 SegmentDescriptionType const & seg_desc = conf.at(seg_idx);
321
322 assert(seg_desc.get_points_x() > 1 && bool("Logic error: Not enough points in x-direction provided for segment"));
323 assert(seg_desc.get_points_y() > 1 && bool("Logic error: Not enough points in y-direction provided for segment"));
324 assert(seg_desc.get_length_x() > 0.0 && bool("Logic error: x-coordinate is degenerate in device generation."));
325 assert(seg_desc.get_length_y() > 0.0 && bool("Logic error: y-coordinate is degenerate in device generation."));
326
327 double distance_tolerance = 1e-10 * std::min(seg_desc.get_length_x(), seg_desc.get_length_y());
328
329 for (std::size_t j=0; j<seg_desc.get_points_y(); ++j)
330 {
331 for (std::size_t i=0; i<seg_desc.get_points_x(); ++i)
332 {
333 if (i == 0 || j == 0 || i == seg_desc.get_points_x() - 1 || j == seg_desc.get_points_y() - 1)
334 {
335 double inc_x = seg_desc.get_length_x() / static_cast<double>(seg_desc.get_points_x() - 1);
336 double inc_y = seg_desc.get_length_y() / static_cast<double>(seg_desc.get_points_y() - 1);
337
338 PointType p(seg_desc.get_start_x() + i * inc_x,
339 seg_desc.get_start_y() + j * inc_y);
340
341 bool insert_p = true;
342
343 for (std::size_t k=0; k<segment_boundary_points.size(); ++k)
344 {
345 if (viennagrid::norm_2(p - segment_boundary_points[k]) < distance_tolerance)
346 {
347 insert_p = false;
348 break;
349 }
350 }
351
352 if (insert_p)
353 segment_boundary_points.push_back(p);
354 }
355 }
356 }
357 }
358
359 //
360 // Set up the vertices:
361 //
362 log::info<log_generate_device>() << "* generate_device(): Setting up vertices..." << std::endl;
363
364 std::vector<long> segment_boundary_ids(segment_boundary_points.size(), -1);
365
366 std::vector< std::vector< std::vector<long> > > segment_vertex_ids(conf.size()); // store the global vertex ID for each segment to save lookups later on.
367
368 int vertex_counter = 0;
369
370 // iterate over all segments and insert points if not already inserted in mesh. Store vertex ID for each segment.
371 for (std::size_t seg_idx=0; seg_idx<conf.size(); ++seg_idx)
372 {
373 SegmentDescriptionType const & seg_desc = conf.at(seg_idx);
374
375 segment_vertex_ids[seg_idx].resize(seg_desc.get_points_x());
376
377 double distance_tolerance = 1e-10 * seg_desc.get_length_x();
378
379 for (std::size_t i = 0; i<seg_desc.get_points_x(); ++i)
380 segment_vertex_ids[seg_idx][i].resize(seg_desc.get_points_y());
381
382 // Add get_points_x() points in the segment to the mesh if they haven't been added yet (check segment boundaries)
383 double inc_x = seg_desc.get_length_x() / static_cast<double>(seg_desc.get_points_x() - 1);
384 double inc_y = seg_desc.get_length_y() / static_cast<double>(seg_desc.get_points_y() - 1);
385
386 for (std::size_t j = 0; j<seg_desc.get_points_y(); ++j)
387 {
388 for (std::size_t i = 0; i<seg_desc.get_points_x(); ++i)
389 {
390 PointType p(seg_desc.get_start_x() + i * inc_x,
391 seg_desc.get_start_y() + j * inc_y);
392
393 // check segment_boundary points, since they might be in the mesh already:
394 if (i == 0 || j == 0 || i == seg_desc.get_points_x() - 1 || j == seg_desc.get_points_y() - 1)
395 {
396 // find matching segment boundary point:
397 bool found = false;
398 for (std::size_t k=0; k<segment_boundary_points.size(); ++k)
399 {
400 if (viennagrid::norm_2(p - segment_boundary_points[k]) < distance_tolerance )
401 {
402 if (segment_boundary_ids[k] == -1) // point hasn't been added yet, so add now:
403 {
404 viennagrid::make_vertex_with_id(mesh, typename VertexType::id_type(vertex_counter), p);
405 segment_boundary_ids[k] = vertex_counter++;
406 }
407 segment_vertex_ids[seg_idx][i][j] = segment_boundary_ids[k];
408 found = true;
409 break;
410 }
411 }
412 assert(found && bool("Logic error: Could not find matching boundary point"));
413 (void)found; //silence unused variable warning in release mode
414 }
415 else
416 {
417 viennagrid::make_vertex_with_id(mesh, typename VertexType::id_type(vertex_counter), p);
418 segment_vertex_ids[seg_idx][i][j] = vertex_counter++;
419 }
420 }
421 }
422 }
423
424
425 //
426 // Set up cells:
427 //
428 log::info<log_generate_device>() << "* generate_device(): Setting up cells..." << std::endl;
429 viennagrid::static_array<VertexHandleType, viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num> cell_vertex_handles;
430 int cell_id = 0;
431 for (std::size_t seg_idx=0; seg_idx<conf.size(); ++seg_idx)
432 {
433 SegmentDescriptionType const & seg_desc = conf.at(seg_idx);
434
435 for (std::size_t j = 0; j<seg_desc.get_points_y() - 1; ++j)
436 {
437 for (std::size_t i = 0; i<seg_desc.get_points_x() - 1; ++i)
438 {
439 cell_vertex_handles[0] = viennagrid::vertices(mesh).handle_at(std::size_t(segment_vertex_ids[seg_idx][i][j]));
440 cell_vertex_handles[1] = viennagrid::vertices(mesh).handle_at(std::size_t(segment_vertex_ids[seg_idx][i+1][j]));
441 cell_vertex_handles[2] = viennagrid::vertices(mesh).handle_at(std::size_t(segment_vertex_ids[seg_idx][i][j+1]));
442 cell_vertex_handles[3] = viennagrid::vertices(mesh).handle_at(std::size_t(segment_vertex_ids[seg_idx][i+1][j+1]));
443
444 viennagrid::make_element_with_id<CellType>(segmentation[static_cast<int>(seg_idx)],
445 cell_vertex_handles.begin(),
446 cell_vertex_handles.end(),
447 typename CellType::id_type(cell_id++));
448 }
449 }
450 }
451
452 log::info<log_generate_device>() << "* generate_device(): DONE" << std::endl;
453 }
454
455
456 } // namespace detail
457
458 //
459 // Public interface
460 //
461
468 template <typename MeshT, typename SegmentationT>
469 void generate_device(MeshT & mesh, SegmentationT & seg, device_generation_config const & conf)
470 {
471 viennashe::util::detail::generate_device_impl(mesh, seg, conf, typename viennagrid::result_of::cell_tag<MeshT>::type());
472 }
473
481 template < typename IndexT = unsigned long>
483 {
484 device_from_array_generator( double ** vertices,
485 IndexT ** cells,
486 IndexT * segmentation,
487 IndexT num_vertices,
488 IndexT num_cells)
489 : vertices_(vertices), cells_(cells), segmentation_(segmentation),
490 num_vertices_(num_vertices), num_cells_(num_cells)
491 { }
492
494 template < typename MeshT, typename SegmentationT >
495 void operator()(MeshT & mesh, SegmentationT & seg) const
496 {
497 typedef typename viennagrid::result_of::point<MeshT>::type PointType;
498 typedef typename viennagrid::result_of::vertex<MeshT>::type VertexType;
499 typedef typename viennagrid::result_of::cell<MeshT>::type CellType;
500
501 typedef typename viennagrid::result_of::cell_tag<MeshT>::type CellTag;
502
503 typedef typename viennagrid::result_of::handle<MeshT, viennagrid::vertex_tag>::type VertexHandleType;
504
505 for (int i = 0; i < static_cast<int>(num_vertices_); ++i)
506 {
507 PointType p;
508 for (std::size_t j = 0; j < (std::size_t )PointType::dim; ++j)
509 p[j] = vertices_[i][j];
510
511 viennagrid::make_vertex_with_id( mesh, typename VertexType::id_type(i), p );
512 }
513
514 for (int i = 0; i < static_cast<int>(num_cells_); ++i )
515 {
516 viennagrid::static_array<VertexHandleType, viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num> cell_vertex_handles;
517 for (std::size_t j=0; j < (std::size_t )viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num; ++j)
518 {
519 cell_vertex_handles[j] = viennagrid::vertices(mesh).handle_at(cells_[i][j]);
520 }
521
522 IndexT seg_id = segmentation_[i];
523 if (segmentation_ != 0) seg_id = segmentation_[i];
524
525 viennagrid::make_element_with_id<CellType>(seg[static_cast<int>(seg_id)],
526 cell_vertex_handles.begin(),
527 cell_vertex_handles.end(),
528 typename CellType::id_type(i));
529 }
530 }
531
532 private:
533 double ** vertices_;
534 IndexT ** cells_;
535 IndexT * segmentation_;
536 IndexT num_vertices_;
537 IndexT num_cells_;
538
539 };
540
548 template < typename IndexT = unsigned long>
550 {
552 IndexT * cells,
553 IndexT * segmentation,
554 IndexT num_vertices,
555 IndexT num_cells)
556 : vertices_(vertices), cells_(cells), segmentation_(segmentation),
557 num_vertices_(num_vertices), num_cells_(num_cells)
558 { }
559
561 template < typename MeshT, typename SegmentationT >
562 void operator()(MeshT & mesh, SegmentationT & seg) const
563 {
564 typedef typename viennagrid::result_of::point<MeshT>::type PointType;
565 typedef typename viennagrid::result_of::vertex<MeshT>::type VertexType;
566 typedef typename viennagrid::result_of::cell<MeshT>::type CellType;
567
568 typedef typename viennagrid::result_of::cell_tag<MeshT>::type CellTag;
569
570 typedef typename viennagrid::result_of::handle<MeshT, viennagrid::vertex_tag>::type VertexHandleType;
571
572 const std::size_t dim = (std::size_t )PointType::dim;
573 for (int i = 0; i < static_cast<int>(num_vertices_); ++i)
574 {
575 PointType p;
576 for (std::size_t j = 0; j < dim; ++j)
577 p[j] = vertices_[std::size_t(i)*dim + j];
578
579 viennagrid::make_vertex_with_id( mesh, typename VertexType::id_type(i), p );
580 }
581
582 for (int i = 0; i < static_cast<int>(num_cells_); ++i )
583 {
584 const std::size_t nen = viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num;
585
586 viennagrid::static_array<VertexHandleType, viennagrid::boundary_elements<CellTag, viennagrid::vertex_tag>::num> cell_vertex_handles;
587 for (std::size_t j = 0; j < nen; ++j)
588 {
589 cell_vertex_handles[j] = viennagrid::vertices(mesh).handle_at(cells_[std::size_t(i)*nen + j]);
590 }
591
592 IndexT seg_id = 0;
593 if (segmentation_ != 0) seg_id = segmentation_[i];
594
595 viennagrid::make_element_with_id<CellType>(seg[int(seg_id)],
596 cell_vertex_handles.begin(),
597 cell_vertex_handles.end(),
598 typename CellType::id_type(i));
599 }
600 }
601
602 private:
603 double * vertices_;
604 IndexT * cells_;
605 IndexT * segmentation_;
606 IndexT num_vertices_;
607 IndexT num_cells_;
608
609 };
610
611 } //namespace util
612} //namespace viennashe
613#endif
segment_description(double start_x, double len_x, unsigned long points_x)
segment_description(double start_x, double start_y, double len_x, double len_y, unsigned long points_x, unsigned long points_y)
Configuration class for the simple mesh generator.
void add_segment(double start_x, double start_y, double len_x, double len_y, unsigned long points_x, unsigned long points_y)
segment_description const & at(std::size_t i) const
void add_segment(double start_x, double len_x, unsigned long points_x)
void add_segment(double start_x, double len_x, unsigned long points_x, double start_y, double len_y, unsigned long points_y)
A logging facility providing fine-grained control over logging in ViennaSHE.
int points_x
Definition: resistor.py:39
int len_x
Definition: resistor.py:38
VectorType::value_type norm_2(VectorType const &v)
Definition: linalg_util.hpp:37
void generate_device_impl(MeshT &mesh, SegmentationT &segmentation, device_generation_config const &conf, viennagrid::simplex_tag< 1 >)
Implementation of a simple one-dimensional 'mesh' generation. Fills a ViennaGrid mesh.
void generate_device(MeshT &mesh, SegmentationT &seg, device_generation_config const &conf)
Public interface for mesh generation of simple one- or two-dimensional meshes. Device must be rectang...
The main ViennaSHE namespace. All functionality resides inside this namespace.
Definition: accessors.hpp:40
A device generator to generate a device from C-Arrays (DOES NOT TAKE OWNERSHIP)
device_from_array_generator(double **vertices, IndexT **cells, IndexT *segmentation, IndexT num_vertices, IndexT num_cells)
void operator()(MeshT &mesh, SegmentationT &seg) const
Functor interface. The mesh and the segmentation need to be given.
A device generator to generate a device from flat C-Arrays (DOES NOT TAKE OWNERSHIP)
device_from_flat_array_generator(double *vertices, IndexT *cells, IndexT *segmentation, IndexT num_vertices, IndexT num_cells)
void operator()(MeshT &mesh, SegmentationT &seg) const
Functor interface. The mesh and the segmentation need to be given.
Defines the log keys used within the viennashe::util namespace.