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"