ENH: support creation of boundaries/zones from list of entries

- this makes it easier to split creation into a two-stage process
  as required

- extend handling for polyBoundaryMeshEntries, faBoundaryMeshEntries
  with more functionality. Ensure that these are never registered.

ENH: addition writeEntry methods for polyBoundaryMesh

- simplifies streaming and collating into other files

ENH: polyMesh rereading - update owner/neighbour header information

- this avoids accidentally reading the "cells" file if the mesh has
  been created with NO_READ and then updated

STYLE: less vertical space when outputting empty PtrList
This commit is contained in:
Mark Olesen
2023-10-27 09:46:12 +02:00
parent 98246a438e
commit 07dcdefa02
18 changed files with 1133 additions and 316 deletions

View File

@ -0,0 +1,3 @@
Test-boundaryMeshEntries.C
EXE = $(FOAM_USER_APPBIN)/Test-boundaryMeshEntries

View File

@ -0,0 +1,2 @@
/* EXE_INC = */
/* EXE_LIBS = */

View File

@ -0,0 +1,146 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-boundaryMeshEntries
Description
Find and print "boundary" information
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "fileName.H"
#include "IOstreams.H"
#include "polyMesh.H"
#include "polyBoundaryMeshEntries.H"
#include "OSspecific.H"
#include "Time.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noFunctionObjects(); // Disallow function objects
argList::addVerboseOption("additional verbosity");
#include "setRootCase.H"
#include "createTime.H"
fileName coherentInst;
coherentInst =
(
runTime.findInstance
(
polyMesh::meshSubDir,
"coherent",
IOobject::READ_IF_PRESENT
)
);
// Unfortunately with READ_IF_PRESENT, cannot tell if the file
// was actually found or not
Info<< "check: " << (coherentInst/polyMesh::meshSubDir/"coherent") << nl;
if (!Foam::isFile(coherentInst/polyMesh::meshSubDir/"coherent"))
{
coherentInst.clear();
}
Info<< "found coherent: " << coherentInst << nl;
PtrList<entry> entries;
if (!coherentInst.empty())
{
IOdictionary coherent
(
IOobject
(
"coherent",
coherentInst,
polyMesh::meshSubDir,
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
ITstream& is = coherent.lookup("boundary");
is >> entries;
}
Info<< "entries: " << entries << nl;
Info<< "type: " << polyBoundaryMeshEntries::types(entries) << nl;
Info<< "start: " << polyBoundaryMeshEntries::patchStarts(entries) << nl;
Info<< "size: " << polyBoundaryMeshEntries::patchSizes(entries) << nl;
Info<< nl;
fileName boundaryInst;
boundaryInst =
(
runTime.findInstance
(
polyMesh::meshSubDir,
"boundary",
IOobject::MUST_READ
)
);
Info<< "found boundary: " << boundaryInst << nl;
polyBoundaryMeshEntries pbm
(
IOobject
(
"boundary",
boundaryInst,
polyMesh::meshSubDir,
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
Info<< "type: " << flatOutput(pbm.types()) << nl;
Info<< "start: " << flatOutput(pbm.patchStarts()) << nl;
Info<< "size: " << flatOutput(pbm.patchSizes()) << nl;
pbm.writeEntry("boundary", Info);
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -40,8 +40,19 @@ Foam::Ostream& Foam::Detail::PtrListDetail<T>::write
{
const label len = this->size();
// The net length (after trimming any nullptr)
const label netLen = (trimNull ? this->count() : len);
if (!netLen)
{
// 0-sized : can write with less vertical space
os << nl << indent << netLen
<< token::BEGIN_LIST << token::END_LIST << nl;
return os;
}
// The (output) size and start delimiter
os << nl << indent << (trimNull ? this->count() : len) << nl
os << nl << indent << netLen << nl
<< indent << token::BEGIN_LIST << incrIndent << nl;
// Contents

View File

@ -105,8 +105,40 @@ void Foam::polyBoundaryMesh::calcGroupIDs() const
}
void Foam::polyBoundaryMesh::populate(PtrList<entry>&& entries)
{
clearLocalAddressing();
polyPatchList& patches = *this;
patches.resize_null(entries.size());
// Transcribe.
// Does not handle nullptr at all (what could possibly be done?)
forAll(patches, patchi)
{
patches.set
(
patchi,
polyPatch::New
(
entries[patchi].keyword(),
entries[patchi].dict(),
patchi,
*this
)
);
}
entries.clear();
}
bool Foam::polyBoundaryMesh::readContents(const bool allowOptionalRead)
{
bool updated = false;
PtrList<entry> entries;
if
(
this->isReadRequired()
@ -116,37 +148,23 @@ bool Foam::polyBoundaryMesh::readContents(const bool allowOptionalRead)
// Warn for MUST_READ_IF_MODIFIED
warnNoRereading<polyBoundaryMesh>();
polyPatchList& patches = *this;
// Read entries
Istream& is = readStream(typeName);
PtrList<entry> entries(is);
patches.resize_null(entries.size());
// Transcribe
forAll(patches, patchi)
{
patches.set
(
patchi,
polyPatch::New
(
entries[patchi].keyword(),
entries[patchi].dict(),
patchi,
*this
)
);
}
is >> entries;
is.check(FUNCTION_NAME);
close();
return true;
updated = true;
}
// Future: support master-only and broadcast?
if (updated)
{
populate(std::move(entries));
}
// Nothing read
return false;
return updated;
}
@ -217,6 +235,25 @@ Foam::polyBoundaryMesh::polyBoundaryMesh
}
Foam::polyBoundaryMesh::polyBoundaryMesh
(
const IOobject& io,
const polyMesh& pm,
PtrList<entry>&& entries
)
:
polyPatchList(),
regIOobject(io),
mesh_(pm)
{
if (!readContents(true)) // allowOptionalRead = true
{
populate(std::move(entries));
}
entries.clear();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
void Foam::polyBoundaryMesh::clear()
@ -237,11 +274,18 @@ void Foam::polyBoundaryMesh::clearGeom()
}
void Foam::polyBoundaryMesh::clearAddressing()
// Private until it is more generally required (and gets a better name?)
void Foam::polyBoundaryMesh::clearLocalAddressing()
{
neighbourEdgesPtr_.reset(nullptr);
patchIDPtr_.reset(nullptr);
groupIDsPtr_.reset(nullptr);
}
void Foam::polyBoundaryMesh::clearAddressing()
{
clearLocalAddressing();
polyPatchList& patches = *this;
@ -1367,22 +1411,56 @@ void Foam::polyBoundaryMesh::reorder
}
bool Foam::polyBoundaryMesh::writeData(Ostream& os) const
void Foam::polyBoundaryMesh::writeEntry(Ostream& os) const
{
const polyPatchList& patches = *this;
const polyPatchList& entries = *this;
os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
os << entries.size();
for (const polyPatch& pp : patches)
if (entries.empty())
{
os.beginBlock(pp.name());
os << pp;
os.endBlock();
// 0-sized : can write with less vertical space
os << token::BEGIN_LIST << token::END_LIST;
}
else
{
os << nl << token::BEGIN_LIST << incrIndent << nl;
for (const auto& pp : entries)
{
os.beginBlock(pp.name());
os << pp;
os.endBlock();
}
os << decrIndent << token::END_LIST;
}
os.check(FUNCTION_NAME);
}
void Foam::polyBoundaryMesh::writeEntry
(
const keyType& keyword,
Ostream& os
) const
{
const polyPatchList& entries = *this;
if (!keyword.empty())
{
os.write(keyword);
os << (entries.empty() ? token::SPACE : token::NL);
}
os << decrIndent << token::END_LIST;
writeEntry(os);
os.check(FUNCTION_NAME);
if (!keyword.empty()) os.endEntry();
}
bool Foam::polyBoundaryMesh::writeData(Ostream& os) const
{
writeEntry(os);
return os.good();
}

View File

@ -33,6 +33,7 @@ Description
SourceFiles
polyBoundaryMesh.C
polyBoundaryMeshTemplates.C
\*---------------------------------------------------------------------------*/
@ -50,6 +51,7 @@ namespace Foam
{
// Forward Declarations
class entry;
class polyMesh;
class wordRe;
class wordRes;
@ -91,6 +93,12 @@ class polyBoundaryMesh
//- Calculate group name to patch ids lookup
void calcGroupIDs() const;
//- Clear addressing at this level
void clearLocalAddressing();
//- Populate/recreate from dictionary entries
void populate(PtrList<entry>&& entries);
//- Return true if contents were read
//- (controlled by IOobject readOption flags).
bool readContents(const bool allowOptionalRead);
@ -149,6 +157,15 @@ public:
const polyPatchList& list
);
//- Read construct (mandatory, optional) based on IOobject properties
//- or fallback to constructing from a list of dictionary entries
polyBoundaryMesh
(
const IOobject& io,
const polyMesh& mesh,
PtrList<entry>&& entries
);
//- Destructor
~polyBoundaryMesh() = default;
@ -354,14 +371,24 @@ public:
// sync in that case)
void reorder(const labelUList& oldToNew, const bool validBoundary);
//- writeData member function required by regIOobject
// Write
//- Write as a plain list of entries
void writeEntry(Ostream& os) const;
//- Write as a primitive entry with given name.
//- If the keyword is empty, revert to a plain list.
void writeEntry(const keyType& keyword, Ostream& os) const;
//- The writeData member function required by regIOobject
virtual bool writeData(Ostream& os) const;
//- Write using stream options
//- Write using stream options, but always UNCOMPRESSED
virtual bool writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc
const bool writeOnProc = true
) const;

View File

@ -37,12 +37,72 @@ namespace Foam
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
void Foam::polyBoundaryMeshEntries::removeProcPatches()
Foam::polyBoundaryMeshEntries::polyBoundaryMeshEntries(const IOobject& io)
:
regIOobject
(
IOobject(io, IOobjectOption::NO_REGISTER)
)
{
// readContents()
if (isReadRequired() || (isReadOptional() && headerOk()))
{
// Read as entries
Istream& is = readStream(typeName);
is >> *this;
close();
}
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::PtrList<Foam::entry>
Foam::polyBoundaryMeshEntries::readContents(const IOobject& io)
{
polyBoundaryMeshEntries reader(io);
return PtrList<entry>(std::move(static_cast<PtrList<entry>&>(reader)));
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Extract optional entry from dictionaries and return as a list
template<class T>
static inline List<T> extract
(
const word& key,
const UPtrList<entry>& entries,
const T& initValue
)
{
List<T> result(entries.size(), initValue);
forAll(entries, i)
{
const dictionary& dict = entries[i].dict();
dict.readIfPresent(key, result[i]);
}
return result;
}
} // End namespace
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::polyBoundaryMeshEntries::removeProcPatches(PtrList<entry>& entries)
{
// Truncate at the first processor patch entry
PtrList<entry>& entries = *this;
label nNonProcessor = entries.size();
@ -62,4 +122,132 @@ void Foam::polyBoundaryMeshEntries::removeProcPatches()
}
bool Foam::polyBoundaryMeshEntries::writeEntries
(
Ostream& os,
const UPtrList<entry>& entries
)
{
os << entries.size();
if (entries.empty())
{
// 0-sized : can write with less vertical space
os << token::BEGIN_LIST << token::END_LIST;
}
else
{
os << nl << token::BEGIN_LIST << incrIndent << nl;
forAll(entries, patchi)
{
const auto& key = entries[patchi].keyword();
const auto& dict = entries[patchi].dict();
dict.writeEntry(key, os);
}
os << decrIndent << token::END_LIST;
}
os.check(FUNCTION_NAME);
return os.good();
}
Foam::wordList Foam::polyBoundaryMeshEntries::types
(
const UPtrList<entry>& entries
)
{
return extract<word>("type", entries, "patch");
}
Foam::labelList Foam::polyBoundaryMeshEntries::patchStarts
(
const UPtrList<entry>& entries
)
{
return extract<label>("startFace", entries, 0);
}
Foam::labelList Foam::polyBoundaryMeshEntries::patchSizes
(
const UPtrList<entry>& entries
)
{
return extract<label>("nFaces", entries, 0);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::polyBoundaryMeshEntries::removeProcPatches()
{
removeProcPatches(*this);
}
Foam::wordList Foam::polyBoundaryMeshEntries::types() const
{
return extract<word>("type", *this, "patch");
}
Foam::labelList Foam::polyBoundaryMeshEntries::patchStarts() const
{
return extract<label>("startFace", *this, 0);
}
Foam::labelList Foam::polyBoundaryMeshEntries::patchSizes() const
{
return extract<label>("nFaces", *this, 0);
}
void Foam::polyBoundaryMeshEntries::writeEntry(Ostream& os) const
{
writeEntries(os, *this);
}
void Foam::polyBoundaryMeshEntries::writeEntry
(
const keyType& keyword,
Ostream& os
) const
{
const PtrList<entry>& entries = *this;
if (!keyword.empty())
{
os.write(keyword);
os << (entries.empty() ? token::SPACE : token::NL);
}
writeEntries(os, entries);
if (!keyword.empty()) os.endEntry();
}
bool Foam::polyBoundaryMeshEntries::writeData(Ostream& os) const
{
return writeEntries(os, *this);
}
bool Foam::polyBoundaryMeshEntries::writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc
) const
{
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
return regIOobject::writeObject(streamOpt, writeOnProc);
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2020-2022 OpenCFD Ltd.
Copyright (C) 2020-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -29,6 +29,9 @@ Class
Description
Read and store dictionary entries for boundary patches
The object is *never* registered to avoid registry name clashes with
polyBoundaryMesh, which may either already have been registered, or
which should subsequently be registered.
SourceFiles
polyBoundaryMeshEntries.C
@ -41,6 +44,7 @@ SourceFiles
#include "regIOobject.H"
#include "PtrList.H"
#include "entry.H"
#include "wordList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -64,33 +68,70 @@ public:
// Constructors
//- Read construct from IOobject
explicit polyBoundaryMeshEntries(const IOobject& io)
:
regIOobject(io)
{
if (isReadRequired() || (isReadOptional() && headerOk()))
{
// Read as entries
Istream& is = readStream(typeName);
is >> *this;
close();
}
}
//- Read construct from IOobject. Never register!
explicit polyBoundaryMeshEntries(const IOobject& io);
// Member Functions
// Factory Methods
//- Read and return contents. The IOobject is never registered
static PtrList<entry> readContents(const IOobject& io);
// Static Functions
//- Truncate entries at the first processor patch entry
static void removeProcPatches(PtrList<entry>& entries);
//- Write list of entries
static bool writeEntries(Ostream& os, const UPtrList<entry>& entries);
//- Return a list of patch types, uses the "patch" entry
static wordList types(const UPtrList<entry>& entries);
//- Return a list of patch start face indices, uses "startFace" entry
static labelList patchStarts(const UPtrList<entry>& entries);
//- Return a list of patch sizes, uses "nFaces" entry
static labelList patchSizes(const UPtrList<entry>& entries);
// Member Functions
//- Truncate at the first processor patch entry
void removeProcPatches();
//- The class is probably read-only
bool writeData(Ostream&) const
{
NotImplemented;
return false;
}
// Characteristics
//- Return a list of patch types, uses the "patch" entry
wordList types() const;
//- Return a list of patch start face indices, uses "startFace" entry
labelList patchStarts() const;
//- Return a list of patch sizes, uses "nFaces" entry
labelList patchSizes() const;
// Write
//- Write as a plain list of entries
void writeEntry(Ostream& os) const;
//- Write as a primitive entry with given name.
//- If the keyword is empty, revert to a plain list.
void writeEntry(const keyType& keyword, Ostream& os) const;
//- The writeData member function required by regIOobject
virtual bool writeData(Ostream& os) const;
//- Write using stream options, forces UNCOMPRESSED
virtual bool writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc = true
) const;
};

View File

@ -259,7 +259,7 @@ Foam::polyMesh::polyMesh(const IOobject& io, const bool doInit)
IOobject::NO_WRITE
),
*this,
PtrList<pointZone>()
PtrList<entry>()
),
faceZones_
(
@ -273,7 +273,7 @@ Foam::polyMesh::polyMesh(const IOobject& io, const bool doInit)
IOobject::NO_WRITE
),
*this,
PtrList<faceZone>()
PtrList<entry>()
),
cellZones_
(
@ -287,7 +287,7 @@ Foam::polyMesh::polyMesh(const IOobject& io, const bool doInit)
IOobject::NO_WRITE
),
*this,
PtrList<cellZone>()
PtrList<entry>()
),
globalMeshDataPtr_(nullptr),
moving_(false),

