I did some simple simulations and got good results -- numbers agree with empirical results.

So I decided to try to apply CFD to an inline gas filter. The filter consists of a housing and a pleated fabric filter. The fabric has around 50 pleats with a porosity of 0.4. I simulated the porosity by cutting slots in the CAD model pleats equally to about 40% of the surface area.

Initially, I started out with USCS units without changing the openFoam unit system and got results within expectations.

Unfortunately, ParaView only appends metric values to the charts so I decided to change to metric units.

By the way, I am using the snappyHexMesh GUI for Blender and STL files generated by Fusion 360. I am trying to use icoFoam. I measure U by using a ParaView line plot across a suitable section of the filter. I use U to calculate the flow rate in SCFH.

I fix the pressure across the filter and want to calculate U. The study I now have is not affected by the pressure values, and has huge Courant values, and divergent residuals. Because of the pleated fabric filter, a lot of small cells are in the model and my delta t is very, very small.

So far I can't seem to get a handle on the problem. ]]>

In the following discussion, we will mainly focus on the use of RANS models since they are the most widely used approach for calculating industrial flows and can be found in most commercial CFD softwares (noting StarCCM+ and Fluent) and non-commercial CFD softwares (like OpenFOAM).

RANS stands for

- k-epsilon model
- k-omega model
- Spalart-Allmaras model

An interesting variation of the standard k-omega model, is the k-omega SST, where SST stands for

For more curious readers, i would suggest the following book, from which i would suggest reading the following book : Rodriguez, Sal. (2019).

or watch the following video : RANS Turbulence Models: Which Should I Choose?

You can also dowload my open source calculator of initial values and boundary conditions of some of the most common turbulence models : github.com/wassim-abdelnour/Turbulence-Calculator

The following animation shows the velocity profile of an air flow over NACA 4415 airfloil, free-stream velocity is 1 m/s. ]]>

I am happy to announce the next occasion of the monthly meeting on the 18th of February 2023 at 14:00 German Time (UTC+1). The meeting takes place using zoom with the attached room details (only visible when logged in). In parallel the meeting times are announced in this calendar for integration in a mail client and as website. Details can be found in this thread.

Everybody is welcome.

See you there.

Patrick ]]>

First，you should go to this site: https://cn.ubuntu.com/download. In this site ,you can install this package. The package's name is ubuntu-22.04.1-desktop-amd64 (1).iso . it's type is iso. After you download it, you should reserve it instead of releasing it. Then, you should install a software named Vmware Work Staion. Last, you should download openfoam and thirdParty. When you finish the installation of Vm and ubuntu Then you can begin to install your openfoam.

First，when you open the terminal in the ubuntu system, you can put this code in it: mkdir OpenFOAM Then copy your openfoam and thirdParty into the OPenFOAM docement.

Then, you should input this code:

sudo apt-get update

sudo apt-get install build-essential autoconf autotools-dev cmake gawk gnuplot

sudo apt-get install flex libfl-dev libreadline-dev zlib1g-dev openmpi-bin libopenmpi-dev mpi-default-bin mpi-default-dev

sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev

After you finish it, you also should input this code to check your software version:

sudo apt-cache show gcc

sudo apt-cache show libopenmpi-dev

sudo apt-cache show cmake

sudo apt-cache show flex

sudo apt-cache show m4

After the system running it, you can:

sudo apt-get install libfftw3-dev libscotch-dev libptscotch-dev libboost-system-dev libboost-thread-dev libcgal-dev

Then, it is time for you to set up enviorment varies:

gedit ~/.bashrc

When you input the code, a texttile will appear and you can put code:source ~/OpenFOAM/[your openfoam name]/etc/bashrc at the last to set up correct enviorment varies.

After you finish it , you should close the terminal and restart it to create the varies.

Finally it is time for you to install your openfoam what you have download from Internet. First, you should put code: cd Openfoam

then : ./Allwmake -j -s -q -l [Pay attention, if you receive the error "icoFoam not installed" at last, you should exclude the -p out of this code]

Finally, we can install the thirdparty; First, you can input : sudo apt install paraview-dev

