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"
|