LCOV - code coverage report
Current view: top level - coupling/filtering/sequencing - FilterSequence.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 77 0.0 %
Date: 2025-06-25 11:26:37 Functions: 0 14 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           0 :     std::cout << PRINT_PREFIX() << "Average application times for filters in this sequence in \u03BCs:" << std::endl;
      95           0 :     for (auto filter : _filters) {
      96           0 :       std::cout << " " << filter->getType() << ": "
      97           0 :                 << (double)std::accumulate(_filterTimes[filter].begin(), _filterTimes[filter].end(), 0) / (double)_timestepsElapsed << std::endl;
      98             :     }
      99             : 
     100           0 :     for (auto v1 : _cellVector1)
     101           0 :       delete v1;
     102           0 :     for (auto v2 : _cellVector2)
     103           0 :       delete v2;
     104           0 :     for (auto f : _filters)
     105           0 :       delete f;
     106             : #ifdef DEBUG_FILTER_PIPELINE
     107             :     std::cout << PRINT_PREFIX() << "Deconstructed." << std::endl;
     108             : #endif
     109           0 :   }
     110             : 
     111             :   /*
     112             :    * Each sequence operates on their own two copies of the md-to-macro domain.
     113             :    * Thus, before applying the sequence, we need to update these two copies.
     114             :    */
     115           0 :   void updateCellVectors() {
     116           0 :     for (unsigned int index = 0; index < _cellVector1.size(); index++) {
     117           0 :       *(_cellVector1[index]) = *(_inputCellVector[index]);
     118           0 :       *(_cellVector2[index]) = *(_inputCellVector[index]);
     119             :     }
     120           0 :   }
     121             : 
     122             :   /*
     123             :    * Applies all filters stored in _filters. Also measures performance times.
     124             :    */
     125           0 :   void operator()() {
     126           0 :     for (auto filter : _filters) {
     127             :       // measure time before application
     128             :       timeval before;
     129           0 :       gettimeofday(&before, NULL);
     130             : 
     131             :       // Apply the filter's operator()
     132           0 :       (*filter)();
     133             : 
     134             :       // measure time after application
     135             :       timeval after;
     136           0 :       gettimeofday(&after, NULL);
     137             : 
     138             :       // store time difference in usec in map
     139           0 :       _filterTimes[filter].push_back((after.tv_sec * 1000000 + after.tv_usec) - (before.tv_sec * 1000000 + before.tv_usec));
     140             : 
     141             : #ifdef DEBUG_FILTER_PIPELINE
     142             :       std::cout << PRINT_PREFIX() << "Applied filter " << filter->getType() << ". Application time: " << _filterTimes[filter].back() << "\u03BCs" << std::endl;
     143             : #endif
     144             :     }
     145           0 :     _timestepsElapsed++;
     146           0 :   }
     147             : 
     148             :   /*
     149             :    * Returns unique name identifier of this sequence.
     150             :    */
     151           0 :   const char* getName() { return _name; }
     152             : 
     153           0 :   bool isOutputToMacro() { return _isOutput; }
     154           0 :   void setAsOutputToMacro() {
     155           0 :     std::cout << PRINT_PREFIX() << " Setting as pipeline to macro solver output." << std::endl;
     156           0 :     _isOutput = true;
     157           0 :   }
     158             : 
     159             :   /*
     160             :    * Modifiable sequences may have filters added dynamically via
     161             :    * FilterFromFunction.
     162             :    */
     163           0 :   bool isModifiable() { return _isModifiable; }
     164           0 :   void makeUnmodifiable() { _isModifiable = false; }
     165             : 
     166             :   std::vector<coupling::filtering::FilterInterface<dim>*> getFilters() { return _filters; }
     167             : 
     168             :   /*
     169             :    * All virtual functions below are redefined in case this sequence is actually
     170             :    * a FilterJunction. Read FilterJunction.h carefully.
     171             :    */
     172             : 
     173             :   /*
     174             :    * Interprets this sequence's filters' parameters (specified in
     175             :    * filter_pipeline.xml) and creates filter objects based on that. Since
     176             :    * different filters require vastly different parameters and thus different
     177             :    * means of instanciation, you need to add each new filter manually to this
     178             :    * method's "if/else-chain".
     179             :    *
     180             :    * Since after all filter objects are created it is possible to determine
     181             :    * whether _cellVector1 or _cellVector2 will be used as output, this is also
     182             :    * done in here.
     183             :    *
     184             :    * In addition to that, if this sequence is declared as unmodifibale, this
     185             :    * gets also detected in here.
     186             :    */
     187             :   virtual int loadFiltersFromXML(tinyxml2::XMLElement* sequenceNode);
     188             : 
     189             :   /*
     190             :    * This member function allows appendance and insertion of filters defined by
     191             :    * two processing functions to a modifiable sequence at runtime. Index -1
     192             :    * implies appending.
     193             :    */
     194             :   virtual void addFilter(
     195             :       const std::function<std::vector<double>(std::vector<double>, std::vector<std::array<unsigned int, dim>>)>* applyScalar,
     196             :       const std::function<std::vector<std::array<double, dim>>(std::vector<std::array<double, dim>>, std::vector<std::array<unsigned int, dim>>)>* applyVector,
     197             :       int filterIndex = -1);
     198             : 
     199             :   /*
     200             :    * Registers existence of a child sequence, i.e. a sequence using this
     201             :    * sequence's output as its input.
     202             :    */
     203           0 :   virtual void addChildSequence(coupling::filtering::FilterSequence<dim>* childSequence) { _childSequences.push_back(childSequence); }
     204             : 
     205             :   /*
     206             :    * Allows changing the input cells after init.
     207             :    */
     208           0 :   virtual void updateInputCellVector(const std::vector<coupling::datastructures::CouplingCell<dim>*> newInputCellVector) {
     209           0 :     _inputCellVector = newInputCellVector; // call copy constructor
     210             : 
     211             :     // cc this change to this sequence's first vector.
     212           0 :     if (!_filters.empty())
     213           0 :       _filters[0]->setInputCells(_inputCellVector);
     214           0 :   }
     215             : 
     216             :   /*
     217             :    * Which one of the two cell vectors are this sequence's output is solely
     218             :    * dependant on the number of filters the sequence contains, because each swap
     219             :    * (see loadFiltersFromXML) changes what is the sequence's final filter's
     220             :    * output.
     221             :    *
     222             :    * Some sequences have more than one output, thus the optional parameter. Has
     223             :    * no effect on a basic FilterSequence.
     224             :    */
     225           0 :   virtual const std::vector<coupling::datastructures::CouplingCell<dim>*>& getOutputCellVector(unsigned int outputIndex = 0) const {
     226           0 :     if (_filters.empty())
     227           0 :       return _inputCellVector;
     228             : 
     229           0 :     if (_filters.size() % 2 == 0)
     230           0 :       return _cellVector1;
     231             : 
     232           0 :     return _cellVector2;
     233             :   }
     234             : 
     235           0 :   virtual void printOutputCellVector() const {
     236           0 :     if (getOutputCellVector() == _inputCellVector)
     237           0 :       std::cout << "The sequence's input cell vector ";
     238           0 :     else if (getOutputCellVector() == _cellVector1)
     239           0 :       std::cout << "Cell vector 1 ";
     240           0 :     else if (getOutputCellVector() == _cellVector2)
     241           0 :       std::cout << "Cell vector 2 ";
     242             :     else { /*unreachable, see function definition above*/
     243             :     }
     244             : 
     245           0 :     std::cout << "will be used as output." << std::endl;
     246           0 :   }
     247             : 
     248             :   /*
     249             :    * This is trivial for the traditional sequence, i.e. non-Junction-case.
     250             :    */
     251           0 :   virtual unsigned int getNumInputs() { return 1; }
     252           0 :   virtual unsigned int getNumOutputs() { return 1; }
     253             : 
     254             :   /*
     255             :    * DUMMY HELPER FUNCTIONS
     256             :    */
     257             : 
     258           0 :   virtual void printFilters() {
     259           0 :     std::cout << "Filters in sequence " << _name << ": ";
     260           0 :     for (auto f : _filters)
     261           0 :       std::cout << f->getType() << " ";
     262           0 :     std::cout << std::endl;
     263           0 :   }
     264             : 
     265           0 :   virtual std::string PRINT_PREFIX() const { return std::string("  FS(").std::string::append(_name).std::string::append("): "); }
     266             : 
     267             : private:
     268             :   /*
     269             :    * Copies all input cells to _cellVector1 and _cellVector2.
     270             :    *
     271             :    * Used in consctructor.
     272             :    *
     273             :    * Not implemented by FilterJunction: Equivalent procedure can be found in
     274             :    * that class' constructor.
     275             :    */
     276             :   void initCellVectors();
     277             : 
     278             : protected:
     279             :   const char* _name;
     280             : 
     281             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _inputCellVector; // points to (foreign) input vector
     282             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _cellVector1;     // allocated for this sequence only
     283             :   std::vector<coupling::datastructures::CouplingCell<dim>*> _cellVector2;     // allocated for this sequence only
     284             : 
     285             : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
     286             :   MPI_Comm _comm;
     287             : #endif
     288             : 
     289             :   std::array<bool, 7> _filteredValues;
     290             : 
     291             :   bool _isOutput;     // true if this sequence's output vector (see above) is the
     292             :                       // Filter Pipeline's output
     293             :   bool _isModifiable; // true while filters can be added to sequence
     294             : 
     295             :   std::vector<coupling::filtering::FilterInterface<dim>*> _filters;
     296             : 
     297             :   // stores application times for all filters
     298             :   std::map<coupling::filtering::FilterInterface<dim>*, std::vector<unsigned int>> _filterTimes;
     299             : 
     300             :   // there must be some other place to get this from
     301             :   unsigned int _timestepsElapsed;
     302             : 
     303             :   // stores pointers to all sequences that use this sequence's output as their
     304             :   // input.
     305             :   std::vector<coupling::filtering::FilterSequence<dim>*> _childSequences;
     306             : };
     307             : 
     308             : // inlcude implementation
     309             : #include "coupling/filtering/sequencing/FilterSequence.cpph"

Generated by: LCOV version 1.14