sudo apt install cmake qtbase5-dev qttools5-dev qttools5-dev-tools libqt5opengl5-dev libqt5x11extras5-dev libxt-dev

After yuo finish the progress, you can input:

cd Openfoam [if you have already in this oposition, you can not input the code]

Second, input this kind of code : ./Allwmake -j -s -q -l

Finally, you will finish the openfoam and paraview in your virtual system.

I hope it can help you to solve your troubles.

At last , if you do not want to follow this progress, you can down a complete package from this site() and then install to your virtual system directly.

If you have any question about it , we can discuss with each others below the comments. ]]>

Before we proceed, since there are a couple of main scientific schools in the world that use different notation, let me declare some notations that I'm going to be using:

<-- this dot is just a general sign for multiplication; both multiplication of scalars and scalar multiplication of vectors can be denoted by it; obviously, if I multiply vectors, I will denote them as vectors (i.e. with an arrow above), everything that doesn't have an arrow above is a scalar

and are tangent and cotangent respectively

is logarithm with the base of 10

is natural logarithm

, and are all the same thing

If we want to describe a two-phase gas-liquid or liquid-liquid flow mathematically, we write the Navier-Stokes for each phase. That's the general consensus of fluid mechanics community (though, I, personally, do not absolutely agree with it).

Such a system of equations is difficult to solve. Therefore, people started simplifying the equations - even throwing away some equations - by, of course, simplifying the physics of the flow they want to describe.

Such systems of equations are called reduced order models. Note, that when you simplify and throw away the equations, you end up having less equations than unknowns in general. Therefore, people try to come up with so called closure relations that are meant to be very simple (preferably, linear algebraic equations) and bring the total number of equations to the total number of unknowns.

That changes the flow physics a lot, but gives you general understanding of the flow behavior. In other words, that doesn't give you the details of the flow but, rather, gives you general characteristics of the flow.

One of such models is called drift-flux model. Its closure relation is called slip relation.

Drift-flux model is one of those models that simplifies the physics to the highest degree possible. It's not suitable for detailed flow description. But if, for instance, you are interested in an approximate pressure drop in a several kilometers deep oil well, that's your model of choice. It will give general understanding of what pumps to use and the cost of running it is very low.

The theory of the drift-flux model was developed by Mamoru Ishii, an emeritus professor at Purdue.

The development of the slip relation started before Mamoru Ishii, but he made a significant contribution to it. The slip relation is used on its own sometimes.

Mamoru Ishii, Takashi Hibiki, "Thermo-fluid dynamics of two-phase flow", 2nd edition, 2011, Springer is the fundamental book on the modeling of two-phase flows in general and the drift-flux model in particular.

The reduction of the physics in the drift-flux model is briefly described by the following. What if one imagines a fluid-fluid flow as the flow of fully diluted gas mixture for which the theory is well developed. One can do that, but should do something with the fact that as opposed to a gas mixture, a bubble in water moves relative to the water due to buoyancy. The theory of gas mixture flow doesn't account for that. Therefore, one must amend the theory of gas mixture flow to account for the drift (slip) velocity of bubbles if he wants to apply that theory to bubbly flows (or other two-phase flows).

In order to account for that, one should use the slip relation.

One of the main parameter in the slip relation is drift velocity. There are many empirical equations for the drift velocity.

OpenFOAM offers the choice of two equations for the drift velocity.

Those equations are accessible under the relativeVelocityModels in OpenFOAM.

NOTE: I have a suspicion that OpenFOAM means something else under driftFluxFoam, I'm still investigating that.

The structure of the code behind relativeVelocityModels is shown here.

You can choose between simple and general drift velocity models.

Note, that in C++, you use two-file system. In .H files, you declare variables and functions. In .C files, you assign values and expressions to the variable and functions declared in .H files.

Therefore, the formula for the simple drift velocity model is shown in the file simple.C, see line 66. It was declared in the file simple.H, see line 90.

The simple drift velocity model goes as follows:

The formula for the general drift velocity model is shown in the file general.C, see line 67. It was declared in the file general.H, see line 93.

The general drift velocity model goes as follows:

The names of some of the parameters in these formulas are:

- is called diffusion velocity, see, e.g., general.H line 92
- is called drift velocity, see, e.g., general.H line 63
- is declared in the createFields.H file (see line 57), which is a part of interPhaseChangeFoam, and not the part of driftFluxFoam.

Instead, these equations are pretty much the same in OpenFOAM10 (the differences are negligible). And OpenFOAM10 commit history readily gives you the commit where the reference to the article is given.

Thus, these equations and their parameters are after Michaels, Bolger, "Settling rates and sediment volumes of flocculated kaolin suspensions", 1962, Industrial and engineering chemistry fundamentals, 1(1), p.24-33. See this commit in the OpenFOAM10 general.C file.

Once I've found the article, it became clear to me that the drift velocity models used in driftFluxFoam are designed for liquid-liquid flows, where one of the liquids should better be non-Newtonian mud (sludge, slurry).

It became clear to me why all the driftFluxFoam tutorials are focused on liquid-liquid scenarios. Especially, dahl tutorial that talks about sludge and water.

That is sufficient knowledge for me at this point, because I'm working with gas-liquid flows, closure relations for which are different from liquid-liquid flows. That is why I didn't look deeper into the theory of the presented closure relations for drift velocity and, thus, I'm not talking about them here. Dear community members with the knowledge on them, please, provide them in the comments and I'll amend the blog.

I'm turning my attention to the main system of equations that constitutes driftFluxFoam.

I've been digging them out from the code for several days already to no success so far. Once I'm ready, I'll post them in another blog entry. ]]>

http://https://openfoamwiki.net/inde...oam-extend-4.1

Code:

dnf install -y python3-pip m4 flex bison git git-core mercurial cmake cmake-gui openmpi openmpi-devel metis metis-devel metis64 metis64-devel llvm llvm-devel zlib zlib-devel ....

Code:

{ echo 'export PATH=/usr/local/cuda/bin:$PATH' echo 'module load mpi/openmpi-x86_64' }>> ~/.bashrc

Code:

cd ~ mkdir foam && cd foam git clone https://git.code.sf.net/p/foam-extend/foam-extend-4.1 foam-extend-4.1

Code:

{ echo '#source ~/foam/foam-extend-4.1/etc/bashrc' echo "alias fe41='source ~/foam/foam-extend-4.1/etc/bashrc' " }>> ~/.bashrc

Code:

pip install --user PyFoam

Code:

cd ~/foam/foam-extend-4.1/etc/ cp prefs.sh-EXAMPLE prefs.sh

/usr/bin/bison

Code:

# Specify system openmpi # ~~~~~~~~~~~~~~~~~~~~~~ export WM_MPLIB=SYSTEMOPENMPI # System installed CMake export CMAKE_SYSTEM=1 export CMAKE_DIR=/usr/bin/cmake # System installed Python export PYTHON_SYSTEM=1 export PYTHON_DIR=/usr/bin/python # System installed PyFoam export PYFOAM_SYSTEM=1 # System installed ParaView export PARAVIEW_SYSTEM=1 export PARAVIEW_DIR=/usr/bin/paraview # System installed bison export BISON_SYSTEM=1 export BISON_DIR=/usr/bin/bison # System installed flex. FLEX_DIR should point to the directory where # $FLEX_DIR/bin/flex is located export FLEX_SYSTEM=1 export FLEX_DIR=/usr/bin/flex #export FLEX_DIR=/usr # System installed m4 export M4_SYSTEM=1 export M4_DIR=/usr/bin/m4

Code:

foam Allwmake.firstInstall -j

I, Dr. Prabhakar Bhandari looking for an collaborative research in the field of microchannel heat sink. The work is totally numerical simulation based. If any body interested can email me on prabhakar.bhandari40@gmail.com ]]>

Quote:

Hi,
In icoFoam's code, we have: Code:
fvScalarMatrix pEqn ( fvm::laplacian(rAU, p) == fvc::div(phiHbyA) ); This equation is deduced by myself. If it was wrong just correct me. |

The argument of fvc::div(phiHbyA) is declared as a surfaceScalarField:

Code:

const surfaceScalarField& phiHbyA,

