Skip to content

Commit

Permalink
Process fixes and README update (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
tobre1 authored Feb 25, 2025
1 parent b0dee56 commit 3773e72
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 136 deletions.
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

[![🐍 Build Bindings](https://github.com/ViennaTools/ViennaPS/actions/workflows/python.yml/badge.svg)](https://github.com/ViennaTools/ViennaPS/actions/workflows/python.yml)
[![🧪 Run Tests](https://github.com/ViennaTools/ViennaPS/actions/workflows/build.yml/badge.svg)](https://github.com/ViennaTools/ViennaPS/actions/workflows/build.yml)
[![PyPi Version](https://img.shields.io/pypi/v/ViennaPS?logo=pypi)](https://pypi.org/project/ViennaPS/)

</div>

Expand All @@ -14,9 +15,23 @@ ViennaPS is a header-only C++ process simulation library, which includes surface
> [!NOTE]
> ViennaPS is under heavy development and improved daily. If you do have suggestions or find bugs, please let us know!
## Quick Start

To install ViennaPS for Python, simply run:

```sh
pip install ViennaPS
```

To use ViennaPS in C++, clone the repository and follow the installation steps below.

For full documentation, visit [ViennaPS Documentation](https://viennatools.github.io/ViennaPS/).

## Releases
Releases are tagged on the master branch and available in the [releases section](https://github.com/ViennaTools/ViennaPS/releases).

ViennaPS is also available on the [Python Package Index (PyPI)](https://pypi.org/project/ViennaPS/) for most platforms.

## Building

### Supported Operating Systems
Expand Down Expand Up @@ -54,7 +69,7 @@ If the dependencies are not found on the system, they will be built from source.
> [!NOTE]
> __For more detailed installation instructions and troubleshooting tips, please refer to the ViennaPS [documentation](https://viennatools.github.io/ViennaPS/inst/).__
ViennaPS operates as a header-only library, eliminating the need for a formal installation process. Nonetheless, we advise following the procedure to neatly organize and relocate all header files to a designated directory:
ViennaPS is a header-only library, so no formal installation is required. However, following the steps below helps organize and manage dependencies more effectively:

```bash
git clone https://github.com/ViennaTools/ViennaPS.git
Expand All @@ -77,7 +92,7 @@ cd ViennaPS
pip install .
```

> Some functionalities of the ViennaPS Python module only work in combination with the ViennaLS Python module. It is therefore recommended to additionally install the ViennaLS Python module on your system. Instructions to do so can be found in the [ViennaLS Git Repository](https://github.com/ViennaTools/viennals).
> Some features of the ViennaPS Python module require the ViennaLS Python module. It is therefore recommended to additionally install the ViennaLS Python module on your system. Instructions to do so can be found in the [ViennaLS Git Repository](https://github.com/ViennaTools/viennals).
## Using the Python package

Expand Down Expand Up @@ -149,6 +164,10 @@ This [example](https://github.com/ViennaTools/ViennaPS/tree/master/examples/hole

The image presents the results of different flux configurations, as tested in _testFluxes.py_. Each structure represents a variation in flux conditions, leading to differences in hole shape, depth, and profile characteristics. The variations highlight the influence of ion and neutral fluxes on the etching process.

> [!NOTE]
> The underlying model may change in future releases, so running this example in newer versions of ViennaPS might not always reproduce exactly the same results.
> The images shown here were generated using **ViennaPS v3.3.0**.
<div align="center">
<img src="assets/sf6o2_results.png" width=700 style="background-color:white;">
</div>
Expand Down Expand Up @@ -228,7 +247,7 @@ cmake --build build --target format

## Authors

Current contributors: Tobias Reiter, Noah Karnel, Lado Filipovic
Current contributors: Tobias Reiter, Lado Filipovic, Noah Karnel

Contact us via: [email protected]

Expand Down
11 changes: 6 additions & 5 deletions examples/cantileverWetEtching/cantileverWetEtching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ int main(int argc, char **argv) {
const NumericType gridDelta = 5.; // um

// Read GDS file and convert to level set
typename ls::Domain<NumericType, D>::BoundaryType boundaryCons[D];
ps::BoundaryType boundaryCons[D];
for (int i = 0; i < D - 1; i++)
boundaryCons[i] = ls::Domain<NumericType, D>::BoundaryType::
REFLECTIVE_BOUNDARY; // boundary conditions in x and y direction
boundaryCons[D - 1] = ls::Domain<NumericType, D>::BoundaryType::
INFINITE_BOUNDARY; // open boundary in z direction
boundaryCons[i] =
ps::BoundaryType::REFLECTIVE_BOUNDARY; // boundary conditions in x and y
// direction
boundaryCons[D - 1] =
ps::BoundaryType::INFINITE_BOUNDARY; // open boundary in z direction
auto gds_mask =
ps::SmartPointer<ps::GDSGeometry<NumericType, D>>::New(gridDelta);
gds_mask->setBoundaryConditions(boundaryCons);
Expand Down
8 changes: 4 additions & 4 deletions examples/cantileverWetEtching/cantileverWetEtching.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

# read GDS mask file
boundaryConditions = [
vls.BoundaryConditionEnum.REFLECTIVE_BOUNDARY,
vls.BoundaryConditionEnum.REFLECTIVE_BOUNDARY,
vls.BoundaryConditionEnum.INFINITE_BOUNDARY,
vps.BoundaryType.REFLECTIVE_BOUNDARY,
vps.BoundaryType.REFLECTIVE_BOUNDARY,
vps.BoundaryType.INFINITE_BOUNDARY,
]

gds_mask = vps.GDSGeometry(gridDelta)
Expand Down Expand Up @@ -62,7 +62,7 @@
process.setProcessModel(model)
process.setProcessDuration(5.0 * 60.0) # 5 minutes of etching
process.setIntegrationScheme(
vls.IntegrationSchemeEnum.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER
vps.IntegrationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER
)

for n in range(minutes):
Expand Down
10 changes: 5 additions & 5 deletions examples/oxideRegrowth/oxideRegrowth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ int main(int argc, char **argv) {
return -1;
}

auto domain = ps::SmartPointer<ps::Domain<NumericType, D>>::New();
auto domain = ps::SmartPointer<ps::Domain<NumericType, D>>::New(
params.get("gridDelta"), params.get("xExtent"), params.get("yExtent"));
ps::MakeStack<NumericType, D>(
domain, params.get("gridDelta"), params.get("xExtent"),
params.get("yExtent"), params.get("numLayers"), params.get("layerHeight"),
params.get("substrateHeight"), 0. /*hole radius*/,
params.get("trenchWidth"), 0., false)
domain, params.get("numLayers"), params.get("layerHeight"),
params.get("substrateHeight"), 0. /*holeRadius*/,
params.get("trenchWidth"), 0. /*maskHeight*/, 0. /*taperAngle*/)
.apply();
// copy top layer for deposition
domain->duplicateTopLevelSet(ps::Material::Polymer);
Expand Down
123 changes: 36 additions & 87 deletions include/viennaps/models/psSF6O2Etching.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,24 +251,23 @@ class SF6O2Ion
params.Ions.n_l);
}
// Gaussian distribution around the Eref_peak scaled by the particle energy
NumericType NewEnergy;
NumericType newEnergy;
std::normal_distribution<NumericType> normalDist(E * Eref_peak, 0.1 * E);
do {
NewEnergy = normalDist(Rng);
} while (NewEnergy > E || NewEnergy < 0.);

NumericType sticking = 0.;
// NumericType sticking = 1.;
// if (incAngle > params.Ions.thetaRMin) {
// sticking =
// 1. - std::min((incAngle - params.Ions.thetaRMin) /
// (params.Ions.thetaRMax - params.Ions.thetaRMin),
// NumericType(1.));
// }
newEnergy = normalDist(Rng);
} while (newEnergy > E || newEnergy < 0.);

NumericType sticking = 1.;
if (incAngle > params.Ions.thetaRMin) {
sticking =
1. - std::clamp((incAngle - params.Ions.thetaRMin) /
(params.Ions.thetaRMax - params.Ions.thetaRMin),
NumericType(0.), NumericType(1.));
}

// Set the flag to stop tracing if the energy is below the threshold
if (NewEnergy > params.Si.Eth_ie) {
E = NewEnergy;
if (newEnergy > params.Si.Eth_ie) {
E = newEnergy;
auto direction = viennaray::ReflectionConedCosine<NumericType, D>(
rayDir, geomNormal, Rng,
M_PI_2 - std::min(incAngle, params.Ions.minAngle));
Expand Down Expand Up @@ -303,12 +302,17 @@ class SF6O2Ion
};

template <typename NumericType, int D>
class SF6O2Etchant
: public viennaray::Particle<SF6O2Etchant<NumericType, D>, NumericType> {
class SF6O2Neutral
: public viennaray::Particle<SF6O2Neutral<NumericType, D>, NumericType> {
const SF6O2Parameters<NumericType> &params;
const std::string fluxLabel;
const std::unordered_map<int, NumericType> &beta_map;

public:
SF6O2Etchant(const SF6O2Parameters<NumericType> &pParams) : params(pParams) {}
SF6O2Neutral(const SF6O2Parameters<NumericType> &pParams,
const std::string pFluxLabel,
std::unordered_map<int, NumericType> &pBetaMap)
: params(pParams), fluxLabel(pFluxLabel), beta_map(pBetaMap) {}

void surfaceCollision(NumericType rayWeight, const Vec3D<NumericType> &,
const Vec3D<NumericType> &, const unsigned int primID,
Expand Down Expand Up @@ -347,70 +351,13 @@ class SF6O2Etchant
}
NumericType getSourceDistributionPower() const override final { return 1.; }
std::vector<std::string> getLocalDataLabels() const override final {
return {"etchantFlux"};
return {fluxLabel};
}

private:
NumericType sticking(const int matieralId) const {
auto beta = params.beta_F.find(matieralId);
if (beta != params.beta_F.end())
return beta->second;

// default value
return 1.0;
}
};

template <typename NumericType, int D>
class SF6O2Oxygen
: public viennaray::Particle<SF6O2Oxygen<NumericType, D>, NumericType> {
const SF6O2Parameters<NumericType> &params;

public:
SF6O2Oxygen(const SF6O2Parameters<NumericType> &pParams) : params(pParams) {}

void surfaceCollision(NumericType rayWeight, const Vec3D<NumericType> &,
const Vec3D<NumericType> &, const unsigned int primID,
const int materialId,
viennaray::TracingData<NumericType> &localData,
const viennaray::TracingData<NumericType> *globalData,
RNG &) override final {
NumericType S_eff = 1.;
if (params.fluxIncludeSticking) {
const auto &phi_F = globalData->getVectorData(0)[primID];
const auto &phi_O = globalData->getVectorData(1)[primID];
NumericType beta = sticking(materialId);
S_eff = beta * std::max(1. - phi_O - phi_F, 0.);
}

localData.getVectorData(0)[primID] += rayWeight * S_eff;
}
std::pair<NumericType, Vec3D<NumericType>>
surfaceReflection(NumericType rayWeight, const Vec3D<NumericType> &rayDir,
const Vec3D<NumericType> &geomNormal,
const unsigned int primID, const int materialId,
const viennaray::TracingData<NumericType> *globalData,
RNG &rngState) override final {

NumericType S_eff;
const auto &phi_F = globalData->getVectorData(0)[primID];
const auto &phi_O = globalData->getVectorData(1)[primID];
NumericType beta = sticking(materialId);
S_eff = beta * std::max(1. - phi_O - phi_F, 0.);

auto direction =
viennaray::ReflectionDiffuse<NumericType, D>(geomNormal, rngState);
return std::pair<NumericType, Vec3D<NumericType>>{S_eff, direction};
}
NumericType getSourceDistributionPower() const override final { return 1.; }
std::vector<std::string> getLocalDataLabels() const override final {
return {"oxygenFlux"};
}

private:
NumericType sticking(const int matieralId) const {
auto beta = params.beta_O.find(matieralId);
if (beta != params.beta_O.end())
auto beta = beta_map.find(matieralId);
if (beta != beta_map.end())
return beta->second;

// default value
Expand All @@ -422,7 +369,6 @@ class SF6O2Oxygen
/// Model for etching Si in a SF6/O2 plasma. The model is based on the paper by
/// Belen et al., Vac. Sci. Technol. A 23, 99–113 (2005),
/// DOI: https://doi.org/10.1116/1.1830495
/// The resulting rate is in units of um / s.
template <typename NumericType, int D>
class SF6O2Etching : public ProcessModel<NumericType, D> {
public:
Expand Down Expand Up @@ -467,25 +413,28 @@ class SF6O2Etching : public ProcessModel<NumericType, D> {
}

// particles
this->particles.clear();
auto ion = std::make_unique<impl::SF6O2Ion<NumericType, D>>(params);
auto etchant = std::make_unique<impl::SF6O2Etchant<NumericType, D>>(params);
auto oxygen = std::make_unique<impl::SF6O2Oxygen<NumericType, D>>(params);
this->insertNextParticleType(ion);
auto etchant = std::make_unique<impl::SF6O2Neutral<NumericType, D>>(
params, "etchantFlux", params.beta_F);
this->insertNextParticleType(etchant);
if (params.oxygenFlux > 0) {
auto oxygen = std::make_unique<impl::SF6O2Neutral<NumericType, D>>(
params, "oxygenFlux", params.beta_O);
this->insertNextParticleType(oxygen);
}

// surface model
auto surfModel =
SmartPointer<impl::SF6O2SurfaceModel<NumericType, D>>::New(params);
this->setSurfaceModel(surfModel);

// velocity field
auto velField = SmartPointer<DefaultVelocityField<NumericType, D>>::New(2);

this->setSurfaceModel(surfModel);
this->setVelocityField(velField);

this->setProcessName("SF6O2Etching");
this->particles.clear();
this->insertNextParticleType(ion);
this->insertNextParticleType(etchant);
if (params.oxygenFlux > 0)
this->insertNextParticleType(oxygen);
}

SF6O2Parameters<NumericType> params;
Expand Down
Loading

0 comments on commit 3773e72

Please sign in to comment.