Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FluidApp] Adding CFD utilities to calculate Y_PLUS and U_TAU #7039

Closed
wants to merge 56 commits into from

Conversation

sunethwarna
Copy link
Member

@sunethwarna sunethwarna commented Jun 9, 2020

This adds a "CFDUtilities" namespace which includes following methods

  1. Linear-Logarithmic y_plus limit calculation method based on kappa and beta
  2. y_plus and u_tau calculation based on linear-logarithmic law for slip walls (velocity is taken from condition center and tangential velocity is calculated). In here wall distance is wall normal distance to the center of the parent element of each condition. y_plus and u_tau is stored in condition data value container
  3. y_plus and u_tau calculation based on tangential reaction. (no wall laws assumed). y_plus and u_tau is stored in condition data value container
  4. A method to distribute y_plus and u_tau to nodes from conditions

A seperate process with json interface is also added to this PR, if someone prefers to calculate y_plus and u_tau without altering run scripts. Otherwise, all CFDUtility methods are exposed to python level so one can use directly those methods. Tests are also added. FluidDynamics tests are passing in FullDebug.

Require #7113 for windows compilation

Copy link
Member

@RiccardoRossi RiccardoRossi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sparse comments, although i am not done with the revision

m.def_submodule("CFDUtilities")
.def("CalculateNumberOfNeighbourConditions", &CFDUtilities::CalculateNumberOfNeighbourConditions)
.def("CalculateLinearLogarithmicWallFunctionBasedYPlusLimit", &CFDUtilities::CalculateLinearLogarithmicWallFunctionBasedYPlusLimit,
py::arg("von_karman") = 0.41,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is done this way to oblige using kwargs?

Copy link
Member Author

@sunethwarna sunethwarna Jun 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this merely to avoid everytime passing the well known values for constants used in wall modelling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the best pf my understanding (it these are kwargs) you are impicitly adding a dictionary on every call.

this will be negligible if you call once the function for many elements, however it wouldn't be acceptable if you are calling it once per node.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These python level calls are not used at the moment, I just exposed them to python in case someone wants to use them in their own scripts. If someone uses them, they need to call this method for every entity (node, element, condition). So I will remove them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -0,0 +1,442 @@
// | / |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit lost. You are adding a lot of unrelated stuff in here no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are few unrelated stuff like EvaluateInPoint, CalculateConditionGeometryData, which are copies taken from elements and conditions. I couldn't find a central place where they are implemented for reuse, each time we define them in the elements or conditions. :/

CalculateConditionNormal method is there in NormalCalculataionUtils, but it assigns nodal historical value NORMAL as well which is problematic. That is because if these methods are used along with wall boundaries, and there is an adjacent SLIP boundary, using the method in NormalCalculationUtils will overwrite NORMALs of common nodes to wall boundaries and SLIP boundaries with wall boundary normals. :/


const int number_of_conditions = rModelPart.NumberOfConditions();
#pragma omp parallel for
for (int i_cond = 0; i_cond < number_of_conditions; ++i_cond)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would advise using the loop as in the parallel utilities:

https://github.com/KratosMultiphysics/Kratos/wiki/Parallel-Utilities

that would make your code cleaner

Copy link
Member Author

@sunethwarna sunethwarna Jun 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done :) It is really clean now :) thanks...