That gives a hint that the class function fvc::div() must have a constructor that takes a surfaceScalarField and return a volVectorField by summing the 6 surface fluxes of each cell and dividing by the cell's volume, to finish the job of computing the divergence of a volume vector field by way of the total surface flux of the cell divided by the cell volume.

The openFoam.com code browser indeed points to https://www.openfoam.com/documentati...ce.html#l00161

Code:

namespace fvc { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template<class Type> tmp<GeometricField<Type, fvPatchField, volMesh>> div ( const GeometricField<Type, fvsPatchField, surfaceMesh>& ssf ) { return tmp<GeometricField<Type, fvPatchField, volMesh>> ( new GeometricField<Type, fvPatchField, volMesh> ( "div("+ssf.name()+')', fvc::surfaceIntegrate(ssf) ) ); }

Code:

namespace Foam { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace fvc { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template<class Type> void surfaceIntegrate ( Field<Type>& ivf, const GeometricField<Type, fvsPatchField, surfaceMesh>& ssf ) { const fvMesh& mesh = ssf.mesh(); const labelUList& owner = mesh.owner(); const labelUList& neighbour = mesh.neighbour(); const Field<Type>& issf = ssf; forAll(owner, facei) { ivf[owner[facei]] += issf[facei]; ivf[neighbour[facei]] -= issf[facei]; } forAll(mesh.boundary(), patchi) { const labelUList& pFaceCells = mesh.boundary()[patchi].faceCells(); const fvsPatchField<Type>& pssf = ssf.boundaryField()[patchi]; forAll(mesh.boundary()[patchi], facei) { ivf[pFaceCells[facei]] += pssf[facei]; } } ivf /= mesh.Vsc(); }

Regrettably, MPI and parallel distributed computing is one of those areas where textbooks and online examples (even SO) are largely useless, as most (if not all) of them just simply go into the details of how to use this or that feature. But most examples are so toy level that you even find cases where the presented code just works for a fixed number of processes (aaargh!).

Every MPI use case is very specific but, I want to present here two examples that are so simple and stupid that it is a shame they are not present in every single book or tutorial. Yet, they have both very practical use cases.

The first MPI piece I want to present is, superficially, related to the necessity to perform a deadlock avoiding loop among all processes. This problem, however, really is a twofold one. On one side, the main issue is: how do I automatically schedule the communications between processes so that, for any couple of processes and , if the communication partner of process is process then the communication partner of process is process ? With a proper communication schedule in place, avoiding deadlock, which is the second part of the problem, is then definitely a triviality (also present in most MPI examples). It turns out that such communication schedule is a triviality as well, to the point of being a single liner solution, so it really is a shame that it is not presented anywhere (to the best of my knowledge). So, here it is a pseudocode example of a loop where each process communicates with each other process (including itself) without deadlock (full Fortran example here):

Code:

nproc = mpi_comm_size !How many processes myid = mpi_comm_rank !My rank among processes !Loop over all processes for i = 1 : nprocs !My communication partner at the i-th stage myp = modulo(i-myid-1,nproc) if (myid>myp) then !The process with higher rank sends and then receives mpi_send mpi_recv elseif (myid<myp) then !The process with lower rank receives and then sends mpi_recv mpi_send else !This is me, no send or recv actually needed endif endfor

Now, the pseudo-code above (and the one in the linked gist as well) is just an example, and you should not,

The second easy MPI piece is related to a very simple case: how would you write your own reduce operation without using mpi_reduce but just mpi_send/recv? While this might just look like a textbook exercise, it is indeed relevant for those cases where the needed reduce operation is not among the intrinsic ones of MPI (SUM, MAX, etc.). I first had a need for it when working on parallel statistics (e.g., how to compute the spatial statistics of a field variable in a finite volume code without using allreduce, which costs just like an mpi_barrier?).

For the most complex cases, MPI provides both an mpi_type_create_struct routine to create a generic user-defined data type and mpi_op_create routine to define a custom reduction operation for said data type (see, for example, here, here and here). Unfortunately, they can't actually cover all use cases, or at least not so straightforwardly.

However, if there are no specific needs in terms of the associativity of the reduce operator, it turns out that you can write your own reduce algorithm with no more than 25 lines of code (full Fortran example here). The algorithm has 3 very simple steps:

- Determine pp2, the largest power of 2 integer smaller than or equal to the current number of processes
- If the current number of processes is above pp2, ranks beyond pp2 just send their data to ranks that are lower by exactly pp2 (e.g., for 7 processes, zero indexed, ranks from 4 to 6 will send, respectively, to ranks from 0 to 2), which will perform the reduce operation
- Log2(pp2) iterations are performed where, at each iteration, the higher half of ranks up to a given power of 2, ppd (=pp2 at the beginning of the first iteration), send their data to the lower half (shifting by ppd/2), which will then reduce it. At the end of each iteration ppd is divided by 2.

The final reduce operation will then be available to the process with rank 0 (which could simply send it to the required root, if different). Note that the algorithm still needs nproc-1 messages to be sent/received but, differently from the naive case where a root process directly receives all the messages one after the other, here the messages of each stage are always between different couples of processes. Of course, by using such simple approach you abandon the possibility to use any possible optimizations on the MPI side (which, however, might not be available at all for the user defined data type and operator), but there is a very large gain in flexibility and simplicity.

If there are associativity needs, you can instead follow this Fortran example, where the MPICH binomial tree algorithm is used. The algorithm (which is shorter and largely more elegant, yet a bit dense in its logic) performs the reduction by following the rank order of the processes, so it is very easy to map them in order to follow a more specific order. ]]>

In all such cases, the formulas presented before are still valid but need a slight rearrangement in order to fit the new conditions. Nothing of this is really new, the concpet is as old as the book of Patankar (probably older) and this is just one of the latest additions. Also, major commercial CFD codes have been offering this for decades. Still, I am not aware of full formulas available in the more general case. Everything I write here for the temperature just straightforwardly applies to other scalars with similar equations. Of course, as per the original wall function ODE, the assumption is that of steady state. That is, the solved problem might or not be steady, but the boundary conditions are, in fact, derived by solving a steady state problem (this was, as a matter of fact, true also for the wall function ODE, even if the unsteady term was considered among the non equilibrium ones).

We start by noting that the wall heat flux formula provided here can actually be rewritten as follows (also taking into account that the original derivation used a wrong sign for ease of exposition):

Where and it is recognized that, being independent, at the first order, from the flow conditions and being an integral that grows with wall distance, the non equilibrium terms are, indeed, just an explicit source term for the near wall cell. In practice, the source term is also assimilable to a non orthogonal correction thus, in the following, we will simply consider the point , with temperature and distance from the wall to be along the normal to the wall. A similar reasoning can also be done for the viscous dissipation that, as presented here, is independent from the temperature distribution and can be absorbed by the same source term as well.

We want to extend the formula above to the case where neither nor are actually given. Also, we assume that and , that is, they are only known as the values at the extreme of an n layers thin wall. So we have , , ..., and , and the same for . They are are the temperatures and fluxes at the intefraces between the n layers of the thin wall. Each one of these n layers will have its own thickness , thermal conductivity and possibly a source term . Finally, we want to consider two possible boundary conditions, either directly given or given as:

with being non-linearly dependent from and where we assumed that the are positive if entering the domain.

In order to formalize a solution, we need to complement the fundamental conservation statement that holds for a layer in the thin wall with a similar relation for the temperature jump across the layer, . Considering that, in our model, the heat conduction equation that holds in each layer has the form:

solving it with proper boundary conditions one easily obtains that:

The two jump relations for single layers above can then be used to obtain jump relations across the whole thin wall of n layers. For the flux it is just, again, a simple conservation statement:

For the temperatures one obtains:

Assigning:

where the latter 3 can all be pre-computed and stored, then it is a matter of simple manipulation (yet a quite long one, which is omitted here), to show that our initial formula can now be generally expressed as follows:

where and depend from the specific boundary condition in use. More specifically, for directly assigned, one has and . For the general convection/radiation boundary condition (or just one of the two, by zeroing the coefficient of the other) one has:

Finally, the coupled case is simply obtained by using , and where the subscript refers to the quantities taken from the coupled side.

The corresponding value of is instead given by:

The last step missing is the determination of , which depends from . A relation for the latter can be obtained, but itself, of course, will depend from . This relation (whose derivation is again simple but long, so it is omitted here) can then be used in tandem with the one for iteratively:

I have found that, starting from no more than 10 iterations are necessary to converge on and .

One thing which is worth highlighting here in the more general context of wall functions is that, as a matter of fact, non equilibrium/viscous dissipation terms (from both sides of the thin wall, if a coupled bc is used) do not directly enter the modifications presented above. That is, they still appear as in the original wall function formulation. This might very easily go unnoticed if a thermal wall function is just presented as a single relation for without distinguishing the roles of the terms.

Another thing worth noting is that, if one decided to solve the original ODE as it was (say, with a tridiagonal algorithm as in one of the scripts provided here), instead of directly integrating it as done here, it would have been impossible to let the exact form above emerge, leading to 3 major consequences: 1) inability to separate the non-equilibrium/viscous dissipation part from the rest (that is, in the ODE solution one only has the wall values, not their dependence), 2) either the need to solve the 1D problem also in the thin wall and/or coupled side or the need to iterate the solution on both sides exchanging wall values at each iteration and 3) which is a consequences of 1 and 2, the impossibility to set up the problem for an implicit implementation in the coupled case, which might have major consequences on convergence in certain cases.

