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 : }