Nektar++
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Private Member Functions | List of all members
Nektar::FieldUtils::ProcessBodyFittedVelocity Class Reference

This processing module calculates the wall shear stress and adds it as an extra-field to the output file, and writes it to a surface output file. More...

#include <ProcessBodyFittedVelocity.h>

Inheritance diagram for Nektar::FieldUtils::ProcessBodyFittedVelocity:
[legend]

Public Member Functions

 ProcessBodyFittedVelocity (FieldSharedPtr f)
 
 ~ProcessBodyFittedVelocity () override
 
void GenPntwiseBodyFittedCoordSys (const int targetBndId, const Array< OneD, NekDouble > assistVec, Array< OneD, NekDouble > &distance, Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &bfcsDir, const bool isCheckAngle, const NekDouble distTol=1.0e-12, const NekDouble iterTol=1.0e-12, const NekDouble dirTol=1.0e-4, const NekDouble geoTol=1.0e-12)
 At each quadrature point inside the domian, compute the body-fitted coordinate system with respect to the input boundary id. More...
 
- Public Member Functions inherited from Nektar::FieldUtils::ProcessBoundaryExtract
 ProcessBoundaryExtract (FieldSharedPtr f)
 
 ~ProcessBoundaryExtract () override
 
- Public Member Functions inherited from Nektar::FieldUtils::ProcessModule
 ProcessModule ()
 
 ProcessModule (FieldSharedPtr p_f)
 
- Public Member Functions inherited from Nektar::FieldUtils::Module
FIELD_UTILS_EXPORT Module (FieldSharedPtr p_f)
 
virtual ~Module ()=default
 
void Process (po::variables_map &vm)
 
std::string GetModuleName ()
 
std::string GetModuleDescription ()
 
const ConfigOptionGetConfigOption (const std::string &key) const
 
ModulePriority GetModulePriority ()
 
std::vector< ModuleKeyGetModulePrerequisites ()
 
FIELD_UTILS_EXPORT void RegisterConfig (std::string key, std::string value="")
 Register a configuration option with a module. More...
 
FIELD_UTILS_EXPORT void PrintConfig ()
 Print out all configuration options for a module. More...
 
FIELD_UTILS_EXPORT void SetDefaults ()
 Sets default configuration options for those which have not been set. More...
 
FIELD_UTILS_EXPORT void AddFile (std::string fileType, std::string fileName)
 
FIELD_UTILS_EXPORT void EvaluateTriFieldAtEquiSpacedPts (LocalRegions::ExpansionSharedPtr &exp, const Array< OneD, const NekDouble > &infield, Array< OneD, NekDouble > &outfield)
 

Static Public Member Functions

static std::shared_ptr< Modulecreate (FieldSharedPtr f)
 Creates an instance of this class. More...
 
- Static Public Member Functions inherited from Nektar::FieldUtils::ProcessBoundaryExtract
static std::shared_ptr< Modulecreate (FieldSharedPtr f)
 Creates an instance of this class. More...
 

Static Public Attributes

static ModuleKey className
 
- Static Public Attributes inherited from Nektar::FieldUtils::ProcessBoundaryExtract
static ModuleKey className
 

Protected Member Functions

void v_Process (po::variables_map &vm) override
 Write mesh to output file. More...
 
std::string v_GetModuleName () override
 
std::string v_GetModuleDescription () override
 
- Protected Member Functions inherited from Nektar::FieldUtils::ProcessBoundaryExtract
void v_Process (po::variables_map &vm) override
 
std::string v_GetModuleName () override
 
std::string v_GetModuleDescription () override
 
ModulePriority v_GetModulePriority () override
 
- Protected Member Functions inherited from Nektar::FieldUtils::Module
 Module ()
 
virtual void v_Process (po::variables_map &vm)
 
virtual std::string v_GetModuleName ()
 
virtual std::string v_GetModuleDescription ()
 
virtual ModulePriority v_GetModulePriority ()
 
virtual std::vector< ModuleKeyv_GetModulePrerequisites ()
 

Private Member Functions

NekDouble PntToBndElmtPntDistance (const Array< OneD, Array< OneD, NekDouble > > &pts, const int pId, const Array< OneD, Array< OneD, NekDouble > > &bndPts)
 Compute the local coordinate for the nearest point on the given 2D boundary element to the input point. More...
 
bool LocCoordForNearestPntOnBndElmt_2D (const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, Array< OneD, NekDouble > > &pts, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
 Compute the local coordinate for the nearest point on the given 2D boundary element to the input point. More...
 
bool LocCoordForNearestPntOnBndElmt (const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
 Compute the local coordinate for the nearest point on the given boundary element to the input point. The locCoord is the position to set up the body-fitted coordinate. This function works as a driver. More...
 
void ScaledCrosssProduct (const Array< OneD, NekDouble > &vec1, const Array< OneD, NekDouble > &vec2, Array< OneD, NekDouble > &vec3)
 Compute the normalized cross product for two 2D vectors. vec3 = vec1 x vec2. More...
 
void GetVelAndConvertToCartSys (Array< OneD, Array< OneD, NekDouble > > &vel)
 Get velocity and convert to Cartesian system, if it is still in transformed system. It is copied and modified from from ProcessGrad.cpp. More...
 

Additional Inherited Members

- Public Attributes inherited from Nektar::FieldUtils::Module
FieldSharedPtr m_f
 Field object. More...
 
- Protected Attributes inherited from Nektar::FieldUtils::Module
std::map< std::string, ConfigOptionm_config
 List of configuration values. More...
 
std::set< std::string > m_allowedFiles
 List of allowed file formats. More...
 

Detailed Description

This processing module calculates the wall shear stress and adds it as an extra-field to the output file, and writes it to a surface output file.

Definition at line 48 of file ProcessBodyFittedVelocity.h.

Constructor & Destructor Documentation

◆ ProcessBodyFittedVelocity()

Nektar::FieldUtils::ProcessBodyFittedVelocity::ProcessBodyFittedVelocity ( FieldSharedPtr  f)

Definition at line 62 of file ProcessBodyFittedVelocity.cpp.

64{
65 f->m_writeBndFld =
66 false; // turned on in the father class ProcessBoundaryExtract
67
68 // bnd is read from father class ProcessBoundaryExtract
69 m_config["assistDir"] =
70 ConfigOption(false, "0.0,0.0,1.0",
71 "The normal direction of the assistant plane, where \
72 the first body-fitted coordinate direction is located. \
73 The assistance plane is defined in point normal form. \
74 Default = [0,0,1]");
75 m_config["checkAngle"] =
76 ConfigOption(true, "0", "The flag for checking the distance vector \
77 perpendicular to the nearest element or not. It \
78 does not need to be turned on if geometry is \
79 smooth and there is no special consideration of \
80 the body-fitted coordinate system. It would be \
81 helpful to set up a desired coordinate system \
82 based on the surface with with sharp corners, \
83 such as at the presence of a step or gap. \
84 Default = false.");
85 m_config["distTol"] = ConfigOption(
86 false, "1.0e-12", "The distance tolerence to properly find out the \
87 nearest boundary element. It works together with \
88 the CHECKANGLE option to set up the body-fitted \
89 coordinate system near the corner. \
90 Default = 1.0e-12.");
91 m_config["bfcOut"] = ConfigOption(
92 true, "1", "The flag control whether the body-fitted coordinate \
93 system will be output. Default = true.");
94}
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:272

References Nektar::FieldUtils::Module::m_config.

◆ ~ProcessBodyFittedVelocity()

Nektar::FieldUtils::ProcessBodyFittedVelocity::~ProcessBodyFittedVelocity ( )
override

Definition at line 96 of file ProcessBodyFittedVelocity.cpp.

97{
98}

Member Function Documentation

◆ create()

static std::shared_ptr< Module > Nektar::FieldUtils::ProcessBodyFittedVelocity::create ( FieldSharedPtr  f)
inlinestatic

Creates an instance of this class.

Definition at line 52 of file ProcessBodyFittedVelocity.h.

53 {
55 }
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.

References Nektar::MemoryManager< DataType >::AllocateSharedPtr().

◆ GenPntwiseBodyFittedCoordSys()

void Nektar::FieldUtils::ProcessBodyFittedVelocity::GenPntwiseBodyFittedCoordSys ( const int  targetBndId,
const Array< OneD, NekDouble assistVec,
Array< OneD, NekDouble > &  distance,
Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &  bfcsDir,
const bool  isCheckAngle,
const NekDouble  distTol = 1.0e-12,
const NekDouble  iterTol = 1.0e-12,
const NekDouble  dirTol = 1.0e-4,
const NekDouble  geoTol = 1.0e-12 
)

At each quadrature point inside the domian, compute the body-fitted coordinate system with respect to the input boundary id.

Parameters
targetBndIdTarget boundary id.
assistVecUnit assistant vector, the cross product of inward- pointing wall normalId and wihch gives of the main tangential direction of the body-fitted system.
bfcsDirPointwise body-fitted coordinate system.
isPerpendicularConditionFlag for using perpendicular check or not
distTolDistance tolerence. Used to find the boundary elements for local coordinate iteration.
iterTolIteration tolerence. Used to check iteration convergence.
dirTolDirection tolerencce. Used to check if the inner product of two unit vectors is cloes enough to 1.0.
geoTolGeometry tolerence. Used as the relative tolerence for local coord and distance absolute tolerence.

Definition at line 504 of file ProcessBodyFittedVelocity.cpp.

510{
511
512 const int nFields = m_f->m_variables.size();
513 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0);
514 const int nSpaceDim = nCoordDim + m_f->m_numHomogeneousDir;
515 const int nBndLcoordDim = nCoordDim - 1;
516
517 // Get expansion list for boundary
518 Array<OneD, MultiRegions::ExpListSharedPtr> BndExp(nFields);
519 for (int i = 0; i < nFields; ++i)
520 {
521 BndExp[i] = m_f->m_exp[i]->UpdateBndCondExpansion(targetBndId);
522 }
523
524 const int nElmts = m_f->m_exp[0]->GetNumElmts(); // num of inner element
525 const int nBndElmts = BndExp[0]->GetNumElmts(); // num of bnd element
526
527 // Use the outward-pointing normal at quardrature pts on bnd elmt as dir ref
528 Array<OneD, Array<OneD, NekDouble>> normalQ;
529 m_f->m_exp[0]->GetBoundaryNormals(targetBndId, normalQ);
530
531 // Vars in the loop
534 Array<OneD, Array<OneD, NekDouble>> bndCoeffs(nCoordDim);
535 Array<OneD, Array<OneD, NekDouble>> bndPts(nCoordDim);
536
537 int nPts, nBndPts;
538 NekDouble dist_tmp, dist_bak;
539 bool isConverge;
540 vector<int> bndElmtIds;
541 int bndElmtId, bndElmtId_bak;
542 int phys_offset, bnd_phys_offset;
543
544 Array<OneD, NekDouble> inGloCoord(3, 0.0); // inner pnt
545 Array<OneD, NekDouble> locCoord(nBndLcoordDim), locCoord_tmp(nBndLcoordDim);
546 Array<OneD, NekDouble> gloCoord(3, 0.0), gloCoord_tmp(3, 0.0);
547 Array<OneD, NekDouble> normal(3), normalRef(3);
548 Array<OneD, NekDouble> tangential1(3),
549 tangential2(3); // 1 - main, 2 - minor
550 Array<OneD, NekDouble> normalChk(3);
551 ProcessWallNormalData wnd(m_f); // wallNormalData object to use its routine
552
553 // backup for angle check
554 Array<OneD, NekDouble> locCoord_bak(nBndLcoordDim), gloCoord_bak(3, 0.0);
555
556 //-------------------------------------------------------------------------
557 // Loop all the quadrature points of the field, and find out the closest
558 // point on the bnd for each of them. The bnd element contains this bnd
559 // point is recorded.
560
561 // Loop inner element
562 for (int eId = 0; eId < nElmts; ++eId) // element id, nElmts
563 {
564 // Get inner points
565 nPts = m_f->m_exp[0]->GetExp(eId)->GetTotPoints();
566 Array<OneD, Array<OneD, NekDouble>> pts(nCoordDim);
567 for (int i = 0; i < nCoordDim; ++i)
568 {
569 pts[i] = Array<OneD, NekDouble>(nPts, 0.0);
570 }
571
572 if (nCoordDim == 2)
573 {
574 m_f->m_exp[0]->GetExp(eId)->GetCoords(pts[0], pts[1]);
575 }
576 else if (nCoordDim == 3)
577 {
578 m_f->m_exp[0]->GetExp(eId)->GetCoords(pts[0], pts[1], pts[2]);
579 }
580
581 // Get the offset for the current elmt
582 phys_offset = m_f->m_exp[0]->GetPhys_Offset(eId);
583
584 // Loop points in the inner element
585 for (int pId = 0; pId < nPts; ++pId)
586 {
587
588 // Compute the distance from the pnt (bnd elmt) to the inner pnt
589 // Step 1 - Estimate search
590 // - Find the closest quadrature pnt among all the bnd elmt;
591 // - The bnd elmt which contains this pnt is saved for Step 2.
592 // * If the quadtature pnt is on the edge or corner of the bnd
593 // elmt, there will be more than one bnd elmt which contains
594 // this point.
595
596 bndElmtIds.clear(); // clear the bnd elmt id vec for a new inner pnt
597
598 // Loop bnd elmt to find the elmt to build body-fitted coord sys
599 for (int beId = 0; beId < nBndElmts; ++beId)
600 {
601 // Get geomery and points
602 bndGeom = BndExp[0]->GetExp(beId)->GetGeom();
603 bndXmap = bndGeom->GetXmap();
604 nBndPts = bndXmap->GetTotPoints();
605
606 for (int i = 0; i < nCoordDim; ++i)
607 {
608 bndPts[i] = Array<OneD, NekDouble>(nBndPts);
609 bndCoeffs[i] = bndGeom->GetCoeffs(i); // 0/1/2 for x/y/z
610 bndXmap->BwdTrans(bndCoeffs[i], bndPts[i]);
611 }
612
613 // Compute the distance (estimate)
614 dist_tmp = PntToBndElmtPntDistance(pts, pId, bndPts);
615
616 if ((dist_tmp < (distance[phys_offset + pId] - geoTol)) &&
617 (dist_tmp < (distance[phys_offset + pId] - distTol)))
618 {
619 // Find a closer quadrature point from a different bnd elmt
620 // Update distance and bnd elmt id vector
621 distance[phys_offset + pId] = dist_tmp;
622 bndElmtIds.clear();
623 bndElmtIds.push_back(beId);
624 }
625 else if ((dist_tmp < (distance[phys_offset + pId] + geoTol)) ||
626 (dist_tmp < (distance[phys_offset + pId] + distTol)))
627 {
628 // The same quadrature point from a different bnd elmt is
629 // found for the other time.
630 // Keep the distance and add the bnd elmt id to the vector
631 bndElmtIds.push_back(beId);
632 }
633
634 } // end of bnd elmt loop
635
636 // Step 2 - Accurate search
637 // - Find the accurate distance and locCoord for the nearest pnt
638 // (to the inner point) on the bnd elmt
639 // - This process will be repeated on all the bnd elmts in the bnd
640 // elmt id vector.
641
642 // Generate the coordinate for the inner point
643 for (int i = 0; i < nCoordDim; ++i)
644 {
645 inGloCoord[i] = pts[i][pId];
646 }
647
648 // reset the dist to make sure the condition for if will be
649 // satisfied
650 distance[phys_offset + pId] = 9999;
651 bndElmtId = -1;
652 dist_bak = 9999;
653 bndElmtId_bak = -1;
654
655 // Compute the accurate distance and locCoord
656 for (int i = 0; i < bndElmtIds.size(); ++i)
657 {
658 // Iterate on each of the possible bnd elmt to get the locCoord
659 // and the smallest dist
660 bndGeom = BndExp[0]->GetExp(bndElmtIds[i])->GetGeom();
661
663 inGloCoord, bndGeom, locCoord_tmp, gloCoord_tmp, dist_tmp,
664 iterTol, 51);
665
666 if (!isConverge)
667 {
668 WARNINGL1(false, "Bisection iteration is not converged!!!");
669 }
670
671 // Perpendicular check (angle check)
672 // When activated (distance > geoTol)
673 // if the pnt-to-pnt vector is not parallel with the wall
674 // normal, this bnd will be skipped. It is helpful to avoid
675 // confusion when there are cornors
676 if (isCheckAngle && (dist_tmp > geoTol)) // skip pts on the bnd
677 {
678 // Generate the scaled vector
679 Vmath::Vcopy(nCoordDim, gloCoord_tmp, 1, normalChk, 1);
680 Vmath::Neg(nCoordDim, normalChk, 1);
681 Vmath::Vadd(nCoordDim, inGloCoord, 1, normalChk, 1,
682 normalChk, 1);
683 Vmath::Smul(nCoordDim,
684 1.0 / sqrt(Vmath::Dot(nCoordDim, normalChk, 1,
685 normalChk, 1)),
686 normalChk, 1, normalChk, 1);
687
688 // Get normal based on the locCoord_tmp
689 wnd.GetNormals(bndGeom, locCoord_tmp, normal);
690
691 // Reverse the direction to make it point into the field
692 bnd_phys_offset = BndExp[0]->GetPhys_Offset(bndElmtIds[i]);
693 for (int j = 0; j < nCoordDim; ++j)
694 {
695 normalRef[j] = normalQ[j][bnd_phys_offset];
696 }
697
698 if (Vmath::Dot(nCoordDim, normal, normalRef) > 0.0)
699 {
700 Vmath::Neg(nCoordDim, normal, 1);
701 }
702
703 // Check if the current bnd elmt convers this inner pnt
704 if (Vmath::Dot(nCoordDim, normalChk, 1, normal, 1) <
705 (1 - dirTol))
706 {
707 // If not covered, save the nearest result as backup
708 // Then skip
709 if (dist_tmp < dist_bak)
710 {
711 bndElmtId_bak = bndElmtIds[i];
712 dist_bak = dist_tmp;
713
714 for (int j = 0; j < nBndLcoordDim; ++j)
715 {
716 locCoord_bak[j] = locCoord_tmp[j];
717 }
718
719 for (int j = 0; j < 3; ++j)
720 {
721 gloCoord_bak[j] = gloCoord_tmp[j];
722 }
723 }
724
725 continue; // Skip current bnd elmt
726 }
727 }
728
729 // No violation occurs, update the current result
730 // This section must be executed at least once if there the
731 // angle check is turned off. It means the following
732 // (bndElmtId == -1) can only be caused by angle check.
733 if (dist_tmp < distance[phys_offset + pId])
734 {
735 bndElmtId = bndElmtIds[i];
736 distance[phys_offset + pId] = dist_tmp;
737
738 for (int j = 0; j < nBndLcoordDim; ++j)
739 {
740 locCoord[j] = locCoord_tmp[j];
741 }
742
743 for (int j = 0; j < 3; ++j)
744 {
745 gloCoord[j] = gloCoord_tmp[j];
746 }
747 }
748 }
749
750 // Check if the bnd elmt is found. If not, use nearest one.
751 if (bndElmtId == -1)
752 {
753 if (bndElmtIds.size() == 0)
754 {
755 ASSERTL0(false, "No boundary element is found to be the \
756 possible nearest element. Please check.");
757 }
758
759 distance[phys_offset + pId] = dist_bak;
760 bndElmtId = bndElmtId_bak;
761
762 for (int i = 0; i < nBndLcoordDim; ++i)
763 {
764 locCoord[i] = locCoord_bak[i];
765 }
766
767 for (int i = 0; i < 3; ++i)
768 {
769 gloCoord[i] = gloCoord_bak[i];
770 }
771
772 WARNINGL1(false,
773 "The boundary element is not found under given \
774 tolerence. Please check and reset the \
775 tolerence, or just turn off the angle check. \
776 If you would like to continue, the nearest \
777 boundary element is used.");
778 }
779
780 // Get the wall normal using the function in wallNormalData class
781 bndGeom = BndExp[0]->GetExp(bndElmtId)->GetGeom();
782 wnd.GetNormals(bndGeom, locCoord, normal);
783
784 // Get ref normal for outward-point dir
785 bnd_phys_offset = BndExp[0]->GetPhys_Offset(bndElmtId);
786 for (int i = 0; i < nCoordDim; ++i)
787 {
788 normalRef[i] = normalQ[i][bnd_phys_offset];
789 }
790
791 // Correct the normal direction to make sure it points inward
792 if (Vmath::Dot(nCoordDim, normal, normalRef) > 0.0)
793 {
794 Vmath::Neg(nCoordDim, normal, 1);
795 }
796
797 // The main tagential direction is defined to be overlapped with the
798 // intersection line of the tangantial plane and the assistant
799 // plane, whose normal is the input assistDir. Both plane is defined
800 // using the point normal form, where the point is the nearest point
801 // on the boundary (gloCoord), and the vectors are the normal
802 // (pointing out) and the assistant direction (assistDir).
803 // Therefore, the main tangantial direction can be obtained by the
804 // cross product of the two vectors, since the two vectors has the
805 // same starting point and the tangantial direction is perpendicular
806 // to both of them.
807 ScaledCrosssProduct(normal, assistVec, tangential1);
808
809 // Save the direction vectors
810 for (int i = 0; i < nSpaceDim; ++i)
811 {
812 bfcsDir[0][i][phys_offset + pId] = tangential1[i];
813 bfcsDir[1][i][phys_offset + pId] = normal[i];
814 }
815
816 if (nSpaceDim == 3)
817 {
818 ScaledCrosssProduct(tangential1, normal, tangential2);
819 for (int i = 0; i < 3; ++i)
820 {
821 bfcsDir[2][i][phys_offset + pId] = tangential2[i];
822 }
823 }
824
825 } // end of inner pts loop
826
827 } // end of inner elmt loop
828}
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:243
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
FieldSharedPtr m_f
Field object.
Definition: Module.h:239
void ScaledCrosssProduct(const Array< OneD, NekDouble > &vec1, const Array< OneD, NekDouble > &vec2, Array< OneD, NekDouble > &vec3)
Compute the normalized cross product for two 2D vectors. vec3 = vec1 x vec2.
NekDouble PntToBndElmtPntDistance(const Array< OneD, Array< OneD, NekDouble > > &pts, const int pId, const Array< OneD, Array< OneD, NekDouble > > &bndPts)
Compute the local coordinate for the nearest point on the given 2D boundary element to the input poin...
bool LocCoordForNearestPntOnBndElmt(const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
Compute the local coordinate for the nearest point on the given boundary element to the input point....
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:51
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
double NekDouble
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.hpp:292
T Dot(int n, const T *w, const T *x)
dot product
Definition: Vmath.hpp:761
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.hpp:100
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.hpp:825
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294

References ASSERTL0, Vmath::Dot(), Nektar::FieldUtils::ProcessWallNormalData::GetNormals(), LocCoordForNearestPntOnBndElmt(), Nektar::FieldUtils::Module::m_f, Vmath::Neg(), PntToBndElmtPntDistance(), ScaledCrosssProduct(), Vmath::Smul(), tinysimd::sqrt(), Vmath::Vadd(), Vmath::Vcopy(), and WARNINGL1.

Referenced by v_Process().

◆ GetVelAndConvertToCartSys()

void Nektar::FieldUtils::ProcessBodyFittedVelocity::GetVelAndConvertToCartSys ( Array< OneD, Array< OneD, NekDouble > > &  vel)
private

Get velocity and convert to Cartesian system, if it is still in transformed system. It is copied and modified from from ProcessGrad.cpp.

Definition at line 835 of file ProcessBodyFittedVelocity.cpp.

837{
838 int spacedim = m_f->m_exp[0]->GetCoordim(0) + m_f->m_numHomogeneousDir;
839 int nfields = m_f->m_variables.size();
840 int npoints = m_f->m_exp[0]->GetNpoints();
841 int var_offset = 0;
842
843 // Check type of the fields and set variable offset
844 vector<string> vars = m_f->m_exp[0]->GetSession()->GetVariables();
845 if (boost::iequals(vars[0], "rho") && boost::iequals(vars[1], "rhou"))
846 {
847 var_offset = spacedim + 2;
848 }
849
850 // Get mapping
852
853 // Get velocity and convert to Cartesian system,
854 // if it is still in transformed system
855 if (m_f->m_fieldMetaDataMap.count("MappingCartesianVel"))
856 {
857 if (m_f->m_fieldMetaDataMap["MappingCartesianVel"] == "False")
858 {
859 // Initialize arrays and copy velocity
860 for (int i = 0; i < spacedim; ++i)
861 {
862 vel[i] = Array<OneD, NekDouble>(npoints);
863 if (m_f->m_exp[0]->GetWaveSpace())
864 {
865 m_f->m_exp[0]->HomogeneousBwdTrans(
866 npoints, m_f->m_exp[var_offset + i]->GetPhys(), vel[i]);
867 }
868 else
869 {
870 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(),
871 1, vel[i], 1);
872 }
873 }
874 // Convert velocity to cartesian system
875 mapping->ContravarToCartesian(vel, vel);
876 // Convert back to wavespace if necessary
877 if (m_f->m_exp[0]->GetWaveSpace())
878 {
879 for (int i = 0; i < spacedim; ++i)
880 {
881 m_f->m_exp[0]->HomogeneousFwdTrans(npoints, vel[i], vel[i]);
882 }
883 }
884 }
885 else
886 {
887 for (int i = 0; i < spacedim; ++i)
888 {
889 vel[i] = Array<OneD, NekDouble>(npoints);
890 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(), 1,
891 vel[i], 1);
892 }
893 }
894 }
895 else
896 {
897 for (int i = 0; i < spacedim && i < nfields; ++i)
898 {
899 vel[i] = Array<OneD, NekDouble>(npoints);
900 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(), 1,
901 vel[i], 1);
902 }
903 }
904}
static GlobalMapping::MappingSharedPtr GetMapping(FieldSharedPtr f)
GLOBAL_MAPPING_EXPORT typedef std::shared_ptr< Mapping > MappingSharedPtr
A shared pointer to a Mapping object.
Definition: Mapping.h:51

References Nektar::FieldUtils::ProcessMapping::GetMapping(), Nektar::FieldUtils::Module::m_f, Nektar::GlobalMapping::MappingSharedPtr, and Vmath::Vcopy().

Referenced by v_Process().

◆ LocCoordForNearestPntOnBndElmt()

bool Nektar::FieldUtils::ProcessBodyFittedVelocity::LocCoordForNearestPntOnBndElmt ( const Array< OneD, const NekDouble > &  inGloCoord,
SpatialDomains::GeometrySharedPtr  bndGeom,
Array< OneD, NekDouble > &  locCoord,
Array< OneD, NekDouble > &  gloCoord,
NekDouble dist,
const NekDouble  iterTol = 1.0e-12,
const int  iterMax = 51 
)
private

Compute the local coordinate for the nearest point on the given boundary element to the input point. The locCoord is the position to set up the body-fitted coordinate. This function works as a driver.

Parameters
inGloCoordGlobal coordinate for the input point.
bndGeomGeometry of the boundary element to search from.
locCoordLocal coordinate of the result.
gloCoordGlobal coordinate of the result.
distDistance from the input point to the boundary element.
iterTolIteration tolerence.
iterMaxMax iteration steps.

Definition at line 428 of file ProcessBodyFittedVelocity.cpp.

