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/mamic::o
4 :
5 : #include <typeinfo>
6 :
7 : // Member functions of coupling::filtering::FilterSequence
8 :
9 0 : template <unsigned int dim> int coupling::filtering::FilterSequence<dim>::loadFiltersFromXML(tinyxml2::XMLElement* sequenceNode) {
10 0 : if (!sequenceNode)
11 : return EXIT_FAILURE;
12 0 : tinyxml2::XMLElement* currFilterNode = sequenceNode->FirstChildElement();
13 :
14 0 : std::vector<coupling::datastructures::CouplingCell<dim>*> inputCellVector = _inputCellVector;
15 0 : std::vector<coupling::datastructures::CouplingCell<dim>*> outputCellVector = _cellVector2;
16 :
17 : #ifdef DEBUG_FILTER_PIPELINE
18 : std::cout << PRINT_PREFIX() << "Initializing filter objects." << std::endl;
19 : #endif
20 : bool firstIteration = true;
21 :
22 0 : while (currFilterNode) {
23 0 : coupling::filtering::FilterInterface<dim>* newfilter = nullptr;
24 :
25 0 : bool sequential = false;
26 0 : if (const char* seqAttr = currFilterNode->Attribute("sequential"))
27 0 : if (std::strcmp(seqAttr, "true") == 0)
28 0 : sequential = true;
29 :
30 : // ###############################################################
31 : // This is where you have to define how to handle each filter individually.
32 : // Write To File
33 0 : if (std::strcmp(currFilterNode->Value(), "write-to-file") == 0) {
34 0 : bool overwrite = false;
35 0 : if (currFilterNode->Attribute("overwrite"))
36 0 : if (std::strcmp(currFilterNode->Attribute("overwrite"), "true") == 0)
37 0 : overwrite = true;
38 :
39 0 : int oco = -1;
40 0 : tarch::configuration::ParseConfiguration::readIntOptional(oco, currFilterNode, "one-cell-only");
41 0 : if (oco < -1 || oco >= (int)inputCellVector.size()) {
42 0 : std::cout << "ERROR: XML config file references undefined cell index " << oco << " for write-to-file." << std::endl;
43 0 : exit(EXIT_FAILURE);
44 : }
45 :
46 0 : const std::string location = currFilterNode->Attribute("location");
47 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
48 : using namespace std::string_literals;
49 : int rank;
50 0 : MPI_Comm_rank(_comm, &rank);
51 :
52 0 : newfilter =
53 0 : new coupling::filtering::WriteToFile<dim>(inputCellVector, outputCellVector, _filteredValues, std::to_string(rank) + "_"s + location, overwrite, oco);
54 : #else
55 : newfilter = new coupling::filtering::WriteToFile<dim>(inputCellVector, outputCellVector, _filteredValues, location, overwrite, oco);
56 : #endif
57 0 : }
58 :
59 : // Read From File
60 0 : else if (std::strcmp(currFilterNode->Value(), "read-from-file") == 0) {
61 :
62 0 : newfilter = new coupling::filtering::ReadFromFile<dim>(inputCellVector, outputCellVector, _filteredValues, currFilterNode->Attribute("location"));
63 0 : const std::string location = currFilterNode->Attribute("location");
64 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
65 : using namespace std::string_literals;
66 : int rank;
67 0 : MPI_Comm_rank(_comm, &rank);
68 :
69 0 : newfilter = new coupling::filtering::ReadFromFile<dim>(inputCellVector, outputCellVector, _filteredValues, std::to_string(rank) + "_"s + location);
70 : #else
71 : newfilter = new coupling::filtering::ReadFromFile<dim>(inputCellVector, outputCellVector, _filteredValues, location);
72 : #endif
73 :
74 0 : }
75 :
76 : // Constant Filter
77 0 : else if (std::strcmp(currFilterNode->Value(), "constant") == 0) {
78 0 : double constant = 0.0; // by default, constant filter uses 0 as its constant.
79 0 : tarch::configuration::ParseConfiguration::readDoubleOptional(constant, currFilterNode, "value");
80 :
81 0 : tarch::la::Vector<dim, bool> filteredDims = {true}; // default: filter multidimensional properties in all dims
82 0 : int dir = -1;
83 0 : tarch::configuration::ParseConfiguration::readIntOptional(dir, currFilterNode, "dir");
84 0 : if (dir >= 0 && (unsigned int)dir < dim) /*if d is within range...*/ {
85 : /*... set all dims but d to false*/
86 0 : filteredDims = {false};
87 0 : filteredDims[dir] = true;
88 : }
89 :
90 0 : newfilter = new coupling::filtering::Constant<dim>(inputCellVector, outputCellVector, _filteredValues, filteredDims, constant);
91 : }
92 :
93 : // Gauss
94 0 : else if (std::strcmp(currFilterNode->Value(), "gauss") == 0) {
95 : // dimension the gauss filter operates on
96 : int d;
97 0 : if (currFilterNode->QueryIntAttribute("dim", &d)) {
98 0 : std::cout << "ERROR: Gaussian filter misses attribute dim in config file." << std::endl;
99 0 : exit(EXIT_FAILURE);
100 : }
101 :
102 : // standard deviation of the gauss filter
103 : double sigma;
104 0 : if (currFilterNode->QueryDoubleAttribute("sigma", &sigma)) {
105 0 : std::cout << "ERROR: Gaussian filter misses attribute sigma in config file." << std::endl;
106 0 : exit(EXIT_FAILURE);
107 : }
108 :
109 : //"extrapolation" is not mandatory
110 : const char* extrapolation;
111 0 : extrapolation = currFilterNode->Attribute("extrapolation");
112 :
113 0 : if (sequential)
114 0 : newfilter = new coupling::filtering::Gauss<dim>(inputCellVector, outputCellVector, _filteredValues, (unsigned int)d, sigma, extrapolation);
115 : else
116 0 : newfilter = new coupling::filtering::Gauss<dim, coupling::indexing::IndexTrait::local>(inputCellVector, outputCellVector, _filteredValues,
117 : (unsigned int)d, sigma, extrapolation);
118 : }
119 :
120 : // POD
121 0 : else if (std::strcmp(currFilterNode->Value(), "POD") == 0) {
122 : #ifdef BUILD_WITH_EIGEN
123 : // In earlier implementations, it used to be possible to override tws via
124 : // function parameter. This feature was removed. See:
125 : // coupling::noisereduction::NoiseReductionConfiguration::interpreteConfiguration<dim>(...,
126 : // int tws)
127 : int tws;
128 : if (currFilterNode->QueryIntAttribute("time-window-size", &tws)) {
129 : std::cout << "ERROR: POD filter misses attribute time-window-size in "
130 : "config file."
131 : << std::endl;
132 : exit(EXIT_FAILURE);
133 : }
134 : if (tws <= 2) {
135 : std::cout << "ERROR: POD: time-window-size must be greater than two." << std::endl;
136 : exit(EXIT_FAILURE);
137 : }
138 : int kmax;
139 : if (currFilterNode->QueryIntAttribute("kmax", &kmax)) {
140 : std::cout << "ERROR: POD filter misses attribute kmax in config file." << std::endl;
141 : exit(EXIT_FAILURE);
142 : }
143 : if (kmax <= 0) {
144 : std::cout << "ERROR: POD: kmax must be greater than zero.";
145 : exit(EXIT_FAILURE);
146 : }
147 :
148 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
149 : newfilter = new coupling::filtering::POD<dim>(inputCellVector, outputCellVector, _comm, _filteredValues, tws, kmax);
150 : #else
151 : newfilter = new coupling::filtering::POD<dim>(inputCellVector, outputCellVector, _filteredValues, tws, kmax);
152 : #endif
153 : #else
154 0 : std::cout << "ERROR: BUILD_WITH_EIGEN was not defined but filter node was set to POD." << std::endl;
155 0 : exit(EXIT_FAILURE);
156 : #endif
157 : }
158 :
159 : // TODO: refactor the following filters to fit to new type system
160 : /*
161 : //Strouhal
162 : else if(std::strcmp(currFilterNode->Value(), "strouhal") == 0) {
163 : double d;
164 : if(currFilterNode->QueryDoubleAttribute("D", &d)){
165 : std::cout << "ERROR: Strouhal filter misses
166 : attribute D in config file." << std::endl; exit(EXIT_FAILURE);
167 : }
168 : double u;
169 : if(currFilterNode->QueryDoubleAttribute("U", &u)){
170 : std::cout << "ERROR: Strouhal filter misses
171 : attribute U in config file." << std::endl; exit(EXIT_FAILURE);
172 : }
173 : newfilter = new
174 : coupling::filtering::Strouhal<dim>(inputCellVector, outputCellVector,
175 : _sequenceDomainCellIndices, _filteredValues, u , d);
176 : }
177 : */
178 :
179 : // ###############################################################
180 :
181 : // Unknown filter identifier
182 : else {
183 0 : std::cout << "ERROR: Filter-Sequence does not recognize filter called " << currFilterNode->Value() << std::endl;
184 0 : exit(EXIT_FAILURE);
185 : }
186 :
187 : // sequential filtering
188 : #if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
189 0 : if (sequential)
190 0 : _filters.push_back(new coupling::filtering::SequentialFilter<dim>(newfilter, _comm));
191 : else
192 : #endif
193 0 : _filters.push_back(newfilter);
194 :
195 0 : if (firstIteration) {
196 0 : inputCellVector = _cellVector1;
197 : firstIteration = false;
198 : }
199 :
200 0 : inputCellVector.swap(outputCellVector);
201 0 : currFilterNode = currFilterNode->NextSiblingElement();
202 : }
203 :
204 : // Check for modfiability. By default true.
205 0 : if (const char* modifiable = sequenceNode->Attribute("modifiable")) {
206 0 : if (std::strcmp(modifiable, "false") == 0)
207 0 : _isModifiable = false;
208 : }
209 :
210 : #ifdef DEBUG_FILTER_PIPELINE
211 : std::cout << PRINT_PREFIX();
212 : printOutputCellVector();
213 : #endif
214 :
215 0 : return 0;
216 0 : }
217 :
218 : // TODO: restructure code: reduce code duplication
219 : template <unsigned int dim>
220 0 : void coupling::filtering::FilterSequence<dim>::addFilter(
221 : const std::function<std::vector<double>(std::vector<double>, std::vector<std::array<unsigned int, dim>>)>* applyScalar,
222 : const std::function<std::vector<std::array<double, dim>>(std::vector<std::array<double, dim>>, std::vector<std::array<unsigned int, dim>>)>* applyVector,
223 : int filterIndex // counting starts at 0, -1 is equivalent to EOL
224 : ) {
225 : // save state before tinkering with output cells
226 0 : auto outputCellVectorBefore = getOutputCellVector();
227 :
228 0 : if (_isModifiable) {
229 0 : const unsigned int index = (filterIndex == -1 || filterIndex > (int)_filters.size()) ? _filters.size() : filterIndex;
230 :
231 : // case: index 0
232 0 : if (index == 0) {
233 : // previous filter at index 0 won't use _inputCellVector any longer
234 0 : if (!_filters.empty())
235 0 : _filters[0]->setInputCells(_cellVector1);
236 :
237 0 : _filters.insert(_filters.begin() + index,
238 0 : new coupling::filtering::FilterFromFunction<dim>(_inputCellVector, _cellVector2, _filteredValues, applyScalar, applyVector));
239 :
240 : // add copy if no copy after index exists, else remove that copy
241 0 : if (_filters.size() > 1) { // dont check if the newly added FFF is the
242 : // only filter in the sequence
243 0 : if (std::strcmp(_filters[1]->getType(), "COPY") == 0)
244 0 : _filters.erase(_filters.begin() + 1);
245 : else
246 0 : _filters.insert(_filters.begin() + 1, new coupling::filtering::Copy<dim>(_cellVector2, _cellVector1, _filteredValues));
247 : } else
248 0 : _filters.insert(_filters.begin() + 1, new coupling::filtering::Copy<dim>(_cellVector2, _cellVector1, _filteredValues));
249 : #ifdef DEBUG_FILTER_PIPELINE
250 : std::cout << PRINT_PREFIX() << "Inserted new filter at index 0" << std::endl;
251 : #endif
252 : }
253 :
254 : // case: appending to nonempty sequence
255 0 : else if (index == _filters.size()) {
256 0 : if (_filters.size() % 2 == 0)
257 0 : _filters.push_back(new coupling::filtering::FilterFromFunction<dim>(_cellVector1, _cellVector2, _filteredValues, applyScalar, applyVector));
258 : else
259 0 : _filters.push_back(new coupling::filtering::FilterFromFunction<dim>(_cellVector2, _cellVector1, _filteredValues, applyScalar, applyVector));
260 : #ifdef DEBUG_FILTER_PIPELINE
261 : std::cout << PRINT_PREFIX() << "Appended new filter to sequence." << std::endl;
262 : #endif
263 : }
264 :
265 : // case: inserting at nonzero index
266 : else {
267 0 : if (index % 2 == 0) {
268 0 : _filters.insert(_filters.begin() + index,
269 0 : new coupling::filtering::FilterFromFunction<dim>(_cellVector1, _cellVector2, _filteredValues, applyScalar, applyVector));
270 :
271 : // add copy if no copy after index exists, else remove that copy
272 0 : if (std::strcmp(_filters[index + 1]->getType(), "COPY") == 0)
273 0 : _filters.erase(_filters.begin() + index + 1);
274 : else
275 0 : _filters.insert(_filters.begin() + index + 1, new coupling::filtering::Copy<dim>(_cellVector2, _cellVector1, _filteredValues));
276 : } else {
277 0 : _filters.insert(_filters.begin() + index,
278 0 : new coupling::filtering::FilterFromFunction<dim>(_cellVector2, _cellVector1, _filteredValues, applyScalar, applyVector));
279 :
280 : // add copy if no copy after index exists, else remove that copy
281 0 : if (std::strcmp(_filters[index + 1]->getType(), "COPY") == 0)
282 0 : _filters.erase(_filters.begin() + index + 1);
283 : else
284 0 : _filters.insert(_filters.begin() + index + 1, new coupling::filtering::Copy<dim>(_cellVector1, _cellVector2, _filteredValues));
285 : }
286 : #ifdef DEBUG_FILTER_PIPELINE
287 : std::cout << PRINT_PREFIX() << "Inserted new filter at index " << index << std::endl;
288 : #endif
289 : }
290 : #ifdef DEBUG_FILTER_PIPELINE
291 : std::cout << PRINT_PREFIX();
292 : printOutputCellVector();
293 : #endif
294 : } else
295 : std::cout << "WARNING: Trying to add filter at runtime to non-modifiable "
296 : "filter sequence "
297 0 : << _name << ". Refused." << std::endl; // exit()?
298 :
299 : // Check if output vector has changed. Currently, this can only happen if the
300 : // output vector was _inputCellVector before.
301 0 : if (outputCellVectorBefore != getOutputCellVector()) {
302 0 : for (auto child : _childSequences) {
303 0 : child->updateInputCellVector(getOutputCellVector());
304 : #ifdef DEBUG_FILTER_PIPELINE
305 : std::cout << PRINT_PREFIX() << "Reported change in output vector to child sequence " << child->getName() << std::endl;
306 : #endif
307 : }
308 : }
309 0 : }
310 :
311 : // Private functions of coupling::filtering::FilterSequence
312 :
313 : // TODO: inline in constructor
314 0 : template <unsigned int dim> void coupling::filtering::FilterSequence<dim>::initCellVectors() {
315 0 : for (auto cell : _inputCellVector) {
316 0 : _cellVector1.push_back(new coupling::datastructures::CouplingCell<dim>(*cell));
317 0 : _cellVector2.push_back(new coupling::datastructures::CouplingCell<dim>(*cell));
318 : }
319 : #ifdef DEBUG_FILTER_PIPELINE
320 : std::cout << PRINT_PREFIX() << "Initialized cell vectors." << std::endl;
321 : #endif
322 0 : }
|