/*========================================================================= Program: Visualization Toolkit Module: vtkTemporalStreamTracer.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkTemporalStreamTracer * @brief A Parallel Particle tracer for unsteady vector fields * * vtkTemporalStreamTracer is a filter that integrates a vector field to generate * * * @sa * vtkRibbonFilter vtkRuledSurfaceFilter vtkInitialValueProblemSolver * vtkRungeKutta2 vtkRungeKutta4 vtkRungeKutta45 vtkStreamTracer */ #ifndef vtkTemporalStreamTracer_h #define vtkTemporalStreamTracer_h #include "vtkFiltersFlowPathsModule.h" // For export macro #include "vtkSmartPointer.h" // For protected ivars. #include "vtkStreamTracer.h" #include // STL Header #include // STL Header class vtkMultiProcessController; class vtkMultiBlockDataSet; class vtkDataArray; class vtkDoubleArray; class vtkGenericCell; class vtkIntArray; class vtkTemporalInterpolatedVelocityField; class vtkPoints; class vtkCellArray; class vtkDoubleArray; class vtkFloatArray; class vtkIntArray; class vtkCharArray; class vtkAbstractParticleWriter; namespace vtkTemporalStreamTracerNamespace { typedef struct { double x[4]; } Position; typedef struct { // These are used during iteration Position CurrentPosition; int CachedDataSetId[2]; vtkIdType CachedCellId[2]; int LocationState; // These are computed scalars we might display int SourceID; int TimeStepAge; int InjectedPointId; int InjectedStepId; int UniqueParticleId; // These are useful to track for debugging etc int ErrorCode; float age; // these are needed across time steps to compute vorticity float rotation; float angularVel; float time; float speed; } ParticleInformation; typedef std::vector ParticleVector; typedef ParticleVector::iterator ParticleIterator; typedef std::list ParticleDataList; typedef ParticleDataList::iterator ParticleListIterator; }; class VTKFILTERSFLOWPATHS_EXPORT vtkTemporalStreamTracer : public vtkStreamTracer { public: vtkTypeMacro(vtkTemporalStreamTracer,vtkStreamTracer); void PrintSelf(ostream& os, vtkIndent indent); /** * Construct object using 2nd order Runge Kutta */ static vtkTemporalStreamTracer *New(); //@{ /** * Set/Get the TimeStep. This is the primary means of advancing * the particles. The TimeStep should be animated and this will drive * the pipeline forcing timesteps to be fetched from upstream. */ vtkSetMacro(TimeStep,unsigned int); vtkGetMacro(TimeStep,unsigned int); //@} //@{ /** * To get around problems with the Paraview Animation controls * we can just animate the time step and ignore the TIME_ requests */ vtkSetMacro(IgnorePipelineTime, int); vtkGetMacro(IgnorePipelineTime, int); vtkBooleanMacro(IgnorePipelineTime, int); //@} //@{ /** * If the data source does not have the correct time values * present on each time step - setting this value to non unity can * be used to adjust the time step size from 1s pre step to * 1x_TimeStepResolution : Not functional in this version. * Broke it @todo, put back time scaling */ vtkSetMacro(TimeStepResolution,double); vtkGetMacro(TimeStepResolution,double); //@} //@{ /** * When animating particles, it is nice to inject new ones every Nth step * to produce a continuous flow. Setting ForceReinjectionEveryNSteps to a * non zero value will cause the particle source to reinject particles * every Nth step even if it is otherwise unchanged. * Note that if the particle source is also animated, this flag will be * redundant as the particles will be reinjected whenever the source changes * anyway */ vtkSetMacro(ForceReinjectionEveryNSteps,int); vtkGetMacro(ForceReinjectionEveryNSteps,int); //@} enum Units { TERMINATION_TIME_UNIT, TERMINATION_STEP_UNIT }; //@{ /** * Setting TerminationTime to a positive value will cause particles * to terminate when the time is reached. Use a vlue of zero to * diable termination. The units of time should be consistent with the * primary time variable. */ vtkSetMacro(TerminationTime,double); vtkGetMacro(TerminationTime,double); //@} //@{ /** * The units of TerminationTime may be actual 'Time' units as described * by the data, or just TimeSteps of iteration. */ vtkSetMacro(TerminationTimeUnit,int); vtkGetMacro(TerminationTimeUnit,int); void SetTerminationTimeUnitToTimeUnit() {this->SetTerminationTimeUnit(TERMINATION_TIME_UNIT);}; void SetTerminationTimeUnitToStepUnit() {this->SetTerminationTimeUnit(TERMINATION_STEP_UNIT);}; //@} //@{ /** * if StaticSeeds is set and the mesh is static, * then every time particles are injected we can re-use the same * injection information. We classify particles according to * processor just once before start. * If StaticSeeds is set and a moving seed source is specified * the motion will be ignored and results will not be as expected. */ vtkSetMacro(StaticSeeds,int); vtkGetMacro(StaticSeeds,int); vtkBooleanMacro(StaticSeeds,int); //@} //@{ /** * if StaticMesh is set, many optimizations for cell caching * can be assumed. if StaticMesh is not set, the algorithm * will attempt to find out if optimizations can be used, but * setting it to true will force all optimizations. * Do not Set StaticMesh to true if a dynamic mesh is being used * as this will invalidate all results. */ vtkSetMacro(StaticMesh,int); vtkGetMacro(StaticMesh,int); vtkBooleanMacro(StaticMesh,int); //@} //@{ /** * Set/Get the Writer associated with this Particle Tracer * Ideally a parallel IO capable vtkH5PartWriter should be used * which will collect particles from all parallel processes * and write them to a single HDF5 file. */ virtual void SetParticleWriter(vtkAbstractParticleWriter *pw); vtkGetObjectMacro(ParticleWriter, vtkAbstractParticleWriter); //@} //@{ /** * Set/Get the filename to be used with the particle writer when * dumping particles to disk */ vtkSetStringMacro(ParticleFileName); vtkGetStringMacro(ParticleFileName); //@} //@{ /** * Set/Get the filename to be used with the particle writer when * dumping particles to disk */ vtkSetMacro(EnableParticleWriting,int); vtkGetMacro(EnableParticleWriting,int); vtkBooleanMacro(EnableParticleWriting,int); //@} //@{ /** * Provide support for multiple see sources */ void AddSourceConnection(vtkAlgorithmOutput* input); void RemoveAllSources(); //@} protected: vtkTemporalStreamTracer(); ~vtkTemporalStreamTracer(); // // Make sure the pipeline knows what type we expect as input // virtual int FillInputPortInformation(int port, vtkInformation* info); // // The usual suspects // virtual int ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector); // // Store any information we need in the output and fetch what we can // from the input // virtual int RequestInformation(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector); // // Compute input time steps given the output step // virtual int RequestUpdateExtent(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector); // // what the pipeline calls for each time step // virtual int RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector); // // these routines are internally called to actually generate the output // virtual int ProcessInput(vtkInformationVector** inputVector); virtual int GenerateOutput(vtkInformationVector** inputVector, vtkInformationVector* outputVector); // // Initialization of input (vector-field) geometry // int InitializeInterpolator(); int SetTemporalInput(vtkDataObject *td, int index); // /** * inside our data. Add good ones to passed list and set count to the * number that passed */ void TestParticles( vtkTemporalStreamTracerNamespace::ParticleVector &candidates, vtkTemporalStreamTracerNamespace::ParticleVector &passed, int &count); /** * all the injection/seed points according to which processor * they belong to. This saves us retesting at every injection time * providing 1) The volumes are static, 2) the seed points are static * If either are non static, then this step is skipped. */ virtual void AssignSeedsToProcessors( vtkDataSet *source, int sourceID, int ptId, vtkTemporalStreamTracerNamespace::ParticleVector &LocalSeedPoints, int &LocalAssignedCount); /** * give each one a uniqu ID. We need to use MPI to find out * who is using which numbers. */ virtual void AssignUniqueIds( vtkTemporalStreamTracerNamespace::ParticleVector &LocalSeedPoints); /** * and sending between processors, into a list, which is used as the master * list on this processor */ void UpdateParticleList( vtkTemporalStreamTracerNamespace::ParticleVector &candidates); /** * this is used during classification of seed points and also between iterations * of the main loop as particles leave each processor domain */ virtual void TransmitReceiveParticles( vtkTemporalStreamTracerNamespace::ParticleVector &outofdomain, vtkTemporalStreamTracerNamespace::ParticleVector &received, bool removeself); /** * particle between the two times supplied. */ void IntegrateParticle( vtkTemporalStreamTracerNamespace::ParticleListIterator &it, double currenttime, double terminationtime, vtkInitialValueProblemSolver* integrator); /** * and sent to the other processors for possible continuation. * These routines manage the collection and sending after each main iteration. * RetryWithPush adds a small pusj to aparticle along it's current velocity * vector, this helps get over cracks in dynamic/rotating meshes */ bool RetryWithPush( vtkTemporalStreamTracerNamespace::ParticleInformation &info, double velocity[3], double delT); // if the particle is added to send list, then returns value is 1, // if it is kept on this process after a retry return value is 0 bool SendParticleToAnotherProcess( vtkTemporalStreamTracerNamespace::ParticleInformation &info, double point1[4], double delT); void AddParticleToMPISendList( vtkTemporalStreamTracerNamespace::ParticleInformation &info); /** * In dnamic meshes, particles might leave the domain and need to be extrapolated across * a gap between the meshes before they re-renter another domain * dodgy rotating meshes need special care.... */ bool ComputeDomainExitLocation( double pos[4], double p2[4], double intersection[4], vtkGenericCell *cell); // // //Track internally which round of RequestData it is--between 0 and 2 int RequestIndex; // Track which process we are int UpdatePiece; int UpdateNumPieces; // Important for Caching of Cells/Ids/Weights etc int AllFixedGeometry; int StaticMesh; int StaticSeeds; // Support 'pipeline' time or manual SetTimeStep unsigned int TimeStep; unsigned int ActualTimeStep; int IgnorePipelineTime; unsigned int NumberOfInputTimeSteps; std::vector InputTimeValues; std::vector OutputTimeValues; // more time management double EarliestTime; double CurrentTimeSteps[2]; double TimeStepResolution; // Particle termination after time double TerminationTime; int TerminationTimeUnit; // Particle injection+Reinjection int ForceReinjectionEveryNSteps; bool ReinjectionFlag; int ReinjectionCounter; vtkTimeStamp ParticleInjectionTime; // Particle writing to disk vtkAbstractParticleWriter *ParticleWriter; char *ParticleFileName; int EnableParticleWriting; // The main lists which are held during operation- between time step updates unsigned int NumberOfParticles; vtkTemporalStreamTracerNamespace::ParticleDataList ParticleHistories; vtkTemporalStreamTracerNamespace::ParticleVector LocalSeeds; // // Scalar arrays that are generated as each particle is updated // vtkSmartPointer ParticleAge; vtkSmartPointer ParticleIds; vtkSmartPointer ParticleSourceIds; vtkSmartPointer InjectedPointIds; vtkSmartPointer InjectedStepIds; vtkSmartPointer ErrorCode; vtkSmartPointer ParticleVorticity; vtkSmartPointer ParticleRotation; vtkSmartPointer ParticleAngularVel; vtkSmartPointer cellVectors; vtkSmartPointer OutputPointData; int InterpolationCount; // The output geometry vtkSmartPointer ParticleCells; vtkSmartPointer OutputCoordinates; // List used for transmitting between processors during parallel operation vtkTemporalStreamTracerNamespace::ParticleVector MPISendList; // The velocity interpolator vtkSmartPointer Interpolator; // The input datasets which are stored by time step 0 and 1 vtkSmartPointer InputDataT[2]; vtkSmartPointer DataReferenceT[2]; // Cache bounds info for each dataset we will use repeatedly typedef struct { double b[6]; } bounds; std::vector CachedBounds[2]; // utility function we use to test if a point is inside any of our local datasets bool InsideBounds(double point[]); // global Id counter used to give particles a stamp vtkIdType UniqueIdCounter; vtkIdType UniqueIdCounterMPI; // for debugging only; int substeps; private: /** * Hide this because we require a new interpolator type */ void SetInterpolatorPrototype(vtkAbstractInterpolatedVelocityField*) {} private: vtkTemporalStreamTracer(const vtkTemporalStreamTracer&) VTK_DELETE_FUNCTION; void operator=(const vtkTemporalStreamTracer&) VTK_DELETE_FUNCTION; }; #endif