CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Programming & Development (https://www.cfd-online.com/Forums/openfoam-programming-development/)
-   -   How to create a field without reading from 0 directroy (https://www.cfd-online.com/Forums/openfoam-programming-development/250569-how-create-field-without-reading-0-directroy.html)

NotOverUnderated June 25, 2023 22:49

How to create a field without reading from 0 directroy
 
Hello,

I have created a volScalarField using the following:

Code:

      volScalarField X
        (
            IOobject
            (
                "X",
                runTime.timeName(),
                mesh,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            mesh
        );


The code compiles fine, but when I run it, I get this error message:

Code:


Create time

Create mesh for time = 0



--> FOAM FATAL ERROR: (openfoam-2112 patch=220610)
cannot find file "/tmp/test/case/0/X"

    From virtual Foam::autoPtr<Foam::ISstream> Foam::fileOperations::uncollatedFileOperation::readStream(Foam::regIOobject&, const Foam::fileName&, const Foam::word&, bool) const
    in file global/fileOperations/uncollatedFileOperation/uncollatedFileOperation.C at line 542.

FOAM exiting

I have used IOobject::NO_READ so why does it complain about X not present in 0 directory?

Thank you

adhiraj June 26, 2023 07:37

Does something like this work?
Code:

volScalarField X
(
    IOobject
    (
        "X",
        runTime.timeName(),
        mesh,
        IOobject::NO_READ,
        IOobject::AUTO_WRITE
    ),
    mesh,
    dimensionedScalar("Z", dimless, 0.0)
);


NotOverUnderated June 26, 2023 13:37

Quote:

Originally Posted by adhiraj (Post 852356)
Does something like this work?
Code:

volScalarField X
(
    IOobject
    (
        "X",
        runTime.timeName(),
        mesh,
        IOobject::NO_READ,
        IOobject::AUTO_WRITE
    ),
    mesh,
    dimensionedScalar("Z", dimless, 0.0)
);


That works! Thank you.

I wonder why does this work? could you please elaborate and explain why NO_READ has no effect?

Tobermory June 27, 2023 03:38

Agreed that this is misleading, but the field has to be initialised with something. The TLDR version is that the original constructor that you used is the "READ constructor" for a field, and will try read from file regardless of the NO_READ flag; the "corrected" constructor is the one to use if you do not want to read from file, but in that case you have to supply the initialisation data for the field.

If you want to see the detail, read on.

In your code, you have defined a new volScalarField, which is a templated type of GemetricField. For the constructor, you passed an IOobject and a mesh, i.e. you used the constructor (line 366 in https://cpp.openfoam.org/v8/Geometri..._source.html):

Code:

        //- Construct and read given IOobject
        GeometricField
        (
            const IOobject&,
            const Mesh&
        );

which is defined on line 342 of https://cpp.openfoam.org/v8/Geometri...8C_source.html as:

Code:

template<class Type, template<class> class PatchField, class GeoMesh>
 Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
 (
    const IOobject& io,
    const Mesh& mesh
 )
 :
    Internal(io, mesh, dimless, false),
    timeIndex_(this->time().timeIndex()),
    field0Ptr_(nullptr),
    fieldPrevIterPtr_(nullptr),
    boundaryField_(mesh.boundary())
 {
    readFields();
 
    ... etc - I pruned out some of the lines here
    }
 }

Note the readFields() call, without any checking of the read flag. This readFields() function is defined on line 72 of GeometricField.C, and constructs an IOdictionary and calls upon the readFields() function on line 48 to read in the data. This is why your original code crashed.


Let's now look at the "corrected" constructor, i.e. the one that works for you. This uses the constructor at line 327 of GeometricField.H:
Code:

        //- Constructor given IOobject, mesh, dimensioned<Type>
        //  and patch field type.
        GeometricField
        (
            const IOobject&,
            const Mesh&,
            const dimensioned<Type>&,
            const word& patchFieldType=PatchField<Type>::calculatedType()
        );

which is defined on line 239 of GeometricField.C as:
Code:

template<class Type, template<class> class PatchField, class GeoMesh>
 Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
 (
    const IOobject& io,
    const Mesh& mesh,
    const dimensioned<Type>& dt,
    const word& patchFieldType
 )
 :
    Internal(io, mesh, dt, false),
    timeIndex_(this->time().timeIndex()),
    field0Ptr_(nullptr),
    fieldPrevIterPtr_(nullptr),
    boundaryField_(mesh.boundary(), *this, patchFieldType)
 {
    if (debug)
    {
        InfoInFunction << "Creating temporary" << endl << this->info() << endl;
    }
 
    boundaryField_ == dt.value();
 
    readIfPresent();
 }

Note that even though the initialisation data that you pass the constructor (dt) is used to fill the field, a call is still made to readIfPresent(). This means that your initialisation data will be overwritten by the contents of the file, if the file is present ... UNLESS you use the NO_READ flag, in which case the read from file is skipped.

Hope this helps!

NotOverUnderated June 27, 2023 04:34

Great explanation!
 
Quote:

Originally Posted by Tobermory (Post 852390)
Agreed that this is misleading, but the field has to be initialised with something. The TLDR version is that the original constructor that you used is the "READ constructor" for a field, and will try read from file regardless of the NO_READ flag; the "corrected" constructor is the one to use if you do not want to read from file, but in that case you have to supply the initialisation data for the field.

If you want to see the detail, read on.

In your code, you have defined a new volScalarField, which is a templated type of GemetricField. For the constructor, you passed an IOobject and a mesh, i.e. you used the constructor (line 366 in https://cpp.openfoam.org/v8/Geometri..._source.html):

Code:

        //- Construct and read given IOobject
        GeometricField
        (
            const IOobject&,
            const Mesh&
        );

which is defined on line 342 of https://cpp.openfoam.org/v8/Geometri...8C_source.html as:

Code:

template<class Type, template<class> class PatchField, class GeoMesh>
 Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
 (
    const IOobject& io,
    const Mesh& mesh
 )
 :
    Internal(io, mesh, dimless, false),
    timeIndex_(this->time().timeIndex()),
    field0Ptr_(nullptr),
    fieldPrevIterPtr_(nullptr),
    boundaryField_(mesh.boundary())
 {
    readFields();
 
    ... etc - I pruned out some of the lines here
    }
 }

Note the readFields() call, without any checking of the read flag. This readFields() function is defined on line 72 of GeometricField.C, and constructs an IOdictionary and calls upon the readFields() function on line 48 to read in the data. This is why your original code crashed.


Let's now look at the "corrected" constructor, i.e. the one that works for you. This uses the constructor at line 327 of GeometricField.H:
Code:

        //- Constructor given IOobject, mesh, dimensioned<Type>
        //  and patch field type.
        GeometricField
        (
            const IOobject&,
            const Mesh&,
            const dimensioned<Type>&,
            const word& patchFieldType=PatchField<Type>::calculatedType()
        );

which is defined on line 239 of GeometricField.C as:
Code:

template<class Type, template<class> class PatchField, class GeoMesh>
 Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
 (
    const IOobject& io,
    const Mesh& mesh,
    const dimensioned<Type>& dt,
    const word& patchFieldType
 )
 :
    Internal(io, mesh, dt, false),
    timeIndex_(this->time().timeIndex()),
    field0Ptr_(nullptr),
    fieldPrevIterPtr_(nullptr),
    boundaryField_(mesh.boundary(), *this, patchFieldType)
 {
    if (debug)
    {
        InfoInFunction << "Creating temporary" << endl << this->info() << endl;
    }
 
    boundaryField_ == dt.value();
 
    readIfPresent();
 }

Note that even though the initialisation data that you pass the constructor (dt) is used to fill the field, a call is still made to readIfPresent(). This means that your initialisation data will be overwritten by the contents of the file, if the file is present ... UNLESS you use the NO_READ flag, in which case the read from file is skipped.

Hope this helps!

Many thanks for this detailed explanation.

olesen June 27, 2023 08:49

Quote:

Originally Posted by NotOverUnderated (Post 852373)
That works! Thank you.

I wonder why does this work? could you please elaborate and explain why NO_READ has no effect?


In the openfoam.com version you should at least have seen a warning message:
Code:

read option IOobject::MUST_READ or MUST_READ_IF_MODIFIED 
suggests that a read constructor for field " field-name
would be more appropriate."


If you want to create without initialization, you should at least provide the dimensionSet (eg, length, velocity etc) so that later assignments make sense.

NotOverUnderated June 27, 2023 16:07

Quote:

Originally Posted by olesen (Post 852402)
In the openfoam.com version you should at least have seen a warning message:
Code:

read option IOobject::MUST_READ or MUST_READ_IF_MODIFIED 
suggests that a read constructor for field " field-name
would be more appropriate."


I am using OpenFOAM v2112 but I do not see that warning message. I have tried with v2212 but no warning message as well.

olesen June 28, 2023 06:03

Quote:

Originally Posted by NotOverUnderated (Post 852415)
I am using OpenFOAM v2112 but I do not see that warning message. I have tried with v2212 but no warning message as well.


Yes you are correct, the warning message are for some of the other constructors, not for the one that you are using. It actually does go off and attempt to read in fields regardless of the IOobject read setting.


The best advice (and the conclusion that you've already reached) is not to use that particular constructor. Aside from the reading issue, the missing dimensions are a bit of a showstopper. Still undecided if it is worth raising an issue for this behaviour. I'll leave that up to you.

NotOverUnderated June 28, 2023 13:03

Quote:

Originally Posted by olesen (Post 852432)
Yes you are correct, the warning message are for some of the other constructors, not for the one that you are using. It actually does go off and attempt to read in fields regardless of the IOobject read setting.


The best advice (and the conclusion that you've already reached) is not to use that particular constructor. Aside from the reading issue, the missing dimensions are a bit of a showstopper. Still undecided if it is worth raising an issue for this behaviour. I'll leave that up to you.

I have seen many online tutorials use the first constructor (without dimensions). My OpenFOAM programming skills are relatively basic and I often find myself forgetting to define these dimensions. While I can't speak for everyone, I personally feel that a warning message would serve as a useful reminder to avoid confusion.

Thank you

Tobermory June 29, 2023 03:05

Quote:

Originally Posted by olesen (Post 852432)
Still undecided if it is worth raising an issue for this behaviour.

As you pointed out Mark - it's working as intended, but also agreed that it's a little confusing. I think the best way to make this more transparent would be to simply ammend the description of the constructor in the header file, to state that this is the read constructor (OF refers to it like this in the warning message that you highlighted), or something similar.

olesen June 30, 2023 03:54

Quote:

Originally Posted by Tobermory (Post 852457)
As you pointed out Mark - it's working as intended, but also agreed that it's a little confusing. I think the best way to make this more transparent would be to simply ammend the description of the constructor in the header file, to state that this is the read constructor (OF refers to it like this in the warning message that you highlighted), or something similar.


Opened an issue: https://develop.openfoam.com/Develop.../-/issues/2926 can add comments/preferences/ideas there.


All times are GMT -4. The time now is 05:00.