CFD Online Logo CFD Online URL
www.cfd-online.com
[Sponsors]
Home > Forums > Software User Forums > OpenFOAM > OpenFOAM Programming & Development

tmp - stands for 'true macro pain'?

Register Blogs Community New Posts Updated Threads Search

Like Tree48Likes
  • 6 Post By marupio
  • 15 Post By hjasak
  • 1 Post By marupio
  • 16 Post By hjasak
  • 1 Post By cgoniva
  • 3 Post By gschaider
  • 6 Post By Zeppo

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old   January 19, 2010, 14:25
Default tmp - stands for 'true macro pain'?
  #1
Senior Member
 
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22
marupio is on a distinguished road
I've never seen such a chopped-up macro-heavy series of classes before. Just trying to figure out DimensionedScalarField is a nightmare for me (and very humbling).

What is tmp?

It looks like a wrapper class for a field, which redirects its pointer on destruction, provided refCount says it's okay. Is this some sort of sneaky way of ensuring local objects survive function exits to prevent copying on return?

Does OpenFOAM get much more complicated than this? I'm not the most experienced programmer out there...

-Dave
marupio is offline   Reply With Quote

Old   January 20, 2010, 06:40
Default
  #2
Senior Member
 
Hrvoje Jasak
Join Date: Mar 2009
Location: London, England
Posts: 1,907
Rep Power: 33
hjasak will become famous soon enough
Yes - it does get much more complicated than this. But, you get used to it.

tmp is essential and extremely useful. This is a mechanism that avoids copying large chunks of data in memory when you do operations on them. Consider for example

scalarField a(1000000, 1.0);
scalarField b(1000000, 2.0);

scalarField c = a + b;

This calls operator+(const scalarField& a, const scalarField& b), and that needs a return type. If the return type is a scalarField, you will first create and then copy a field of length 1000000 floating point numbers - which hurts and takes time.

Therefore, you make a return type a tmp<scalarField>, where tmp holds a pointer to the actual array. Its (tmp's) constructor, copy constructor and destructor get called, but they do not involve allocation and copying of the real array of data - it just counts the number of references and manages storage.

Clear? Hope this helps...

Now to the real question: this is a piece of optimisation machinery in FOAM. Why do you need to know more (unless you are writing field and matrix operators)? It should all be transparent and automatic.

Good luck,

Hrv
__________________
Hrvoje Jasak
Providing commercial FOAM/OpenFOAM and CFD Consulting: http://wikki.co.uk
hjasak is offline   Reply With Quote

Old   January 20, 2010, 10:47
Default
  #3
Senior Member
 
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22
marupio is on a distinguished road
I figured I was going too deep into the primitives. It's just sometimes I was seeing tmp<> and sometimes I wasn't. For instance, in icoFoam we see:

fvVectorMatrix UEqn

whereas in simpleFoam (UEqn.H) we see:

tmp<fvVectorMatrix> UEqn

... and two days later I have a macro headache. Am I right in thinking the tmp<> is unnecessary in simpleFoam? Otherwise, if it's supposed to work in the background, why should it appear at the top level (in a solver)?

At the moment, I don't intend to write any matrix functions for this project, just a solver with a complex biochemistry model (called ADM1).

begin aside
But the whole reason I'm using OpenFOAM for this project is because my long term goal is to write a new kind of fluid solver that models a fluid as a sort of half-continuum, half-particle cloud. So every fluid quantity has a fully-specified statistical distribution at every point. I imagine that will involve adding new primitive classes and operators (e.g. DimensionedScalarDistributionField).
end aside

-Dave

edit:

BTW You cite operator+ for scalarField: operator+(const scalarField& a, const scalarField& b)... this was the exact function I was looking for, but never found it. I used gcc's preprocessor to assemble the macros, and for DimensionedScalarField, the operator+'s it found are listed below. Note, it always involves a Field and a single scalar. I'm sure it exists... but I couldn't find it. This just goes to show: the deeper you go, the foggier it gets.

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const dimensioned<scalar>& dt1,
const DimensionedField<scalar, GeoMesh>& df2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const scalar& t1,
const DimensionedField<scalar, GeoMesh>& df2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const dimensioned<scalar>& dt1,
const tmp<DimensionedField<scalar, GeoMesh> >& tdf2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const scalar& t1,
const tmp<DimensionedField<scalar, GeoMesh> >& tdf2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const DimensionedField<scalar, GeoMesh>& df1,
const dimensioned<scalar>& dt2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const DimensionedField<scalar, GeoMesh>& df1,
const scalar& t2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const tmp<DimensionedField<scalar, GeoMesh> >& tdf1,
const dimensioned<scalar>& dt2
);

