MaMiCo 1.2
Loading...
Searching...
No Matches
FilterSequence.h
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
45namespace coupling {
46namespace filtering {
47template <unsigned int dim> class FilterSequence;
48}
49} // namespace coupling
50
51template <unsigned int dim> class coupling::filtering::FilterSequence {
52public:
53 /*
54 * Filter Sequences are constructed in
55 * coupling::FilterPipeline::loadSequencesFromXML(...).
56 */
57 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 : _name(name), _inputCellVector(inputCells),
63#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
64 _comm(comm),
65#endif
66 _filteredValues(filteredValues), _isOutput(false), // potentially updated via loadSequencesFromXML
67 // calling setAsOutput()
68 _isModifiable(true), // TODO: allow const sequences via XML attribute
69 _timestepsElapsed(0) {
70#ifdef DEBUG_FILTER_PIPELINE
71 std::cout << PRINT_PREFIX() << "Now initializing." << std::endl;
72#endif
73
74 initCellVectors();
75
76 bool filtersAnything = false;
77 for (unsigned int i = 0; i < 7; i++)
78 if (_filteredValues[i]) {
79 filtersAnything = true;
80 break;
81 }
82 if (!filtersAnything)
83 std::cout << "Warning: Filter sequence " << _name
84 << " does not filter any values. Add 'filtered-values' "
85 "attribute to XML element to change this."
86 << std::endl;
87#ifdef DEBUG_FILTER_PIPELINE
88 std::cout << PRINT_PREFIX() << "Finished initialization." << std::endl;
89#endif
90 }
91
92 virtual ~FilterSequence() {
93 // Output average application times for all filters
94 std::cout << PRINT_PREFIX() << "Average application times for filters in this sequence in \u03BCs:" << std::endl;
95 for (auto filter : _filters) {
96 std::cout << " " << filter->getType() << ": "
97 << (double)std::accumulate(_filterTimes[filter].begin(), _filterTimes[filter].end(), 0) / (double)_timestepsElapsed << std::endl;
98 }
99
100 for (auto v1 : _cellVector1)
101 delete v1;
102 for (auto v2 : _cellVector2)
103 delete v2;
104 for (auto f : _filters)
105 delete f;
106#ifdef DEBUG_FILTER_PIPELINE
107 std::cout << PRINT_PREFIX() << "Deconstructed." << std::endl;
108#endif
109 }
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 void updateCellVectors() {
116 for (unsigned int index = 0; index < _cellVector1.size(); index++) {
117 *(_cellVector1[index]) = *(_inputCellVector[index]);
118 *(_cellVector2[index]) = *(_inputCellVector[index]);
119 }
120 }
121
122 /*
123 * Applies all filters stored in _filters. Also measures performance times.
124 */
125 void operator()() {
126 for (auto filter : _filters) {
127 // measure time before application
128 timeval before;
129 gettimeofday(&before, NULL);
130
131 // Apply the filter's operator()
132 (*filter)();
133
134 // measure time after application
135 timeval after;
136 gettimeofday(&after, NULL);
137
138 // store time difference in usec in map
139 _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 _timestepsElapsed++;
146 }
147
148 /*
149 * Returns unique name identifier of this sequence.
150 */
151 const char* getName() { return _name; }
152
153 bool isOutputToMacro() { return _isOutput; }
154 void setAsOutputToMacro() {
155 std::cout << PRINT_PREFIX() << " Setting as pipeline to macro solver output." << std::endl;
156 _isOutput = true;
157 }
158
159 /*
160 * Modifiable sequences may have filters added dynamically via
161 * FilterFromFunction.
162 */
163 bool isModifiable() { return _isModifiable; }
164 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 virtual void addChildSequence(coupling::filtering::FilterSequence<dim>* childSequence) { _childSequences.push_back(childSequence); }
204
205 /*
206 * Allows changing the input cells after init.
207 */
208 virtual void updateInputCellVector(const std::vector<coupling::datastructures::CouplingCell<dim>*> newInputCellVector) {
209 _inputCellVector = newInputCellVector; // call copy constructor
210
211 // cc this change to this sequence's first vector.
212 if (!_filters.empty())
213 _filters[0]->setInputCells(_inputCellVector);
214 }
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 virtual const std::vector<coupling::datastructures::CouplingCell<dim>*>& getOutputCellVector(unsigned int outputIndex = 0) const {
226 if (_filters.empty())
227 return _inputCellVector;
228
229 if (_filters.size() % 2 == 0)
230 return _cellVector1;
231
232 return _cellVector2;
233 }
234
235 virtual void printOutputCellVector() const {
236 if (getOutputCellVector() == _inputCellVector)
237 std::cout << "The sequence's input cell vector ";
238 else if (getOutputCellVector() == _cellVector1)
239 std::cout << "Cell vector 1 ";
240 else if (getOutputCellVector() == _cellVector2)
241 std::cout << "Cell vector 2 ";
242 else { /*unreachable, see function definition above*/
243 }
244
245 std::cout << "will be used as output." << std::endl;
246 }
247
248 /*
249 * This is trivial for the traditional sequence, i.e. non-Junction-case.
250 */
251 virtual unsigned int getNumInputs() { return 1; }
252 virtual unsigned int getNumOutputs() { return 1; }
253
254 /*
255 * DUMMY HELPER FUNCTIONS
256 */
257
258 virtual void printFilters() {
259 std::cout << "Filters in sequence " << _name << ": ";
260 for (auto f : _filters)
261 std::cout << f->getType() << " ";
262 std::cout << std::endl;
263 }
264
265 virtual std::string PRINT_PREFIX() const { return std::string(" FS(").std::string::append(_name).std::string::append("): "); }
266
267private:
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
278protected:
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"
defines the cell type with cell-averaged quantities only (no linked cells).
Definition CouplingCell.h:29
Definition FilterSequence.h:51
Definition tinyxml2.h:1268
Definition FilterPipeline.h:21
everything necessary for coupling operations, is defined in here
Definition AdditiveMomentumInsertion.h:15