1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 Hrvoje Jasak, Wikki Ltd. All rights reserved
31 Reconstructs a mesh using geometrical matching and catenation.
32 Use following topological changes in parallel to create global mesh
33 and xxxxProcAddressing files in the processor meshes.
35 \*---------------------------------------------------------------------------*/
38 #include "processorMeshesReconstructor.H"
39 #include "fvFieldReconstructor.H"
40 #include "pointFieldReconstructor.H"
41 #include "tetPointFieldReconstructor.H"
42 #include "reconstructLagrangian.H"
46 #include "processorFaMeshes.H"
47 #include "faFieldReconstructor.H"
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 int main(int argc, char *argv[])
53 // enable -constant ... if someone really wants it
54 // enable -zeroTime to prevent accidentally trashing the initial fields
55 timeSelector::addOptions(false, true);
56 argList::noParallel();
57 # include "addRegionOption.H"
58 argList::validOptions.insert("cellDist", "");
59 argList::validOptions.insert("fields", "\"(list of fields)\"");
60 argList::validOptions.insert("noLagrangian", "");
62 # include "setRootCase.H"
64 bool writeCellDist = args.optionFound("cellDist");
66 # include "createTime.H"
68 HashSet<word> selectedFields;
69 if (args.optionFound("fields"))
71 args.optionLookup("fields")() >> selectedFields;
74 bool noLagrangian = args.optionFound("noLagrangian");
76 // Determine the processor count directly
78 while (isDir(args.path()/(word("processor") + name(nProcs))))
85 FatalErrorIn(args.executable())
86 << "No processor* directories found"
90 // Create the processor databases
91 PtrList<Time> databases(nProcs);
93 forAll (databases, procI)
100 Time::controlDictName,
102 args.caseName()/fileName(word("processor") + name(procI))
107 // use the times list from the master processor
108 // and select a subset based on the command-line options
109 instantList timeDirs = timeSelector::select
111 databases[0].times(),
115 if (timeDirs.empty())
117 FatalErrorIn(args.executable())
118 << "No times selected"
122 Foam::word regionName = polyMesh::defaultRegion;
124 if (args.optionReadIfPresent("region", regionName))
126 Info<< "Selecting region " << regionName << " for time = "
127 << runTime.timeName() << Foam::nl << Foam::endl;
130 // Set all times on processor meshes equal to reconstructed mesh
131 forAll (databases, procI)
133 Info<< "Reading database for processor " << procI << endl;
135 databases[procI].setTime(runTime.timeName(), runTime.timeIndex());
138 // Read all meshes and addressing to reconstructed mesh
139 processorMeshesReconstructor procMeshes(databases, regionName);
141 autoPtr<fvMesh> meshPtr = procMeshes.reconstructMesh(runTime);
144 // Mesh write will be controlled by hand
146 procMeshes.writeAddressing();
147 meshPtr->setMotionWriteOpt(IOobject::NO_WRITE);
148 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
150 // Write cell decomposition
153 // Write as volScalarField for post-processing
154 Info<< "Writing cellDist to time " << runTime.timeName()
156 volScalarField cellDist
167 dimensionedScalar("cellDist", dimless, 0),
168 zeroGradientFvPatchScalarField::typeName
170 scalarField& cellDistIn = cellDist.internalField();
174 forAll (procMeshes.meshes(), procI)
179 i < procMeshes.meshes()[procI].nCells();
183 cellDistIn[cellI] = procI;
191 // Get region prefix for lagrangian
192 fileName regionPrefix = "";
193 if (regionName != fvMesh::defaultRegion)
195 regionPrefix = regionName;
199 // Loop over all times
200 forAll (timeDirs, timeI)
202 // Set time for global database
203 runTime.setTime(timeDirs[timeI], timeI);
205 Info << "Time = " << runTime.timeName() << endl << endl;
207 // Set time for all databases
208 forAll (databases, procI)
210 databases[procI].setTime(timeDirs[timeI], timeI);
213 polyMesh::readUpdateState procStat = procMeshes.readUpdate();
215 if (procStat == polyMesh::UNCHANGED)
217 Info<< "Mesh unchanged" << endl;
219 meshPtr->setMotionWriteOpt(IOobject::NO_WRITE);
220 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
222 else if (procStat == polyMesh::POINTS_MOVED)
224 Info<< "Mesh motion detected. Reconstruct motion points"
227 // Reconstruct the points for moving mesh cases and write them out
228 procMeshes.reconstructPoints(meshPtr());
231 meshPtr->setMotionWriteOpt(IOobject::AUTO_WRITE);
232 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
239 procStat == polyMesh::TOPO_CHANGE
240 || procStat == polyMesh::TOPO_PATCH_CHANGE
243 Info<< "Topological change detected. Reconstructing mesh"
247 meshPtr = procMeshes.reconstructMesh(runTime);
250 meshPtr->setMotionWriteOpt(IOobject::AUTO_WRITE);
251 meshPtr->setTopoWriteOpt(IOobject::AUTO_WRITE);
252 procMeshes.writeAddressing();
257 // Write out mapping in processor directories
258 forAll (databases, procI)
260 databases[procI].write();
265 // Write as volScalarField for post-processing
266 Info<< "Writing cellDist to time " << runTime.timeName()
268 volScalarField cellDist
279 dimensionedScalar("cellDist", dimless, 0),
280 zeroGradientFvPatchScalarField::typeName
282 scalarField& cellDistIn = cellDist.internalField();
286 forAll (procMeshes.meshes(), procI)
291 i < procMeshes.meshes()[procI].nCells();
295 cellDistIn[cellI] = procI;
305 FatalErrorIn(args.executable())
306 << "Unknown readUpdate state"
307 << abort(FatalError);
310 fvMesh& mesh = meshPtr();
312 // Get list of objects from processor0 database
313 IOobjectList objects(procMeshes.meshes()[0], databases[0].timeName());
316 // If there are any FV fields, reconstruct them
320 objects.lookupClass(volScalarField::typeName).size()
321 || objects.lookupClass(volVectorField::typeName).size()
322 || objects.lookupClass(volSphericalTensorField::typeName).size()
323 || objects.lookupClass(volSymmTensorField::typeName).size()
324 || objects.lookupClass(volTensorField::typeName).size()
325 || objects.lookupClass(surfaceScalarField::typeName).size()
326 || objects.lookupClass(surfaceVectorField::typeName).size()
327 || objects.lookupClass(surfaceSphericalTensorField::typeName).size()
328 || objects.lookupClass(surfaceSymmTensorField::typeName).size()
329 || objects.lookupClass(surfaceTensorField::typeName).size()
332 Info << "Reconstructing FV fields" << nl << endl;
334 fvFieldReconstructor fvReconstructor
338 procMeshes.faceProcAddressing(),
339 procMeshes.cellProcAddressing(),
340 procMeshes.boundaryProcAddressing()
343 fvReconstructor.reconstructFvVolumeFields<scalar>
348 fvReconstructor.reconstructFvVolumeFields<vector>
353 fvReconstructor.reconstructFvVolumeFields<sphericalTensor>
358 fvReconstructor.reconstructFvVolumeFields<symmTensor>
363 fvReconstructor.reconstructFvVolumeFields<tensor>
369 fvReconstructor.reconstructFvSurfaceFields<scalar>
374 fvReconstructor.reconstructFvSurfaceFields<vector>
379 fvReconstructor.reconstructFvSurfaceFields<sphericalTensor>
384 fvReconstructor.reconstructFvSurfaceFields<symmTensor>
389 fvReconstructor.reconstructFvSurfaceFields<tensor>
397 Info << "No FV fields" << nl << endl;
401 // If there are any point fields, reconstruct them
404 objects.lookupClass(pointScalarField::typeName).size()
405 || objects.lookupClass(pointVectorField::typeName).size()
406 || objects.lookupClass(pointSphericalTensorField::typeName).size()
407 || objects.lookupClass(pointSymmTensorField::typeName).size()
408 || objects.lookupClass(pointTensorField::typeName).size()
411 Info << "Reconstructing point fields" << nl << endl;
413 pointMesh pMesh(mesh);
414 PtrList<pointMesh> pMeshes(procMeshes.meshes().size());
416 forAll (pMeshes, procI)
418 pMeshes.set(procI, new pointMesh(procMeshes.meshes()[procI]));
421 pointFieldReconstructor pointReconstructor
425 procMeshes.pointProcAddressing(),
426 procMeshes.boundaryProcAddressing()
429 pointReconstructor.reconstructFields<scalar>(objects);
430 pointReconstructor.reconstructFields<vector>(objects);
431 pointReconstructor.reconstructFields<sphericalTensor>(objects);
432 pointReconstructor.reconstructFields<symmTensor>(objects);
433 pointReconstructor.reconstructFields<tensor>(objects);
437 Info << "No point fields" << nl << endl;
440 // If there are any tetFem fields, reconstruct them
443 objects.lookupClass(tetPointScalarField::typeName).size()
444 || objects.lookupClass(tetPointVectorField::typeName).size()
445 || objects.lookupClass(tetPointSphericalTensorField::typeName).size()
446 || objects.lookupClass(tetPointSymmTensorField::typeName).size()
447 || objects.lookupClass(tetPointTensorField::typeName).size()
449 || objects.lookupClass(elementScalarField::typeName).size()
450 || objects.lookupClass(elementVectorField::typeName).size()
453 Info << "Reconstructing tet point fields" << nl << endl;
455 tetPolyMesh tetMesh(mesh);
456 PtrList<tetPolyMesh> tetMeshes(procMeshes.meshes().size());
458 forAll (tetMeshes, procI)
463 new tetPolyMesh(procMeshes.meshes()[procI])
467 tetPointFieldReconstructor tetPointReconstructor
471 procMeshes.pointProcAddressing(),
472 procMeshes.faceProcAddressing(),
473 procMeshes.cellProcAddressing(),
474 procMeshes.boundaryProcAddressing()
477 // Reconstruct tet point fields
478 tetPointReconstructor.reconstructTetPointFields<scalar>(objects);
479 tetPointReconstructor.reconstructTetPointFields<vector>(objects);
480 tetPointReconstructor.
481 reconstructTetPointFields<sphericalTensor>(objects);
482 tetPointReconstructor.
483 reconstructTetPointFields<symmTensor>(objects);
484 tetPointReconstructor.reconstructTetPointFields<tensor>(objects);
486 tetPointReconstructor.reconstructElementFields<scalar>(objects);
487 tetPointReconstructor.reconstructElementFields<vector>(objects);
491 Info << "No tetFem fields" << nl << endl;
495 // If there are any clouds, reconstruct them.
496 // The problem is that a cloud of size zero will not get written so
497 // in pass 1 we determine the cloud names and per cloud name the
498 // fields. Note that the fields are stored as IOobjectList from
499 // the first processor that has them. They are in pass2 only used
500 // for name and type (scalar, vector etc).
504 HashTable<IOobjectList> cloudObjects;
506 forAll (databases, procI)
508 fileNameList cloudDirs
512 databases[procI].timePath()/regionPrefix/cloud::prefix,
517 forAll (cloudDirs, i)
519 // Check if we already have cloud objects for
521 HashTable<IOobjectList>::const_iterator iter =
522 cloudObjects.find(cloudDirs[i]);
524 if (iter == cloudObjects.end())
526 // Do local scan for valid cloud objects
527 IOobjectList sprayObjs
529 procMeshes.meshes()[procI],
530 databases[procI].timeName(),
531 cloud::prefix/cloudDirs[i]
534 IOobject* positionsPtr = sprayObjs.lookup("positions");
538 cloudObjects.insert(cloudDirs[i], sprayObjs);
545 if (cloudObjects.size())
547 // Pass2: reconstruct the cloud
548 forAllConstIter(HashTable<IOobjectList>, cloudObjects, iter)
550 const word cloudName = string::validate<word>(iter.key());
552 // Objects (on arbitrary processor)
553 const IOobjectList& sprayObjs = iter();
555 Info<< "Reconstructing lagrangian fields for cloud "
556 << cloudName << nl << endl;
558 reconstructLagrangianPositions
563 procMeshes.faceProcAddressing(),
564 procMeshes.cellProcAddressing()
566 reconstructLagrangianFields<label>
573 reconstructLagrangianFields<scalar>
580 reconstructLagrangianFields<vector>
587 reconstructLagrangianFields<sphericalTensor>
594 reconstructLagrangianFields<symmTensor>
601 reconstructLagrangianFields<tensor>
612 Info << "No lagrangian fields" << nl << endl;
616 // If there are any FA fields, reconstruct them
620 objects.lookupClass(areaScalarField::typeName).size()
621 || objects.lookupClass(areaVectorField::typeName).size()
622 || objects.lookupClass(areaSphericalTensorField::typeName).size()
623 || objects.lookupClass(areaSymmTensorField::typeName).size()
624 || objects.lookupClass(areaTensorField::typeName).size()
625 || objects.lookupClass(edgeScalarField::typeName).size()
628 Info << "Reconstructing FA fields" << nl << endl;
632 processorFaMeshes procFaMeshes(procMeshes.meshes());
634 faFieldReconstructor faReconstructor
637 procFaMeshes.meshes(),
638 procFaMeshes.edgeProcAddressing(),
639 procFaMeshes.faceProcAddressing(),
640 procFaMeshes.boundaryProcAddressing()
643 faReconstructor.reconstructFaAreaFields<scalar>(objects);
644 faReconstructor.reconstructFaAreaFields<vector>(objects);
646 .reconstructFaAreaFields<sphericalTensor>(objects);
647 faReconstructor.reconstructFaAreaFields<symmTensor>(objects);
648 faReconstructor.reconstructFaAreaFields<tensor>(objects);
650 faReconstructor.reconstructFaEdgeFields<scalar>(objects);
654 Info << "No FA fields" << nl << endl;
657 // If there are any "uniform" directories copy them from
658 // the master processor
660 fileName uniformDir0 = databases[0].timePath()/"uniform";
661 if (isDir(uniformDir0))
663 cp(uniformDir0, runTime.timePath());
667 Info<< "End.\n" << endl;
673 // ************************************************************************* //