433{
434 bool isConverge = false;
435 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0); // =2 for 2.5D cases
436
437 StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
438 int nBndPts = bndXmap->GetTotPoints();
439
440 Array<OneD, Array<OneD, const NekDouble>> bndCoeffs(nCoordDim);
441 Array<OneD, Array<OneD, NekDouble>> bndPts(nCoordDim);
442 for (int i = 0; i < nCoordDim; ++i)
443 {
444 bndPts[i] = Array<OneD, NekDouble>(nBndPts);
445 bndCoeffs[i] = bndGeom->GetCoeffs(i);
446 bndXmap->BwdTrans(bndCoeffs[i], bndPts[i]);
447 }
448
449 // Compute the locCoord for the pnt on the bnd elmt
450 if (nCoordDim == 2)
451 {
452 // Bisection search
454 inGloCoord, bndGeom, bndPts, locCoord, gloCoord, dist, iterTol,
455 iterMax);
456 }
457 else
458 {
459 // Bi-bisection search
460 ASSERTL0(false, "Not available at the moment.");
461 }
462
463 return isConverge;
464}
bool LocCoordForNearestPntOnBndElmt_2D(const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, Array< OneD, NekDouble > > &pts, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
Compute the local coordinate for the nearest point on the given 2D boundary element to the input poin...

References ASSERTL0, LocCoordForNearestPntOnBndElmt_2D(), and Nektar::FieldUtils::Module::m_f.

Referenced by GenPntwiseBodyFittedCoordSys().

◆ LocCoordForNearestPntOnBndElmt_2D()

bool Nektar::FieldUtils::ProcessBodyFittedVelocity::LocCoordForNearestPntOnBndElmt_2D ( const Array< OneD, const NekDouble > &  inGloCoord,
SpatialDomains::GeometrySharedPtr  bndGeom,
const Array< OneD, Array< OneD, NekDouble > > &  pts,
Array< OneD, NekDouble > &  locCoord,
Array< OneD, NekDouble > &  gloCoord,
NekDouble dist,
const NekDouble  iterTol = 1.0e-12,
const int  iterMax = 51 
)
private

Compute the local coordinate for the nearest point on the given 2D boundary element to the input point.

Parameters
inGloCoordGlobal coordinate for the input point.
bndGeomGeometry of the boundary element to search from.
ptsGlobal coordinate of the quadrature points in the boundary element.
locCoordLocal coordinate of the result.
gloCoordGlobal coordinate of the result.
distDistance from the input point to the boundary element.
iterTolIteration tolerence.
iterMaxMax iteration steps.

Definition at line 354 of file ProcessBodyFittedVelocity.cpp.

360{
361
362 // Initial settings
363 Array<OneD, NekDouble> etaLR(2); // range [-1,1]
364 etaLR[0] = -1.0; // left
365 etaLR[1] = 1.0; // right
366 NekDouble tmpLx, tmpLy, tmpRx, tmpRy; // tmp values for L/R
367 NekDouble distL2, distR2; // distance square
368
369 StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
370 locCoord[0] = -2.0;
371 int cnt = 0;
372 bool isConverge = false;
373 while (cnt < iterMax)
374 {
375 tmpLx = bndXmap->PhysEvaluate(etaLR, pts[0]);
376 tmpLy = bndXmap->PhysEvaluate(etaLR, pts[1]);
377 tmpRx = bndXmap->PhysEvaluate(etaLR + 1, pts[0]);
378 tmpRy = bndXmap->PhysEvaluate(etaLR + 1, pts[1]);
379
380 distL2 = (tmpLx - inGloCoord[0]) * (tmpLx - inGloCoord[0]) +
381 (tmpLy - inGloCoord[1]) * (tmpLy - inGloCoord[1]);
382 distR2 = (tmpRx - inGloCoord[0]) * (tmpRx - inGloCoord[0]) +
383 (tmpRy - inGloCoord[1]) * (tmpRy - inGloCoord[1]);
384
385 if (distL2 >= distR2)
386 {
387 etaLR[0] = 0.5 * (etaLR[0] + etaLR[1]);
388 }
389 else
390 {
391 etaLR[1] = 0.5 * (etaLR[0] + etaLR[1]);
392 }
393
394 if ((etaLR[1] - etaLR[0]) < iterTol)
395 {
396 locCoord[0] = 0.5 * (etaLR[0] + etaLR[1]);
397 gloCoord[0] = 0.5 * (tmpLx + tmpRx);
398 gloCoord[1] = 0.5 * (tmpLy + tmpRy);
399 dist = sqrt(0.5 * (distL2 + distR2));
400 isConverge = true;
401 break;
402 }
403
404 ++cnt;
405 }
406
407 // Warning if failed
408 if (cnt >= iterMax)
409 {
410 WARNINGL1(false, "Bisection iteration is not converged");
411 }
412
413 return isConverge;
414}

References tinysimd::sqrt(), and WARNINGL1.

Referenced by LocCoordForNearestPntOnBndElmt().

◆ PntToBndElmtPntDistance()

NekDouble Nektar::FieldUtils::ProcessBodyFittedVelocity::PntToBndElmtPntDistance ( const Array< OneD, Array< OneD, NekDouble > > &  pts,
const int  pId,
const Array< OneD, Array< OneD, NekDouble > > &  bndPts 
)
private

Compute the local coordinate for the nearest point on the given 2D boundary element to the input point.

Compute the point-to-point distance to find the estimated cloest element.

Parameters
inGloCoordGlobal coordinate for the input point.
bndGeomGeometry of the boundary element to search from.
ptsGlobal coordinate of the quadrature points in the boundary element.
locCoordLocal coordinate of the result.
gloCoordGlobal coordinate of the result.
distDistance from the input point to the boundary element.
iterTolIteration tolerence.
iterMaxMax iteration steps.
ptsGlobal coordinate of the quadrature points in the inner element.
pIdId of the inner point of interest in the current loop.
bndPtsGlobal coordinate of the quadrature points in the boundary element.

Definition at line 313 of file ProcessBodyFittedVelocity.cpp.

316{
317 const int nCoordDim = pts.size();
318
319 NekDouble dist = 9999, dist_tmp;
320
321 for (int i = 0; i < bndPts[0].size(); ++i)
322 {
323 // Compute distance
324 dist_tmp = 0.0;
325 for (int j = 0; j < nCoordDim; ++j)
326 {
327 dist_tmp +=
328 (bndPts[j][i] - pts[j][pId]) * (bndPts[j][i] - pts[j][pId]);
329 }
330 dist_tmp = sqrt(dist_tmp);
331
332 if (dist_tmp < dist)
333 {
334 dist = dist_tmp;
335 }
336 }
337
338 return dist;
339}

References tinysimd::sqrt().

Referenced by GenPntwiseBodyFittedCoordSys().

◆ ScaledCrosssProduct()

void Nektar::FieldUtils::ProcessBodyFittedVelocity::ScaledCrosssProduct ( const Array< OneD, NekDouble > &  vec1,
const Array< OneD, NekDouble > &  vec2,
Array< OneD, NekDouble > &  vec3 
)
private

Compute the normalized cross product for two 2D vectors. vec3 = vec1 x vec2.

Definition at line 470 of file ProcessBodyFittedVelocity.cpp.

473{
474 vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
475 vec3[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
476 vec3[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
477
478 NekDouble coef;
479 coef =
480 1.0 / sqrt(vec3[0] * vec3[0] + vec3[1] * vec3[1] + vec3[2] * vec3[2]);
481
482 vec3[0] = vec3[0] * coef;
483 vec3[1] = vec3[1] * coef;
484 vec3[2] = vec3[2] * coef;
485}

References tinysimd::sqrt().

Referenced by GenPntwiseBodyFittedCoordSys().

◆ v_GetModuleDescription()

std::string Nektar::FieldUtils::ProcessBodyFittedVelocity::v_GetModuleDescription ( )
inlineoverrideprotectedvirtual

Reimplemented from Nektar::FieldUtils::Module.

Definition at line 70 of file ProcessBodyFittedVelocity.h.

71 {
72 return "Get velocity in the body-fitted coordinate system.";
73 }

◆ v_GetModuleName()

std::string Nektar::FieldUtils::ProcessBodyFittedVelocity::v_GetModuleName ( )
inlineoverrideprotectedvirtual

Reimplemented from Nektar::FieldUtils::Module.

Definition at line 65 of file ProcessBodyFittedVelocity.h.

66 {
67 return "ProcessBodyFittedVelocity";
68 }

◆ v_Process()

void Nektar::FieldUtils::ProcessBodyFittedVelocity::v_Process ( po::variables_map &  vm)
overrideprotectedvirtual

Write mesh to output file.

Reimplemented from Nektar::FieldUtils::Module.

Definition at line 115 of file ProcessBodyFittedVelocity.cpp.

116{
118
119 // Get dim to store data
120 const int nFields = m_f->m_variables.size();
121 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0);
122 const int nSpaceDim = nCoordDim + m_f->m_numHomogeneousDir;
123 const int nAddFields = nSpaceDim + 1; // distanceToWall, u_bfc, v_bfc, w_bfc
124
125 // Tolerence setting
126 // To include more elmts for further check
127 const NekDouble distTol = m_config["distTol"].as<NekDouble>();
128 const NekDouble geoTol = 1.0e-12; // To check if two pnts are too close
129 const NekDouble dirTol = 1.0e-4; // To check if two unit vecs are parallel
130 const NekDouble iterTol = 1.0e-12; // To check if locCoord iter convergence
131
132 const bool isCheckAngle = m_config["checkAngle"].as<bool>();
133 const bool isOutputBfc = m_config["bfcOut"].as<bool>();
134
135 // Get the assist vector
136 vector<NekDouble> assistDir;
137 ASSERTL0(ParseUtils::GenerateVector(m_config["assistDir"].as<string>(),
138 assistDir),
139 "Failed to interpret assistance direction");
140
141 Array<OneD, NekDouble> assistVec(3); // Save the assist vector
142 for (int i = 0; i < 3; ++i)
143 {
144 assistVec[i] = (assistDir.size() > i) ? assistDir[i] : 0.0;
145 }
146 if (nCoordDim == 2)
147 {
148 assistVec[0] = 0.0;
149 assistVec[1] = 0.0;
150 }
151
152 NekDouble norm = sqrt(Vmath::Dot(3, assistVec, 1, assistVec, 1));
153 if (norm < geoTol)
154 {
155 ASSERTL0(false, "Error. The amplitude of assist vector is smaller than \
156 the geometry tolerence 1.0e-12.");
157 }
158 Vmath::Smul(3, 1.0 / norm, assistVec, 1, assistVec, 1);
159
160 // Get the bnd id
161 // We only use the first one [0], check ProcessBoundaryExtract for more info
162 SpatialDomains::BoundaryConditions bcs(m_f->m_session,
163 m_f->m_exp[0]->GetGraph());
165 bcs.GetBoundaryRegions();
166 map<int, int> BndRegionMap;
167 int cnt = 0;
168 for (auto &breg_it : bregions)
169 {
170 BndRegionMap[breg_it.first] = cnt++;
171 }
172 int bnd = BndRegionMap[m_f->m_bndRegionsToWrite[0]];
173
174 // Generate the distance array and three arrays for directional vectors
175 // bfcsDir[i][j][k]
176 // i - dir vec: 0-main tangential, 1-normal, (2-minor tangential)
177 // j - component: 0-x, 1-y, (2-z)
178 // k - point id
179 int npoints = m_f->m_exp[0]->GetNpoints();
180 Array<OneD, NekDouble> distance(npoints, 9999);
181 Array<OneD, Array<OneD, Array<OneD, NekDouble>>> bfcsDir(nSpaceDim);
182 for (int i = 0; i < nSpaceDim; ++i)
183 {
184 bfcsDir[i] = Array<OneD, Array<OneD, NekDouble>>(nSpaceDim);
185
186 for (int j = 0; j < nSpaceDim; ++j)
187 {
188 bfcsDir[i][j] = Array<OneD, NekDouble>(npoints);
189 }
190 }
191
192 // Key function. At each quadrature point inside the domian, compute the
193 // body-fitted coordinate system with respect to the input bnd id
194 GenPntwiseBodyFittedCoordSys(bnd, assistVec, distance, bfcsDir,
195 isCheckAngle, distTol, iterTol, dirTol,
196 geoTol);
197
198 // Compute the velocity
199 Array<OneD, Array<OneD, NekDouble>> vel_car(nSpaceDim); // Cartesian
200 Array<OneD, Array<OneD, NekDouble>> vel_bfc(nSpaceDim); // body-fiitted
201 Array<OneD, NekDouble> vel_tmp(npoints);
202
203 for (int i = 0; i < nSpaceDim; ++i)
204 {
205 vel_bfc[i] = Array<OneD, NekDouble>(npoints, 0.0);
206 }
207
208 // Get the velocity in Cartesian coordinate system
210
211 // Project the velocity into the body-fitted coordinate system
212 for (int i = 0; i < nSpaceDim; ++i) // loop for bfc velocity
213 {
214 for (int j = 0; j < nSpaceDim; ++j)
215 {
216 Vmath::Vmul(npoints, vel_car[j], 1, bfcsDir[i][j], 1, vel_tmp, 1);
217 Vmath::Vadd(npoints, vel_tmp, 1, vel_bfc[i], 1, vel_bfc[i], 1);
218 }
219 }
220
221 // Add var names
222 m_f->m_variables.push_back("distanceToWall");
223 m_f->m_variables.push_back("u_bfc");
224 m_f->m_variables.push_back("v_bfc");
225 if (nSpaceDim == 3)
226 {
227 m_f->m_variables.push_back("w_bfc");
228 }
229 else if (nSpaceDim == 1)
230 {
231 ASSERTL0(false, "Velocity in 1D case is already in the body fitted \
232 coordinate. The dimension should be 2 or 3.");
233 }
234
235 // Add the new fields (distance + u,v,w_bfc)
236 // copy distance
237 m_f->m_exp.resize(nFields + nAddFields);
238
239 m_f->m_exp[nFields] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
240 Vmath::Vcopy(npoints, distance, 1, m_f->m_exp[nFields]->UpdatePhys(), 1);
241 m_f->m_exp[nFields]->FwdTransLocalElmt(distance,
242 m_f->m_exp[nFields]->UpdateCoeffs());
243
244 // copy vel_bfc
245 for (int i = 1; i < nAddFields; ++i)
246 {
247 m_f->m_exp[nFields + i] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
248 Vmath::Vcopy(npoints, vel_bfc[i - 1], 1,
249 m_f->m_exp[nFields + i]->UpdatePhys(), 1);
250 m_f->m_exp[nFields + i]->FwdTransLocalElmt(
251 vel_bfc[i - 1], m_f->m_exp[nFields + i]->UpdateCoeffs());
252 }
253
254 // Output the the body-fitted coordinate into the file
255 // The filter will read the coordiante through file
256 // bfcsDir[i][j][k]
257 // i - dir vec: 0-main tangential, 1-normal, (2-minor tangential)
258 // j - component: 0-x, 1-y, (2-z)
259 // k - point id
260 if (isOutputBfc)
261 {
262 m_f->m_variables.push_back("bfc_dir0_x");
263 m_f->m_variables.push_back("bfc_dir0_y");
264 if (nSpaceDim == 3)
265 {
266 m_f->m_variables.push_back("bfc_dir0_z");
267 }
268 m_f->m_variables.push_back("bfc_dir1_x");
269 m_f->m_variables.push_back("bfc_dir1_y");
270 if (nSpaceDim == 3)
271 {
272 m_f->m_variables.push_back("bfc_dir1_z");
273
274 m_f->m_variables.push_back("bfc_dir2_x");
275 m_f->m_variables.push_back("bfc_dir2_y");
276 m_f->m_variables.push_back("bfc_dir2_z");
277 }
278
279 int nAddFields_coord = (nSpaceDim == 3) ? 9 : 4;
280 m_f->m_exp.resize(nFields + nAddFields + nAddFields_coord);
281
282 cnt = 0;
283 for (int i = 0; i < nSpaceDim; ++i)
284 {
285 for (int j = 0; j < nSpaceDim; ++j)
286 {
287
288 m_f->m_exp[nFields + nAddFields + cnt] =
289 m_f->AppendExpList(m_f->m_numHomogeneousDir);
290
292 npoints, bfcsDir[i][j], 1,
293 m_f->m_exp[nFields + nAddFields + cnt]->UpdatePhys(), 1);
294 m_f->m_exp[nFields + nAddFields + cnt]->FwdTransLocalElmt(
295 bfcsDir[i][j],
296 m_f->m_exp[nFields + nAddFields + cnt]->UpdateCoeffs());
297
298 ++cnt;
299 }
300 }
301 }
302}
void GenPntwiseBodyFittedCoordSys(const int targetBndId, const Array< OneD, NekDouble > assistVec, Array< OneD, NekDouble > &distance, Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &bfcsDir, const bool isCheckAngle, const NekDouble distTol=1.0e-12, const NekDouble iterTol=1.0e-12, const NekDouble dirTol=1.0e-4, const NekDouble geoTol=1.0e-12)
At each quadrature point inside the domian, compute the body-fitted coordinate system with respect to...
void GetVelAndConvertToCartSys(Array< OneD, Array< OneD, NekDouble > > &vel)
Get velocity and convert to Cartesian system, if it is still in transformed system....
void v_Process(po::variables_map &vm) override
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
Definition: ParseUtils.cpp:130
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:210
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.hpp:72

References ASSERTL0, Vmath::Dot(), Nektar::ParseUtils::GenerateVector(), GenPntwiseBodyFittedCoordSys(), Nektar::SpatialDomains::BoundaryConditions::GetBoundaryRegions(), GetVelAndConvertToCartSys(), Nektar::FieldUtils::Module::m_config, Nektar::FieldUtils::Module::m_f, Vmath::Smul(), tinysimd::sqrt(), Nektar::FieldUtils::ProcessBoundaryExtract::v_Process(), Vmath::Vadd(), Vmath::Vcopy(), and Vmath::Vmul().

Member Data Documentation

◆ className

ModuleKey Nektar::FieldUtils::ProcessBodyFittedVelocity::className
static
Initial value:
=
ModuleKey(eProcessModule, "bodyFittedVelocity"),
"Convert the velocity components from the Cartesian coordinate into "
"the body-fitted coordinate.")
static std::shared_ptr< Module > create(FieldSharedPtr f)
Creates an instance of this class.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:197
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:180
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:47

Definition at line 56 of file ProcessBodyFittedVelocity.h.