ViennaSHE 1.3.0
Free open-source semiconductor device simulator using spherical harmonics expansions techniques.
equilibrium_resistor.cpp
Go to the documentation of this file.
1/* ============================================================================
2 Copyright (c) 2011-2022, Institute for Microelectronics,
3 Institute for Analysis and Scientific Computing,
4 TU Wien.
5
6 -----------------
7 ViennaSHE - The Vienna Spherical Harmonics Expansion Boltzmann Solver
8 -----------------
9
10 http://viennashe.sourceforge.net/
11
12 License: MIT (X11), see file LICENSE in the base directory
13=============================================================================== */
14
15#if defined(_MSC_VER)
16 // Disable name truncation warning obtained in Visual Studio
17 #pragma warning(disable:4503)
18#endif
19
20#include <iostream>
21#include <cstdlib>
22#include <cmath>
23#include <vector>
24
25#include "viennashe/forwards.h"
26
27#include "tests/src/common.hpp"
28
29// ViennaSHE includes:
30#include "viennashe/core.hpp"
31
32// ViennaGrid default configurations and centroid() algorithm:
33#include "viennagrid/config/default_configs.hpp"
34#include "viennagrid/algorithm/centroid.hpp"
35
36
46template <typename SHEQuanT>
47class kinetic_energy_wrapper
48{
49 public:
50 kinetic_energy_wrapper(SHEQuanT const & q, viennashe::carrier_type_id ctype) : quan_(q), carrier_type_(ctype) {}
51
52 template <typename ElementType>
53 double operator()(ElementType const & el, std::size_t index_H) const
54 {
55 return quan_.kinetic_energy(el, index_H, carrier_type_);
56 }
57
58 private:
59 SHEQuanT const & quan_;
60 viennashe::carrier_type_id carrier_type_;
61};
62
63
71template <typename DeviceType>
72void init_device(DeviceType & device, double len_x)
73{
74 typedef typename DeviceType::mesh_type MeshType;
75
76 // STEP 2: Set doping
77 std::cout << "* init_device(): Setting doping..." << std::endl;
78
79 // STEP 1: Set material properties:
80 device.set_doping_n(1e16);
81 device.set_doping_p(1e16);
82 device.set_material(viennashe::materials::si());
83
84
85 // STEP 2: Define contacts
86 typedef typename viennagrid::result_of::const_cell_range<MeshType>::type CellContainer;
87 typedef typename viennagrid::result_of::iterator<CellContainer>::type CellIterator;
88
89 double gnd = 0.0;
90 double vcc = 0.0;
91
92 CellContainer cells(device.mesh());
93 for (CellIterator cit = cells.begin();
94 cit != cells.end();
95 ++cit)
96 {
97 //left contact:
98 if (viennagrid::centroid(*cit)[0] < 0.1 * len_x)
99 {
100 device.set_contact_potential(gnd, *cit);
101 }
102
103 //right contact:
104 if (viennagrid::centroid(*cit)[0] > 0.9 * len_x)
105 device.set_contact_potential(vcc, *cit);
106 }
107
108}
109
120template <typename DeviceType, typename SHEQuantity, typename CellType>
121int test_result_at_point(viennashe::carrier_type_id carrier_type,
122 DeviceType const & device,
123 SHEQuantity const & quan,
124 viennashe::config const & conf,
125 CellType const & cell,
126 std::size_t index_H)
127{
128 const double T = device.get_lattice_temperature(cell);
129 const double tol = 1e-3;
130 double kinetic_energy = quan.get_kinetic_energy(cell, index_H);
132
133 double ref = std::exp(- kinetic_energy / viennashe::physics::constants::kB / T)
134 * quan.get_values(cell, 1)[0]; //for normalization
135
136 // Test 1: Check Maxwell distribution of zeroth-order SHE coefficients:
137 if ( !viennashe::testing::fuzzy_equal(quan.get_values(cell, index_H)[0], ref, tol)
138 || (quan.get_values(cell, index_H)[0] < quan.get_values(cell, index_H)[0])
139 || (quan.get_values(cell, index_H)[0] > quan.get_values(cell, index_H)[0])
140 )
141 {
142 std::cerr << "* ERROR: Maxwell distribution test failed at vertex " << cell << " with index_H = " << index_H << std::endl;
143 return EXIT_FAILURE;
144 }
145
146 // Test 2: Interpolated first-order expansion coefficients should be to zero (up to round-off):
147 viennashe::she::interpolated_she_df_wrapper<DeviceType, SHEQuantity> interpolated_she_df(device, conf, quan);
148 for (long m = -1; m <= 1; ++m)
149 {
150 double f_1m = interpolated_she_df(cell, kinetic_energy, 1, m, index_H);
151 if ( std::abs(f_1m) > 1e-18 )
152 {
153 std::cerr << "* ERROR: Check for vanishing first-order failed at vertex " << cell << " with index_H = " << index_H << std::endl;
154 std::cerr << " value: " << f_1m << std::endl;
155 return EXIT_FAILURE;
156 }
157 }
158
159 // Test 3: Generalized distribution function evaluated at random angles should be the same (up to round-off)
161 double gdf_val1 = generalized_df(cell, kinetic_energy, 0.123, 1.02);
162 double gdf_val2 = generalized_df(cell, kinetic_energy, 0.420, 3.60);
163 double gdf_val3 = generalized_df(cell, kinetic_energy, 0.360, 4.02);
164 ref *= conf.dispersion_relation(carrier_type).density_of_states(kinetic_energy) * Y_00(0, 0);
165 if ( ! viennashe::testing::fuzzy_equal(gdf_val1, ref, tol)
166 || ! viennashe::testing::fuzzy_equal(gdf_val2, ref, tol)
167 || ! viennashe::testing::fuzzy_equal(gdf_val3, ref, tol)
168 )
169 {
170 std::cerr << "* ERROR: Check for generalized distribution function failed at vertex " << cell << " with index_H = " << index_H << std::endl;
171 std::cerr << " val1: " << gdf_val1 << std::endl;
172 std::cerr << " val2: " << gdf_val2 << std::endl;
173 std::cerr << " val3: " << gdf_val3 << std::endl;
174 std::cerr << " ref: " << ref << std::endl;
175 return EXIT_FAILURE;
176 }
177
178 // Test 4: Now check the same for the generalized energy distribution function wrapper:
180 double edf_val1 = generalized_edf(cell, kinetic_energy);
181 double edf_val2 = generalized_edf(cell, kinetic_energy);
182 double edf_val3 = generalized_edf(cell, kinetic_energy);
183 if ( ! viennashe::testing::fuzzy_equal(edf_val1, ref, tol)
184 || ! viennashe::testing::fuzzy_equal(edf_val2, ref, tol)
185 || ! viennashe::testing::fuzzy_equal(edf_val3, ref, tol)
186 )
187 {
188 std::cerr << "* ERROR: Check for generalized energy distribution function failed at vertex " << cell << " with index_H = " << index_H << std::endl;
189 std::cerr << " val1: " << edf_val1 << std::endl;
190 std::cerr << " val2: " << edf_val2 << std::endl;
191 std::cerr << " val3: " << edf_val3 << std::endl;
192 std::cerr << " ref: " << ref << std::endl;
193 return EXIT_FAILURE;
194 }
195
196
197 return EXIT_SUCCESS;
198}
199
200
201inline int simulate(double temperature)
202{
203 typedef viennagrid::quadrilateral_2d_mesh MeshType;
204 typedef viennashe::device<MeshType> DeviceType;
205
206 std::cout << "* main(): Creating device..." << std::endl;
207 DeviceType device;
208
209 // STEP 1: Generate device:
211 generator_params.add_segment(0.0, 6.0e-7, 10, //start at x=, length, points
212 0.0, 6.0e-7, 2); //start at y=, length, points
213 device.generate_mesh(generator_params);
214 device.set_lattice_temperature(temperature);
215
216 std::cout << "* main(): Initializing device..." << std::endl;
217 init_device(device, generator_params.at(0).get_length_x());
218
219 std::cout << "* main(): Creating DD simulator..." << std::endl;
220 viennashe::config dd_cfg;
221 dd_cfg.with_electrons(true);
223
224 dd_cfg.with_holes(true);
226 //dd_cfg.gummel_iters(50);
227 viennashe::simulator<DeviceType> dd_simulator(device, dd_cfg);
228
229 std::cout << "* main(): Launching simulator..." << std::endl;
230 dd_simulator.run();
231
232 viennashe::io::write_quantities_to_VTK_file(dd_simulator, "equilibrium-resistor_dd_quan");
233
234 // A single SHE solution step:
235 std::cout << "* main(): Setting up SHE..." << std::endl;
236 //size_t energy_points = 10;
237 viennashe::config config;
238 //config.max_expansion_order(3);
239 config.with_electrons(true);
240 config.with_holes(true);
243 config.scattering().ionized_impurity().enabled(false);
244 //config.energy_levels(energy_points);
246 config.nonlinear_solver().max_iters(1);
247
248 std::cout << "* main(): Computing SHE..." << std::endl;
249 viennashe::simulator<DeviceType> she_simulator(device, config);
250 she_simulator.set_initial_guess(viennashe::quantity::potential(), dd_simulator.potential());
251 she_simulator.set_initial_guess(viennashe::quantity::electron_density(), dd_simulator.electron_density());
252 she_simulator.set_initial_guess(viennashe::quantity::hole_density(), dd_simulator.hole_density());
253 she_simulator.run();
254
255 std::cout << "Energy range: [" << she_simulator.quantities().electron_distribution_function().get_value_H(0) << ", "
256 << she_simulator.quantities().electron_distribution_function().get_value_H(she_simulator.quantities().electron_distribution_function().get_value_H_size() - 1)
257 << "] (" << she_simulator.quantities().electron_distribution_function().get_value_H_size() << " discrete energies)" << std::endl;
258
259 std::cout << "* main(): Writing SHE result..." << std::endl;
260 std::stringstream ss;
261 ss << "equilibrium_resistor_" << temperature << "_edf";
263 she_simulator.config(),
264 she_simulator.quantities().electron_distribution_function(),
265 ss.str());
266
267 //
268 // check result: Must equal kinetic energy:
269 //
270 typedef viennagrid::result_of::const_cell_range<MeshType>::type CellContainer;
271 typedef viennagrid::result_of::iterator<CellContainer>::type CellIterator;
272
273 //VectorType she_result = she_simulator.edf().vector();
274 //std::cout << "she_result: " << she_result << std::endl;
275
276 CellContainer cells(device.mesh());
277 for (CellIterator cit = cells.begin();
278 cit != cells.end();
279 ++cit)
280 {
281 for (size_t index_H=0; index_H < she_simulator.quantities().electron_distribution_function().get_value_H_size(); ++index_H)
282 {
283 long index = she_simulator.quantities().electron_distribution_function().get_unknown_index(*cit, index_H);// indices_on_vertex[index_H];
284 if (index > -1)
285 {
286 if (she_simulator.config().with_electrons())
287 {
288 if (test_result_at_point(viennashe::ELECTRON_TYPE_ID, device, she_simulator.quantities().electron_distribution_function(), config, *cit, index_H) != EXIT_SUCCESS)
289 return EXIT_FAILURE;
290 }
291 else if (she_simulator.config().with_holes())
292 {
293 if (test_result_at_point(viennashe::HOLE_TYPE_ID, device, she_simulator.quantities().hole_distribution_function(), config, *cit, index_H) != EXIT_SUCCESS)
294 return EXIT_FAILURE;
295 }
296 }
297 }
298 std::cout << "Tests passed for cell " << cit->id().get() << std::endl;
299 }
300
301 return EXIT_SUCCESS;
302}
303
304
305int main()
306{
307 // Simulate at 300 K and at 400 K to make sure temperature is considered accordingly:
308 std::cout << "--------- Testing at 300 K --------------" << std::endl;
309 int retval = simulate(300.0);
310
311 if (retval != EXIT_SUCCESS)
312 return retval;
313
314 std::cout << std::endl;
315 std::cout << "--------- Testing at 400 K --------------" << std::endl;
316 retval = simulate(400.0);
317 if (retval != EXIT_SUCCESS)
318 return retval;
319
320 std::cout << "*******************************" << std::endl;
321 std::cout << "* Test finished successfully! *" << std::endl;
322 std::cout << "*******************************" << std::endl;
323
324 return EXIT_SUCCESS;
325}
326
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
bool with_holes() const
Returns true if holes are considered in the simulation.
Definition: config.hpp:234
nonlinear_solver_config_type & nonlinear_solver()
Returns the configuration object for the nonlinear solver.
Definition: config.hpp:495
void set_electron_equation(equation_id equ_id)
Definition: config.hpp:231
double energy_spacing() const
Returns the uniform energy spacing of discrete energies.
Definition: config.hpp:460
void set_hole_equation(equation_id equ_id)
Definition: config.hpp:239
bool with_electrons() const
Returns true if electrons are considered in the simulation.
Definition: config.hpp:226
viennashe::she::scatter_config & scattering()
Returns the configuration object for scattering.
Definition: config.hpp:475
Defines the physical properties of a device, e.g. doping. This is the implementation for 2d and highe...
Definition: device.hpp:818
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 generalized distribution function (i.e. f * Z,...
A convenience wrapper for accessing the generalized energy distribution function (f * Z,...
A convenience wrapper for accessing the distribution function coefficients over the device on each ve...
ionized_impurity_scattering_parameters const & ionized_impurity() const
Returns the parameters for ionized impurity scattering. Const-version.
Definition: config.hpp:377
Class for self-consistent SHE simulations.
Definition: simulator.hpp:675
std::size_t max_iters() const
Returns the maximum number of nonlinear solver iterations.
Definition: config.hpp:317
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
Convenience header, which includes all core functionality available in ViennaSHE.
Contains forward declarations and definition of small classes that must be defined at an early stage.
void init_device(DeviceType &device, double Vg_init, double Nd, double Na)
Initalizes the MOS 1D device for testing.
Definition: mos1d_dg.hpp:94
int len_x
Definition: resistor.py:38
void write_quantities_to_VTK_file(viennashe::simulator< DeviceType > const &simulator_obj, std::string filename, bool include_debug_information=false)
Generic interface function for writing simulated quantities to a VTK file.
std::string electron_distribution_function()
std::string electron_density()
bool fuzzy_equal(double is, double should, double tol=1e-1)
Performs a fuzzy (up to a tolerance) equal. Returns true if is and should are equal within the tolera...
Definition: common.hpp:39
carrier_type_id
Enumeration type for selecting the carrier type.
Definition: forwards.h:185
@ HOLE_TYPE_ID
Definition: forwards.h:188
@ ELECTRON_TYPE_ID
Definition: forwards.h:187
@ EQUATION_SHE
Definition: forwards.h:118
@ EQUATION_CONTINUITY
Definition: forwards.h:117
int main()
Definition: resistor1d-c.c:108
A class referring to silicon and providing certain material parameters Note that this is the default ...
Definition: all.hpp:50
static const double q
Elementary charge.
Definition: constants.hpp:44
static const double kB
Boltzmann constant.
Definition: constants.hpp:46
Contains common functions, functors and other classes often needed by the tests.