diff --git a/applications/FluidDynamicsApplication/CMakeLists.txt b/applications/FluidDynamicsApplication/CMakeLists.txt index 93200c86c11c..b8cc20bc34a8 100644 --- a/applications/FluidDynamicsApplication/CMakeLists.txt +++ b/applications/FluidDynamicsApplication/CMakeLists.txt @@ -18,6 +18,7 @@ set( KRATOS_FLUID_DYNAMICS_APPLICATION_CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/custom_utilities/statistics_record.cpp ${CMAKE_CURRENT_SOURCE_DIR}/custom_utilities/vorticity_utilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/custom_utilities/acceleration_limitation_utilities.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/custom_utilities/cfd_utilities.cpp # elements ${CMAKE_CURRENT_SOURCE_DIR}/custom_elements/vms.cpp diff --git a/applications/FluidDynamicsApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/FluidDynamicsApplication/custom_python/add_custom_utilities_to_python.cpp index 89674e8b0ef4..e4b42b6357f7 100644 --- a/applications/FluidDynamicsApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/FluidDynamicsApplication/custom_python/add_custom_utilities_to_python.cpp @@ -36,6 +36,7 @@ #include "custom_utilities/periodic_condition_utilities.h" #include "custom_utilities/compressible_element_rotation_utility.h" #include "custom_utilities/acceleration_limitation_utilities.h" +#include "custom_utilities/cfd_utilities.h" #include "utilities/split_tetrahedra.h" @@ -180,6 +181,15 @@ void AddCustomUtilitiesToPython(pybind11::module& m) .def("Execute", &AccelerationLimitationUtilities::Execute) ; + // Adding cfd utilities + m.def_submodule("CFDUtilities") + .def("CalculateNumberOfNeighbourConditions", &CFDUtilities::CalculateNumberOfNeighbourConditions) + .def("CalculateLinearLogarithmicWallFunctionBasedYPlusLimit", &CFDUtilities::CalculateLinearLogarithmicWallFunctionBasedYPlusLimit) + .def("CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau", &CFDUtilities::CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau) + .def("CalculateReactionBasedYPlusUTau", &CFDUtilities::CalculateReactionBasedYPlusUTau) + .def("CalculateYPlusAndUTauForConditionsBasedOnReaction", &CFDUtilities::CalculateYPlusAndUTauForConditionsBasedOnReaction) + .def("CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction", &CFDUtilities::CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction) + ; } } // namespace Python. diff --git a/applications/FluidDynamicsApplication/custom_python/fluid_dynamics_python_application.cpp b/applications/FluidDynamicsApplication/custom_python/fluid_dynamics_python_application.cpp index 617d4ccc75ef..c0d053de4574 100644 --- a/applications/FluidDynamicsApplication/custom_python/fluid_dynamics_python_application.cpp +++ b/applications/FluidDynamicsApplication/custom_python/fluid_dynamics_python_application.cpp @@ -108,6 +108,11 @@ PYBIND11_MODULE(KratosFluidDynamicsApplication,m) KRATOS_REGISTER_IN_PYTHON_VARIABLE(m,SHOCK_SENSOR); KRATOS_REGISTER_IN_PYTHON_VARIABLE(m,SHOCK_CAPTURING_VISCOSITY); KRATOS_REGISTER_IN_PYTHON_VARIABLE(m,SHOCK_CAPTURING_CONDUCTIVITY); + + // CFD Utility variables + KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, Y_PLUS); + KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, NUMBER_OF_NEIGHBOUR_CONDITIONS); + KRATOS_REGISTER_IN_PYTHON_VARIABLE(m, FRICTION_VELOCITY); } diff --git a/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp b/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp new file mode 100644 index 000000000000..3750f8251712 --- /dev/null +++ b/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp @@ -0,0 +1,386 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya (/~https://github.com/sunethwarna) +// + +// System includes +#include +#include + +// External includes + +// Project includes +#include "utilities/geometry_utilities.h" +#include "utilities/math_utils.h" +#include "utilities/parallel_utilities.h" +#include "utilities/variable_utils.h" + +// Application includes +#include "fluid_dynamics_application_variables.h" + +// Include base h +#include "cfd_utilities.h" + +namespace Kratos +{ +namespace CFDUtilities +{ +void CalculateConditionGeometryData( + const GeometryType& rGeometry, + const GeometryData::IntegrationMethod& rIntegrationMethod, + Vector& rGaussWeights, + Matrix& rNContainer) +{ + const GeometryType::IntegrationPointsArrayType& integration_points = + rGeometry.IntegrationPoints(rIntegrationMethod); + + const std::size_t number_of_integration_points = integration_points.size(); + const int dimension = rGeometry.WorkingSpaceDimension(); + const double domain_size = rGeometry.DomainSize(); + + if (rGaussWeights.size() != number_of_integration_points) + { + rGaussWeights.resize(number_of_integration_points, false); + } + + rNContainer = rGeometry.ShapeFunctionsValues(rIntegrationMethod); + + // CAUTION: "Jacobian" is 2.0*A for triangles but 0.5*A for lines + double det_J = (dimension == 2) ? 0.5 * domain_size : 2.0 * domain_size; + + for (unsigned int g = 0; g < number_of_integration_points; g++) + { + rGaussWeights[g] = det_J * integration_points[g].Weight(); + } +} + +double CalculateConditionWallHeight(const ConditionType& rCondition, const array_1d& rNormal) +{ + KRATOS_TRY + + array_1d normal = rNormal / norm_2(rNormal); + + const ElementType& r_parent_element = rCondition.GetValue(NEIGHBOUR_ELEMENTS)[0]; + + const GeometryType& r_parent_geometry = r_parent_element.GetGeometry(); + const GeometryType& r_condition_geometry = rCondition.GetGeometry(); + + const array_1d& parent_center = r_parent_geometry.Center(); + const array_1d& condition_center = r_condition_geometry.Center(); + + return inner_prod(condition_center - parent_center, normal); + + KRATOS_CATCH(""); +} + +void CalculateNumberOfNeighbourConditions(ModelPart& rModelPart) +{ + KRATOS_TRY + + ModelPart::NodesContainerType& r_nodes = rModelPart.Nodes(); + + // reseting all nodal variables which needs to be calculated + VariableUtils().SetNonHistoricalVariableToZero(NUMBER_OF_NEIGHBOUR_CONDITIONS, r_nodes); + + // updating + block_for_each(rModelPart.Conditions(), [](ConditionType& r_cond) { + ConditionType::GeometryType& r_geometry = r_cond.GetGeometry(); + for (IndexType i_node = 0; i_node < r_geometry.PointsNumber(); ++i_node) + { + NodeType& r_node = r_geometry[i_node]; + r_node.SetLock(); + r_node.GetValue(NUMBER_OF_NEIGHBOUR_CONDITIONS) += 1; + r_node.UnSetLock(); + } + }); + + rModelPart.GetCommunicator().AssembleNonHistoricalData(NUMBER_OF_NEIGHBOUR_CONDITIONS); + + KRATOS_CATCH(""); +} + +double CalculateReactionBasedYPlusUTau( + array_1d& rFrictionVelocity, + const array_1d& rReaction, + const array_1d& rNormal, + const double Density, + const double KinematicViscosity, + const double WallHeight) +{ + KRATOS_TRY + + // calculating unit normal since rNormal contains surface area of the condition + const double surface_area = norm_2(rNormal); + const array_1d& unit_normal = rNormal / surface_area; + + // calculate tangential stress + noalias(rFrictionVelocity) = + (rReaction - unit_normal * inner_prod(rReaction, unit_normal)) / surface_area; + const double shear_stress = norm_2(rFrictionVelocity); + + // calculate y_plus + const double y_plus = std::sqrt(shear_stress / Density) * WallHeight / KinematicViscosity; + + // calculate u_tau + noalias(rFrictionVelocity) = + rFrictionVelocity / + std::sqrt((shear_stress <= std::numeric_limits::epsilon() ? 1.0 : shear_stress) * Density); + + return y_plus; + + KRATOS_CATCH(""); +} + +double CalculateLinearLogarithmicWallFunctionBasedYPlusLimit( + const double VonKarman, const double WallSmoothness, const int MaxIterations, const double Tolerance) +{ + double y_plus = 11.06; + const double inv_kappa = 1.0 / VonKarman; + double dx = 0.0; + for (int i = 0; i < MaxIterations; ++i) + { + const double value = inv_kappa * std::log(y_plus) + WallSmoothness; + dx = value - y_plus; + + if (std::abs(dx) < Tolerance) + return y_plus; + + y_plus = value; + } + + KRATOS_WARNING("CalculateLinearLogarithmicWallFunctionBasedYPlusLimit") + << "Logarithmic y_plus limit reached max iterations with dx > " + "Tolerance [ " + << dx << " > " << Tolerance << ", MaxIterations = " << MaxIterations << " ].\n"; + return y_plus; +} + +double CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau( + array_1d& rFrictionVelocity, + const array_1d& rWallVelocity, + const array_1d& rNormal, + const double KinematicViscosity, + const double WallHeight, + const double VonKarman, + const double WallSmoothness, + const int MaxIterations, + const double Tolerance) +{ + KRATOS_TRY + + // calculating unit normal since rNormal contains surface area of the condition + const double surface_area = norm_2(rNormal); + const array_1d& unit_normal = rNormal / surface_area; + + // calculate tangential velocity + noalias(rFrictionVelocity) = + rWallVelocity - unit_normal * inner_prod(rWallVelocity, unit_normal); + const double wall_velocity = norm_2(rFrictionVelocity); + + // calculate linear log region limit + const double limit_y_plus = CalculateLinearLogarithmicWallFunctionBasedYPlusLimit( + VonKarman, WallSmoothness, MaxIterations, Tolerance); + + // linear region + double u_tau = std::sqrt(wall_velocity * KinematicViscosity / WallHeight); + double y_plus = u_tau * WallHeight / KinematicViscosity; + const double inv_kappa = 1.0 / VonKarman; + + // log region + if (y_plus > limit_y_plus) + { + int iter = 0; + double dx = 1e10; + double u_plus = inv_kappa * std::log(y_plus) + WallSmoothness; + + while (iter < MaxIterations && std::abs(dx) > Tolerance * u_tau) + { + // Newton-Raphson iteration + double f = u_tau * u_plus - wall_velocity; + double df = u_plus + inv_kappa; + dx = f / df; + + // Update variables + u_tau -= dx; + y_plus = WallHeight * u_tau / KinematicViscosity; + u_plus = inv_kappa * std::log(y_plus) + WallSmoothness; + ++iter; + } + + KRATOS_WARNING_IF("CFDUtilities", iter >= MaxIterations) + << "CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau " + "couldn't converge Newton-Raphson. Residual is " + << dx << std::endl; + } + + noalias(rFrictionVelocity) = + rFrictionVelocity * + (-1.0 * u_tau / + (wall_velocity <= std::numeric_limits::epsilon() ? 1.0 : wall_velocity)); + + return y_plus; + + KRATOS_CATCH(""); +} + +void CalculateYPlusAndUTauForConditions( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const std::function&, + const GeometryType&, + const array_1d&, + const Vector&, + const double, + const double, + const double + )>& rYPlusAndUTauCalculationMethod) +{ + KRATOS_TRY + + const array_1d local_point = ZeroVector(3); + + KRATOS_ERROR_IF(!rModelPart.HasNodalSolutionStepVariable(rKinematicViscosityVariable)) + << rModelPart.Name() << " doesn't have " << rKinematicViscosityVariable.Name() + << " in nodal solution step variable list. Please add it first.\n"; + KRATOS_ERROR_IF(!rModelPart.HasNodalSolutionStepVariable(DENSITY)) + << rModelPart.Name() << " doesn't have " << DENSITY.Name() + << " in nodal solution step variable list. Please add it first.\n"; + + block_for_each( + rModelPart.Conditions(), [local_point, rKinematicViscosityVariable, + rYPlusAndUTauCalculationMethod](ConditionType& r_condition) { + GeometryType& r_geometry = r_condition.GetGeometry(); + + Vector gauss_weights; + Matrix shape_functions; + CalculateConditionGeometryData( + r_condition.GetGeometry(), GeometryData::GI_GAUSS_1, + gauss_weights, shape_functions); + + const Vector& gauss_shape_functions = row(shape_functions, 0); + + // calculate normal for the condition + const array_1d normal = r_geometry.Normal(local_point); + const double y_wall = CalculateConditionWallHeight(r_condition, normal); + double nu; + GeometryUtils::EvaluateHistoricalVariableValueAtGaussPoint( + nu, r_geometry, rKinematicViscosityVariable, gauss_shape_functions); + double rho; + GeometryUtils::EvaluateHistoricalVariableValueAtGaussPoint( + rho, r_geometry, DENSITY, gauss_shape_functions); + + array_1d u_tau; + const double y_plus = rYPlusAndUTauCalculationMethod( + u_tau, r_geometry, normal, gauss_shape_functions, rho, nu, y_wall); + + r_condition.SetValue(FRICTION_VELOCITY, u_tau); + r_condition.SetValue(Y_PLUS, y_plus); + }); + + KRATOS_CATCH(""); +} + +void CalculateYPlusAndUTauForConditionsBasedOnReaction( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const Variable>& rReactionVariable) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(!rModelPart.HasNodalSolutionStepVariable(rReactionVariable)) + << rModelPart.Name() << " doesn't have " << rReactionVariable.Name() + << " in nodal solution step variable list. Please add it first.\n"; + + CalculateNumberOfNeighbourConditions(rModelPart); + + const std::function&, const GeometryType&, const array_1d&, + const Vector&, const double, const double, const double)> + method = [rReactionVariable]( + array_1d& rFrictionVelocity, + const GeometryType& rGeometry, const array_1d& rNormal, + const Vector& rGaussShapeFunctions, const double Density, + const double KinematicViscosity, const double WallHeight) { + array_1d reaction = + rGeometry[0].FastGetSolutionStepValue(rReactionVariable) / + rGeometry[0].GetValue(NUMBER_OF_NEIGHBOUR_CONDITIONS); + for (unsigned int i_node = 1; i_node < rGeometry.PointsNumber(); ++i_node) + { + const NodeType& r_node = rGeometry[i_node]; + noalias(reaction) += r_node.FastGetSolutionStepValue(rReactionVariable) / + r_node.GetValue(NUMBER_OF_NEIGHBOUR_CONDITIONS); + } + + return CalculateReactionBasedYPlusUTau( + rFrictionVelocity, reaction, rNormal, Density, KinematicViscosity, WallHeight); + }; + + CalculateYPlusAndUTauForConditions(rModelPart, rKinematicViscosityVariable, method); + + KRATOS_CATCH(""); +} + +void CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const double VonKarman, + const double WallSmoothness, + const int MaxIterations, + const double Tolerance) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(VonKarman <= 0.0) + << "Von Karman constant needs to be greater than zero. [ " << VonKarman + << " !> 0.0 ].\n"; + KRATOS_ERROR_IF(WallSmoothness <= 0.0) + << "Wall smoothness parameter needs to be greater than zero. [ " + << WallSmoothness << " !> 0.0 ].\n"; + KRATOS_ERROR_IF(MaxIterations < 0) + << "Max iterations needs to be greater than zero. [ " << MaxIterations + << " !> 0 ].\n"; + KRATOS_ERROR_IF(Tolerance < 0.0) + << "Tolerance needs to be greater than zero. [ " << Tolerance << " !> 0.0 ].\n"; + KRATOS_ERROR_IF(!rModelPart.HasNodalSolutionStepVariable(VELOCITY)) + << rModelPart.Name() << " doesn't have " << VELOCITY.Name() + << " in nodal solution step variable list. Please add it first.\n"; + KRATOS_ERROR_IF(!rModelPart.HasNodalSolutionStepVariable(MESH_VELOCITY)) + << rModelPart.Name() << " doesn't have " << MESH_VELOCITY.Name() + << " in nodal solution step variable list. Please add it first.\n"; + + const std::function&, const GeometryType&, const array_1d&, + const Vector&, const double, const double, const double)> + method = [VonKarman, WallSmoothness, MaxIterations, Tolerance]( + array_1d& rFrictionVelocity, + const GeometryType& rGeometry, const array_1d& rNormal, + const Vector& rGaussShapeFunctions, const double Density, + const double KinematicViscosity, const double WallHeight) { + array_1d r_wall_velocity; + GeometryUtils::EvaluateHistoricalVariableValueAtGaussPoint( + r_wall_velocity, rGeometry, VELOCITY, rGaussShapeFunctions); + array_1d r_mesh_velocity; + GeometryUtils::EvaluateHistoricalVariableValueAtGaussPoint( + r_mesh_velocity, rGeometry, MESH_VELOCITY, rGaussShapeFunctions); + + return CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau( + rFrictionVelocity, r_wall_velocity - r_mesh_velocity, rNormal, KinematicViscosity, + WallHeight, VonKarman, WallSmoothness, MaxIterations, Tolerance); + }; + + CalculateYPlusAndUTauForConditions(rModelPart, rKinematicViscosityVariable, method); + + KRATOS_CATCH(""); +} + +} // namespace CFDUtilities + +} // namespace Kratos. diff --git a/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.h b/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.h new file mode 100644 index 000000000000..95830f33b9ca --- /dev/null +++ b/applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.h @@ -0,0 +1,283 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +#if !defined(KRATOS_CFD_UTILITIES_H_INCLUDED) +#define KRATOS_CFD_UTILITIES_H_INCLUDED + +// System includes +#include + +// External includes + +// Project includes +#include "containers/array_1d.h" +#include "geometries/geometry.h" +#include "geometries/geometry_data.h" +#include "includes/define.h" +#include "includes/model_part.h" + +namespace Kratos +{ +namespace CFDUtilities +{ +using NodeType = ModelPart::NodeType; +using ElementType = ModelPart::ElementType; +using ConditionType = ModelPart::ConditionType; +using GeometryType = Geometry; + +/** + * @brief Calculate gauss point data for condition + * + * The method calculates and retrieves gauss point data namely + * gauss_weight, and gauss point shape function values at each gauss point. + * rNContainer matrix rows corresponds to gauss point index + * + * @param rGeometry + * @param rIntegrationMethod + * @param rGaussWeights + * @param rNContainer + */ +void KRATOS_API(FLUID_DYNAMICS_APPLICATION) CalculateConditionGeometryData( + const GeometryType& rGeometry, + const GeometryData::IntegrationMethod& rIntegrationMethod, + Vector& rGaussWeights, + Matrix& rNContainer); + +/** + * @brief Calculates wall height for condition + * + * Wall height is for given condition is calculated. Wall height is the wall normal distance + * between center of condition and center of parent element for that particular condition. + * TetrahedralMeshOrientationCheck needs to be used with ASSIGN_NEIGHBOUR_ELEMENTS_TO_CONDITIONS flag + * to assign parent element for each condition to use this method. + * + * @param rCondition Condition for which wall height is calculated + * @param rNormal Wall normal (outwards pointing) + * @return double Wall height + * + * @see TetrahedralMeshOrientationCheck + */ +double KRATOS_API(FLUID_DYNAMICS_APPLICATION) + CalculateConditionWallHeight(const ConditionType& rCondition, const array_1d& rNormal); + +/** + * @brief Calculates neighbour conditions + * + * @param rModelPart + */ +void KRATOS_API(FLUID_DYNAMICS_APPLICATION) + CalculateNumberOfNeighbourConditions(ModelPart& rModelPart); + +/** + * @brief Calculates $y^+$ limit for linear-logarithmic wall law + * + * Linear law + * \[ + * y^+ = \frac{u_\tau y}{\nu} + * \] + * + * Log law + * \[ + * u^+ = \frac{1}{\kappa}log\left(y^+\right) + \beta + * \] + * + * Where $\kappa$ is the VonKarman constant, and $\beta$ is the wall smoothness parameter + * $\nu$ is the kinematic viscosity, $u_\tau$ is the wall friction velocity, $y$ is the wall height. + * + * At the limit following relation is assumed. + * + * \[ + * y^+_{limit} = \frac{1}{\kappa}log\left(y^+_{limit}\right) + \beta + * \] + * + * Therefore, this method tries to find limiting $y^+$ where linear and log law meets. + * + * @param VonKarman Von Karman constant ($\kappa$) + * @param WallSmoothness Wall smoothness parameter ($\beta$) + * @param MaxIterations Number of maximum iterations to use to identify limit + * @param Tolerance Tolerance for convergence + * @return double $y^+_{limit}$ limit at the boundary + */ +double KRATOS_API(FLUID_DYNAMICS_APPLICATION) + CalculateLinearLogarithmicWallFunctionBasedYPlusLimit( + const double VonKarman = 0.41, + const double WallSmoothness = 5.2, + const int MaxIterations = 20, + const double Tolerance = 1e-6); + +/** + * @brief Calculate $y^+$ and $u_\tau$ based on log and linear laws + * + * $y^+$ and $u_\tau$ is calculated using either linear or log wall laws. + * + * In the linear region where $y^+ \le y^+_{limit}$ + * \[ + * y^+ = u^+ + * \] + * where $y^+=\frac{u_\tau y}{\nu}$ and $u^+=\frac{|\mathbf{u}|}{u_\tau}$. In here $u_\tau$ is the + * friction velocity. $y$ is the wall height calculated from CalculateConditionWallHeight method. + * $\nu$ is the kinematic viscosity. $\mathbf{u}$ is the wall velocity, where tangential component + * is calculated inside this method and used in the wall law. + * + * If $y^+>y^+_{limit}$ then log law is applied where + * \[ + * u^+ = \frac{1}{\kappa}log\left(y^+\right) + \beta + * \] + * Where $y^+$ and $u^+$ definitions remains the same as in linear region. $\kappa$ is the Von Karman + * constant, and $\beta$ is the wall smoothness parameter. Iterative Newton-Raphson method is used + * to calculate proper $y^+$ and $u_\tau$. + * + * Finally calculated $u_\tau$ is presented in the opposite direction to tangential velocity at wall. + * + * It is advised to use this method with slip boundary conditions, where wall laws are applied. + * + * @param rFrictionVelocity Output friction velocity ($u_\tau$) + * @param rWallVelocity Wall velocity (tangential component will be derrived within this method) + * @param rNormal Wall outwards pointing normal for condition + * @param KinematicViscosity Kinematic viscosity ($\nu$) + * @param WallHeight Wall height ($y$) + * @param VonKarman Von Karman constant ($\kappa$) + * @param WallSmoothness Wall smoothness parameter ($\beta$) + * @param MaxIterations Max iterations used in Newton-Raphson solver + * @param Tolerance Tolerance to be converged for Newton-Raphson solver + * @return double Output $y^+$ value + */ +double KRATOS_API(FLUID_DYNAMICS_APPLICATION) + CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau( + array_1d& rFrictionVelocity, + const array_1d& rWallVelocity, + const array_1d& rNormal, + const double KinematicViscosity, + const double WallHeight, + const double VonKarman = 0.41, + const double WallSmoothness = 5.2, + const int MaxIterations = 20, + const double Tolerance = 1e-6); + +/** + * @brief Calculates $y^+$ at the cell center (no wall laws assumed) + * + * This method calculates $y^+$ at center of the parent element of the condition. + * No wall laws are assumed. + * + * \[ + * u_\tau = \sqrt{\frac{\tau}{\rho}} + * \] + * + * Where $u_\tau$ is the wall friction velocity, $\tau$ is the shear stress at walls. + * $\rho$ is the density. + * + * Total force acting on condition surface ($\mathbf{R}$) is calculate using, + * \[ + * \mathbf{R} = \sum^M_i \frac{\mathbf{R}_i}{N_i} + * \] + * Where $M$ is number of nodes in the condition. $N_i$ is number of neighbour conditions at $i^{th}$ node. + * \mathbf{R}_i is the reaction force at $i^{th}$ node. + * + * $\tau$ is calculated using + * \[ + * \tau = \frac{\mathbf{R} - \left(\mathbf{R}\cdot\mathbf{n}\right)\mathbf{n}}{A} + * \] + * Where $A$ is the surface area of the condition (i.e. line length in 2D). $\mathbf{n}$ is the + * outward pointing unit normal. $\mathbf{R}$ is the reaction acting upon fluid flow. Finally direction + * of $u_\tau$ is kept as the tangential direction of $\mathbf{R}$. + * + * It is advised to use this method with no slip boundary conditions. + * + * @param rFrictionVelocity Output friction velocity $u_\tau$ + * @param rReaction Reaction force vector (tangential component is calculated within the method) + * @param rNormal Outwards pointing condition normal (Magnitude contains surface area) + * @param Density Density of the fluid + * @param KinematicViscosity Kinematic viscosity of fluid + * @param WallHeight Wall height at center of the parent element + * @return double Output $y^+$ at center of the parent element + */ +double KRATOS_API(FLUID_DYNAMICS_APPLICATION) CalculateReactionBasedYPlusUTau( + array_1d& rFrictionVelocity, + const array_1d& rReaction, + const array_1d& rNormal, + const double Density, + const double KinematicViscosity, + const double WallHeight); + +/** + * @brief Calculates $y^+$ and $u_\tau$ for given method + * + * This holds common steps required to calculate and store $y^+$ and $u_\tau$ for given model part's conditions. + * + * @param rModelPart Model part + * @param rKinematicViscosityVariable Variable for kinematic viscosity + * @param rYPlusAndUTauCalculationMethod $y^+$ and $u_\tau$ calculation method. + * + * @see CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau + * @see CalculateReactionBasedYPlusUTau + */ +void KRATOS_API(FLUID_DYNAMICS_APPLICATION) CalculateYPlusAndUTauForConditions( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const std::function&, const GeometryType&, const array_1d&, const Vector&, const double, const double, const double)>& + rYPlusAndUTauCalculationMethod); +/** + * @brief Calculates $y^+$ and $u_\tau$ based on reaction for conditions + * + * This method calculates $y^+$ and $u_\tau$ for conditions in given model part based on reaction. + * Calculated $y^+$ and $u_\tau$ is stored at Y_PLUS, and FRICTION_VELOCITY variables in condition + * data value container. + * + * It is advised to use model parts where only no slip boundary condition is used for conditions + * + * @param rModelPart Model part + * @param rKinematicViscosityVariable Kinematic viscosity variable + * @param rReactionVariable Reaction variable + * + * @see CalculateReactionBasedYPlusUTau + * @see CalculateYPlusAndUTauForConditions + */ +void KRATOS_API(FLUID_DYNAMICS_APPLICATION) CalculateYPlusAndUTauForConditionsBasedOnReaction( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const Variable>& rReactionVariable); + +/** + * @brief Calculates $y^+$ and $u_\tau$ based on linear-log wall laws for conditions + * + * This method calculates $y^+$ and $u_\tau$ for conditions in given model part based on + * linear and log wall laws. Calculated $y^+$ and $u_\tau$ is stored at Y_PLUS, and FRICTION_VELOCITY variables in condition + * data value container. + * + * It is advied to use model parts where only slip boundary with wall functions are used for conditions + * + * @param rModelPart Model part where $y^+$ and $u_\tau$ is calculated for conditions + * @param rKinematicViscosityVariable Kinematic viscosity variable + * @param VonKarman Von Karman constant + * @param WallSmoothness Wall smoothness constant + * @param MaxIterations Max iterations used in Newton-Raphson solver + * @param Tolerance Tolerance used in Newton-Raphson solver + * + * @see CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau + * @see CalculateYPlusAndUTauForConditions + */ +void KRATOS_API(FLUID_DYNAMICS_APPLICATION) + CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + ModelPart& rModelPart, + const Variable& rKinematicViscosityVariable, + const double VonKarman = 0.41, + const double WallSmoothness = 5.2, + const int MaxIterations = 20, + const double Tolerance = 1e-6); + +} // namespace CFDUtilities + +} // namespace Kratos. + +#endif // KRATOS_CFD_UTILITIES_H_INCLUDED defined diff --git a/applications/FluidDynamicsApplication/fluid_dynamics_application.cpp b/applications/FluidDynamicsApplication/fluid_dynamics_application.cpp index 83a5e3166011..4440bfcb723c 100644 --- a/applications/FluidDynamicsApplication/fluid_dynamics_application.cpp +++ b/applications/FluidDynamicsApplication/fluid_dynamics_application.cpp @@ -191,6 +191,11 @@ void KratosFluidDynamicsApplication::Register() { // Auxiliary variables KRATOS_REGISTER_3D_VARIABLE_WITH_COMPONENTS(DRAG_FORCE_CENTER) + // CFD Utility variables + KRATOS_REGISTER_VARIABLE( Y_PLUS ) + KRATOS_REGISTER_VARIABLE( NUMBER_OF_NEIGHBOUR_CONDITIONS ) + KRATOS_REGISTER_3D_VARIABLE_WITH_COMPONENTS( FRICTION_VELOCITY ) + // Register Elements KRATOS_REGISTER_ELEMENT("VMS2D3N",mVMS2D); //this is the name the element should have according to the naming convention KRATOS_REGISTER_ELEMENT("VMS3D4N",mVMS3D); //this is the name the element should have according to the naming convention diff --git a/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.cpp b/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.cpp index 30772e0199aa..e9294620f556 100644 --- a/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.cpp +++ b/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.cpp @@ -90,4 +90,9 @@ KRATOS_CREATE_VARIABLE( double, UPDATE_STATISTICS ) // Auxiliary variables KRATOS_CREATE_3D_VARIABLE_WITH_COMPONENTS(DRAG_FORCE_CENTER) +// CFD Utility variables +KRATOS_CREATE_VARIABLE( double, Y_PLUS ) +KRATOS_CREATE_VARIABLE( int, NUMBER_OF_NEIGHBOUR_CONDITIONS ) +KRATOS_CREATE_3D_VARIABLE_WITH_COMPONENTS( FRICTION_VELOCITY ) + } diff --git a/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.h b/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.h index 495e24e39e3e..9b4939bb27ea 100644 --- a/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.h +++ b/applications/FluidDynamicsApplication/fluid_dynamics_application_variables.h @@ -94,6 +94,11 @@ KRATOS_DEFINE_APPLICATION_VARIABLE( FLUID_DYNAMICS_APPLICATION, StatisticsRecord KRATOS_DEFINE_APPLICATION_VARIABLE( FLUID_DYNAMICS_APPLICATION, StatisticsData, TURBULENCE_STATISTICS_DATA) KRATOS_DEFINE_APPLICATION_VARIABLE( FLUID_DYNAMICS_APPLICATION, double, UPDATE_STATISTICS ) +// CFD Utility variables +KRATOS_DEFINE_APPLICATION_VARIABLE( FLUID_DYNAMICS_APPLICATION, double, Y_PLUS ) +KRATOS_DEFINE_APPLICATION_VARIABLE( FLUID_DYNAMICS_APPLICATIONint, int, NUMBER_OF_NEIGHBOUR_CONDITIONS ) +KRATOS_DEFINE_3D_APPLICATION_VARIABLE_WITH_COMPONENTS( FLUID_DYNAMICS_APPLICATION, FRICTION_VELOCITY ) + // Auxiliary variables KRATOS_DEFINE_3D_APPLICATION_VARIABLE_WITH_COMPONENTS( FLUID_DYNAMICS_APPLICATION, DRAG_FORCE_CENTER ) diff --git a/applications/FluidDynamicsApplication/python_scripts/cfd_utility_function_process.py b/applications/FluidDynamicsApplication/python_scripts/cfd_utility_function_process.py new file mode 100755 index 000000000000..73c9dc45f5d5 --- /dev/null +++ b/applications/FluidDynamicsApplication/python_scripts/cfd_utility_function_process.py @@ -0,0 +1,80 @@ +# Importing the Kratos Library +import KratosMultiphysics as Kratos +from .cfd_utility_functions import GetCFDUtilityFunction + + +def Factory(settings, model): + if (not isinstance(settings, Kratos.Parameters)): + raise Exception( + "expected input shall be a Parameters object, encapsulating a json string" + ) + if (not isinstance(model, Kratos.Model)): + raise Exception( + "expected input shall be a Model object, encapsulating a json string" + ) + + return CFDUtilityFunctionProcess(model, settings["Parameters"]) + + +class CFDUtilityFunctionProcess(Kratos.Process): + """This process executes CFD functions implemented in c++ level + + This process is used to evaluate CFD functions implemented in c++ level + and exposed through "CFDUtilities" submodule in FluidDynamicsApplication. + + Kratos Parameter settings: + "model_part_name" : The model part on which CFDUtility function will be executed + "function_settings": Settings of appropriate function. ("function_name" is a must have under this group) + "execution_points" : User defined execution points in simulation, where function is executed. + Allowed execution points: + "Initialize", + "InitializeSolutionStep", + "FinalizeSolutionStep", + "Finalize" + + """ + def __init__(self, model, params): + Kratos.Process.__init__(self) + + default_settings = Kratos.Parameters(""" + { + "model_part_name" : "", + "function_settings": {}, + "execution_points" : ["FinalizeSolutionStep"] + } + """) + + params.ValidateAndAssignDefaults(default_settings) + self.model_part = model.GetModelPart( + params["model_part_name"].GetString()) + self.execution_points_list = params["execution_points"].GetStringArray( + ) + + allowed_execution_points = [ + "Initialize", "InitializeSolutionStep", "FinalizeSolutionStep", + "Finalize" + ] + for execution_point in self.execution_points_list: + if (execution_point not in allowed_execution_points): + msg = "Unknown function execution point [ \"execution_point\" = \"" + execution_point + "\" ].\n" + msg += "Supported execution points are:" + msg += "\n\t".join(allowed_execution_points) + raise Exception(msg) + + self.function = GetCFDUtilityFunction(params["function_settings"]) + + def ExecuteInitialize(self): + if ("Initialize" in self.execution_points_list): + self.function(self.model_part) + + def ExecuteInitializeSolutionStep(self): + if ("InitializeSolutionStep" in self.execution_points_list): + self.function(self.model_part) + + def ExecuteFinalizeSolutionStep(self): + if ("FinalizeSolutionStep" in self.execution_points_list): + self.function(self.model_part) + + def ExecuteFinalize(self): + if ("Finalize" in self.execution_points_list): + self.function(self.model_part) \ No newline at end of file diff --git a/applications/FluidDynamicsApplication/python_scripts/cfd_utility_functions.py b/applications/FluidDynamicsApplication/python_scripts/cfd_utility_functions.py new file mode 100755 index 000000000000..8c0923746898 --- /dev/null +++ b/applications/FluidDynamicsApplication/python_scripts/cfd_utility_functions.py @@ -0,0 +1,132 @@ +# Importing the Kratos Library +import KratosMultiphysics as Kratos +import KratosMultiphysics.FluidDynamicsApplication as KratosCFD + + +def CheckVariableType(variable_name, required_variable_type): + variable_type = Kratos.KratosGlobals.GetVariableType(variable_name) + if (variable_type != required_variable_type): + msg = "Type of " + variable_name + " is not supported. Please provide a " + required_variable_type + " [ " + variable_name + " = " + variable_type + " ]." + raise Exception(msg) + + +def GetCFDUtilityFunction(params): + """This is the factory for CFDUtilityFunctions + + This method returns the correct lambda function from CFDUtilityFunctions class + + Args: + params (Kratos.Parameters): Parameters required for function execution + + Returns: + [lambda model_part]: Returns correct CFDUtilityFunction lambda + """ + if (params.Has("function_name")): + function_name = params["function_name"].GetString() + else: + raise Exception("Please provide a function_name.") + + function_list = [func for func in dir(CFDUtilityFunctions)] + + if (function_name not in function_list): + msg = "Unknown function name [ \"function_name\" = \"" + function_name + "\" ].\n" + msg += "Supported function names are:" + msg += "\n\t".join(function_list) + raise Exception(msg) + + Kratos.Logger.PrintInfo("CFDUtilityFunctions", + "Created " + function_name + " function.") + return getattr(CFDUtilityFunctions, function_name)(params) + + +class CFDUtilityFunctions: + """A class to hold CFDUtilities C++ methods + + This class holds wrappers for CFDUtilities developed in C++. These C++ methods + should be standalone, and they should be able to have single point execution without + depending on any other information rather than model_part which is being passed as an + input argument at execution point. + + This wrapper methods are used to provide additional information for CFDUtilities methods + based on input from Kratos.Parameters. + + The wrappers defined here needs to have following signature: + Input args : (Kratos.Parameters) + Output args: Returns a lambda function. The lambda function should have Kratos.ModelPart as + an input, and not output should be there. + + """ + @staticmethod + def NeighbourWeightedAccumulateConditionVariableOnNodes(params): + default_settings = Kratos.Parameters(""" + { + "function_name": "NeighbourWeightedAccumulateConditionVariableOnNodes", + "variable_name": "PLEASE_PROVIDE_A_VARIABLE_NAME" + }""") + + params.ValidateAndAssignDefaults(default_settings) + variable_name = params["variable_name"].GetString() + if (not Kratos.KratosGlobals.HasVariable(variable_name)): + raise Exception("Variable " + variable_name + " not found.") + variable_type = Kratos.KratosGlobals.GetVariableType(variable_name) + variable = Kratos.KratosGlobals.GetVariable(variable_name) + if (variable_type in ["Double", "Array"]): + def func_method(model_part): + KratosCFD.CFDUtilities.CalculateNumberOfNeighbourConditions(model_part) + Kratos.VariableUtils().WeightedAccumulateConditionVariableOnNodes(model_part, variable, KratosCFD.NUMBER_OF_NEIGHBOUR_CONDITIONS, True) + return func_method + else: + raise Exception("Unsupported variable type " + variable_type + + " in " + variable_name + " variable.") + + @staticmethod + def CalculateYPlusAndUTauForConditionsBasedOnReaction(params): + default_settings = Kratos.Parameters(""" + { + "function_name" : "CalculateYPlusAndUTauForConditionsBasedOnReaction", + "kinematic_viscosity_variable_name": "VISCOSITY", + "reaction_variable_name" : "REACTION" + }""") + + params.ValidateAndAssignDefaults(default_settings) + + nu_variable_name = params[ + "kinematic_viscosity_variable_name"].GetString() + CheckVariableType(nu_variable_name, "Double") + nu_variable = Kratos.KratosGlobals.GetVariable(nu_variable_name) + + reaction_variable_name = params["reaction_variable_name"].GetString() + CheckVariableType(reaction_variable_name, "Array") + reaction_variable = Kratos.KratosGlobals.GetVariable( + reaction_variable_name) + + return lambda model_part: KratosCFD.CFDUtilities.CalculateYPlusAndUTauForConditionsBasedOnReaction( + model_part, nu_variable, reaction_variable) + + @staticmethod + def CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + params): + default_settings = Kratos.Parameters(""" + { + "function_name" : "CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction", + "kinematic_viscosity_variable_name": "VISCOSITY", + "von_karman" : 0.41, + "wall_smoothness" : 5.2, + "max_iterations" : 20, + "tolerance" : 1e-6 + }""") + + params.ValidateAndAssignDefaults(default_settings) + + nu_variable_name = params[ + "kinematic_viscosity_variable_name"].GetString() + CheckVariableType(nu_variable_name, "Double") + nu_variable = Kratos.KratosGlobals.GetVariable(nu_variable_name) + + kappa = params["von_karman"].GetDouble() + beta = params["wall_smoothness"].GetDouble() + max_iterations = params["max_iterations"].GetInt() + tolerance = params["tolerance"].GetDouble() + + return lambda model_part: KratosCFD.CFDUtilities.CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + model_part, nu_variable, kappa, beta, max_iterations, tolerance) diff --git a/applications/FluidDynamicsApplication/tests/Cavity/cfd_function_process_output_ref.json b/applications/FluidDynamicsApplication/tests/Cavity/cfd_function_process_output_ref.json new file mode 100644 index 000000000000..f164f4b0c22d --- /dev/null +++ b/applications/FluidDynamicsApplication/tests/Cavity/cfd_function_process_output_ref.json @@ -0,0 +1 @@ +{"TIME": [1.5], "NODE_1": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.4978186628220273], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.00780892020112984]}, "NODE_2": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [-0.027963511528386553], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.016056483720352017]}, "NODE_3": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_4": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_5": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_6": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [-0.9301792706221907], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.014591047382308875]}, "NODE_7": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_8": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_9": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_10": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_11": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [-0.17702712387106576], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.009910071665450793]}, "NODE_12": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_13": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_14": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_15": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_16": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_17": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [1.01816033627012], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.015971142529727367]}, "NODE_18": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_19": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_20": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_21": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_22": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_23": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.7907903638694087], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.012404554727363272]}, "NODE_24": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [17.367084792014207], "FRICTION_VELOCITY_Z": [-21.361514294177475], "Y_PLUS": [0.4318514068318868]}, "NODE_25": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_26": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_27": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_28": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [36.924692007622156], "FRICTION_VELOCITY_Z": [-36.02971970588344], "Y_PLUS": [0.8153339012555719]}, "NODE_29": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_30": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [40.66323049852544], "FRICTION_VELOCITY_Z": [-22.89939849204378], "Y_PLUS": [0.7388380269025749]}, "NODE_31": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_32": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_33": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [42.8503972232268], "FRICTION_VELOCITY_Z": [-11.492909171384218], "Y_PLUS": [0.7002659932906665]}, "NODE_34": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [0.0], "FRICTION_VELOCITY_Z": [0.0], "Y_PLUS": [0.0]}, "NODE_35": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [43.605926445875696], "FRICTION_VELOCITY_Z": [-3.9175506662133883], "Y_PLUS": [0.6879847794274268]}, "NODE_36": {"FRICTION_VELOCITY_X": [0.0], "FRICTION_VELOCITY_Y": [21.861152505566388], "FRICTION_VELOCITY_Z": [-0.6558345751669918], "Y_PLUS": [0.34307431861565]}, "ELEMENT_1": {}, "ELEMENT_2": {}, "ELEMENT_3": {}, "ELEMENT_4": {}, "ELEMENT_5": {}, "ELEMENT_6": {}, "ELEMENT_7": {}, "ELEMENT_8": {}, "ELEMENT_9": {}, "ELEMENT_10": {}, "ELEMENT_11": {}, "ELEMENT_12": {}, "ELEMENT_13": {}, "ELEMENT_14": {}, "ELEMENT_15": {}, "ELEMENT_16": {}, "ELEMENT_17": {}, "ELEMENT_18": {}, "ELEMENT_19": {}, "ELEMENT_20": {}, "ELEMENT_21": {}, "ELEMENT_22": {}, "ELEMENT_23": {}, "ELEMENT_24": {}, "ELEMENT_25": {}, "ELEMENT_26": {}, "ELEMENT_27": {}, "ELEMENT_28": {}, "ELEMENT_29": {}, "ELEMENT_30": {}, "ELEMENT_31": {}, "ELEMENT_32": {}, "ELEMENT_33": {}, "ELEMENT_34": {}, "ELEMENT_35": {}, "ELEMENT_36": {}, "ELEMENT_37": {}, "ELEMENT_38": {}, "ELEMENT_39": {}, "ELEMENT_40": {}, "ELEMENT_41": {}, "ELEMENT_42": {}, "ELEMENT_43": {}, "ELEMENT_44": {}, "ELEMENT_45": {}, "ELEMENT_46": {}, "ELEMENT_47": {}, "ELEMENT_48": {}, "ELEMENT_49": {}, "ELEMENT_50": {}} \ No newline at end of file diff --git a/applications/FluidDynamicsApplication/tests/Cavity/cfd_utility_function_process.json b/applications/FluidDynamicsApplication/tests/Cavity/cfd_utility_function_process.json new file mode 100644 index 000000000000..397031f04802 --- /dev/null +++ b/applications/FluidDynamicsApplication/tests/Cavity/cfd_utility_function_process.json @@ -0,0 +1,217 @@ +{ + "problem_data": { + "problem_name": "cavity5", + "parallel_type": "OpenMP", + "echo_level": 0, + "start_time": 0.0, + "end_time": 2.0 + }, + "restart_options": { + "SaveRestart": "False", + "RestartFrequency": 0, + "LoadRestart": "False", + "Restart_Step": 0 + }, + "solver_settings": { + "solver_type": "Monolithic", + "model_part_name": "MainModelPart", + "domain_size": 2, + "model_import_settings": { + "input_type": "mdpa", + "input_filename": "square5" + }, + "material_import_settings": { + "materials_filename": "cavity_test_materials.json" + }, + "echo_level": 0, + "compute_reactions": false, + "maximum_iterations": 1000, + "formulation": { + "element_type": "qsvms", + "use_orthogonal_subscales": false, + "dynamic_tau": 0.0 + }, + "relative_velocity_tolerance": 1e-6, + "absolute_velocity_tolerance": 1e-6, + "relative_pressure_tolerance": 1e-6, + "absolute_pressure_tolerance": 1e-6, + "linear_solver_settings": { + "solver_type": "amgcl", + "max_iteration": 200, + "tolerance": 1e-9, + "provide_coordinates": false, + "smoother_type": "ilu0", + "krylov_type": "gmres", + "coarsening_type": "aggregation", + "scaling": false + }, + "volume_model_part_name": "Parts_Fluid", + "skin_parts": [ + "NoSlip2D_left_wall", + "NoSlip2D_right_wall", + "NoSlip2D_bottom_wall", + "NoSlip2D_top_wall" + ], + "no_skin_parts": [ + "Pressure_lower_left_corner" + ], + "assign_neighbour_elements_to_conditions": true, + "time_stepping": { + "automatic_time_step": false, + "time_step": 0.5 + } + }, + "processes": { + "initial_conditions_process_list": [], + "boundary_conditions_process_list": [ + { + "python_module": "assign_vector_variable_process", + "kratos_module": "KratosMultiphysics", + "help": "This process fixes the selected components of a given vector variable", + "process_name": "AssignVectorVariableProcess", + "Parameters": { + "model_part_name": "MainModelPart.Parts_Fluid", + "variable_name": "VELOCITY", + "constrained": [ + false, + false, + false + ], + "value": [ + "5*t*t*x*y-3*t*x", + "-20*t*x*x", + "t*y*30*y" + ], + "interval": [ + 0.0, + "End" + ] + } + }, + { + "python_module": "assign_vector_variable_process", + "kratos_module": "KratosMultiphysics", + "help": "This process fixes the selected components of a given vector variable", + "process_name": "AssignVectorVariableProcess", + "Parameters": { + "model_part_name": "MainModelPart.Parts_Fluid", + "variable_name": "REACTION", + "constrained": [ + false, + false, + false + ], + "value": [ + "20*t*t*x*y-15*t*x", + "-2*t*x*x", + "t*y*3*y" + ], + "interval": [ + 0.0, + "End" + ] + } + }, + { + "python_module": "assign_scalar_variable_process", + "kratos_module": "KratosMultiphysics", + "process_name": "AssignScalarVariableProcess", + "Parameters": { + "model_part_name": "MainModelPart.Parts_Fluid", + "variable_name": "VISCOSITY", + "value": "t*t+2", + "constrained": false + } + }, + { + "python_module": "assign_scalar_variable_process", + "kratos_module": "KratosMultiphysics", + "process_name": "AssignScalarVariableProcess", + "Parameters": { + "model_part_name": "MainModelPart.Parts_Fluid", + "variable_name": "DENSITY", + "value": "t*t*3+2", + "constrained": false + } + } + ], + "gravity": [], + "auxiliar_process_list": [ + { + "kratos_module": "KratosMultiphysics.FluidDynamicsApplication", + "python_module": "cfd_utility_function_process", + "help": "", + "Parameters": { + "model_part_name": "MainModelPart.NoSlip2D_left_wall", + "function_settings": { + "function_name": "CalculateYPlusAndUTauForConditionsBasedOnReaction", + "kinematic_viscosity_variable_name": "VISCOSITY", + "reaction_variable_name": "REACTION" + } + } + }, + { + "kratos_module": "KratosMultiphysics.FluidDynamicsApplication", + "python_module": "cfd_utility_function_process", + "help": "", + "Parameters": { + "model_part_name": "MainModelPart.NoSlip2D_right_wall", + "function_settings": { + "function_name": "CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction", + "kinematic_viscosity_variable_name": "VISCOSITY", + "von_karman": 0.41, + "wall_smoothness": 5.2, + "max_iterations": 20, + "tolerance": 1e-6 + } + } + }, + { + "kratos_module": "KratosMultiphysics.FluidDynamicsApplication", + "python_module": "cfd_utility_function_process", + "help": "", + "Parameters": { + "model_part_name": "MainModelPart", + "function_settings": { + "function_name": "NeighbourWeightedAccumulateConditionVariableOnNodes", + "variable_name": "FRICTION_VELOCITY" + } + } + }, + { + "kratos_module": "KratosMultiphysics.FluidDynamicsApplication", + "python_module": "cfd_utility_function_process", + "help": "", + "Parameters": { + "model_part_name": "MainModelPart", + "function_settings": { + "function_name": "NeighbourWeightedAccumulateConditionVariableOnNodes", + "variable_name": "Y_PLUS" + } + } + }, + { + "python_module": "from_json_check_result_process", + "kratos_module": "KratosMultiphysics", + "Parameters": { + "help": "This process checks the solution obtained from a given json file. It can be used for generating tests for a problem", + "check_variables": [ + "FRICTION_VELOCITY", + "Y_PLUS" + ], + "gauss_points_check_variables": [], + "input_file_name": "cfd_function_process_output_ref.json", + "model_part_name": "MainModelPart", + "sub_model_part_name": "", + "check_for_flag": "", + "historical_value": false, + "tolerance": 1e-5, + "relative_tolerance": 1e-9, + "time_frequency": 1.00, + "use_node_coordinates": false, + "check_only_local_entities": false + } + } + ] + } +} \ No newline at end of file diff --git a/applications/FluidDynamicsApplication/tests/cfd_function_process_test.py b/applications/FluidDynamicsApplication/tests/cfd_function_process_test.py new file mode 100644 index 000000000000..122fdf77a058 --- /dev/null +++ b/applications/FluidDynamicsApplication/tests/cfd_function_process_test.py @@ -0,0 +1,69 @@ +import KratosMultiphysics as km + +from fluid_analysis_without_solution import FluidAnalysisWithoutSolution + +import KratosMultiphysics.KratosUnittest as UnitTest +import KratosMultiphysics.kratos_utilities as kratos_utilities + + +class CFDFunctionProcessTest(UnitTest.TestCase): + def setUp(self): + # Set to true to get post-process files for the test + self.print_output = False + + def testCFDFunctionProcess(self): + work_folder = "Cavity" + settings_file_name = "cfd_utility_function_process.json" + + with UnitTest.WorkFolderScope(work_folder, __file__): + self._runTest(settings_file_name) + + kratos_utilities.DeleteFileIfExisting("square5.time") + + def _runTest(self, settings_file_name): + model = km.Model() + with open(settings_file_name, 'r') as settings_file: + settings = km.Parameters(settings_file.read()) + + # to check the results: add output settings block if needed + if self.print_output: + settings.AddValue( + "output_processes", + km.Parameters(r'''{ + "gid_output" : [{ + "python_module" : "gid_output_process", + "kratos_module" : "KratosMultiphysics", + "process_name" : "GiDOutputProcess", + "Parameters" : { + "model_part_name" : "MainModelPart.fluid_computational_model_part", + "output_name" : "cavity", + "postprocess_parameters" : { + "result_file_configuration" : { + "gidpost_flags" : { + "GiDPostMode" : "GiD_PostBinary", + "WriteDeformedMeshFlag" : "WriteDeformed", + "WriteConditionsFlag" : "WriteConditions", + "MultiFileFlag" : "SingleFile" + }, + "file_label" : "time", + "output_control_type" : "step", + "output_frequency" : 1, + "body_output" : true, + "node_output" : false, + "skin_output" : false, + "plane_output" : [], + "nodal_results" : ["VELOCITY","PRESSURE"], + "gauss_point_results" : [] + }, + "point_data_configuration" : [] + } + } + }] + }''')) + + analysis = FluidAnalysisWithoutSolution(model, settings) + analysis.Run() + + +if __name__ == '__main__': + UnitTest.main() diff --git a/applications/FluidDynamicsApplication/tests/cfd_utilities_test.py b/applications/FluidDynamicsApplication/tests/cfd_utilities_test.py new file mode 100644 index 000000000000..51e2f48e3e65 --- /dev/null +++ b/applications/FluidDynamicsApplication/tests/cfd_utilities_test.py @@ -0,0 +1,257 @@ +import KratosMultiphysics as Kratos +import KratosMultiphysics.FluidDynamicsApplication as KratosCFD +from KratosMultiphysics.FluidDynamicsApplication import check_and_prepare_model_process_fluid + +import KratosMultiphysics.KratosUnittest as UnitTest +import math + + +class CFDUtilitiesTest(UnitTest.TestCase): + def testCalculateLinearLogarithmicWallFunctionBasedYPlusLimit(self): + kappa = 0.5 + beta = 6.0 + y_plus = KratosCFD.CFDUtilities.CalculateLinearLogarithmicWallFunctionBasedYPlusLimit( + kappa, beta, 20, 1e-6) + u_plus = math.log(y_plus) / kappa + beta + self.assertAlmostEqual(u_plus, y_plus, 6) + + def testCalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau(self): + u_tau = Kratos.Array3() + velocity = Kratos.Array3() + normal = Kratos.Array3([1.0, 0.5, 0.5]) + nu = 10.0 + y = 1.1 + kappa = 0.5 + beta = 6.0 + + unit_normal = normal * (1.0 / CFDUtilitiesTest.__CalculateArray3DNorm(normal)) + + # checking for linear region + velocity[0] = 0.1 + velocity[1] = 0.2 + velocity[2] = 0.3 + y_plus = KratosCFD.CFDUtilities.CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau( + u_tau, velocity, normal, nu, y, kappa, beta, 20, 1e-6) + tangential_velocity = velocity - unit_normal * ( + velocity[0] * unit_normal[0] + velocity[1] * unit_normal[1] + + velocity[2] * unit_normal[2]) + u_tau_magnitude = math.sqrt( + CFDUtilitiesTest.__CalculateArray3DNorm(tangential_velocity) * nu / y) + u_tau_check = tangential_velocity * ( + u_tau_magnitude * -1.0 / + CFDUtilitiesTest.__CalculateArray3DNorm(tangential_velocity)) + y_plus_check = u_tau_magnitude * y / nu + + self.assertVectorAlmostEqual(u_tau, u_tau_check, 7) + self.assertAlmostEqual(y_plus, y_plus_check, 7) + + # checking for logarithmic region + velocity[0] = 1000.0 + velocity[1] = 2000.0 + velocity[2] = 3000.0 + y_plus = KratosCFD.CFDUtilities.CalculateLinearLogarithmicWallFunctionBasedYPlusAndUtau( + u_tau, velocity, normal, nu, y, kappa, beta, 20, 1e-6) + tangential_velocity = velocity - unit_normal * ( + velocity[0] * unit_normal[0] + velocity[1] * unit_normal[1] + + velocity[2] * unit_normal[2]) + u_tau_magnitude = y_plus * nu / y + u_tau_check = tangential_velocity * ( + u_tau_magnitude * -1.0 / + CFDUtilitiesTest.__CalculateArray3DNorm(tangential_velocity)) + y_plus_check = math.exp( + (CFDUtilitiesTest.__CalculateArray3DNorm(tangential_velocity) / + CFDUtilitiesTest.__CalculateArray3DNorm(u_tau) - beta) * kappa) + + self.assertVectorAlmostEqual(u_tau, u_tau_check, 7) + self.assertAlmostEqual(y_plus, y_plus_check, 7) + + def testCalculateReactionBasedYPlusUTau(self): + u_tau = Kratos.Array3() + reaction = Kratos.Array3([1.0, 2.0, 5.0]) + normal = Kratos.Array3([1.0, 0.5, 0.5]) + nu = 10.0 + y = 1.1 + rho = 1.2 + + y_plus = KratosCFD.CFDUtilities.CalculateReactionBasedYPlusUTau( + u_tau, reaction, normal, rho, nu, y) + surface_area = CFDUtilitiesTest.__CalculateArray3DNorm(normal) + unit_normal = normal * (1.0 / surface_area) + + tangential_reaction_check = reaction - unit_normal * ( + reaction[0] * unit_normal[0] + reaction[1] * unit_normal[1] + + reaction[2] * unit_normal[2]) + u_tau_magnitude = CFDUtilitiesTest.__CalculateArray3DNorm(u_tau) + tangential_reaction = u_tau * (u_tau_magnitude**2 * rho * + surface_area / u_tau_magnitude) + y_plus_check = u_tau_magnitude * y / nu + self.assertVectorAlmostEqual(tangential_reaction, + tangential_reaction_check, 7) + self.assertAlmostEqual(y_plus, y_plus_check, 7) + + def testCalculateNumberOfNeighbourConditions(self): + self.__CreateModel() + model_part = self.model.GetModelPart("test.submodelpart_1") + KratosCFD.CFDUtilities.CalculateNumberOfNeighbourConditions(model_part) + + check_values = [1, 2, 1] + for node, value in zip(model_part.Nodes, check_values): + node_value = node.GetValue( + KratosCFD.NUMBER_OF_NEIGHBOUR_CONDITIONS) + self.assertEqual(node_value, value) + + def testCalculateYPlusAndUTauForConditionsBasedOnReaction(self): + self.__CreateModel() + model_part = self.model.GetModelPart("test.submodelpart_1") + KratosCFD.CFDUtilities.CalculateYPlusAndUTauForConditionsBasedOnReaction( + model_part, Kratos.VISCOSITY, Kratos.REACTION) + + check_y_plus_values = [154.37981820205698, 40.0630232620064] + check_u_tau_values = [ + Kratos.Array3([1.2995046003231017, 0.0, 1.6293788450205047]), + Kratos.Array3([1.8308118481697873, 0.0, 0.1722050748278512]) + ] + for condition, y_plus_check, u_tau_check in zip( + model_part.Conditions, check_y_plus_values, + check_u_tau_values): + self.assertAlmostEqual(condition.GetValue(KratosCFD.Y_PLUS), + y_plus_check, 7) + self.assertVectorAlmostEqual( + condition.GetValue(KratosCFD.FRICTION_VELOCITY), u_tau_check, + 7) + + def testCalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + self): + self.__CreateModel() + model_part = self.model.GetModelPart("test.submodelpart_1") + + kappa = 0.5 + beta = 10.0 + KratosCFD.CFDUtilities.CalculateYPlusAndUTauForConditionsBasedOnLinearLogarithmicWallFunction( + model_part, Kratos.VISCOSITY, kappa, beta, 20, 1e-6) + + check_y_plus_values = [42.184008341432026, 14.937830572275276] + check_u_tau_values = [ + Kratos.Array3([-0.3145718416438325, 0.0, -0.4747175064806927]), + Kratos.Array3([-0.6091915392914995, 0.0, -0.31463738842527994]) + ] + for condition, y_plus_check, u_tau_check in zip( + model_part.Conditions, check_y_plus_values, + check_u_tau_values): + self.assertAlmostEqual(condition.GetValue(KratosCFD.Y_PLUS), + y_plus_check, 7) + self.assertVectorAlmostEqual( + condition.GetValue(KratosCFD.FRICTION_VELOCITY), u_tau_check, + 7) + + @staticmethod + def __CalculateArray3DNorm(value): + return math.sqrt(value[0]**2 + value[1]**2 + value[2]**2) + + +# test model part is as follows +# 6 5 4 +# .---.---. +# / |4 /\ 3| +# / 1| / \ | +# / |/ 2 \| +# .----.------. +# 1 2 3 + + def __CreateModel(self): + variable_list = [ + Kratos.VELOCITY, Kratos.REACTION, Kratos.DENSITY, Kratos.VISCOSITY, Kratos.MESH_VELOCITY + ] + self.model = Kratos.Model() + self.model_part = self.model.CreateModelPart("test") + for variable in variable_list: + self.model_part.AddNodalSolutionStepVariable(variable) + + self.model_part.CreateNewNode(1, 0.0, 0.0, 0.0) + self.model_part.CreateNewNode(2, 1.0, 0.0, 0.0) + self.model_part.CreateNewNode(3, 2.0, 0.0, 0.0) + self.model_part.CreateNewNode(4, 2.0, 1.0, 0.0) + self.model_part.CreateNewNode(5, 1.5, 1.0, 0.0) + self.model_part.CreateNewNode(6, 1.0, 1.0, 0.0) + prop = self.model_part.GetProperties()[0] + + self.model_part.CreateNewElement("Element2D3N", 1, [1, 2, 6], prop) + self.model_part.CreateNewElement("Element2D3N", 2, [2, 3, 5], prop) + self.model_part.CreateNewElement("Element2D3N", 3, [3, 4, 5], prop) + self.model_part.CreateNewElement("Element2D3N", 4, [2, 5, 6], prop) + + self.submodelpart_1 = self.model_part.CreateSubModelPart( + "submodelpart_1") + self.submodelpart_1.AddNodes([1, 2, 3]) + self.submodelpart_1.CreateNewCondition("LineCondition2D2N", 1, [1, 2], + prop) + self.submodelpart_1.CreateNewCondition("LineCondition2D2N", 2, [2, 3], + prop) + + self.submodelpart_2 = self.model_part.CreateSubModelPart( + "submodelpart_2") + self.submodelpart_2.AddNodes([3, 4, 5]) + self.submodelpart_2.CreateNewCondition("LineCondition2D2N", 3, [3, 4], + prop) + self.submodelpart_2.CreateNewCondition("LineCondition2D2N", 4, [4, 5], + prop) + + self.submodelpart_3 = self.model_part.CreateSubModelPart( + "submodelpart_3") + self.submodelpart_3.AddNodes([1, 6, 5]) + self.submodelpart_3.CreateNewCondition("LineCondition2D2N", 5, [5, 6], + prop) + self.submodelpart_3.CreateNewCondition("LineCondition2D2N", 6, [6, 1], + prop) + + prepare_model_part_settings = Kratos.Parameters("{}") + + prepare_model_part_settings.AddEmptyValue("volume_model_part_name") + prepare_model_part_settings["volume_model_part_name"].SetString("test") + + prepare_model_part_settings.AddEmptyArray("skin_parts") + prepare_model_part_settings["skin_parts"].Append("submodelpart_1") + prepare_model_part_settings["skin_parts"].Append("submodelpart_2") + prepare_model_part_settings["skin_parts"].Append("submodelpart_3") + + prepare_model_part_settings.AddEmptyValue( + "assign_neighbour_elements_to_conditions") + prepare_model_part_settings[ + "assign_neighbour_elements_to_conditions"].SetBool(True) + + check_and_prepare_model_process_fluid.CheckAndPrepareModelProcess( + self.model_part, prepare_model_part_settings).Execute() + + self.model_part.SetBufferSize(2) + self.model_part.ProcessInfo[Kratos.DOMAIN_SIZE] = 2 + + for node in self.model_part.Nodes: + nid = node.Id + x = node.X + 0.6 + y = node.Y + 1.2 + z = node.Z + 3.0 + + vector = Kratos.Vector(3) + vector[0] = nid * x + y * z + vector[1] = nid * x - y * z + vector[2] = -1.0 * nid * x + y * 1 + 3 * z + if (node.SolutionStepsDataHas(Kratos.VELOCITY)): + vector = node.SetSolutionStepValue(Kratos.VELOCITY, 0, vector) + + vector = Kratos.Vector(3) + vector[0] = nid * x + y * z * 2 + vector[1] = nid * x - y * z * 5 + vector[2] = -2.0 * nid * x + y * 4 + 3 * z + if (node.SolutionStepsDataHas(Kratos.REACTION)): + vector = node.SetSolutionStepValue(Kratos.REACTION, 0, vector) + + scalar = nid * y + z + if (node.SolutionStepsDataHas(Kratos.DENSITY)): + node.SetSolutionStepValue(Kratos.DENSITY, 0, scalar) + + scalar = (nid * z * x - y) * 1e-3 + if (node.SolutionStepsDataHas(Kratos.VISCOSITY)): + node.SetSolutionStepValue(Kratos.VISCOSITY, 0, scalar) + +if __name__ == '__main__': + UnitTest.main() diff --git a/applications/FluidDynamicsApplication/tests/test_FluidDynamicsApplication.py b/applications/FluidDynamicsApplication/tests/test_FluidDynamicsApplication.py index 26858b73f3d1..dc364cf9e1f7 100644 --- a/applications/FluidDynamicsApplication/tests/test_FluidDynamicsApplication.py +++ b/applications/FluidDynamicsApplication/tests/test_FluidDynamicsApplication.py @@ -29,6 +29,8 @@ from hdf5_io_test import HDF5IOTest from test_statistics_process import IntegrationPointStatisticsTest from cfl_output_process_test import CFLOutputProcessTest +from cfd_function_process_test import CFDFunctionProcessTest +from cfd_utilities_test import CFDUtilitiesTest def AssembleTestSuites(): ''' Populates the test suites to run. @@ -60,6 +62,7 @@ def AssembleTestSuites(): smallSuite.addTest(EmbeddedVelocityInletEmulationTest('testEmbeddedVelocityInletEmulationSymbolic2D')) smallSuite.addTest(NavierStokesWallConditionTest('testNavierStokesWallCondition')) smallSuite.addTest(FluidAnalysisTest('testSteadyAnalysisSmall')) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([CFDUtilitiesTest])) #smallSuite.addTest(BuoyancyTest('testBFECC')) # I'm skipping this one, it varies too much between runs JC. # Create a test suite with the selected tests plus all small tests @@ -101,6 +104,7 @@ def AssembleTestSuites(): nightSuite.addTest(FluidAnalysisTest('testSteadyCylinder')) nightSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([IntegrationPointStatisticsTest])) nightSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([CFLOutputProcessTest])) + nightSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([CFDFunctionProcessTest])) # For very long tests that should not be in nighly and you can use to validate