Finally, I want to mention that all the above developments are also relevant for the Musker-modified Spalart-Allmaras model for which, given the proper conditions (equilibrium for the velocity, steady state in general), they represent a full analytical solution, which now is thus extended to the present more general boundary conditions. ]]>

with its obvious extension to the velocity case. In order to go back to the framework presented here one should notice that:

from which, it follows that:

which is all that is needed to compute (numerically if not doable analytically) the remaining integrals for non equilibrium and/or TKE production terms.

For the non equilibrium terms this leads to the following:

Hence, integration by parts finally leads to:

Formally, this is the generalized trick that I used here to extend the Reichardt wall law to constant only non equilibrium cases (i.e., i=0). ]]>

A first integration leads to:

where is the integral of and has the same form we assumed for , just with its coefficients divided by . Then a further integration leads to:

The first integral in the equation above has been the subject of the previous posts, while the neglected viscous dissipation term is the last term in the equation. Now, there are two ways which could be used to proceed. A first one involves invoking the velocity equation and transforming the viscous dissipation term as follows:

where has the same form as , but with the velocity coefficients. At this point, then, one can note that the integral has the exact same form of the first one, but with the additional velocity in it. I have not attempted to solve it with none of the models presented but, even if doable, I expect high levels of cumbersomeness.

