-
Notifications
You must be signed in to change notification settings - Fork 248
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
Conversation
There was a problem hiding this 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, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping @sunethwarna
applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp
Show resolved
Hide resolved
@@ -0,0 +1,442 @@ | |||
// | / | |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. :/
applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp
Show resolved
Hide resolved
|
||
const int number_of_conditions = rModelPart.NumberOfConditions(); | ||
#pragma omp parallel for | ||
for (int i_cond = 0; i_cond < number_of_conditions; ++i_cond) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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.
applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.cpp
Show resolved
Hide resolved
applications/FluidDynamicsApplication/custom_utilities/cfd_utilities.h
Outdated
Show resolved
Hide resolved
|
||
class CFDFunctions: | ||
@staticmethod | ||
def GetFunction(params): |
There was a problem hiding this comment.
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"
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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": { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 :)
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a separated namespace?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 :/ :|
// License: BSD License | ||
// Kratos default license: kratos/license.txt | ||
// | ||
// Main authors: Suneth Warnakulasuriya (https://github.com/sunethwarna) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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; |
There was a problem hiding this comment.
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.
double CalculateLinearLogarithmicWallFunctionBasedYPlusLimit( | ||
const double VonKarman, const double WallSmoothness, const int MaxIterations, const double Tolerance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
const int MaxIterations, | ||
const double Tolerance) |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same viscosity comment.
const int MaxIterations, | ||
const double Tolerance) |
There was a problem hiding this comment.
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.
// License: BSD License | ||
// Kratos default license: kratos/license.txt | ||
// | ||
// Main authors: Suneth Warnakulasuriya |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Header tabs.
namespace CFDUtilities | ||
{ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
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). |
with respect to the classes vs namespace issue please refer to #7434 |
closing since this is done in #10097 . |
This adds a "CFDUtilities" namespace which includes following methods
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