TTK
Loading...
Searching...
No Matches
ttkCinemaQuery.cpp
Go to the documentation of this file.
1#include <ttkCinemaQuery.h>
2
3#include <vtkInformation.h>
4
5#include <vtkDelimitedTextReader.h>
6#include <vtkFieldData.h>
7#include <vtkInformationVector.h>
8#include <vtkObjectFactory.h>
9#include <vtkSmartPointer.h>
10#include <vtkTable.h>
11
12#include <ttkUtils.h>
13
14#include <numeric>
15#include <regex>
16
17#include <boost/algorithm/string.hpp>
18#include <boost/algorithm/string/replace.hpp>
19
21
23 this->SetNumberOfInputPorts(1);
24 this->SetNumberOfOutputPorts(1);
25}
27
28int ttkCinemaQuery::FillInputPortInformation(int port, vtkInformation *info) {
29 if(port == 0) {
30 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
31 info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
32 return 1;
33 }
34 return 0;
35}
36
37int ttkCinemaQuery::FillOutputPortInformation(int port, vtkInformation *info) {
38 if(port == 0) {
39 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable");
40 return 1;
41 }
42 return 0;
43}
44
45int ttkCinemaQuery::RequestData(vtkInformation *ttkNotUsed(request),
46 vtkInformationVector **inputVector,
47 vtkInformationVector *outputVector) {
48 ttk::Timer timer;
49
50 // get output table
51 auto outTable = vtkTable::GetData(outputVector);
52
53 // ===========================================================================
54 // Convert Input Tables to SQL Tables
55 auto nTables = inputVector[0]->GetNumberOfInformationObjects();
56 if(nTables == 0) {
57 this->printErr("No input vtkTable found");
58 return 0;
59 }
60
61 std::vector<vtkTable *> inTables(nTables);
62 for(int i = 0; i < nTables; ++i) {
63 inTables[i] = vtkTable::GetData(inputVector[0], i);
64 }
65
66 auto firstTable = inTables[0];
67
68 std::vector<std::string> sqlTableDefinitions;
69 std::vector<std::string> sqlInsertStatements;
70 {
71 ttk::Timer conversionTimer;
72
73 for(int i = 0; i < nTables; i++) {
74 auto inTable = inTables[i];
75
76 size_t const nc = inTable->GetNumberOfColumns();
77 size_t const nr = inTable->GetNumberOfRows();
78 std::vector<bool> isNumeric(nc);
79
80 std::vector<size_t> includeColumns(nc);
81 std::iota(includeColumns.begin(), includeColumns.end(), 0);
82
83 // exclude input columns whose name matches the regexp
84 if(this->ExcludeColumnsWithRegexp) {
85 const auto oldSize{includeColumns.size()};
86 includeColumns.erase(
87 std::remove_if(includeColumns.begin(), includeColumns.end(),
88 [inTable, this](const size_t a) {
89 const auto name{inTable->GetColumnName(a)};
90 return std::regex_match(
91 name, std::regex(this->RegexpString));
92 }),
93 includeColumns.end());
94 if(includeColumns.size() < oldSize) {
95 this->printMsg("Removed "
96 + std::to_string(oldSize - includeColumns.size())
97 + " columns with regexp `" + this->RegexpString + "'");
98 }
99 }
100
101 // exclude non-scalar columnns
102 {
103 const auto oldSize{includeColumns.size()};
104 includeColumns.erase(
105 std::remove_if(includeColumns.begin(), includeColumns.end(),
106 [inTable](const size_t a) {
107 const auto col{inTable->GetColumn(a)};
108 return col->GetNumberOfComponents() != 1;
109 }),
110 includeColumns.end());
111 if(includeColumns.size() < oldSize) {
112 this->printWrn("Removed "
113 + std::to_string(oldSize - includeColumns.size())
114 + " non-scalar columns");
115 }
116 }
117
118 // exclude columns with a space in their name
119 {
120 const auto oldSize{includeColumns.size()};
121 includeColumns.erase(
122 std::remove_if(includeColumns.begin(), includeColumns.end(),
123 [inTable](const size_t a) {
124 const std::string colName{inTable->GetColumnName(a)};
125 return colName.find(' ') != std::string::npos;
126 }),
127 includeColumns.end());
128 if(includeColumns.size() < oldSize) {
129 this->printWrn("Removed "
130 + std::to_string(oldSize - includeColumns.size())
131 + " columns with a space in their name");
132 }
133 }
134
135 if(includeColumns.empty()) {
136 this->printWrn("No columns to process!");
137 return 1;
138 }
139
140 // -----------------------------------------------------------------------
141 // Table Definition
142 std::string sqlTableDefinition
143 = "CREATE TABLE InputTable" + std::to_string(i) + " (";
144 bool firstCol{true};
145 for(const auto j : includeColumns) {
146 auto c = inTable->GetColumn(j);
147 isNumeric[j] = c->IsNumeric();
148 sqlTableDefinition += (firstCol ? "" : ",") + std::string(c->GetName())
149 + " " + (isNumeric[j] ? "REAL" : "TEXT");
150 if(firstCol) {
151 firstCol = false;
152 }
153 }
154 sqlTableDefinition += ")";
155 sqlTableDefinitions.emplace_back(sqlTableDefinition);
156
157 // -----------------------------------------------------------------------
158 // Insert Statements
159 size_t q = 0;
160 while(q < nr) {
161 std::string sqlInsertStatement
162 = "INSERT INTO InputTable" + std::to_string(i) + " VALUES ";
163 for(size_t j = 0; j < 500 && q < nr; j++) {
164 if(j > 0)
165 sqlInsertStatement += ",";
166
167 sqlInsertStatement += "(";
168 firstCol = true;
169 for(const auto k : includeColumns) {
170 sqlInsertStatement += (firstCol ? "" : ",");
171 if(firstCol) {
172 firstCol = false;
173 }
174 if(isNumeric[k]) {
175 const auto var = inTable->GetValue(q, k);
176 if(var.IsChar() || var.IsSignedChar()) {
177 // convert char/signed char to int to get its value
178 // instead of its char representation
179 sqlInsertStatement += std::to_string(var.ToInt());
180 } else if(std::isnan(var.ToDouble())) {
181 sqlInsertStatement += "'NaN'";
182 } else {
183 sqlInsertStatement += var.ToString();
184 }
185 } else {
186 sqlInsertStatement
187 += "'" + inTable->GetValue(q, k).ToString() + "'";
188 }
189 }
190 sqlInsertStatement += ")";
191 q++;
192 }
193 sqlInsertStatements.emplace_back(sqlInsertStatement);
194 }
195 }
196
197 this->printMsg("Converting input VTK tables to SQL tables", 1,
198 conversionTimer.getElapsedTime());
199 }
200
201 // ===========================================================================
202 // Replace Variables in Querystd::string (e.g. {time[2]})
203 std::string finalQueryString;
204 {
205 std::string errorMsg;
206 if(!ttkUtils::replaceVariables(this->GetSQLStatement(),
207 firstTable->GetFieldData(), finalQueryString,
208 errorMsg)) {
209 this->printErr(errorMsg);
210 return 0;
211 }
212 }
213
214 // ===========================================================================
215 // Compute Query Result
216 std::stringstream csvResult;
217 int csvNColumns = 0;
218 int csvNRows = 0;
219
220 int const status
221 = this->execute(sqlTableDefinitions, sqlInsertStatements, finalQueryString,
222 csvResult, csvNColumns, csvNRows);
223
224 // ===========================================================================
225 // Process Result
226 {
227 if(csvNRows < 1 || status != 1) {
228 csvResult << "NULL";
229 for(int i = 0; i < csvNColumns; i++)
230 csvResult << ",NULL";
231 }
232
233 ttk::Timer conversionTimer;
234
235 this->printMsg(
236 "Converting SQL result to VTK table", 0, ttk::debug::LineMode::REPLACE);
237
239 reader->SetReadFromInputString(true);
240 reader->SetInputString(csvResult.str().data());
241 reader->DetectNumericColumnsOn();
242 reader->SetHaveHeaders(true);
243 reader->SetFieldDelimiterCharacters(",");
244 reader->Update();
245
246 outTable->ShallowCopy(reader->GetOutput());
247
248 auto outFD = outTable->GetFieldData();
249 for(const auto inTable : inTables) {
250 if(!inTable)
251 continue;
252 auto inFD = inTable->GetFieldData();
253
254 size_t const n = inFD->GetNumberOfArrays();
255 for(size_t i = 0; i < n; i++) {
256 auto iArray = inFD->GetAbstractArray(i);
257 if(!outFD->GetAbstractArray(iArray->GetName())) {
258 outFD->AddArray(iArray);
259 }
260 }
261 }
262
263 this->printMsg("Converting SQL result to VTK table", 1,
264 conversionTimer.getElapsedTime());
265 }
266
267 // print stats
269 this->printMsg("Complete (#rows: " + std::to_string(csvNRows) + ")", 1,
270 timer.getElapsedTime());
272
273 return 1;
274}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
TTK VTK-filter that uses a SQL statement to select a subset of a vtkTable.
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
~ttkCinemaQuery() override
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
static int replaceVariables(const std::string &iString, vtkFieldData *fieldData, std::string &oString, std::string &errorMsg)
Definition ttkUtils.cpp:73
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
double getElapsedTime()
Definition Timer.h:15
T var(const T *v, const int &dimension=3)
vtkStandardNewMacro(ttkCinemaQuery)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)