One could approximate the integral by assuming a constant, representative, value for , say, and take it out of the integral. In this case, while one should still be careful in mixing the velocity numerator with the temperature denominator in the integrand, the resulting integral would be formally identical to the first one, which we have solved in previous posts.

A second, preferred way to proceed would instead first recognize that the integral above can be transformed as:

Hence integration by parts leads to the following result:

At this point we are still left with an even more cumbersome integral to evaluate, if possible at all. However, this integral is exactly 0 in two special cases: fully laminar ones () and when . Another advanatge of this form is that if we now assume a constant, representative, value for , say, and take it out of the integral, we are left with no more work to do and just obtain:

which also always works in the cases where the integral is exactly 0. Of course, we are now left with determining , but this seems a more reasonable task, also because it must be representative just for the region where derivative in the integrand is not 0 and not the full y length. A value for commonly used with standard wall functions is the velocity at . By extension, for the Musker-Monkewitz wall function one could use the velocity at , the profile constant modified by the ratio (see here). In more general cases, it seems that a good generalization for is the velocity at the point where , which is where the term under the derivative reaches half its maximum excursion.

However, this whole presentation is an approximate solution to the original problem for the viscous dissipation, that's why I left it out of the general discussion of the previous posts. ]]>

The first group of scripts is actually made of functions, that you are not supposed to directly call or modify:

