//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt 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. //============================================================================ #ifndef vtk_m_filter_LagrangianStructures_hxx #define vtk_m_filter_LagrangianStructures_hxx #include #include #include #include #include #include #include #include namespace vtkm { namespace filter { namespace detail { class ExtractParticlePosition : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn particle, FieldOut position); using ExecutionSignature = void(_1, _2); using InputDomain = _1; VTKM_EXEC void operator()(const vtkm::Particle& particle, vtkm::Vec3f& pt) const { pt = particle.Pos; } }; } //detail //----------------------------------------------------------------------------- inline VTKM_CONT LagrangianStructures::LagrangianStructures() : vtkm::filter::FilterDataSetWithField() { OutputFieldName = std::string("FTLE"); } //----------------------------------------------------------------------------- template inline VTKM_CONT vtkm::cont::DataSet LagrangianStructures::DoExecute( const vtkm::cont::DataSet& input, const vtkm::cont::ArrayHandle, StorageType>& field, const vtkm::filter::FieldMetadata& fieldMeta, const vtkm::filter::PolicyBase&) { if (!fieldMeta.IsPointField()) { throw vtkm::cont::ErrorFilterExecution("Point field expected."); } using Structured2DType = vtkm::cont::CellSetStructured<2>; using Structured3DType = vtkm::cont::CellSetStructured<3>; using FieldHandle = vtkm::cont::ArrayHandle, StorageType>; using GridEvaluator = vtkm::worklet::particleadvection::GridEvaluator; using Integrator = vtkm::worklet::particleadvection::RK4Integrator; vtkm::FloatDefault stepSize = this->GetStepSize(); vtkm::Id numberOfSteps = this->GetNumberOfSteps(); vtkm::cont::CoordinateSystem coordinates = input.GetCoordinateSystem(); vtkm::cont::DynamicCellSet cellset = input.GetCellSet(); vtkm::cont::DataSet lcsInput; if (this->GetUseAuxiliaryGrid()) { vtkm::Id3 lcsGridDims = this->GetAuxiliaryGridDimensions(); vtkm::Bounds inputBounds = coordinates.GetBounds(); vtkm::Vec3f origin(static_cast(inputBounds.X.Min), static_cast(inputBounds.Y.Min), static_cast(inputBounds.Z.Min)); vtkm::Vec3f spacing; spacing[0] = static_cast(inputBounds.X.Length()) / static_cast(lcsGridDims[0] - 1); spacing[1] = static_cast(inputBounds.Y.Length()) / static_cast(lcsGridDims[1] - 1); spacing[2] = static_cast(inputBounds.Z.Length()) / static_cast(lcsGridDims[2] - 1); vtkm::cont::DataSetBuilderUniform uniformDatasetBuilder; lcsInput = uniformDatasetBuilder.Create(lcsGridDims, origin, spacing); } else { // Check if input dataset is structured. // If not, we cannot proceed. if (!(cellset.IsType() || cellset.IsType())) throw vtkm::cont::ErrorFilterExecution( "Provided data is not structured, provide parameters for an auxiliary grid."); lcsInput = input; } vtkm::cont::ArrayHandle lcsInputPoints, lcsOutputPoints; vtkm::cont::ArrayCopy(lcsInput.GetCoordinateSystem().GetData(), lcsInputPoints); if (this->GetUseFlowMapOutput()) { // Check if there is a 1:1 correspondense between the flow map // and the input points lcsOutputPoints = this->GetFlowMapOutput(); if (lcsInputPoints.GetNumberOfValues() != lcsOutputPoints.GetNumberOfValues()) throw vtkm::cont::ErrorFilterExecution( "Provided flow map does not correspond to the input points for LCS filter."); } else { GridEvaluator evaluator(input.GetCoordinateSystem(), input.GetCellSet(), field); Integrator integrator(evaluator, stepSize); vtkm::worklet::ParticleAdvection particles; vtkm::worklet::ParticleAdvectionResult advectionResult; vtkm::cont::ArrayHandle advectionPoints; vtkm::cont::ArrayCopy(lcsInputPoints, advectionPoints); advectionResult = particles.Run(integrator, advectionPoints, numberOfSteps); vtkm::cont::Invoker invoke; invoke(detail::ExtractParticlePosition{}, advectionResult.Particles, lcsOutputPoints); } // FTLE output field vtkm::cont::ArrayHandle outputField; vtkm::FloatDefault advectionTime = this->GetAdvectionTime(); vtkm::cont::DynamicCellSet lcsCellSet = lcsInput.GetCellSet(); if (lcsCellSet.IsType()) { using AnalysisType = vtkm::worklet::LagrangianStructures<2>; AnalysisType ftleCalculator(advectionTime, lcsCellSet); vtkm::worklet::DispatcherMapField dispatcher(ftleCalculator); dispatcher.Invoke(lcsInputPoints, lcsOutputPoints, outputField); } else if (lcsCellSet.IsType()) { using AnalysisType = vtkm::worklet::LagrangianStructures<3>; AnalysisType ftleCalculator(advectionTime, lcsCellSet); vtkm::worklet::DispatcherMapField dispatcher(ftleCalculator); dispatcher.Invoke(lcsInputPoints, lcsOutputPoints, outputField); } vtkm::cont::DataSet output; vtkm::cont::DataSetFieldAdd fieldAdder; output.AddCoordinateSystem(lcsInput.GetCoordinateSystem()); output.SetCellSet(lcsInput.GetCellSet()); fieldAdder.AddPointField(output, this->GetOutputFieldName(), outputField); return output; } //----------------------------------------------------------------------------- template inline VTKM_CONT bool LagrangianStructures::DoMapField( vtkm::cont::DataSet&, const vtkm::cont::ArrayHandle&, const vtkm::filter::FieldMetadata&, vtkm::filter::PolicyBase) { return false; } } } // namespace vtkm::filter #endif