1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM 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 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 Hrvoje Jasak, Wikki Ltd. All rights reserved
32 Reconstructs a mesh using geometrical matching and catenation.
33 Use following topological changes in parallel to create global mesh
34 and xxxxProcAddressing files in the processor meshes.
36 \*---------------------------------------------------------------------------*/
39 #include "processorMeshesReconstructor.H"
40 #include "fvFieldReconstructor.H"
41 #include "pointFieldReconstructor.H"
42 #include "tetPointFieldReconstructor.H"
43 #include "reconstructLagrangian.H"
47 #include "processorFaMeshes.H"
48 #include "faFieldReconstructor.H"
50 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52 int main(int argc, char *argv[])
54 // enable -constant ... if someone really wants it
55 // enable -zeroTime to prevent accidentally trashing the initial fields
56 timeSelector::addOptions(false, true);
57 argList::noParallel();
58 # include "addRegionOption.H"
59 argList::validOptions.insert("cellDist", "");
60 argList::validOptions.insert("fields", "\"(list of fields)\"");
61 argList::validOptions.insert("noLagrangian", "");
63 # include "setRootCase.H"
65 bool writeCellDist = args.optionFound("cellDist");
67 # include "createTime.H"
69 HashSet<word> selectedFields;
70 if (args.optionFound("fields"))
72 args.optionLookup("fields")() >> selectedFields;
75 bool noLagrangian = args.optionFound("noLagrangian");
77 // Determine the processor count directly
79 while (isDir(args.path()/(word("processor") + name(nProcs))))
86 FatalErrorIn(args.executable())
87 << "No processor* directories found"
91 // Create the processor databases
92 PtrList<Time> databases(nProcs);
94 forAll (databases, procI)
101 Time::controlDictName,
103 args.caseName()/fileName(word("processor") + name(procI))
108 // use the times list from the master processor
109 // and select a subset based on the command-line options
110 instantList timeDirs = timeSelector::select
112 databases[0].times(),
116 if (timeDirs.empty())
118 FatalErrorIn(args.executable())
119 << "No times selected"
123 Foam::word regionName = polyMesh::defaultRegion;
125 if (args.optionReadIfPresent("region", regionName))
127 Info<< "Selecting region " << regionName << " for time = "
128 << runTime.timeName() << Foam::nl << Foam::endl;
131 // Set all times on processor meshes equal to reconstructed mesh
132 forAll (databases, procI)
134 Info<< "Reading database for processor " << procI << endl;
136 databases[procI].setTime(runTime.timeName(), runTime.timeIndex());
139 // Read all meshes and addressing to reconstructed mesh
140 processorMeshesReconstructor procMeshes(databases, regionName);
142 autoPtr<fvMesh> meshPtr = procMeshes.reconstructMesh(runTime);
145 // Mesh write will be controlled by hand
147 procMeshes.writeAddressing();
148 meshPtr->setMotionWriteOpt(IOobject::NO_WRITE);
149 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
151 // Write cell decomposition
154 // Write as volScalarField for post-processing
155 Info<< "Writing cellDist to time " << runTime.timeName()
157 volScalarField cellDist
168 dimensionedScalar("cellDist", dimless, 0),
169 zeroGradientFvPatchScalarField::typeName
171 scalarField& cellDistIn = cellDist.internalField();
175 forAll (procMeshes.meshes(), procI)
180 i < procMeshes.meshes()[procI].nCells();
184 cellDistIn[cellI] = procI;
192 // Get region prefix for lagrangian
193 fileName regionPrefix = "";
194 if (regionName != fvMesh::defaultRegion)
196 regionPrefix = regionName;
200 // Loop over all times
201 forAll (timeDirs, timeI)
203 // Set time for global database
204 runTime.setTime(timeDirs[timeI], timeI);
206 Info << "Time = " << runTime.timeName() << endl << endl;
208 // Set time for all databases
209 forAll (databases, procI)
211 databases[procI].setTime(timeDirs[timeI], timeI);
214 polyMesh::readUpdateState procStat = procMeshes.readUpdate();
216 if (procStat == polyMesh::UNCHANGED)
218 Info<< "Mesh unchanged" << endl;
220 meshPtr->setMotionWriteOpt(IOobject::NO_WRITE);
221 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
223 else if (procStat == polyMesh::POINTS_MOVED)
225 Info<< "Mesh motion detected. Reconstruct motion points"
228 // Reconstruct the points for moving mesh cases and write them out
229 procMeshes.reconstructPoints(meshPtr());
232 meshPtr->setMotionWriteOpt(IOobject::AUTO_WRITE);
233 meshPtr->setTopoWriteOpt(IOobject::NO_WRITE);
240 procStat == polyMesh::TOPO_CHANGE
241 || procStat == polyMesh::TOPO_PATCH_CHANGE
244 Info<< "Topological change detected. Reconstructing mesh"
248 meshPtr = procMeshes.reconstructMesh(runTime);
251 meshPtr->setMotionWriteOpt(IOobject::AUTO_WRITE);
252 meshPtr->setTopoWriteOpt(IOobject::AUTO_WRITE);
253 procMeshes.writeAddressing();
258 // Write out mapping in processor directories
259 forAll (databases, procI)
261 databases[procI].write();
266 // Write as volScalarField for post-processing
267 Info<< "Writing cellDist to time " << runTime.timeName()
269 volScalarField cellDist
280 dimensionedScalar("cellDist", dimless, 0),
281 zeroGradientFvPatchScalarField::typeName
283 scalarField& cellDistIn = cellDist.internalField();
287 forAll (procMeshes.meshes(), procI)
292 i < procMeshes.meshes()[procI].nCells();
296 cellDistIn[cellI] = procI;
306 FatalErrorIn(args.executable())
307 << "Unknown readUpdate state"
308 << abort(FatalError);
311 fvMesh& mesh = meshPtr();
313 // Get list of objects from processor0 database
314 IOobjectList objects(procMeshes.meshes()[0], databases[0].timeName());
317 // If there are any FV fields, reconstruct them
321 objects.lookupClass(volScalarField::typeName).size()
322 || objects.lookupClass(volVectorField::typeName).size()
323 || objects.lookupClass(volSphericalTensorField::typeName).size()
324 || objects.lookupClass(volSymmTensorField::typeName).size()
325 || objects.lookupClass(volTensorField::typeName).size()
326 || objects.lookupClass(surfaceScalarField::typeName).size()
327 || objects.lookupClass(surfaceVectorField::typeName).size()
328 || objects.lookupClass(surfaceSphericalTensorField::typeName).size()
329 || objects.lookupClass(surfaceSymmTensorField::typeName).size()
330 || objects.lookupClass(surfaceTensorField::typeName).size()
333 Info << "Reconstructing FV fields" << nl << endl;
335 fvFieldReconstructor fvReconstructor
339 procMeshes.faceProcAddressing(),
340 procMeshes.cellProcAddressing(),
341 procMeshes.boundaryProcAddressing()
344 fvReconstructor.reconstructFvVolumeFields<scalar>
349 fvReconstructor.reconstructFvVolumeFields<vector>
354 fvReconstructor.reconstructFvVolumeFields<sphericalTensor>
359 fvReconstructor.reconstructFvVolumeFields<symmTensor>
364 fvReconstructor.reconstructFvVolumeFields<tensor>
370 fvReconstructor.reconstructFvSurfaceFields<scalar>
375 fvReconstructor.reconstructFvSurfaceFields<vector>
380 fvReconstructor.reconstructFvSurfaceFields<sphericalTensor>
385 fvReconstructor.reconstructFvSurfaceFields<symmTensor>
390 fvReconstructor.reconstructFvSurfaceFields<tensor>
398 Info << "No FV fields" << nl << endl;
402 // If there are any point fields, reconstruct them
405 objects.lookupClass(pointScalarField::typeName).size()
406 || objects.lookupClass(pointVectorField::typeName).size()
407 || objects.lookupClass(pointSphericalTensorField::typeName).size()
408 || objects.lookupClass(pointSymmTensorField::typeName).size()
409 || objects.lookupClass(pointTensorField::typeName).size()
412 Info << "Reconstructing point fields" << nl << endl;
414 pointMesh pMesh(mesh);
415 PtrList<pointMesh> pMeshes(procMeshes.meshes().size());
417 forAll (pMeshes, procI)
419 pMeshes.set(procI, new pointMesh(procMeshes.meshes()[procI]));
422 pointFieldReconstructor pointReconstructor
426 procMeshes.pointProcAddressing(),
427 procMeshes.boundaryProcAddressing()
430 pointReconstructor.reconstructFields<scalar>(objects);
431 pointReconstructor.reconstructFields<vector>(objects);
432 pointReconstructor.reconstructFields<sphericalTensor>(objects);
433 pointReconstructor.reconstructFields<symmTensor>(objects);
434 pointReconstructor.reconstructFields<tensor>(objects);
438 Info << "No point fields" << nl << endl;
441 // If there are any tetFem fields, reconstruct them
444 objects.lookupClass(tetPointScalarField::typeName).size()
445 || objects.lookupClass(tetPointVectorField::typeName).size()
446 || objects.lookupClass(tetPointSphericalTensorField::typeName).size()
447 || objects.lookupClass(tetPointSymmTensorField::typeName).size()
448 || objects.lookupClass(tetPointTensorField::typeName).size()
450 || objects.lookupClass(elementScalarField::typeName).size()
451 || objects.lookupClass(elementVectorField::typeName).size()
454 Info << "Reconstructing tet point fields" << nl << endl;
456 tetPolyMesh tetMesh(mesh);
457 PtrList<tetPolyMesh> tetMeshes(procMeshes.meshes().size());
459 forAll (tetMeshes, procI)
464 new tetPolyMesh(procMeshes.meshes()[procI])
468 tetPointFieldReconstructor tetPointReconstructor
472 procMeshes.pointProcAddressing(),
473 procMeshes.faceProcAddressing(),
474 procMeshes.cellProcAddressing(),
475 procMeshes.boundaryProcAddressing()
478 // Reconstruct tet point fields
479 tetPointReconstructor.reconstructTetPointFields<scalar>(objects);
480 tetPointReconstructor.reconstructTetPointFields<vector>(objects);
481 tetPointReconstructor.
482 reconstructTetPointFields<sphericalTensor>(objects);
483 tetPointReconstructor.
484 reconstructTetPointFields<symmTensor>(objects);
485 tetPointReconstructor.reconstructTetPointFields<tensor>(objects);
487 tetPointReconstructor.reconstructElementFields<scalar>(objects);
488 tetPointReconstructor.reconstructElementFields<vector>(objects);
492 Info << "No tetFem fields" << nl << endl;
496 // If there are any clouds, reconstruct them.
497 // The problem is that a cloud of size zero will not get written so
498 // in pass 1 we determine the cloud names and per cloud name the
499 // fields. Note that the fields are stored as IOobjectList from
500 // the first processor that has them. They are in pass2 only used
501 // for name and type (scalar, vector etc).
505 HashTable<IOobjectList> cloudObjects;
507 forAll (databases, procI)
509 fileNameList cloudDirs
513 databases[procI].timePath()/regionPrefix/cloud::prefix,
518 forAll (cloudDirs, i)
520 // Check if we already have cloud objects for
522 HashTable<IOobjectList>::const_iterator iter =
523 cloudObjects.find(cloudDirs[i]);
525 if (iter == cloudObjects.end())
527 // Do local scan for valid cloud objects
528 IOobjectList sprayObjs
530 procMeshes.meshes()[procI],
531 databases[procI].timeName(),
532 cloud::prefix/cloudDirs[i]
535 IOobject* positionsPtr = sprayObjs.lookup("positions");
539 cloudObjects.insert(cloudDirs[i], sprayObjs);
546 if (cloudObjects.size())
548 // Pass2: reconstruct the cloud
549 forAllConstIter(HashTable<IOobjectList>, cloudObjects, iter)
551 const word cloudName = string::validate<word>(iter.key());
553 // Objects (on arbitrary processor)
554 const IOobjectList& sprayObjs = iter();
556 Info<< "Reconstructing lagrangian fields for cloud "
557 << cloudName << nl << endl;
559 reconstructLagrangianPositions
564 procMeshes.faceProcAddressing(),
565 procMeshes.cellProcAddressing()
567 reconstructLagrangianFields<label>
574 reconstructLagrangianFields<scalar>
581 reconstructLagrangianFields<vector>
588 reconstructLagrangianFields<sphericalTensor>
595 reconstructLagrangianFields<symmTensor>
602 reconstructLagrangianFields<tensor>
613 Info << "No lagrangian fields" << nl << endl;
617 // If there are any FA fields, reconstruct them
621 objects.lookupClass(areaScalarField::typeName).size()
622 || objects.lookupClass(areaVectorField::typeName).size()
623 || objects.lookupClass(areaSphericalTensorField::typeName).size()
624 || objects.lookupClass(areaSymmTensorField::typeName).size()
625 || objects.lookupClass(areaTensorField::typeName).size()
626 || objects.lookupClass(edgeScalarField::typeName).size()
629 Info << "Reconstructing FA fields" << nl << endl;
633 processorFaMeshes procFaMeshes(procMeshes.meshes());
635 faFieldReconstructor faReconstructor
638 procFaMeshes.meshes(),
639 procFaMeshes.edgeProcAddressing(),
640 procFaMeshes.faceProcAddressing(),
641 procFaMeshes.boundaryProcAddressing()
644 faReconstructor.reconstructFaAreaFields<scalar>(objects);
645 faReconstructor.reconstructFaAreaFields<vector>(objects);
647 .reconstructFaAreaFields<sphericalTensor>(objects);
648 faReconstructor.reconstructFaAreaFields<symmTensor>(objects);
649 faReconstructor.reconstructFaAreaFields<tensor>(objects);
651 faReconstructor.reconstructFaEdgeFields<scalar>(objects);
655 Info << "No FA fields" << nl << endl;
658 // If there are any "uniform" directories copy them from
659 // the master processor
661 fileName uniformDir0 = databases[0].timePath()/"uniform";
662 if (isDir(uniformDir0))
664 cp(uniformDir0, runTime.timePath());
668 Info<< "End.\n" << endl;
674 // ************************************************************************* //