View File

@ -135,39 +135,58 @@ Foam::polyMesh::readUpdateState Foam::polyMesh::readUpdate()
)
);
// NOTE: owner_.hasHeaderClass() is probably sticky from before.
// Could potentially cause problems if constructed without reading
// and then using readUpdate() to create a new mesh
// owner
{
owner_.clear();
owner_.clear();
owner_ = labelIOList
(
IOobject
labelIOList list
(
"owner",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
IOobject
(
"owner",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
neighbour_.clear();
neighbour_ = labelIOList
(
IOobject
// Update owner headerClassName.
// The "cells" logic below may rely on it!
owner_ = std::move(static_cast<labelList&>(list));
owner_.headerClassName() = std::move(list.headerClassName());
owner_.note() = std::move(list.note());
}
// neighbour
{
neighbour_.clear();
labelIOList list
(
"neighbour",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
IOobject
(
"neighbour",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
)
);
// Update neighbour headerClassName.
// - not currently needed, but for symmetry with owner
// The "cells" logic below may rely on it!
neighbour_ = std::move(static_cast<labelList&>(list));
neighbour_.headerClassName() = std::move(list.headerClassName());
neighbour_.note() = std::move(list.note());
}
// Reset the boundary patches
polyBoundaryMesh newBoundary
@ -290,117 +309,49 @@ Foam::polyMesh::readUpdateState Foam::polyMesh::readUpdate()
// - this will be extremely fragile (not just here) if the names
// or the order of the zones also change
// pointZones
{
pointZones_.clearAddressing();
pointZones_.clearPrimitives();
pointZoneMesh newZones
(
IOobject
(
"pointZones",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
*this,
PtrList<pointZone>()
);
pointZones_.resize(newZones.size());
forAll(pointZones_, zonei)
{
// Existing or new empty zone
auto& zn =
pointZones_.try_emplace
(
zonei,
newZones[zonei], Foam::zero{}, pointZones_
);
// Set addressing
zn.resetAddressing(std::move(newZones[zonei]));
}
#undef update_meshZones
#define update_meshZones(DataMember) \
{ \
(DataMember).clearAddressing(); \
(DataMember).clearPrimitives(); \
\
decltype(DataMember) newZones \
( \
IOobject \
( \
(DataMember).name(), \
facesInst, \
meshSubDir, \
*this, \
IOobject::READ_IF_PRESENT, \
IOobject::NO_WRITE, \
IOobject::NO_REGISTER \
), \
*this, \
PtrList<entry>() \
); \
const label numZones = newZones.size(); \
(DataMember).resize(numZones); \
\
for (label zonei = 0; zonei < numZones; ++zonei) \
{ \
/* Existing or new empty zone */ \
auto& zn = (DataMember).try_emplace \
( \
zonei, \
newZones[zonei], Foam::zero{}, (DataMember) \
); \
\
/* Set addressing */ \
zn.resetAddressing(std::move(newZones[zonei])); \
} \
}
// faceZones
{
faceZones_.clearAddressing();
faceZones_.clearPrimitives();
update_meshZones(pointZones_);
update_meshZones(faceZones_);
update_meshZones(cellZones_);
#undef update_meshZones
faceZoneMesh newZones
(
IOobject
(
"faceZones",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
*this,
PtrList<faceZone>()
);
faceZones_.resize(newZones.size());
forAll(faceZones_, zonei)
{
// Existing or new empty zone
auto& zn =
faceZones_.try_emplace
(
zonei,
newZones[zonei], Foam::zero{}, faceZones_
);
// Set addressing
zn.resetAddressing(std::move(newZones[zonei]));
}
}
// cellZones
{
cellZones_.clearAddressing();
cellZones_.clearPrimitives();
cellZoneMesh newZones
(
IOobject
(
"cellZones",
facesInst,
meshSubDir,
*this,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
*this,
PtrList<cellZone>()
);
cellZones_.resize(newZones.size());
forAll(cellZones_, zonei)
{
// Existing or new empty zone
auto& zn =
cellZones_.try_emplace
(
zonei,
newZones[zonei], Foam::zero{}, cellZones_
);
// Set addressing
zn.resetAddressing(std::move(newZones[zonei]));
}
}
// Re-read tet base points
tetBasePtIsPtr_ = readTetBasePtIs();

View File

@ -157,12 +157,55 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcGroupIDs() const
}
template<class ZoneType, class MeshType>
void Foam::ZoneMesh<ZoneType, MeshType>::populate
(
PtrList<entry>&& entries
)
{
clearLocalAddressing();
PtrList<ZoneType>& zones = *this;
zones.resize_null(entries.size());
// Transcribe
// Does not handle nullptr at all
forAll(zones, zonei)
{
// Possible handling for nullptr:
// zones.emplace_set
// (
// zonei,
// "missing_" + ::Foam::name(zonei), zonei, *this
// );
zones.set
(
zonei,
ZoneType::New
(
entries[zonei].keyword(),
entries[zonei].dict(),
zonei,
*this
)
);
}
entries.clear();
}
template<class ZoneType, class MeshType>
bool Foam::ZoneMesh<ZoneType, MeshType>::readContents
(
const bool allowOptionalRead
)
{
bool updated = false;
PtrList<entry> entries;
if
(
isReadRequired()
@ -172,37 +215,24 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::readContents
// Warn for MUST_READ_IF_MODIFIED
warnNoRereading<ZoneMesh<ZoneType, MeshType>>();
PtrList<ZoneType>& zones = *this;
// Read entries
Istream& is = readStream(typeName);
PtrList<entry> entries(is);
zones.resize_null(entries.size());
// Transcribe
forAll(zones, zonei)
{
zones.set
(
zonei,
ZoneType::New
(
entries[zonei].keyword(),
entries[zonei].dict(),
zonei,
*this
)
);
}
is >> entries;
is.check(FUNCTION_NAME);
close();
return true;
updated = true;
}
// Nothing read
return false;
// Future: support master-only and broadcast?
if (updated)
{
populate(std::move(entries));
}
return updated;
}
@ -283,6 +313,26 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
}
template<class ZoneType, class MeshType>
Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
(
const IOobject& io,
const MeshType& mesh,
PtrList<entry>&& entries
)
:
PtrList<ZoneType>(),
regIOobject(io),
mesh_(mesh)
{
if (!readContents(true)) // allowOptionalRead = true
{
populate(std::move(entries));
}
entries.clear();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class ZoneType, class MeshType>
@ -759,11 +809,19 @@ void Foam::ZoneMesh<ZoneType, MeshType>::setGroup
}
// Private until it is more generally required (and gets a better name?)
template<class ZoneType, class MeshType>
void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
void Foam::ZoneMesh<ZoneType, MeshType>::clearLocalAddressing()
{
zoneMapPtr_.reset(nullptr);
groupIDsPtr_.reset(nullptr);
}
template<class ZoneType, class MeshType>
void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
{
clearLocalAddressing();
PtrList<ZoneType>& zones = *this;

View File

@ -82,10 +82,6 @@ class ZoneMesh
// Private Member Functions
//- Return true if contents were read
//- (controlled by IOobject readOption flags).
bool readContents(const bool allowOptionalRead);
//- Total of number of addressed items (all zones)
label totalSize() const;
@ -98,6 +94,31 @@ class ZoneMesh
//- Calculate group name to zone ids lookup
void calcGroupIDs() const;
//- Clear addressing at this level
void clearLocalAddressing();
//- Populate/recreate from dictionary entries
void populate(PtrList<entry>&& entries);
//- Return true if contents were read
//- (controlled by IOobject readOption flags).
bool readContents(const bool allowOptionalRead);
public:
// Public Typedefs
//- The zone type. Same as PtrList<ZoneType>::value_type
typedef ZoneType zone_type;
//- Debug switch to disallow the use of generic zones
static int disallowGenericZones;
// Generated Methods
//- No copy construct
ZoneMesh(const ZoneMesh&) = delete;
@ -105,12 +126,6 @@ class ZoneMesh
void operator=(const ZoneMesh<ZoneType, MeshType>&) = delete;
public:
//- Debug switch to disallow the use of generic zones
static int disallowGenericZones;
// Constructors
//- Read construct from IOobject and mesh reference
@ -148,6 +163,15 @@ public:
const PtrList<ZoneType>& list
);
//- Read construct (mandatory, optional) based on IOobject properties
//- or use the fallback PtrList (with cloning).
ZoneMesh
(
const IOobject& io,
const MeshType& mesh,
PtrList<entry>&& entries
);
//- Destructor
~ZoneMesh() = default;

View File

@ -72,6 +72,7 @@ Foam::boundaryPatch::boundaryPatch(const boundaryPatch& p, const label index)
void Foam::boundaryPatch::write(Ostream& os) const
{
// if (!type_.empty()) os.writeEntry("type", type_);
patchIdentifier::write(os);
os.writeEntry("nFaces", size_);
os.writeEntry("startFace", start_);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -41,6 +41,7 @@ SourceFiles
#define Foam_boundaryPatch_H
#include "patchIdentifier.H"
#include "labelRange.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -58,8 +59,10 @@ class boundaryPatch
{
// Private Data
//- The size of the patch
label size_;
//- Start label of the patch
label start_;
public:
@ -100,24 +103,22 @@ public:
// Member Functions
label size() const
{
return size_;
}
//- The start of the patch
label start() const noexcept { return start_; }
label& size()
{
return size_;
}
//- The start of the patch (modifiable)
label& start() noexcept { return start_; }
label start() const
{
return start_;
}
//- The size of the patch
label size() const noexcept { return size_; }
label& start()
//- The size of the patch (modifiable)
label& size() noexcept { return size_; }
//- Return start/size range of this patch
labelRange range() const noexcept
{
return start_;
return labelRange(start_, size_);
}

View File

@ -101,8 +101,40 @@ void Foam::faBoundaryMesh::calcGroupIDs() const
}
void Foam::faBoundaryMesh::populate(PtrList<entry>&& entries)
{
clearLocalAddressing();
faPatchList& patches = *this;
patches.resize_null(entries.size());
// Transcribe.
// Does not handle nullptr at all (what could possibly be done?)
forAll(patches, patchi)
{
patches.set
(
patchi,
faPatch::New
(
entries[patchi].keyword(),
entries[patchi].dict(),
patchi,
*this
)
);
}
entries.clear();
}
bool Foam::faBoundaryMesh::readContents(const bool allowOptionalRead)
{
bool updated = false;
PtrList<entry> entries;
if
(
isReadRequired()
@ -112,37 +144,23 @@ bool Foam::faBoundaryMesh::readContents(const bool allowOptionalRead)
// Warn for MUST_READ_IF_MODIFIED
warnNoRereading<faBoundaryMesh>();
faPatchList& patches = *this;
// Read entries
Istream& is = readStream(typeName);
PtrList<entry> entries(is);
patches.resize_null(entries.size());
// Transcribe
forAll(patches, patchi)
{
patches.set
(
patchi,
faPatch::New
(
entries[patchi].keyword(),
entries[patchi].dict(),
patchi,
*this
)
);
}
is >> entries;
is.check(FUNCTION_NAME);
close();
return true;
updated = true;
}
// Future: support master-only and broadcast?
if (updated)
{
populate(std::move(entries));
}
// Nothing read
return false;
return updated;
}
@ -213,11 +231,36 @@ Foam::faBoundaryMesh::faBoundaryMesh
}
Foam::faBoundaryMesh::faBoundaryMesh
(
const IOobject& io,
const faMesh& fam,
PtrList<entry>&& entries
)
:
faPatchList(),
regIOobject(io),
mesh_(fam)
{
if (!readContents(true)) // allowOptionalRead = true
{
populate(std::move(entries));
}
entries.clear();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
void Foam::faBoundaryMesh::clear()
{
clearLocalAddressing();
faPatchList::clear();
}
void Foam::faBoundaryMesh::clearLocalAddressing()
{
groupIDsPtr_.reset(nullptr);
}
@ -987,22 +1030,56 @@ void Foam::faBoundaryMesh::updateMesh()
}
bool Foam::faBoundaryMesh::writeData(Ostream& os) const
void Foam::faBoundaryMesh::writeEntry(Ostream& os) const
{
const faPatchList& patches = *this;
const faPatchList& entries = *this;
os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
os << entries.size();
for (const faPatch& p : patches)
if (entries.empty())
{
os.beginBlock(p.name());
os << p;
os.endBlock();
// 0-sized : can write with less vertical space
os << token::BEGIN_LIST << token::END_LIST;
}
else
{
os << nl << token::BEGIN_LIST << incrIndent << nl;
for (const auto& pp : entries)
{
os.beginBlock(pp.name());
os << pp;
os.endBlock();
}
os << decrIndent << token::END_LIST;
}
os.check(FUNCTION_NAME);
}
void Foam::faBoundaryMesh::writeEntry
(
const keyType& keyword,
Ostream& os
) const
{
const faPatchList& entries = *this;
if (!keyword.empty())
{
os.write(keyword);
os << (entries.empty() ? token::SPACE : token::NL);
}
os << decrIndent << token::END_LIST;
writeEntry(os);
os.check(FUNCTION_NAME);
if (!keyword.empty()) os.endEntry();
}
bool Foam::faBoundaryMesh::writeData(Ostream& os) const
{
writeEntry(os);
return os.good();
}
@ -1013,10 +1090,7 @@ bool Foam::faBoundaryMesh::writeObject
const bool writeOnProc
) const
{
// Allow/disallow compression?
// 1. keep readable
// 2. save some space
// ??? streamOpt.compression(IOstreamOption::UNCOMPRESSED);
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
return regIOobject::writeObject(streamOpt, writeOnProc);
}

View File

@ -55,6 +55,7 @@ namespace Foam
{
// Forward Declarations
class entry;
class faMesh;
class faBoundaryMesh;
class wordRes;
@ -87,11 +88,16 @@ class faBoundaryMesh
//- Calculate group name to patch ids lookup
void calcGroupIDs() const;
//- Clear addressing at this level
void clearLocalAddressing();
//- Populate/recreate from dictionary entries
void populate(PtrList<entry>&& entries);
//- Return true if contents were read
//- (controlled by IOobject readOption flags).
bool readContents(const bool allowOptionalRead);
public:
//- Runtime type information
@ -143,6 +149,15 @@ public:
const faPatchList& list
);
//- Read construct (mandatory, optional) based on IOobject properties
//- or fallback to constructing from a list of dictionary entries
faBoundaryMesh
(
const IOobject& io,
const faMesh& fam,
PtrList<entry>&& entries
);
//- Destructor
~faBoundaryMesh() = default;
@ -278,14 +293,24 @@ public:
//- Correct faBoundaryMesh after topology update
void updateMesh();
//- The writeData member function required by regIOobject
bool writeData(Ostream& os) const;
//- Write using stream options
// Write
//- Write as a plain list of entries
void writeEntry(Ostream& os) const;
//- Write as a primitive entry with given name.
//- If the keyword is empty, revert to a plain list.
void writeEntry(const keyType& keyword, Ostream& os) const;
//- The writeData member function required by regIOobject
virtual bool writeData(Ostream& os) const;
//- Write using stream options, but always UNCOMPRESSED
virtual bool writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc
const bool writeOnProc = true
) const;

View File

@ -36,12 +36,72 @@ namespace Foam
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
void Foam::faBoundaryMeshEntries::removeProcPatches()
Foam::faBoundaryMeshEntries::faBoundaryMeshEntries(const IOobject& io)
:
regIOobject
(
IOobject(io, IOobjectOption::NO_REGISTER)
)
{
// readContents()
if (isReadRequired() || (isReadOptional() && headerOk()))
{
// Read as entries
Istream& is = readStream(typeName);
is >> *this;
close();
}
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::PtrList<Foam::entry>
Foam::faBoundaryMeshEntries::readContents(const IOobject& io)
{
faBoundaryMeshEntries reader(io);
return PtrList<entry>(std::move(static_cast<PtrList<entry>&>(reader)));
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Extract optional entry from dictionaries and return as a list
template<class T>
static inline List<T> extract
(
const word& key,
const UPtrList<entry>& entries,
const T& initValue
)
{
List<T> result(entries.size(), initValue);
forAll(entries, i)
{
const dictionary& dict = entries[i].dict();
dict.readIfPresent(key, result[i]);
}
return result;
}
} // End namespace
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
void Foam::faBoundaryMeshEntries::removeProcPatches(PtrList<entry>& entries)
{
// Truncate at the first processor patch entry
PtrList<entry>& entries = *this;
label nNonProcessor = entries.size();
@ -61,4 +121,102 @@ void Foam::faBoundaryMeshEntries::removeProcPatches()
}
bool Foam::faBoundaryMeshEntries::writeEntries
(
Ostream& os,
const UPtrList<entry>& entries
)
{
os << entries.size();
if (entries.empty())
{
// 0-sized : can write with less vertical space
os << token::BEGIN_LIST << token::END_LIST;
}
else
{
os << nl << token::BEGIN_LIST << incrIndent << nl;
forAll(entries, patchi)
{
const auto& key = entries[patchi].keyword();
const auto& dict = entries[patchi].dict();
dict.writeEntry(key, os);
}
os << decrIndent << token::END_LIST;
}
os.check(FUNCTION_NAME);
return os.good();
}
Foam::wordList Foam::faBoundaryMeshEntries::types
(
const UPtrList<entry>& entries
)
{
return extract<word>("type", entries, "patch");
}
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
void Foam::faBoundaryMeshEntries::removeProcPatches()
{
removeProcPatches(*this);
}
Foam::wordList Foam::faBoundaryMeshEntries::types() const
{
return extract<word>("type", *this, "patch");
}
void Foam::faBoundaryMeshEntries::writeEntry(Ostream& os) const
{
writeEntries(os, *this);
}
void Foam::faBoundaryMeshEntries::writeEntry
(
const keyType& keyword,
Ostream& os
) const
{
const PtrList<entry>& entries = *this;
if (!keyword.empty())
{
os.write(keyword);
os << (entries.empty() ? token::SPACE : token::NL);
}
writeEntries(os, entries);
if (!keyword.empty()) os.endEntry();
}
bool Foam::faBoundaryMeshEntries::writeData(Ostream& os) const
{
return writeEntries(os, *this);
}
bool Foam::faBoundaryMeshEntries::writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc
) const
{
streamOpt.compression(IOstreamOption::UNCOMPRESSED);
return regIOobject::writeObject(streamOpt, writeOnProc);
}
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
Copyright (C) 2022-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,6 +28,9 @@ Class
Description
Read and store dictionary entries for finite-area boundary patches.
The object is *never* registered to avoid registry name clashes with
faBoundaryMesh, which may either already have been registered, or
which should subsequently be registered.
SourceFiles
faBoundaryMeshEntries.C
@ -40,6 +43,7 @@ SourceFiles
#include "regIOobject.H"
#include "PtrList.H"
#include "entry.H"
#include "wordList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -63,20 +67,26 @@ public:
// Constructors
//- Read construct from IOobject
explicit faBoundaryMeshEntries(const IOobject& io)
:
regIOobject(io)
{
if (isReadRequired() || (isReadOptional() && headerOk()))
{
// Read as entries
Istream& is = readStream(typeName);
//- Read construct from IOobject. Never register!
explicit faBoundaryMeshEntries(const IOobject& io);
is >> *this;
close();
}
}
// Factory Methods
//- Read and return contents. The IOobject is never registered
static PtrList<entry> readContents(const IOobject& io);
// Static Functions
//- Truncate entries at the first processor patch entry
static void removeProcPatches(PtrList<entry>& entries);
//- Write list of entries
static bool writeEntries(Ostream& os, const UPtrList<entry>& entries);
//- Return a list of patch types, uses the "patch" entry
static wordList types(const UPtrList<entry>& entries);
// Member Functions
@ -84,12 +94,31 @@ public:
//- Truncate at the first processor patch entry
void removeProcPatches();
//- The class is probably read-only
bool writeData(Ostream&) const
{
NotImplemented;
return false;
}
// Characteristics
//- Return a list of patch types, uses the "patch" entry
wordList types() const;
// Write
//- Write as a plain list of entries
void writeEntry(Ostream& os) const;
//- Write as a primitive entry with given name.
//- If the keyword is empty, revert to a plain list.
void writeEntry(const keyType& keyword, Ostream& os) const;
//- The writeData member function required by regIOobject
virtual bool writeData(Ostream& os) const;
//- Write using stream options, forces UNCOMPRESSED
virtual bool writeObject
(
IOstreamOption streamOpt,
const bool writeOnProc = true
) const;
};