LCOV - code coverage report
Current view: top level - coupling/filtering/sequencing - FilterSequence.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 72 0.0 %
Date: 2026-02-16 14:39:39 Functions: 0 13 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, or at
       3             : // www5.in.tum.de/mamico
       4             : 
       5             : #pragma once
       6             : #include <functional>
       7             : #include <map>
       8             : #include <numeric>
       9             : #include <sys/time.h>
      10             : 
      11             : #include "coupling/filtering/interfaces/FilterInterface.h"
      12             : #include "coupling/indexing/CellIndex.h"
      13             : #include "tarch/configuration/ParseConfiguration.h"
      14             : 
      15             : // INCLUDE ALL FILTER HEADERS HERE
      16             : #include "coupling/filtering/filters/Constant.h"
      17             : #include "coupling/filtering/filters/Gauss.h"
      18             : #ifdef BUILD_WITH_EIGEN
      19             : #include "coupling/filtering/filters/POD.h"
      20             : #endif
      21             : #include "coupling/filtering/filters/ReadFromFile.h"
      22             : #include "coupling/filtering/filters/WriteToFile.h"
      23             : /*
      24             : #include "coupling/filtering/filters/Strouhal.h"
      25             : */
      26             : #include "coupling/filtering/filters/Copy.h"
      27             : #include "coupling/filtering/filters/FilterFromFunction.h"
      28             : 
      29             : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
      30             : #include "coupling/filtering/SequentialFilter.h"
      31             : #endif
      32             : 
      33             : /*
      34             :  * Filter Sequences are used to group filters that will be applied in
      35             :  * chronological order. It is possible to customize
      36             :  *  - sequence input
      37             :  *      - filter parameters
      38             :  *      - modifiablitiy of filter list
      39             :  * per Filter Sequence.
      40             :  *
      41             :  * A generalized version of this concept is FilterJunction.
      42             :  * @author Felix Maurer
      43             :  */
      44             : 
      45             : namespace coupling {
      46             : namespace filtering {
      47             : template <unsigned int dim> class FilterSequence;
      48             : }
      49             : } // namespace coupling
      50             : 
      51             : template <unsigned int dim> class coupling::filtering::FilterSequence {
      52             : public:
      53             :   /*
      54             :    * Filter Sequences are constructed in
      55             :    * coupling::FilterPipeline::loadSequencesFromXML(...).
      56             :    */
      57           0 :   FilterSequence(const char* name, const std::vector<coupling::datastructures::CouplingCell<dim>*> inputCells,
      58             : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
      59             :                  MPI_Comm comm,
      60             : #endif
      61             :                  std::array<bool, 7> filteredValues = {true})
      62           0 :       : _name(name), _inputCellVector(inputCells),
      63             : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
      64           0 :         _comm(comm),
      65             : #endif
      66           0 :         _filteredValues(filteredValues), _isOutput(false), // potentially updated via loadSequencesFromXML
      67             :                                                            // calling setAsOutput()
      68           0 :         _isModifiable(true),                               // TODO: allow const sequences via XML attribute
      69           0 :         _timestepsElapsed(0) {
      70             : #ifdef DEBUG_FILTER_PIPELINE
      71             :     std::cout << PRINT_PREFIX() << "Now initializing." << std::endl;
      72             : #endif
      73             : 
      74           0 :     initCellVectors();
      75             : 
      76           0 :     bool filtersAnything = false;
      77           0 :     for (unsigned int i = 0; i < 7; i++)
      78           0 :       if (_filteredValues[i]) {
      79             :         filtersAnything = true;
      80             :         break;
      81             :       }
      82           0 :     if (!filtersAnything)
      83             :       std::cout << "Warning: Filter sequence " << _name
      84           0 :                 << " does not filter any values. Add 'filtered-values' "
      85             :                    "attribute to XML element to change this."
      86           0 :                 << std::endl;
      87             : #ifdef DEBUG_FILTER_PIPELINE
      88             :     std::cout << PRINT_PREFIX() << "Finished initialization." << std::endl;
      89             : #endif
      90           0 :   }
      91             : 
      92           0 :   virtual ~FilterSequence() {
      93             :     // Output average application times for all filters
      94             : #ifdef DEBUG_FILTER_PIPELINE
      95             :     if (IDXS.getRank() == 0) {
      96             :       std::cout << PRINT_PREFIX() << "Average application times for filters in this sequence in \u03BCs:" << std::endl;
      97             :       for (auto filter : _filters) {
      98             :         std::cout << "       " << filter->getType() << ": "
      99             :                   << (double)std::accumulate(_filterTimes[filter].begin(), _filterTimes[filter].end(), 0) / (double)_timestepsElapsed << std::endl;
     100             :       }
     101             :     }
     102             : #endif
     103             : 
     104           0 :     for (auto v1 : _cellVector1)
     105           0 :       delete v1;
     106           0 :     for (auto v2 : _cellVector2)
     107           0 :       delete v2;
     108           0 :     for (auto f : _filters)
     109           0 :       delete f;
     110             : #ifdef DEBUG_FILTER_PIPELINE
     111             :     std::cout << PRINT_PREFIX() << "Deconstructed." << std::endl;
     112             : #endif
     113           0 :   }
     114             : 
     115             :   /*
     116             :    * Each sequence operates on their own two copies of the md-to-macro domain.
     117             :    * Thus, before applying the sequence, we need to update these two copies.
     118             :    */
     119           0 :   void updateCellVectors() {
     120           0 :     for (unsigned int index = 0; index < _cellVector1.size(); index++) {
     121           0 :       *(_cellVector1[index]) = *(_inputCellVector[index]);
     122           0 :       *(_cellVector2[index]) = *(_inputCellVector[index]);
     123             :     }
     124           0 :   }
     125             : 
     126             :   /*
     127             :    * Applies all filters stored in _filters. Also measures performance times.
     128             :    */
     129           0 :   void operator()() {
     130           0 :     for (auto filter : _filters) {
     131             :       // measure time before application
     132             :       timeval before;
     133           0 :       gettimeofday(&before, NULL);
     134             : 
     135             :       // Apply the filter's operator()
     136           0 :       (*filter)();
     137             : 
     138             :       // measure time after application
     139             :       timeval after;
     140           0 :       gettimeofday(&after, NULL);
     141             : 
     142             :       // store time difference in usec in map
     143           0 :       _filterTimes[filter].push_back((after.tv_sec * 1000000 + after.tv_usec) - (before.tv_sec * 1000000 + before.tv_usec));
     144             : 
     145             : #ifdef DEBUG_FILTER_PIPELINE
     146             :       std::cout << PRINT_PREFIX() << "Applied filter " << filter->getType() << ". Application time: " << _filterTimes[filter].back() << "\u03BCs" << std::endl;
     147             : #endif
     148             :     }
     149           0 :     _timestepsElapsed++;
     150           0 :   }
     151             : 
     152             :   /*
     153             :    * Returns unique name identifier of this sequence.
     154             :    */
     155           0 :   const char* getName() { return _name; }
     156             : 
     157           0 :   bool isOutputToMacro() { return _isOutput; }
     158           0 :   void setAsOutputToMacro() {
     159             : #ifdef DEBUG_FILTER_PIPELINE
     160             :     std::cout << PRINT_PREFIX() << " Setting as pipeline to macro solver output." << std::endl;
     161             : #endif
     162           0 :     _isOutput = true;
     163           0 :   }
     164             : 
     165             :   /*
     166             :    * Modifiable sequences may have filters added dynamically via
     167             :    * FilterFromFunction.
     168             :    */
     169           0 :   bool isModifiable() { return _isModifiable; }
     170           0 :   void makeUnmodifiable() { _isModifiable = false; }
     171             : 
     172             :   std::vector<coupling::filtering::FilterInterface<dim>*> getFilters() { return _filters; }
     173             : 
     174             :   /*
     175             :    * All virtual functions below are redefined in case this sequence is actually
     176             :    * a FilterJunction. Read FilterJunction.h carefully.
     177             :    */
     178             : 
     179             :   /*
     180             :    * Interprets this sequence's filters' parameters (specified in
     181             :    * filter_pipeline.xml) and creates filter objects based on that. Since
     182             :    * different filters require vastly different parameters and thus different
     183             :    * means of instanciation, you need to add each new filter manually to this
     184             :    * method's "if/else-chain".
     185             :    *
     186             :    * Since after all filter objects are created it is possible to determine
     187             :    * whether _cellVector1 or _cellVector2 will be used as output, this is also
     188             :    * done in here.
     189             :    *
     190             :    * In addition to that, if this sequence is declared as unmodifibale, this
     191             :    * gets also detected in here.
     192             :    */
     193             :   virtual int loadFiltersFromXML(tinyxml2::XMLElement* sequenceNode);
     194             : 
     195             :   /*
     196             :    * This member function allows appendance and insertion of filters defined by
     197             :    * two processing functions to a modifiable sequence at runtime. Index -1
     198             :    * implies appending.
     199             :    */
     200             :   virtual void addFilter(
     201             :       const std::function<std::vector<double>(std::vector<double>, std::vector<std::array<unsigned int, dim>>)>* applyScalar,
     202             :       const std::function<std::vector<std::array<double, dim>>(std::vector<std::array<double, dim>>, std::vector<std::array<unsigned int, dim>>)>* applyVector,
     203             :       int filterIndex = -1);
     204             : 
     205             :   /*
     206             :    * Registers existence of a child sequence, i.e. a sequence using this
     207             :    * sequence's output as its input.
     208             :    */
     209           0 :   virtual void addChildSequence(coupling::filtering::FilterSequence<dim>* childSequence) { _childSequences.push_back(childSequence); }
     210             : 
     211             :   /*
     212             :    * Allows changing the input cells after init.
     213             :    */
     214           0 :   virtual void updateInputCellVector(const std::vector<coupling::datastructures::CouplingCell<dim>*> newInputCellVector) {
     215           0 :     _inputCellVector = newInputCellVector; // call copy constructor
     216             : 
     217             :     // cc this change to this sequence's first vector.
     218           0 :     if (!_filters.empty())
     219           0 :       _filters[0]->setInputCells(_inputCellVector);
     220           0 :   }
     221             : 
     222             :   /*
     223             :    * Which one of the two cell vectors are this sequence's output is solely
     224             :    * dependant on the number of filters the sequence contains, because each swap
     225             :    * (see loadFiltersFromXML) changes what is the sequence's final filter's
     226             :    * output.
     227             :    *
     228             :    * Some sequences have more than one output, thus the optional parameter. Has
     229             :    * no effect on a basic FilterSequence.
     230             :    */
     231           0 :   virtual const std::vector<coupling::datastructures::CouplingCell<dim>*>& getOutputCellVector(unsigned int outputIndex = 0) const {
     232           0 :     if (_filters.empty())
     233           0 :       return _inputCellVector;
     234             : 
     235           0 :     if (_filters.size() % 2 == 0)
     236           0 :       return _cellVector1;
     237             : 
     238           0 :     return _cellVector2;
     239             :   }
     240             : 
     241           0 :   virtual void printOutputCellVector() const {
     242           0 :     if (getOutputCellVector() == _inputCellVector)
     243           0 :       std::cout << "The sequence's input cell vector ";
     244           0 :     else if (getOutputCellVector() == _cellVector1)
     245           0 :       std::cout << "Cell vector 1 ";
     246           0 :     else if (getOutputCellVector() == _cellVector2)
     247           0 :       std::cout << "Cell vector 2 ";
     248             :     else { /*unreachable, see function definition above*/
     249             :     }
     250             : 
     251           0 :     std::cout << "will be used as output." << std::endl;
     252           0 :   }
     253             : 
     254             :   /*
     255             :    * This is trivial for the traditional sequence, i.e. non-Junction-case.
     256             :    */
     257           0 :   virtual unsigned int getNumInputs() { return 1; }
     258           0 :   virtual unsigned int getNumOutputs() { return 1; }
     259             : 
     260             :   /*
     261             :    * DUMMY HELPER FUNCTIONS
     262             :    */
     263             : 
     264           0 :   virtual void printFilters() {
     265           0 :     std::cout << "Filters in sequence " << _name << ": ";
     266           0 :     for (auto f : _filters)
     267           0 :       std::cout << f->getType() << " ";
     268           0 :     std::cout << std::endl;
     269           0 :   }
     270             : 
     271           0 :   virtual std::string PRINT_PREFIX() const { return std::string("  FS(").std::string::append(_name).std::string::append("): "); }
     272             : 
     273             : private:
     274             :   /*
     275             :    * Copies all input cells to _cellVector1 and _cellVector2.
     276             :    *
     277             :    * Used in consctructor.
     278             :    *
     279             :    * Not implemented by FilterJunction: Equivalent procedure can be found in
     280             :    * that class' constructor.
     281             :    */
     282             :   void initCellVectors();
     283             : 
     284             : protected:
     285             :   const char* _name;
     286             : 
     287             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _inputCellVector; // points to (foreign) input vector
     288             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _cellVector1;     // allocated for this sequence only
     289             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _cellVector2;     // allocated for this sequence only
     290             : 
     291             : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
     292             :   MPI_Comm _comm;
     293             : #endif
     294             : 
     295             :   std::array<bool, 7> _filteredValues;
     296             : 
     297             :   bool _isOutput;     // true if this sequence's output vector (see above) is the
     298             :                       // Filter Pipeline's output
     299             :   bool _isModifiable; // true while filters can be added to sequence
     300             : 
     301             :   std::vector<coupling::filtering::FilterInterface<dim>*> _filters;
     302             : 
     303             :   // stores application times for all filters
     304             :   std::map<coupling::filtering::FilterInterface<dim>*, std::vector<unsigned int>> _filterTimes;
     305             : 
     306             :   // there must be some other place to get this from
     307             :   unsigned int _timestepsElapsed;
     308             : 
     309             :   // stores pointers to all sequences that use this sequence's output as their
     310             :   // input.
     311             :   std::vector<coupling::filtering::FilterSequence<dim>*> _childSequences;
     312             : };
     313             : 
     314             : // inlcude implementation
     315             : #include "coupling/filtering/sequencing/FilterSequence.cpph"

Generated by: LCOV version 1.14