ViennaEMC is a header-only C++17 library for semiconductor carrier transport simulation using the Multi-Valley Ensemble Monte Carlo (EMC) method. It is developed at the Institute for Microelectronics at TU Wien.
- What it does
- Library architecture
- System requirements
- Building
- Examples
- Building and running tests
- Installing as a library
- Integrating into your own CMake project
- Plotting results
- Generating documentation
- Troubleshooting
- Authors and license
The Ensemble Monte Carlo method simulates the quantum-mechanical transport of charge carriers (electrons, holes) through a semiconductor by tracking a statistical ensemble of representative particles. Each particle drifts under the applied electric field and is scattered stochastically by phonons, impurities, and other mechanisms. The distribution of carrier momenta and energies evolves from these microscopic events, giving macroscopic observables such as drift velocity, energy, and valley occupancy.
ViennaEMC extends the classical EMC method with:
- Multi-valley analytical band structures β parabolic and non-parabolic, isotropic and anisotropic effective masses, with the HerringβVogt transformation for anisotropic valleys.
- Pluggable scatter mechanisms β acoustic phonon, optical phonon (zero- and first-order intervalley), FrΓΆhlich (polar-optical) in 3D and 2D, Coulomb scattering, grain boundary scattering, and more. New mechanisms can be added by subclassing
emcScatterMechanism. - Self-scattering (null-scattering) β the standard technique that lets every particle share the same time step regardless of its local scatter rate.
- Particleβparticle interactions via FMM β long-range Coulomb forces between moving carriers and fixed donors, computed with ScalFMM.
- Poisson solver coupling β for full device simulations (MOSFETs, resistors) the electrostatic potential is solved self-consistently on a grid.
- Hot-carrier dynamics in metal-halide perovskites β a dynamic phonon bath (
emcPhononBath) tracks the out-of-equilibrium LO phonon occupation N_q per wave-vector bin, coupled to an acoustic reservoir in a three-temperature carrier/LO/acoustic model. FrΓΆhlich scatter rates are rebuilt every time step from the evolving occupation, capturing the hot-phonon bottleneck and the acoustic cascade. The FrΓΆhlich vertex can be dynamically screened by the free-carrier gas (emcPlasmonScreening+emcScreenedFroehlichInteraction), with the rate and final-state angle drawn from the coupling-weighted occupation over the accessible wavevector window. On top of this thehotCarrierMHPexample builds a full bipolar device model β electrons and holes sharing the bath, carrierβcarrier and electronβhole scattering, radiative and Auger recombination, Pauli band filling, and energy-selective extraction from which open-circuit voltage and power conversion efficiency are computed. The same machinery drives thehotPhononGa2O3high-field transport example for wide-bandgap Ξ²-GaβOβ. - Monolayer MoSβ transport and gas sensing β a first-principles-parameterised model for 2D transition-metal dichalcogenides, with the full intrinsic and extrinsic scattering stack (screened polar-optical and piezoelectric phonons, remote surface-optical substrate phonons, charged-impurity and surface-roughness scattering), screened multivalley (K+Q) transport with per-valley Pauli exclusion, a self-consistent gated-FET device, and an ambient/adsorbate extension for chemical sensing (charge-transfer doping, adsorbate Coulomb and 1/f noise, humidity screening).
ViennaEMC is header-only: all classes live under include/. No library file needs to be compiled β you only link against ScalFMM (for FMM examples) and OpenMP.
include/
βββ emcDevice.hpp β simulation domain (geometry, doping, temperature)
βββ emcMaterial.hpp β material constants (dielectric, mass density, β¦)
βββ emcSimulation.hpp β top-level device simulation loop
βββ emcScatterHandler.hpp β manages scatter table construction and selection
βββ emcConstants.hpp β physical constants (SI units)
β # hot-carrier modules (examples/hotCarrierMHP)
βββ emcPhononBath.hpp β three-temperature LO/acoustic phonon bath (HPB + acoustic cascade), wavevector-resolved N_q with optional per-bin lifetime profile
βββ emcPlasmonScreening.hpp β dynamic Debye screening state (q_s from live density and carrier temperature)
βββ emcCarrierCarrierScatter.hpp β intra-species carrierβcarrier scattering
βββ emcInterCarrierScatter.hpp β electronβhole scattering (reduced-mass frame)
βββ emcRecombination.hpp β radiative (Bnp) + Auger (CCCH/CHHS) recombination
βββ emcEnergySelectiveContact.hpp β energy-selective carrier extraction
βββ emcPauliExclusion.hpp β LugliβFerry band filling on a k-space occupancy grid
βββ emcHotCarrierOutput.hpp β FermiβDirac fit β carrier temperature, V_OC, PCE
β # monolayer-MoSβ modules (examples/singleLayerMoS2, gatedMoS2FET)
βββ emcMultiValleyPauliExclusion.hpp β per-valley/subvalley band filling (K+Q)
βββ Ambient/
β βββ emcAdsorbateChargeTransfer.hpp β surface charge-transfer doping (donor/acceptor)
β βββ emcAdsorbateNoise.hpp β adsorption/desorption KMC (1/f + RTN)
β βββ emcHumidityDielectric.hpp β humidity-dependent surface permittivity
βββ ParticleType/
β βββ emcParticleType.hpp β base class; holds valleys + scatter mechanisms
β βββ emcElectron.hpp β concrete electron particle type
β βββ emcHole.hpp β concrete hole particle type (bipolar transport)
β βββ emcAcceptor.hpp β acceptor particle type
βββ ValleyTypes/
β βββ emcParabolicIsotropValley.hpp
β βββ emcNonParabolicIsotropValley.hpp
β βββ emcParabolicAnisotropValley.hpp
β βββ emcNonParabolicAnistropValley.hpp
β βββ β¦SingleLayer variants β 2D transport (e.g. MoSβ)
βββ ScatterMechanisms/
βββ emcAcousticScatterMechanism.hpp
βββ emcFroehlichInteraction.hpp β equilibrium FrΓΆhlich (3D)
βββ emcHotPhononFroehlichMechanism.hpp β HPB FrΓΆhlich with dynamic N_q
βββ emcScreenedFroehlichInteraction.hpp β screened FrΓΆhlich (equilibrium + HPB, q-resolved rate and angle)
βββ emcZeroOrderInterValleyScatterMechanism.hpp
βββ emcFirstOrderInterValleyScatterMechanism.hpp
βββ emcCoulombScatterMechanism.hpp
β # 2D-material (MoSβ) mechanisms
βββ emcFroehlichInteractionSingleLayer.hpp β 2D polar-optical (FrΓΆhlich)
βββ emcScreenedIntravalleyOpticalMechanism.hpp β screened intravalley optical
βββ emcPiezoelectricSingleLayerScatterMechanism.hpp β piezoelectric acoustic
βββ emcRemoteSurfaceOpticalPhononMechanism.hpp β remote substrate SO phonons
βββ emc2DChargedImpurityScatterMechanism.hpp β charged-impurity sheet
βββ emcSurfaceRoughnessScatterMechanism.hpp β interface roughness
βββ emc2DScreening.hpp β free-carrier static screening
The examples/ directory contains standalone programs that use the library. Each example has its own CMakeLists.txt and can be studied as a template for new simulations.
| Requirement | Minimum version | Notes |
|---|---|---|
| Linux | any recent | Tested on Ubuntu 22.04+ |
| C++ compiler | GCC 9 / Clang 10 | Must support C++17 and OpenMP |
| CMake | 3.12 | |
| Git | any | Required to fetch ScalFMM |
| Internet access | β | Only during make buildDependencies |
| Intel MKL | optional | Used by ScalFMM for BLAS/LAPACK; LAPACK/OpenBLAS can substitute |
ScalFMM is the only external dependency and is downloaded and built automatically by CMake the first time you run make buildDependencies.
git clone https://github.com/ViennaTools/ViennaEMC.git
cd ViennaEMC
mkdir build && cd build
# Configure (release build, examples enabled)
cmake .. -DCMAKE_BUILD_TYPE=Release -DVIENNAEMC_BUILD_EXAMPLES=ONIf you want to install the library to a custom prefix instead of /usr/local:
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DVIENNAEMC_BUILD_EXAMPLES=ON \
-DCMAKE_INSTALL_PREFIX=/path/to/installThis downloads ScalFMM from its Git repository and compiles it. It only needs to run once and may take several minutes depending on your machine and internet connection.
make buildDependenciesAfter it completes, re-run CMake so it can find the newly built ScalFMM:
cmake ..Note: If you already have ScalFMM installed, skip this step and pass
-Dscalfmm_DIR=/path/to/scalfmm/installto thecmakecommand instead.
make -j$(nproc)This compiles all examples in parallel. Each executable is placed under build/examples/<name>/.
The executables write their output to the directory from which they are invoked, so change into the example's build folder first:
cd build/examples/bulkSimulation
./bulkSimulationOutput files (.txt) appear in the same directory and can then be plotted with the provided Python scripts (see Plotting results).
Each example is a standalone program with its own CMakeLists.txt and its
own README describing the model, the parameters, and the output files.
Executables build to build/examples/<name>/ and write their output to
the directory they are run from.
| Example | Description |
|---|---|
| Bulk Silicon | Electron transport in bulk silicon under a constant field: six non-parabolic anisotropic X-valleys, acoustic and zero-order intervalley phonon scattering. Velocityβfield curves, mean energy, valley occupation. The recommended starting point. |
| Bulk Silicon with FMM | The bulk example plus real-space Coulomb forces between carriers and fixed donors, computed with the Fast Multipole Method (ScalFMM). |
| Single-layer MoSβ | 2D transport in monolayer MoSβ: deformation-potential, polar-optical, and piezoelectric phonons, remote substrate phonons, charged impurities, surface roughness, free-carrier screening, multivalley (K+Q) transport with per-valley Pauli exclusion. Kaasbjerg, Li, and Pilotto parameter sets. |
| Ambient gas sensing in MoSβ | The ambientMoS2 driver in the same directory: adsorbate charge-transfer doping, adsorbate Coulomb scattering, humidity screening, and adsorption/desorption noise (1/f, RTN) for chemical sensing. |
| Gated MoSβ FET | Self-consistent (EMC + Poisson) back-gated monolayer-MoSβ transistor in 3D, with ohmic, Schottky, and carrier-reservoir contacts. Transfer characteristics and channel profiles. |
| 2D MOSFET | n-channel silicon MOSFET with self-consistent Poisson coupling; validated against the CEMC simulator from ViennaWD. |
| 2D Resistor | Uniformly doped silicon resistor β the simplest self-consistent device, a stepping stone to the MOSFET. |
| Hot-Carrier Dynamics in Metal-Halide Perovskites | Photo-excited cooling and hot-carrier device operation in bulk MHPs: wavevector-resolved hot-phonon bottleneck with dynamic screening, acoustic cascade, bipolar transport, recombination, band filling, and energy-selective extraction (V_OC, PCE). Presets for MAPbIβ, CsSnIβ, FAPbIβ, CsPbIβ, CsPbBrβ. |
| Hot-Phonon Transport in Ξ²-GaβOβ | High-field electron transport in bulk Ξ²-GaβOβ with equilibrium vs. wavevector-resolved non-equilibrium phonon occupations: velocityβfield curves, five-mode polar-phonon set, plasmon screening, impurity scattering. |
cd build
cmake .. -DVIENNAEMC_BUILD_TESTS=ON
make buildTests
ctest --output-on-failureTo install the headers and CMake config files to a system or custom path:
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install
make installThis copies:
- Headers to
<prefix>/include/ViennaEMC/ - CMake package files to
<prefix>/lib/cmake/ViennaEMC/
To uninstall:
make uninstallAfter installing, add the following to your project's CMakeLists.txt:
find_package(ViennaEMC REQUIRED
PATHS "/path/to/install/lib/cmake/ViennaEMC")
add_executable(myApp main.cpp)
target_include_directories(myApp PUBLIC ${VIENNAEMC_INCLUDE_DIRS})
target_link_libraries(myApp PRIVATE ${VIENNAEMC_LIBRARIES})A minimal simulation program has this structure:
#include <emcDevice.hpp>
#include <ParticleType/emcElectron.hpp>
#include <ValleyTypes/emcNonParabolicIsotropValley.hpp>
#include <ScatterMechanisms/emcFroehlichInteraction.hpp>
// ... include your particle handler
int main() {
// 1. Define material and device geometry
emcMaterial<double> material(eps_r, mass_density, ni, v_sound, bandgap);
emcDevice<double, 3> device{material, maxPos, spacing, tempK};
device.addConstantDopingRegion({0,0,0}, maxPos, dopingDensity);
// 2. Define carrier type, valley(s), and scatter mechanism(s)
std::map<int, std::unique_ptr<emcParticleType<...>>> particleTypes;
particleTypes[0] = std::make_unique<emcElectron<double, DeviceType>>(nrEnergies, maxEnergy);
particleTypes[0]->addValley(std::make_unique<emcNonParabolicIsotropValley<double>>(
relEffMass, constants::me, degFactor, alpha));
particleTypes[0]->addScatterMechanism({0},
std::make_unique<emcFroehlichEmission3D<double>>(
0, phononEnergy, relEffMass, eps_hi, eps_lo, tempK, "myMaterial"));
// 3. Create particle handler, generate particles, run loop
MyParticleHandler handler(device, particleTypes, field, dt);
handler.generateInitialParticles();
for (SizeType step = 0; step < nrSteps; step++)
handler.moveParticles(dt);
}The examples/bulkSimulation/ example is the recommended starting point.
A Python helper package emcPlottingFiles is provided in helper/emcPlottingFiles/. Install it once:
cd helper
pip install emcPlottingFilesRequired Python packages (installed automatically): numpy, matplotlib, pandas, scipy.
Most examples contain a Python plotting script (see each example's README). Run it from the directory where the output .txt files were written:
cd build/examples/bulkSimulation
python3 ../../../examples/bulkSimulation/plotBulkSimulationResults.pyThe API documentation is generated with Doxygen:
cd docs/doxygen
./make_doxygen.sh
firefox html/index.htmlIf CMake reports a path like /opt/intel/oneapi/compiler/2025.3/include does not exist, this is a mismatch between different oneAPI component versions. Two workarounds:
# Option A: create the missing directory
sudo mkdir -p /opt/intel/oneapi/compiler/2025.3/include
# Option B: remove the conflicting version from pkg-config search path
export PKG_CONFIG_PATH=$(echo $PKG_CONFIG_PATH | tr ':' '\n' \
| grep -v '2025.3' | tr '\n' ':')
cmake ..This means the CMake config is passing a plain string scalfmm instead of the imported target scalfmm::scalfmm. Check that cmake/ViennaEMCConfig.cmake.in uses:
list(APPEND VIENNAEMC_LIBRARIES scalfmm::scalfmm)This is almost always a sign that the phonon mode density Dph has Vsim in the denominator instead of the numerator. The correct formula in emcPhononBath.hpp is:
T Dph = q * q * dq * Vsim / (T(2) * constants::pi * constants::pi);Dph should be a large number (order 10β΅ for a 100 nm box with dq = 2Γ10βΉ mβ»ΒΉ).
This occurs when there are too few phonon modes per bin (small Dph), so each scatter event changes N_q by a large fraction. Solutions:
- Use fewer, wider bins: reduce
nrPhononBinsand increasedq. - For the single-mode approximation, use
nrPhononBins = 1anddq = 2e9(covers the full FrΓΆhlich q-range).
C++ block comments are terminated by the first */. Symbols like m*/m_e inside /** β¦ */ comments will prematurely close the comment block. Use m_star/m_e (ASCII only) in block comments. Similarly, avoid Unicode characters such as Ξ΅ β use ASCII descriptions (eps_inf) instead.
Current maintainer: Lado Filipovic
Former contributors: Laura Gollner, Robin Steiner, Anna Benzer
This library was developed at the Institute for Microelectronics, TU Wien.
See file LICENSE in the base directory for the license terms.