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#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 for (auto v1 : _cellVector1)
105 delete v1;
106 for (auto v2 : _cellVector2)
107 delete v2;
108 for (auto f : _filters)
109 delete f;
110#ifdef DEBUG_FILTER_PIPELINE
111 std::cout << PRINT_PREFIX() << "Deconstructed." << std::endl;
112#endif
113 }
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 void updateCellVectors() {
120 for (unsigned int index = 0; index < _cellVector1.size(); index++) {
121 *(_cellVector1[index]) = *(_inputCellVector[index]);
122 *(_cellVector2[index]) = *(_inputCellVector[index]);
123 }
124 }
125
126 /*
127 * Applies all filters stored in _filters. Also measures performance times.
128 */
129 void operator()() {
130 for (auto filter : _filters) {
131 // measure time before application
132 timeval before;
133 gettimeofday(&before, NULL);
134
135 // Apply the filter's operator()
136 (*filter)();
137
138 // measure time after application
139 timeval after;
140 gettimeofday(&after, NULL);
141
142 // store time difference in usec in map
143 _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 _timestepsElapsed++;
150 }
151
152 /*
153 * Returns unique name identifier of this sequence.
154 */
155 const char* getName() { return _name; }
156
157 bool isOutputToMacro() { return _isOutput; }
158 void setAsOutputToMacro() {
159#ifdef DEBUG_FILTER_PIPELINE
160 std::cout << PRINT_PREFIX() << " Setting as pipeline to macro solver output." << std::endl;
161#endif
162 _isOutput = true;
163 }
164
165 /*
166 * Modifiable sequences may have filters added dynamically via
167 * FilterFromFunction.
168 */
169 bool isModifiable() { return _isModifiable; }
170 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 virtual void addChildSequence(coupling::filtering::FilterSequence<dim>* childSequence) { _childSequences.push_back(childSequence); }
210
211 /*
212 * Allows changing the input cells after init.
213 */
214 virtual void updateInputCellVector(const std::vector<coupling::datastructures::CouplingCell<dim>*> newInputCellVector) {
215 _inputCellVector = newInputCellVector; // call copy constructor
216
217 // cc this change to this sequence's first vector.
218 if (!_filters.empty())
219 _filters[0]->setInputCells(_inputCellVector);
220 }
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 virtual const std::vector<coupling::datastructures::CouplingCell<dim>*>& getOutputCellVector(unsigned int outputIndex = 0) const {
232 if (_filters.empty())
233 return _inputCellVector;
234
235 if (_filters.size() % 2 == 0)
236 return _cellVector1;
237
238 return _cellVector2;
239 }
240
241 virtual void printOutputCellVector() const {
242 if (getOutputCellVector() == _inputCellVector)
243 std::cout << "The sequence's input cell vector ";
244 else if (getOutputCellVector() == _cellVector1)
245 std::cout << "Cell vector 1 ";
246 else if (getOutputCellVector() == _cellVector2)
247 std::cout << "Cell vector 2 ";
248 else { /*unreachable, see function definition above*/
249 }
250
251 std::cout << "will be used as output." << std::endl;
252 }
253
254 /*
255 * This is trivial for the traditional sequence, i.e. non-Junction-case.
256 */
257 virtual unsigned int getNumInputs() { return 1; }
258 virtual unsigned int getNumOutputs() { return 1; }
259
260 /*
261 * DUMMY HELPER FUNCTIONS
262 */
263
264 virtual void printFilters() {
265 std::cout << "Filters in sequence " << _name << ": ";
266 for (auto f : _filters)
267 std::cout << f->getType() << " ";
268 std::cout << std::endl;
269 }
270
271 virtual std::string PRINT_PREFIX() const { return std::string(" FS(").std::string::append(_name).std::string::append("): "); }
272
273private:
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
284protected:
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"
defines the cell type with cell-averaged quantities only (no linked cells).
Definition CouplingCell.h:29
Definition FilterSequence.h:51
Definition tinyxml2.h:1124
Definition FilterPipeline.h:21
everything necessary for coupling operations, is defined in here
Definition AdditiveMomentumInsertion.h:15