Loading...
Searching...
No Matches
cellDecomposer.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2024-2025 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "cellDecomposer.H"
30#include "polyTopoChange.H"
31#include "mapPolyMesh.H"
32#include "tetDecomposer.H"
33#include "syncTools.H"
34#include "dummyTransform.H"
35#include "ReadFields.H"
36#include "surfaceFields.H"
37#include "fvMeshTools.H"
38#include "cellSetOption.H"
39#include "cellBitSet.H"
40#include "cellSet.H"
41#include "hexMatcher.H"
42#include "prismMatcher.H"
43#include "pyrMatcher.H"
44#include "tetMatcher.H"
45
46#include "OBJstream.H"
48// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
49
50namespace Foam
51{
52namespace functionObjects
53{
56}
57}
58
59
60// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
61
62void Foam::functionObjects::cellDecomposer::makeMesh
63(
64 const dictionary& dict,
65 const word& regionName
66)
67{
68 Info<< name() << ':' << nl
69 << " Decomposing cells to region " << regionName << endl;
70
72
73 const fv::cellSetOption::selectionModeType selectionMode
74 (
76 (
77 "selectionMode",
78 dict
79 )
80 );
81
82
83 // Start off from existing mesh
84 polyTopoChange meshMod(mesh_);
85
86 tetDecompPtr_.reset(new Foam::tetDecomposer(mesh_));
87
88 // Default values
89 bitSet decomposeCell(mesh_.nCells());
90 autoPtr<bitSet> decomposeFacePtr;
92 (
94 );
95
96
97 switch (selectionMode)
98 {
100 {
101 Info<< indent << "- selecting all cells" << endl;
102
103 decomposeCell = true;
104 break;
105 }
107 {
108 Info<< indent << "- selecting cells geometrically" << endl;
109
110 decomposeCell =
111 cellBitSet::select(mesh_, dict.subDict("selection"), true);
112 break;
113 }
115 {
116 const word selectionName(dict.get<word>("cellSet"));
117
118 Info<< indent
119 << "- selecting cells using cellSet "
120 << selectionName << endl;
121
122 decomposeCell.set
123 (
124 cellSet(mesh_, selectionName, IOobject::MUST_READ).toc()
125 );
126 break;
127 }
129 {
130 wordRes selectionNames;
131 if
132 (
133 !dict.readIfPresent("cellZones", selectionNames)
134 || selectionNames.empty()
135 )
136 {
137 selectionNames.resize(1);
138 dict.readEntry("cellZone", selectionNames.first());
139 }
140
141 Info<< indent
142 << "- selecting cells using cellZones "
143 << flatOutput(selectionNames) << nl;
144
145 const auto& zones = mesh_.cellZones();
146
147 // Also handles groups, multiple zones etc ...
148 labelList zoneIDs = zones.indices(selectionNames);
149
150 if (zoneIDs.empty())
151 {
153 << "No matching cellZones: "
154 << flatOutput(selectionNames) << nl
155 << "Valid zones : "
156 << flatOutput(zones.names()) << nl
157 << "Valid groups: "
158 << flatOutput(zones.groupNames())
159 << nl
160 << exit(FatalError);
161 }
162
163 if (zoneIDs.size() == 1)
164 {
165 decomposeCell.set(zones[zoneIDs.first()]);
166 // TBD: Foam::sort(cells_);
167 }
168 else
169 {
170 decomposeCell.set(zones.selection(zoneIDs).sortedToc());
171 }
172 break;
173 }
174 default:
175 {
177 << "Unsupported selectionMode "
179 << ". Valid selectionMode types are "
181 << exit(FatalError);
182 }
183 }
184
185 word decompTypeName;
186 if (dict.readIfPresent("decomposeType", decompTypeName))
187 {
188 if (decompTypeName == "polyhedral")
189 {
190 // Automatic selection to generate hex/prism/tet only
191 // - subset decomposeCell to exclude hex/prism/tet
192 // - set faces to FACE_DIAG_QUADS
193 // Usually start with cellSetOption::smAll
194 decomposeFacePtr.reset(new bitSet(mesh_.nFaces()));
195 auto& decomposeFace = decomposeFacePtr();
196
198 bitSet oldDecomposeCell(decomposeCell);
199 decomposeCell = false;
200
201 // Construct shape recognizers
202 prismMatcher prism;
203
204 for (const label celli : oldDecomposeCell)
205 {
206 if
207 (
208 !hexMatcher::test(mesh_, celli)
209 && !tetMatcher::test(mesh_, celli)
210 && !pyrMatcher::test(mesh_, celli)
211 && !prism.isA(mesh_, celli)
212 )
213 {
214 decomposeCell.set(celli);
215 decomposeFace.set(mesh_.cells()[celli]);
216 }
217 }
218
219 // Sync boundary info
221 (
222 mesh_,
223 decomposeFace,
224 orEqOp<unsigned int>()
225 );
226 }
227 else
228 {
229 decompType = tetDecomposer::decompositionTypeNames[decompTypeName];
230 }
231 }
232
233
234 // Insert all changes to create tets
235 if (decomposeFacePtr)
236 {
237 if (debug)
238 {
239 OBJstream os(mesh_.time().path()/"orig_faces.obj");
240 os.write
241 (
242 UIndirectList<face>
243 (
244 mesh_.faces(),
245 decomposeFacePtr().sortedToc()
246 )(),
247 mesh_.points(),
248 false
249 );
250 Pout<< "Written " << meshMod.faces().size()
251 << " faces to " << os.name() << endl;
252 }
253
254 tetDecompPtr_().setRefinement
255 (
256 decompType, //Foam::tetDecomposer::FACE_CENTRE_TRIS,
257 decomposeCell,
258 decomposeFacePtr(),
259 meshMod
260 );
261 }
262 else
263 {
264 tetDecompPtr_().setRefinement
265 (
266 decompType, //Foam::tetDecomposer::FACE_CENTRE_TRIS,
267 decomposeCell,
268 meshMod
269 );
270 }
271
272
273 if (debug)
274 {
275 OBJstream os(mesh_.time().path()/"faces.obj");
276 os.write(meshMod.faces(), pointField(meshMod.points()), false);
277 Pout<< "Written " << meshMod.faces().size()
278 << " faces to " << os.name() << endl;
279 }
280
281
282 autoPtr<fvMesh> tetMeshPtr;
283
284 mapPtr_ = meshMod.makeMesh
285 (
286 tetMeshPtr,
287 IOobject
288 (
290 mesh_.facesInstance(), // same instance as original mesh
291 mesh_.time(), //? why same database? TBD.
292 IOobject::READ_IF_PRESENT, // Read fv* if present
295 ),
296 mesh_
297 );
298
299
300 //- Update numbering on tet-decomposition engine
301 tetDecompPtr_().updateMesh(mapPtr_());
302
303 Info<< indent << "Writing decomposed mesh to "
304 << tetMeshPtr().objectRegistry::objectRelPath()
305 << endl;
306 tetMeshPtr().write();
307
309
310 // Store new mesh on object registry
311 tetMeshPtr.ptr()->polyMesh::store();
312
315
316
317// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
318
320(
321 const word& name,
322 const Time& runTime,
323 const dictionary& dict
324)
325:
327 cacheDecomposition_(false)
328{
329 read(dict);
331
332
333// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
334
336{
338 {
339 // Generate new tet equivalent mesh. TBD: why meshObject?
340 //meshObjects::tetDecomposition::New(mesh, dict);
341
342 dict_ = dict.optionalSubDict(typeName + "Coeffs");
343 dict_.readEntry("mapRegion", mapRegion_);
344 dict_.readEntry("fields", fieldNames_);
345 dict_.readIfPresent("cacheDecomposition", cacheDecomposition_);
346 makeMesh(dict_, mapRegion_);
347 }
349 return true;
350}
351
352
354{
355 Log << type() << " " << name() << " execute:" << nl;
356
357 bool ok = false;
358
359 if (mesh_.changing())
360 {
361 // Re-do mesh. Currently rebuilds whole mesh. Could move points only
362 // for mesh motion.
363 const auto* mapRegionPtr =
364 this->mesh_.time().findObject<fvMesh>(mapRegion_);
365
366 if (cacheDecomposition_ && mapRegionPtr && tetDecompPtr_)
367 {
368 //- Could update points (on tetMesh and mapper). Gives AMI
369 //- issues currently.
370 // fvMesh& mapRegion = const_cast<fvMesh&>(*mapRegionPtr);
371 // const auto& cellToPoint = tetDecompPtr_().cellToPoint();
372 // const auto& faceToPoint = tetDecompPtr_().faceToPoint();
373 // pointField newPoints(mapRegion.nPoints());
374 // forAll(cellToPoint, celli)
375 // {
376 // const label pti = cellToPoint[celli];
377 // if (pti != -1)
378 // {
379 // newPoints[pti] = mesh_.cellCentres()[celli];
380 // }
381 // }
382 // forAll(faceToPoint, facei)
383 // {
384 // const label pti = faceToPoint[facei];
385 // if (pti != -1)
386 // {
387 // newPoints[pti] = mesh_.faceCentres()[facei];
388 // }
389 // }
390 // mapRegion.movePoints(newPoints);
391 }
392 else
393 {
394 tetDecompPtr_.clear();
395 mapPtr_.clear();
396 const_cast<Time&>(this->mesh_.time()).erase(mapRegion_);
397 makeMesh(dict_, mapRegion_);
398 }
399 }
400
401 // Look up
402 ok = mapFieldType<scalar>() || ok;
403 ok = mapFieldType<vector>() || ok;
404 ok = mapFieldType<sphericalTensor>() || ok;
405 ok = mapFieldType<symmTensor>() || ok;
406 ok = mapFieldType<tensor>() || ok;
407
408
409 if (!ok)
410 {
411 Log << " none" << nl;
412 }
413
414 Log << endl;
415
416 return true;
417}
419
421{
422 Log << type() << " " << name() << " write:" << nl;
423
424 bool ok = false;
425
426 ok = writeFieldType<scalar>() || ok;
427 ok = writeFieldType<vector>() || ok;
428 ok = writeFieldType<sphericalTensor>() || ok;
429 ok = writeFieldType<symmTensor>() || ok;
430 ok = writeFieldType<tensor>() || ok;
431
432
433 if (!ok)
434 {
435 Log << " none" << nl;
436 }
437
438 Log << endl;
439
440 return true;
441}
442
443
444// ************************************************************************* //
#define Log
Definition PDRblock.C:28
Field reading functions for post-processing utilities.
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
@ REGISTER
Request registration (bool: true).
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ MUST_READ
Reading required.
@ AUTO_WRITE
Automatically write from objectRegistry::writeObject().
virtual const fileName & name() const override
Get the name of the output serial stream. (eg, the name of the Fstream file name).
Definition OSstream.H:134
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition Time.H:75
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition autoPtrI.H:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
static bitSet select(const polyMesh &mesh, const dictionary &dict, const bool verbosity=false)
Return a cell selection according to the dictionary specification of actions.
Definition cellBitSet.C:84
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
Abstract base-class for Time/database function objects.
const word & name() const noexcept
Return the name of this functionObject.
virtual bool read(const dictionary &dict)
Read and set the function object if its data have changed.
static int debug
Flag to execute debug content.
Maps input fields from local mesh to a secondary mesh at runtime.
virtual bool read(const dictionary &dict)
Read the function-object dictionary.
cellDecomposer(const word &name, const Time &runTime, const dictionary &dict)
Construct from name, Time and dictionary.
virtual bool execute()
Execute the function-object operations.
virtual bool write()
Write the function-object results.
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
const fvMesh & mesh_
Reference to the fvMesh.
fvMeshFunctionObject(const fvMeshFunctionObject &)=delete
No copy construct.
static void createDummyFvMeshFiles(const objectRegistry &parent, const word &regionName, const bool verbose=false)
Create additional fvSchemes/fvSolution files.
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
static const Enum< selectionModeType > selectionModeTypeNames_
List of selection mode type names.
selectionModeType
Enumeration for selection mode types.
static bool test(const UList< face > &faces)
Test if given list of faces satisfies criteria for HEX. (6 quad).
Definition hexMatcher.C:80
bool erase(const iterator &iter)
Erase an entry specified by the given iterator.
Direct mesh changes based on v1.3 polyTopoChange syntax.
label nCells() const noexcept
Number of mesh cells.
static bool test(const UList< face > &faces)
Test if given list of faces satisfies criteria for PYR. (4 tri, 1 quad).
Definition pyrMatcher.C:107
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition syncTools.H:465
Decomposes polyMesh into tets (or pyramids).
static const Enum< decompositionType > decompositionTypeNames
static bool test(const UList< face > &faces)
Test if given list of faces satisfies criteria for TET. (4 tri).
Definition tetMatcher.C:82
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
engineTime & runTime
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
Dummy transform to be used with syncTools.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
auto & name
const labelIOList & zoneIDs
Definition correctPhi.H:59
List< label > toc(const UList< bool > &bools)
Return the (sorted) values corresponding to 'true' entries.
Definition BitOps.C:163
List< label > sortedToc(const UList< bool > &bools)
Return the (sorted) values corresponding to 'true' entries.
Definition BitOps.C:200
Function objects are OpenFOAM utilities to ease workflow configurations and enhance workflows.
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition Ostream.H:490
const word GlobalIOList< Tuple2< scalar, vector > >::typeName("scalarVectorTable")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
Ostream & indent(Ostream &os)
Indent stream.
Definition Ostream.H:481
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition FlatOutput.H:217
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition Ostream.H:499
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
Foam::surfaceFields.