**muskersp.m**: returns , and as shown here. It only works for N up to 0 (constant non equilibrium terms)**EDIT: There is an apparently innocuous mistake in the limiting behavior of s, as it should not use the factor prprt for the thermal case. It seems innocuous as it only affects the first order term, which probably is already negligible, and only for the temperature case (so in the scripts it is only used for plotting purposes, and probably never at those low ).****standardsp.m**: returns the same quantities but for the standard wall function presented here. It works for arbitrary N but the scripts below only test it up to 0 (constant non equilibrium terms)**iteryv.m**: returns the value of needed by standardsp.m for**numericalsp.m**: a generic wall function that takes as input a function handle for the turbulent viscosity ratio and provides the required integrals by numerical integration. It works for arbitrary N (but, again, it is only tested for N up to 0). It only works for turbulent viscosities going to 0 at least as fast as .**standard.m**: the actual standard wall function adapted to the present framework for comparisons. Only works for equilibrium cases (N=-1)**spiter.m**: the function that performs the iterations on the wall functions to find following what is presented here**sa1d.m**: solves the original ODE of the problem (actually a slightly more general one) using a second order cell centered finite volume discretization, the Spalart-Allmaras turbulence model (actually a generalized version that also works with the Musker profile) and the tridiagonal solver

The second group of scripts is the one actually making the tests and the comparisons:

**check.m**: for given flow conditions, it tests that a) the analytical musker profile in muskersp is consistent with the one obtained trough numerical integration with numericalsp, b) that the numerical musker profile (and, by point a above, also the analytical one) is consistent with the Spalart-Allmaras direct solution of the ODE with a properly modified fv1 function c) that the numericalsp routine (already tested in a and b above) is consistent with the non modified Spalart-Allmaras solution of the ODE when the relative turbulent viscosity profile is used. Note that the velocity wall function can only match the Spalart-Allmaras solution in the equilibrium case (dpdx=0), but in the same case the temperature equation can have non equilibrium terms and the solutions will match.**wfiter.m**: for a given wall function (user selectable) and flow conditions plots the iterations to find as produced by itersp.m**wfcompare.m**: a straightforward comparison of multiple wall functions for given flow conditions**wfmap.m**: for the musker profile (but easily adaptable to other profiles) it maps the solution of the iterative procedure to find in a certain range of and parameters.**apr.m**: a comparison of the variations of the constant in the Musker profile and in the standard profile as a function of giving a sensation of how the variation of the Musker constant with is, indeed, a sort of Jayatilleke term.

Few comments on the use of the scripts above and some claims made in previous posts.

In the second post of this series I mentioned that, when using the Spalart-Allmaras model, one could avoid iterations to find by using . This is confirmed in check.m where the Spalart-Allmaras boundary conditions for the solution of the 1D ODE are obtained from the relation above using as input the value obtained by the underlying wall function.

In the same post it is also mentioned that one could precompute the wall function for a given range of parameters and later interpolate from it. Such precomputation is what the script wfmap.m does, and you can also see from the commented parts how it could be adapted to directly use the 1D ODE solution instead of the musker profile actually used by the script.

Still in the same post, I mentioned how, for non equilibrium cases, the iterative computation of might become cumbersome as multiple solution branches might exist for non favourable pressure gradients. This can be easily visualized by using wfiter.m.

It has been mentioned here that in the standard profile can be obtained by few iterations of the Halley's method. The specific implementation is in iteryv.m.

In the last post I have mentioned that the van Driest damped mixing length is, indeed, mostly equivalent to the Musker profile for the incompressible formulation used here. This is clearly shown in wfcompare.m. While I don't directly provide the 1D ODE solution with the mixing length (just its wall function form trough numericalsp), I do for two different turbulent viscosity formulations trough the Spalart-Allmaras model in check.m and show that they correspond to the analogous formulation used as wall function.

All the scripts are in a zipped folder for convenience (as a maximum of 5 files can be uploaded here) and have been tested with MATLAB R2022a.

where is the von Karman constant and is a constant that specifies the for which but, in practical terms has the same role of in the standard wall function of the previous post.

