ViennaSHE 1.3.0
Free open-source semiconductor device simulator using spherical harmonics expansions techniques.
df_wrappers.hpp
Go to the documentation of this file.
1#ifndef VIENNASHE_SHE_DF_WRAPPERS_HPP
2#define VIENNASHE_SHE_DF_WRAPPERS_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#include <cmath>
19
20#include "viennashe/forwards.h"
23
24#include "viennagrid/forwards.hpp"
25#include "viennagrid/mesh/mesh.hpp"
26
27#include "viennashe/config.hpp"
33
38namespace viennashe
39{
40 namespace she
41 {
42 namespace detail
43 {
45 template <typename UnknownSHEType, typename ElementType>
46 std::size_t find_best_H(UnknownSHEType const & she_quantity, ElementType const & el, double kin_energy, std::size_t index_H_guess)
47 {
48 long carrier_sign = (she_quantity.get_carrier_type_id() == viennashe::ELECTRON_TYPE_ID) ? -1 : 1;
49
50 std::size_t index_H = std::min<std::size_t>(index_H_guess, she_quantity.get_value_H_size() - 2);
51
52 // find best index_H:
53 while ( (she_quantity.get_kinetic_energy(el, index_H) < kin_energy) //search upwards
54 && ( (carrier_sign == 1) ? (index_H > 0) : (index_H < she_quantity.get_value_H_size() - 1) )
55 )
56 {
57 index_H -= static_cast<std::size_t>(carrier_sign);
58 }
59
60 while ( (she_quantity.get_kinetic_energy(el, index_H) > kin_energy) //search downwards
61 && ( (carrier_sign == -1) ? (index_H > 0) : (index_H < she_quantity.get_value_H_size() - 1) )
62 )
63 {
64 index_H += static_cast<std::size_t>(carrier_sign);
65 }
66
67 // finally, pick index_H or index_H + 1 (electrons), whichever is better
68 double error_down = she_quantity.get_kinetic_energy(el, index_H) - kin_energy;
69 if (error_down <= 0)
70 return index_H;
71
72 double error_up = error_down;
73 if ( static_cast<long>(index_H) >= static_cast<long>(carrier_sign)
74 && static_cast<long>(index_H) < static_cast<long>(she_quantity.get_value_H_size()) + static_cast<long>(carrier_sign))
75 {
76 error_up = she_quantity.get_kinetic_energy(el, static_cast<std::size_t>(static_cast<long>(index_H) - carrier_sign)) - kin_energy;
77 if (she_quantity.get_unknown_index(el, static_cast<std::size_t>(static_cast<long>(index_H) - carrier_sign)) < 0)
78 error_up = 2.0 * error_down; //make sure error_up is not selected
79 }
80
81 if (std::abs(error_up) < std::abs(error_down))
82 index_H -= static_cast<std::size_t>(carrier_sign);
83
84 return index_H;
85 }
86 }
87
88
89
90 // Class Arguments Comments
91 // --------------------------------------------------------------------------------------------------------------------------------------------
92 // she_df_wrapper (tag, energy, l, m) Returns f_{l,m}. Even l on vertices, odd l on edges. Optional guess argument
93 // |
94 // |--> interpolated_she_df_wrapper (tag, energy, l, m) Returns f_{l,m} on vertices. Odd l are automatically interpolated from edges.
95 // | |
96 // \--> df_wrapper --> generalized_df_wrapper (tag, energy, theta, phi) Returns the full (generalized) distribution function on each vertex.
97 // |
98 // \---------> edf_wrapper --> generalized_edf_wrapper (tag, energy) Returns the (generalized) energy distribution function on each vertex.
99 //
100
106 template <typename DeviceType, typename SHEQuantityT>
108 {
109 private:
111
112 typedef typename DeviceType::mesh_type MeshType;
113
114 typedef typename viennagrid::result_of::vertex<MeshType>::type VertexType;
115 typedef typename viennagrid::result_of::facet<MeshType>::type FacetType;
116 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
117
118 public:
119
121 typedef SHEQuantityT she_quantity_type;
122
123
130 SHEQuantityT const & quan)
131 : conf_(conf), she_unknown_(quan), dispersion_(conf.dispersion_relation(quan.get_carrier_type_id()))
132 { }
133
134
143 double operator()(CellType const & cell,
144 double kinetic_energy,
145 std::size_t l,
146 long m,
147 std::size_t index_H_guess = 0) const
148 {
149 if ( (l % 2 != 0) || (std::abs(static_cast<double>(m)) > static_cast<double>(l)) )
150 throw invalid_expansion_order_exception("Invalid expansion order on vertex", l, m);
151
152 return evaluate(cell,
153 detail::find_best_H(she_unknown_, cell, kinetic_energy, index_H_guess),
154 l, m);
155 }
156
157
166 double operator()(FacetType const & facet,
167 double kinetic_energy,
168 std::size_t l,
169 long m,
170 std::size_t index_H_guess = 0) const
171 {
172 if ( (l % 2 != 1) || (std::abs(static_cast<double>(m)) > static_cast<double>(l)) )
173 throw invalid_expansion_order_exception("Invalid expansion order on edge", l, m);
174
175 return evaluate(facet,
176 detail::find_best_H(she_unknown_, facet, kinetic_energy, index_H_guess),
177 l, m);
178 }
179
180
182 template <typename FoldVectorType>
183 void fill(CellType const & cell,
184 double kin_energy,
185 std::size_t index_H_guess,
186 FoldVectorType & vec) const
187 {
188 typedef typename FoldVectorType::value_type value_type;
189
190 std::size_t index_H = detail::find_best_H(she_unknown_, cell, kin_energy, index_H_guess);
191
192 value_type const * pValues = she_unknown_.get_values(cell, index_H);
193
194 std::size_t num_values = she_unknown_.get_unknown_num(cell, index_H);
195 for (std::size_t i=0; i < num_values; ++i)
196 vec[i] = pValues[i];
197 }
198
199
201 template <typename FoldVectorType>
202 void fill(FacetType const & facet,
203 double kin_energy,
204 std::size_t index_H_guess,
205 FoldVectorType & vec) const
206 {
207 typedef typename FoldVectorType::value_type value_type;
208
209 std::size_t index_H = detail::find_best_H(she_unknown_, facet, kin_energy, index_H_guess);
210
211 value_type const * pValues = she_unknown_.get_values(facet, index_H);
212
213 std::size_t num_values = she_unknown_.get_unknown_num(facet, index_H);
214 for (std::size_t i=0; i < num_values; ++i)
215 vec[i] = pValues[i];
216 }
217
218 viennashe::config const & config() const { return conf_; }
219 SHEQuantityT const & quan() const { return this->she_unknown_; }
220
221 dispersion_relation_type const & dispersion_relation() const { return this->dispersion_; }
222
223 private:
224
233 template <typename ElementType>
234 double evaluate(ElementType const & el,
235 std::size_t index_H,
236 std::size_t l,
237 long m) const
238 {
239 std::size_t vec_index = 0;
240 const std::size_t unknown_num = she_unknown_.get_unknown_num(el, index_H);
241
242 for (std::size_t i = parity_for_element(el); i < l; i += 2)
243 vec_index += 2 * i + 1;
244
245 if (unknown_num > 0 && unknown_num >= vec_index)
246 {
247 switch (conf_.she_discretization_type())
248 {
250 return she_unknown_.get_values(el, index_H)[vec_index + std::size_t(long(l) + m)];
252 return she_unknown_.get_values(el, index_H)[vec_index + std::size_t(long(l) + m)] / averaged_density_of_states(she_unknown_, dispersion_, el, index_H);
253 default: throw std::runtime_error("she_df_wrapper::evaluate(): Unknown SHE discretization type!");
254 }
255 }
256
257 return 0.0;
258 }
259
260 std::size_t parity_for_element(CellType const &) const { return 0; }
261 std::size_t parity_for_element(FacetType const &) const { return 1; }
262
263 viennashe::config conf_;
264 SHEQuantityT she_unknown_;
265 dispersion_relation_type dispersion_;
266 };
267
268
269 //
270 // Start of derived wrappers: Interpolated SHE wrapper branch
271 //
272
278 template <typename DeviceType, typename SHEQuantityT>
280 {
281 private:
282 typedef typename DeviceType::mesh_type MeshType;
283
284 typedef typename viennagrid::result_of::facet<MeshType>::type FacetType;
285 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
286
287 public:
288
290
292 typedef SHEQuantityT she_quantity_type;
293
295 viennashe::config const & conf,
296 SHEQuantityT const & quan)
297 : device_(device), //Note: Reference to device is required for ViennaGrid co-boundary operations
298 she_df_(conf, quan) {}
299
308 double operator()(CellType const & cell,
309 double kinetic_energy,
310 std::size_t l,
311 long m,
312 std::size_t index_H_guess = 0) const
313 {
314 if (l % 2 == 0)
315 return she_df_(cell, kinetic_energy, l, m, index_H_guess);
316
317 return interpolated_odd_coefficient(cell, kinetic_energy, l, m, index_H_guess);
318 }
319
320
321 SHEQuantityT const & quan() const { return this->she_df_.quan(); }
322
323 dispersion_relation_type const & dispersion_relation() const { return this->she_df_.dispersion_relation(); }
324
325 private:
326
327 double interpolated_odd_coefficient(CellType const & cell,
328 double kinetic_energy,
329 std::size_t l,
330 long m,
331 std::size_t index_H_guess) const
332 {
333 typedef typename viennagrid::result_of::const_facet_range<CellType>::type FacetOnCellContainer;
334 typedef typename viennagrid::result_of::iterator<FacetOnCellContainer>::type FacetOnCellIterator;
335
336 // Interpolation strategy: Due to the Galerkin approach for the odd-order coefficients, the weighted arithmetic mean is returned. Dual box interpolator does not make sense here, because this is an interpolation from scalar to scalar.
337 double result = 0;
338 double summed_volume = 0;
339
340 FacetOnCellContainer facets(cell);
341 for (FacetOnCellIterator focit = facets.begin();
342 focit != facets.end();
343 ++focit)
344 {
345 // TODO: Think about how to deal with facets which don't carry unknowns!
346
347 double facet_volume = viennagrid::volume(*focit);
348 summed_volume += facet_volume;
349 result += she_df_(*focit, kinetic_energy, l, m, index_H_guess) * facet_volume;
350 //Note: Alternatives for interpolations are:
351 // - Harmonic weights: 'result += she_df_() / box_volume; ...; result *= summed_volume;'
352 // - No weights: Just ignore box_volume.
353 }
354
355 if (summed_volume > 0)
356 result /= summed_volume;
357
358 return result;
359 }
360
361 DeviceType const & device_;
362 she_df_wrapper<DeviceType, SHEQuantityT> she_df_;
363 };
364
365
366
374 template <typename DeviceType, typename SHEQuantityT>
376 {
377 private:
378 typedef df_wrapper self_type;
379
380 typedef typename DeviceType::mesh_type MeshType;
381
382 typedef typename viennagrid::result_of::facet<MeshType>::type FacetType;
383 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
384
386
387 public:
388
390 typedef SHEQuantityT she_quantity_type;
391
392 df_wrapper(DeviceType const & device,
393 viennashe::config const & conf,
394 SHEQuantityT const & quan)
395 : she_unknown_(quan),
396 interpolated_she_df_(device, conf, quan) {}
397
406 double operator()(CellType const & cell,
407 double kinetic_energy,
408 double theta,
409 double phi,
410 std::size_t index_H_guess = 0) const
411 {
412 return evaluate(cell, kinetic_energy, theta, phi, index_H_guess);
413 }
414
415 SHEQuantityT const & quan() const { return this->interpolated_she_df_.quan(); }
416
417 dispersion_relation_type const & dispersion_relation() const { return this->interpolated_she_df_.dispersion_relation(); }
418
419 private:
420
421 double evaluate(CellType const & cell,
422 double kinetic_energy,
423 double theta,
424 double phi,
425 std::size_t index_H_guess) const
426 {
427 std::size_t index_H = detail::find_best_H(she_unknown_, cell, kinetic_energy, index_H_guess);
428 std::size_t L = she_unknown_.get_expansion_order(cell, index_H);
429
430 double result = 0;
431 for (std::size_t l=0; l <= L; ++l)
432 {
433 for (int m = -static_cast<int>(l); m <= static_cast<int>(l); ++m)
434 {
435 viennashe::math::SphericalHarmonic Y_lm(static_cast<int>(l),m);
436 result += interpolated_she_df_(cell, kinetic_energy, l, m, index_H) * Y_lm(theta, phi);
437 }
438 }
439
440 return result;
441 }
442
443 UnknownSHEType she_unknown_;
444 interpolated_she_df_wrapper<DeviceType, SHEQuantityT> interpolated_she_df_;
445 };
446
447
448
449
455 template <typename DeviceType, typename SHEQuantityT>
457 {
458 private:
460
461 typedef typename DeviceType::mesh_type MeshType;
462
463 typedef typename viennagrid::result_of::facet<MeshType>::type FacetType;
464 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
465
466 public:
467
469 typedef SHEQuantityT she_quantity_type;
470
471 generalized_df_wrapper(DeviceType const & device,
472 viennashe::config const & conf,
473 SHEQuantityT const & quan) : dispersion_(conf.dispersion_relation(quan.get_carrier_type_id())), df_(device, conf, quan) {}
474
483 double operator()(CellType const & cell,
484 double kinetic_energy,
485 double theta,
486 double phi,
487 std::size_t index_H_guess = 0) const
488 {
489 return df_(cell, kinetic_energy, theta, phi, index_H_guess) * dispersion_.density_of_states(kinetic_energy, theta, phi);
490 }
491
492 SHEQuantityT const & quan() const { return this->df_.quan(); }
493
494 dispersion_relation_type const & dispersion_relation() const { return this->df_.dispersion_relation(); }
495
496
497 private:
498 dispersion_relation_type dispersion_;
500 };
501
502
503
504
505
506
507 //
508 // Derived wrappers: EDF Wrappers
509 //
510
516 template <typename DeviceType, typename SHEQuantityT>
518 {
519 private:
520 typedef edf_wrapper self_type;
521
522 typedef typename DeviceType::mesh_type MeshType;
523
524 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
525
526 public:
527
529 typedef SHEQuantityT she_quantity_type;
530
531
538 SHEQuantityT const & quan) : she_df_(conf, quan), Y_00_(0, 0) {}
539
540
547 double operator()(CellType const & cell,
548 double kinetic_energy,
549 std::size_t index_H_guess = 0) const
550 {
551 return she_df_(cell, kinetic_energy, 0, 0, index_H_guess) * Y_00_(0, 0);
552 }
553
554 SHEQuantityT const & quan() const { return this->she_df_.quan(); }
555
556 dispersion_relation_type const & dispersion_relation() const { return this->she_df_.dispersion_relation(); }
557
558
559 private:
562 };
563
564
570 template <typename DeviceType, typename SHEQuantityT>
572 {
573 private:
575
576 typedef typename DeviceType::mesh_type MeshType;
577
578 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
579
580 public:
581
583 typedef SHEQuantityT she_quantity_type;
584
591 SHEQuantityT const & quan)
592 : dispersion_(conf.dispersion_relation(quan.get_carrier_type_id())), edf_(conf, quan) {}
593
594
601 double operator()(CellType const & cell,
602 double kinetic_energy,
603 std::size_t index_H_guess = 0) const
604 {
605 return edf_(cell, kinetic_energy, index_H_guess) * dispersion_.density_of_states(kinetic_energy);
606 }
607
608 SHEQuantityT const & quan() const { return this->edf_.quan(); }
609
610 dispersion_relation_type const & dispersion_relation() const { return this->edf_.dispersion_relation(); }
611
612
613 private:
614 dispersion_relation_type dispersion_;
616 };
617
618
619 }
620}
621
622#endif
The main SHE configuration class. To be adjusted by the user for his/her needs.
Definition: config.hpp:124
she_discretization_type_id she_discretization_type() const
Definition: config.hpp:360
Defines the physical properties of a device, e.g. doping. This is the implementation for 2d and highe...
Definition: device.hpp:818
A proxy object for a dispersion relation. Does NOT take ownership of the provided pointer!
Definition: dispersion.hpp:69
double density_of_states(double ekin, double theta=0, double phi=0) const
Returns the density of states as a function of kinetic energy (and angles, eventually)
Definition: dispersion.hpp:75
A convenience wrapper for evaluating the full distribution function. Note: Evaluations are quite cost...
double operator()(CellType const &cell, double kinetic_energy, double theta, double phi, std::size_t index_H_guess=0) const
Returns the energy distribution function for electrons in one valley on a vertex:
dispersion_relation_type const & dispersion_relation() const
viennashe::config::dispersion_relation_type dispersion_relation_type
SHEQuantityT const & quan() const
df_wrapper(DeviceType const &device, viennashe::config const &conf, SHEQuantityT const &quan)
A convenience wrapper for accessing the energy distribution function on each vertex of the device.
SHEQuantityT const & quan() const
viennashe::config::dispersion_relation_type dispersion_relation_type
edf_wrapper(viennashe::config const &conf, SHEQuantityT const &quan)
Constructs the wrapper.
double operator()(CellType const &cell, double kinetic_energy, std::size_t index_H_guess=0) const
Returns the energy distribution function for the respective carrier in one valley on a vertex:
dispersion_relation_type const & dispersion_relation() const
A convenience wrapper for evaluating the generalized distribution function (i.e. f * Z,...
SHEQuantityT const & quan() const
viennashe::config::dispersion_relation_type dispersion_relation_type
generalized_df_wrapper(DeviceType const &device, viennashe::config const &conf, SHEQuantityT const &quan)
double operator()(CellType const &cell, double kinetic_energy, double theta, double phi, std::size_t index_H_guess=0) const
Returns the energy distribution function for the respective carrier in one valley on a vertex:
dispersion_relation_type const & dispersion_relation() const
A convenience wrapper for accessing the generalized energy distribution function (f * Z,...
double operator()(CellType const &cell, double kinetic_energy, std::size_t index_H_guess=0) const
Returns the energy distribution function for electrons in one valley on a vertex:
SHEQuantityT const & quan() const
generalized_edf_wrapper(viennashe::config const &conf, SHEQuantityT const &quan)
Constructs the wrapper.
dispersion_relation_type const & dispersion_relation() const
viennashe::config::dispersion_relation_type dispersion_relation_type
A convenience wrapper for accessing the distribution function coefficients over the device on each ve...
interpolated_she_df_wrapper self_type
dispersion_relation_type const & dispersion_relation() const
viennashe::config::dispersion_relation_type dispersion_relation_type
interpolated_she_df_wrapper(DeviceType const &device, viennashe::config const &conf, SHEQuantityT const &quan)
double operator()(CellType const &cell, double kinetic_energy, std::size_t l, long m, std::size_t index_H_guess=0) const
Returns the energy distribution function for the respective carrier type in one valley on a vertex:
Exception for the case that invalid expansion order is accessed.
Definition: exception.hpp:60
A convenience wrapper for accessing the distribution function coefficients over the device....
void fill(CellType const &cell, double kin_energy, std::size_t index_H_guess, FoldVectorType &vec) const
Batch-evaluation: Returns the expansion coefficents computed at the particular vertex for the particu...
SHEQuantityT const & quan() const
viennashe::config::dispersion_relation_type dispersion_relation_type
double operator()(CellType const &cell, double kinetic_energy, std::size_t l, long m, std::size_t index_H_guess=0) const
Returns an even-order SHE coefficient for the respective carrier on a vertex:
dispersion_relation_type const & dispersion_relation() const
viennashe::config const & config() const
void fill(FacetType const &facet, double kin_energy, std::size_t index_H_guess, FoldVectorType &vec) const
Batch-evaluation: Returns the expansion coefficents computed at the particular edge for the particula...
she_df_wrapper(viennashe::config const &conf, SHEQuantityT const &quan)
Constructs the wrapper.
double operator()(FacetType const &facet, double kinetic_energy, std::size_t l, long m, std::size_t index_H_guess=0) const
Returns an even-order SHE coefficient for the respective carrier on an edge:
std::size_t get_expansion_order(AssociatedT1 const &elem, std::size_t index_H) const
The SHE configuration class is defined here.
Defines several filter functors for the device. A filter functor returns true if the supplied argumen...
Contains forward declarations and definition of small classes that must be defined at an early stage.
Miscellaneous utilities.
std::size_t find_best_H(UnknownSHEType const &she_quantity, ElementType const &el, double kin_energy, std::size_t index_H_guess)
Returns the best total energy in order to match the supplied kinetic energy.
Definition: df_wrappers.hpp:46
double averaged_density_of_states(SHEQuantity const &quan, viennashe::config::dispersion_relation_type const &dispersion, CellFacetType const &cell_facet, std::size_t index_H)
Returns the density of states around a vertex or an edge at total energy specified by index_H....
The main ViennaSHE namespace. All functionality resides inside this namespace.
Definition: accessors.hpp:40
@ SHE_DISCRETIZATION_EVEN_ODD_ORDER_GENERALIZED_DF
Definition: forwards.h:146
@ SHE_DISCRETIZATION_EVEN_ODD_ORDER_DF
Definition: forwards.h:145
@ ELECTRON_TYPE_ID
Definition: forwards.h:187
Provides a number of fundamental constants. All constants in SI units.
Provides the exceptions used inside the viennashe::she namespace.
Defines a SHE quantity in (x, H)-space for use within the solvers of ViennaSHE.
Defines a generic simulator quantity for use within the solvers of ViennaSHE.
Implementation of spherical harmonics plus helper functions.