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"