|
[Sponsors] |
January 19, 2010, 14:25 |
tmp - stands for 'true macro pain'?
|
#1 |
Senior Member
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22 |
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 |
|
January 20, 2010, 06:40 |
|
#2 |
Senior Member
Hrvoje Jasak
Join Date: Mar 2009
Location: London, England
Posts: 1,907
Rep Power: 33 |
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 |
|
January 20, 2010, 10:47 |
|
#3 |
Senior Member
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22 |
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 ); |
|
January 20, 2010, 10:56 |
|
#4 |
Senior Member
Hrvoje Jasak
Join Date: Mar 2009
Location: London, England
Posts: 1,907
Rep Power: 33 |
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 |
|
January 21, 2010, 17:35 |
|
#5 |
Senior Member
David Gaden
Join Date: Apr 2009
Location: Winnipeg, Canada
Posts: 437
Rep Power: 22 |
Got it. Thanks! I'm sure I'll be back...
|
|
September 22, 2010, 04:52 |
|
#6 |
New Member
Join Date: Sep 2009
Posts: 13
Rep Power: 17 |
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 |
|
September 22, 2010, 05:31 |
|
#7 | |
Assistant Moderator
Bernhard Gschaider
Join Date: Mar 2009
Posts: 4,225
Rep Power: 51 |
Quote:
I think it is explained quite nicely there Bernhard |
||
September 22, 2010, 06:07 |
|
#8 |
New Member
Join Date: Sep 2009
Posts: 13
Rep Power: 17 |
Thx for your quick reply Bernhard!
I'll have a look at that link! Cheers Chris |
|
June 4, 2015, 09:26 |
|
#9 |
Senior Member
Robert Sawko
Join Date: Mar 2009
Posts: 117
Rep Power: 22 |
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 |
|
June 8, 2015, 00:01 |
|
#10 | |
New Member
Albert Yiamakis
Join Date: Jun 2015
Posts: 6
Rep Power: 11 |
Quote:
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. |
||
October 2, 2017, 09:50 |
Move Constructor?
|
#11 | |
New Member
Rodrigo de Oliveira
Join Date: Oct 2017
Posts: 2
Rep Power: 0 |
Quote:
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! |
||
April 11, 2019, 07:04 |
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 |
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. |
|
May 24, 2019, 17:41 |
Still facing issues with the use of tmp<>
|
#13 | |
Member
Raunak Bardia
Join Date: Jan 2015
Posts: 32
Rep Power: 11 |
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 ); } 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 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:
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 |
||
May 25, 2019, 10:28 |
|
#14 |
Senior Member
Sergei
Join Date: Dec 2009
Posts: 261
Rep Power: 22 |
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; } |
|
June 2, 2019, 16:31 |
|
#15 |
Member
Raunak Bardia
Join Date: Jan 2015
Posts: 32
Rep Power: 11 |
Thanks. I realized that.
|
|
Tags |
macro, refcount, tmp |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Macro problem | cfddummy | Siemens | 1 | April 9, 2007 13:37 |