Merge branch 'master' of /home/dm4/OpenFOAM/OpenFOAM-dev

This commit is contained in:
andy
2012-04-10 14:25:23 +01:00
149 changed files with 5782 additions and 9176 deletions

View File

@ -0,0 +1,9 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
set -x
wclean
wclean rhoPorousMRFSimpleFoam
wclean rhoSimplecFoam
# ----------------------------------------------------------------- end-of-file

View File

@ -4,5 +4,6 @@ set -x
wmake
wmake rhoPorousMRFSimpleFoam
wmake rhoSimplecFoam
# ----------------------------------------------------------------- end-of-file

View File

@ -3,6 +3,7 @@
tmp<fvVectorMatrix> UEqn
(
fvm::div(phi, U)
- fvm::Sp(fvc::div(phi), U)
+ turbulence->divDevRhoReff(U)
);

View File

@ -1,11 +1,13 @@
{
volScalarField K("K", 0.5*magSqr(U));
fvScalarMatrix hEqn
(
fvm::div(phi, h)
- fvm::Sp(fvc::div(phi), h)
- fvm::laplacian(turbulence->alphaEff(), h)
==
- fvc::div(phi, 0.5*magSqr(U), "div(phi,K)")
fvc::div(phi)*K - fvc::div(phi, K)
);
hEqn.relax();

View File

@ -28,7 +28,7 @@ if (simple.transonic())
);
// Relax the pressure equation to ensure diagonal-dominance
pEqn.relax(mesh.equationRelaxationFactor("pEqn"));
pEqn.relax();
pEqn.setReference(pRefCell, pRefValue);

View File

@ -1,5 +1,5 @@
EXE_INC = \
-I../rhoSimpleFoam \
-I.. \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/turbulenceModels \
-I$(LIB_SRC)/turbulenceModels/compressible/RAS/RASModel \

View File

@ -29,21 +29,17 @@ if (simple.transonic())
(
"phic",
fvc::interpolate(rho/AtU - rho/AU)*fvc::snGrad(p)*mesh.magSf()
+ phid*(fvc::interpolate(p) - fvc::interpolate(p, "UD"))
);
//refCast<mixedFvPatchScalarField>(p.boundaryField()[1]).refValue()
// = p.boundaryField()[1];
fvScalarMatrix pEqn
(
fvm::div(phid, p)
+ fvc::div(phic)
- fvm::Sp(fvc::div(phid), p)
+ fvc::div(phid)*p
- fvm::laplacian(rho/AtU, p)
);
//pEqn.relax();
// Relax the pressure equation to ensure diagonal-dominance
pEqn.relax();
pEqn.setReference(pRefCell, pRefValue);
@ -71,7 +67,6 @@ else
fvScalarMatrix pEqn
(
fvc::div(phiHbyA)
//- fvm::laplacian(rho/AU, p)
- fvm::laplacian(rho/AtU, p)
);

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License

View File

