diff --git a/examples/TEOSPECVDTrenchDeposition/CMakeLists (copy).txt b/examples/TEOSPECVDTrenchDeposition/CMakeLists (copy).txt new file mode 100644 index 0000000..8fa5bf5 --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/CMakeLists (copy).txt @@ -0,0 +1,8 @@ +project(TEOSTrenchDeposition LANGUAGES CXX) + +add_executable(TEOSPECVD "TEOSPECVD.cpp") +target_link_libraries(TEOSPECVD PRIVATE ViennaPS) +configure_file(TEOSPECVD_config.txt ${CMAKE_CURRENT_BINARY_DIR}/TEOSPECVD_config.txt COPYONLY) + +add_dependencies(ViennaPS_Examples TEOSPECVD) +setup_windows_bat(TEOSPECVD ${VIENNAPS_EXAMPLES_LIB}) diff --git a/examples/TEOSPECVDTrenchDeposition/CMakeLists.txt b/examples/TEOSPECVDTrenchDeposition/CMakeLists.txt new file mode 100644 index 0000000..40d0211 --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.12) +project("TEOS_PE-CVD") + +# set default build type +SET(DEFAULT_BUILD_TYPE "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +set (CMAKE_CXX_STANDARD 17) + +list(APPEND CMAKE_PREFIX_PATH "/home/filipov/Software/ViennaTools/VPS") + +find_package(ViennaPS) + +# CMake target +add_executable(TEOSPECVD TEOSPECVD.cpp) +target_link_libraries(TEOSPECVD PUBLIC ViennaTools::ViennaPS) +configure_file(TEOSPECVD_config.txt ${CMAKE_CURRENT_BINARY_DIR}/TEOSPECVD_config.txt COPYONLY) diff --git a/examples/TEOSPECVDTrenchDeposition/TEOSPECVD.cpp b/examples/TEOSPECVDTrenchDeposition/TEOSPECVD.cpp new file mode 100644 index 0000000..1446a24 --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/TEOSPECVD.cpp @@ -0,0 +1,64 @@ +#include +#include + +#include +#include + +#include "parameters.hpp" + +int main(int argc, char **argv) { + psLogger::setLogLevel(psLogLevel::DEBUG); + + using NumericType = double; + constexpr int D = 2; + + // Parse the parameters + Parameters params; + if (argc > 1) { + auto config = psUtils::readConfigFile(argv[1]); + if (config.empty()) { + std::cerr << "Empty config provided" << std::endl; + return -1; + } + params.fromMap(config); + } + + auto geometry = psSmartPointer>::New(); + psMakeTrench( + geometry, params.gridDelta /* grid delta */, params.xExtent /*x extent*/, + params.yExtent /*y extent*/, params.trenchWidth /*trench width*/, + params.trenchHeight /*trench height*/, + params.taperAngle /* tapering angle */, 0 /*base height*/, + false /*periodic boundary*/, false /*create mask*/, + psMaterial::Si /*material*/) + .apply(); + + // copy top layer to capture deposition + geometry->duplicateTopLevelSet(psMaterial::SiO2); + + // process model encompasses surface model and particle types + auto model = psSmartPointer>::New( + params.stickingProbabilityRadical /*radical sticking probability*/, + params.depositionRateRadical /*neutral radical deposition rate*/, + params.depositionRateIon /*charged ion deposition rate*/, + params.exponentIon /*cosine power exponent*/, + params.stickingProbabilityIon /*ion sticking probability*/, + params.reactionOrderRadical /*radical reaction order*/, + params.reactionOrderIon /*ion reaction order*/, + params.minAngleIon /*minimum reflected angle ion*/); + + psProcess process; + process.setDomain(geometry); + process.setProcessModel(model); + process.setNumberOfRaysPerPoint(params.numRaysPerPoint); + process.setProcessDuration(params.processTime); + + geometry->saveSurfaceMesh("TEOS_PECVD_initial.vtp"); + + process.apply(); + + geometry->saveSurfaceMesh("TEOS_PECVD_final.vtp"); + + if constexpr (D == 2) + geometry->saveVolumeMesh("TEOS_PECVD_final"); +} diff --git a/examples/TEOSPECVDTrenchDeposition/TEOSPECVD_config.txt b/examples/TEOSPECVDTrenchDeposition/TEOSPECVD_config.txt new file mode 100644 index 0000000..7d84f03 --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/TEOSPECVD_config.txt @@ -0,0 +1,25 @@ +# Domain +gridDelta=2.5 # um +xExtent=110. # um +yExtent=110. # um (3D mode only) + +# Geometry +trenchWidth=70 # um +trenchHeight=70 # um +taperAngle=0. # degrees + +# Process +processTime=350 # min +numRaysPerPoint=1000 + +# radical +depositionRateRadical=0.05 # um / min +stickingProbabilityRadical=1e-4 +reactionOrderRadical=1.0 + +# ion +depositionRateIon=0.05 # um / min +stickingProbabilityIon=1. +reactionOrderIon=1.0 +exponentIon=100. +minAngleIon=1.34 \ No newline at end of file diff --git a/examples/TEOSPECVDTrenchDeposition/multiTEOS.py b/examples/TEOSPECVDTrenchDeposition/multiTEOS.py new file mode 100644 index 0000000..3859b5c --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/multiTEOS.py @@ -0,0 +1,63 @@ +from argparse import ArgumentParser + +# parse config file name and simulation dimension +parser = ArgumentParser( + prog="multiTEOS", + description="Run a multi TEOS deposition process on a trench geometry.", +) +parser.add_argument("-D", "-DIM", dest="dim", type=int, default=2) +parser.add_argument("filename") +args = parser.parse_args() + +# switch between 2D and 3D mode +if args.dim == 2: + print("Running 2D simulation.") + import viennaps2d as vps +else: + print("Running 3D simulation.") + import viennaps3d as vps + +params = vps.ReadConfigFile(args.filename) + +geometry = vps.Domain() +vps.MakeTrench( + domain=geometry, + gridDelta=params["gridDelta"], + xExtent=params["xExtent"], + yExtent=params["yExtent"], + trenchWidth=params["trenchWidth"], + trenchDepth=params["trenchHeight"], + taperingAngle=params["taperAngle"], + baseHeight=0.0, + periodicBoundary=False, + makeMask=False, + material=vps.Material.Si, +).apply() + +# copy top layer to capture deposition +geometry.duplicateTopLevelSet(vps.Material.SiO2) + +# process model encompasses surface model and particle types +model = vps.TEOSDeposition( + stickingProbabilityP1=params["stickingProbabilityP1"], + rateP1=params["depositionRateP1"], + orderP1=params["reactionOrderP1"], + stickingProbabilityP2=params["stickingProbabilityP2"], + rateP2=params["depositionRateP2"], + orderP2=params["reactionOrderP2"], +) + +process = vps.Process() +process.setDomain(geometry) +process.setProcessModel(model) +process.setNumberOfRaysPerPoint(int(params["numRaysPerPoint"])) +process.setProcessDuration(params["processTime"]) + +geometry.saveSurfaceMesh("MultiTEOS_initial.vtp") + +process.apply() + +geometry.saveSurfaceMesh("MultiTEOS_final.vtp") + +if args.dim == 2: + geometry.saveVolumeMesh("MultiTEOS_final") diff --git a/examples/TEOSPECVDTrenchDeposition/parameters.hpp b/examples/TEOSPECVDTrenchDeposition/parameters.hpp new file mode 100644 index 0000000..c367799 --- /dev/null +++ b/examples/TEOSPECVDTrenchDeposition/parameters.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +#include + +template struct Parameters { + // Domain + NumericType gridDelta = 5.; // um + NumericType xExtent = 100.; // um + NumericType yExtent = 100.; // um (3D mode only) + + // Geometry + NumericType trenchWidth = 70; // um + NumericType trenchHeight = 70; // um + NumericType taperAngle = 0.; // degrees + + // Process + NumericType processTime = 350.; // min + int numRaysPerPoint = 2000; + + // Radical particle + NumericType depositionRateRadical = 0.1; + NumericType stickingProbabilityRadical = 0.1; + NumericType reactionOrderRadical = 1.; + + // Ion particle + NumericType depositionRateIon = 0.1; + NumericType stickingProbabilityIon = 1e-4; + NumericType reactionOrderIon = 1.; + NumericType exponentIon = 100.; + NumericType minAngleIon = 1.3962634; + + Parameters() {} + + void fromMap(std::unordered_map &m) { + psUtils::AssignItems( // + m, // + psUtils::Item{"gridDelta", gridDelta}, // + psUtils::Item{"xExtent", xExtent}, // + psUtils::Item{"yExtent", yExtent}, // + psUtils::Item{"trenchWidth", trenchWidth}, // + psUtils::Item{"trenchHeight", trenchHeight}, // + psUtils::Item{"taperAngle", taperAngle}, // + psUtils::Item{"processTime", processTime}, // + psUtils::Item{"numRaysPerPoint", numRaysPerPoint}, // + psUtils::Item{"depositionRateRadical", depositionRateRadical}, // + psUtils::Item{"stickingProbabilityRadical", stickingProbabilityRadical}, // + psUtils::Item{"reactionOrderRadical", reactionOrderRadical}, // + psUtils::Item{"depositionRateIon", depositionRateIon}, // + psUtils::Item{"stickingProbabilityIon", stickingProbabilityIon}, // + psUtils::Item{"reactionOrderIon", reactionOrderIon}, // + psUtils::Item{"exponentIon", exponentIon}, // + psUtils::Item{"minAngleIon", minAngleIon} // + ); + } +}; diff --git a/examples/TEOSTrenchDeposition/CMakeLists (copy).txt b/examples/TEOSTrenchDeposition/CMakeLists (copy).txt new file mode 100644 index 0000000..23f2be0 --- /dev/null +++ b/examples/TEOSTrenchDeposition/CMakeLists (copy).txt @@ -0,0 +1,19 @@ +project(TEOSTrenchDeposition LANGUAGES CXX) + +add_executable(singleTEOS "singleTEOS.cpp") +target_link_libraries(singleTEOS PRIVATE ViennaPS) + +configure_file(singleTEOS.py ${CMAKE_CURRENT_BINARY_DIR}/singleTEOS.py COPYONLY) +configure_file(singleTEOS_config.txt ${CMAKE_CURRENT_BINARY_DIR}/singleTEOS_config.txt COPYONLY) + +add_dependencies(ViennaPS_Examples singleTEOS) +setup_windows_bat(singleTEOS ${VIENNAPS_EXAMPLES_LIB}) + +add_executable(multiTEOS "multiTEOS.cpp") +target_link_libraries(multiTEOS PRIVATE ViennaPS) + +configure_file(multiTEOS.py ${CMAKE_CURRENT_BINARY_DIR}/multiTEOS.py COPYONLY) +configure_file(multiTEOS_config.txt ${CMAKE_CURRENT_BINARY_DIR}/multiTEOS_config.txt COPYONLY) + +add_dependencies(ViennaPS_Examples multiTEOS) +setup_windows_bat(multiTEOS ${VIENNAPS_EXAMPLES_LIB}) diff --git a/examples/TEOSTrenchDeposition/CMakeLists.txt b/examples/TEOSTrenchDeposition/CMakeLists.txt index 23f2be0..9602721 100644 --- a/examples/TEOSTrenchDeposition/CMakeLists.txt +++ b/examples/TEOSTrenchDeposition/CMakeLists.txt @@ -1,19 +1,24 @@ -project(TEOSTrenchDeposition LANGUAGES CXX) +cmake_minimum_required(VERSION 3.12) +project("TEOSDeposition") -add_executable(singleTEOS "singleTEOS.cpp") -target_link_libraries(singleTEOS PRIVATE ViennaPS) +# set default build type +SET(DEFAULT_BUILD_TYPE "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() -configure_file(singleTEOS.py ${CMAKE_CURRENT_BINARY_DIR}/singleTEOS.py COPYONLY) -configure_file(singleTEOS_config.txt ${CMAKE_CURRENT_BINARY_DIR}/singleTEOS_config.txt COPYONLY) +set (CMAKE_CXX_STANDARD 17) -add_dependencies(ViennaPS_Examples singleTEOS) -setup_windows_bat(singleTEOS ${VIENNAPS_EXAMPLES_LIB}) +list(APPEND CMAKE_PREFIX_PATH "/home/filipov/Software/ViennaTools/VPS") -add_executable(multiTEOS "multiTEOS.cpp") -target_link_libraries(multiTEOS PRIVATE ViennaPS) +find_package(ViennaPS) -configure_file(multiTEOS.py ${CMAKE_CURRENT_BINARY_DIR}/multiTEOS.py COPYONLY) +# CMake target +add_executable(TEOSDeposition multiTEOS.cpp) +target_link_libraries(TEOSDeposition PUBLIC ViennaTools::ViennaPS) configure_file(multiTEOS_config.txt ${CMAKE_CURRENT_BINARY_DIR}/multiTEOS_config.txt COPYONLY) - -add_dependencies(ViennaPS_Examples multiTEOS) -setup_windows_bat(multiTEOS ${VIENNAPS_EXAMPLES_LIB}) diff --git a/include/viennaps/models/psTEOSPECVD.hpp b/include/viennaps/models/psTEOSPECVD.hpp new file mode 100644 index 0000000..d081461 --- /dev/null +++ b/include/viennaps/models/psTEOSPECVD.hpp @@ -0,0 +1,173 @@ +#pragma once + +#include "../psProcessModel.hpp" + +#include +#include +#include + +namespace TEOSPECVDImplementation { +template +class PECVDSurfaceModel : public psSurfaceModel { + const NumericType radicalRate; + const NumericType radicalReactionOrder; + const NumericType ionRate; + const NumericType ionReactionOrder; + +public: + PECVDSurfaceModel(const NumericType passedRadicalRate, + const NumericType passedRadicalReactionOrder, + const NumericType passedIonRate, + const NumericType passedIonReactionOrder) + : radicalRate(passedRadicalRate), radicalReactionOrder(passedRadicalReactionOrder), + ionRate(passedIonRate), ionReactionOrder(passedIonReactionOrder) {} + + psSmartPointer> calculateVelocities( + psSmartPointer> rates, + const std::vector> &coordinates, + const std::vector &materialIDs) override { + // define the surface reaction here + auto particleFluxRadical = rates->getScalarData("radicalFlux"); + auto particleFluxIon = rates->getScalarData("ionFlux"); + + std::vector velocity(particleFluxRadical->size(), 0.); + + for (std::size_t i = 0; i < velocity.size(); i++) { + // calculate surface velocity based on particle fluxes + velocity[i] = + radicalRate * std::pow(particleFluxRadical->at(i), radicalReactionOrder) + + ionRate * std::pow(particleFluxIon->at(i), ionReactionOrder); + } + + return psSmartPointer>::New(velocity); + } +}; + +// Particle type (modify at you own risk) +template +class Radical + : public rayParticle, NumericType> { +public: + Radical(const NumericType pStickingProbability, + const std::string pDataLabel = "radicalFlux") + : stickingProbability(pStickingProbability), + dataLabel(pDataLabel) {} + std::pair> + surfaceReflection(NumericType rayWeight, const rayTriple &rayDir, + const rayTriple &geomNormal, + const unsigned int primID, const int materialId, + const rayTracingData *globalData, + rayRNG &Rng) override final { + auto direction = rayReflectionDiffuse(geomNormal, Rng); + return std::pair>{stickingProbability, + direction}; + } + void surfaceCollision(NumericType rayWeight, + const rayTriple &rayDir, + const rayTriple &geomNormal, + const unsigned int primID, const int materialId, + rayTracingData &localData, + const rayTracingData *globalData, + rayRNG &Rng) override final { + localData.getVectorData(0)[primID] += rayWeight; + } + NumericType getSourceDistributionPower() const override final { return 1; } + std::vector getLocalDataLabels() const override final { + return {dataLabel}; + } + +private: + const NumericType stickingProbability; + const std::string dataLabel = "radicalFlux"; +}; + +template +class Ion : public rayParticle, NumericType> { +public: + Ion(const NumericType pStickingProbability, + const NumericType pExponent, + const NumericType pMinAngle, + const std::string pDataLabel = "ionFlux") + : stickingProbability(pStickingProbability), + exponent(pExponent), minAngle(pMinAngle), + dataLabel(pDataLabel) {} + + std::pair> + surfaceReflection(NumericType rayWeight, const rayTriple &rayDir, + const rayTriple &geomNormal, + const unsigned int primId, const int materialId, + const rayTracingData *globalData, + rayRNG &Rng) override final { + auto cosTheta = -rayInternal::DotProduct(rayDir, geomNormal); + + assert(cosTheta >= 0 && "Hit backside of disc"); + assert(cosTheta <= 1 + 1e-6 && "Error in calculating cos theta"); + + NumericType incAngle = + std::acos(std::max(std::min(cosTheta, static_cast(1.)), + static_cast(0.))); + + auto direction = rayReflectionConedCosine( + rayDir, geomNormal, Rng, std::max(incAngle, minAngle)); + return std::pair>{stickingProbability, direction}; + } + + void surfaceCollision(NumericType rayWeight, + const rayTriple &rayDir, + const rayTriple &geomNormal, + const unsigned int primID, const int materialId, + rayTracingData &localData, + const rayTracingData *globalData, + rayRNG &Rng) override final { + localData.getVectorData(0)[primID] += rayWeight; + } + + NumericType getSourceDistributionPower() const override final { + return exponent; + } + std::vector getLocalDataLabels() const override final { + return {dataLabel}; + } + +private: + const NumericType stickingProbability; + const NumericType exponent; + const NumericType minAngle; + const std::string dataLabel = "ionFlux"; +}; +} // namespace TEOSPECVDImplementation + +template +class psTEOSPECVD : public psProcessModel { +public: + psTEOSPECVD(const NumericType pRadicalSticking, + const NumericType pRadicalRate, + const NumericType pIonRate, + const NumericType pIonExponent, + const NumericType pIonSticking = 1., + const NumericType pRadicalOrder = 1., + const NumericType pIonOrder = 1., + const NumericType pIonMinAngle = 0.) { + // velocity field + auto velField = psSmartPointer>::New(2); + this->setVelocityField(velField); + + // particles + auto radical = std::make_unique< + TEOSPECVDImplementation::Radical>( + pRadicalSticking, "radicalFlux"); + auto ion = std::make_unique< + TEOSPECVDImplementation::Ion>( + pIonSticking, pIonExponent, pIonMinAngle, "ionFlux"); + + // surface model + auto surfModel = + psSmartPointer>::New(pRadicalRate, pRadicalOrder, pIonRate, pIonOrder); + + this->setSurfaceModel(surfModel); + this->insertNextParticleType(radical); + this->insertNextParticleType(ion); + this->setProcessName("TEOSPECVD"); + } +}; diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index a5e1355..6f77557 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -58,6 +58,7 @@ #include #include #include +#include // visualization #include @@ -570,6 +571,24 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { pybind11::arg("stickingProbabilityP2") = 0., pybind11::arg("rateP2") = 0., pybind11::arg("orderP2") = 0.); + // TEOS PE-CVD + pybind11::class_, + psSmartPointer>>( + module, "TEOSPECVD", processModel) + .def(pybind11::init( + &psSmartPointer>::New< + const T /*stR*/, const T /*rateR*/, const T /*orderR*/, + const T /*stI*/, const T /*rateI*/, const T /*orderI*/, + const T /*exponentI*/, const T /*minAngleIon*/>), + pybind11::arg("stickingProbabilityRadical"), + pybind11::arg("depositionRateRadical"), + pybind11::arg("depositionRateIon"), + pybind11::arg("exponentIon"), + pybind11::arg("stickingProbabilityIon") = 1., + pybind11::arg("reactionOrderRadical") = 1., + pybind11::arg("reactionOrderIon") = 1., + pybind11::arg("minAngleIon") = 0.); + // SF6O2 Parameters pybind11::class_::MaskType>( module, "SF6O2ParametersMask")