template<class GeoMesh>
tmp<DimensionedField<scalar, GeoMesh> > operator +
(
const tmp<DimensionedField<scalar, GeoMesh> >& tdf1,
const scalar& t2
);
atulkjoy likes this.
marupio is offline   Reply With Quote

Old   January 20, 2010, 10:56
Default
  #4
Senior Member
 
Hrvoje Jasak
Join Date: Mar 2009
Location: London, England
Posts: 1,907
Rep Power: 33
hjasak will become famous soon enough
Well, put on your 1970-s hat (or a shirt with huge collars!) and let's talk about memory peaks. For simpleFoam, the memory peak is at the point of creation of the pressure equation, because, unlike PISO, I am allowed to delete the momentum matrix before the creation of the pressure matrix. Therefore, I make the momentum matrix a tmp and call UEqn.clear(); at an opportune place in the code and drop the peak memory requirement by one complete assymetric matrix!

Guess what clear() does: it will delete the pointer to the actual momentum matrix (before reaching the destructor) and free up a lot of memory to be re-used for the pressure matrix.

This is how FOAM beats eg Fluent and STAR in memory usage per cell, but in the 21st century (and especially when you are writing new discretisation capability) you don't care that much. In PISO-based solvers you don't have this option, since you will call UEqn.H() later on in the algorithm, and this requires access to momentum matrix coefficients. Therefore, there's no need for the tmp<matrix> gymnastics...

Clear?

Hrv
__________________
Hrvoje Jasak
Providing commercial FOAM/OpenFOAM and CFD Consulting: http://wikki.co.uk
hjasak is offline   Reply With Quote

Old   January 21, 2010, 17:35
Smile
  #5
Senior Member
 
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22
marupio is on a distinguished road
Got it. Thanks! I'm sure I'll be back...
marupio is offline   Reply With Quote

Old   September 22, 2010, 04:52
Default
  #6
New Member
 
Join Date: Sep 2009
Posts: 13
Rep Power: 17
cgoniva is on a distinguished road
Dear All!

I'm trying to write a code which is similar to the
inline tmp <volVectorField> spray::momentumSource()

Inside that function a tmp <volVectorField> is built from a new volVectorField

So I am wondering what is the scope of this tmp object and whether I need to do some clean up using delete at some point? I could not find such a thing inside the spray class.

Thx for your advise,
Cheers Chris
lpz456 likes this.
cgoniva is offline   Reply With Quote

Old   September 22, 2010, 05:31
Default
  #7
Assistant Moderator
 
Bernhard Gschaider
Join Date: Mar 2009
Posts: 4,225
Rep Power: 51
gschaider will become famous soon enoughgschaider will become famous soon enough
Quote:
Originally Posted by cgoniva View Post
Dear All!

I'm trying to write a code which is similar to the
inline tmp <volVectorField> spray::momentumSource()

Inside that function a tmp <volVectorField> is built from a new volVectorField

So I am wondering what is the scope of this tmp object and whether I need to do some clean up using delete at some point? I could not find such a thing inside the spray class.

Thx for your advise,
Cheers Chris
The whole point of tmp is that you don't have to care about deleting too much. Have you read: http://openfoamwiki.net/index.php/OpenFOAM_guide/tmp
I think it is explained quite nicely there

Bernhard
gschaider is offline   Reply With Quote

Old   September 22, 2010, 06:07
Default
  #8
New Member
 
Join Date: Sep 2009
Posts: 13
Rep Power: 17
cgoniva is on a distinguished road
Thx for your quick reply Bernhard!

I'll have a look at that link!

Cheers
Chris
cgoniva is offline   Reply With Quote

Old   June 4, 2015, 09:26
Default
  #9
Senior Member
 
Robert Sawko
Join Date: Mar 2009
Posts: 117
Rep Power: 22
AlmostSurelyRob will become famous soon enough
Sorry for necro-bumping this thread, but I would still like to ask for the clarification on tmp class. I understood the idea of returning a sort of smart pointer which will handle the memory allocation properly, but how is this related to mechanism of copy-elision* that already exists in C++?

