|
[Sponsors] |
December 16, 2016, 10:24 |
Call of probes::write() function
|
#1 |
Super Moderator
Tobias Holzmann
Join Date: Oct 2010
Location: Bad Wörishofen
Posts: 2,711
Blog Entries: 6
Rep Power: 52 |
Dear all,
I am struggling to figure out how the probes::write() function is called or which class is executing this method. Up to know, it should be clear but I get unexpected results; there should be a class that I miss. However, in order to provide all information I start from the beginning. The function objects are called within the Time::run() function: Code:
bool Foam::Time::run() const { bool running = value() < (endTime_ - 0.5*deltaT_); if (!subCycling_) { // only execute when the condition is no longer true // ie, when exiting the control loop if (!running && timeIndex_ != startTimeIndex_) { // Note, end() also calls an indirect start() as required Info<< "run() Call end" << endl; functionObjects_.end(); } } if (running) { if (!subCycling_) { const_cast<Time&>(*this).readModifiedObjects(); if (timeIndex_ == startTimeIndex_) { Info<< "run() Call start" << endl; functionObjects_.start(); } else { Info<< "run() Call execute" << endl; functionObjects_.execute(); } } // Update the "running" status following the // possible side-effects from functionObjects running = value() < (endTime_ - 0.5*deltaT_); } return running; } Code:
bool Foam::functionObjectList::execute() { Info<< "In functionObjectList::execute()" << endl; bool ok = true; if (execution_) { if (!updated_) { read(); } forAll(*this, objectI) { Info<< "Call operator[](objectI).execute()" << endl; ok = operator[](objectI).execute() && ok; Info<< "Call operator[](objectI).write()" << endl; ok = operator[](objectI).write() && ok; } } return ok; } Code:
bool Foam::probes::execute() { Info<< " probes::execute()" << endl; return true; } bool Foam::probes::write() { Info<< " probes::write()" << endl; if (size() && prepare()) { sampleAndWrite(scalarFields_); sampleAndWrite(vectorFields_); sampleAndWrite(sphericalTensorFields_); sampleAndWrite(symmTensorFields_); sampleAndWrite(tensorFields_); sampleAndWriteSurfaceFields(surfaceScalarFields_); sampleAndWriteSurfaceFields(surfaceVectorFields_); sampleAndWriteSurfaceFields(surfaceSphericalTensorFields_); sampleAndWriteSurfaceFields(surfaceSymmTensorFields_); sampleAndWriteSurfaceFields(surfaceTensorFields_); } return true; } To sum up: For each time step I know that the functions:
probes::execute() probes::write() However, the output looks different: Code:
run() Call start Time = 0.005 DICPCG: Solving for T, Initial residual = 1, Final residual = 1.65094e-07, No Iterations 5 DICPCG: Solving for T, Initial residual = 0.00446913, Final residual = 2.58563e-07, No Iterations 3 DICPCG: Solving for T, Initial residual = 0.000148071, Final residual = 1.6611e-07, No Iterations 2 ExecutionTime = 0.13 s ClockTime = 0 s run() Call execute In functionObjectList::execute() = execution_ 1 Call operator[](objectI).execute() probes::execute() Call operator[](objectI).write() Time = 0.01 DICPCG: Solving for T, Initial residual = 0.203755, Final residual = 3.79207e-07, No Iterations 4 DICPCG: Solving for T, Initial residual = 0.00184335, Final residual = 1.15759e-07, No Iterations 3 DICPCG: Solving for T, Initial residual = 5.70567e-05, Final residual = 6.6188e-08, No Iterations 2 ExecutionTime = 0.14 s ClockTime = 0 s run() Call execute In functionObjectList::execute() = execution_ 1 Call operator[](objectI).execute() probes::execute() Call operator[](objectI).write() probes::write() Time = 0.015 DICPCG: Solving for T, Initial residual = 0.109922, Final residual = 2.11614e-07, No Iterations 4 DICPCG: Solving for T, Initial residual = 0.00104612, Final residual = 6.94234e-08, No Iterations 3 DICPCG: Solving for T, Initial residual = 3.13333e-05, Final residual = 7.19276e-07, No Iterations 1 ExecutionTime = 0.14 s ClockTime = 0 s run() Call execute In functionObjectList::execute() = execution_ 1 Call operator[](objectI).execute() probes::execute() Call operator[](objectI).write() Time = 0.02 DICPCG: Solving for T, Initial residual = 0.0728088, Final residual = 1.56726e-07, No Iterations 4 DICPCG: Solving for T, Initial residual = 0.000680395, Final residual = 6.78655e-07, No Iterations 2 DICPCG: Solving for T, Initial residual = 2.06035e-05, Final residual = 4.78523e-07, No Iterations 1 ExecutionTime = 0.14 s ClockTime = 0 s run() Call end probes::execute() probes::write() End
__________________
Keep foaming, Tobias Holzmann |
|
December 16, 2016, 12:32 |
|
#2 |
Senior Member
Kevin van As
Join Date: Sep 2014
Location: TU Delft, The Netherlands
Posts: 252
Rep Power: 21 |
I think I found it... The reasoning was quite simple in hindsight:
If there is a "class in between", then that class must necessarily extend "probes", as probes in the direct child of functionObject (probes extends functionObject). Then probes' child's write() would be called before probes' write(). However, this is not the case and it would be nonsensical design, as every FO would then require a child to do the time-stuff. Those are a lot of different children - all educated to do exactly the same thing! Therefore, the FO you call "execute()" and "write()" on simply cannot be your probes FO. (Or there is some magic C++ going on that I do not understand as a Java programmer.) This brought me to the runtime selection mechanism: where are the FOs constructed? This made me find your problem. Let me explain: --- Let's do it in the chronological calling order. First, a functionObjectList is constructed and its read() method is called. This method reads the "functions" entity of controlDict. Then it constructs the appropriate functionObject using OF's runtime selection mechanism and it adds it to the list (= to itself). Inside the read() method you may find: Code:
(...) try { if ( dict.found("writeControl") || dict.found("outputControl") ) { foPtr.set ( new functionObjects::timeControl(key, time_, dict) ); } else { foPtr = functionObject::New(key, time_, dict); } } (...) if (foPtr.valid()) { objPtr = foPtr.ptr(); } else { ok = false; } (...) // Insert active functionObjects into the list if (objPtr) { newPtrs.set(nFunc, objPtr); newIndices.insert(key, nFunc); nFunc++; } Its constructor looks as follows: Code:
Foam::functionObjects::timeControl::timeControl ( const word& name, const Time& t, const dictionary& dict ) : functionObject(name), time_(t), dict_(dict), timeStart_(-VGREAT), timeEnd_(VGREAT), nStepsToStartTimeChange_ ( dict.lookupOrDefault("nStepsToStartTimeChange", 3) ), executeControl_(t, dict, "execute"), writeControl_(t, dict, "write"), foPtr_(functionObject::New(name, t, dict_)) { readControls(); } This makes sense based on the comment in timeControlFunctionObject.H: Code:
//- The functionObject to execute autoPtr<functionObject> foPtr_; Code:
bool Foam::functionObjects::timeControl::write() { if (active() && (postProcess || writeControl_.execute())) { foPtr_->write(); } return true; } So you are right. "probes.write()" will only be called if it is the time to execute. I can speculate why OF implemented it in this "pointer sequence" way, rather than with inheritance (randomFO -> timeControlFO -> FO)... With inheritance, it would be the user's responsibility to call the parent write() method before writing, which is "unsafe". Or, timeControlFO must ensure that "write" cannot be overwritten by randomFO and it should define a new interface for a new method that should do the writing. However, I don't think it is possible to prevent a child from overwriting, is it? Either way, even if it is, this would make the name of the "write()" function inconsistent between FOs that are not timeControlFOs. That was a tough nut to crack (2 hours later...), but quite educative. |
|
December 16, 2016, 13:07 |
|
#3 |
Super Moderator
Tobias Holzmann
Join Date: Oct 2010
Location: Bad Wörishofen
Posts: 2,711
Blog Entries: 6
Rep Power: 52 |
Dear Kevin,
thank you very much for your clear explanation. I was so focused on my interpretation that I forgot that there could be other ways like, taking a pointer of the object to the time selector class which will then call the function. Great explanation and thanks for your time. I highly appreciate that. Tobi
__________________
Keep foaming, Tobias Holzmann |
|
November 29, 2021, 03:43 |
|
#4 | |
Senior Member
mohammad
Join Date: Sep 2015
Posts: 281
Rep Power: 12 |
Quote:
Hi Tobi, Thank you for posting this fantastic question. You have looked at probes function object and more specifically, the write and execute functions in both functionObjectList.C and probes.C. However, I need to look at another function object, forces, for force calculation over a patch. This functionObject includes a function called forceEff(). This only returns the calculated forces vector over the patch. However, I don't how I can call it inside my solver. I have tested this: Code:
word patchName = "forcesP"; \\patchName label id = runTime.functionObjects().findObjectID(patchName); \\finding object id runTime.functionObjects()[id].execute(); runTime.functionObjects()[id].write(); To check my access to execute and write functions within the solver, and it works. But actually, using this command: Code:
runTime.functionObjects()[id].forceEff(); leads to the following error: Code:
nonNewtonianIcoFoamModified.C: In function ‘int main(int, char**)’: nonNewtonianIcoFoamModified.C:124:39: error: ‘class Foam::functionObject’ has no member named ‘forceEff’ runTime.functionObjects()[id].forceEff(); I know functionObjects() in the above comes from functionObjectList class, but don't know why it leads to an error for an existing function. So your help is this regard is much appreciated. Cheers, Mohammad |
||
December 3, 2021, 07:42 |
|
#5 | |
Senior Member
Mark Olesen
Join Date: Mar 2009
Location: https://olesenm.github.io/
Posts: 1,715
Rep Power: 40 |
Quote:
Code:
dynamicCast<const functionObjects::forces>(runTime.functionObjects()[id]) .forceEff(); Code:
{ const auto* forcesFo = isA<functionObjects::forces>(runTime.functionObjects()[id]); if (forcesFo) { forcesFo->forceEff(); } } |
||
December 4, 2021, 20:36 |
|
#6 | |
Senior Member
mohammad
Join Date: Sep 2015
Posts: 281
Rep Power: 12 |
Quote:
Thanks Mark foryour nice comment. So you think this form of cast function can be added to a point of solver for calling the forces value? Am I right? |
||
Tags |
coding |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
foamToTecplot360 | thomasduerr | OpenFOAM Post-Processing | 121 | June 11, 2021 11:05 |
[blockMesh] Errors during blockMesh meshing | Madeleine P. Vincent | OpenFOAM Meshing & Mesh Conversion | 51 | May 30, 2016 11:51 |
ParaView for OF-1.6-ext | Chrisi1984 | OpenFOAM Installation | 0 | December 31, 2010 07:42 |
latest OpenFOAM-1.6.x from git failed to compile | phsieh2005 | OpenFOAM Bugs | 25 | February 9, 2010 05:37 |
Version 15 on Mac OS X | gschaider | OpenFOAM Installation | 113 | December 2, 2009 11:23 |