LCOV - code coverage report
Current view: top level - coupling/filtering/filters - NLM.cpph (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 114 0
Test Date: 2026-08-21 15:14:06 Functions: 0.0 % 6 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
       3              : 
       4            0 : template <unsigned int dim, coupling::indexing::IndexTrait... scope> void coupling::filtering::NLM<dim, scope...>::operator()() {
       5              : #ifdef NLM_DEBUG
       6              :   std::cout << "    NLM: called operator()" << std::endl;
       7              : #endif
       8              : 
       9            0 :   save_data();
      10            0 :   update_patchfield();
      11            0 :   denoise();
      12            0 :   increment_time();
      13            0 : }
      14              : 
      15            0 : template <unsigned int dim, coupling::indexing::IndexTrait... scope> void coupling::filtering::NLM<dim, scope...>::save_data() {
      16            0 :   for (unsigned int i = 0; i < this->_inputCells.size(); ++i) {
      17              :     using namespace coupling::indexing;
      18            0 :     CellIndex_T idx{CellIndex<dim, IndexTrait::local, IndexTrait::md2macro, IndexTrait::noGhost>{i}};
      19            0 :     tarch::la::Vector<dim, unsigned int> idx_raw{idx.get()};
      20            0 :     coupling::filtering::Quantities<dim>& q = _flowfield(idx_raw, _t);
      21            0 :     coupling::filtering::Quantities<dim>& qp = _flowfield_prefiltered(idx_raw, _t);
      22            0 :     q[0] = this->_inputCellVectors[0][i]->getMacroscopicMass();
      23            0 :     qp[0] = this->_inputCellVectors[1][i]->getMacroscopicMass();
      24            0 :     for (unsigned int d = 0; d < dim; d++) {
      25            0 :       q[d + 1] = this->_inputCellVectors[0][i]->getMacroscopicMomentum()[d];
      26            0 :       qp[d + 1] = this->_inputCellVectors[1][i]->getMacroscopicMomentum()[d];
      27              :     }
      28              :   }
      29            0 : }
      30              : 
      31            0 : template <unsigned int dim, coupling::indexing::IndexTrait... scope> void coupling::filtering::NLM<dim, scope...>::update_patchfield() {
      32            0 :   for (auto idx : _innerCellIndices) {
      33            0 :     auto idx_inner = (tarch::la::Vector<dim, unsigned int>)(idx.get()) - tarch::la::Vector<dim, unsigned int>{1};
      34            0 :     if (_cycleCounter > _t)
      35            0 :       _patchfield.destroy(idx_inner, _t);
      36            0 :     _patchfield.construct(idx_inner, _t, tarch::la::Vector<dim, unsigned int>(2 * _d + 1), 2 * _d + 1, _flowfield_prefiltered,
      37            0 :                           (tarch::la::Vector<dim, unsigned int>)(idx.get()), _t);
      38              :   }
      39            0 : }
      40              : 
      41            0 : template <unsigned int dim, coupling::indexing::IndexTrait... scope> void coupling::filtering::NLM<dim, scope...>::denoise() {
      42              :   // counter for adaptive parameter modification
      43            0 :   int cnt_sigsq = 0, cnt_hsq = 0, cnt_total = 0;
      44            0 :   for (auto const& idx : _innerCellIndices) {
      45            0 :     auto idx_inner = (tarch::la::Vector<dim, unsigned int>)(idx.get()) - tarch::la::Vector<dim, unsigned int>{1};
      46            0 :     auto& me = _patchfield(idx_inner, _t);
      47            0 :     double C = 0;
      48              : 
      49            0 :     auto res_offset = compute_boundary_neighbors(idx_inner);
      50            0 :     std::vector<coupling::filtering::Quantities<dim>> res(res_offset.size(), 0);
      51              : 
      52            0 :     int tdist = std::min((int)_timeWindowSize, (int)_cycleCounter + 1);
      53              :     // TODO restrict loops to bouncing V_i search window
      54            0 :     for (int offset_t = 0; offset_t > -tdist; offset_t--) {
      55            0 :       unsigned int t = posmod((int)_t + offset_t, _timeWindowSize);
      56            0 :       for (auto idx2 : _innerCellIndices) {
      57            0 :         auto idx2_inner = (tarch::la::Vector<dim, unsigned int>)(idx2.get()) - tarch::la::Vector<dim, unsigned int>{1};
      58            0 :         auto& other = _patchfield(idx2_inner, t);
      59            0 :         double dist = me.distance(other);
      60              : #ifdef NLM_DEBUG
      61              :         std::cout << "dist = " << dist << std::endl;
      62              : #endif
      63            0 :         if (dist < _sigsq)
      64            0 :           cnt_sigsq++;
      65            0 :         if (dist - _sigsq < _hsq)
      66            0 :           cnt_hsq++;
      67            0 :         cnt_total++;
      68            0 :         double weight = std::exp(-std::max(dist - _sigsq, 0.0) / _hsq) * 1 / (-offset_t + 1);
      69              : #ifdef NLM_DEBUG
      70              :         std::cout << "weight = " << weight << std::endl;
      71              : #endif
      72            0 :         for (unsigned int i = 0; i < res_offset.size(); i++) {
      73            0 :           tarch::la::Vector<dim, unsigned int> residx(idx2.get() + res_offset[i]);
      74            0 :           coupling::filtering::Quantities<dim>& q = _flowfield(residx, t);
      75            0 :           res[i] += q * weight;
      76              :         }
      77            0 :         C += weight;
      78              :       }
      79              :     }
      80              : 
      81            0 :     for (unsigned int i = 0; i < res_offset.size(); i++) {
      82            0 :       res[i] = res[i] * (1 / C);
      83            0 :       tarch::la::Vector<dim, int> residx(idx.get() + res_offset[i]);
      84            0 :       int cellidx = coupling::indexing::convertToScalar(CellIndex_T(residx));
      85              : 
      86            0 :       coupling::filtering::JunctorInterface<dim, 2, 1>::_outputCellVectors[0][cellidx]->setMacroscopicMass(res[i][0]);
      87            0 :       tarch::la::Vector<dim, double> momentum;
      88            0 :       for (unsigned int d = 0; d < dim; d++)
      89            0 :         momentum[d] = res[i][d + 1];
      90            0 :       coupling::filtering::JunctorInterface<dim, 2, 1>::_outputCellVectors[0][cellidx]->setMacroscopicMomentum(momentum);
      91              :     }
      92              :   }
      93              :   // dynamic parameter adaption: Goal: cnt/cnt_total should be close to
      94              :   // value_rel
      95            0 :   if (_sigsq_rel >= 0) { // negative value means adaptivity disabled
      96            0 :     double rel = (double)(cnt_sigsq) / cnt_total;
      97            0 :     if (rel < _sigsq_rel * 0.9)
      98            0 :       _sigsq *= 1.05;
      99            0 :     else if (rel > _sigsq_rel * 1.1)
     100            0 :       _sigsq *= 0.95;
     101            0 :     if (_cycleCounter % 20 == 0)
     102            0 :       std::cout << "NLM info: _sigsq is " << _sigsq << std::endl;
     103              :   }
     104            0 :   if (_hsq_rel >= 0) { // negative value means adaptivity disabled
     105            0 :     double rel = (double)(cnt_hsq) / cnt_total;
     106            0 :     if (rel < _hsq_rel * 0.9)
     107            0 :       _hsq *= 1.05;
     108            0 :     else if (rel > _hsq_rel * 1.1)
     109            0 :       _hsq *= 0.95;
     110            0 :     if (_cycleCounter % 20 == 0)
     111            0 :       std::cout << "NLM info: _hsq is " << _hsq << std::endl;
     112              :   }
     113            0 : }
     114              : 
     115              : template <unsigned int dim, coupling::indexing::IndexTrait... scope>
     116              : std::vector<tarch::la::Vector<dim, int>>
     117            0 : coupling::filtering::NLM<dim, scope...>::compute_boundary_neighbors(const tarch::la::Vector<dim, unsigned int>& idx_inner) {
     118            0 :   auto domainSize = CellIndex_T::numberCellsInDomain;
     119            0 :   std::vector<tarch::la::Vector<dim, int>> res_offset;
     120            0 :   res_offset.reserve(1 << dim); // max this many neighbors are possible
     121            0 :   res_offset.push_back(0);      // result for me (i.e. idx) is always needed
     122            0 :   for (unsigned int d = 0; d < dim; d++) {
     123            0 :     tarch::la::Vector<dim, int> offset{0};
     124            0 :     if (idx_inner[d] == 0) {
     125            0 :       offset[d] = -1;
     126            0 :       res_offset.push_back(offset); // Comp res for neighbor cell on boundary surface
     127            0 :     } else if (idx_inner[d] == domainSize[d] - 3) {
     128            0 :       offset[d] = 1;
     129            0 :       res_offset.push_back(offset); // Comp res for neighbor cell on boundary surface
     130              :     }
     131            0 :     if (offset[d] != 0) {
     132            0 :       for (unsigned int d2 = d + 1; d2 < dim; d2++) {
     133            0 :         if (idx_inner[d2] == 0) {
     134            0 :           offset[d2] = -1;
     135            0 :           res_offset.push_back(offset); // Comp res for neighbor cell on boundary edge
     136            0 :         } else if (idx_inner[d2] == domainSize[d2] - 3) {
     137            0 :           offset[d2] = 1;
     138            0 :           res_offset.push_back(offset); // Comp res for neighbor cell on boundary edge
     139              :         }
     140            0 :         if (dim == 3 && d2 == 1 && offset[d2] != 0) {
     141            0 :           if (idx_inner[2] == 0) {
     142            0 :             offset[2] = -1;
     143            0 :             res_offset.push_back(offset); // Comp res for neighbor cell on boundary corner
     144            0 :           } else if (idx_inner[2] == domainSize[2] - 3) {
     145            0 :             offset[2] = 1;
     146            0 :             res_offset.push_back(offset); // Comp res for neighbor cell on boundary corner
     147              :           }
     148            0 :           offset[2] = 0;
     149              :         }
     150            0 :         offset[d2] = 0;
     151              :       }
     152              :     }
     153              :   }
     154            0 :   return res_offset; // (implicit std::move here)
     155            0 : }
     156              : 
     157            0 : template <unsigned int dim, coupling::indexing::IndexTrait... scope> void coupling::filtering::NLM<dim, scope...>::increment_time() {
     158            0 :   _cycleCounter++;
     159            0 :   _t = _cycleCounter % _timeWindowSize;
     160            0 : }
        

Generated by: LCOV version 2.0-1