Advanced Example


Coming Soon

template <typename NumericType, int D>
class Ion : public rayParticle<Ion<NumericType, D>, NumericType> {
public:
  Ion(const NumericType passedMeanEnergy, const NumericType passedSigmaEnergy,
      const NumericType passedPower)
      : meanEnergy(passedMeanEnergy), sigmaEnergy(passedSigmaEnergy),
        power(passedPower) {}

  void surfaceCollision(NumericType rayWeight,
                        const rayTriple<NumericType> &rayDir,
                        const rayTriple<NumericType> &geomNormal,
                        const unsigned int primID, const int materialId,
                        rayTracingData<NumericType> &localData,
                        const rayTracingData<NumericType> *globalData,
                        rayRNG &Rng) override final {
    // collect data for this hit
    const double cosTheta = -rayInternal::DotProduct(rayDir, geomNormal);
    const double angle = std::acos(std::max(std::min(cosTheta, 1.), 0.));

    // angle and energy dependent yield
    NumericType f_enhanced_theta;
    if (cosTheta > 0.5) {
      f_enhanced_theta = 1.;
    } else {
      f_enhanced_theta = 3. - 6. * angle / rayInternal::PI;
    }
    NumericType f_sp_theta =
        (1 + 9.3 * (1 - cosTheta * cosTheta)) * cosTheta;

    double sqrtE = std::sqrt(E);
    NumericType energy_yield = std::max(sqrtE - thresholdEnergy, 0.)

    // two fluxes can be calculated from one particle        
    // sputtering yield ionSputteringRate
    localData.getVectorData(0)[primID] += rayWeight * energy_yield * f_sp_theta;

    // ion enhanced etching yield ionEnhancedRate
    localData.getVectorData(1)[primID] += rayWeight * energy_yield * f_enhanced_theta;
  }

  std::pair<NumericType, rayTriple<NumericType>>
  surfaceReflection(NumericType rayWeight, const rayTriple<NumericType> &rayDir,
                    const rayTriple<NumericType> &geomNormal,
                    const unsigned int primId, const int materialId,
                    const rayTracingData<NumericType> *globalData,
                    rayRNG &Rng) override final {
    // Reflect particle
    auto cosTheta = -rayInternal::DotProduct(rayDir, geomNormal);

    NumericType Eref_peak = cosTheta;
    // Gaussian distribution around the Eref_peak scaled by the particle energy
    NumericType NewEnergy;
    std::normal_distribution<NumericType> normalDist(E * Eref_peak, 0.1 * E);
    do {
      NewEnergy = normalDist(Rng);
    } while (NewEnergy > E || NewEnergy < 0.);

    // Set the flag to stop tracing if the energy is below a minimal energy
    if (NewEnergy > minEnergy) {
      E = NewEnergy;
      auto direction = rayReflectionSpecular<NumericType>(rayDir, geomNormal);
      return std::pair<NumericType, rayTriple<NumericType>>{1. - Eref_peak,
                                                            direction};
    } else {
      return std::pair<NumericType, rayTriple<NumericType>>{
          1., rayTriple<NumericType>{0., 0., 0.}};
    }
  }
  void initNew(rayRNG &RNG) override final {
    // Initialize energy of particle
    std::normal_distribution<NumericType> normalDist{meanEnergy, sigmaEnergy};
    do {
      E = normalDist(RNG);
    } while (E < minEnergy);
  }
  NumericType getSourceDistributionPower() const override final {
    return power;
  }
  std::vector<std::string> getLocalDataLabels() const override final {
    return {"ionSputteringRate", "ionEnhancedRate"};
  }

private:
  // ion energy
  const NumericType minEnergy = 4.; // Discard particles with energy < 4
  const NumericType meanEnergy;
  const NumericType sigmaEnergy;
  const NumericType power;
  NumericType E;
};