LCOV - code coverage report
Current view: top level - coupling/filtering/filters - Gauss.cpph (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 68 0
Test Date: 2026-08-21 15:14:06 Functions: 0.0 % 10 0

            Line data    Source code
       1              : // This file is part of the Mamico project. For conditions of distribution
       2              : // and use, please see the copyright notice in Mamico's main folder, or at
       3              : // www5.in.tum.de/mamico
       4              : 
       5              : /** Implementation of Gauss.h
       6              :  *  @author Felix Maurer
       7              :  */
       8              : 
       9              : // Member functions of Gauss.h:
      10              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
      11              : // TODO: This is very much hardcoded for kernel radius = 1
      12            0 : void coupling::filtering::Gauss<dim, scope...>::operator()() {
      13              : #ifdef DEBUG_GAUSS
      14              :   std::cout << "             GAUSS(Dim: " << _dim << "): Applying filter..." << std::endl;
      15              : #endif
      16              : 
      17              :   using namespace coupling::indexing;
      18              : 
      19              :   ScalarIndex index;
      20              :   ScalarIndex indexAbove;
      21              :   ScalarIndex indexBelow;
      22              : 
      23            0 :   for (unsigned int raw_index = 0; raw_index < _inputCells.size(); raw_index++) {
      24              : 
      25              :     // construct CellIndex using raw index
      26            0 :     index = ScalarIndex{raw_index};
      27              : 
      28              :     // make use of implicit conversion between linear <-> vector indices
      29            0 :     indexAbove = getIndexAbove(index, _dim);
      30            0 :     indexBelow = getIndexBelow(index, _dim);
      31              : 
      32              :     /*
      33              :     std::cout << "INDEX: " << index << std::endl;
      34              :     std::cout << "ABOVE: " << indexAbove << std::endl;
      35              :     std::cout << "BELOW: " << indexBelow << std::endl;
      36              :     */
      37              : 
      38              :     //[0] = below, [1] = at index, [2] = above
      39            0 :     double weights[3] = {_kernel[0], _kernel[1], _kernel[2]};
      40              : 
      41              :     // only one of these two cases can occur at once
      42            0 :     if (indexBelow == index) {
      43              :       // set weight of out of bounds index to zero
      44            0 :       weights[0] = 0;
      45              : 
      46            0 :       switch (_extrapolationStrategy) {
      47              :       case NONE:
      48              :         break;
      49            0 :       case MIRROR:
      50            0 :         weights[2] *= 2;
      51            0 :         break;
      52            0 :       case REFLECT:
      53            0 :         weights[1] *= 2;
      54            0 :         break;
      55              :       }
      56              : 
      57              :       // normalize the other two weights
      58            0 :       double weightsSum = weights[1] + weights[2];
      59            0 :       weights[1] /= weightsSum;
      60            0 :       weights[2] /= weightsSum;
      61              :     }
      62              : 
      63              :     // Since the domain has to be larger than one unit in all directions, not
      64              :     // both the index above and below can be illegal at the same time.
      65            0 :     else if (indexAbove == index) {
      66              :       // set weight of out of bounds index to zero
      67            0 :       weights[2] = 0;
      68              : 
      69            0 :       switch (_extrapolationStrategy) {
      70              :       case NONE:
      71              :         break;
      72            0 :       case MIRROR:
      73            0 :         weights[0] *= 2;
      74            0 :         break;
      75            0 :       case REFLECT:
      76            0 :         weights[1] *= 2;
      77            0 :         break;
      78              :       }
      79              : 
      80              :       // normalize the other two weights
      81            0 :       double weightsSum = weights[0] + weights[1];
      82            0 :       weights[0] /= weightsSum;
      83            0 :       weights[1] /= weightsSum;
      84              :     }
      85              : 
      86              :     // apply to scalars
      87            0 :     for (const auto scalarProperty : _scalarAccessFunctionPairs) {
      88            0 :       (_outputCells[raw_index]->*scalarProperty.set)((_inputCells[indexBelow.get()]->*scalarProperty.get)() * weights[0] +
      89            0 :                                                      (_inputCells[raw_index]->*scalarProperty.get)() * weights[1] +
      90            0 :                                                      (_inputCells[indexAbove.get()]->*scalarProperty.get)() * weights[2]);
      91              :     }
      92              :     // apply to vectors
      93            0 :     for (const auto vectorProperty : _vectorAccessFunctionPairs) {
      94            0 :       (_outputCells[raw_index]->*vectorProperty.set)((_inputCells[indexBelow.get()]->*vectorProperty.get)() * weights[0] +
      95            0 :                                                      (_inputCells[raw_index]->*vectorProperty.get)() * weights[1] +
      96            0 :                                                      (_inputCells[indexAbove.get()]->*vectorProperty.get)() * weights[2]);
      97              :     }
      98              :   } // index
      99              : 
     100              : #ifdef DEBUG_GAUSS
     101              :   std::cout << "done." << std::endl;
     102              : #endif
     103            0 : }
     104              : 
     105              : // Private functions of Gauss.h:
     106              : 
     107              : /**
     108              :  * @brief Computes the one-dimensional Gaussian kernel.
     109              :  * Kernel size is 1 + 2 * GAUSS_KERNEL_RADIUS, because there is one central cell a
     110              :  *  and GAUSS_KERNEL_RADIUS neighboring cells before and after that.
     111              :  *
     112              :  * @returns an array with kernel weights, normalized to sum(weights)=1
     113              :  */
     114              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
     115            0 : std::array<double, 1 + 2 * GAUSS_KERNEL_RADIUS> coupling::filtering::Gauss<dim, scope...>::generateKernel() {
     116              :   // std::cout << "gauss: kernel radius: " << GAUSS_KERNEL_RADIUS << std::endl;
     117              : 
     118              :   std::array<double, 1 + 2 * GAUSS_KERNEL_RADIUS> kernel;
     119            0 :   unsigned int i = 0; // index in kernel
     120            0 :   double sum = 0;     // used for normalization
     121              : 
     122              :   // fill kernel using Gaussian error function
     123            0 :   for (int x = -GAUSS_KERNEL_RADIUS; x <= GAUSS_KERNEL_RADIUS; x++) {
     124            0 :     kernel[i] = gaussianDensityFunction(x);
     125              : 
     126            0 :     sum += kernel[i];
     127            0 :     i++;
     128              :   }
     129              : 
     130              :   // normalize kernel. by definition, sum cannot be 0.
     131            0 :   for (auto& k : kernel) {
     132            0 :     k *= 1 / sum;
     133              : 
     134              : #ifdef DEBUG_GAUSS
     135              :     std::cout << "           GAUSS(Dim: " << _dim << "): Add kernel entry: " << k << std::endl;
     136              : #endif
     137              :   }
     138              : 
     139            0 :   return kernel;
     140              : }
     141              : 
     142              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
     143            0 : constexpr double coupling::filtering::Gauss<dim, scope...>::gaussianDensityFunction(int x) {
     144            0 :   double ans = (1 / (_sigma * sqrt(2 * M_PI))) * exp(-0.5 * (x / _sigma) * (x / _sigma));
     145            0 :   return ans;
     146              : }
     147              : 
     148              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
     149              : typename coupling::filtering::Gauss<dim, scope...>::VectorIndex
     150            0 : coupling::filtering::Gauss<dim, scope...>::getIndexAbove(const coupling::filtering::Gauss<dim, scope...>::VectorIndex index, unsigned int d) {
     151              :   // check for border indices
     152            0 :   const coupling::indexing::BaseIndex<dim> boundary = coupling::filtering::Gauss<dim, scope...>::VectorIndex::upperBoundary;
     153            0 :   for (unsigned int d = 0; d < dim; d++) {
     154              :     // convert index to BaseIndex and compare with boundary.
     155            0 :     if ((coupling::indexing::BaseIndex<dim>{index}).get()[d] >= boundary.get()[d])
     156              :       // if index is out of bounds, return it unmodified. this gets detected in
     157              :       // operator()'s boundary handling.
     158            0 :       return index;
     159              :   }
     160              : 
     161              :   // get raw vector index
     162            0 :   tarch::la::Vector<dim, int> ans = index.get();
     163              :   // get upper index in dimension d
     164            0 :   ans[d] += 1;
     165              : 
     166            0 :   return VectorIndex{ans};
     167              : }
     168              : 
     169              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
     170              : typename coupling::filtering::Gauss<dim, scope...>::VectorIndex
     171            0 : coupling::filtering::Gauss<dim, scope...>::getIndexBelow(const coupling::filtering::Gauss<dim, scope...>::VectorIndex index, unsigned int d) {
     172              :   // check for border indices
     173            0 :   const coupling::indexing::BaseIndex<dim> boundary = coupling::filtering::Gauss<dim, scope...>::VectorIndex::lowerBoundary;
     174            0 :   for (unsigned int d = 0; d < dim; d++) {
     175              :     // convert index to BaseIndex and compare with boundary.
     176            0 :     if ((coupling::indexing::BaseIndex<dim>{index}).get()[d] <= boundary.get()[d])
     177              :       // if index is out of bounds, return it unmodified. this gets detected in
     178              :       // operator()'s boundary handling.
     179            0 :       return index;
     180              :   }
     181              : 
     182              :   // copy input index
     183            0 :   tarch::la::Vector<dim, int> ans = index.get();
     184              :   // get lower index in dimension d
     185            0 :   ans[d] -= 1;
     186              : 
     187            0 :   return VectorIndex{ans};
     188              : }
        

Generated by: LCOV version 2.0-1