I occasionally come across it when dealing with multiphase models as various interaction expressions return tmp.

* Copy-elision wikipedia:
http://en.wikipedia.org/wiki/Copy_elision
https://en.wikipedia.org/wiki/Return_value_optimization
AlmostSurelyRob is offline   Reply With Quote

Old   June 8, 2015, 00:01
Default
  #10
New Member
 
Kojirion's Avatar
 
Albert Yiamakis
Join Date: Jun 2015
Posts: 6
Rep Power: 11
Kojirion is on a distinguished road
Quote:
Originally Posted by hjasak View Post
scalarField a(1000000, 1.0);
scalarField b(1000000, 2.0);

scalarField c = a + b;

This calls operator+(const scalarField& a, const scalarField& b), and that needs a return type. If the return type is a scalarField, you will first create and then copy a field of length 1000000 floating point numbers - which hurts and takes time.
I would expect that copy to be elided. RVO has been supported for a long time - apparently Scott Meyers recommended return by value in More Effective C++ back in 1996.
So while I do not dispute that tmp may have very good uses throughout OF code, this example - and the simllar reasoning answering 'Why is it needed?' in the guide is unconvincing.

Regarding early deletion, if the object is local it would be sufficient to create an arbitrary scope with a pair of braces; that makes it perfectly possible to destruct some locals in the middle of a function.

More interesting would be the problem of a+b+c and avoiding the temporary result of a+b, which expression templates would help with and tmp does not, as far as I can tell.
Kojirion is offline   Reply With Quote

Old   October 2, 2017, 09:50
Default Move Constructor?
  #11
New Member
 
Rodrigo de Oliveira
Join Date: Oct 2017
Posts: 2
Rep Power: 0
MadScientist is on a distinguished road
Quote:
I would expect that copy to be elided.
I agree, but going further than that, today couldn't this problem be addressed by a simple move constructor? It doesn't even have to rely on a "smart" compiler.

In my opinion, the problem with the tmp fields is not even the gymnastics. The big pain is that, when something breaks, the error message is very cryptic!
MadScientist is offline   Reply With Quote

Old   April 11, 2019, 07:04
Default Help need in OpenFoam by BlueCFD terminal to study Gray Scott Model
  #12
New Member
 
Shahid Hasnain
Join Date: Jul 2013
Location: Islamabad
Posts: 3
Rep Power: 13
shahidqa32 is on a distinguished road
I am posting my error. Your help will be highly appreciated.

perputation.H: In function 'int main(int, char**)':
perputation.H:3:42: error: binding reference of type 'Foam::scalarField& {aka Foam::Field<double>&}' to 'const Foam::Field<double>' discards qualifiers
scalarField& AField = A.internalField();

when I use command wmake
it shows error as mentioned above.

Thank you in advance to help.
shahidqa32 is offline   Reply With Quote

Old   May 24, 2019, 17:41
Default Still facing issues with the use of tmp<>
  #13
Member
 
Raunak Bardia
Join Date: Jan 2015
Posts: 32
Rep Power: 11
raunakbardia is on a distinguished road
Here is my problem:

1. I am trying to modify an existing class and am using the return types in the other functions that the class was originally designed with. My function returns a tmp<> type variable and looks something like this:

Code:
Foam::tmp<Foam::volScalarField>
Foam::temperaturePhaseChangeTwoPhaseMixtures::constant::mFlux() const
{
    const volScalarField massGenerationRate
    (   
        IOobject
        (   
            "mDot",
            mesh_.time().timeName(),
            mesh_
        ),  
        mesh_,
        mDotA_
    );  
    return tmp<volScalarField>
    (   
        massGenerationRate
    );  
}
2. Now in the main program this function is called by the mixture object in the following way.

Code:
    tmp<volScalarField> mCheck = mixture->mFlux();
    const volScalarField& mDotAlpha = mCheck();    // Reference volScalarField
    Info << mDotAlpha[397] << '\n';      // This prints when I run the program
    const volScalarField mDotFinal(mDotAlpha); // ERROR
    Info << mDotAlpha[397] << '\n'; // This does not print out
3. The program compiles and then I run the solver from the run directory. At runtime, the code crashes at the line that is commented as an error in the above piece.