m.def_submodule("CFDUtilities")
.def("CalculateNumberOfNeighbourConditions", &CFDUtilities::CalculateNumberOfNeighbourConditions)
.def("CalculateLinearLogarithmicWallFunctionBasedYPlusLimit", &CFDUtilities::CalculateLinearLogarithmicWallFunctionBasedYPlusLimit,
py::arg("von_karman") = 0.41,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the best pf my understanding (it these are kwargs) you are impicitly adding a dictionary on every call.

this will be negligible if you call once the function for many elements, however it wouldn't be acceptable if you are calling it once per node.


class CFDFunctions:
@staticmethod
def GetFunction(params):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is a CFDFunction?

a process? I am a bit lost about the use of this, in particular about the role of "GetFunction"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetFunction is not a process. It is a wrapper for cfd utility methods. These are wrapper functions to be used in the json settings. All of them are standalone functions. As an example, this way it enables me to use reaction based y+ (for no slip) and wall law based y+(for slip with wall functions) calculations in the same simulation, and distribute them to nodes appropriately. (Still the common node between no slip and slip will have a problem).

This also makes having new cfd methods easily extensible to json settings using the same cfd_function_process.py. No need to have different python processes for different cfd utility methods.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THB I don't love the idea of implementing an additional concept in parallel to the processes. I.e. this could easily be done with separate processes (for which several py-scripts are needed ofc).

Is the only reason to do it as you propose bcs you don't want the additional py-scripts? Or would you have additional overhead?

To me the current script (cfd_function_process.py) is completely unreadable :/

If we really want to go this way then why not what is done in the HDF or the statistics app? There it is cleaner IMO

"Parameters": {
"model_part_name": "MainModelPart.NoSlip2D_left_wall",
"function_settings": {
"function_name": "CalculateYPlusAndUTauForConditionsBasedOnReaction",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why didn't u use two distinct processes for this and for the next?

"help": "",
"Parameters": {
"model_part_name": "MainModelPart",
"function_settings": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, theses should be separated processes...i see no reason for having a nested function_settings

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason behind this is, if I am to use different processes, then I need to have different python files which will have same code redundancy. I wanted to reduce code redundancy as much as possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the point is that doing the way you do it is non-standard.

wouldn't it be possible to have a base_cfd_utility_process which implements the common code, and to derive all other processes from that one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats possible. I will change it like that :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THB I don't love the idea of implementing an additional concept in parallel to the processes. I.e. this could easily be done with separate processes (for which several py-scripts are needed ofc).

Is the only reason to do it as you propose bcs you don't want the additional py-scripts? Or would you have additional overhead?

To me the current script (cfd_function_process.py) is completely unreadable :/

If we really want to go this way then why not what is done in the HDF or the statistics app? There it is cleaner IMO

Copy link
Member Author

@sunethwarna sunethwarna Jun 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your point, as you stated, only reason I did it like this is to avoid maintaining several py files, make it easier for extending for new methods easily, keep list of files in check inside python_scripts folder. I don't think there is an additional overhead if I do seperate py files, except for overhead in maintaining them.

Could I use folder sctructure in python_scripts with __init__.py? @philbucher @RiccardoRossi @rubenzorrilla

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could I use folder sctructure in python_scripts with init.py

yes, see the CoSimApp

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can speak in person tmr, I think this way we can eliminate some concerns


namespace Kratos
{
namespace CFDUtilities
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a separated namespace?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure that there aren't any conflicting names. Do you think it is not necessary?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I don't think it harms but we normally keep everything in the same namespace. If we want to start using them, I will consensus how to do so to be consistent among applications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any comment about the namespace issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is ok for me to have everything under one namespace, I am in favor of using different namespaces :). In most of the utilities available in Kratos, we are used to have classes and public and/or static methods to nicely package them. I was thinking to do it using namespaces, so then these namespaces can be extended in different files to as it develops. But I have no clue on how to properly adhere to Kratos guide lines about use of namespaces :/ :|

Comment on lines +7 to +10
// License: BSD License
// Kratos default license: kratos/license.txt
//
// Main authors: Suneth Warnakulasuriya (https://github.com/sunethwarna)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header format (tabs and link)

}
}

double CalculateConditionWallHeight(const ConditionType& rCondition, const array_1d<double, 3>& rNormal)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
double CalculateConditionWallHeight(const ConditionType& rCondition, const array_1d<double, 3>& rNormal)
double CalculateConditionWallHeight(
const ConditionType& rCondition,
const array_1d<double, 3>& rNormal)

Style guide for more than one argument functions.

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we call the Jacobian of the geometry? Despite it is more expensive, it would make this compatible with any geometry.

Comment on lines +141 to +142
double CalculateLinearLogarithmicWallFunctionBasedYPlusLimit(
const double VonKarman, const double WallSmoothness, const int MaxIterations, const double Tolerance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
double CalculateLinearLogarithmicWallFunctionBasedYPlusLimit(
const double VonKarman, const double WallSmoothness, const int MaxIterations, const double Tolerance)
double CalculateLinearLogarithmicWallFunctionBasedYPlusLimit(
const double VonKarman,
const double WallSmoothness,
const int MaxIterations,
const double Tolerance)

Comment on lines +173 to +174
const int MaxIterations,
const double Tolerance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd give default arguments to these (same above)

const Vector& gauss_shape_functions = row(shape_functions, 0);

// calculate normal for the condition
const array_1d<double, 3> normal = r_geometry.Normal(local_point);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const array_1d<double, 3> normal = r_geometry.Normal(local_point);
const auto normal = r_geometry.Normal(local_point);


void CalculateYPlusAndUTauForConditions(
ModelPart& rModelPart,
const Variable<double>& rKinematicViscosityVariable,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note what we discussed about Kinematic vs. Dynamic viscosity. Some years ago we decided to favor the use of the dynamic viscosity to be consistent among the different elements. I suggest following this in here.

array_1d<double, 3>& rFrictionVelocity,
const array_1d<double, 3>& rWallVelocity,
const array_1d<double, 3>& rNormal,
const double KinematicViscosity,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the viscosity comment below.


void CalculateYPlusAndUTauForConditionsBasedOnReaction(
ModelPart& rModelPart,
const Variable<double>& rKinematicViscosityVariable,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same viscosity comment.

Comment on lines +336 to +337
const int MaxIterations,
const double Tolerance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd set defaults for these.

Comment on lines +7 to +10
// License: BSD License
// Kratos default license: kratos/license.txt
//
// Main authors: Suneth Warnakulasuriya
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header tabs.

Comment on lines +30 to +31
namespace CFDUtilities
{
Copy link
Member

@rubenzorrilla rubenzorrilla Jun 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To follow what we normally do, I'd create a WallLawUtilities, WallUtilities, CFDWallUtilities or whatever name you prefer class with static methods to follow what we normally do. If there is an specific reason to implement these as functions in a new namespace we can discuss about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, to me using namespaces aka free functions is much cleaner
I.e. when using a class one never knows if e.g. something is saved internally or not etc
With free functions this is very clear
Plus it follows what the standard library does

I think using classes with static methods is a relic bcs we didn’t know a better way
Esp the py-exposure was a problem I think, but now it is solved

return CFDUtilityFunctionProcess(model, settings["Parameters"])


class CFDUtilityFunctionProcess(Kratos.Process):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about exposing these as a process to the user...

Instead, I think we can add the settings to the turbulence_model_solver_settings in the solver_settings. Then the methods must be automatically called internally.

@@ -0,0 +1,132 @@
# Importing the Kratos Library
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the CFDUtilities are implemented as a class with static methods this could be avoided by exposing such class to Python.

Concerning the Parameters input, I think it should be implemented also in the C++ level. The ModelPart + Parameters version of the methods can call the "standard" functions that are already there.

Copy link
Member

@rubenzorrilla rubenzorrilla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need to discuss about the namespace vs. class issue as well as the Python exposition.

@philbucher
Copy link
Member

I think we still need to discuss about the namespace vs. class issue as well as the Python exposition.

I guess this is then for the @KratosMultiphysics/technical-committee

What are your reasons for using class?

I honestly thought that this was dropped long ago, I use namespaces for years already

@rubenzorrilla
Copy link
Member

I think we still need to discuss about the namespace vs. class issue as well as the Python exposition.

I guess this is then for the @KratosMultiphysics/technical-committee

What are your reasons for using class?

I honestly thought that this was dropped long ago, I use namespaces for years already

Well, I've no specific reason more than historical reasons and code organization. I have the feeling that it's easier to search for things if you now they are stored in one class rather than open the possibility to add things to a namespace from different files (possibly this is because I'm not used to work with namespaces).

@RiccardoRossi
Copy link
Member

with respect to the classes vs namespace issue please refer to #7434

@roigcarlo roigcarlo linked an issue Sep 10, 2020 that may be closed by this pull request
@roigcarlo roigcarlo removed a link to an issue Sep 10, 2020
@sunethwarna
Copy link
Member Author

closing since this is done in #10097 .

@sunethwarna sunethwarna deleted the flud-cfd-utility-y-plus branch August 17, 2022 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants