From 081b9e08ab22e66126d294643b7cdae66d2301af Mon Sep 17 00:00:00 2001 From: Lukas Werner <lks.werner@fau.de> Date: Fri, 16 Oct 2020 09:50:08 +0200 Subject: [PATCH] LBM: Q criterion, curl and vorticity calculation and vtk output --- src/lbm/field/MacroscopicValueCalculation.h | 17 +++ src/lbm/field/QCriterion.h | 99 +++++++++++++++++ src/lbm/field/QCriterionFieldWriter.h | 78 +++++++++++++ src/lbm/field/Vorticity.h | 89 +++++++++++++++ src/lbm/vtk/CurlMagnitude.h | 114 +++++++++++++++++++ src/lbm/vtk/QCriterion.h | 72 ++++++++++++ src/lbm/vtk/QCriterionCellFilter.h | 77 +++++++++++++ src/lbm/vtk/VelocityCellFilter.h | 76 +++++++++++++ src/lbm/vtk/Vorticity.h | 81 ++++++++++++++ src/lbm/vtk/all.h | 6 +- tests/lbm/CMakeLists.txt | 3 + tests/lbm/field/QCriterionTest.cpp | 116 ++++++++++++++++++++ 12 files changed, 827 insertions(+), 1 deletion(-) create mode 100644 src/lbm/field/QCriterion.h create mode 100644 src/lbm/field/QCriterionFieldWriter.h create mode 100644 src/lbm/field/Vorticity.h create mode 100644 src/lbm/vtk/CurlMagnitude.h create mode 100644 src/lbm/vtk/QCriterion.h create mode 100644 src/lbm/vtk/QCriterionCellFilter.h create mode 100644 src/lbm/vtk/VelocityCellFilter.h create mode 100644 src/lbm/vtk/Vorticity.h create mode 100644 tests/lbm/field/QCriterionTest.cpp diff --git a/src/lbm/field/MacroscopicValueCalculation.h b/src/lbm/field/MacroscopicValueCalculation.h index dae0a43cb..50059b370 100644 --- a/src/lbm/field/MacroscopicValueCalculation.h +++ b/src/lbm/field/MacroscopicValueCalculation.h @@ -27,6 +27,8 @@ #include "Equilibrium.h" #include "ShearRate.h" #include "PressureTensor.h" +#include "QCriterion.h" +#include "Vorticity.h" #include "core/DataTypes.h" #include "core/math/Vector3.h" @@ -433,6 +435,21 @@ inline void getPressureTensor( Matrix3< real_t > & pressureTensor, const Lattice } +template< typename VelocityField_T, typename Filter_T > +inline real_t getQCriterion(const VelocityField_T &velocityField, const Filter_T &filter, + const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, + real_t dx = real_t(1), real_t dy = real_t(1), real_t dz = real_t(1)) { + return QCriterion::get(velocityField, filter, x, y, z, dx, dy, dz); +} + +template< typename VelocityField_T, typename Filter_T > +inline Vector3<real_t> getVorticity(const VelocityField_T &velocityField, const Filter_T &filter, + const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, + real_t dx = real_t(1), real_t dy = real_t(1), real_t dz = real_t(1)) { + return Vorticity::get(velocityField, filter, x, y, z, dx, dy, dz); +} + + } // namespace lbm } // namespace walberla diff --git a/src/lbm/field/QCriterion.h b/src/lbm/field/QCriterion.h new file mode 100644 index 000000000..c399218de --- /dev/null +++ b/src/lbm/field/QCriterion.h @@ -0,0 +1,99 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QCriterion.h +//! \ingroup lbm +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/DataTypes.h" +#include "core/math/Vector3.h" + +#include "lbm/lattice_model/CollisionModel.h" +#include "lbm/lattice_model/EquilibriumDistribution.h" + +#include <type_traits> + + + +// Back-end for calculating macroscopic values +// You should never use these functions directly, always refer to the member functions +// of PdfField or the free functions that can be found in MacroscopicValueCalculation.h + +namespace walberla { +namespace lbm { + +struct QCriterion { + template< typename VelocityField_T, typename Filter_T > + static inline real_t get(const VelocityField_T & velocityField, const Filter_T & filter, + const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, + real_t dx = real_t(1), real_t dy = real_t(1), real_t dz = real_t(1)) { + const auto one = cell_idx_t(1); + + if(filter(x,y,z) && filter(x+one,y,z) && filter(x-one,y,z) && filter(x,y+one,z) + && filter(x,y-one,z) && filter(x,y,z+one) && filter(x,y,z-one)) { + const Vector3<real_t> xa = velocityField.get(x+one,y,z); + const Vector3<real_t> xb = velocityField.get(x-one,y,z); + const Vector3<real_t> ya = velocityField.get(x,y+one,z); + const Vector3<real_t> yb = velocityField.get(x,y-one,z); + const Vector3<real_t> za = velocityField.get(x,y,z+one); + const Vector3<real_t> zb = velocityField.get(x,y,z-one); + + return calculate(xa, xb, ya, yb, za, zb, dx, dy, dz); + } + + return real_t(0); + } + + static inline real_t calculate(const Vector3<real_t> xa, const Vector3<real_t> xb, + const Vector3<real_t> ya, const Vector3<real_t> yb, + const Vector3<real_t> za, const Vector3<real_t> zb, + const real_t dx, const real_t dy, const real_t dz) { + + const auto halfInvDx = real_t(0.5) / dx; + const auto halfInvDy = real_t(0.5) / dy; + const auto halfInvDz = real_t(0.5) / dz; + + const real_t duxdx = (xa[0] - xb[0]) * halfInvDx; + const real_t duxdy = (ya[0] - yb[0]) * halfInvDy; + const real_t duxdz = (za[0] - zb[0]) * halfInvDz; + + const real_t duydx = (xa[1] - xb[1]) * halfInvDx; + const real_t duydy = (ya[1] - yb[1]) * halfInvDy; + const real_t duydz = (za[1] - zb[1]) * halfInvDz; + + const real_t duzdx = (xa[2] - xb[2]) * halfInvDx; + const real_t duzdy = (ya[2] - yb[2]) * halfInvDy; + const real_t duzdz = (za[2] - zb[2]) * halfInvDz; + + // Q = 1/2 * (||W||² - ||S||²) + real_t sNormSq = duxdx*duxdx + duydy*duydy + duzdz*duzdz + + real_t(0.5)*(duxdy+duydx)*(duxdy+duydx) + real_t(0.5)*(duydz+duzdy)*(duydz+duzdy) + + real_t(0.5)*(duxdz+duzdx)*(duxdz+duzdx); + + real_t omegaNormSq = real_t(0.5)*(duxdz-duzdx)*(duxdz-duzdx) + + real_t(0.5)*(duxdy-duydx)*(duxdy-duydx) + + real_t(0.5)*(duydz-duzdy)*(duydz-duzdy); + + return real_t(0.5) * (omegaNormSq - sNormSq); + } +}; + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/field/QCriterionFieldWriter.h b/src/lbm/field/QCriterionFieldWriter.h new file mode 100644 index 000000000..9948ea9ec --- /dev/null +++ b/src/lbm/field/QCriterionFieldWriter.h @@ -0,0 +1,78 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VelocityFieldWriter.h +//! \ingroup lbm +//! \author Florian Schornbaum <florian.schornbaum@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/DataTypes.h" +#include "core/math/Vector3.h" +#include "domain_decomposition/BlockDataID.h" +#include "domain_decomposition/IBlock.h" +#include "domain_decomposition/StructuredBlockStorage.h" +#include "field/iterators/IteratorMacros.h" +#include "lbm/field/QCriterion.h" + +namespace walberla { +namespace lbm { + +template< typename VelocityField_T, typename QCriterionField_T, typename Filter_T > +class QCriterionFieldWriter { +public: + QCriterionFieldWriter(const shared_ptr<StructuredBlockStorage> & blockStorage, const ConstBlockDataID & velocityFieldId, + const BlockDataID & qCriterionFieldId, Filter_T & filter) : + blockStorage_(blockStorage), velocityFieldId_(velocityFieldId), qCriterionFieldId_(qCriterionFieldId), + filter_(filter) + {} + + void operator()(IBlock * const block) { + const VelocityField_T* velocityField = block->template getData<VelocityField_T>(velocityFieldId_); + QCriterionField_T* qCriterionField = block->template getData<QCriterionField_T>(qCriterionFieldId_); + + WALBERLA_ASSERT_EQUAL(velocityField->xyzSize(), qCriterionField->xyzSize()); + + const real_t dx = blockStorage_->dx(blockStorage_->getLevel(*block)); + const real_t dy = blockStorage_->dy(blockStorage_->getLevel(*block)); + const real_t dz = blockStorage_->dz(blockStorage_->getLevel(*block)); + + filter_(*block); + + WALBERLA_FOR_ALL_CELLS_XYZ(velocityField, + store(velocityField, qCriterionField, x, y, z, dx, dy, dz); + ) + } + +private: + + void store(const VelocityField_T* velocityField, QCriterionField_T* qCriterionField, + const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, + const real_t dx, const real_t dy, const real_t dz) { + qCriterionField->get(x,y,z,0) = QCriterion::get(*velocityField, filter_, x, y, z, dx, dy, dz); + } + + const shared_ptr<StructuredBlockStorage> blockStorage_; + ConstBlockDataID velocityFieldId_; + BlockDataID qCriterionFieldId_; + Filter_T & filter_; +}; + + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/field/Vorticity.h b/src/lbm/field/Vorticity.h new file mode 100644 index 000000000..7766ddb3b --- /dev/null +++ b/src/lbm/field/Vorticity.h @@ -0,0 +1,89 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QCriterion.h +//! \ingroup lbm +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "core/DataTypes.h" +#include "core/math/Vector3.h" + +#include "lbm/lattice_model/CollisionModel.h" +#include "lbm/lattice_model/EquilibriumDistribution.h" + +#include <type_traits> + + + +// Back-end for calculating macroscopic values +// You should never use these functions directly, always refer to the member functions +// of PdfField or the free functions that can be found in MacroscopicValueCalculation.h + +namespace walberla { +namespace lbm { + +struct Vorticity { + template< typename VelocityField_T, typename Filter_T > + static inline Vector3<real_t> get(const VelocityField_T & velocityField, const Filter_T & filter, + const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, + real_t dx = real_t(1), real_t dy = real_t(1), real_t dz = real_t(1)) { + const auto one = cell_idx_t(1); + + if(filter(x,y,z) && filter(x+one,y,z) && filter(x-one,y,z) && filter(x,y+one,z) + && filter(x,y-one,z) && filter(x,y,z+one) && filter(x,y,z-one)) { + const Vector3<real_t> xa = velocityField.get(x+one,y,z); + const Vector3<real_t> xb = velocityField.get(x-one,y,z); + const Vector3<real_t> ya = velocityField.get(x,y+one,z); + const Vector3<real_t> yb = velocityField.get(x,y-one,z); + const Vector3<real_t> za = velocityField.get(x,y,z+one); + const Vector3<real_t> zb = velocityField.get(x,y,z-one); + + return calculate(xa, xb, ya, yb, za, zb, dx, dy, dz); + } + + return Vector3<real_t>(real_t(0)); + } + + static inline Vector3<real_t> calculate(const Vector3<real_t> xa, const Vector3<real_t> xb, + const Vector3<real_t> ya, const Vector3<real_t> yb, + const Vector3<real_t> za, const Vector3<real_t> zb, + const real_t dx, const real_t dy, const real_t dz) { + + const auto halfInvDx = real_t(0.5) / dx; + const auto halfInvDy = real_t(0.5) / dy; + const auto halfInvDz = real_t(0.5) / dz; + + const real_t duxdy = (ya[0] - yb[0]) * halfInvDy; + const real_t duxdz = (za[0] - zb[0]) * halfInvDz; + + const real_t duydx = (xa[1] - xb[1]) * halfInvDx; + const real_t duydz = (za[1] - zb[1]) * halfInvDz; + + const real_t duzdx = (xa[2] - xb[2]) * halfInvDx; + const real_t duzdy = (ya[2] - yb[2]) * halfInvDy; + + const Vector3< real_t > curl( duzdy - duydz, duxdz - duzdx, duydx - duxdy ); + + return curl; + } +}; + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/vtk/CurlMagnitude.h b/src/lbm/vtk/CurlMagnitude.h new file mode 100644 index 000000000..0aa89feab --- /dev/null +++ b/src/lbm/vtk/CurlMagnitude.h @@ -0,0 +1,114 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Velocity.h +//! \ingroup lbm +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "lbm/field/PdfField.h" +#include "core/debug/Debug.h" +#include "vtk/BlockCellDataWriter.h" + + +namespace walberla { +namespace lbm { + +/** + * lengthScaleWeight is only used to be able to derive quantities for the adaptive mesh refinement criterium of curl. + * + * @tparam VelocityField_T + * @tparam Filter_T + * @tparam OutputType + */ +template< typename VelocityField_T, typename Filter_T, typename OutputType = float > +class CurlMagnitudeVTKWriter : public vtk::BlockCellDataWriter< OutputType, 1 > +{ +public: + CurlMagnitudeVTKWriter(const shared_ptr<StructuredBlockStorage> blockStorage, Filter_T & filter, + const ConstBlockDataID & velocityFieldId, const std::string & id, const real_t lengthScaleWeight = real_t(-1)) : + vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter), + velocityFieldId_(velocityFieldId), velocityField_(NULL), lengthScaleWeight_(lengthScaleWeight) {} + +protected: + + void configure() { + WALBERLA_ASSERT_NOT_NULLPTR( this->block_ ); + velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ ); + } + + OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) + { + WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ ); + + const real_t dx = blockStorage_->dx(blockStorage_->getLevel(*this->block_)); + const real_t dy = blockStorage_->dy(blockStorage_->getLevel(*this->block_)); + const real_t dz = blockStorage_->dz(blockStorage_->getLevel(*this->block_)); + + filter_(*this->block_); + + const auto one = cell_idx_t(1); + + const auto halfInvDx = real_t(0.5) * real_t(1) / dx; + const auto halfInvDy = real_t(0.5) * real_t(1) / dy; + const auto halfInvDz = real_t(0.5) * real_t(1) / dz; + + const real_t lengthScale = std::cbrt(dx*dy*dz); + const real_t weightedLengthScale = !realIsIdentical(lengthScaleWeight_, real_t(-1)) ? + std::pow(lengthScale, (lengthScaleWeight_+1)/lengthScaleWeight_) : real_t(1); + + if(filter_(x,y,z) && filter_(x+one,y,z) && filter_(x-one,y,z) && filter_(x,y+one,z) + && filter_(x,y-one,z) && filter_(x,y,z+one) && filter_(x,y,z-one)) { + const Vector3< real_t > xa = velocityField_->get(x+one,y,z); + const Vector3< real_t > xb = velocityField_->get(x-one,y,z); + const Vector3< real_t > ya = velocityField_->get(x,y+one,z); + const Vector3< real_t > yb = velocityField_->get(x,y-one,z); + const Vector3< real_t > za = velocityField_->get(x,y,z+one); + const Vector3< real_t > zb = velocityField_->get(x,y,z-one); + + const real_t duxdy = (ya[0] - yb[0]) * halfInvDy; + const real_t duxdz = (za[0] - zb[0]) * halfInvDz; + + const real_t duydx = (xa[1] - xb[1]) * halfInvDx; + const real_t duydz = (za[1] - zb[1]) * halfInvDz; + + const real_t duzdx = (xa[2] - xb[2]) * halfInvDx; + const real_t duzdy = (ya[2] - yb[2]) * halfInvDy; + + const Vector3< real_t > curl( duzdy - duydz, duxdz - duzdx, duydx - duxdy ); + const auto curlMag = curl.length(); + + const auto curlSensor = curlMag * weightedLengthScale; + + return numeric_cast< OutputType >(curlSensor); + } + + return numeric_cast< OutputType >(0); + } + + const shared_ptr<StructuredBlockStorage> blockStorage_; + Filter_T filter_; + const ConstBlockDataID velocityFieldId_; + const VelocityField_T* velocityField_; + const real_t lengthScaleWeight_; +}; + + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/vtk/QCriterion.h b/src/lbm/vtk/QCriterion.h new file mode 100644 index 000000000..e3b2748ec --- /dev/null +++ b/src/lbm/vtk/QCriterion.h @@ -0,0 +1,72 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QCriterion.h +//! \ingroup lbm +//! \author Florian Schornbaum <florian.schornbaum@fau.de> +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "lbm/field/PdfField.h" +#include "lbm/field/MacroscopicValueCalculation.h" +#include "core/debug/Debug.h" +#include "vtk/BlockCellDataWriter.h" + + +namespace walberla { +namespace lbm { + + +template< typename VelocityField_T, typename Filter_T, typename OutputType = float > +class QCriterionVTKWriter : public vtk::BlockCellDataWriter< OutputType, 1 > +{ +public: + QCriterionVTKWriter(const shared_ptr<StructuredBlockStorage> blockStorage, Filter_T & filter, + const ConstBlockDataID & velocityFieldId, const std::string & id ) : + vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter), velocityFieldId_(velocityFieldId), velocityField_(NULL) {} + +protected: + + void configure() { + WALBERLA_ASSERT_NOT_NULLPTR( this->block_ ); + velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ ); + } + + OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) + { + WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ ); + + const real_t dx = blockStorage_->dx(blockStorage_->getLevel(*this->block_)); + const real_t dy = blockStorage_->dy(blockStorage_->getLevel(*this->block_)); + const real_t dz = blockStorage_->dz(blockStorage_->getLevel(*this->block_)); + + filter_(*this->block_); + + return numeric_cast<OutputType>(getQCriterion(*velocityField_, filter_, x, y, z, dx, dy, dz)); + } + + const shared_ptr<StructuredBlockStorage> blockStorage_; + Filter_T filter_; + const ConstBlockDataID velocityFieldId_; + const VelocityField_T* velocityField_; +}; + + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/vtk/QCriterionCellFilter.h b/src/lbm/vtk/QCriterionCellFilter.h new file mode 100644 index 000000000..5310bc172 --- /dev/null +++ b/src/lbm/vtk/QCriterionCellFilter.h @@ -0,0 +1,77 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QValueCellFilter.h +//! \ingroup field +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "field/FlagField.h" +#include "core/cell/CellSet.h" +#include "core/debug/Debug.h" +#include "domain_decomposition/StructuredBlockStorage.h" +#include "lbm/field/PdfField.h" +#include "lbm/field/MacroscopicValueCalculation.h" + + +namespace walberla { +namespace field { + +template< typename VelocityField_T, typename Filter_T > +class QCriterionCellFilter { +public: + QCriterionCellFilter(const ConstBlockDataID velocityFieldId, Filter_T & filter, real_t lowerLimit, + real_t upperLimit = std::numeric_limits<real_t>::infinity()) + : velocityFieldId_(velocityFieldId), filter_(filter), lowerLimit_(lowerLimit), upperLimit_(upperLimit) {} + + void operator()( CellSet& filteredCells, const IBlock& block, const StructuredBlockStorage& storage, + const uint_t ghostLayers = uint_t(0) ) { + const VelocityField_T* velocityField = block.getData< VelocityField_T >( velocityFieldId_ ); + WALBERLA_CHECK_NOT_NULLPTR(velocityField); + + const real_t dx = storage.dx(storage.getLevel(block)); + const real_t dy = storage.dy(storage.getLevel(block)); + const real_t dz = storage.dz(storage.getLevel(block)); + + filter_(block); + + const cell_idx_t gl = cell_idx_c(ghostLayers); + const cell_idx_t begin = cell_idx_c(-1) * gl; + + for (cell_idx_t z = begin; z < cell_idx_c(storage.getNumberOfZCells(block))+gl; ++z) { + for (cell_idx_t y = begin; y < cell_idx_c(storage.getNumberOfYCells(block))+gl; ++y) { + for (cell_idx_t x = begin; x < cell_idx_c(storage.getNumberOfXCells(block))+gl; ++x) { + real_t q = lbm::getQCriterion(*velocityField, filter_, x, y, z, dx, dy, dz); + + if (q >= lowerLimit_ && q <= upperLimit_) { + filteredCells.insert(x,y,z); + } + } + } + } + } + +private: + const ConstBlockDataID velocityFieldId_; + Filter_T filter_; + real_t lowerLimit_; + real_t upperLimit_; +}; + +} // namespace field +} // namespace walberla diff --git a/src/lbm/vtk/VelocityCellFilter.h b/src/lbm/vtk/VelocityCellFilter.h new file mode 100644 index 000000000..0e290db21 --- /dev/null +++ b/src/lbm/vtk/VelocityCellFilter.h @@ -0,0 +1,76 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VectorFieldCellFilter.h +//! \ingroup field +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "field/FlagField.h" +#include "core/cell/CellSet.h" +#include "core/debug/Debug.h" +#include "domain_decomposition/StructuredBlockStorage.h" +#include "lbm/field/PdfField.h" + + +namespace walberla { +namespace field { + +template< typename PdfField_T, typename Filter_T > +class VelocityCellFilter { +public: + VelocityCellFilter(const ConstBlockDataID pdfFieldId, Filter_T & filter, real_t lowerLimit, + real_t upperLimit = std::numeric_limits<real_t>::infinity()) + : pdfFieldId_(pdfFieldId), filter_(filter), lowerLimit_(lowerLimit), upperLimit_(upperLimit) {} + + void operator()( CellSet& filteredCells, const IBlock& block, const StructuredBlockStorage& storage, + const uint_t ghostLayers = uint_t(0) ) { + const PdfField_T* pdf = block.getData< PdfField_T >( pdfFieldId_ ); + WALBERLA_CHECK_NOT_NULLPTR(pdf); + + filter_(block); + + const cell_idx_t gl = cell_idx_c(ghostLayers); + const cell_idx_t begin = cell_idx_c(-1) * gl; + + for (cell_idx_t z = begin; z < cell_idx_c(storage.getNumberOfZCells(block))+gl; ++z) { + for (cell_idx_t y = begin; y < cell_idx_c(storage.getNumberOfYCells(block))+gl; ++y) { + for (cell_idx_t x = begin; x < cell_idx_c(storage.getNumberOfXCells(block))+gl; ++x) { + if (filter_(x,y,z)) { + const Vector3<real_t> value = pdf->getVelocity(x,y,z); + const real_t sqrLength = value.sqrLength(); + if (sqrLength > lowerLimit_*lowerLimit_ + && (realIsIdentical(upperLimit_, std::numeric_limits<real_t>::infinity()) + || sqrLength < upperLimit_*upperLimit_)) { + filteredCells.insert(x, y, z); + } + } + } + } + } + } + +private: + const ConstBlockDataID pdfFieldId_; + Filter_T filter_; + real_t lowerLimit_; + real_t upperLimit_; +}; + +} // namespace field +} // namespace walberla diff --git a/src/lbm/vtk/Vorticity.h b/src/lbm/vtk/Vorticity.h new file mode 100644 index 000000000..237b711d5 --- /dev/null +++ b/src/lbm/vtk/Vorticity.h @@ -0,0 +1,81 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Vorticity.h +//! \ingroup lbm +//! \author Florian Schornbaum <florian.schornbaum@fau.de> +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + +#pragma once + +#include "lbm/field/PdfField.h" +#include "lbm/field/MacroscopicValueCalculation.h" +#include "core/debug/Debug.h" +#include "vtk/BlockCellDataWriter.h" + + +namespace walberla { +namespace lbm { + + +template< typename VelocityField_T, typename Filter_T, typename OutputType = float > +class VorticityComponentVTKWriter : public vtk::BlockCellDataWriter< OutputType, 1 > +{ +public: + VorticityComponentVTKWriter(const shared_ptr<StructuredBlockStorage> blockStorage, Filter_T & filter, + const ConstBlockDataID & velocityFieldId, const uint_t componentIdx, const std::string & id, + const real_t normalizationConstant = real_t(1)) : + vtk::BlockCellDataWriter< OutputType, 1 >(id), blockStorage_(blockStorage), filter_(filter), + velocityFieldId_(velocityFieldId), componentIdx_(componentIdx), velocityField_(NULL), + normalizationConstant_(normalizationConstant) { + WALBERLA_ASSERT(componentIdx < uint_t(3), + "The vorticity vector only has three components, i.e. the highest possible component index is 2."); + } + +protected: + + void configure() { + WALBERLA_ASSERT_NOT_NULLPTR( this->block_ ); + velocityField_ = this->block_->template getData< VelocityField_T >(velocityFieldId_ ); + } + + OutputType evaluate( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z, const cell_idx_t /*f*/ ) { + WALBERLA_ASSERT_NOT_NULLPTR(velocityField_ ); + + const real_t dx = blockStorage_->dx(blockStorage_->getLevel(*this->block_)); + const real_t dy = blockStorage_->dy(blockStorage_->getLevel(*this->block_)); + const real_t dz = blockStorage_->dz(blockStorage_->getLevel(*this->block_)); + + filter_(*this->block_); + + Vector3<real_t> curl = getVorticity(*velocityField_, filter_, x, y, z, dx, dy, dz); + + return numeric_cast<OutputType>(curl[componentIdx_]/normalizationConstant_); + } + + const shared_ptr<StructuredBlockStorage> blockStorage_; + Filter_T filter_; + const ConstBlockDataID velocityFieldId_; + const uint_t componentIdx_; + const VelocityField_T* velocityField_; + const real_t normalizationConstant_; +}; + + + +} // namespace lbm +} // namespace walberla diff --git a/src/lbm/vtk/all.h b/src/lbm/vtk/all.h index 07ab8b35a..7f4285777 100644 --- a/src/lbm/vtk/all.h +++ b/src/lbm/vtk/all.h @@ -27,5 +27,9 @@ #include "Velocity.h" #include "VTKOutput.h" #include "PressureTensor.h" - +#include "QCriterion.h" +#include "Vorticity.h" +#include "CurlMagnitude.h" +#include "QCriterionCellFilter.h" +#include "VelocityCellFilter.h" diff --git a/tests/lbm/CMakeLists.txt b/tests/lbm/CMakeLists.txt index b9631921b..b17f65cfa 100644 --- a/tests/lbm/CMakeLists.txt +++ b/tests/lbm/CMakeLists.txt @@ -71,6 +71,9 @@ waLBerla_compile_test( FILES SuViscoelasticityTest.cpp DEPENDS field blockforest waLBerla_execute_test( NAME SuViscoelasticityLongTest COMMAND $<TARGET_FILE:SuViscoelasticityTest> ${CMAKE_CURRENT_SOURCE_DIR}/Su.prm LABELS longrun) waLBerla_execute_test( NAME SuViscoelasticityShortTest COMMAND $<TARGET_FILE:SuViscoelasticityTest> ${CMAKE_CURRENT_SOURCE_DIR}/Su.prm -Parameters.shortrun=true ) +waLBerla_compile_test( FILES field/QCriterionTest.cpp DEPENDS field blockforest ) +waLBerla_execute_test( NAME QCriterionTest ) + # Code Generation if( WALBERLA_BUILD_WITH_CODEGEN ) diff --git a/tests/lbm/field/QCriterionTest.cpp b/tests/lbm/field/QCriterionTest.cpp new file mode 100644 index 000000000..0e5dc2dd0 --- /dev/null +++ b/tests/lbm/field/QCriterionTest.cpp @@ -0,0 +1,116 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file QCriterionTest.cpp +//! \author Lukas Werner <lks.werner@fau.de> +// +//====================================================================================================================== + + +#include "blockforest/all.h" +#include "core/all.h" +#include "field/all.h" +#include "lbm/all.h" + +namespace walberla { + +class Filter { +public: + explicit Filter(uint_t numberOfCells) : numberOfCells_(numberOfCells) {} + + void operator()( const IBlock & /*block*/ ){ + + } + + bool operator()( const cell_idx_t x, const cell_idx_t y, const cell_idx_t z ) const { + return x >= -1 && x <= cell_idx_t(numberOfCells_) && + y >= -1 && y <= cell_idx_t(numberOfCells_) && + z >= -1 && z <= cell_idx_t(numberOfCells_); + } + +private: + uint_t numberOfCells_; +}; + +using VelocityField_T = GhostLayerField<Vector3<real_t>, 1>; +using FluidFilter_T = Filter; + +int main( int argc, char ** argv ) +{ + debug::enterTestMode(); + Environment env( argc, argv ); + + auto numberOfCells = uint_t(40); + + VelocityField_T velocityField(numberOfCells, numberOfCells, numberOfCells, uint_t(1)); + + FluidFilter_T filter(numberOfCells); + + //// initialize field + + real_t xv = 0, yv = 0, zv = 0; + + for (auto cellIt = velocityField.beginWithGhostLayerXYZ(); cellIt != velocityField.end(); ++cellIt) { + xv = math::realRandom<real_t>(real_t(-1), real_t(1)); + yv = math::realRandom<real_t>(real_t(-1), real_t(1)); + zv = math::realRandom<real_t>(real_t(-1), real_t(1)); + + *cellIt = Vector3<real_t>(real_t(xv), real_t(yv), real_t(zv)); + } + + //// evaluate field + + const auto one = cell_idx_t(1); + for (auto cellIt = velocityField.beginXYZ(); cellIt != velocityField.end(); ++cellIt) { + cell_idx_t x = cellIt.x(); + cell_idx_t y = cellIt.y(); + cell_idx_t z = cellIt.z(); + + // ParaView's formula serves as comparison. + // From: https://github.com/Kitware/VTK/blob/8b08cf7a0523d88a5602a98c0456f7e397560698/Filters/General/vtkGradientFilter.cxx + + const Vector3<real_t> xa = velocityField.get(x+one,y,z); + const Vector3<real_t> xb = velocityField.get(x-one,y,z); + const Vector3<real_t> ya = velocityField.get(x,y+one,z); + const Vector3<real_t> yb = velocityField.get(x,y-one,z); + const Vector3<real_t> za = velocityField.get(x,y,z+one); + const Vector3<real_t> zb = velocityField.get(x,y,z-one); + + const real_t duxdx = (xa[0] - xb[0]) * real_t(0.5); + const real_t duxdy = (ya[0] - yb[0]) * real_t(0.5); + const real_t duxdz = (za[0] - zb[0]) * real_t(0.5); + + const real_t duydx = (xa[1] - xb[1]) * real_t(0.5); + const real_t duydy = (ya[1] - yb[1]) * real_t(0.5); + const real_t duydz = (za[1] - zb[1]) * real_t(0.5); + + const real_t duzdx = (xa[2] - xb[2]) * real_t(0.5); + const real_t duzdy = (ya[2] - yb[2]) * real_t(0.5); + const real_t duzdz = (za[2] - zb[2]) * real_t(0.5); + + real_t q_paraview = -real_t(0.5)*(duxdx*duxdx + duydy*duydy + duzdz*duzdz) + -(duxdy*duydx + duxdz*duzdx + duydz*duzdy); + + WALBERLA_CHECK_FLOAT_EQUAL(q_paraview, lbm::getQCriterion(velocityField, filter, x, y, z)); + } + + return 0; +} +} + +int main( int argc, char ** argv ) +{ + return walberla::main(argc, argv); +} \ No newline at end of file -- GitLab