From what I understood tmp<> destroys the pointer to the object if it is not referenced immediately. But in the above example, I do reference it in the very next line and it works. only up to that point. The permanent creation of that object in my program fails. Here is the error:

Quote:
#0 Foam::error:rintStack(Foam::Ostream&) in "/usr/local/openfoam/v1706/OpenFOAM-v1706/platforms/linux64GccDPInt32Opt/lib/libOpenFOAM.so"
#1 Foam::sigSegv::sigHandler(int) in "/usr/local/openfoam/v1706/OpenFOAM-v1706/platforms/linux64GccDPInt32Opt/lib/libOpenFOAM.so"
#2 ? in "/lib64/libc.so.6"
#3 std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) in "/usr/local/openfoam/v1706/ThirdParty-v1706/platforms/linux64/gcc-4.8.5/lib64/libstdc++.so.6"
#4 Foam::regIOobject::regIOobject(Foam::regIOobject const&) in "/usr/local/openfoam/v1706/OpenFOAM-v1706/platforms/linux64GccDPInt32Opt/lib/libOpenFOAM.so"
#5 Foam:imensionedField<double, Foam::volMesh>:imensionedField(Foam:imensioned Field<double, Foam::volMesh> const&)BFD: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
in "/home/rbardia/OpenFOAM/rbardia-v1706/platforms/linux64GccDPInt32Opt/bin/phaseChangeInterIsoFoam"
#6 Foam::GeometricField<double, Foam::fvPatchField, Foam::volMesh>::GeometricField(Foam::GeometricFiel d<double, Foam::fvPatchField, Foam::volMesh> const&)BFD: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
in "/home/rbardia/OpenFOAM/rbardia-v1706/platforms/linux64GccDPInt32Opt/bin/phaseChangeInterIsoFoam"
#7 ?BFD: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
in "/home/rbardia/OpenFOAM/rbardia-v1706/platforms/linux64GccDPInt32Opt/bin/phaseChangeInterIsoFoam"
#8 __libc_start_main in "/lib64/libc.so.6"
#9 Foam::UOPstream::write(float)BFD: Dwarf Error: found dwarf version '4', this reader only handles version 2 information.
in "/home/rbardia/OpenFOAM/rbardia-v1706/platforms/linux64GccDPInt32Opt/bin/phaseChangeInterIsoFoam"
Segmentation fault
What is the possible reason behind this? Similar, pre-defined functions that are part of the same class work fine. I have spent a lot of time but am not able to resolve this issue.

I have attached the header and implementation files of the function: constant.H & constant.C and the file that calls that function in the main folder: alphaEqn.H
Attached Files
File Type: c constant.C (5.0 KB, 0 views)
File Type: h constant.H (3.6 KB, 0 views)
File Type: h alphaEqn.H (2.3 KB, 4 views)
raunakbardia is offline   Reply With Quote

Old   May 25, 2019, 10:28
Default
  #14
Senior Member
 
Zeppo's Avatar
 
Sergei
Join Date: Dec 2009
Posts: 261
Rep Power: 22
Zeppo will become famous soon enough
In your code an object massGenerationRate is created on stack and so is destroyed whenever the execution flow leaves function mFlux. Storing a reference to it in tmp doesn't help because returning a tmp you rerurn a reference to nothnig as the object was wiped out and doesn't exist anymore. All you have to do is to create massGenerationRate in virtual (dynamic) memory, store the pointer to it in smart pointer (tmp) object and you are pretty safe to return it from function. Please try this
Code:
Foam::tmp<Foam::volScalarField>
Foam::temperaturePhaseChangeTwoPhaseMixtures::constant::mFlux() const
{
    tmp<volScalarField> massGenerationRate
    (   
        new volScalarField
        (   
            IOobject
            (   
                "mDot",
                mesh_.time().timeName(),
                mesh_
            ),  
            mesh_,
            mDotA_
        );  
    );

    return massGenerationRate;
}
Zeppo is offline   Reply With Quote

Old   June 2, 2019, 16:31
Default
  #15
Member
 
Raunak Bardia
Join Date: Jan 2015
Posts: 32
Rep Power: 11
raunakbardia is on a distinguished road
Thanks. I realized that.
raunakbardia is offline   Reply With Quote

Reply

Tags
macro, refcount, tmp


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
Macro problem cfddummy Siemens 1 April 9, 2007 13:37


All times are GMT -4. The time now is 15:52.