@ -310,14 +310,21 @@
Info << "dispersedPhase is " << dispersedPhase << endl;
scalar minInterfaceAlpha
scalar residualPhaseFraction
(
readScalar
(
interfacialProperties.lookup("minInterfaceAlpha")
interfacialProperties.lookup("residualPhaseFraction")
)
);
dimensionedScalar residualSlip
(
"residualSlip",
dimVelocity,
interfacialProperties.lookup("residualSlip")
);
kineticTheoryModel kineticTheory
(
phase1,

View File

@ -36,7 +36,7 @@ volScalarField heatTransferCoeff
{
volVectorField Ur(U1 - U2);
volScalarField magUr(mag(Ur));
volScalarField magUr(mag(Ur) + residualSlip);
if (dispersedPhase == "1")
{
@ -69,12 +69,9 @@ volScalarField heatTransferCoeff
<< exit(FatalError);
}
volScalarField alpha1Coeff
(
(alpha1 + minInterfaceAlpha)*(alpha2 + minInterfaceAlpha)
);
dragCoeff *= alpha1Coeff;
heatTransferCoeff *= alpha1Coeff;
volScalarField alphaCoeff(max(alpha1*alpha2, residualPhaseFraction));
dragCoeff *= alphaCoeff;
heatTransferCoeff *= alphaCoeff;
liftForce = Cl*(alpha1*rho1 + alpha2*rho2)*(Ur ^ fvc::curl(U));

View File

@ -32,7 +32,7 @@
dimensionedScalar rAUf("(1|A(U))", dimTime/rho.dimensions(), 1.0);
adjustPhi(phi, U, pcorr);
//adjustPhi(phi, U, pcorr);
while (pimple.correctNonOrthogonal())
{

View File

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

View File

@ -0,0 +1,5 @@
EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lmeshTools

View File

@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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-tetTetOverlap
Description
Overlap volume of two tets
\*---------------------------------------------------------------------------*/
#include "tetrahedron.H"
#include "OFstream.H"
#include "meshTools.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void writeOBJ
(
Ostream& os,
label& vertI,
const tetPoints& tet
)
{
forAll(tet, fp)
{
meshTools::writeOBJ(os, tet[fp]);
}
os << "l " << vertI+1 << ' ' << vertI+2 << nl
<< "l " << vertI+1 << ' ' << vertI+3 << nl
<< "l " << vertI+1 << ' ' << vertI+4 << nl
<< "l " << vertI+2 << ' ' << vertI+3 << nl
<< "l " << vertI+2 << ' ' << vertI+4 << nl
<< "l " << vertI+3 << ' ' << vertI+4 << nl;
vertI += 4;
}
int main(int argc, char *argv[])
{
tetPoints A
(
point(0, 0, 0),
point(1, 0, 0),
point(1, 1, 0),
point(1, 1, 1)
);
const tetPointRef tetA = A.tet();
tetPoints B
(
point(0.1, 0.1, 0.1),
point(1.1, 0.1, 0.1),
point(1.1, 1.1, 0.1),
point(1.1, 1.1, 1.1)
);
const tetPointRef tetB = B.tet();
tetPointRef::tetIntersectionList insideTets;
label nInside = 0;
tetPointRef::tetIntersectionList outsideTets;
label nOutside = 0;
tetA.tetOverlap
(
tetB,
insideTets,
nInside,
outsideTets,
nOutside
);
// Dump to file
// ~~~~~~~~~~~~
{
OFstream str("tetA.obj");
Info<< "Writing A to " << str.name() << endl;
label vertI = 0;
writeOBJ(str, vertI, A);
}
{
OFstream str("tetB.obj");
Info<< "Writing B to " << str.name() << endl;
label vertI = 0;
writeOBJ(str, vertI, B);
}
{
OFstream str("inside.obj");
Info<< "Writing parts of A inside B to " << str.name() << endl;
label vertI = 0;
for (label i = 0; i < nInside; ++i)
{
writeOBJ(str, vertI, insideTets[i]);
}
}
{
OFstream str("outside.obj");
Info<< "Writing parts of A outside B to " << str.name() << endl;
label vertI = 0;
for (label i = 0; i < nOutside; ++i)
{
writeOBJ(str, vertI, outsideTets[i]);
}
}
// Check
// ~~~~~
Info<< "Vol A:" << tetA.mag() << endl;
scalar volInside = 0;
for (label i = 0; i < nInside; ++i)
{
volInside += insideTets[i].tet().mag();
}
Info<< "Vol A inside B:" << volInside << endl;
scalar volOutside = 0;
for (label i = 0; i < nOutside; ++i)
{
volOutside += outsideTets[i].tet().mag();
}
Info<< "Vol A outside B:" << volOutside << endl;
Info<< "Sum inside and outside:" << volInside+volOutside << endl;
if (mag(volInside+volOutside-tetA.mag()) > SMALL)
{
FatalErrorIn("Test-tetetOverlap")
<< "Tet volumes do not sum up to input tet."
<< exit(FatalError);
}
return 0;
}
// ************************************************************************* //

View File

@ -4,5 +4,7 @@ set -x
wclean libso conformalVoronoiMesh
wclean
wclean cvMeshSurfaceSimplify
wclean cvMeshBackgroundMesh
# ----------------------------------------------------------------- end-of-file

View File

@ -4,6 +4,7 @@ set -x
wmake libso conformalVoronoiMesh
wmake
wmake cvMeshSurfaceSimplify
wmake cvMeshBackgroundMesh
(cd cvMeshSurfaceSimplify && ./Allwmake)
# ----------------------------------------------------------------- end-of-file

View File

@ -2,11 +2,15 @@ EXE_DEBUG = -DFULLDEBUG -g -O0
EXE_FROUNDING_MATH = -frounding-math
EXE_NDEBUG = -DNDEBUG
CGAL_EXACT =
CGAL_INEXACT = -DCGAL_INEXACT
include $(GENERAL_RULES)/CGAL
EXE_INC = \
${EXE_FROUNDING_MATH} \
${EXE_NDEBUG} \
${CGAL_INEXACT} \
${CGAL_INC} \
-IconformalVoronoiMesh/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \

View File

@ -2,12 +2,16 @@ EXE_DEBUG = -DFULLDEBUG -g -O0
EXE_FROUNDING_MATH = -frounding-math
EXE_NDEBUG = -DNDEBUG
CGAL_EXACT =
CGAL_INEXACT = -DCGAL_INEXACT
include $(GENERAL_RULES)/CGAL
FFLAGS = -DCGAL_FILES='"${CGAL_ARCH_PATH}/share/files"'
EXE_INC = \
${EXE_FROUNDING_MATH} \
${EXE_NDEBUG} \
${CGAL_INEXACT} \
${CGAL_INC} \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -142,7 +142,7 @@ void Foam::backgroundMeshDecomposition::initialRefinement()
zeroGradientFvPatchScalarField::typeName
);
const conformationSurfaces& geometry = cvMesh_.geometryToConformTo();
const conformationSurfaces& geometry = geometryToConformTo_;
decompositionMethod& decomposer = decomposerPtr_();
@ -512,7 +512,7 @@ bool Foam::backgroundMeshDecomposition::refineCell
// Sample the box to find an estimate of the min size, and a volume
// estimate when overlapping == true.
const conformationSurfaces& geometry = cvMesh_.geometryToConformTo();
const conformationSurfaces& geometry = geometryToConformTo_;
treeBoundBox cellBb
(
@ -578,7 +578,7 @@ bool Foam::backgroundMeshDecomposition::refineCell
forAll(samplePoints, i)
{
scalar s = cvMesh_.cellSizeControl().cellSize
scalar s = cellSizeControl_.cellSize
(
hitInfo[i].hitPoint()
);
@ -693,7 +693,7 @@ void Foam::backgroundMeshDecomposition::buildPatchAndTree()
// Overall bb
treeBoundBox overallBb(boundaryFacesPtr_().localPoints());
Random& rnd = cvMesh_.rndGen();
Random& rnd = rndGen_;
bFTreePtr_.reset
(
@ -726,11 +726,11 @@ void Foam::backgroundMeshDecomposition::buildPatchAndTree()
octreeNearestDistances_ = bFTreePtr_().calcNearestDistance();
if (cvMesh_.cvMeshControls().objOutput())
if (cvMeshControls_.objOutput())
{
OFstream fStr
(
cvMesh_.time().path()
mesh_.time().path()
/"backgroundMeshDecomposition_proc_"
+ name(Pstream::myProcNo())
+ "_boundaryFaces.obj"
@ -777,15 +777,18 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
const conformalVoronoiMesh& cvMesh
)
:
coeffsDict_(coeffsDict),
cvMesh_(cvMesh),
runTime_(cvMesh.time()),
geometryToConformTo_(cvMesh.geometryToConformTo()),
cellSizeControl_(cvMesh.cellSizeControl()),
rndGen_(cvMesh.rndGen()),
cvMeshControls_(cvMesh.cvMeshControls()),
mesh_
(
IOobject
(
fvMesh::defaultRegion,
cvMesh_.time().timeName(),
cvMesh_.time(),
runTime_.timeName(),
runTime_,
IOobject::MUST_READ
)
),
@ -805,22 +808,22 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
IOobject
(
"decomposeParDict",
cvMesh_.time().system(),
cvMesh_.time(),
runTime_.system(),
runTime_,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
),
decomposerPtr_(decompositionMethod::New(decomposeDict_)),
mergeDist_(1e-6*mesh_.bounds().mag()),
spanScale_(readScalar(coeffsDict_.lookup("spanScale"))),
spanScale_(readScalar(coeffsDict.lookup("spanScale"))),
minCellSizeLimit_
(
coeffsDict_.lookupOrDefault<scalar>("minCellSizeLimit", 0.0)
coeffsDict.lookupOrDefault<scalar>("minCellSizeLimit", 0.0)
),
minLevels_(readLabel(coeffsDict_.lookup("minLevels"))),
volRes_(readLabel(coeffsDict_.lookup("sampleResolution"))),
maxCellWeightCoeff_(readScalar(coeffsDict_.lookup("maxCellWeightCoeff")))
minLevels_(readLabel(coeffsDict.lookup("minLevels"))),
volRes_(readLabel(coeffsDict.lookup("sampleResolution"))),
maxCellWeightCoeff_(readScalar(coeffsDict.lookup("maxCellWeightCoeff")))
{
if (!Pstream::parRun())
{
@ -854,6 +857,74 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
}
Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
(
const scalar spanScale,
const scalar minCellSizeLimit,
const label minLevels,
const label volRes,
const scalar maxCellWeightCoeff,
const Time& runTime,
const conformationSurfaces& geometryToConformTo,
const cellSizeControlSurfaces& cellSizeControl,
Random& rndGen,
const cvControls& cvMeshControls
)
:
runTime_(runTime),
geometryToConformTo_(geometryToConformTo),
cellSizeControl_(cellSizeControl),
rndGen_(rndGen),
cvMeshControls_(cvMeshControls),
mesh_
(
IOobject
(
fvMesh::defaultRegion,
runTime_.timeName(),
runTime_,
IOobject::MUST_READ
)
),
meshCutter_
(
mesh_,
labelList(mesh_.nCells(), 0),
labelList(mesh_.nPoints(), 0)
),
boundaryFacesPtr_(),
bFTreePtr_(),
octreeNearestDistances_(),
allBackgroundMeshBounds_(Pstream::nProcs()),
globalBackgroundBounds_(),
decomposeDict_
(
IOobject
(
"decomposeParDict",
runTime_.system(),
runTime_,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
),
decomposerPtr_(decompositionMethod::New(decomposeDict_)),
mergeDist_(1e-6*mesh_.bounds().mag()),
spanScale_(spanScale),
minCellSizeLimit_(minCellSizeLimit),
minLevels_(minLevels),
volRes_(volRes),
maxCellWeightCoeff_(maxCellWeightCoeff)
{
// Stand-alone operation
Info<< nl << "Building initial background mesh decomposition" << endl;
initialRefinement();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::backgroundMeshDecomposition::~backgroundMeshDecomposition()

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -92,10 +92,22 @@ class backgroundMeshDecomposition
// Private data
//- Method details dictionary
dictionary coeffsDict_;
//dictionary coeffsDict_;
//- Reference to the conformalVoronoiMesh holding this object
const conformalVoronoiMesh& cvMesh_;
//- Reference to runtime
const Time& runTime_;
//- Reference to surface
const conformationSurfaces& geometryToConformTo_;
//- The cell size control object
const cellSizeControlSurfaces& cellSizeControl_;
//- Random number generator
Random& rndGen_;
//- Controls
const cvControls& cvMeshControls_;
//- Mesh stored on for this processor, specifiying the domain that it
// is responsible for.
@ -191,13 +203,29 @@ public:
// Constructors
//- Construct from components
//- Construct from components in cvMesh operation
backgroundMeshDecomposition
(
const dictionary& coeffsDict,
const conformalVoronoiMesh& cvMesh
);
//- Construct from components for standalone operation
backgroundMeshDecomposition
(
const scalar spanScale,
const scalar minCellSizeLimit,
const label minLevels,
const label volRes,
const scalar maxCellWeightCoeff,
const Time& runTime,
const conformationSurfaces& geometryToConformTo,
const cellSizeControlSurfaces& cellSizeControl,
Random& rndGen,
const cvControls& cvMeshControls
);
//- Destructor
~backgroundMeshDecomposition();
@ -299,6 +327,15 @@ public:
//- Return the boundBox of this processor
inline const treeBoundBox& procBounds() const;
//- Return the cell level of the underlying mesh
inline const labelList& cellLevel() const;
//- Return the point level of the underlying mesh
inline const labelList& pointLevel() const;
//- Return the current decomposition method
inline const decompositionMethod& decomposer() const;
};

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -43,9 +43,30 @@ Foam::backgroundMeshDecomposition::octreeNearestDistances() const
}
const Foam::treeBoundBox& Foam::backgroundMeshDecomposition::procBounds() const
const Foam::treeBoundBox&
Foam::backgroundMeshDecomposition::procBounds() const
{
return allBackgroundMeshBounds_[Pstream::myProcNo()];
}
const Foam::labelList& Foam::backgroundMeshDecomposition::cellLevel() const
{
return meshCutter_.cellLevel();
}
const Foam::labelList& Foam::backgroundMeshDecomposition::pointLevel() const
{
return meshCutter_.pointLevel();
}
const Foam::decompositionMethod&
Foam::backgroundMeshDecomposition::decomposer() const
{
return decomposerPtr_();
}
// ************************************************************************* //

View File

@ -249,6 +249,7 @@ Foam::conformationSurfaces::conformationSurfaces
Info<< endl
<< "Testing for locationInMesh " << locationInMesh_ << endl;
forAll(surfaces_, s)
{
const searchableSurface& surface(allGeometry_[surfaces_[s]]);
@ -267,7 +268,6 @@ Foam::conformationSurfaces::conformationSurfaces
referenceVolumeTypes_[s] = vTypes[0];
Info<< " is "
<< searchableSurface::volumeTypeNames[referenceVolumeTypes_[s]]
<< " surface " << surface.name()

View File

@ -303,6 +303,9 @@ public:
//- Find which patch is closest to the point
label findPatch(const point& pt) const;
//- Is the surface a baffle
inline bool isBaffle(const label index) const;
// Write

View File

@ -62,4 +62,10 @@ const Foam::treeBoundBox& Foam::conformationSurfaces::globalBounds() const
}
bool Foam::conformationSurfaces::isBaffle(const label index) const
{
return baffleSurfaces_[index];
}
// ************************************************************************* //

View File

@ -61,7 +61,7 @@ Foam::cvControls::cvControls
specialiseFeaturePoints_ = Switch
(
surfDict.lookupOrDefault<Switch>("specialiseFeaturePoints", false)
surfDict.lookup("specialiseFeaturePoints")
);
surfaceSearchDistanceCoeff_ = readScalar

View File

@ -0,0 +1,3 @@
cvMeshBackgroundMesh.C
EXE = $(FOAM_APPBIN)/cvMeshBackgroundMesh

View File

@ -0,0 +1,29 @@
EXE_DEBUG = -DFULLDEBUG -g -O0
EXE_FROUNDING_MATH = -frounding-math
EXE_NDEBUG = -DNDEBUG
include $(GENERAL_RULES)/CGAL
EXE_INC = \
${EXE_FROUNDING_MATH} \
${EXE_NDEBUG} \
${CGAL_INC} \
-I../conformalVoronoiMesh/lnInclude \
-I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
-I$(LIB_SRC)/edgeMesh/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude
EXE_LIBS = \
$(CGAL_LIBS) \
-lconformalVoronoiMesh \
-ldecompositionMethods /* -L$(FOAM_LIBBIN)/dummy -lscotchDecomp */ \
-ledgeMesh \
-lsampling \
-ltriSurface \
-lmeshTools \
-ldynamicMesh \
-lfiniteVolume

View File

@ -0,0 +1,770 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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
cvMeshBackGroundMesh
Description
Writes out background mesh as constructed by cvMesh and constructs
distanceSurface.
\*---------------------------------------------------------------------------*/
#include "PatchTools.H"
#include "argList.H"
#include "Time.H"
#include "triSurface.H"
#include "searchableSurfaces.H"
#include "conformationSurfaces.H"
#include "cellSizeControlSurfaces.H"
#include "backgroundMeshDecomposition.H"
#include "cellShape.H"
#include "cellModeller.H"
#include "DynamicField.H"
#include "isoSurfaceCell.H"
#include "vtkSurfaceWriter.H"
#include "syncTools.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Tolerance (as fraction of the bounding box). Needs to be fairly lax since
// usually meshes get written with limited precision (6 digits)
static const scalar defaultMergeTol = 1E-6;
// Get merging distance when matching face centres
scalar getMergeDistance
(
const argList& args,
const Time& runTime,
const boundBox& bb
)
{
scalar mergeTol = defaultMergeTol;
args.optionReadIfPresent("mergeTol", mergeTol);
scalar writeTol =
Foam::pow(scalar(10.0), -scalar(IOstream::defaultPrecision()));
Info<< "Merge tolerance : " << mergeTol << nl
<< "Write tolerance : " << writeTol << endl;
if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
{
FatalErrorIn("getMergeDistance")
<< "Your current settings specify ASCII writing with "
<< IOstream::defaultPrecision() << " digits precision." << endl
<< "Your merging tolerance (" << mergeTol << ") is finer than this."
<< endl
<< "Please change your writeFormat to binary"
<< " or increase the writePrecision" << endl
<< "or adjust the merge tolerance (-mergeTol)."
<< exit(FatalError);
}
scalar mergeDist = mergeTol * bb.mag();
Info<< "Overall meshes bounding box : " << bb << nl
<< "Relative tolerance : " << mergeTol << nl
<< "Absolute matching distance : " << mergeDist << nl
<< endl;
return mergeDist;
}
void printMeshData(const polyMesh& mesh)
{
// Collect all data on master
globalIndex globalCells(mesh.nCells());
labelListList patchNeiProcNo(Pstream::nProcs());
labelListList patchSize(Pstream::nProcs());
const labelList& pPatches = mesh.globalData().processorPatches();
patchNeiProcNo[Pstream::myProcNo()].setSize(pPatches.size());
patchSize[Pstream::myProcNo()].setSize(pPatches.size());
forAll(pPatches, i)
{
const processorPolyPatch& ppp = refCast<const processorPolyPatch>
(
mesh.boundaryMesh()[pPatches[i]]
);
patchNeiProcNo[Pstream::myProcNo()][i] = ppp.neighbProcNo();
patchSize[Pstream::myProcNo()][i] = ppp.size();
}
Pstream::gatherList(patchNeiProcNo);
Pstream::gatherList(patchSize);
// Print stats
globalIndex globalBoundaryFaces(mesh.nFaces()-mesh.nInternalFaces());
label maxProcCells = 0;
label totProcFaces = 0;
label maxProcPatches = 0;
label totProcPatches = 0;
label maxProcFaces = 0;
for (label procI = 0; procI < Pstream::nProcs(); procI++)
{
Info<< endl
<< "Processor " << procI << nl
<< " Number of cells = " << globalCells.localSize(procI)
<< endl;
label nProcFaces = 0;
const labelList& nei = patchNeiProcNo[procI];
forAll(patchNeiProcNo[procI], i)
{
Info<< " Number of faces shared with processor "
<< patchNeiProcNo[procI][i] << " = " << patchSize[procI][i]
<< endl;
nProcFaces += patchSize[procI][i];
}
Info<< " Number of processor patches = " << nei.size() << nl
<< " Number of processor faces = " << nProcFaces << nl
<< " Number of boundary faces = "
<< globalBoundaryFaces.localSize(procI) << endl;
maxProcCells = max(maxProcCells, globalCells.localSize(procI));
totProcFaces += nProcFaces;
totProcPatches += nei.size();
maxProcPatches = max(maxProcPatches, nei.size());
maxProcFaces = max(maxProcFaces, nProcFaces);
}
// Stats
scalar avgProcCells = scalar(globalCells.size())/Pstream::nProcs();
scalar avgProcPatches = scalar(totProcPatches)/Pstream::nProcs();
scalar avgProcFaces = scalar(totProcFaces)/Pstream::nProcs();
// In case of all faces on one processor. Just to avoid division by 0.
if (totProcPatches == 0)
{
avgProcPatches = 1;
}
if (totProcFaces == 0)
{
avgProcFaces = 1;
}
Info<< nl
<< "Number of processor faces = " << totProcFaces/2 << nl
<< "Max number of cells = " << maxProcCells
<< " (" << 100.0*(maxProcCells-avgProcCells)/avgProcCells
<< "% above average " << avgProcCells << ")" << nl
<< "Max number of processor patches = " << maxProcPatches
<< " (" << 100.0*(maxProcPatches-avgProcPatches)/avgProcPatches
<< "% above average " << avgProcPatches << ")" << nl
<< "Max number of faces between processors = " << maxProcFaces
<< " (" << 100.0*(maxProcFaces-avgProcFaces)/avgProcFaces
<< "% above average " << avgProcFaces << ")" << nl
<< endl;
}
// Return cellID
label cellLabel
(
const Vector<label>& nCells,
const label i,
const label j,
const label k
)
{
return i*nCells[1]*nCells[2]+j*nCells[2]+k;
}
label vtxLabel
(
const Vector<label>& nCells,
const label i,
const label j,
const label k
)
{
Vector<label> nPoints
(
nCells[0]+1,
nCells[1]+1,
nCells[2]+1
);
return i*nPoints[1]*nPoints[2]+j*nPoints[2]+k;
}
autoPtr<polyMesh> generateHexMesh
(
const IOobject& io,
const point& origin,
const vector& cellSize,
const Vector<label>& nCells
)
{
pointField points;
if (nCells[0]+nCells[1]+nCells[2] > 0)
{
points.setSize((nCells[0]+1)*(nCells[1]+1)*(nCells[2]+1));
// Generate points
for (label i = 0; i <= nCells[0]; i++)
{
for (label j = 0; j <= nCells[1]; j++)
{
for (label k = 0; k <= nCells[2]; k++)
{
point pt = origin;
pt.x() += i*cellSize[0];
pt.y() += j*cellSize[1];
pt.z() += k*cellSize[2];
points[vtxLabel(nCells, i, j, k)] = pt;
}
}
}
}
const cellModel& hex = *(cellModeller::lookup("hex"));
cellShapeList cellShapes(nCells[0]*nCells[1]*nCells[2]);
labelList hexPoints(8);
label cellI = 0;
for (label i = 0; i < nCells[0]; i++)
{
for (label j = 0; j < nCells[1]; j++)
{
for (label k = 0; k < nCells[2]; k++)
{
hexPoints[0] = vtxLabel(nCells, i, j, k);
hexPoints[1] = vtxLabel(nCells, i+1, j, k);
hexPoints[2] = vtxLabel(nCells, i+1, j+1, k);
hexPoints[3] = vtxLabel(nCells, i, j+1, k);
hexPoints[4] = vtxLabel(nCells, i, j, k+1);
hexPoints[5] = vtxLabel(nCells, i+1, j, k+1);
hexPoints[6] = vtxLabel(nCells, i+1, j+1, k+1);
hexPoints[7] = vtxLabel(nCells, i, j+1, k+1);
cellShapes[cellI++] = cellShape(hex, hexPoints);
}
}
}
faceListList boundary(0);
wordList patchNames(0);
wordList patchTypes(0);
word defaultFacesName = "defaultFaces";
word defaultFacesType = polyPatch::typeName;
wordList patchPhysicalTypes(0);
return autoPtr<polyMesh>
(
new polyMesh
(
io,
xferMoveTo<pointField>(points),
cellShapes,
boundary,
patchNames,
patchTypes,
defaultFacesName,
defaultFacesType,
patchPhysicalTypes
)
);
}
// Determine for every point a signed distance to the nearest surface
// (outside is positive)
tmp<scalarField> signedDistance
(
const scalarField& distSqr,
const pointField& points,
const searchableSurfaces& geometry,
const labelList& surfaces
)
{
tmp<scalarField> tfld(new scalarField(points.size(), Foam::sqr(GREAT)));
scalarField& fld = tfld();
// Find nearest
List<pointIndexHit> nearest;
labelList nearestSurfaces;
searchableSurfacesQueries::findNearest
(
geometry,
surfaces,
points,
scalarField(points.size(), Foam::sqr(GREAT)),//distSqr
nearestSurfaces,
nearest
);
// Determine sign of nearest. Sort by surface to do this.
DynamicField<point> surfPoints(points.size());
DynamicList<label> surfIndices(points.size());
forAll(surfaces, surfI)
{
// Extract points on this surface
surfPoints.clear();
surfIndices.clear();
forAll(nearestSurfaces, i)
{
if (nearestSurfaces[i] == surfI)
{
surfPoints.append(points[i]);
surfIndices.append(i);
}
}
// Calculate sideness of these surface points
label geomI = surfaces[surfI];
List<searchableSurface::volumeType> volType;
geometry[geomI].getVolumeType(surfPoints, volType);
// Push back to original
forAll(volType, i)
{
label pointI = surfIndices[i];
scalar dist = mag(points[pointI] - nearest[pointI].hitPoint());
searchableSurface::volumeType vT = volType[i];
if (vT == searchableSurface::OUTSIDE)
{
fld[pointI] = dist;
}
else if (vT == searchableSurface::INSIDE)
{
fld[i] = -dist;
}
else
{
FatalErrorIn("signedDistance()")
<< "getVolumeType failure, neither INSIDE or OUTSIDE"
<< exit(FatalError);
}
}
}
return tfld;
}
// Main program:
int main(int argc, char *argv[])
{
argList::addNote
(
"Generate cvMesh-consistent representation of surfaces"
);
argList::addBoolOption
(
"writeMesh",
"write the resulting mesh and distance fields"
);
argList::addOption
(
"mergeTol",
"scalar",
"specify the merge distance relative to the bounding box size "
"(default 1E-6)"
);
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
const bool writeMesh = args.optionFound("writeMesh");
if (writeMesh)
{
Info<< "Writing resulting mesh and cellDistance, pointDistance fields."
<< nl << endl;
}
IOdictionary cvMeshDict
(
IOobject
(
"cvMeshDict",
runTime.system(),
runTime,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
// Define/load all geometry
searchableSurfaces allGeometry
(
IOobject
(
"cvSearchableSurfaces",
runTime.constant(),
"triSurface",
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE
),
cvMeshDict.subDict("geometry")
);
Random rndGen(64293*Pstream::myProcNo());
conformationSurfaces geometryToConformTo
(
runTime,
rndGen,
allGeometry,
cvMeshDict.subDict("surfaceConformation")
);
cellSizeControlSurfaces cellSizeControl
(
allGeometry,
cvMeshDict.subDict("motionControl")
);
// Generate starting block mesh
vector cellSize;
{
const treeBoundBox& bb = geometryToConformTo.globalBounds();
// Determine the number of cells in each direction.
const vector span = bb.span();
vector nScalarCells = span/cellSizeControl.defaultCellSize();
// Calculate initial cell size to be a little bit smaller than the
// defaultCellSize to avoid initial refinement triggering.
Vector<label> nCells = Vector<label>
(
label(nScalarCells.x())+2,
label(nScalarCells.y())+2,
label(nScalarCells.z())+2
);
cellSize = vector
(
span[0]/nCells[0],
span[1]/nCells[1],
span[2]/nCells[2]
);
Info<< "Generating initial hex mesh with" << nl
<< " bounding box : " << bb << nl
<< " nCells : " << nCells << nl
<< " cellSize : " << cellSize << nl
<< endl;
autoPtr<polyMesh> meshPtr
(
generateHexMesh
(
IOobject
(
polyMesh::defaultRegion,
runTime.constant(),
runTime
),
bb.min(),
cellSize,
(
Pstream::master()
? nCells
: Vector<label>(0, 0, 0)
)
)
);
Info<< "Writing initial hex mesh to " << meshPtr().instance() << nl
<< endl;
meshPtr().write();
}
// Distribute the initial mesh
if (Pstream::parRun())
{
# include "createMesh.H"
Info<< "Loaded mesh:" << endl;
printMeshData(mesh);
// Allocate a decomposer
IOdictionary decompositionDict
(
IOobject
(
"decomposeParDict",
runTime.system(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
autoPtr<decompositionMethod> decomposer
(
decompositionMethod::New
(
decompositionDict
)
);
labelList decomp = decomposer().decompose(mesh, mesh.cellCentres());
// Global matching tolerance
const scalar tolDim = getMergeDistance
(
args,
runTime,
mesh.bounds()
);
// Mesh distribution engine
fvMeshDistribute distributor(mesh, tolDim);
Info<< "Wanted distribution:"
<< distributor.countCells(decomp) << nl << endl;
// Do actual sending/receiving of mesh
autoPtr<mapDistributePolyMesh> map = distributor.distribute(decomp);
// Print some statistics
//Info<< "After distribution:" << endl;
//printMeshData(mesh);
mesh.setInstance(runTime.constant());
Info<< "Writing redistributed mesh" << nl << endl;
mesh.write();
}
Info<< "Refining backgroud mesh according to cell size specification" << nl
<< endl;
backgroundMeshDecomposition backgroundMesh
(
1.0, //spanScale,ratio of poly cell size v.s. hex cell size
0.0, //minCellSizeLimit
0, //minLevels
4, //volRes, check multiple points per cell
20.0, //maxCellWeightCoeff
runTime,
geometryToConformTo,
cellSizeControl,
rndGen,
cvMeshDict
);
if (writeMesh)
{
runTime++;
Info<< "Writing mesh to " << runTime.timeName() << endl;
backgroundMesh.mesh().write();
}
const scalar tolDim = getMergeDistance
(
args,
runTime,
backgroundMesh.mesh().bounds()
);
faceList isoFaces;
pointField isoPoints;
{
// Apply a distanceSurface to it.
const fvMesh& fvm = backgroundMesh.mesh();
volScalarField cellDistance
(
IOobject
(
"cellDistance",
fvm.time().timeName(),
fvm.time(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
fvm,
dimensionedScalar("zero", dimLength, 0)
);
const searchableSurfaces& geometry = geometryToConformTo.geometry();
const labelList& surfaces = geometryToConformTo.surfaces();
// Get maximum search size per cell
scalarField distSqr(cellDistance.size());
const labelList& cellLevel = backgroundMesh.cellLevel();
forAll(cellLevel, cellI)
{
// The largest edge of the cell will always be less than the
// span of the bounding box of the cell.
distSqr[cellI] = magSqr(cellSize)/pow(2, cellLevel[cellI]);
}
{
// Internal field
cellDistance.internalField() = signedDistance
(
distSqr,
fvm.C(),
geometry,
surfaces
);
// Patch fields
forAll(fvm.C().boundaryField(), patchI)
{
const pointField& cc = fvm.C().boundaryField()[patchI];
fvPatchScalarField& fld = cellDistance.boundaryField()[patchI];
scalarField patchDistSqr
(
fld.patch().patchInternalField(distSqr)
);
fld = signedDistance(patchDistSqr, cc, geometry, surfaces);
}
// On processor patches the fvm.C() will already be the cell centre
// on the opposite side so no need to swap cellDistance.
if (writeMesh)
{
cellDistance.write();
}
}
// Distance to points
pointScalarField pointDistance
(
IOobject
(
"pointDistance",
fvm.time().timeName(),
fvm.time(),
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
pointMesh::New(fvm),
dimensionedScalar("zero", dimLength, 0)
);
{
scalarField pointDistSqr(fvm.nPoints(), -sqr(GREAT));
for (label faceI = 0; faceI < fvm.nInternalFaces(); faceI++)
{
label own = fvm.faceOwner()[faceI];
label ownDistSqr = distSqr[own];
const face& f = fvm.faces()[faceI];
forAll(f, fp)
{
pointDistSqr[f[fp]] = max(pointDistSqr[f[fp]], ownDistSqr);
}
}
syncTools::syncPointList
(
fvm,
pointDistSqr,
maxEqOp<scalar>(),
-sqr(GREAT) // null value
);
pointDistance.internalField() = signedDistance
(
pointDistSqr,
fvm.points(),
geometry,
surfaces
);
if (writeMesh)
{
pointDistance.write();
}
}
isoSurfaceCell iso
(
fvm,
cellDistance,
pointDistance,
0, //distance,
false //regularise
);
isoFaces.setSize(iso.size());
forAll(isoFaces, i)
{
isoFaces[i] = iso[i].triFaceFace();
}
isoPoints = iso.points();
}
pointField mergedPoints;
faceList mergedFaces;
labelList pointMergeMap;
PatchTools::gatherAndMerge
(
tolDim,
primitivePatch
(
SubList<face>(isoFaces, isoFaces.size()),
isoPoints
),
mergedPoints,
mergedFaces,
pointMergeMap
);
vtkSurfaceWriter writer;
writer.write
(
runTime.path(),
"iso",
mergedPoints,
mergedFaces
);
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,10 @@
#!/bin/sh
cd ${0%/*} || exit 1 # run from this directory
set -x
if [ -d "${FASTDUALOCTREE_SRC_PATH}" ]
then
wmake
fi
# ----------------------------------------------------------------- end-of-file

View File

@ -1,6 +1,22 @@
cvMeshSurfaceSimplify.C
/*
cvMeshSurfaceSimplify_non_octree.C
MarchingCubes/MarchingCubes.cpp
MarchingCubes/ply.c
*/
/*
MarchingCubes = fastdualoctree_sgp
$(MarchingCubes)/data_access.cpp
$(MarchingCubes)/fparser.cpp
$(MarchingCubes)/fpoptimizer.cpp
$(MarchingCubes)/MarchingCubes.cpp
$(MarchingCubes)/mc_draw.cpp
$(MarchingCubes)/morton.cpp
$(MarchingCubes)/opt_octree.cpp
$(MarchingCubes)/hash_octree.cpp
*/
cvMeshSurfaceSimplify.C
EXE = $(FOAM_APPBIN)/cvMeshSurfaceSimplify

View File

@ -1,7 +1,12 @@
MarchingCubes = fastdualoctree_sgp
include $(GENERAL_RULES)/CGAL
EXE_INC = \
-IMarchingCubes \
-DUNIX \
-Wno-old-style-cast \
/* -IMarchingCubes */ \
-I$(FASTDUALOCTREE_SRC_PATH) \
-I../conformalVoronoiMesh/lnInclude \
-I$(LIB_SRC)/edgeMesh/lnInclude \
-I$(LIB_SRC)/triSurface/lnInclude \
@ -9,6 +14,8 @@ EXE_INC = \
EXE_LIBS = \
$(CGAL_LIBS) \
-L$(FASTDUALOCTREE_SRC_PATH) -lperf_main \
-lGL \
-lconformalVoronoiMesh \
-ldecompositionMethods -L$(FOAM_LIBBIN)/dummy -lscotchDecomp \
-ledgeMesh \

View File

@ -1,343 +0,0 @@
/**
* @file MarchingCubes.h
* @author Thomas Lewiner <thomas.lewiner@polytechnique.org>
* @author Math Dept, PUC-Rio
* @version 0.2
* @date 12/08/2002
*
* @brief MarchingCubes Algorithm
*/
//________________________________________________
#ifndef _MARCHINGCUBES_H_
#define _MARCHINGCUBES_H_
#if !defined(WIN32) || defined(__CYGWIN__)
#pragma interface
#endif // WIN32
//_____________________________________________________________________________
// types
/** unsigned char alias */
typedef unsigned char uchar ;
/** signed char alias */
typedef signed char schar ;
/** isovalue alias */
typedef float real ;
//-----------------------------------------------------------------------------
// Vertex structure
/** \struct Vertex "MarchingCubes.h" MarchingCubes
* Position and normal of a vertex
* \brief vertex structure
* \param x X coordinate
* \param y Y coordinate
* \param z Z coordinate
* \param nx X component of the normal
* \param ny Y component of the normal
* \param nz Z component of the normal
*/
typedef struct
{
real x, y, z ; /**< Vertex coordinates */
real nx, ny, nz ; /**< Vertex normal */
} Vertex ;
//-----------------------------------------------------------------------------
// Triangle structure
/** \struct Triangle "MarchingCubes.h" MarchingCubes
* Indices of the oriented triange vertices
* \brief triangle structure
* \param v1 First vertex index
* \param v2 Second vertex index
* \param v3 Third vertex index
*/
typedef struct
{
int v1,v2,v3 ; /**< Triangle vertices */
} Triangle ;
//_____________________________________________________________________________
//_____________________________________________________________________________
/** Marching Cubes algorithm wrapper */
/** \class MarchingCubes
* \brief Marching Cubes algorithm.
*/
class MarchingCubes
//-----------------------------------------------------------------------------
{
// Constructors
public :
/**
* Main and default constructor
* \brief constructor
* \param size_x width of the grid
* \param size_y depth of the grid
* \param size_z height of the grid
*/
MarchingCubes ( const int size_x = -1, const int size_y = -1, const int size_z = -1 ) ;
/** Destructor */
~MarchingCubes() ;
//-----------------------------------------------------------------------------
// Accessors
public :
/** accesses the number of vertices of the generated mesh */
inline const int nverts() const { return _nverts ; }
/** accesses the number of triangles of the generated mesh */
inline const int ntrigs() const { return _ntrigs ; }
/** accesses a specific vertex of the generated mesh */
inline Vertex * vert( const int i ) const { if( i < 0 || i >= _nverts ) return ( Vertex *)NULL ; return _vertices + i ; }
/** accesses a specific triangle of the generated mesh */
inline Triangle * trig( const int i ) const { if( i < 0 || i >= _ntrigs ) return (Triangle*)NULL ; return _triangles + i ; }
/** accesses the vertex buffer of the generated mesh */
inline Vertex *vertices () { return _vertices ; }
/** accesses the triangle buffer of the generated mesh */
inline Triangle *triangles() { return _triangles ; }
/** accesses the width of the grid */
inline const int size_x() const { return _size_x ; }
/** accesses the depth of the grid */
inline const int size_y() const { return _size_y ; }
/** accesses the height of the grid */
inline const int size_z() const { return _size_z ; }
/**
* changes the size of the grid
* \param size_x width of the grid
* \param size_y depth of the grid
* \param size_z height of the grid
*/
inline void set_resolution( const int size_x, const int size_y, const int size_z ) { _size_x = size_x ; _size_y = size_y ; _size_z = size_z ; }
/**
* selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes
* \param originalMC true for the original Marching Cubes
*/
inline void set_method ( const bool originalMC = false ) { _originalMC = originalMC ; }
/**
* selects to use data from another class
* \param data is the pointer to the external data, allocated as a size_x*size_y*size_z vector running in x first
*/
inline void set_ext_data ( real *data )
{ if( !_ext_data ) delete [] _data ; _ext_data = data != NULL ; if( _ext_data ) _data = data ; }
/**
* selects to allocate data
*/
inline void set_int_data () { _ext_data = false ; _data = NULL ; }
// Data access
/**
* accesses a specific cube of the grid
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline const real get_data ( const int i, const int j, const int k ) const { return _data[ i + j*_size_x + k*_size_x*_size_y] ; }
/**
* sets a specific cube of the grid
* \param val new value for the cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline void set_data ( const real val, const int i, const int j, const int k ) { _data[ i + j*_size_x + k*_size_x*_size_y] = val ; }
// Data initialization
/** inits temporary structures (must set sizes before call) : the grid and the vertex index per cube */
void init_temps () ;
/** inits all structures (must set sizes before call) : the temporary structures and the mesh buffers */
void init_all () ;
/** clears temporary structures : the grid and the main */
void clean_temps() ;
/** clears all structures : the temporary structures and the mesh buffers */
void clean_all () ;
//-----------------------------------------------------------------------------
// Exportation
public :
/**
* PLY exportation of the generated mesh
* \param fn name of the PLY file to create
* \param bin if true, the PLY will be written in binary mode
*/
void writePLY( const char *fn, bool bin = false ) ;
/**
* PLY importation of a mesh
* \param fn name of the PLY file to read from
*/
void readPLY( const char *fn ) ;
/**
* VRML / Open Inventor exportation of the generated mesh
* \param fn name of the IV file to create
*/
void writeIV ( const char *fn ) ;
/**
* ISO exportation of the input grid
* \param fn name of the ISO file to create
*/
void writeISO( const char *fn ) ;
//-----------------------------------------------------------------------------
// Algorithm
public :
/**
* Main algorithm : must be called after init_all
* \param iso isovalue
*/
void run( real iso = (real)0.0 ) ;
protected :
/** tesselates one cube */
void process_cube () ;
/** tests if the components of the tesselation of the cube should be connected by the interior of an ambiguous face */
bool test_face ( schar face ) ;
/** tests if the components of the tesselation of the cube should be connected through the interior of the cube */
bool test_interior( schar s ) ;
//-----------------------------------------------------------------------------
// Operations
protected :
/**
* computes almost all the vertices of the mesh by interpolation along the cubes edges
* \param iso isovalue
*/
void compute_intersection_points( real iso ) ;
/**
* routine to add a triangle to the mesh
* \param trig the code for the triangle as a sequence of edges index
* \param n the number of triangles to produce
* \param v12 the index of the interior vertex to use, if necessary
*/
void add_triangle ( const char* trig, char n, int v12 = -1 ) ;
/** tests and eventually doubles the vertex buffer capacity for a new vertex insertion */
void test_vertex_addition() ;
/** adds a vertex on the current horizontal edge */
int add_x_vertex() ;
/** adds a vertex on the current longitudinal edge */
int add_y_vertex() ;
/** adds a vertex on the current vertical edge */
int add_z_vertex() ;
/** adds a vertex inside the current cube */
int add_c_vertex() ;
/**
* interpolates the horizontal gradient of the implicit function at the lower vertex of the specified cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
real get_x_grad( const int i, const int j, const int k ) const ;
/**
* interpolates the longitudinal gradient of the implicit function at the lower vertex of the specified cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
real get_y_grad( const int i, const int j, const int k ) const ;
/**
* interpolates the vertical gradient of the implicit function at the lower vertex of the specified cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
real get_z_grad( const int i, const int j, const int k ) const ;
/**
* accesses the pre-computed vertex index on the lower horizontal edge of a specific cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline int get_x_vert( const int i, const int j, const int k ) const { return _x_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
/**
* accesses the pre-computed vertex index on the lower longitudinal edge of a specific cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline int get_y_vert( const int i, const int j, const int k ) const { return _y_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
/**
* accesses the pre-computed vertex index on the lower vertical edge of a specific cube
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline int get_z_vert( const int i, const int j, const int k ) const { return _z_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
/**
* sets the pre-computed vertex index on the lower horizontal edge of a specific cube
* \param val the index of the new vertex
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline void set_x_vert( const int val, const int i, const int j, const int k ) { _x_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
/**
* sets the pre-computed vertex index on the lower longitudinal edge of a specific cube
* \param val the index of the new vertex
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline void set_y_vert( const int val, const int i, const int j, const int k ) { _y_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
/**
* sets the pre-computed vertex index on the lower vertical edge of a specific cube
* \param val the index of the new vertex
* \param i abscisse of the cube
* \param j ordinate of the cube
* \param k height of the cube
*/
inline void set_z_vert( const int val, const int i, const int j, const int k ) { _z_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
/** prints cube for debug */
void print_cube() ;
//-----------------------------------------------------------------------------
// Elements
protected :
bool _originalMC ; /**< selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes */
bool _ext_data ; /**< selects wether to allocate data or use data from another class */
int _size_x ; /**< width of the grid */
int _size_y ; /**< depth of the grid */
int _size_z ; /**< height of the grid */
real *_data ; /**< implicit function values sampled on the grid */
int *_x_verts ; /**< pre-computed vertex indices on the lower horizontal edge of each cube */
int *_y_verts ; /**< pre-computed vertex indices on the lower longitudinal edge of each cube */
int *_z_verts ; /**< pre-computed vertex indices on the lower vertical edge of each cube */
int _nverts ; /**< number of allocated vertices in the vertex buffer */
int _ntrigs ; /**< number of allocated triangles in the triangle buffer */
int _Nverts ; /**< size of the vertex buffer */
int _Ntrigs ; /**< size of the triangle buffer */
Vertex *_vertices ; /**< vertex buffer */
Triangle *_triangles ; /**< triangle buffer */
int _i ; /**< abscisse of the active cube */
int _j ; /**< height of the active cube */
int _k ; /**< ordinate of the active cube */
real _cube[8] ; /**< values of the implicit function on the active cube */
uchar _lut_entry ; /**< cube sign representation in [0..255] */
uchar _case ; /**< case of the active cube in [0..15] */
uchar _config ; /**< configuration of the active cube */
uchar _subconfig ; /**< subconfiguration of the active cube */
};
//_____________________________________________________________________________
#endif // _MARCHINGCUBES_H_

View File

@ -1,233 +0,0 @@
/*
Header for PLY polygon files.
- Greg Turk
A PLY file contains a single polygonal _object_.
An object is composed of lists of _elements_. Typical elements are
vertices, faces, edges and materials.
Each type of element for a given object has one or more _properties_
associated with the element type. For instance, a vertex element may
have as properties three floating-point values x,y,z and three unsigned
chars for red, green and blue.
-----------------------------------------------------------------------
Copyright (c) 1998 Georgia Institute of Technology. All rights reserved.
Permission to use, copy, modify and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that the above copyright notice and this permission notice appear in
all copies of this software and that you do not sell the software.
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef __PLY_H__
#define __PLY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stddef.h>
#define PLY_ASCII 1 /* ascii PLY file */
#define PLY_BINARY_BE 2 /* binary PLY file, big endian */
#define PLY_BINARY_LE 3 /* binary PLY file, little endian */
#define PLY_OKAY 0 /* ply routine worked okay */
#define PLY_ERROR -1 /* error in ply routine */
/* scalar data types supported by PLY format */
#define StartType 0
#define Int8 1
#define Int16 2
#define Int32 3
#define Uint8 4
#define Uint16 5
#define Uint32 6
#define Float32 7
#define Float64 8
#define EndType 9
#define PLY_SCALAR 0
#define PLY_LIST 1
#define PLY_STRING 2
typedef struct PlyProperty { /* description of a property */
char *name; /* property name */
int external_type; /* file's data type */
int internal_type; /* program's data type */
int offset; /* offset bytes of prop in a struct */
int is_list; /* 0 = scalar, 1 = list, 2 = char string */
int count_external; /* file's count type */
int count_internal; /* program's count type */
int count_offset; /* offset byte for list count */
} PlyProperty;
typedef struct PlyElement { /* description of an element */
char *name; /* element name */
int num; /* number of elements in this object */
int size; /* size of element (bytes) or -1 if variable */
int nprops; /* number of properties for this element */
PlyProperty **props; /* list of properties in the file */
char *store_prop; /* flags: property wanted by user? */
int other_offset; /* offset to un-asked-for props, or -1 if none*/
int other_size; /* size of other_props structure */
} PlyElement;
typedef struct PlyOtherProp { /* describes other properties in an element */
char *name; /* element name */
int size; /* size of other_props */
int nprops; /* number of properties in other_props */
PlyProperty **props; /* list of properties in other_props */
} PlyOtherProp;
typedef struct OtherData { /* for storing other_props for an other element */
void *other_props;
} OtherData;
typedef struct OtherElem { /* data for one "other" element */
char *elem_name; /* names of other elements */
int elem_count; /* count of instances of each element */
OtherData **other_data; /* actual property data for the elements */
PlyOtherProp *other_props; /* description of the property data */
} OtherElem;
typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */
int num_elems; /* number of other elements */
OtherElem *other_list; /* list of data for other elements */
} PlyOtherElems;
#define AVERAGE_RULE 1
#define MAJORITY_RULE 2
#define MINIMUM_RULE 3
#define MAXIMUM_RULE 4
#define SAME_RULE 5
#define RANDOM_RULE 6
typedef struct PlyPropRules { /* rules for combining "other" properties */
PlyElement *elem; /* element whose rules we are making */
int *rule_list; /* types of rules (AVERAGE_PLY, MAJORITY_PLY, etc.) */
int nprops; /* number of properties we're combining so far */
int max_props; /* maximum number of properties we have room for now */
void **props; /* list of properties we're combining */
float *weights; /* list of weights of the properties */
} PlyPropRules;
typedef struct PlyRuleList {
char *name; /* name of the rule */
char *element; /* name of element that rule applies to */
char *property; /* name of property that rule applies to */
struct PlyRuleList *next; /* pointer for linked list of rules */
} PlyRuleList;
typedef struct PlyFile { /* description of PLY file */
FILE *fp; /* file pointer */
int file_type; /* ascii or binary */
float version; /* version number of file */
int num_elem_types; /* number of element types of object */
PlyElement **elems; /* list of elements */
int num_comments; /* number of comments */
char **comments; /* list of comments */
int num_obj_info; /* number of items of object information */
char **obj_info; /* list of object info items */
PlyElement *which_elem; /* element we're currently reading or writing */
PlyOtherElems *other_elems; /* "other" elements from a PLY file */
PlyPropRules *current_rules; /* current propagation rules */
PlyRuleList *rule_list; /* rule list from user */
} PlyFile;
/* memory allocation */
/*
extern char *my_alloc();
*/
#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
/* old routines */
#if 0
extern PlyFile *ply_write(FILE *, int, char **, int);
extern PlyFile *ply_read(FILE *, int *, char ***);
extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *);
extern void ply_close(PlyFile *);
extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int);
#endif
extern void ply_describe_property( PlyFile * , char * , PlyProperty * );
extern void ply_get_property( PlyFile * , char * , PlyProperty * );
extern void ply_get_element( PlyFile * , void * );
/*** delcaration of routines ***/
PlyOtherElems *get_other_element_ply( PlyFile * );
PlyFile *read_ply( FILE * );
PlyFile *write_ply( FILE * , int, char ** , int );
extern PlyFile *open_for_writing_ply( char * , int, char ** , int );
void close_ply( PlyFile * );
void free_ply( PlyFile * );
void get_info_ply( PlyFile * , float * , int * );
void free_other_elements_ply( PlyOtherElems * );
void append_comment_ply( PlyFile * , char * );
void append_obj_info_ply( PlyFile * , char * );
void copy_comments_ply( PlyFile * , PlyFile * );
void copy_obj_info_ply( PlyFile * , PlyFile * );
char* *get_comments_ply( PlyFile * , int * );
char* *get_obj_info_ply( PlyFile * , int * );
char* *get_element_list_ply( PlyFile * , int * );
int setup_property_ply( PlyFile * , PlyProperty * );
void get_element_ply( PlyFile * , void * );
char *setup_element_read_ply( PlyFile * , int, int * );
PlyOtherProp *get_other_properties_ply( PlyFile * , int );
void element_count_ply( PlyFile * , char * , int );
void describe_element_ply( PlyFile * , char * , int );
void describe_property_ply( PlyFile * , PlyProperty * );
void describe_other_properties_ply( PlyFile * , PlyOtherProp * , int );
void describe_other_elements_ply( PlyFile * , PlyOtherElems * );
void get_element_setup_ply( PlyFile * , char * , int, PlyProperty * );
PlyProperty* *get_element_description_ply( PlyFile * , char * , int * , int * );
void element_layout_ply( PlyFile * , char * , int, int, PlyProperty * );
void header_complete_ply( PlyFile * );
void put_element_setup_ply( PlyFile * , char * );
void put_element_ply( PlyFile * , void * );
void put_other_elements_ply( PlyFile * );
PlyPropRules *init_rule_ply( PlyFile * , char * );
void modify_rule_ply( PlyPropRules * , char * , int );
void start_props_ply( PlyFile * , PlyPropRules * );
void weight_props_ply( PlyFile * , float, void * );
void *get_new_props_ply( PlyFile * );
void set_prop_rules_ply( PlyFile * , PlyRuleList * );
PlyRuleList *append_prop_rule( PlyRuleList * , char * , char * );
int matches_rule_name( char * );
int equal_strings( char * , char * );
char *recreate_command_line( int, char *argv[] );
#ifdef __cplusplus
}
#endif
#endif /* !__PLY_H__ */

View File

@ -28,6 +28,7 @@ Description
Simplifies surfaces by resampling.
Uses Thomas Lewiner's topology preserving MarchingCubes.
(http://zeus.mat.puc-rio.br/tomlew/tomlew_uk.php)
\*---------------------------------------------------------------------------*/
@ -37,13 +38,328 @@ Description
#include "conformationSurfaces.H"
#include "triSurfaceMesh.H"
#include "MarchingCubes.h"
#include "opt_octree.h"
#include "cube.h"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
class pointConversion
{
const vector scale_;
const vector offset_;
public:
//- Construct from components
pointConversion
(
const vector scale,
const vector offset
)
:
scale_(scale),
offset_(offset)
{}
inline Point toLocal(const Foam::point& pt) const
{
Foam::point p = cmptMultiply(scale_, (pt + offset_));
return Point(p.x(), p.y(), p.z());
}
inline Foam::point toGlobal(const Point& pt) const
{
point p(pt.x(), pt.y(), pt.z());
return cmptDivide(p, scale_) - offset_;
}
};
// For use in Fast-Dual Octree from Thomas Lewiner
class distanceCalc
:
public ::data_access
{
const Level min_level_;
const conformationSurfaces& geometryToConformTo_;
const pointConversion& converter_;
// Private Member Functions
scalar signedDistance(const Foam::point& pt) const
{
const searchableSurfaces& geometry = geometryToConformTo_.geometry();
const labelList& surfaces = geometryToConformTo_.surfaces();
static labelList nearestSurfaces;
static scalarField distance;
static pointField samples(1);
samples[0] = pt;
searchableSurfacesQueries::signedDistance
(
geometry,
surfaces,
samples,
scalarField(1, GREAT),
searchableSurface::OUTSIDE,
nearestSurfaces,
distance
);
return distance[0];
}
public:
// Constructors
//- Construct from components
distanceCalc
(
Level max_level_,
real iso_val_,
Level min_level,
const conformationSurfaces& geometryToConformTo,
const pointConversion& converter
)
:
data_access(max_level_,iso_val_),
min_level_(min_level),
geometryToConformTo_(geometryToConformTo),
converter_(converter)
{}
//- Destructor
virtual ~distanceCalc()
{}
// Member Functions
//- test function
virtual bool need_refine( const Cube &c )
{
int l = c.lv() ;
if( l >= _max_level ) return false;
if( l < min_level_ ) return true;
treeBoundBox bb
(
converter_.toGlobal
(
Point
(
c.xmin(),
c.ymin(),
c.zmin()
)
),
converter_.toGlobal
(
Point
(
c.xmax(),
c.ymax(),
c.zmax()
)
)
);
const searchableSurfaces& geometry =
geometryToConformTo_.geometry();
const labelList& surfaces =
geometryToConformTo_.surfaces();
//- Uniform refinement around surface
{
forAll(surfaces, i)
{
if (geometry[surfaces[i]].overlaps(bb))
{
return true;
}
}
return false;
}
////- Surface intersects bb (but not using intersection test)
//scalar ccDist = signedDistance(bb.midpoint());
//scalar ccVal = ccDist - _iso_val;
//if (mag(ccVal) < SMALL)
//{
// return true;
//}
//const pointField points(bb.points());
//forAll(points, pointI)
//{
// scalar pointVal = signedDistance(points[pointI]) - _iso_val;
// if (ccVal*pointVal < 0)
// {
// return true;
// }
//}
//return false;
////- Refinement based on intersection with multiple planes.
//// Does not work well - too high a ratio between
//// neighbouring cubes.
//const pointField points(bb.points());
//const edgeList& edges = treeBoundBox::edges;
//pointField start(edges.size());
//pointField end(edges.size());
//forAll(edges, i)
//{
// start[i] = points[edges[i][0]];
// end[i] = points[edges[i][1]];
//}
//Foam::List<Foam::List<pointIndexHit> > hitInfo;
//labelListList hitSurfaces;
//searchableSurfacesQueries::findAllIntersections
//(
// geometry,
// surfaces,
// start,
// end,
// hitSurfaces,
// hitInfo
//);
//
//// Count number of intersections
//label nInt = 0;
//forAll(hitSurfaces, edgeI)
//{
// nInt += hitSurfaces[edgeI].size();
//}
//
//if (nInt == 0)
//{
// // No surface intersected. See if there is one inside
// forAll(surfaces, i)
// {
// if (geometry[surfaces[i]].overlaps(bb))
// {
// return true;
// }
// }
// return false;
//}
//
//// Check multiple surfaces
//label baseSurfI = -1;
//forAll(hitSurfaces, edgeI)
//{
// const labelList& hSurfs = hitSurfaces[edgeI];
// forAll(hSurfs, i)
// {
// if (baseSurfI == -1)
// {
// baseSurfI = hSurfs[i];
// }
// else if (baseSurfI != hSurfs[i])
// {
// // Multiple surfaces
// return true;
// }
// }
//}
//
//// Get normals
//DynamicList<pointIndexHit> baseInfo(nInt);
//forAll(hitInfo, edgeI)
//{
// const Foam::List<pointIndexHit>& hits = hitInfo[edgeI];
// forAll(hits, i)
// {
// (void)hits[i].hitPoint();
// baseInfo.append(hits[i]);
// }
//}
//vectorField normals;
//geometry[surfaces[baseSurfI]].getNormal(baseInfo, normals);
//for (label i = 1; i < normals.size(); ++i)
//{
// if ((normals[0] & normals[i]) < 0.9)
// {
// return true;
// }
//}
//labelList regions;
//geometry[surfaces[baseSurfI]].getRegion(baseInfo, regions);
//for (label i = 1; i < regions.size(); ++i)
//{
// if (regions[0] != regions[i])
// {
// return true;
// }
//}
//return false;
//samples[0] = point(c.xmin(), c.ymin(), c.zmin());
//samples[1] = point(c.xmax(), c.ymin(), c.zmin());
//samples[2] = point(c.xmax(), c.ymax(), c.zmin());
//samples[3] = point(c.xmin(), c.ymax(), c.zmin());
//
//samples[4] = point(c.xmin(), c.ymin(), c.zmax());
//samples[5] = point(c.xmax(), c.ymin(), c.zmax());
//samples[6] = point(c.xmax(), c.ymax(), c.zmax());
//samples[7] = point(c.xmin(), c.ymax(), c.zmax());
//scalarField nearestDistSqr(8, GREAT);
//
//Foam::List<pointIndexHit> nearestInfo;
//surf_.findNearest(samples, nearestDistSqr, nearestInfo);
//vectorField normals;
//surf_.getNormal(nearestInfo, normals);
//
//for (label i = 1; i < normals.size(); ++i)
//{
// if ((normals[0] & normals[i]) < 0.5)
// {
// return true;
// }
//}
//return false;
//// Check if surface octree same level
//const labelList elems(surf_.tree().findBox(bb));
//
//if (elems.size() > 1)
//{
// return true;
//}
//else
//{
// return false;
//}
}
//- data function
virtual real value_at( const Cube &c )
{
return signedDistance(converter_.toGlobal(c)) - _iso_val;
}
};
// Main program:
int main(int argc, char *argv[])
@ -52,19 +368,16 @@ int main(int argc, char *argv[])
(
"Re-sample surfaces used in cvMesh operation"
);
//argList::validArgs.append("inputFile");
argList::validArgs.append("(nx ny nz)");
argList::validArgs.append("outputName");
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
const Vector<label> n(IStringStream(args.args()[1])());
const fileName exportName = args.args()[2];
const fileName exportName = args.args()[1];
Info<< "Reading surfaces as specified in the cvMeshDict and"
<< " writing re-sampled " << n << " to " << exportName
<< " writing a re-sampled surface to " << exportName
<< nl << endl;
cpuTime timer;
@ -114,124 +427,100 @@ int main(int argc, char *argv[])
<< timer.cpuTimeIncrement() << " s." << nl << endl;
// Extend
treeBoundBox bb = geometryToConformTo.globalBounds();
{
const vector smallVec = 0.1*bb.span();
bb.min() -= smallVec;
bb.max() += smallVec;
}
Info<< "Meshing to bounding box " << bb << nl << endl;
const vector span(bb.span());
const vector d
(
span.x()/(n.x()-1),
span.y()/(n.y()-1),
span.z()/(n.z()-1)
);
MarchingCubes mc(span.x(), span.y(), span.z() ) ;
mc.set_resolution(n.x(), n.y(), n.z());
mc.init_all() ;
// Generate points
pointField points(mc.size_x()*mc.size_y()*mc.size_z());
label pointI = 0;
point pt;
for( int k = 0 ; k < mc.size_z() ; k++ )
{
pt.z() = bb.min().z() + k*d.z();
for( int j = 0 ; j < mc.size_y() ; j++ )
{
pt.y() = bb.min().y() + j*d.y();
for( int i = 0 ; i < mc.size_x() ; i++ )
{
pt.x() = bb.min().x() + i*d.x();
points[pointI++] = pt;
}
}
}
Info<< "Generated " << points.size() << " sampling points in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
// Compute data
const searchableSurfaces& geometry = geometryToConformTo.geometry();
const labelList& surfaces = geometryToConformTo.surfaces();
scalarField signedDist;
labelList nearestSurfaces;
searchableSurfacesQueries::signedDistance
const label minLevel = 2;
// The max cube size follows from the minLevel and the default cube size
// (1)
const scalar maxSize = 1.0 / (1 << minLevel);
const scalar halfMaxSize = 0.5*maxSize;
// Scale the geometry to fit within
// halfMaxSize .. 1-halfMaxSize
scalar wantedRange = 1.0-maxSize;
const treeBoundBox bb = geometryToConformTo.globalBounds();
const vector scale = cmptDivide
(
geometry,
surfaces,
points,
scalarField(points.size(), sqr(GREAT)),
nearestSurfaces,
signedDist
point(wantedRange, wantedRange, wantedRange),
bb.span()
);
const vector offset =
cmptDivide
(
point(halfMaxSize, halfMaxSize, halfMaxSize),
scale
)
-bb.min();
const pointConversion converter(scale, offset);
// Marching cubes
OptOctree octree;
distanceCalc ref
(
8, //maxLevel
0.0, //distance
minLevel, //minLevel
geometryToConformTo,
converter
);
// Fill elements
pointI = 0;
for( int k = 0 ; k < mc.size_z() ; k++ )
{
for( int j = 0 ; j < mc.size_y() ; j++ )
{
for( int i = 0 ; i < mc.size_x() ; i++ )
{
mc.set_data(float(signedDist[pointI++]), i, j, k);
}
}
}
octree.refine(&ref);
octree.set_impl(&ref);
Info<< "Determined signed distance in = "
Info<< "Calculated octree in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
MarchingCubes& mc = octree.mc();
mc.run() ;
mc.clean_all() ;
octree.build_isosurface(&ref) ;
Info<< "Constructed iso surface in = "
Info<< "Constructed iso surface of distance in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
mc.clean_temps() ;
// Write output file
if (mc.ntrigs() > 0)
{
Triangle* triangles = mc.triangles();
List<labelledTri> tris(mc.ntrigs());
forAll(tris, triI)
label nTris = mc.ntrigs();
Foam::DynamicList<labelledTri> tris(mc.ntrigs());
for (label triI = 0; triI < nTris; ++triI)
{
tris[triI] = labelledTri
(
triangles[triI].v1,
triangles[triI].v2,
triangles[triI].v3,
0 // region
);
const Triangle& t = triangles[triI];
if (t.v1 != t.v2 && t.v1 != t.v3 && t.v2 != t.v3)
{
tris.append
(
labelledTri
(
triangles[triI].v1,
triangles[triI].v2,
triangles[triI].v3,
0 // region
)
);
}
}
Vertex* vertices = mc.vertices();
Point* vertices = mc.vertices();
pointField points(mc.nverts());
forAll(points, pointI)
{
Vertex& v = vertices[pointI];
points[pointI] = point
(
bb.min().x() + v.x*span.x()/mc.size_x(),
bb.min().y() + v.y*span.y()/mc.size_y(),
bb.min().z() + v.z*span.z()/mc.size_z()
);
const Point& v = vertices[pointI];
points[pointI] = converter.toGlobal(v);
}
@ -265,6 +554,7 @@ int main(int argc, char *argv[])
}
triSurface s(tris, patches, points, true);
tris.clearStorage();
Info<< "Extracted triSurface in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
@ -272,7 +562,7 @@ int main(int argc, char *argv[])
// Find out region on local surface of nearest point
{
List<pointIndexHit> hitInfo;
Foam::List<pointIndexHit> hitInfo;
labelList hitSurfaces;
geometryToConformTo.findSurfaceNearest
(
@ -340,7 +630,6 @@ int main(int argc, char *argv[])
mc.clean_all() ;
Info<< "End\n" << endl;
return 0;

View File

@ -0,0 +1,352 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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
cvMeshSurfaceSimplify
Description
Simplifies surfaces by resampling.
Uses Thomas Lewiner's topology preserving MarchingCubes.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "searchableSurfaces.H"
#include "conformationSurfaces.H"
#include "triSurfaceMesh.H"
#include "MarchingCubes.h"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::addNote
(
"Re-sample surfaces used in cvMesh operation"
);
//argList::validArgs.append("inputFile");
argList::validArgs.append("(nx ny nz)");
argList::validArgs.append("outputName");
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
const Vector<label> n(IStringStream(args.args()[1])());
const fileName exportName = args.args()[2];
Info<< "Reading surfaces as specified in the cvMeshDict and"
<< " writing re-sampled " << n << " to " << exportName
<< nl << endl;
cpuTime timer;
IOdictionary cvMeshDict
(
IOobject
(
"cvMeshDict",
runTime.system(),
runTime,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
// Define/load all geometry
searchableSurfaces allGeometry
(
IOobject
(
"cvSearchableSurfaces",
runTime.constant(),
"triSurface",
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE
),
cvMeshDict.subDict("geometry")
);
Info<< "Geometry read in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
Random rndGen(64293*Pstream::myProcNo());
conformationSurfaces geometryToConformTo
(
runTime,
rndGen,
allGeometry,
cvMeshDict.subDict("surfaceConformation")
);
Info<< "Set up geometry in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
// Extend
treeBoundBox bb = geometryToConformTo.globalBounds();
{
const vector smallVec = 0.1*bb.span();
bb.min() -= smallVec;
bb.max() += smallVec;
}
Info<< "Meshing to bounding box " << bb << nl << endl;
const vector span(bb.span());
const vector d
(
span.x()/(n.x()-1),
span.y()/(n.y()-1),
span.z()/(n.z()-1)
);
MarchingCubes mc(span.x(), span.y(), span.z() ) ;
mc.set_resolution(n.x(), n.y(), n.z());
mc.init_all() ;
// Generate points
pointField points(mc.size_x()*mc.size_y()*mc.size_z());
label pointI = 0;
point pt;
for( int k = 0 ; k < mc.size_z() ; k++ )
{
pt.z() = bb.min().z() + k*d.z();
for( int j = 0 ; j < mc.size_y() ; j++ )
{
pt.y() = bb.min().y() + j*d.y();
for( int i = 0 ; i < mc.size_x() ; i++ )
{
pt.x() = bb.min().x() + i*d.x();
points[pointI++] = pt;
}
}
}
Info<< "Generated " << points.size() << " sampling points in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
// Compute data
const searchableSurfaces& geometry = geometryToConformTo.geometry();
const labelList& surfaces = geometryToConformTo.surfaces();
scalarField signedDist;
labelList nearestSurfaces;
searchableSurfacesQueries::signedDistance
(
geometry,
surfaces,
points,
scalarField(points.size(), sqr(GREAT)),
searchableSurface::OUTSIDE, // for non-closed surfaces treat as
// outside
nearestSurfaces,
signedDist
);
// Fill elements
pointI = 0;
for( int k = 0 ; k < mc.size_z() ; k++ )
{
for( int j = 0 ; j < mc.size_y() ; j++ )
{
for( int i = 0 ; i < mc.size_x() ; i++ )
{
mc.set_data(float(signedDist[pointI++]), i, j, k);
}
}
}
Info<< "Determined signed distance in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
mc.run() ;
Info<< "Constructed iso surface in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
mc.clean_temps() ;
// Write output file
if (mc.ntrigs() > 0)
{
Triangle* triangles = mc.triangles();
List<labelledTri> tris(mc.ntrigs());
forAll(tris, triI)
{
tris[triI] = labelledTri
(
triangles[triI].v1,
triangles[triI].v2,
triangles[triI].v3,
0 // region
);
}
Vertex* vertices = mc.vertices();
pointField points(mc.nverts());
forAll(points, pointI)
{
Vertex& v = vertices[pointI];
points[pointI] = point
(
bb.min().x() + v.x*span.x()/mc.size_x(),
bb.min().y() + v.y*span.y()/mc.size_y(),
bb.min().z() + v.z*span.z()/mc.size_z()
);
}
// Find correspondence to original surfaces
labelList regionOffsets(surfaces.size());
label nRegions = 0;
forAll(surfaces, i)
{
const wordList& regions = geometry[surfaces[i]].regions();
regionOffsets[i] = nRegions;
nRegions += regions.size();
}
geometricSurfacePatchList patches(nRegions);
nRegions = 0;
forAll(surfaces, i)
{
const wordList& regions = geometry[surfaces[i]].regions();
forAll(regions, regionI)
{
patches[nRegions] = geometricSurfacePatch
(
"patch",
geometry[surfaces[i]].name() + "_" + regions[regionI],
nRegions
);
nRegions++;
}
}
triSurface s(tris, patches, points, true);
Info<< "Extracted triSurface in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
// Find out region on local surface of nearest point
{
List<pointIndexHit> hitInfo;
labelList hitSurfaces;
geometryToConformTo.findSurfaceNearest
(
s.faceCentres(),
scalarField(s.size(), sqr(GREAT)),
hitInfo,
hitSurfaces
);
// Get region
DynamicList<pointIndexHit> surfInfo(hitSurfaces.size());
DynamicList<label> surfIndices(hitSurfaces.size());
forAll(surfaces, surfI)
{
// Extract info on this surface
surfInfo.clear();
surfIndices.clear();
forAll(hitSurfaces, triI)
{
if (hitSurfaces[triI] == surfI)
{
surfInfo.append(hitInfo[triI]);
surfIndices.append(triI);
}
}
// Calculate sideness of these surface points
labelList region;
geometry[surfaces[surfI]].getRegion(surfInfo, region);
forAll(region, i)
{
label triI = surfIndices[i];
s[triI].region() = regionOffsets[surfI]+region[i];
}
}
}
Info<< "Re-patched surface in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
triSurfaceMesh smesh
(
IOobject
(
exportName,
runTime.constant(), // instance
"triSurface",
runTime, // registry
IOobject::NO_READ,
IOobject::AUTO_WRITE,
false
),
s
);
Info<< "writing surfMesh:\n "
<< smesh.searchableSurface::objectPath() << nl << endl;
smesh.searchableSurface::write();
Info<< "Written surface in = "
<< timer.cpuTimeIncrement() << " s." << nl << endl;
}
mc.clean_all() ;
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -154,6 +154,13 @@ castellatedMeshControls
//faceZone sphere;
//cellZone sphere;
//cellZoneInside inside; //outside/insidePoint
//- Optional specification of what to do with faceZone faces:
// internal : keep them as internal faces (default)
// baffle : create baffles from them. This gives more
// freedom in mesh motion
// boundary : create free-standing boundary faces (baffles
// but without the shared points)
//faceType internal;
}
}

View File

@ -641,9 +641,12 @@ int main(int argc, char *argv[])
Info<< "Mesh size: " << mesh.globalData().nTotalCells() << nl
<< "Before renumbering :" << nl
<< " band : " << band << nl
<< " profile : " << profile << nl
<< " rms frontwidth : " << rmsFrontwidth << nl
<< endl;
<< " profile : " << profile << nl;
if (doFrontWidth)
{
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
}
Info<< endl;
bool sortCoupledFaceCells = false;
bool writeMaps = false;

View File

@ -1,3 +1,4 @@
loadOrCreateMesh.C
redistributePar.C
EXE = $(FOAM_APPBIN)/redistributePar

View File

@ -0,0 +1,323 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
#include "loadOrCreateMesh.H"
#include "processorPolyPatch.H"
#include "Time.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
// Read mesh if available. Otherwise create empty mesh with same non-proc
// patches as proc0 mesh. Requires all processors to have all patches
// (and in same order).
Foam::autoPtr<Foam::fvMesh> Foam::loadOrCreateMesh
(
const IOobject& io
)
{
fileName meshSubDir;
if (io.name() == polyMesh::defaultRegion)
{
meshSubDir = polyMesh::meshSubDir;
}
else
{
meshSubDir = io.name()/polyMesh::meshSubDir;
}
// Check who has a mesh
const bool haveMesh = isDir(io.time().path()/io.instance()/meshSubDir);
Pout<< "meshpath:" << io.time().path()/io.instance()/meshSubDir << endl;
Pout<< "haveMesh:" << haveMesh << endl;
if (!haveMesh)
{
// Create dummy mesh. Only used on procs that don't have mesh.
IOobject noReadIO(io);
noReadIO.readOpt() = IOobject::NO_READ;
fvMesh dummyMesh
(
noReadIO,
xferCopy(pointField()),
xferCopy(faceList()),
xferCopy(labelList()),
xferCopy(labelList()),
false
);
// Add some dummy zones so upon reading it does not read them
// from the undecomposed case. Should be done as extra argument to
// regIOobject::readStream?
List<pointZone*> pz
(
1,
new pointZone
(
"dummyPointZone",
labelList(0),
0,
dummyMesh.pointZones()
)
);
List<faceZone*> fz
(
1,
new faceZone
(
"dummyFaceZone",
labelList(0),
boolList(0),
0,
dummyMesh.faceZones()
)
);
List<cellZone*> cz
(
1,
new cellZone
(
"dummyCellZone",
labelList(0),
0,
dummyMesh.cellZones()
)
);
dummyMesh.addZones(pz, fz, cz);
//Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
// << endl;
dummyMesh.write();
}
//Pout<< "Reading mesh from " << io.objectPath() << endl;
autoPtr<fvMesh> meshPtr(new fvMesh(io));
fvMesh& mesh = meshPtr();
// Sync patches
// ~~~~~~~~~~~~
if (Pstream::master())
{
// Send patches
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
OPstream toSlave(Pstream::scheduled, slave);
toSlave << mesh.boundaryMesh();
}
}
else
{
// Receive patches
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
PtrList<entry> patchEntries(fromMaster);
if (haveMesh)
{
// Check master names against mine
const polyBoundaryMesh& patches = mesh.boundaryMesh();
forAll(patchEntries, patchI)
{
const entry& e = patchEntries[patchI];
const word type(e.dict().lookup("type"));
const word& name = e.keyword();
if (type == processorPolyPatch::typeName)
{
break;
}
if (patchI >= patches.size())
{
FatalErrorIn
(
"createMesh(const Time&, const fileName&, const bool)"
) << "Non-processor patches not synchronised."
<< endl
<< "Processor " << Pstream::myProcNo()
<< " has only " << patches.size()
<< " patches, master has "
<< patchI
<< exit(FatalError);
}
if
(
type != patches[patchI].type()
|| name != patches[patchI].name()
)
{
FatalErrorIn
(
"createMesh(const Time&, const fileName&, const bool)"
) << "Non-processor patches not synchronised."
<< endl
<< "Master patch " << patchI
<< " name:" << type
<< " type:" << type << endl
<< "Processor " << Pstream::myProcNo()
<< " patch " << patchI
<< " has name:" << patches[patchI].name()
<< " type:" << patches[patchI].type()
<< exit(FatalError);
}
}
}
else
{
// Add patch
List<polyPatch*> patches(patchEntries.size());
label nPatches = 0;
forAll(patchEntries, patchI)
{
const entry& e = patchEntries[patchI];
const word type(e.dict().lookup("type"));
const word& name = e.keyword();
if (type == processorPolyPatch::typeName)
{
break;
}
//Pout<< "Adding patch:" << nPatches
// << " name:" << name << " type:" << type << endl;
dictionary patchDict(e.dict());
patchDict.remove("nFaces");
patchDict.add("nFaces", 0);
patchDict.remove("startFace");
patchDict.add("startFace", 0);
patches[patchI] = polyPatch::New
(
name,
patchDict,
nPatches++,
mesh.boundaryMesh()
).ptr();
}
patches.setSize(nPatches);
mesh.addFvPatches(patches, false); // no parallel comms
//// Write empty mesh now we have correct patches
//meshPtr().write();
}
}
// Determine zones
// ~~~~~~~~~~~~~~~
wordList pointZoneNames(mesh.pointZones().names());
Pstream::scatter(pointZoneNames);
wordList faceZoneNames(mesh.faceZones().names());
Pstream::scatter(faceZoneNames);
wordList cellZoneNames(mesh.cellZones().names());
Pstream::scatter(cellZoneNames);
if (!haveMesh)
{
// Add the zones. Make sure to remove the old dummy ones first
mesh.pointZones().clear();
mesh.faceZones().clear();
mesh.cellZones().clear();
List<pointZone*> pz(pointZoneNames.size());
forAll(pointZoneNames, i)
{
pz[i] = new pointZone
(
pointZoneNames[i],
labelList(0),
i,
mesh.pointZones()
);
}
List<faceZone*> fz(faceZoneNames.size());
forAll(faceZoneNames, i)
{
fz[i] = new faceZone
(
faceZoneNames[i],
labelList(0),
boolList(0),
i,
mesh.faceZones()
);
}
List<cellZone*> cz(cellZoneNames.size());
forAll(cellZoneNames, i)
{
cz[i] = new cellZone
(
cellZoneNames[i],
labelList(0),
i,
mesh.cellZones()
);
}
mesh.addZones(pz, fz, cz);
}
if (!haveMesh)
{
// We created a dummy mesh file above. Delete it.
//Pout<< "Removing dummy mesh " << io.objectPath() << endl;
rmDir(io.objectPath());
}
// Force recreation of globalMeshData.
mesh.clearOut();
mesh.globalData();
// Do some checks.
// Check if the boundary definition is unique
mesh.boundaryMesh().checkDefinition(true);
// Check if the boundary processor patches are correct
mesh.boundaryMesh().checkParallelSync(true);
// Check names of zones are equal
mesh.cellZones().checkDefinition(true);
mesh.cellZones().checkParallelSync(true);
mesh.faceZones().checkDefinition(true);
mesh.faceZones().checkParallelSync(true);
mesh.pointZones().checkDefinition(true);
mesh.pointZones().checkParallelSync(true);
return meshPtr;
}
// ************************************************************************* //

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
InNamespace
Foam
Description
Load or create (0 size) a mesh. Used in distributing meshes to a
larger number of processors
SourceFiles
loadOrCreateMesh.C
\*---------------------------------------------------------------------------*/
#ifndef loadOrCreateMesh_H
#define loadOrCreateMesh_H
#include "fvMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//- Load (if it exists) or create zero cell mesh given an IOobject:
// name : regionName
// instance : exact directory where to find mesh (i.e. does not
// do a findInstance
autoPtr<fvMesh> loadOrCreateMesh(const IOobject& io);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -54,6 +54,7 @@ Description
#include "mapDistributePolyMesh.H"
#include "IOobjectList.H"
#include "globalIndex.H"
#include "loadOrCreateMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -62,292 +63,292 @@ Description
static const scalar defaultMergeTol = 1E-6;
// Read mesh if available. Otherwise create empty mesh with same non-proc
// patches as proc0 mesh. Requires all processors to have all patches
// (and in same order).
autoPtr<fvMesh> createMesh
(
const Time& runTime,
const word& regionName,
const fileName& instDir,
const bool haveMesh
)
{
//Pout<< "Create mesh for time = "
// << runTime.timeName() << nl << endl;
IOobject io
(
regionName,
instDir,
runTime,
IOobject::MUST_READ
);
if (!haveMesh)
{
// Create dummy mesh. Only used on procs that don't have mesh.
IOobject noReadIO(io);
noReadIO.readOpt() = IOobject::NO_READ;
fvMesh dummyMesh
(
noReadIO,
xferCopy(pointField()),
xferCopy(faceList()),
xferCopy(labelList()),
xferCopy(labelList()),
false
);
// Add some dummy zones so upon reading it does not read them
// from the undecomposed case. Should be done as extra argument to
// regIOobject::readStream?
List<pointZone*> pz
(
1,
new pointZone
(
"dummyPointZone",
labelList(0),
0,
dummyMesh.pointZones()
)
);
List<faceZone*> fz
(
1,
new faceZone
(
"dummyFaceZone",
labelList(0),
boolList(0),
0,
dummyMesh.faceZones()
)
);
List<cellZone*> cz
(
1,
new cellZone
(
"dummyCellZone",
labelList(0),
0,
dummyMesh.cellZones()
)
);
dummyMesh.addZones(pz, fz, cz);
//Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
// << endl;
dummyMesh.write();
}
//Pout<< "Reading mesh from " << io.objectPath() << endl;
autoPtr<fvMesh> meshPtr(new fvMesh(io));
fvMesh& mesh = meshPtr();
// Sync patches
// ~~~~~~~~~~~~
if (Pstream::master())
{
// Send patches
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
OPstream toSlave(Pstream::scheduled, slave);
toSlave << mesh.boundaryMesh();
}
}
else
{
// Receive patches
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
PtrList<entry> patchEntries(fromMaster);
if (haveMesh)
{
// Check master names against mine
const polyBoundaryMesh& patches = mesh.boundaryMesh();
forAll(patchEntries, patchI)
{
const entry& e = patchEntries[patchI];
const word type(e.dict().lookup("type"));
const word& name = e.keyword();
if (type == processorPolyPatch::typeName)
{
break;
}
if (patchI >= patches.size())
{
FatalErrorIn
(
"createMesh(const Time&, const fileName&, const bool)"
) << "Non-processor patches not synchronised."
<< endl
<< "Processor " << Pstream::myProcNo()
<< " has only " << patches.size()
<< " patches, master has "
<< patchI
<< exit(FatalError);
}
if
(
type != patches[patchI].type()
|| name != patches[patchI].name()
)
{
FatalErrorIn
(
"createMesh(const Time&, const fileName&, const bool)"
) << "Non-processor patches not synchronised."
<< endl
<< "Master patch " << patchI
<< " name:" << type
<< " type:" << type << endl
<< "Processor " << Pstream::myProcNo()
<< " patch " << patchI
<< " has name:" << patches[patchI].name()
<< " type:" << patches[patchI].type()
<< exit(FatalError);
}
}
}
else
{
// Add patch
List<polyPatch*> patches(patchEntries.size());
label nPatches = 0;
forAll(patchEntries, patchI)
{
const entry& e = patchEntries[patchI];
const word type(e.dict().lookup("type"));
const word& name = e.keyword();
if (type == processorPolyPatch::typeName)
{
break;
}
//Pout<< "Adding patch:" << nPatches
// << " name:" << name << " type:" << type << endl;
dictionary patchDict(e.dict());
patchDict.remove("nFaces");
patchDict.add("nFaces", 0);
patchDict.remove("startFace");
patchDict.add("startFace", 0);
patches[patchI] = polyPatch::New
(
name,
patchDict,
nPatches++,
mesh.boundaryMesh()
).ptr();
}
patches.setSize(nPatches);
mesh.addFvPatches(patches, false); // no parallel comms
//// Write empty mesh now we have correct patches
//meshPtr().write();
}
}
// Determine zones
// ~~~~~~~~~~~~~~~
wordList pointZoneNames(mesh.pointZones().names());
Pstream::scatter(pointZoneNames);
wordList faceZoneNames(mesh.faceZones().names());
Pstream::scatter(faceZoneNames);
wordList cellZoneNames(mesh.cellZones().names());
Pstream::scatter(cellZoneNames);
if (!haveMesh)
{
// Add the zones. Make sure to remove the old dummy ones first
mesh.pointZones().clear();
mesh.faceZones().clear();
mesh.cellZones().clear();
List<pointZone*> pz(pointZoneNames.size());
forAll(pointZoneNames, i)
{
pz[i] = new pointZone
(
pointZoneNames[i],
labelList(0),
i,
mesh.pointZones()
);
}
List<faceZone*> fz(faceZoneNames.size());
forAll(faceZoneNames, i)
{
fz[i] = new faceZone
(
faceZoneNames[i],
labelList(0),
boolList(0),
i,
mesh.faceZones()
);
}
List<cellZone*> cz(cellZoneNames.size());
forAll(cellZoneNames, i)
{
cz[i] = new cellZone
(
cellZoneNames[i],
labelList(0),
i,
mesh.cellZones()
);
}
mesh.addZones(pz, fz, cz);
}
if (!haveMesh)
{
// We created a dummy mesh file above. Delete it.
//Pout<< "Removing dummy mesh " << io.objectPath() << endl;
rmDir(io.objectPath());
}
// Force recreation of globalMeshData.
mesh.clearOut();
mesh.globalData();
// Do some checks.
// Check if the boundary definition is unique
mesh.boundaryMesh().checkDefinition(true);
// Check if the boundary processor patches are correct
mesh.boundaryMesh().checkParallelSync(true);
// Check names of zones are equal
mesh.cellZones().checkDefinition(true);
mesh.cellZones().checkParallelSync(true);
mesh.faceZones().checkDefinition(true);
mesh.faceZones().checkParallelSync(true);
mesh.pointZones().checkDefinition(true);
mesh.pointZones().checkParallelSync(true);
return meshPtr;
}
//// Read mesh if available. Otherwise create empty mesh with same non-proc
//// patches as proc0 mesh. Requires all processors to have all patches
//// (and in same order).
//autoPtr<fvMesh> createMesh
//(
// const Time& runTime,
// const word& regionName,
// const fileName& instDir,
// const bool haveMesh
//)
//{
// //Pout<< "Create mesh for time = "
// // << runTime.timeName() << nl << endl;
//
// IOobject io
// (
// regionName,
// instDir,
// runTime,
// IOobject::MUST_READ
// );
//
// if (!haveMesh)
// {
// // Create dummy mesh. Only used on procs that don't have mesh.
// IOobject noReadIO(io);
// noReadIO.readOpt() = IOobject::NO_READ;
// fvMesh dummyMesh
// (
// noReadIO,
// xferCopy(pointField()),
// xferCopy(faceList()),
// xferCopy(labelList()),
// xferCopy(labelList()),
// false
// );
// // Add some dummy zones so upon reading it does not read them
// // from the undecomposed case. Should be done as extra argument to
// // regIOobject::readStream?
// List<pointZone*> pz
// (
// 1,
// new pointZone
// (
// "dummyPointZone",
// labelList(0),
// 0,
// dummyMesh.pointZones()
// )
// );
// List<faceZone*> fz
// (
// 1,
// new faceZone
// (
// "dummyFaceZone",
// labelList(0),
// boolList(0),
// 0,
// dummyMesh.faceZones()
// )
// );
// List<cellZone*> cz
// (
// 1,
// new cellZone
// (
// "dummyCellZone",
// labelList(0),
// 0,
// dummyMesh.cellZones()
// )
// );
// dummyMesh.addZones(pz, fz, cz);
// //Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
// // << endl;
// dummyMesh.write();
// }
//
// //Pout<< "Reading mesh from " << io.objectPath() << endl;
// autoPtr<fvMesh> meshPtr(new fvMesh(io));
// fvMesh& mesh = meshPtr();
//
//
// // Sync patches
// // ~~~~~~~~~~~~
//
// if (Pstream::master())
// {
// // Send patches
// for
// (
// int slave=Pstream::firstSlave();
// slave<=Pstream::lastSlave();
// slave++
// )
// {
// OPstream toSlave(Pstream::scheduled, slave);
// toSlave << mesh.boundaryMesh();
// }
// }
// else
// {
// // Receive patches
// IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
// PtrList<entry> patchEntries(fromMaster);
//
// if (haveMesh)
// {
// // Check master names against mine
//
// const polyBoundaryMesh& patches = mesh.boundaryMesh();
//
// forAll(patchEntries, patchI)
// {
// const entry& e = patchEntries[patchI];
// const word type(e.dict().lookup("type"));
// const word& name = e.keyword();
//
// if (type == processorPolyPatch::typeName)
// {
// break;
// }
//
// if (patchI >= patches.size())
// {
// FatalErrorIn
// (
// "createMesh(const Time&, const fileName&, const bool)"
// ) << "Non-processor patches not synchronised."
// << endl
// << "Processor " << Pstream::myProcNo()
// << " has only " << patches.size()
// << " patches, master has "
// << patchI
// << exit(FatalError);
// }
//
// if
// (
// type != patches[patchI].type()
// || name != patches[patchI].name()
// )
// {
// FatalErrorIn
// (
// "createMesh(const Time&, const fileName&, const bool)"
// ) << "Non-processor patches not synchronised."
// << endl
// << "Master patch " << patchI
// << " name:" << type
// << " type:" << type << endl
// << "Processor " << Pstream::myProcNo()
// << " patch " << patchI
// << " has name:" << patches[patchI].name()
// << " type:" << patches[patchI].type()
// << exit(FatalError);
// }
// }
// }
// else
// {
// // Add patch
// List<polyPatch*> patches(patchEntries.size());
// label nPatches = 0;
//
// forAll(patchEntries, patchI)
// {
// const entry& e = patchEntries[patchI];
// const word type(e.dict().lookup("type"));
// const word& name = e.keyword();
//
// if (type == processorPolyPatch::typeName)
// {
// break;
// }
//
// //Pout<< "Adding patch:" << nPatches
// // << " name:" << name << " type:" << type << endl;
//
// dictionary patchDict(e.dict());
// patchDict.remove("nFaces");
// patchDict.add("nFaces", 0);
// patchDict.remove("startFace");
// patchDict.add("startFace", 0);
//
// patches[patchI] = polyPatch::New
// (
// name,
// patchDict,
// nPatches++,
// mesh.boundaryMesh()
// ).ptr();
// }
// patches.setSize(nPatches);
// mesh.addFvPatches(patches, false); // no parallel comms
//
// //// Write empty mesh now we have correct patches
// //meshPtr().write();
// }
// }
//
//
// // Determine zones
// // ~~~~~~~~~~~~~~~
//
// wordList pointZoneNames(mesh.pointZones().names());
// Pstream::scatter(pointZoneNames);
// wordList faceZoneNames(mesh.faceZones().names());
// Pstream::scatter(faceZoneNames);
// wordList cellZoneNames(mesh.cellZones().names());
// Pstream::scatter(cellZoneNames);
//
// if (!haveMesh)
// {
// // Add the zones. Make sure to remove the old dummy ones first
// mesh.pointZones().clear();
// mesh.faceZones().clear();
// mesh.cellZones().clear();
//
// List<pointZone*> pz(pointZoneNames.size());
// forAll(pointZoneNames, i)
// {
// pz[i] = new pointZone
// (
// pointZoneNames[i],
// labelList(0),
// i,
// mesh.pointZones()
// );
// }
// List<faceZone*> fz(faceZoneNames.size());
// forAll(faceZoneNames, i)
// {
// fz[i] = new faceZone
// (
// faceZoneNames[i],
// labelList(0),
// boolList(0),
// i,
// mesh.faceZones()
// );
// }
// List<cellZone*> cz(cellZoneNames.size());
// forAll(cellZoneNames, i)
// {
// cz[i] = new cellZone
// (
// cellZoneNames[i],
// labelList(0),
// i,
// mesh.cellZones()
// );
// }
// mesh.addZones(pz, fz, cz);
// }
//
//
// if (!haveMesh)
// {
// // We created a dummy mesh file above. Delete it.
// //Pout<< "Removing dummy mesh " << io.objectPath() << endl;
// rmDir(io.objectPath());
// }
//
// // Force recreation of globalMeshData.
// mesh.clearOut();
// mesh.globalData();
//
//
// // Do some checks.
//
// // Check if the boundary definition is unique
// mesh.boundaryMesh().checkDefinition(true);
// // Check if the boundary processor patches are correct
// mesh.boundaryMesh().checkParallelSync(true);
// // Check names of zones are equal
// mesh.cellZones().checkDefinition(true);
// mesh.cellZones().checkParallelSync(true);
// mesh.faceZones().checkDefinition(true);
// mesh.faceZones().checkParallelSync(true);
// mesh.pointZones().checkDefinition(true);
// mesh.pointZones().checkParallelSync(true);
//
// return meshPtr;
//}
// Get merging distance when matching face centres
@ -786,13 +787,24 @@ int main(int argc, char *argv[])
const bool allHaveMesh = (findIndex(haveMesh, false) == -1);
// Create mesh
autoPtr<fvMesh> meshPtr = createMesh
//autoPtr<fvMesh> meshPtr = createMesh
//(
// runTime,
// regionName,
// masterInstDir,
// haveMesh[Pstream::myProcNo()]
//);
autoPtr<fvMesh> meshPtr = loadOrCreateMesh
(
runTime,
regionName,
masterInstDir,
haveMesh[Pstream::myProcNo()]
IOobject
(
regionName,
masterInstDir,
runTime,
Foam::IOobject::MUST_READ
)
);
fvMesh& mesh = meshPtr();
// Print some statistics

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -216,7 +216,6 @@ bool intersectSurfaces
int main(int argc, char *argv[])
{
argList::validArgs.clear();
argList::noParallel();
argList::validArgs.append("action");
argList::validArgs.append("surface file");

View File

@ -525,12 +525,6 @@ int main(int argc, char *argv[])
surfaceDict.lookupOrAddDefault<Switch>("writeVTK", "off");
const Switch writeObj =
surfaceDict.lookupOrAddDefault<Switch>("writeObj", "off");
const Switch writeFeatureEdgeMesh =
surfaceDict.lookupOrAddDefault<Switch>
(
"writeFeatureEdgeMesh",
"off"
);
const Switch curvature =
surfaceDict.lookupOrAddDefault<Switch>("curvature", "off");
@ -592,7 +586,7 @@ int main(int argc, char *argv[])
if (extractionMethod == "extractFromFile")
{
const fileName featureEdgeFile =
surfaceDict.subDict("extractFromFile").lookup
surfaceDict.subDict("extractFromFileCoeffs").lookup
(
"featureEdgeFile"
);
@ -612,7 +606,7 @@ int main(int argc, char *argv[])
const scalar includedAngle =
readScalar
(
surfaceDict.subDict("extractFromSurface").lookup
surfaceDict.subDict("extractFromSurfaceCoeffs").lookup
(
"includedAngle"
)
@ -747,10 +741,10 @@ int main(int argc, char *argv[])
surfaceFeatures newSet(surf);
newSet.setFromStatus(edgeStat);
if (writeObj)
{
newSet.writeObj("final");
}
//if (writeObj)
//{
// newSet.writeObj("final");
//}
Info<< nl
<< "Final feature set after trimming and subsetting:" << nl
@ -773,37 +767,36 @@ int main(int argc, char *argv[])
Info<< nl << "Writing extendedFeatureEdgeMesh to "
<< feMesh.objectPath() << endl;
mkDir(feMesh.path());
if (writeObj)
{
feMesh.writeObj(surfFileName.lessExt().name());
feMesh.writeObj(feMesh.path()/surfFileName.lessExt().name());
}
feMesh.write();
// Write a featureEdgeMesh for backwards compatibility
if (writeFeatureEdgeMesh)
{
featureEdgeMesh bfeMesh
featureEdgeMesh bfeMesh
(
IOobject
(
IOobject
(
surfFileName.lessExt().name() + ".eMesh", // name
runTime.constant(), // instance
"triSurface",
runTime, // registry
IOobject::NO_READ,
IOobject::AUTO_WRITE,
false
),
feMesh.points(),
feMesh.edges()
);
surfFileName.lessExt().name() + ".eMesh", // name
runTime.constant(), // instance
"triSurface",
runTime, // registry
IOobject::NO_READ,
IOobject::AUTO_WRITE,
false
),
feMesh.points(),
feMesh.edges()
);
Info<< nl << "Writing featureEdgeMesh to "
<< bfeMesh.objectPath() << endl;
Info<< nl << "Writing featureEdgeMesh to "
<< bfeMesh.objectPath() << endl;
bfeMesh.regIOobject::write();
}
bfeMesh.regIOobject::write();
triSurfaceMesh searchSurf
(

View File

@ -16,10 +16,34 @@ FoamFile
surface1.stl
{
// extractFromFile || extractFromSurface
// How to obtain raw features (extractFromFile || extractFromSurface)
extractionMethod extractFromSurface;
extractFromSurfaceCoeffs
{
// Mark edges whose adjacent surface normals are at an angle less
// than includedAngle as features
// - 0 : selects no edges
// - 180: selects all edges
includedAngle 120;
}
// Write options
// Write .eMesh file (for snappyHexMesh)
writeFeatureEdgeMesh yes;
// Write features to obj format for postprocessing
writeObj yes;
}
surface2.nas
{
// How to obtain raw features (extractFromFile || extractFromSurface)
extractionMethod extractFromFile;
extractFromFile
extractFromFileCoeffs
{
// Load from an existing feature edge file
featureEdgeFile "constant/triSurface/featureEdges.nas";
@ -62,24 +86,13 @@ surface1.stl
closeness no;
// Write options
writeVTK no;
writeObj yes;
writeFeatureEdgeMesh no;
}
// Write features to obj format for postprocessing
writeObj yes;
surface2.nas
{
extractionMethod extractFromSurface;
extractFromSurface
{
// Mark edges whose adjacent surface normals are at an angle less
// than includedAngle as features
// - 0 : selects no edges
// - 180: selects all edges
includedAngle 120;
}
// Write surface proximity and curvature fields to vtk format
// for postprocessing
writeVTK no;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -312,7 +312,7 @@ int main(int argc, char *argv[])
triSurface allSurf(allFaces, allPatches, allPoints);
// Cleanup (which does point merge as well
// Cleanup (which does point merge as well)
allSurf.cleanup(false);
// Write surface mesh