TTK
Loading...
Searching...
No Matches
ttkIntegralLines.cpp
Go to the documentation of this file.
1#include <string>
2#include <ttkIntegralLines.h>
3#include <ttkMacros.h>
4#include <ttkUtils.h>
5
6#include <ArrayLinkedList.h>
7#include <vtkCellData.h>
8#include <vtkDataArray.h>
9#include <vtkDataObject.h>
10#include <vtkDataSet.h>
11#include <vtkDoubleArray.h>
12#include <vtkInformation.h>
13#include <vtkObjectFactory.h>
14#include <vtkPointData.h>
15#include <vtkPointSet.h>
16#include <vtkUnstructuredGrid.h>
17
18#include <array>
19
21
23 this->SetNumberOfInputPorts(2);
24 this->SetNumberOfOutputPorts(1);
25}
26
28
29int ttkIntegralLines::FillInputPortInformation(int port, vtkInformation *info) {
30 if(port == 0)
31 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataSet");
32 if(port == 1)
33 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPointSet");
34
35 return 1;
36}
37
39 vtkInformation *info) {
40 if(port == 0)
41 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
42
43 return 1;
44}
45
46template <typename triangulationType>
48 vtkDataSet *input,
49 const triangulationType *triangulation,
50 const std::vector<
52 &integralLines,
53#ifdef TTK_ENABLE_MPI
54 const std::vector<ttk::SimplexId> &globalVertexId,
55 const std::vector<ttk::SimplexId> &globalCellId,
56#endif
57 vtkUnstructuredGrid *output) {
58 if(input == nullptr || output == nullptr
59 || input->GetPointData() == nullptr) {
60 this->printErr("Null pointers in getTrajectories parameters");
61 return 0;
62 }
63
64 vtkNew<vtkUnstructuredGrid> ug{};
65 vtkNew<vtkPoints> pts{};
66 vtkNew<vtkDoubleArray> dist{};
67 vtkNew<vtkIdTypeArray> identifier{};
68#ifdef TTK_ENABLE_MPI
69 vtkNew<vtkIdTypeArray> vtkEdgeIdentifiers{};
70 vtkNew<vtkIdTypeArray> vtkVertexGlobalIdArray{};
71 vtkNew<vtkIntArray> vtkVertexRankArray{};
72 vtkNew<vtkIntArray> vtkEdgeRankArray{};
73#endif
74 vtkNew<vtkIdTypeArray> vtkForkIdentifiers{};
75 vtkNew<vtkUnsignedCharArray> outputMaskField{};
76
77 outputMaskField->SetNumberOfComponents(1);
78 outputMaskField->SetName(ttk::MaskScalarFieldName);
79
80 dist->SetNumberOfComponents(1);
81 dist->SetName("DistanceFromSeed");
82 identifier->SetNumberOfComponents(1);
83 identifier->SetName("SeedIdentifier");
84 vtkForkIdentifiers->SetNumberOfComponents(1);
85 vtkForkIdentifiers->SetName("ForkIdentifiers");
86
87#ifdef TTK_ENABLE_MPI
88 vtkVertexGlobalIdArray->SetNumberOfComponents(1);
89 vtkVertexGlobalIdArray->SetName("GlobalPointIds");
90 vtkEdgeIdentifiers->SetNumberOfComponents(1);
91 vtkEdgeIdentifiers->SetName("GlobalCellIds");
92 vtkEdgeRankArray->SetNumberOfComponents(1);
93 vtkEdgeRankArray->SetName("RankArray");
94 vtkVertexRankArray->SetNumberOfComponents(1);
95 vtkVertexRankArray->SetName("RankArray");
96#endif
97 const auto numberOfArrays = input->GetPointData()->GetNumberOfArrays();
98
99 std::vector<vtkDataArray *> scalarArrays{};
100 scalarArrays.reserve(numberOfArrays);
101 for(int k = 0; k < numberOfArrays; ++k) {
102 const auto a = input->GetPointData()->GetArray(k);
103 if(a->GetNumberOfComponents() == 1) {
104 // only keep scalar arrays
105 scalarArrays.push_back(a);
106 }
107 }
108
109 std::vector<vtkSmartPointer<vtkDataArray>> inputScalars(scalarArrays.size());
110 for(size_t k = 0; k < scalarArrays.size(); ++k) {
111 inputScalars[k]
112 = vtkSmartPointer<vtkDataArray>::Take(scalarArrays[k]->NewInstance());
113 inputScalars[k]->SetNumberOfComponents(1);
114 inputScalars[k]->SetName(scalarArrays[k]->GetName());
115 }
116 std::array<float, 3> p;
117 std::array<vtkIdType, 2> ids;
118#ifdef TTK_ENABLE_MPI
119 ttk::SimplexId vertexCounter = 0;
120 ttk::SimplexId edgeCounter = 0;
121#endif
122 for(int thread = 0; thread < threadNumber_; thread++) {
123 auto integralLine = integralLines[thread].list_.begin();
124 while(integralLine != integralLines[thread].list_.end()) {
125 for(int i = 0; i < INTEGRAL_LINE_TABULAR_SIZE; i++) {
126 if(integralLine->at(i).trajectory.size() > 0) {
127 ttk::SimplexId vertex = integralLine->at(i).trajectory.at(0);
128 triangulation->getVertexPoint(vertex, p[0], p[1], p[2]);
129 ids[0] = pts->InsertNextPoint(p.data());
130 // distanceScalars
131 dist->InsertNextTuple1(integralLine->at(i).distanceFromSeed.at(0));
132#ifdef TTK_ENABLE_MPI
133 outputMaskField->InsertNextTuple1(0);
134 vtkVertexGlobalIdArray->InsertNextTuple1(
135 globalVertexId.at(vertexCounter));
136 vertexCounter++;
137 vtkVertexRankArray->InsertNextTuple1(
138 triangulation->getVertexRank(vertex));
139#else
140 outputMaskField->InsertNextTuple1(0);
141#endif
142 identifier->InsertNextTuple1(integralLine->at(i).seedIdentifier);
143 vtkForkIdentifiers->InsertNextTuple1(
144 integralLine->at(i).forkIdentifier);
145 // inputScalars
146 for(size_t k = 0; k < scalarArrays.size(); ++k) {
147 inputScalars[k]->InsertNextTuple1(
148 scalarArrays[k]->GetTuple1(vertex));
149 }
150 for(size_t j = 1; j < integralLine->at(i).trajectory.size(); ++j) {
151 vertex = integralLine->at(i).trajectory.at(j);
152#ifdef TTK_ENABLE_MPI
153 vtkVertexGlobalIdArray->InsertNextTuple1(
154 globalVertexId.at(vertexCounter));
155 vertexCounter++;
156 vtkEdgeIdentifiers->InsertNextTuple1(globalCellId.at(edgeCounter));
157 edgeCounter++;
158 vtkEdgeRankArray->InsertNextTuple1(triangulation->getVertexRank(
159 integralLine->at(i).trajectory.at(j - 1)));
160 vtkVertexRankArray->InsertNextTuple1(
161 triangulation->getVertexRank(vertex));
162#endif
163 outputMaskField->InsertNextTuple1(1);
164 vtkForkIdentifiers->InsertNextTuple1(
165 integralLine->at(i).forkIdentifier);
166 triangulation->getVertexPoint(vertex, p[0], p[1], p[2]);
167 ids[1] = pts->InsertNextPoint(p.data());
168 // distanceScalars
169 dist->InsertNextTuple1(integralLine->at(i).distanceFromSeed.at(j));
170 identifier->InsertNextTuple1(integralLine->at(i).seedIdentifier);
171 // inputScalars
172 for(unsigned int k = 0; k < scalarArrays.size(); ++k)
173 inputScalars[k]->InsertNextTuple1(
174 scalarArrays[k]->GetTuple1(vertex));
175 ug->InsertNextCell(VTK_LINE, 2, ids.data());
176 // iteration
177 ids[0] = ids[1];
178 }
179 outputMaskField->SetTuple1(
180 outputMaskField->GetNumberOfTuples() - 1, 0);
181 } else {
182 break;
183 }
184 }
185 integralLine++;
186 }
187 }
188
189 ug->SetPoints(pts);
190 ug->GetPointData()->AddArray(dist);
191 ug->GetPointData()->AddArray(identifier);
192 ug->GetPointData()->AddArray(vtkForkIdentifiers);
193 ug->GetPointData()->AddArray(outputMaskField);
194
195 for(unsigned int k = 0; k < scalarArrays.size(); ++k) {
196 ug->GetPointData()->AddArray(inputScalars[k]);
197 }
198#ifdef TTK_ENABLE_MPI
199 ug->GetPointData()->AddArray(vtkVertexRankArray);
200 ug->GetCellData()->AddArray(vtkEdgeRankArray);
201 ug->GetCellData()->SetGlobalIds(vtkEdgeIdentifiers);
202 ug->GetPointData()->SetGlobalIds(vtkVertexGlobalIdArray);
203#endif
204 output->ShallowCopy(ug);
205
206 return 1;
207}
208
209int ttkIntegralLines::RequestData(vtkInformation *ttkNotUsed(request),
210 vtkInformationVector **inputVector,
211 vtkInformationVector *outputVector) {
212
213 vtkDataSet *domain = vtkDataSet::GetData(inputVector[0], 0);
214 vtkPointSet *seeds = vtkPointSet::GetData(inputVector[1], 0);
215 vtkUnstructuredGrid *output = vtkUnstructuredGrid::GetData(outputVector, 0);
216
217 ttk::Triangulation *triangulation = ttkAlgorithm::GetTriangulation(domain);
218 vtkDataArray *inputScalars = this->GetInputArrayToProcess(0, domain);
219
220 int keepGoing = checkEmptyMPIInput<ttk::Triangulation>(triangulation);
221 if(keepGoing < 2) {
222 return keepGoing;
223 }
224 vtkDataArray *inputOffsets
225 = this->GetOrderArray(domain, 0, 1, ForceInputOffsetScalarField);
226
227 const ttk::SimplexId numberOfPointsInDomain = domain->GetNumberOfPoints();
228 this->setVertexNumber(numberOfPointsInDomain);
229 int numberOfPointsInSeeds = seeds->GetNumberOfPoints();
230#ifndef TTK_ENABLE_KAMIKAZE
231 int totalSeeds;
232#else
233#ifdef TTK_ENABLE_MPI
234 int totalSeeds;
235#endif
236#endif
237
238#ifdef TTK_ENABLE_MPI_TIME
239 ttk::Timer t_mpi;
240 ttk::startMPITimer(t_mpi, ttk::MPIrank_, ttk::MPIsize_);
241#endif
242#ifdef TTK_ENABLE_MPI
243 // Necessary when using MPI
244 std::vector<ttk::SimplexId> inputIdentifiers{};
245 if(ttk::MPIsize_ > 1) {
246 MPI_Reduce(&numberOfPointsInSeeds, &totalSeeds, 1, MPI_INTEGER, MPI_SUM, 0,
247 ttk::MPIcomm_);
248 int isDistributed;
249
250 if(ttk::MPIrank_ == 0) {
251 isDistributed = numberOfPointsInSeeds != totalSeeds;
252 }
253 MPI_Bcast(&isDistributed, 1, MPI_INTEGER, 0, ttk::MPIcomm_);
254 MPI_Bcast(&totalSeeds, 1, MPI_INTEGER, 0, ttk::MPIcomm_);
255
256 if(!isDistributed) {
257 this->setGlobalElementCounter(totalSeeds);
258 vtkDataArray *globalSeedsId;
259 if(ttk::MPIrank_ == 0) {
260 globalSeedsId = seeds->GetPointData()->GetArray("GlobalPointIds");
261 } else {
262 globalSeedsId = vtkDataArray::CreateDataArray(VTK_ID_TYPE);
263 }
264
265 if(ttk::MPIrank_ != 0) {
266 globalSeedsId->SetNumberOfComponents(1);
267 globalSeedsId->SetNumberOfTuples(totalSeeds);
268 }
269 ttk::LongSimplexId id = 0;
270 MPI_Bcast(ttkUtils::GetPointer<ttk::LongSimplexId>(globalSeedsId),
271 totalSeeds, ttk::getMPIType(id), 0, ttk::MPIcomm_);
272 ttk::SimplexId localId = -1;
273 for(int i = 0; i < totalSeeds; i++) {
274 localId = triangulation->getVertexLocalId(globalSeedsId->GetTuple1(i));
275
276 if(localId != -1
277 && triangulation->getVertexRank(localId) == ttk::MPIrank_) {
278 inputIdentifiers.push_back(localId);
279 }
280 }
281 numberOfPointsInSeeds = inputIdentifiers.size();
282 } else {
283 std::vector<ttk::SimplexId> idSpareStorage{};
284 ttk::SimplexId *inputIdentifierGlobalId;
285 inputIdentifierGlobalId = this->GetIdentifierArrayPtr(
286 ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds,
287 idSpareStorage);
288 ttk::SimplexId localId = 0;
289 for(int i = 0; i < numberOfPointsInSeeds; i++) {
290 localId = triangulation->getVertexLocalId(inputIdentifierGlobalId[i]);
291 if(localId != -1) {
292 inputIdentifiers.push_back(localId);
293 }
294 }
295 numberOfPointsInSeeds = inputIdentifiers.size();
296 MPI_Allreduce(&numberOfPointsInSeeds, &totalSeeds, 1, MPI_INTEGER,
297 MPI_SUM, ttk::MPIcomm_);
298 this->setGlobalElementCounter(totalSeeds);
299 }
300 } else {
301 this->setGlobalElementCounter(numberOfPointsInSeeds);
302 inputIdentifiers.resize(numberOfPointsInSeeds);
303 totalSeeds = numberOfPointsInSeeds;
304 std::vector<ttk::SimplexId> idSpareStorage{};
305 ttk::SimplexId *inputIdentifierGlobalId;
306 inputIdentifierGlobalId = this->GetIdentifierArrayPtr(
307 ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds,
308 idSpareStorage);
309 for(int i = 0; i < numberOfPointsInSeeds; i++) {
310 inputIdentifiers.at(i)
311 = triangulation->getVertexLocalId(inputIdentifierGlobalId[i]);
312 }
313 }
314#else
315 std::vector<ttk::SimplexId> idSpareStorage{};
316 ttk::SimplexId *identifiers = this->GetIdentifierArrayPtr(
317 ForceInputVertexScalarField, 2, ttk::VertexScalarFieldName, seeds,
318 idSpareStorage);
319 std::unordered_set<ttk::SimplexId> isSeed;
320 for(ttk::SimplexId k = 0; k < numberOfPointsInSeeds; ++k) {
321 isSeed.insert(identifiers[k]);
322 }
323 std::vector<ttk::SimplexId> inputIdentifiers(isSeed.begin(), isSeed.end());
324#ifndef TTK_ENABLE_KAMIKAZE
325 totalSeeds = inputIdentifiers.size();
326#endif
327 isSeed.clear();
328#endif
329
330 std::vector<
332 integralLines(
335
336 this->setVertexNumber(numberOfPointsInDomain);
337 this->setSeedNumber(numberOfPointsInSeeds);
338 this->setDirection(Direction);
339 this->setInputScalarField(inputScalars->GetVoidPointer(0));
340 this->setInputOffsets(ttkUtils::GetPointer<ttk::SimplexId>(inputOffsets));
341 this->setVertexIdentifierScalarField(&inputIdentifiers);
342 this->setOutputIntegralLines(&integralLines);
343 this->preconditionTriangulation(triangulation);
344 this->setChunkSize(
345 std::max(std::max(std::min(1000, (int)numberOfPointsInSeeds),
346 (int)numberOfPointsInSeeds / (threadNumber_ * 100)),
347 1));
348#ifdef TTK_ENABLE_MPI
349 std::vector<std::vector<std::vector<ttk::intgl::ElementToBeSent>>> toSend(
351 this->setNeighbors(triangulation->getNeighborRanks());
352 if(ttk::MPIsize_ > 1) {
353 toSend.resize(this->neighborNumber_);
354 for(int i = 0; i < this->neighborNumber_; i++) {
355 toSend[i].resize(this->threadNumber_);
356 for(int j = 0; j < this->threadNumber_; j++) {
357 toSend[i][j].reserve((int)numberOfPointsInSeeds * 0.005
358 / this->threadNumber_);
359 }
360 }
361 }
362 this->setToSend(&toSend);
363 this->createMessageType();
364#endif
365#ifdef TTK_ENABLE_MPI_TIME
366 double elapsedTime = ttk::endMPITimer(t_mpi, ttk::MPIrank_, ttk::MPIsize_);
367 if(ttk::MPIrank_ == 0) {
368 printMsg("Preparation performed using " + std::to_string(ttk::MPIsize_)
369 + " MPI processes lasted :" + std::to_string(elapsedTime));
370 }
371#endif
372#ifndef TTK_ENABLE_KAMIKAZE
373 // field problem
374 if(!inputScalars) {
375 this->printErr("wrong scalar field.");
376 return -1;
377 }
378 // field problem
379 if(inputOffsets->GetDataType() != VTK_INT
380 and inputOffsets->GetDataType() != VTK_ID_TYPE) {
381 this->printErr("input offset field type not supported.");
382 return -1;
383 }
384
385 // no points.
386 if(numberOfPointsInDomain <= 0) {
387 this->printErr("domain has no points.");
388 return -1;
389 }
390 // no points.
391 if(totalSeeds <= 0) {
392 this->printErr("seeds have no points.");
393 return -1;
394 }
395#endif
396#ifdef TTK_ENABLE_MPI_TIME
397 ttk::startMPITimer(t_mpi, ttk::MPIrank_, ttk::MPIsize_);
398#endif
399 int status = 0;
400 ttkTemplateMacro(triangulation->getType(),
401 (status = this->execute<TTK_TT>(
402 static_cast<TTK_TT *>(triangulation->getData()))));
403
404#ifndef TTK_ENABLE_KAMIKAZE
405 // something wrong in baseCode
406 if(status != 0) {
407 this->printErr("IntegralLines.execute() error code : "
408 + std::to_string(status));
409 return 0;
410 }
411#endif
412#ifdef TTK_ENABLE_MPI
413 std::vector<ttk::SimplexId> globalVertexId;
414 std::vector<ttk::SimplexId> globalCellId;
415 ttkTemplateMacro(triangulation->getType(),
416 (getGlobalIdentifiers<TTK_TT>(
417 globalVertexId, globalCellId, integralLines,
418 static_cast<TTK_TT *>(triangulation->getData()))));
419#ifdef TTK_ENABLE_MPI_TIME
420 elapsedTime = ttk::endMPITimer(t_mpi, ttk::MPIrank_, ttk::MPIsize_);
421 if(ttk::MPIrank_ == 0) {
422 printMsg("Computation performed using " + std::to_string(ttk::MPIsize_)
423 + " MPI processes lasted :" + std::to_string(elapsedTime));
424 }
425#endif
426#endif
427 // make the vtk trajectories
428#ifdef TTK_ENABLE_MPI
429 ttkTemplateMacro(triangulation->getType(),
430 (getTrajectories<TTK_TT>(
431 domain, static_cast<TTK_TT *>(triangulation->getData()),
432 integralLines, globalVertexId, globalCellId, output)));
433#else
434 ttkTemplateMacro(triangulation->getType(),
435 (getTrajectories<TTK_TT>(
436 domain, static_cast<TTK_TT *>(triangulation->getData()),
437 integralLines, output)));
438#endif
439
440 return (int)(status == 0);
441}
#define ttkTemplateMacro(triangulationType, call)
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition: BaseClass.h:47
#define INTEGRAL_LINE_TABULAR_SIZE
Definition: IntegralLines.h:31
ttk::SimplexId * GetIdentifierArrayPtr(const bool &enforceArrayIndex, const int &arrayIndex, const std::string &arrayName, vtkDataSet *const inputData, std::vector< ttk::SimplexId > &spareStorage, const int inputPort=0, const bool printErr=true)
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
TTK VTK-filter for the computation of edge-based integral lines of the gradient of an input scalar fi...
int getTrajectories(vtkDataSet *input, const triangulationType *triangulation, const std::vector< ttk::ArrayLinkedList< ttk::intgl::IntegralLine, INTEGRAL_LINE_TABULAR_SIZE > > &integralLines, vtkUnstructuredGrid *output)
int FillOutputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillInputPortInformation(int port, vtkInformation *info) override
~ttkIntegralLines() override
This class describes a dynamic size data structure for thread safe computation. It is a linked list o...
int threadNumber_
Definition: BaseClass.h:95
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:149
void setInputOffsets(const SimplexId *const data)
void setDirection(int direction)
void setInputScalarField(void *data)
void setChunkSize(int size)
int preconditionTriangulation(ttk::AbstractTriangulation *triangulation)
void setVertexNumber(const SimplexId &vertexNumber)
void setOutputIntegralLines(std::vector< ttk::ArrayLinkedList< ttk::intgl::IntegralLine, INTEGRAL_LINE_TABULAR_SIZE > > *integralLines)
void setVertexIdentifierScalarField(std::vector< SimplexId > *const data)
void setSeedNumber(const SimplexId &seedNumber)
Triangulation is a class that provides time and memory efficient traversal methods on triangulations ...
Definition: Triangulation.h:48
AbstractTriangulation * getData()
Triangulation::Type getType() const
COMMON_EXPORTS int MPIsize_
Definition: BaseClass.cpp:10
COMMON_EXPORTS int MPIrank_
Definition: BaseClass.cpp:9
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition: DataTypes.h:35
long long int LongSimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:15
const char MaskScalarFieldName[]
default name for mask scalar field
Definition: DataTypes.h:32
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22
Struct containing the data of an integral line. trajectories: vector of identifiers of each vertex th...
Definition: IntegralLines.h:49
vtkStandardNewMacro(ttkIntegralLines)