ViennaSHE 1.3.0
Free open-source semiconductor device simulator using spherical harmonics expansions techniques.
mapping.hpp
Go to the documentation of this file.
1#ifndef VIENNASHE_MAPPING_HPP
2#define VIENNASHE_MAPPING_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 <iostream>
19#include <fstream>
20#include <vector>
21#include <memory>
22#include <petsc.h>
23
24//ViennaGrid includes:
25#include "viennagrid/mesh/mesh.hpp"
26
27#include "viennashe/forwards.h"
32
34
39namespace viennashe
40{
41
43
52 template <typename DeviceType, typename VertexT>
53 long create_mapping(DeviceType const & device,
55 long start_index = 0)
56 {
57 typedef typename DeviceType::mesh_type MeshType;
58
59 typedef typename viennagrid::result_of::const_cell_range<MeshType>::type CellContainer;
60 typedef typename viennagrid::result_of::iterator<CellContainer>::type CellIterator;
61
62 //
63 // Run the mapping on allowed vertices
64 //
65 long mapping_index = start_index;
66
67 CellContainer cells(device.mesh());
68 for (CellIterator cit = cells.begin();
69 cit != cells.end();
70 ++cit)
71 {
72 if ( quantity.get_boundary_type(*cit) != BOUNDARY_DIRICHLET && quantity.get_unknown_mask(*cit) ) // Dirichlet boundary condition
73 quantity.set_unknown_index(*cit, mapping_index++);
74 else
75 quantity.set_unknown_index(*cit, -1);
76 }
77
78 return mapping_index;
79 } //create_mapping
80
81
83
84 namespace detail
85 {
86
96 template <typename DeviceType, typename CellType, typename SHEQuantity>
97 void map_cell(DeviceType const & device,
98 CellType const & cell,
99 std::size_t index_H,
100 SHEQuantity & quan,
101 viennashe::config const & conf,
102 long & current_index)
103 {
104 const long expansion_order = static_cast<long>(quan.get_expansion_order(cell, index_H));
105 const double kinetic_energy_max = conf.max_kinetic_energy_range(quan.get_carrier_type_id());
106
107
108 if ( device.get_material(cell) == viennashe::materials::metal::id) //this is a contact element attached to a semiconductor
109 {
110 if (viennashe::she::averaged_density_of_states(quan, conf.dispersion_relation(quan.get_carrier_type_id()), cell, index_H) > 0
111 && quan.get_kinetic_energy(cell, index_H) < kinetic_energy_max) // truncate range for high energies
112 {
113 quan.set_unknown_index(cell, index_H, current_index);
114 current_index += viennashe::she::even_unknowns_on_node(expansion_order);
115 }
116 else
117 {
118 quan.set_unknown_index(cell, index_H, -1);
119 quan.set_expansion_order(cell, index_H, 0);
120 }
121 }
122 else if ( viennashe::she::averaged_density_of_states(quan, conf.dispersion_relation(quan.get_carrier_type_id()), cell, index_H) > 0
123 && quan.get_kinetic_energy(cell, index_H) < kinetic_energy_max) // truncate range for high energies
124 {
125 quan.set_unknown_index(cell, index_H, current_index);
126 current_index += viennashe::she::even_unknowns_on_node(expansion_order);
127 }
128 else
129 {
130 quan.set_unknown_index(cell, index_H, -1);
131 quan.set_expansion_order(cell, index_H, 0);
132 }
133 }
134
135
140 template <typename DeviceType, typename SHEQuantity, typename FacetType>
141 void map_facet(DeviceType const & device,
142 SHEQuantity & quan,
143 viennashe::config const & conf,
144 FacetType const & facet,
145 std::size_t index_H,
146 long & current_index)
147 {
148 typedef typename DeviceType::mesh_type MeshType;
149
150 typedef typename viennagrid::result_of::cell<MeshType>::type CellType;
151
152 typedef typename viennagrid::result_of::const_coboundary_range<MeshType, FacetType, CellType>::type CellOnFacetContainer;
153 typedef typename viennagrid::result_of::iterator<CellOnFacetContainer>::type CellOnFacetIterator;
154
155 // Get cells of the facet
156 CellOnFacetContainer cells_on_facet(device.mesh(), viennagrid::handle(device.mesh(), facet));
157 CellOnFacetIterator cofit = cells_on_facet.begin();
158
159 CellType const & c1 = *cofit;
160 ++cofit;
161 if (cofit == cells_on_facet.end())
162 {
163 quan.set_unknown_index(facet, index_H, -1);
164 quan.set_expansion_order(facet, index_H, 0);
165 }
166 else
167 {
168 CellType const & c2 = *cofit;
169
170 //
171 // assign unknowns to facet if both cells carry unknowns:
172 //
173 long dof1 = quan.get_unknown_index(c1, index_H);
174 long dof2 = quan.get_unknown_index(c2, index_H);
175 if (dof1 > -1 && dof2 > -1
176 && (averaged_density_of_states(quan, conf.dispersion_relation(quan.get_carrier_type_id()), facet, index_H) > 0)
177 && (viennashe::materials::is_semiconductor(device.get_material(c1)) || viennashe::materials::is_semiconductor(device.get_material(c2))) ) // at least one of the two cells must be a semiconductor!
178 {
179 quan.set_unknown_index(facet, index_H, current_index);
180 current_index += static_cast<long>(quan.get_unknown_num(facet, index_H));
181 }
182 else //energy is in forbidden band
183 {
184 quan.set_unknown_index(facet, index_H, -1);
185 quan.set_expansion_order(facet, index_H, 0);
186 }
187 }
188
189 } //map_edge()
190
191 } //namespace detail
192
193
194
195
203 template <typename DeviceType, typename SHEQuantity>
204 long create_even_mapping(DeviceType const & device,
205 SHEQuantity & quan,
206 viennashe::config const & conf,
207 long unknown_offset = 0)
208 {
209 typedef typename DeviceType::mesh_type MeshType;
210
211 typedef typename viennagrid::result_of::const_cell_range<MeshType>::type CellContainer;
212 typedef typename viennagrid::result_of::iterator<CellContainer>::type CellIterator;
213
214 MeshType const & mesh = device.mesh();
215
216 CellContainer cells(mesh);
217
218 //
219 // Distribute SHE unknown indices over the mesh.
220 // This is NOT completely arbitrary:
221 // * First all even unknowns for a certain energy level
222 // * Then all even unknowns for the next energy level, and so on, until all energies for even are populated
223 // * Now the same for all even unknowns of other quantities when using Newton's method (call this function again)
224 // * Odd unknowns get mapped only after all even unknowns and spatial unknowns (potential, etc.) have been mapped.
225 // Reasons:
226 // * after elimination of odd unknowns, "upper left block" of system matrix remains.
227 // * for each energy level, preconditioners for the "upper left block" can be computed in parallel
228 //
229 // Note that for a particular energy, only the first unknown-index (for Y_00) is stored.
230 // Number of unknowns at that energy point is obtained from the (local) expansion order.
231 //
232
233 /*
234 * PETSC
235 * */
236 if(quan.get_value_H_size() == 0 )return 0;
237
238 int size = 1, rank = 0;
240 {
241 MPI_Comm_size(PETSC_COMM_WORLD,&size);
242 MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
243 }
244 std::size_t maxquantityfull = quan.get_value_H_size();
245 //* Overleap the regions to avoid the singular matrix*/
246 std::size_t maxquantity = rank < size-1 ? ((rank+1)*maxquantityfull)/size+1 :maxquantityfull ;
247 std::size_t init = ((rank)*maxquantityfull)/size;//;
248 long unknown_index = unknown_offset;
249 for (std::size_t index_H = init; index_H < maxquantity; ++index_H)
250 {
251 for (CellIterator cit = cells.begin();
252 cit != cells.end();
253 ++cit)
254 {
255 if (quan.get_unknown_mask(*cit) == false )
256 {
257 //no SHE unknowns here
258 quan.set_unknown_index(*cit, index_H, -1);
259 }
260 else
261 {
262 if ( (index_H == 0) || (index_H == quan.get_value_H_size() - 1) )
263 //no SHE unknowns at energy boundary (otherwise scattering at simulation domain gets pretty delicate w.r.t. symmetrization of in- and out-scattering)
264 quan.set_unknown_index(*cit, index_H, -1);
265 else
266 detail::map_cell(device, *cit, index_H, quan, conf, unknown_index);
267 }
268 }
269 }
270
271 return unknown_index;
272 }
273
274
275
283 template <typename DeviceType, typename SHEQuantity>
284 long create_odd_mapping(DeviceType const & device,
285 SHEQuantity & quan,
286 viennashe::config const & conf,
287 long unknown_offset = 0) //nonzero value if e.g. the potential is also considered within Newton iteration
288 {
289 typedef typename DeviceType::mesh_type MeshType;
290
291 typedef typename viennagrid::result_of::const_facet_range<MeshType>::type FacetContainer;
292 typedef typename viennagrid::result_of::iterator<FacetContainer>::type FacetIterator;
293
294 MeshType const & mesh = device.mesh();
295
296 FacetContainer facets(mesh);
297 /*
298 * PETSC
299 * */
300 if(quan.get_value_H_size() == 0 )return 0;
301 int size = 1,rank = 0;
303 {
304 MPI_Comm_size(PETSC_COMM_WORLD,&size);
305 MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
306 }
307 std::size_t maxquantityfull = quan.get_value_H_size();
308 std::size_t maxquantity = rank < size-1 ? ((rank+1)*maxquantityfull)/size+1:maxquantityfull ;
309 std::size_t init = ((rank)*maxquantityfull)/size;
310 long unknown_index = unknown_offset;
311 for (std::size_t index_H = init; index_H < maxquantity; ++index_H)
312 {
313 for (FacetIterator fit = facets.begin();
314 fit != facets.end();
315 ++fit)
316 {
317
318 detail::map_facet(device, quan, conf, *fit, index_H, unknown_index);
319 }
320 }
321
322 return unknown_index;
323 }
324
325
326
327
329
337 template<typename DeviceT>
340 viennashe::config const & conf)
341 {
342 typedef typename map_info_type::value_type::second_type PairType;
343
345
346 long last_mapping_index = 0;
347 long current_mapping_index = 0;
348 map_info_type map_info;
349
350
351
352 // Create mapping for spatial quantities:
353 for (std::size_t i=0; i<quantities.unknown_quantities().size(); ++i)
354 {
355 current_mapping_index = viennashe::create_mapping(device, quantities.unknown_quantities()[i], last_mapping_index);
356
357 map_info[quantities.unknown_quantities()[i].get_name()] = PairType(std::size_t(current_mapping_index - last_mapping_index), 0);
358 if (use_newton)
359 last_mapping_index = current_mapping_index;
360 }
361
362 // Create mapping for SHE quantities (even):
363 for (std::size_t i=0; i<quantities.unknown_she_quantities().size(); ++i)
364 {
365 current_mapping_index = viennashe::create_even_mapping(device, quantities.unknown_she_quantities()[i], conf, last_mapping_index);
366
367 map_info[quantities.unknown_she_quantities()[i].get_name()].first = std::size_t(current_mapping_index - last_mapping_index);
368
369 if (use_newton)
370 last_mapping_index = current_mapping_index;
371 else //mapping for odd quantities
372 {
373 long last_even_mapping_index = current_mapping_index;
374 current_mapping_index = viennashe::create_odd_mapping(device, quantities.unknown_she_quantities()[i], conf, last_even_mapping_index);
375
376 map_info[quantities.unknown_she_quantities()[i].get_name()].second = std::size_t(current_mapping_index - last_even_mapping_index);
377 }
378 }
379
380 // Create mapping for SHE quantities (odd) when using Newton:
381 if (use_newton)
382 {
383 for (std::size_t i=0; i<quantities.unknown_she_quantities().size(); ++i)
384 {
385 current_mapping_index = viennashe::create_odd_mapping(device, quantities.unknown_she_quantities()[i], conf, last_mapping_index);
386
387 map_info[quantities.unknown_she_quantities()[i].get_name()].second = std::size_t(current_mapping_index - last_mapping_index);
388 last_mapping_index = current_mapping_index;
389 }
390 }
391
392 return map_info;
393 } // create_mapping()
394
395} //namespace viennashe
396
397#endif
Common routines for the assembly of SHE equations.
The main SHE configuration class. To be adjusted by the user for his/her needs.
Definition: config.hpp:124
viennashe::physics::dispersion_proxy dispersion_relation(viennashe::carrier_type_id ctype) const
Returns the dispersion relation for electrons.
Definition: config.hpp:266
nonlinear_solver_config_type & nonlinear_solver()
Returns the configuration object for the nonlinear solver.
Definition: config.hpp:495
double max_kinetic_energy_range(viennashe::carrier_type_id ctype) const
Returns the minimum kinetic energy range for the selected carrier.
Definition: config.hpp:425
linear_solver_config_type & linear_solver()
Returns the configuration object for the linear solver.
Definition: config.hpp:485
long get_material(cell_type const &elem) const
Returns the material id of the provided cell.
Definition: device.hpp:502
MeshT const & mesh() const
Returns the underlying mesh.
Definition: device.hpp:145
Defines the physical properties of a device, e.g. doping. This is the implementation for 2d and highe...
Definition: device.hpp:818
The main SHE simulator controller class. Acts as an accessor for all SHE quantities needed for the si...
UnknownSHEQuantityListType & unknown_she_quantities()
std::deque< UnknownQuantityType > & unknown_quantities()
long id() const
Returns the current linear solver ID.
Definition: config.hpp:79
long id() const
Returns the current linear solver ID.
Definition: config.hpp:262
bool get_unknown_mask(associated_type const &elem) const
boundary_type_id get_boundary_type(associated_type const &elem) const
void set_unknown_index(associated_type const &elem, long value)
Contains forward declarations and definition of small classes that must be defined at an early stage.
A very simple material database. Needs to be replaced by something more versatile soon.
Miscellaneous utilities.
void map_cell(DeviceType const &device, CellType const &cell, std::size_t index_H, SHEQuantity &quan, viennashe::config const &conf, long &current_index)
Handles the mapping of a SHE unkown quantity on a single cell and H-space index.
Definition: mapping.hpp:97
void map_facet(DeviceType const &device, SHEQuantity &quan, viennashe::config const &conf, FacetType const &facet, std::size_t index_H, long &current_index)
Assigns an unknown index for odd SHE unknowns to a facet. Preconditions:
Definition: mapping.hpp:141
bool is_semiconductor(long material_id)
Convenience function for checking whether the supplied material ID refers to a semiconductor.
Definition: all.hpp:156
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....
long even_unknowns_on_node(long L)
Returns the number of even spherical harmonics up to (including) order L.
The main ViennaSHE namespace. All functionality resides inside this namespace.
Definition: accessors.hpp:40
std::map< std::string, std::pair< std::size_t, std::size_t > > map_info_type
Information on the number of unknowns per quantity.
Definition: forwards.h:101
long create_odd_mapping(DeviceType const &device, SHEQuantity &quan, viennashe::config const &conf, long unknown_offset=0)
Distributes SHE unknown indices (dofs) over the device.
Definition: mapping.hpp:284
long create_even_mapping(DeviceType const &device, SHEQuantity &quan, viennashe::config const &conf, long unknown_offset=0)
Distributes SHE unknown indices (dofs) over the device.
Definition: mapping.hpp:204
long create_mapping(DeviceType const &device, viennashe::unknown_quantity< VertexT > &quantity, long start_index=0)
Maps unkown indices in the system matrix to the given unknown spatial quantity.
Definition: mapping.hpp:53
@ BOUNDARY_DIRICHLET
Definition: forwards.h:127
Defines a generic simulator quantity for use within the solvers of ViennaSHE.
@ petsc_parallel_linear_solver
gpu-assisted solver (block ILUT)
Definition: config.hpp:47
@ newton_nonlinear_solver
Gummel iteration.
Definition: config.hpp:244
A container of all quantities defined for a certain timestep t.