LCOV - code coverage report
Current view: top level - coupling/filtering/filters - Datastructures.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 78 0
Test Date: 2026-08-21 15:14:06 Functions: 0.0 % 11 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 > _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 > _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              :   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] > _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 > _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*>(_flowfield._data);
     174            0 :     double* const other_data = reinterpret_cast<double*>(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 2.0-1