ENH: Added new abaqus sampledSet

Generates sample positions from points specified in a file as Abaqus mesh
points.

Example usage:

    sets
    {
        cone25 // user-specified set name
        {
            type        abaqusMesh;
            file        "abaqusMesh.inp";

            // Optional entries

            // Scale, e.g. mm to m
            scale       0.001;

            // Search distance when the sample point is not located in a cell
            maxDist     0.25;

            ...
        }
    }
This commit is contained in:
Andrew Heather 2023-06-12 09:16:57 +01:00 committed by Mark Olesen
parent d3b3a5a41e
commit a1819a5411
3 changed files with 497 additions and 0 deletions

View File

@ -1,6 +1,7 @@
probes/probes.C
probes/patchProbes.C
sampledSet/abaqus/abaqusMeshSet.C
sampledSet/circle/circleSet.C
sampledSet/cloud/cloudSet.C
sampledSet/patchCloud/patchCloudSet.C

View File

@ -0,0 +1,346 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "abaqusMeshSet.H"
#include "stringOps.H"
#include "Fstream.H"
#include "SpanStream.H"
#include "meshSearch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(abaqusMeshSet, 0);
addToRunTimeSelectionTable(sampledSet, abaqusMeshSet, word);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::abaqusMeshSet::readCoord(ISstream& is, vector& coord) const
{
string buffer;
do
{
//buffer.clear();
is.getLine(buffer);
const auto elems = buffer.find("*ELEMENT");
if (elems != std::string::npos)
{
buffer.clear();
break;
}
// Trim out any '*' comments
const auto pos = buffer.find('*');
if (pos != std::string::npos)
{
buffer.erase(pos);
}
stringOps::inplaceTrimRight(buffer);
}
while (buffer.empty() && is.good());
if (buffer.empty())
{
return false;
}
const auto strings = stringOps::split(buffer, ',');
if (strings.size() != 4)
{
FatalErrorInFunction
<< "Read error: expected format int, float, float, float"
<< " but read buffer " << buffer
<< exit(FatalError);
}
for (int i = 0; i <= 2; ++i)
{
// Swallow i=0 for node label
const auto& s = strings[i+1].str();
ISpanStream buf(s.data(), s.length());
buf >> coord[i];
}
coord *= scale_;
return true;
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::abaqusMeshSet::calcSamples
(
DynamicList<point>& samplingPts,
DynamicList<label>& samplingCells,
DynamicList<label>& samplingFaces,
DynamicList<label>& samplingSegments,
DynamicList<scalar>& samplingCurveDist
) const
{
DebugInfo
<< "abaqusMeshSet : sampling " << sampleCoords_.size() << " points"
<< endl;
List<bool> found(sampleCoords_.size(), false);
forAll(sampleCoords_, samplei)
{
const vector& pt = sampleCoords_[samplei];
label celli = searchEngine().findCell(pt);
if (celli != -1)
{
found[samplei] = true;
samplingPts.append(pt);
samplingCells.append(celli);
samplingFaces.append(-1);
samplingSegments.append(0);
samplingCurveDist.append(1.0*samplei);
}
}
Pstream::listCombineAllGather(found, orEqOp<bool>());
DynamicList<label> lost;
forAll(found, samplei)
{
if (!found[samplei]) lost.append(samplei);
}
const label nFound = sampleCoords_.size() - lost.size();
label nOutOfBounds = 0;
if (Pstream::parRun())
{
typedef Tuple2<label, Tuple2<label, scalar>> procCellDist;
List<procCellDist> pcd(lost.size(), procCellDist(-1, {-1, GREAT}));
forAll(pcd, i)
{
const label samplei = lost[i];
const vector& pt0 = sampleCoords_[samplei];
const label celli = searchEngine().findNearestCell(pt0);
const vector& pt1 = mesh().cellCentres()[celli];
const scalar distSqr = magSqr(pt1 - pt0);
pcd[i] = procCellDist(Pstream::myProcNo(), {celli, distSqr});
}
Pstream::listCombineAllGather
(
pcd,
[](procCellDist& x, const procCellDist& y)
{
// Select item with smallest distance
if (y.second().second() < x.second().second())
{
x = y;
}
}
);
forAll(pcd, i)
{
const label samplei = lost[i];
if (pcd[i].second().second() < maxDistSqr_)
{
if (pcd[i].first() == Pstream::myProcNo())
{
const label celli = pcd[i].second().first();
const vector& pt1 = mesh().cellCentres()[celli];
samplingPts.append(pt1);
samplingCells.append(celli);
samplingFaces.append(-1);
samplingSegments.append(0);
samplingCurveDist.append(1.0*samplei);
}
}
else
{
// Insert points that have not been found as null points
if (Pstream::master())
{
samplingPts.append(sampleCoords_[samplei]);
samplingCells.append(-1);
samplingFaces.append(-1);
samplingSegments.append(0);
samplingCurveDist.append(1.0*samplei);
++nOutOfBounds;
}
}
}
}
else
{
// Serial running
forAll(lost, i)
{
const label samplei = lost[i];
const vector& pt0 = sampleCoords_[samplei];
const label celli = searchEngine().findNearestCell(pt0);
const vector& pt1 = mesh().cellCentres()[celli];
const scalar distSqr = magSqr(pt1 - pt0);
if (distSqr < maxDistSqr_)
{
samplingPts.append(pt1);
samplingCells.append(celli);
samplingFaces.append(-1);
samplingSegments.append(0);
samplingCurveDist.append(1.0*samplei);
}
else
{
// Insert points that have not been found as null points
samplingPts.append(sampleCoords_[samplei]);
samplingCells.append(-1);
samplingFaces.append(-1);
samplingSegments.append(0);
samplingCurveDist.append(1.0*samplei);
++nOutOfBounds;
}
}
}
DebugInFunction
<< "Sample size : " << sampleCoords_.size() << nl
<< "Lost samples : " << nOutOfBounds << nl
<< "Recovered samples : "
<< (sampleCoords_.size() - nOutOfBounds - nFound) << nl
<< endl;
if (nOutOfBounds)
{
WarningInFunction
<< "Identified " << nOutOfBounds << " out-of-bounds points"
<< endl;
}
}
void Foam::abaqusMeshSet::genSamples()
{
// Storage for sample points
DynamicList<point> samplingPts;
DynamicList<label> samplingCells;
DynamicList<label> samplingFaces;
DynamicList<label> samplingSegments;
DynamicList<scalar> samplingCurveDist;
calcSamples
(
samplingPts,
samplingCells,
samplingFaces,
samplingSegments,
samplingCurveDist
);
samplingPts.shrink();
samplingCells.shrink();
samplingFaces.shrink();
samplingSegments.shrink();
samplingCurveDist.shrink();
setSamples
(
std::move(samplingPts),
std::move(samplingCells),
std::move(samplingFaces),
std::move(samplingSegments),
std::move(samplingCurveDist)
);
if (debug > 1)
{
write(Info);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::abaqusMeshSet::abaqusMeshSet
(
const word& name,
const polyMesh& mesh,
const meshSearch& searchEngine,
const dictionary& dict
)
:
sampledSet(name, mesh, searchEngine, dict),
scale_(dict.getOrDefault<scalar>("scale", 1)),
sampleCoords_(),
maxDistSqr_(sqr(dict.getOrDefault<scalar>("maxDist", 0)))
{
if (Pstream::master())
{
const fileName inputFile(dict.get<fileName>("file").expand());
IFstream pointsFile(inputFile);
if (!pointsFile.good())
{
FatalIOErrorInFunction(dict)
<< "Unable to find file " << pointsFile.name()
<< abort(FatalIOError);
}
// Read the points file
DynamicList<point> coords;
vector c;
while (readCoord(pointsFile, c))
{
coords.append(c);
}
sampleCoords_.transfer(coords);
}
Pstream::broadcast(sampleCoords_);
DebugInfo
<< "Number of sample points: " << sampleCoords_.size() << nl
<< "Sample points bounds: " << boundBox(sampleCoords_) << endl;
genSamples();
}
// ************************************************************************* //

View File

@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::abaqusMeshSet
Description
Generates sample positions from points specified in a file as Abaqus mesh
points.
Example usage:
\verbatim
sets
{
cone25 // user-specified set name
{
type abaqusMesh;
file "abaqusMesh.inp";
// Optional entries
// Scale, e.g. mm to m
scale 0.001;
// Search distance when the sample point is not located in a cell
maxDist 0.25;
...
}
}
\endverbatim
For a dictionary specification:
\table
Property | Description | Required | Default
type | abaqusMesh | yes |
file | Path to Abaqus file | yes |
scale | scale input point positions | no | 1
maxDist | Search distance for sample points | no | 1
\endtable
SourceFiles
abaqusMeshSet.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_abaqusMeshSet_H
#define Foam_abaqusMeshSet_H
#include "sampledSet.H"
#include "vectorList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class abaqusMeshSet Declaration
\*---------------------------------------------------------------------------*/
class abaqusMeshSet
:
public sampledSet
{
// Private data
//- Scale
const scalar scale_;
//- Sample coordinates
vectorList sampleCoords_;
//- Maximum search distance-squared
const scalar maxDistSqr_;
// Private Member Functions
bool readCoord(ISstream& is, vector& coord) const;
//- Samples all points in sampleCoords.
void calcSamples
(
DynamicList<point>& samplingPts,
DynamicList<label>& samplingCells,
DynamicList<label>& samplingFaces,
DynamicList<label>& samplingSegments,
DynamicList<scalar>& samplingCurveDist
) const;
//- Uses calcSamples to obtain samples. Copies them into *this.
void genSamples();
public:
//- Runtime type information
TypeName("abaqusMesh");
// Constructors
//- Construct from dictionary
abaqusMeshSet
(
const word& name,
const polyMesh& mesh,
const meshSearch& searchEngine,
const dictionary& dict
);
//- Destructor
virtual ~abaqusMeshSet() = default;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //