1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkStreamTracer.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkStreamTracer.h"
16
17 #include "vtkAMRInterpolatedVelocityField.h"
18 #include "vtkAbstractInterpolatedVelocityField.h"
19 #include "vtkCellArray.h"
20 #include "vtkCellData.h"
21 #include "vtkCellLocatorInterpolatedVelocityField.h"
22 #include "vtkCompositeDataIterator.h"
23 #include "vtkCompositeDataPipeline.h"
24 #include "vtkCompositeDataSet.h"
25 #include "vtkDataSetAttributes.h"
26 #include "vtkDoubleArray.h"
27 #include "vtkExecutive.h"
28 #include "vtkGenericCell.h"
29 #include "vtkIdList.h"
30 #include "vtkInformation.h"
31 #include "vtkInformationVector.h"
32 #include "vtkIntArray.h"
33 #include "vtkInterpolatedVelocityField.h"
34 #include "vtkMath.h"
35 #include "vtkMultiBlockDataSet.h"
36 #include "vtkNew.h"
37 #include "vtkObjectFactory.h"
38 #include "vtkOverlappingAMR.h"
39 #include "vtkPointData.h"
40 #include "vtkPointSet.h"
41 #include "vtkPolyData.h"
42 #include "vtkPolyLine.h"
43 #include "vtkRungeKutta2.h"
44 #include "vtkRungeKutta4.h"
45 #include "vtkRungeKutta45.h"
46 #include "vtkSmartPointer.h"
47 #include "vtkStaticCellLocator.h"
48
49 #include <vector>
50
51 vtkObjectFactoryNewMacro(vtkStreamTracer);
52 vtkCxxSetObjectMacro(vtkStreamTracer, Integrator, vtkInitialValueProblemSolver);
53 vtkCxxSetObjectMacro(vtkStreamTracer, InterpolatorPrototype, vtkAbstractInterpolatedVelocityField);
54
55 const double vtkStreamTracer::EPSILON = 1.0E-12;
56
57 namespace
58 {
59 // special function to interpolate the point data from the input to the output
60 // if fast == true, then it just calls the usual InterpolatePoint function,
61 // otherwise,
62 // it makes sure the array exists in the input before trying to copy it to the
63 // output. if it doesn't exist in the input but is in the output then we
64 // remove it from the output instead of having bad values there.
65 // this is meant for multiblock data sets where the grids may not have the
66 // same point data arrays or have them in different orders.
InterpolatePoint(vtkDataSetAttributes * outPointData,vtkDataSetAttributes * inPointData,vtkIdType toId,vtkIdList * ids,double * weights,bool fast)67 void InterpolatePoint(vtkDataSetAttributes* outPointData, vtkDataSetAttributes* inPointData,
68 vtkIdType toId, vtkIdList* ids, double* weights, bool fast)
69 {
70 if (fast)
71 {
72 outPointData->InterpolatePoint(inPointData, toId, ids, weights);
73 }
74 else
75 {
76 for (int i = outPointData->GetNumberOfArrays() - 1; i >= 0; i--)
77 {
78 vtkAbstractArray* toArray = outPointData->GetAbstractArray(i);
79 if (vtkAbstractArray* fromArray = inPointData->GetAbstractArray(toArray->GetName()))
80 {
81 toArray->InterpolateTuple(toId, ids, fromArray, weights);
82 }
83 else
84 {
85 outPointData->RemoveArray(toArray->GetName());
86 }
87 }
88 }
89 }
90
91 }
92
93 //------------------------------------------------------------------------------
vtkStreamTracer()94 vtkStreamTracer::vtkStreamTracer()
95 {
96 this->Integrator = vtkRungeKutta2::New();
97 this->IntegrationDirection = FORWARD;
98 for (int i = 0; i < 3; i++)
99 {
100 this->StartPosition[i] = 0.0;
101 }
102
103 this->MaximumPropagation = 1.0;
104 this->IntegrationStepUnit = CELL_LENGTH_UNIT;
105 this->InitialIntegrationStep = 0.5;
106 this->MinimumIntegrationStep = 1.0E-2;
107 this->MaximumIntegrationStep = 1.0;
108
109 this->MaximumError = 1.0e-6;
110 this->MaximumNumberOfSteps = 2000;
111 this->TerminalSpeed = EPSILON;
112
113 this->ComputeVorticity = true;
114 this->RotationScale = 1.0;
115
116 this->LastUsedStepSize = 0.0;
117
118 this->GenerateNormalsInIntegrate = true;
119
120 this->InterpolatorPrototype = nullptr;
121
122 this->SetNumberOfInputPorts(2);
123
124 // by default process active point vectors
125 this->SetInputArrayToProcess(
126 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::VECTORS);
127
128 this->HasMatchingPointAttributes = true;
129
130 this->SurfaceStreamlines = false;
131 }
132
133 //------------------------------------------------------------------------------
~vtkStreamTracer()134 vtkStreamTracer::~vtkStreamTracer()
135 {
136 this->SetIntegrator(nullptr);
137 this->SetInterpolatorPrototype(nullptr);
138 }
139
140 //------------------------------------------------------------------------------
SetSourceConnection(vtkAlgorithmOutput * algOutput)141 void vtkStreamTracer::SetSourceConnection(vtkAlgorithmOutput* algOutput)
142 {
143 this->SetInputConnection(1, algOutput);
144 }
145
146 //------------------------------------------------------------------------------
SetSourceData(vtkDataSet * source)147 void vtkStreamTracer::SetSourceData(vtkDataSet* source)
148 {
149 this->SetInputData(1, source);
150 }
151
152 //------------------------------------------------------------------------------
GetSource()153 vtkDataSet* vtkStreamTracer::GetSource()
154 {
155 if (this->GetNumberOfInputConnections(1) < 1)
156 {
157 return nullptr;
158 }
159 return vtkDataSet::SafeDownCast(this->GetExecutive()->GetInputData(1, 0));
160 }
161
162 //------------------------------------------------------------------------------
GetIntegratorType()163 int vtkStreamTracer::GetIntegratorType()
164 {
165 if (!this->Integrator)
166 {
167 return NONE;
168 }
169 if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta2"))
170 {
171 return RUNGE_KUTTA2;
172 }
173 if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta4"))
174 {
175 return RUNGE_KUTTA4;
176 }
177 if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta45"))
178 {
179 return RUNGE_KUTTA45;
180 }
181 return UNKNOWN;
182 }
183
184 //------------------------------------------------------------------------------
SetInterpolatorTypeToDataSetPointLocator()185 void vtkStreamTracer::SetInterpolatorTypeToDataSetPointLocator()
186 {
187 this->SetInterpolatorType(static_cast<int>(INTERPOLATOR_WITH_DATASET_POINT_LOCATOR));
188 }
189
190 //------------------------------------------------------------------------------
SetInterpolatorTypeToCellLocator()191 void vtkStreamTracer::SetInterpolatorTypeToCellLocator()
192 {
193 this->SetInterpolatorType(static_cast<int>(INTERPOLATOR_WITH_CELL_LOCATOR));
194 }
195
196 //------------------------------------------------------------------------------
SetInterpolatorType(int interpType)197 void vtkStreamTracer::SetInterpolatorType(int interpType)
198 {
199 if (interpType == INTERPOLATOR_WITH_CELL_LOCATOR)
200 {
201 // create an interpolator equipped with a cell locator
202 vtkNew<vtkCellLocatorInterpolatedVelocityField> cellLoc;
203
204 // specify the type of the cell locator attached to the interpolator
205 constexpr double tolerance = 1e-6;
206 vtkNew<vtkStaticCellLocator> cellLocType;
207 cellLocType->SetTolerance(tolerance);
208 cellLocType->UseDiagonalLengthToleranceOn();
209 cellLoc->SetCellLocatorPrototype(cellLocType);
210
211 this->SetInterpolatorPrototype(cellLoc);
212 }
213 else
214 {
215 // create an interpolator equipped with a point locator (by default)
216 vtkSmartPointer<vtkInterpolatedVelocityField> pntLoc =
217 vtkSmartPointer<vtkInterpolatedVelocityField>::New();
218 this->SetInterpolatorPrototype(pntLoc);
219 }
220 }
221
222 //------------------------------------------------------------------------------
SetIntegratorType(int type)223 void vtkStreamTracer::SetIntegratorType(int type)
224 {
225 vtkInitialValueProblemSolver* ivp = nullptr;
226 switch (type)
227 {
228 case RUNGE_KUTTA2:
229 ivp = vtkRungeKutta2::New();
230 break;
231 case RUNGE_KUTTA4:
232 ivp = vtkRungeKutta4::New();
233 break;
234 case RUNGE_KUTTA45:
235 ivp = vtkRungeKutta45::New();
236 break;
237 default:
238 vtkWarningMacro("Unrecognized integrator type. Keeping old one.");
239 break;
240 }
241 if (ivp)
242 {
243 this->SetIntegrator(ivp);
244 ivp->Delete();
245 }
246 }
247
248 //------------------------------------------------------------------------------
SetIntegrationStepUnit(int unit)249 void vtkStreamTracer::SetIntegrationStepUnit(int unit)
250 {
251 if (unit != LENGTH_UNIT && unit != CELL_LENGTH_UNIT)
252 {
253 unit = CELL_LENGTH_UNIT;
254 }
255
256 if (unit == this->IntegrationStepUnit)
257 {
258 return;
259 }
260
261 this->IntegrationStepUnit = unit;
262 this->Modified();
263 }
264
265 //------------------------------------------------------------------------------
ConvertToLength(double interval,int unit,double cellLength)266 double vtkStreamTracer::ConvertToLength(double interval, int unit, double cellLength)
267 {
268 double retVal = 0.0;
269 if (unit == LENGTH_UNIT)
270 {
271 retVal = interval;
272 }
273 else if (unit == CELL_LENGTH_UNIT)
274 {
275 retVal = interval * cellLength;
276 }
277 return retVal;
278 }
279
280 //------------------------------------------------------------------------------
ConvertToLength(vtkStreamTracer::IntervalInformation & interval,double cellLength)281 double vtkStreamTracer::ConvertToLength(
282 vtkStreamTracer::IntervalInformation& interval, double cellLength)
283 {
284 return ConvertToLength(interval.Interval, interval.Unit, cellLength);
285 }
286
287 //------------------------------------------------------------------------------
ConvertIntervals(double & step,double & minStep,double & maxStep,int direction,double cellLength)288 void vtkStreamTracer::ConvertIntervals(
289 double& step, double& minStep, double& maxStep, int direction, double cellLength)
290 {
291 minStep = maxStep = step = direction *
292 this->ConvertToLength(this->InitialIntegrationStep, this->IntegrationStepUnit, cellLength);
293
294 if (this->MinimumIntegrationStep > 0.0)
295 {
296 minStep =
297 this->ConvertToLength(this->MinimumIntegrationStep, this->IntegrationStepUnit, cellLength);
298 }
299
300 if (this->MaximumIntegrationStep > 0.0)
301 {
302 maxStep =
303 this->ConvertToLength(this->MaximumIntegrationStep, this->IntegrationStepUnit, cellLength);
304 }
305 }
306
307 //------------------------------------------------------------------------------
CalculateVorticity(vtkGenericCell * cell,double pcoords[3],vtkDoubleArray * cellVectors,double vorticity[3])308 void vtkStreamTracer::CalculateVorticity(
309 vtkGenericCell* cell, double pcoords[3], vtkDoubleArray* cellVectors, double vorticity[3])
310 {
311 double* cellVel;
312 double derivs[9];
313
314 cellVel = cellVectors->GetPointer(0);
315 cell->Derivatives(0, pcoords, cellVel, 3, derivs);
316 vorticity[0] = derivs[7] - derivs[5];
317 vorticity[1] = derivs[2] - derivs[6];
318 vorticity[2] = derivs[3] - derivs[1];
319 }
320
321 //------------------------------------------------------------------------------
InitializeSeeds(vtkDataArray * & seeds,vtkIdList * & seedIds,vtkIntArray * & integrationDirections,vtkDataSet * source)322 void vtkStreamTracer::InitializeSeeds(vtkDataArray*& seeds, vtkIdList*& seedIds,
323 vtkIntArray*& integrationDirections, vtkDataSet* source)
324 {
325 seedIds = vtkIdList::New();
326 integrationDirections = vtkIntArray::New();
327 seeds = nullptr;
328
329 if (source)
330 {
331 vtkIdType numSeeds = source->GetNumberOfPoints();
332 if (numSeeds > 0)
333 {
334 // For now, one thread will do all
335
336 if (this->IntegrationDirection == BOTH)
337 {
338 seedIds->SetNumberOfIds(2 * numSeeds);
339 for (vtkIdType i = 0; i < numSeeds; ++i)
340 {
341 seedIds->SetId(i, i);
342 seedIds->SetId(numSeeds + i, i);
343 }
344 }
345 else
346 {
347 seedIds->SetNumberOfIds(numSeeds);
348 for (vtkIdType i = 0; i < numSeeds; ++i)
349 {
350 seedIds->SetId(i, i);
351 }
352 }
353 // Check if the source is a PointSet
354 vtkPointSet* seedPts = vtkPointSet::SafeDownCast(source);
355 if (seedPts)
356 {
357 // If it is, use it's points as source
358 vtkDataArray* orgSeeds = seedPts->GetPoints()->GetData();
359 seeds = orgSeeds->NewInstance();
360 seeds->DeepCopy(orgSeeds);
361 }
362 else
363 {
364 // Else, create a seed source
365 seeds = vtkDoubleArray::New();
366 seeds->SetNumberOfComponents(3);
367 seeds->SetNumberOfTuples(numSeeds);
368 for (vtkIdType i = 0; i < numSeeds; ++i)
369 {
370 seeds->SetTuple(i, source->GetPoint(i));
371 }
372 }
373 }
374 }
375 else
376 {
377 seeds = vtkDoubleArray::New();
378 seeds->SetNumberOfComponents(3);
379 seeds->InsertNextTuple(this->StartPosition);
380 seedIds->InsertNextId(0);
381 if (this->IntegrationDirection == BOTH)
382 {
383 seedIds->InsertNextId(0);
384 }
385 }
386
387 if (seeds)
388 {
389 vtkIdType i;
390 vtkIdType numSeeds = seeds->GetNumberOfTuples();
391 if (this->IntegrationDirection == BOTH)
392 {
393 for (i = 0; i < numSeeds; i++)
394 {
395 integrationDirections->InsertNextValue(FORWARD);
396 }
397 for (i = 0; i < numSeeds; i++)
398 {
399 integrationDirections->InsertNextValue(BACKWARD);
400 }
401 }
402 else
403 {
404 for (i = 0; i < numSeeds; i++)
405 {
406 integrationDirections->InsertNextValue(this->IntegrationDirection);
407 }
408 }
409 }
410 }
411
412 //------------------------------------------------------------------------------
SetupOutput(vtkInformation * inInfo,vtkInformation * outInfo)413 int vtkStreamTracer::SetupOutput(vtkInformation* inInfo, vtkInformation* outInfo)
414 {
415 if (!inInfo || !outInfo)
416 {
417 vtkErrorMacro("Input/Output informations are not set, aborting.");
418 return 0;
419 }
420
421 int piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
422 int numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
423
424 vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
425 vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT());
426
427 // Pass through field data
428 output->GetFieldData()->PassData(input->GetFieldData());
429
430 vtkCompositeDataSet* hdInput = vtkCompositeDataSet::SafeDownCast(input);
431 vtkDataSet* dsInput = vtkDataSet::SafeDownCast(input);
432 if (hdInput)
433 {
434 this->InputData = hdInput;
435 hdInput->Register(this);
436 return 1;
437 }
438 else if (dsInput)
439 {
440 vtkMultiBlockDataSet* mb = vtkMultiBlockDataSet::New();
441 mb->SetNumberOfBlocks(numPieces);
442 mb->SetBlock(piece, dsInput);
443 this->InputData = mb;
444 mb->Register(this);
445 mb->Delete();
446 return 1;
447 }
448 else
449 {
450 vtkErrorMacro(
451 "This filter cannot handle input of type: " << (input ? input->GetClassName() : "(none)"));
452 return 0;
453 }
454 }
455
456 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)457 int vtkStreamTracer::RequestData(vtkInformation* vtkNotUsed(request),
458 vtkInformationVector** inputVector, vtkInformationVector* outputVector)
459 {
460 vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
461 vtkInformation* outInfo = outputVector->GetInformationObject(0);
462
463 if (!this->SetupOutput(inInfo, outInfo))
464 {
465 return 0;
466 }
467
468 vtkInformation* sourceInfo = inputVector[1]->GetInformationObject(0);
469 vtkDataSet* source = nullptr;
470 if (sourceInfo)
471 {
472 source = vtkDataSet::SafeDownCast(sourceInfo->Get(vtkDataObject::DATA_OBJECT()));
473 }
474 vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
475
476 vtkDataArray* seeds = nullptr;
477 vtkIdList* seedIds = nullptr;
478 vtkIntArray* integrationDirections = nullptr;
479 this->InitializeSeeds(seeds, seedIds, integrationDirections, source);
480
481 if (seeds)
482 {
483 double lastPoint[3];
484 vtkAbstractInterpolatedVelocityField* func = nullptr;
485 int maxCellSize = 0;
486 if (this->CheckInputs(func, &maxCellSize) != VTK_OK)
487 {
488 vtkDebugMacro("No appropriate inputs have been found. Can not execute.");
489 if (func)
490 {
491 func->Delete();
492 }
493 seeds->Delete();
494 integrationDirections->Delete();
495 seedIds->Delete();
496 this->InputData->UnRegister(this);
497 return 1;
498 }
499
500 if (vtkOverlappingAMR::SafeDownCast(this->InputData))
501 {
502 vtkOverlappingAMR* amr = vtkOverlappingAMR::SafeDownCast(this->InputData);
503 amr->GenerateParentChildInformation();
504 }
505
506 vtkCompositeDataIterator* iter = this->InputData->NewIterator();
507 vtkSmartPointer<vtkCompositeDataIterator> iterP(iter);
508 iter->Delete();
509
510 iterP->GoToFirstItem();
511 vtkDataSet* input0 = nullptr;
512 if (!iterP->IsDoneWithTraversal() && !input0)
513 {
514 input0 = vtkDataSet::SafeDownCast(iterP->GetCurrentDataObject());
515 iterP->GoToNextItem();
516 }
517 int vecType(0);
518 vtkDataArray* vectors = this->GetInputArrayToProcess(0, input0, vecType);
519 if (vectors)
520 {
521 const char* vecName = vectors->GetName();
522 double propagation = 0;
523 vtkIdType numSteps = 0;
524 double integrationTime = 0;
525 this->Integrate(input0->GetPointData(), output, seeds, seedIds, integrationDirections,
526 lastPoint, func, maxCellSize, vecType, vecName, propagation, numSteps, integrationTime);
527 }
528 func->Delete();
529 seeds->Delete();
530 }
531
532 integrationDirections->Delete();
533 seedIds->Delete();
534
535 this->InputData->UnRegister(this);
536 return 1;
537 }
538
539 //------------------------------------------------------------------------------
CheckInputs(vtkAbstractInterpolatedVelocityField * & func,int * maxCellSize)540 int vtkStreamTracer::CheckInputs(vtkAbstractInterpolatedVelocityField*& func, int* maxCellSize)
541 {
542 if (!this->InputData)
543 {
544 return VTK_ERROR;
545 }
546
547 vtkOverlappingAMR* amrData = vtkOverlappingAMR::SafeDownCast(this->InputData);
548
549 vtkSmartPointer<vtkCompositeDataIterator> iter;
550 iter.TakeReference(this->InputData->NewIterator());
551
552 vtkDataSet* input0 = nullptr;
553 iter->GoToFirstItem();
554 while (!iter->IsDoneWithTraversal() && input0 == nullptr)
555 {
556 input0 = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject());
557 iter->GoToNextItem();
558 }
559 if (!input0)
560 {
561 return VTK_ERROR;
562 }
563
564 int vecType(0);
565 vtkDataArray* vectors = this->GetInputArrayToProcess(0, input0, vecType);
566 if (!vectors)
567 {
568 return VTK_ERROR;
569 }
570
571 // Set the function set to be integrated
572 if (!this->InterpolatorPrototype)
573 {
574 if (amrData)
575 {
576 func = vtkAMRInterpolatedVelocityField::New();
577 }
578 else
579 {
580 func = vtkInterpolatedVelocityField::New();
581 }
582 // turn on the following segment, in place of the above line, if an
583 // interpolator equipped with a cell locator is dedired as the default
584 //
585 // func = vtkCellLocatorInterpolatedVelocityField::New();
586 // vtkSmartPointer< vtkStaticCellLocator > locator =
587 // vtkSmartPointer< vtkStaticCellLocator >::New();
588 // vtkCellLocatorInterpolatedVelocityField::SafeDownCast( func )
589 // ->SetCellLocatorPrototype( locator );
590 }
591 else
592 {
593 if (amrData &&
594 vtkAMRInterpolatedVelocityField::SafeDownCast(this->InterpolatorPrototype) == nullptr)
595 {
596 this->InterpolatorPrototype = vtkAMRInterpolatedVelocityField::New();
597 }
598 func = this->InterpolatorPrototype->NewInstance();
599 func->CopyParameters(this->InterpolatorPrototype);
600 }
601
602 if (vtkAMRInterpolatedVelocityField::SafeDownCast(func))
603 {
604 assert(amrData);
605 vtkAMRInterpolatedVelocityField::SafeDownCast(func)->SetAMRData(amrData);
606 if (maxCellSize)
607 {
608 *maxCellSize = 8;
609 }
610 }
611 else if (vtkCompositeInterpolatedVelocityField::SafeDownCast(func))
612 {
613 iter->GoToFirstItem();
614 while (!iter->IsDoneWithTraversal())
615 {
616 vtkDataSet* inp = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject());
617 if (inp)
618 {
619 int cellSize = inp->GetMaxCellSize();
620 if (cellSize > *maxCellSize)
621 {
622 *maxCellSize = cellSize;
623 }
624 vtkCompositeInterpolatedVelocityField::SafeDownCast(func)->AddDataSet(inp);
625 }
626 iter->GoToNextItem();
627 }
628 }
629 else
630 {
631 assert(false);
632 }
633
634 const char* vecName = vectors->GetName();
635 func->SelectVectors(vecType, vecName);
636
637 // Check if the data attributes match, warn if not
638 vtkPointData* pd0 = input0->GetPointData();
639 int numPdArrays = pd0->GetNumberOfArrays();
640 this->HasMatchingPointAttributes = true;
641 for (iter->GoToFirstItem(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
642 {
643 vtkDataSet* data = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject());
644 vtkPointData* pd = data->GetPointData();
645 if (pd->GetNumberOfArrays() != numPdArrays)
646 {
647 this->HasMatchingPointAttributes = false;
648 }
649 for (int i = 0; i < numPdArrays; i++)
650 {
651 if (!pd->GetArray(pd0->GetArrayName(i)) || !pd0->GetArray(pd->GetArrayName(i)))
652 {
653 this->HasMatchingPointAttributes = false;
654 }
655 }
656 }
657 return VTK_OK;
658 }
659
660 //------------------------------------------------------------------------------
Integrate(vtkPointData * input0Data,vtkPolyData * output,vtkDataArray * seedSource,vtkIdList * seedIds,vtkIntArray * integrationDirections,double lastPoint[3],vtkAbstractInterpolatedVelocityField * func,int maxCellSize,int vecType,const char * vecName,double & inPropagation,vtkIdType & inNumSteps,double & inIntegrationTime)661 void vtkStreamTracer::Integrate(vtkPointData* input0Data, vtkPolyData* output,
662 vtkDataArray* seedSource, vtkIdList* seedIds, vtkIntArray* integrationDirections,
663 double lastPoint[3], vtkAbstractInterpolatedVelocityField* func, int maxCellSize, int vecType,
664 const char* vecName, double& inPropagation, vtkIdType& inNumSteps, double& inIntegrationTime)
665 {
666 vtkIdType numLines = seedIds->GetNumberOfIds();
667 double propagation = inPropagation;
668 vtkIdType numSteps = inNumSteps;
669 double integrationTime = inIntegrationTime;
670
671 // Useful pointers
672 vtkDataSetAttributes* outputPD = output->GetPointData();
673 vtkDataSetAttributes* outputCD = output->GetCellData();
674 vtkPointData* inputPD;
675 vtkDataSet* input;
676 vtkDataArray* inVectors;
677
678 int direction = 1;
679
680 if (this->GetIntegrator() == nullptr)
681 {
682 vtkErrorMacro("No integrator is specified.");
683 return;
684 }
685
686 double* weights = nullptr;
687 if (maxCellSize > 0)
688 {
689 weights = new double[maxCellSize];
690 }
691
692 // Used in GetCell()
693 vtkGenericCell* cell = vtkGenericCell::New();
694
695 // Create a new integrator, the type is the same as Integrator
696 vtkInitialValueProblemSolver* integrator = this->GetIntegrator()->NewInstance();
697 integrator->SetFunctionSet(func);
698
699 // Check Surface option
700 vtkInterpolatedVelocityField* surfaceFunc = nullptr;
701 if (this->SurfaceStreamlines == true)
702 {
703 surfaceFunc = vtkInterpolatedVelocityField::SafeDownCast(func);
704 if (surfaceFunc)
705 {
706 surfaceFunc->SetForceSurfaceTangentVector(true);
707 surfaceFunc->SetSurfaceDataset(true);
708 }
709 }
710
711 // Since we do not know what the total number of points
712 // will be, we do not allocate any. This is important for
713 // cases where a lot of streamers are used at once. If we
714 // were to allocate any points here, potentially, we can
715 // waste a lot of memory if a lot of streamers are used.
716 // Always insert the first point
717 vtkPoints* outputPoints = vtkPoints::New();
718 vtkCellArray* outputLines = vtkCellArray::New();
719
720 // We will keep track of integration time in this array
721 vtkDoubleArray* time = vtkDoubleArray::New();
722 time->SetName("IntegrationTime");
723
724 // This array explains why the integration stopped
725 vtkIntArray* retVals = vtkIntArray::New();
726 retVals->SetName("ReasonForTermination");
727
728 vtkIntArray* sids = vtkIntArray::New();
729 sids->SetName("SeedIds");
730
731 vtkSmartPointer<vtkDoubleArray> velocityVectors;
732 if (vecType != vtkDataObject::POINT)
733 {
734 velocityVectors = vtkSmartPointer<vtkDoubleArray>::New();
735 velocityVectors->SetName(vecName);
736 velocityVectors->SetNumberOfComponents(3);
737 }
738 vtkDoubleArray* cellVectors = nullptr;
739 vtkDoubleArray* vorticity = nullptr;
740 vtkDoubleArray* rotation = nullptr;
741 vtkDoubleArray* angularVel = nullptr;
742 if (this->ComputeVorticity)
743 {
744 cellVectors = vtkDoubleArray::New();
745 cellVectors->SetNumberOfComponents(3);
746 cellVectors->Allocate(3 * VTK_CELL_SIZE);
747
748 vorticity = vtkDoubleArray::New();
749 vorticity->SetName("Vorticity");
750 vorticity->SetNumberOfComponents(3);
751
752 rotation = vtkDoubleArray::New();
753 rotation->SetName("Rotation");
754
755 angularVel = vtkDoubleArray::New();
756 angularVel->SetName("AngularVelocity");
757 }
758
759 // We will interpolate all point attributes of the input on each point of
760 // the output (unless they are turned off). Note that we are using only
761 // the first input, if there are more than one, the attributes have to match.
762 //
763 // Note: We have to use a specific value (safe to employ the maximum number
764 // of steps) as the size of the initial memory allocation here. The
765 // use of the default argument might incur a crash problem (due to
766 // "insufficient memory") in the parallel mode. This is the case when
767 // a streamline intensely shuttles between two processes in an exactly
768 // interleaving fashion --- only one point is produced on each process
769 // (and actually two points, after point duplication, are saved to a
770 // vtkPolyData in vtkDistributedStreamTracer::NoBlockProcessTask) and
771 // as a consequence a large number of such small vtkPolyData objects
772 // are needed to represent a streamline, consuming up the memory before
773 // the intermediate memory is timely released.
774 outputPD->InterpolateAllocate(input0Data, this->MaximumNumberOfSteps);
775
776 vtkIdType numPtsTotal = 0;
777 double velocity[3];
778
779 int shouldAbort = 0;
780
781 for (int currentLine = 0; currentLine < numLines; currentLine++)
782 {
783 double progress = static_cast<double>(currentLine) / numLines;
784 this->UpdateProgress(progress);
785
786 switch (integrationDirections->GetValue(currentLine))
787 {
788 case FORWARD:
789 direction = 1;
790 break;
791 case BACKWARD:
792 direction = -1;
793 break;
794 }
795
796 // temporary variables used in the integration
797 double point1[3], point2[3], pcoords[3], vort[3], omega;
798 vtkIdType index, numPts = 0;
799
800 // Clear the last cell to avoid starting a search from
801 // the last point in the streamline
802 func->ClearLastCellId();
803
804 // Initial point
805 seedSource->GetTuple(seedIds->GetId(currentLine), point1);
806 memcpy(point2, point1, 3 * sizeof(double));
807 if (!func->FunctionValues(point1, velocity))
808 {
809 continue;
810 }
811
812 if (propagation >= this->MaximumPropagation || numSteps > this->MaximumNumberOfSteps)
813 {
814 continue;
815 }
816
817 numPts++;
818 numPtsTotal++;
819 vtkIdType nextPoint = outputPoints->InsertNextPoint(point1);
820 double lastInsertedPoint[3];
821 outputPoints->GetPoint(nextPoint, lastInsertedPoint);
822 time->InsertNextValue(integrationTime);
823
824 // We will always pass an arc-length step size to the integrator.
825 // If the user specifies a step size in cell length unit, we will
826 // have to convert it to arc length.
827 IntervalInformation stepSize; // either positive or negative
828 stepSize.Unit = LENGTH_UNIT;
829 stepSize.Interval = 0;
830 IntervalInformation aStep; // always positive
831 aStep.Unit = LENGTH_UNIT;
832 double step, minStep = 0, maxStep = 0;
833 double stepTaken;
834 double speed;
835 double cellLength;
836 int retVal = OUT_OF_LENGTH, tmp;
837
838 // Make sure we use the dataset found by the vtkAbstractInterpolatedVelocityField
839 input = func->GetLastDataSet();
840 inputPD = input->GetPointData();
841 inVectors = input->GetAttributesAsFieldData(vecType)->GetArray(vecName);
842 // Convert intervals to arc-length unit
843 input->GetCell(func->GetLastCellId(), cell);
844 cellLength = sqrt(static_cast<double>(cell->GetLength2()));
845 speed = vtkMath::Norm(velocity);
846 // Never call conversion methods if speed == 0
847 if (speed != 0.0)
848 {
849 this->ConvertIntervals(stepSize.Interval, minStep, maxStep, direction, cellLength);
850 }
851
852 // Interpolate all point attributes on first point
853 func->GetLastWeights(weights);
854 InterpolatePoint(
855 outputPD, inputPD, nextPoint, cell->PointIds, weights, this->HasMatchingPointAttributes);
856 // handle both point and cell velocity attributes.
857 vtkDataArray* outputVelocityVectors = outputPD->GetArray(vecName);
858 if (vecType != vtkDataObject::POINT)
859 {
860 velocityVectors->InsertNextTuple(velocity);
861 outputVelocityVectors = velocityVectors;
862 }
863
864 // Compute vorticity if required
865 // This can be used later for streamribbon generation.
866 if (this->ComputeVorticity)
867 {
868 if (vecType == vtkDataObject::POINT)
869 {
870 inVectors->GetTuples(cell->PointIds, cellVectors);
871 func->GetLastLocalCoordinates(pcoords);
872 vtkStreamTracer::CalculateVorticity(cell, pcoords, cellVectors, vort);
873 }
874 else
875 {
876 vort[0] = 0;
877 vort[1] = 0;
878 vort[2] = 0;
879 }
880 vorticity->InsertNextTuple(vort);
881 // rotation
882 // local rotation = vorticity . unit tangent ( i.e. velocity/speed )
883 if (speed != 0.0)
884 {
885 omega = vtkMath::Dot(vort, velocity);
886 omega /= speed;
887 omega *= this->RotationScale;
888 }
889 else
890 {
891 omega = 0.0;
892 }
893 angularVel->InsertNextValue(omega);
894 rotation->InsertNextValue(0.0);
895 }
896
897 double error = 0;
898
899 // Integrate until the maximum propagation length is reached,
900 // maximum number of steps is reached or until a boundary is encountered.
901 // Begin Integration
902 while (propagation < this->MaximumPropagation)
903 {
904
905 if (numSteps > this->MaximumNumberOfSteps)
906 {
907 retVal = OUT_OF_STEPS;
908 break;
909 }
910
911 bool endIntegration = false;
912 for (std::size_t i = 0; i < this->CustomTerminationCallback.size(); ++i)
913 {
914 if (this->CustomTerminationCallback[i](
915 this->CustomTerminationClientData[i], outputPoints, outputVelocityVectors, direction))
916 {
917 retVal = this->CustomReasonForTermination[i];
918 endIntegration = true;
919 break;
920 }
921 }
922 if (endIntegration)
923 {
924 break;
925 }
926
927 if (numSteps++ % 1000 == 1)
928 {
929 progress = (currentLine + propagation / this->MaximumPropagation) / numLines;
930 this->UpdateProgress(progress);
931
932 if (this->GetAbortExecute())
933 {
934 shouldAbort = 1;
935 break;
936 }
937 }
938
939 // Never call conversion methods if speed == 0
940 if ((speed == 0) || (speed <= this->TerminalSpeed))
941 {
942 retVal = STAGNATION;
943 break;
944 }
945
946 // If, with the next step, propagation will be larger than
947 // max, reduce it so that it is (approximately) equal to max.
948 aStep.Interval = fabs(stepSize.Interval);
949
950 if ((propagation + aStep.Interval) > this->MaximumPropagation)
951 {
952 aStep.Interval = this->MaximumPropagation - propagation;
953 if (stepSize.Interval >= 0)
954 {
955 stepSize.Interval = this->ConvertToLength(aStep, cellLength);
956 }
957 else
958 {
959 stepSize.Interval = this->ConvertToLength(aStep, cellLength) * (-1.0);
960 }
961 maxStep = stepSize.Interval;
962 }
963 this->LastUsedStepSize = stepSize.Interval;
964
965 // Calculate the next step using the integrator provided
966 // Break if the next point is out of bounds.
967 func->SetNormalizeVector(true);
968 tmp = integrator->ComputeNextStep(point1, point2, 0, stepSize.Interval, stepTaken, minStep,
969 maxStep, this->MaximumError, error);
970 func->SetNormalizeVector(false);
971 if (tmp != 0)
972 {
973 retVal = tmp;
974 memcpy(lastPoint, point2, 3 * sizeof(double));
975 break;
976 }
977
978 // This is the next starting point
979 if (this->SurfaceStreamlines && surfaceFunc != nullptr)
980 {
981 if (surfaceFunc->SnapPointOnCell(point2, point1) != 1)
982 {
983 retVal = OUT_OF_DOMAIN;
984 memcpy(lastPoint, point2, 3 * sizeof(double));
985 break;
986 }
987 }
988 else
989 {
990 for (int i = 0; i < 3; i++)
991 {
992 point1[i] = point2[i];
993 }
994 }
995
996 // Interpolate the velocity at the next point
997 if (!func->FunctionValues(point2, velocity))
998 {
999 retVal = OUT_OF_DOMAIN;
1000 memcpy(lastPoint, point2, 3 * sizeof(double));
1001 break;
1002 }
1003
1004 // It is not enough to use the starting point for stagnation calculation
1005 // Use average speed to check if it is below stagnation threshold
1006 double speed2 = vtkMath::Norm(velocity);
1007 if ((speed + speed2) / 2 <= this->TerminalSpeed)
1008 {
1009 retVal = STAGNATION;
1010 break;
1011 }
1012
1013 integrationTime += stepTaken / speed;
1014 // Calculate propagation (using the same units as MaximumPropagation
1015 propagation += fabs(stepSize.Interval);
1016
1017 // Make sure we use the dataset found by the vtkAbstractInterpolatedVelocityField
1018 input = func->GetLastDataSet();
1019 inputPD = input->GetPointData();
1020 inVectors = input->GetAttributesAsFieldData(vecType)->GetArray(vecName);
1021
1022 // Calculate cell length and speed to be used in unit conversions
1023 input->GetCell(func->GetLastCellId(), cell);
1024 cellLength = sqrt(static_cast<double>(cell->GetLength2()));
1025 speed = speed2;
1026
1027 // Check if conversion to float will produce a point in same place
1028 float convertedPoint[3];
1029 for (int i = 0; i < 3; i++)
1030 {
1031 convertedPoint[i] = point1[i];
1032 }
1033 if (lastInsertedPoint[0] != convertedPoint[0] || lastInsertedPoint[1] != convertedPoint[1] ||
1034 lastInsertedPoint[2] != convertedPoint[2])
1035 {
1036 // Point is valid. Insert it.
1037 numPts++;
1038 numPtsTotal++;
1039 nextPoint = outputPoints->InsertNextPoint(point1);
1040 outputPoints->GetPoint(nextPoint, lastInsertedPoint);
1041 time->InsertNextValue(integrationTime);
1042
1043 // Interpolate all point attributes on current point
1044 func->GetLastWeights(weights);
1045 InterpolatePoint(
1046 outputPD, inputPD, nextPoint, cell->PointIds, weights, this->HasMatchingPointAttributes);
1047
1048 if (vecType != vtkDataObject::POINT)
1049 {
1050 velocityVectors->InsertNextTuple(velocity);
1051 }
1052 // Compute vorticity if required
1053 // This can be used later for streamribbon generation.
1054 if (this->ComputeVorticity)
1055 {
1056 if (vecType == vtkDataObject::POINT)
1057 {
1058 inVectors->GetTuples(cell->PointIds, cellVectors);
1059 func->GetLastLocalCoordinates(pcoords);
1060 vtkStreamTracer::CalculateVorticity(cell, pcoords, cellVectors, vort);
1061 }
1062 else
1063 {
1064 vort[0] = 0;
1065 vort[1] = 0;
1066 vort[2] = 0;
1067 }
1068 vorticity->InsertNextTuple(vort);
1069 // rotation
1070 // angular velocity = vorticity . unit tangent ( i.e. velocity/speed )
1071 // rotation = sum ( angular velocity * stepSize )
1072 omega = vtkMath::Dot(vort, velocity);
1073 omega /= speed;
1074 omega *= this->RotationScale;
1075 index = angularVel->InsertNextValue(omega);
1076 rotation->InsertNextValue(rotation->GetValue(index - 1) +
1077 (angularVel->GetValue(index - 1) + omega) / 2 *
1078 (integrationTime - time->GetValue(index - 1)));
1079 }
1080 }
1081
1082 // Never call conversion methods if speed == 0
1083 if ((speed == 0) || (speed <= this->TerminalSpeed))
1084 {
1085 retVal = STAGNATION;
1086 break;
1087 }
1088
1089 // Convert all intervals to arc length
1090 this->ConvertIntervals(step, minStep, maxStep, direction, cellLength);
1091
1092 // If the solver is adaptive and the next step size (stepSize.Interval)
1093 // that the solver wants to use is smaller than minStep or larger
1094 // than maxStep, re-adjust it. This has to be done every step
1095 // because minStep and maxStep can change depending on the cell
1096 // size (unless it is specified in arc-length unit)
1097 if (integrator->IsAdaptive())
1098 {
1099 if (fabs(stepSize.Interval) < fabs(minStep))
1100 {
1101 stepSize.Interval = fabs(minStep) * stepSize.Interval / fabs(stepSize.Interval);
1102 }
1103 else if (fabs(stepSize.Interval) > fabs(maxStep))
1104 {
1105 stepSize.Interval = fabs(maxStep) * stepSize.Interval / fabs(stepSize.Interval);
1106 }
1107 }
1108 else
1109 {
1110 stepSize.Interval = step;
1111 }
1112 }
1113
1114 if (shouldAbort)
1115 {
1116 break;
1117 }
1118
1119 if (numPts > 1)
1120 {
1121 outputLines->InsertNextCell(numPts);
1122 for (int i = numPtsTotal - numPts; i < numPtsTotal; i++)
1123 {
1124 outputLines->InsertCellPoint(i);
1125 }
1126 retVals->InsertNextValue(retVal);
1127 sids->InsertNextValue(seedIds->GetId(currentLine));
1128 }
1129
1130 // Initialize these to 0 before starting the next line.
1131 // The values passed in the function call are only used
1132 // for the first line.
1133 inPropagation = propagation;
1134 inNumSteps = numSteps;
1135 inIntegrationTime = integrationTime;
1136
1137 propagation = 0;
1138 numSteps = 0;
1139 integrationTime = 0;
1140 }
1141
1142 if (!shouldAbort)
1143 {
1144 // Create the output polyline
1145 output->SetPoints(outputPoints);
1146 outputPD->AddArray(time);
1147 if (vecType != vtkDataObject::POINT)
1148 {
1149 outputPD->AddArray(velocityVectors);
1150 }
1151 if (vorticity)
1152 {
1153 outputPD->AddArray(vorticity);
1154 outputPD->AddArray(rotation);
1155 outputPD->AddArray(angularVel);
1156 }
1157
1158 vtkIdType numPts = outputPoints->GetNumberOfPoints();
1159 if (numPts > 1)
1160 {
1161 // Assign geometry and attributes
1162 output->SetLines(outputLines);
1163 if (this->GenerateNormalsInIntegrate)
1164 {
1165 this->GenerateNormals(output, nullptr, vecName);
1166 }
1167
1168 outputCD->AddArray(retVals);
1169 outputCD->AddArray(sids);
1170 }
1171 }
1172
1173 if (vorticity)
1174 {
1175 vorticity->Delete();
1176 rotation->Delete();
1177 angularVel->Delete();
1178 }
1179
1180 if (cellVectors)
1181 {
1182 cellVectors->Delete();
1183 }
1184 retVals->Delete();
1185 sids->Delete();
1186
1187 outputPoints->Delete();
1188 outputLines->Delete();
1189
1190 time->Delete();
1191
1192 integrator->Delete();
1193 cell->Delete();
1194
1195 delete[] weights;
1196
1197 output->Squeeze();
1198 }
1199
1200 //------------------------------------------------------------------------------
GenerateNormals(vtkPolyData * output,double * firstNormal,const char * vecName)1201 void vtkStreamTracer::GenerateNormals(vtkPolyData* output, double* firstNormal, const char* vecName)
1202 {
1203 // Useful pointers
1204 vtkDataSetAttributes* outputPD = output->GetPointData();
1205
1206 vtkPoints* outputPoints = output->GetPoints();
1207 vtkCellArray* outputLines = output->GetLines();
1208
1209 vtkDataArray* rotation = outputPD->GetArray("Rotation");
1210
1211 vtkIdType numPts = outputPoints->GetNumberOfPoints();
1212 if (numPts > 1)
1213 {
1214 if (this->ComputeVorticity)
1215 {
1216 vtkPolyLine* lineNormalGenerator = vtkPolyLine::New();
1217 vtkDoubleArray* normals = vtkDoubleArray::New();
1218 normals->SetNumberOfComponents(3);
1219 normals->SetNumberOfTuples(numPts);
1220 // Make sure the normals are initialized in case
1221 // GenerateSlidingNormals() fails and returns before
1222 // creating all normals
1223 for (vtkIdType idx = 0; idx < numPts; idx++)
1224 {
1225 normals->SetTuple3(idx, 1, 0, 0);
1226 }
1227
1228 vtkPolyLine::GenerateSlidingNormals(outputPoints, outputLines, normals, firstNormal);
1229 lineNormalGenerator->Delete();
1230
1231 vtkIdType i;
1232 int j;
1233 double normal[3], local1[3], local2[3], theta, costheta, sintheta, length;
1234 double velocity[3];
1235 normals->SetName("Normals");
1236 vtkDataArray* newVectors = outputPD->GetVectors(vecName);
1237 for (i = 0; i < numPts; i++)
1238 {
1239 normals->GetTuple(i, normal);
1240 if (newVectors == nullptr || newVectors->GetNumberOfTuples() != numPts)
1241 { // This should never happen.
1242 vtkErrorMacro("Bad velocity array.");
1243 return;
1244 }
1245 newVectors->GetTuple(i, velocity);
1246 // obtain two unit orthogonal vectors on the plane perpendicular to
1247 // the streamline
1248 for (j = 0; j < 3; j++)
1249 {
1250 local1[j] = normal[j];
1251 }
1252 length = vtkMath::Normalize(local1);
1253 vtkMath::Cross(local1, velocity, local2);
1254 vtkMath::Normalize(local2);
1255 // Rotate the normal with theta
1256 rotation->GetTuple(i, &theta);
1257 costheta = cos(theta);
1258 sintheta = sin(theta);
1259 for (j = 0; j < 3; j++)
1260 {
1261 normal[j] = length * (costheta * local1[j] + sintheta * local2[j]);
1262 }
1263 normals->SetTuple(i, normal);
1264 }
1265 outputPD->AddArray(normals);
1266 outputPD->SetActiveAttribute("Normals", vtkDataSetAttributes::VECTORS);
1267 normals->Delete();
1268 }
1269 }
1270 }
1271
1272 //------------------------------------------------------------------------------
1273 // This is used by sub-classes in certain situations. It
1274 // does a lot less (for example, does not compute attributes)
1275 // than Integrate.
SimpleIntegrate(double seed[3],double lastPoint[3],double stepSize,vtkAbstractInterpolatedVelocityField * func)1276 double vtkStreamTracer::SimpleIntegrate(
1277 double seed[3], double lastPoint[3], double stepSize, vtkAbstractInterpolatedVelocityField* func)
1278 {
1279 vtkIdType numSteps = 0;
1280 vtkIdType maxSteps = 20;
1281 double error = 0;
1282 double stepTaken = 0;
1283 double point1[3], point2[3];
1284 double velocity[3];
1285 double speed;
1286 int stepResult;
1287
1288 (void)seed; // Seed is not used
1289
1290 memcpy(point1, lastPoint, 3 * sizeof(double));
1291
1292 // Create a new integrator, the type is the same as Integrator
1293 vtkInitialValueProblemSolver* integrator = this->GetIntegrator()->NewInstance();
1294 integrator->SetFunctionSet(func);
1295
1296 while (true)
1297 {
1298
1299 if (numSteps++ > maxSteps)
1300 {
1301 break;
1302 }
1303
1304 // Calculate the next step using the integrator provided
1305 // Break if the next point is out of bounds.
1306 func->SetNormalizeVector(true);
1307 double tmpStepTaken = 0;
1308 stepResult =
1309 integrator->ComputeNextStep(point1, point2, 0, stepSize, tmpStepTaken, 0, 0, 0, error);
1310 stepTaken += tmpStepTaken;
1311 func->SetNormalizeVector(false);
1312 if (stepResult != 0)
1313 {
1314 memcpy(lastPoint, point2, 3 * sizeof(double));
1315 break;
1316 }
1317
1318 // This is the next starting point
1319 for (int i = 0; i < 3; i++)
1320 {
1321 point1[i] = point2[i];
1322 }
1323
1324 // Interpolate the velocity at the next point
1325 if (!func->FunctionValues(point2, velocity))
1326 {
1327 memcpy(lastPoint, point2, 3 * sizeof(double));
1328 break;
1329 }
1330
1331 speed = vtkMath::Norm(velocity);
1332
1333 // Never call conversion methods if speed == 0
1334 if ((speed == 0) || (speed <= this->TerminalSpeed))
1335 {
1336 break;
1337 }
1338
1339 memcpy(point1, point2, 3 * sizeof(double));
1340 // End Integration
1341 }
1342
1343 integrator->Delete();
1344 return stepTaken;
1345 }
1346
1347 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)1348 int vtkStreamTracer::FillInputPortInformation(int port, vtkInformation* info)
1349 {
1350 if (port == 0)
1351 {
1352 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
1353 }
1354 else if (port == 1)
1355 {
1356 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
1357 info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
1358 }
1359 return 1;
1360 }
1361
1362 //------------------------------------------------------------------------------
AddCustomTerminationCallback(CustomTerminationCallbackType callback,void * clientdata,int reasonForTermination)1363 void vtkStreamTracer::AddCustomTerminationCallback(
1364 CustomTerminationCallbackType callback, void* clientdata, int reasonForTermination)
1365 {
1366 this->CustomTerminationCallback.push_back(callback);
1367 this->CustomTerminationClientData.push_back(clientdata);
1368 this->CustomReasonForTermination.push_back(reasonForTermination);
1369 this->Modified();
1370 }
1371
1372 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1373 void vtkStreamTracer::PrintSelf(ostream& os, vtkIndent indent)
1374 {
1375 this->Superclass::PrintSelf(os, indent);
1376 os << indent << "Start position: " << this->StartPosition[0] << " " << this->StartPosition[1]
1377 << " " << this->StartPosition[2] << endl;
1378 os << indent << "Terminal speed: " << this->TerminalSpeed << endl;
1379
1380 os << indent << "Maximum propagation: " << this->MaximumPropagation << " unit: length." << endl;
1381
1382 os << indent << "Integration step unit: "
1383 << ((this->IntegrationStepUnit == LENGTH_UNIT) ? "length." : "cell length.") << endl;
1384
1385 os << indent << "Initial integration step: " << this->InitialIntegrationStep << endl;
1386
1387 os << indent << "Minimum integration step: " << this->MinimumIntegrationStep << endl;
1388
1389 os << indent << "Maximum integration step: " << this->MaximumIntegrationStep << endl;
1390
1391 os << indent << "Integration direction: ";
1392 switch (this->IntegrationDirection)
1393 {
1394 case FORWARD:
1395 os << "forward.";
1396 break;
1397 case BACKWARD:
1398 os << "backward.";
1399 break;
1400 case BOTH:
1401 os << "both directions.";
1402 break;
1403 }
1404 os << endl;
1405
1406 os << indent << "Integrator: " << this->Integrator << endl;
1407 os << indent << "Maximum error: " << this->MaximumError << endl;
1408 os << indent << "Maximum number of steps: " << this->MaximumNumberOfSteps << endl;
1409 os << indent << "Vorticity computation: " << (this->ComputeVorticity ? " On" : " Off") << endl;
1410 os << indent << "Rotation scale: " << this->RotationScale << endl;
1411 }
1412
1413 //------------------------------------------------------------------------------
CreateDefaultExecutive()1414 vtkExecutive* vtkStreamTracer::CreateDefaultExecutive()
1415 {
1416 return vtkCompositeDataPipeline::New();
1417 }
1418