//============================================================================ // 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. // // Copyright 2014 Sandia Corporation. // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #ifndef VTKM_KERNEL_SPLINE_3RD_ORDER_H #define VTKM_KERNEL_SPLINE_3RD_ORDER_H #include "KernelBase.h" // // Spline 3rd Order kernel. // namespace vtkm { namespace worklet { namespace splatkernels { template struct Spline3rdOrder : public KernelBase< Spline3rdOrder > { //--------------------------------------------------------------------- // Constructor // Calculate coefficients used repeatedly when evaluating the kernel // value or gradient VTKM_EXEC_CONT_EXPORT Spline3rdOrder(double smoothingLength) : KernelBase< Spline3rdOrder >(smoothingLength) { Hinverse_ = 1.0/smoothingLength; Hinverse2_ = Hinverse_*Hinverse_; maxRadius_ = 2.0*smoothingLength; maxRadius2_ = maxRadius_*maxRadius_; // if (Dimensions==2) { norm_ = 10.0/(7.0*M_PI); } if (Dimensions==3) { norm_ = 1.0/M_PI; } scale_W_ = norm_ * power (Hinverse_); scale_GradW_ = norm_ * power(Hinverse_); } //--------------------------------------------------------------------- // Calculates the kernel value for the given distance VTKM_EXEC_CONT_EXPORT double w(double distance) const { // compute Q=(r/h) double Q = distance * Hinverse_; if (Q<1.0) { return scale_W_ *(1.0 - (3.0/2.0)*Q*Q + (3.0/4.0)*Q*Q*Q); } else if (Q<2.0) { double q2 = (2.0-Q); return scale_W_ * (1.0/4.0) * (q2*q2*q2);; } else { return 0.0; } } //--------------------------------------------------------------------- // Calculates the kernel value for the given squared distance VTKM_EXEC_CONT_EXPORT double w2(double distance2) const { // compute Q double Q = sqrt(distance2) * Hinverse_; if (Q<1.0) { return scale_W_ *(1.0 - (3.0/2.0)*Q*Q + (3.0/4.0)*Q*Q*Q); } else if (Q<2.0) { double q2 = (2.0-Q); return scale_W_ * (1.0/4.0) * (q2*q2*q2);; } else { return 0.0; } } //--------------------------------------------------------------------- // compute w(h) for a variable h kernel VTKM_EXEC_CONT_EXPORT double w(double h, double distance) const { double Hinverse = 1.0/h; double scale_W = norm_ * power(Hinverse); double Q = distance * Hinverse; if (Q<1.0) { return scale_W *(1.0 - (3.0/2.0)*Q*Q + (3.0/4.0)*Q*Q*Q); } else if (Q<2.0) { double q2 = (2.0-Q); return scale_W * (1.0/4.0) * (q2*q2*q2);; } else { return 0.0; } } //--------------------------------------------------------------------- // compute w(h) for a variable h kernel using distance squared VTKM_EXEC_CONT_EXPORT double w2(double h, double distance2) const { double Hinverse = 1.0/h; double scale_W = norm_ * power(Hinverse); double Q = sqrt(distance2) * Hinverse; if (Q<1.0) { return scale_W *(1.0 - (3.0/2.0)*Q*Q + (3.0/4.0)*Q*Q*Q); } else if (Q<2.0) { double q2 = (2.0-Q); return scale_W * (1.0/4.0) * (q2*q2*q2);; } else { return 0.0; } } //--------------------------------------------------------------------- // Calculates the kernel derivation for the given distance of two particles. // The used formula is the derivation of Speith (3.126) for the value // with (3.21) for the direction of the gradient vector. // Be careful: grad W is antisymmetric in r (3.25)!. VTKM_EXEC_CONT_EXPORT vector_type gradW(double distance, const vector_type& pos) const { double Q = distance * Hinverse_; if (Q==0.0) { return vector_type(0.0); } else if (Q<1.0) { return scale_GradW_ * (-3.0*Q + (9.0/4.0)*Q*Q) * pos; } else if (Q<2.0) { double q2 = (2.0-Q); return scale_GradW_ * (-3.0/4.0)*q2*q2 * pos; } else { return vector_type(0.0); } } //--------------------------------------------------------------------- VTKM_EXEC_CONT_EXPORT vector_type gradW(double h, double distance, const vector_type& pos) const { double Hinverse = 1.0/h; double scale_GradW = norm_ * power(Hinverse); double Q = distance * Hinverse; if (Q==0.0) { return vector_type(0.0); } else if (Q<1.0) { return scale_GradW * (-3.0*Q + (9.0/4.0)*Q*Q) * pos; } else if (Q<2.0) { double q2 = (2.0-Q); return scale_GradW * (-3.0/4.0)*q2*q2 * pos; } else { return vector_type(0.0); } } //--------------------------------------------------------------------- // return the maximum distance at which this kernel is non zero VTKM_EXEC_CONT_EXPORT double maxDistance() const { return maxRadius_; } //--------------------------------------------------------------------- // return the maximum distance at which this variable h kernel is non zero VTKM_EXEC_CONT_EXPORT double maxDistance(double h) const { return 2.0*h; } //--------------------------------------------------------------------- // return the maximum distance at which this kernel is non zero VTKM_EXEC_CONT_EXPORT double maxSquaredDistance() const { return maxRadius2_; } //--------------------------------------------------------------------- // return the maximum distance at which this kernel is non zero VTKM_EXEC_CONT_EXPORT double maxSquaredDistance(double h) const { return 4.0*h*h; } //--------------------------------------------------------------------- // return the multiplier between smoothing length and max cutoff distance VTKM_EXEC_CONT_EXPORT double getDilationFactor() const { return 2.0; } private: double norm_; double Hinverse_; double Hinverse2_; double maxRadius_; double maxRadius2_; double scale_W_; double scale_GradW_; }; }}} #endif