LCOV - code coverage report
Current view: top level - coupling/filtering/filters - Datastructures.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 79 0.0 %
Date: 2025-06-25 11:26:37 Functions: 0 11 0.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             : #pragma once
       5             : 
       6             : #include <memory>
       7             : 
       8             : namespace coupling {
       9             : 
      10             : /** Modular filtering and data analytics system. Includes inferfaces and
      11             :  * services that manage the filtering subsystem, as well as several filter
      12             :  * implementations.
      13             :  */
      14             : namespace filtering {
      15             : 
      16             : /***
      17             :  * Quantities<dim>[0] := mass
      18             :  * Quantities<dim>[1..dim] := momentum
      19             :  */
      20             : template <unsigned int dim> using Quantities = tarch::la::Vector<dim + 1, double>;
      21             : 
      22             : /***
      23             :  *      Spacetime window of data, i.e. 4D field of T
      24             :  */
      25             : template <unsigned int dim, typename T> class Field;
      26             : 
      27             : /***
      28             :  *      Spacetime window of flow quantities
      29             :  */
      30             : template <unsigned int dim> using Flowfield = Field<dim, Quantities<dim>>;
      31             : 
      32             : /***
      33             :  *      includes local flowfield, and mean and standard deviation of quantities
      34             :  */
      35             : template <unsigned int dim> class Patch;
      36             : 
      37             : /***
      38             :  *   similar to patch, but
      39             :  *   does not store local flowfield, but accesses basefield for distance
      40             :  * computation
      41             :  */
      42             : template <unsigned int dim> class PatchView;
      43             : 
      44             : /***
      45             :  *      Spacetime window of patches
      46             :  */
      47             : template <unsigned int dim> using Patchfield = Field<dim, Patch<dim>>;
      48             : // using Patchfield = Field<dim, PatchView<dim>>;
      49             : 
      50             : } // namespace filtering
      51             : } // namespace coupling
      52             : 
      53             : /***
      54             :  *      Spacetime window of data, i.e. 4D field of T
      55             :  */
      56             : template <unsigned int dim, typename T> class coupling::filtering::Field {
      57             : public:
      58           0 :   Field(const tarch::la::Vector<dim, unsigned int>& spatialSize, const unsigned int& temporalSize)
      59           0 :       : _spatialSize(spatialSize), _temporalSize(temporalSize), _scalarSize(computeScalarSize(spatialSize, temporalSize)),
      60           0 :         _data(std::allocator_traits<std::allocator<T>>::allocate(allo, _scalarSize)) {}
      61             : 
      62           0 :   template <class... Args> void construct(const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t, Args&&... args) {
      63           0 :     std::allocator_traits<std::allocator<T>>::construct(allo, _data + idx(pos, t), std::forward<Args>(args)...);
      64           0 :   }
      65             : 
      66           0 :   void destroy(const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t) {
      67           0 :     std::allocator_traits<std::allocator<T>>::destroy(allo, _data + idx(pos, t));
      68           0 :   }
      69             : 
      70           0 :   T& operator()(const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t) { return _data[idx(pos, t)]; }
      71             : 
      72           0 :   const T& operator()(const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t) const { return _data[idx(pos, t)]; }
      73             : 
      74           0 :   T& operator[](unsigned int pos) {
      75             : #ifdef NLM_DEBUG
      76             :     if (pos < 0 || pos > _scalarSize - 1) {
      77             :       std::cout << "ERROR Field T& operator[](int pos): pos out of range!" << std::endl;
      78             :       std::cout << "pos=" << pos << ", _scalarSize=" << _scalarSize << std::endl;
      79             :       exit(EXIT_FAILURE);
      80             :     }
      81             : #endif
      82           0 :     return _data[pos];
      83             :   }
      84             : 
      85             :   const T& operator[](unsigned int pos) const {
      86             : #ifdef NLM_DEBUG
      87             :     if (pos < 0 || pos > _scalarSize - 1) {
      88             :       std::cout << "ERROR Field T& operator[](int pos): pos out of range!" << std::endl;
      89             :       std::cout << "pos=" << pos << ", _scalarSize=" << _scalarSize << std::endl;
      90             :       exit(EXIT_FAILURE);
      91             :     }
      92             : #endif
      93             :     return _data[pos];
      94             :   }
      95             : 
      96           0 :   ~Field() { std::allocator_traits<std::allocator<T>>::deallocate(allo, _data, _scalarSize); }
      97             : 
      98           0 :   unsigned int getScalarSize() const { return _scalarSize; }
      99             : 
     100           0 :   const tarch::la::Vector<dim, unsigned int>& getSpatialSize() const { return _spatialSize; }
     101             : 
     102           0 :   unsigned int getTemporalSize() const { return _temporalSize; }
     103             : 
     104             :   void print() {
     105             :     for (unsigned int i = 0; i < _scalarSize; i++) {
     106             :       std::cout << "Field elem " << i << " = " << _data[i] << std::endl;
     107             :     }
     108             :   }
     109             : 
     110             : private:
     111           0 :   unsigned int computeScalarSize(const tarch::la::Vector<dim, unsigned int>& spatialSize, const unsigned int& temporalSize) const {
     112           0 :     unsigned int res = spatialSize[0];
     113           0 :     for (unsigned int d = 1; d < dim; d++) {
     114           0 :       res *= (spatialSize[d]);
     115             :     }
     116           0 :     res *= temporalSize;
     117             :     return res;
     118             :   }
     119             : 
     120           0 :   unsigned int idx(const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t) const {
     121             : #ifdef NLM_DEBUG
     122             :     for (unsigned int d = 0; d < dim; d++) {
     123             :       if (pos[d] < 0 || pos[d] > _spatialSize[d] - 1) {
     124             :         std::cout << "ERROR Field idx(): pos out of range!" << std::endl;
     125             :         std::cout << "pos=" << pos << ", _spatialSize=" << _spatialSize << std::endl;
     126             :         exit(EXIT_FAILURE);
     127             :       }
     128             :     }
     129             :     if (t < 0 || t > _temporalSize - 1) {
     130             :       std::cout << "ERROR Field idx(): t out of range!" << std::endl;
     131             :       std::cout << "t=" << t << ", _temporalSize=" << _temporalSize << std::endl;
     132             :       exit(EXIT_FAILURE);
     133             :     }
     134             : #endif
     135           0 :     unsigned int idx = 0, step = 1;
     136           0 :     for (unsigned int d = 0; d < dim; d++) {
     137           0 :       idx += pos[d] * step;
     138           0 :       step *= _spatialSize[d];
     139             :     }
     140           0 :     idx += t * step;
     141           0 :     return idx;
     142             :   }
     143             : 
     144             :   static std::allocator<T> allo;
     145             :   const tarch::la::Vector<dim, unsigned int> _spatialSize;
     146             :   const unsigned int _temporalSize;
     147             :   const unsigned int _scalarSize;
     148             :   T* const _data;
     149             : 
     150             :   friend class coupling::filtering::Patch<dim>; // patches need direct access to
     151             :                                                 // their field's _data for
     152             :                                                 // memory efficiency
     153             : };
     154             : 
     155             : template <unsigned int dim, typename T> std::allocator<T> coupling::filtering::Field<dim, T>::allo;
     156             : 
     157             : /***
     158             :  *      includes local flowfield, and mean and standard deviation of quantities
     159             :  */
     160             : template <unsigned int dim> class coupling::filtering::Patch {
     161             : public:
     162           0 :   Patch(const tarch::la::Vector<dim, unsigned int>& spatialSize, const unsigned int& temporalSize, const Flowfield<dim>& basefield,
     163             :         const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t)
     164           0 :       : _flowfield(spatialSize, temporalSize), _localMean(0.0), _localStandardDeviation(0.0) {
     165           0 :     fillFromBasefield(basefield, pos, t);
     166           0 :     computeLocalMean();
     167           0 :     computeLocalStandardDeviation();
     168           0 :   }
     169             : 
     170           0 :   double distance(const coupling::filtering::Patch<dim>& other) {
     171           0 :     unsigned int size = _flowfield.getScalarSize() * (dim + 1);
     172             : 
     173           0 :     double* const my_data = reinterpret_cast<double* const>(_flowfield._data);
     174           0 :     double* const other_data = reinterpret_cast<double* const>(other._flowfield._data);
     175             : 
     176           0 :     double res = 0;
     177           0 :     for (unsigned int i = 0; i < size; i += 1) {
     178           0 :       double diff(my_data[i] - other_data[i]);
     179           0 :       res += diff * diff;
     180             :     }
     181           0 :     return res;
     182             :   }
     183             : 
     184           0 :   ~Patch() {}
     185             : 
     186             :   void print() { _flowfield.print(); }
     187             : 
     188             : private:
     189           0 :   inline unsigned int posmod(int i, int n) { return (i % n + n) % n; }
     190             : 
     191           0 :   void fillFromBasefield(const Flowfield<dim>& basefield, const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t) {
     192             :     static_assert(dim == 2 || dim == 3, "ERROR filtering::Patch::fillFromBasefield only implemented "
     193             :                                         "for 2D and 3D");
     194             : 
     195           0 :     tarch::la::Vector<dim, unsigned int> center;
     196           0 :     for (unsigned int d = 0; d < dim; d++) {
     197           0 :       center[d] = _flowfield.getSpatialSize()[d] / 2;
     198             :     }
     199             : 
     200           0 :     tarch::la::Vector<dim, unsigned int> local_pos(0);
     201           0 :     unsigned int local_t(0);
     202           0 :     tarch::la::Vector<dim, unsigned int> base_pos(0);
     203           0 :     unsigned int base_t(0);
     204             : 
     205           0 :     for (int offset_t = 0; offset_t > -(int)_flowfield.getTemporalSize(); offset_t--) {
     206           0 :       local_t = posmod(offset_t, _flowfield.getTemporalSize());
     207           0 :       base_t = posmod(t + offset_t, basefield.getTemporalSize());
     208           0 :       for (int offset_x = -(int)(_flowfield.getSpatialSize()[0]) / 2; offset_x <= (int)(_flowfield.getSpatialSize()[0]) / 2; offset_x++) {
     209           0 :         local_pos[0] = center[0] + offset_x;
     210           0 :         base_pos[0] = pos[0] + offset_x;
     211           0 :         for (int offset_y = -(int)(_flowfield.getSpatialSize()[1]) / 2; offset_y <= (int)(_flowfield.getSpatialSize()[1]) / 2; offset_y++) {
     212           0 :           local_pos[1] = center[1] + offset_y;
     213           0 :           base_pos[1] = pos[1] + offset_y;
     214             :           if constexpr (dim == 3) {
     215           0 :             for (int offset_z = -(int)(_flowfield.getSpatialSize()[2]) / 2; offset_z <= (int)(_flowfield.getSpatialSize()[2]) / 2; offset_z++) {
     216           0 :               local_pos[2] = center[2] + offset_z;
     217           0 :               base_pos[2] = pos[2] + offset_z;
     218           0 :               _flowfield(local_pos, local_t) = basefield(base_pos, base_t);
     219             :             }
     220             :           } else {
     221             :             _flowfield(local_pos, local_t) = basefield(base_pos, base_t);
     222             :           }
     223             :         }
     224             :       }
     225             :     }
     226           0 :   }
     227             : 
     228           0 :   void computeLocalMean() {
     229           0 :     for (unsigned int i = 0; i < _flowfield.getScalarSize(); i++)
     230           0 :       _localMean += _flowfield[i];
     231           0 :     _localMean = _localMean * (1.0 / _flowfield.getScalarSize());
     232           0 :   }
     233             : 
     234           0 :   void computeLocalStandardDeviation() {
     235           0 :     for (unsigned int i = 0; i < _flowfield.getScalarSize(); i++) {
     236           0 :       Quantities<dim> diff = _localMean - _flowfield[i];
     237           0 :       _localStandardDeviation += tarch::la::dot(diff, diff);
     238             :     }
     239           0 :     _localStandardDeviation = sqrt(_localStandardDeviation / _flowfield.getScalarSize());
     240           0 :   }
     241             : 
     242             :   Flowfield<dim> _flowfield;
     243             :   Quantities<dim> _localMean;
     244             :   double _localStandardDeviation;
     245             : };
     246             : 
     247             : /***
     248             :  *   similar to patch, but does not store local flowfield,
     249             :  *   accesses basefield for distance computation
     250             :  */
     251             : template <unsigned int dim> class coupling::filtering::PatchView {
     252             : public:
     253             :   PatchView(const tarch::la::Vector<dim, unsigned int>& spatialSize, const unsigned int& temporalSize, const Flowfield<dim>& basefield,
     254             :             const tarch::la::Vector<dim, unsigned int>& pos, const unsigned int& t)
     255             :       : _spatialSize(spatialSize), _temporalSize(temporalSize), _basefield(basefield), _pos(pos), _t(t) {}
     256             : 
     257             :   double distance(const coupling::filtering::PatchView<dim>& other) const {
     258             :     double res = 0;
     259             : 
     260             :     tarch::la::Vector<dim, unsigned int> base_pos(0);
     261             :     unsigned int base_t(0);
     262             : 
     263             :     for (int offset_t = 0; offset_t > -(int)_temporalSize; offset_t--) {
     264             :       base_t = posmod(_t + offset_t, _basefield.getTemporalSize());
     265             :       for (int offset_x = -(int)(_spatialSize[0]) / 2; offset_x <= (int)(_spatialSize[0]) / 2; offset_x++) {
     266             :         base_pos[0] = _pos[0] + offset_x;
     267             :         for (int offset_y = -(int)(_spatialSize[1]) / 2; offset_y <= (int)(_spatialSize[1]) / 2; offset_y++) {
     268             :           base_pos[1] = _pos[1] + offset_y;
     269             :           if constexpr (dim == 3) {
     270             :             for (int offset_z = -(int)(_spatialSize[2]) / 2; offset_z <= (int)(_spatialSize[2]) / 2; offset_z++) {
     271             :               base_pos[2] = _pos[2] + offset_z;
     272             :               // TODO: this is not correct. fix me
     273             :               auto diff(_basefield(base_pos, base_t) - _basefield(base_pos + other._pos - _pos, posmod(base_t + other._t - _t, _basefield.getTemporalSize())));
     274             :               res += diff[0] * diff[0];
     275             :             }
     276             :           } else {
     277             :             auto diff(_basefield(base_pos, base_t) - other._basefield(base_pos, base_t));
     278             :             res += tarch::la::dot(diff, diff);
     279             :           }
     280             :         }
     281             :       }
     282             :     }
     283             :     return res;
     284             :   }
     285             : 
     286             : private:
     287             :   inline unsigned int posmod(int i, int n) const { return (i % n + n) % n; }
     288             : 
     289             :   const tarch::la::Vector<dim, unsigned int> _spatialSize;
     290             :   const unsigned int _temporalSize;
     291             :   const Flowfield<dim>& _basefield;
     292             :   const tarch::la::Vector<dim, unsigned int> _pos;
     293             :   const unsigned int _t;
     294             : };

Generated by: LCOV version 1.14