There are really several reasons for which this profile is relevant. First of all, it is a continuous, all profile which has the correct limiting near wall behavior as well as the correct logarithmic behavior. Second, as already mentioned here, it has a nice closed form solution. The third reason, as already stated here, but worth restating here, it allows computing the temperature integrals:

from the same formula for the velocity integrals:

by properly redefining the two profile constants and , so it works for arbitrary ratios (or, seen differently, the constant redefinition of the model is, in its own, a model like the Jayatilleke term for the standard wall function). Finally, the model has a strong similarity with the behavior that the Spalart-Allmaras turbulent viscosity assumes in equilibrium conditions ( in the SA model):

Which means that, for a properly coded Spalart-Allmaras model, changing a constant and an exponent is all that is required to let it have a closed form analytical solution for arbitrary ratios which is also, obviously, its own wall function.

Note that the original Spalart-Allmaras turbulent viscosity can be analytically integrated as well. But differently from the Musker one, the solution is only known in terms of numerical constants. Which means that, for each given ratio, the numerical constants must be recomputed, which is not very useful.

Back to the present Musker-Monkewitz solution, after substitution of the turbulent viscosity profile in the integrals above, and reminding that we only need the one for the velocity (from which temperature and scalars can be obtained), one obtains:

for the velocity and:

for the average turbulent kinetic energy production, with . Now, it is easy to obtain closed form solutions to the integrals above for each value of i, but a closed form solution that works for arbitrary i seems out of reach. In the final scripts I will provide a solution just for the constant non equilibrium term (thus for i=-1 and i=0), but here I just want to highlight that, heuristically, solutions to the integrals above seem to have the following forms ():

with:

where the and are constants which are only function of . Thus, notably, one only has to compute a given integral with a symbolic toolbox and pick up the constants expressions, as the functions are fixed (and 3 of 4 common between the two integrals).

The last thing which is worth mentioning about the Musker-Monkewitz wall function is that, as will be shown running the scripts provided in the last post of this series, it very closely follows a turbulent viscosity prescription which is very popular in the LES community that directly solves the original ODE with a tridiagonal solver (like this), the van Driest damped mixing length:

Thus, the take home message here is that, unless you are adding compressibility effects, you are wasting resources, because the Musker-Monkewitz profile is, to all the practical means, identical. Large differences only arise at very large ratios, say, 100 or more.

Finally, following the general discussion here, it is worth mentioning that the same feature that makes the Musker-Monkewitz profile adaptable to any ratio, also makes it easily adaptable to any relevant turbulence model (yet, of course, not exactly). What is needed is just a different law to modify the profile constant, one that can be derived by adapting the Musker profile to the given model profile instead of the one embedded in the model. Such adaptation, which should be done in equilibrium conditions, can be very easily performed as a non linear least-squares optimization. ]]>

where is the von Karman constant and is, for the moment, an unspecified positive parameter. One can then show that the following results:

where , , and:

The general problem with the standard formulation is that, while it is reasonable to pick up an value for the velocity case, even a second one for the TKE production (rigorous doesn't mean stupid, so if different values work better for and , why not?), it is not reasonable to manually pick a value in for each value of the ratio .

As it turns out, however, the above formulation requires modifying only for , but just works in all the other cases. This statement just accounts of the fact that for the turbulent viscosity ratio becomes less and less important, while it becomes more and more important in every detail when multiplied by the ratio .

The case is correctly accounted by the present formulation because it has not neglected the 1 at the denominator of the integrand function in and because the solution is not arbitrarily expressed in terms of the velocity one with all the logarithmic constants lumped in a single one (typically E). The fact that the formulation still doesn't work for is just a statement of the fact that, in this case, the turbulent viscosity ratio becomes important for the temperature distribution before it does for the velocity one, so in must be reduced. Let's call this new value (yet, this is only needed for ).

As the Jayatilleke P term exactly embeds this exact same concept, it is easy to show that it can be used by computing from the following non linear, implicit equation (a similar one must be solved also for the classical standard wall function):

where is the original value used in the velocity profile and P is the mentioned Jayatilleke term (but any similar correlation can substitute it in the equation above, say the Spalding one). I have found that, initializing as , 3 iterations of the Halley's method are sufficient to compute close to machine precision for any practical value of . ]]>